Index: sys/arm64/include/cpu.h =================================================================== --- sys/arm64/include/cpu.h +++ sys/arm64/include/cpu.h @@ -79,6 +79,7 @@ #define CPU_IMPL_INTEL 0x69 #define CPU_PART_THUNDER 0x0A1 +#define CPU_PART_THUNDERX2 0x0AF #define CPU_PART_FOUNDATION 0xD00 #define CPU_PART_CORTEX_A35 0xD04 #define CPU_PART_CORTEX_A53 0xD03 @@ -91,6 +92,8 @@ #define CPU_REV_THUNDER_1_0 0x00 #define CPU_REV_THUNDER_1_1 0x01 +#define CPU_REV_THUNDERX2_0 0x00 + #define CPU_IMPL(midr) (((midr) >> 24) & 0xff) #define CPU_PART(midr) (((midr) >> 4) & 0xfff) #define CPU_VAR(midr) (((midr) >> 20) & 0xf) Index: sys/dev/acpica/acpi.c =================================================================== --- sys/dev/acpica/acpi.c +++ sys/dev/acpica/acpi.c @@ -2085,15 +2085,6 @@ break; } - /* - * Get the device's resource settings and attach them. - * Note that if the device has _PRS but no _CRS, we need - * to decide when it's appropriate to try to configure the - * device. Ignore the return value here; it's OK for the - * device not to have any resources. - */ - acpi_parse_resources(child, handle, &acpi_res_parse_set, NULL); - ad = device_get_ivars(child); ad->ad_cls_class = 0xffffff; if (ACPI_SUCCESS(AcpiGetObjectInfo(handle, &devinfo))) { @@ -2111,6 +2102,14 @@ #endif AcpiOsFree(devinfo); } + /* + * Get the device's resource settings and attach them. + * Note that if the device has _PRS but no _CRS, we need + * to decide when it's appropriate to try to configure the + * device. Ignore the return value here; it's OK for the + * device not to have any resources. + */ + acpi_parse_resources(child, handle, &acpi_res_parse_set, NULL); break; } } Index: sys/dev/acpica/acpi_resource.c =================================================================== --- sys/dev/acpica/acpi_resource.c +++ sys/dev/acpica/acpi_resource.c @@ -542,6 +542,9 @@ if (cp == NULL) return; + while (bus_get_resource_start(dev, SYS_RES_MEMORY, cp->ar_nmem)) + cp->ar_nmem++; + bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length); } Index: sys/dev/pci/pci_host_generic.c =================================================================== --- sys/dev/pci/pci_host_generic.c +++ sys/dev/pci/pci_host_generic.c @@ -71,7 +71,7 @@ /* Forward prototypes */ -static uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot, +uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes); static void generic_pcie_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int bytes); @@ -107,7 +107,7 @@ return (error); rid = 0; - sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->res == NULL) { device_printf(dev, "could not map memory.\n"); return (ENXIO); @@ -137,7 +137,7 @@ return (0); } -static uint32_t +uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { @@ -226,8 +226,7 @@ sc = device_get_softc(dev); if (index == PCIB_IVAR_BUS) { - /* this pcib adds only pci bus 0 as child */ - secondary_bus = 0; + secondary_bus = sc->ecam * 0x80; *result = secondary_bus; return (0); Index: sys/dev/pci/pci_host_generic_acpi.c =================================================================== --- sys/dev/pci/pci_host_generic_acpi.c +++ sys/dev/pci/pci_host_generic_acpi.c @@ -1,10 +1,10 @@ /*- + * Copyright (C) 2018 Cavium Inc. * Copyright (c) 2015 Ruslan Bukin * Copyright (c) 2014 The FreeBSD Foundation * All rights reserved. * - * This software was developed by Semihalf under - * the sponsorship of the FreeBSD Foundation. + * Developed by Semihalf. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -93,15 +93,36 @@ ACPI_BUFFER ap_prt; /* interrupt routing table */ }; +typedef void (*pci_host_generic_acpi_quirk_function)(device_t); + +struct pci_host_generic_acpi_quirk_entry { + int impl; + int part; + int var; + int rev; + pci_host_generic_acpi_quirk_function func; +}; + /* Forward prototypes */ static int generic_pcie_acpi_probe(device_t dev); -static uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot, +uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes); static void generic_pcie_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int bytes); static int generic_pcie_release_resource(device_t dev, device_t child, int type, int rid, struct resource *res); +static void pci_host_generic_acpi_apply_quirks(device_t); +static void thunderx2_ahci_bar_quirk(device_t); +static void thunderx2_ecam_base_quirk(device_t); + +struct pci_host_generic_acpi_quirk_entry pci_host_generic_acpi_quirks[] = +{ + {CPU_IMPL_CAVIUM, CPU_PART_THUNDERX2, 0, 0, thunderx2_ecam_base_quirk}, + {CPU_IMPL_CAVIUM, CPU_PART_THUNDERX2, 0, 0, thunderx2_ahci_bar_quirk}, + {0, 0, 0, 0, NULL} +}; + static int generic_pcie_acpi_probe(device_t dev) @@ -127,6 +148,8 @@ { struct generic_pcie_acpi_softc *sc; ACPI_HANDLE handle; + struct resource *res; + int rid; int error; sc = device_get_softc(dev); @@ -144,10 +167,63 @@ if (error != 0) return (error); + /* + * All subsequent memory regions represent PCIe Memory Windows. + */ + for (rid = 1; rid < 4; rid++) { + res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_UNMAPPED); + if (res == NULL) + break; + error = rman_manage_region(&sc->base.mem_rman, + rman_get_start(res), rman_get_end(res)); + if (error) { + device_printf(dev, "unable to allocate %lx-%lx range\n", + rman_get_start(res), rman_get_end(res)); + return (ENXIO); + } + device_printf(dev, "allocating %lx-%lx range\n", rman_get_start(res), rman_get_end(res)); + } + device_add_child(dev, "pci", -1); + pci_host_generic_acpi_apply_quirks(dev); + return (bus_generic_attach(dev)); } +static void +pci_host_generic_acpi_apply_quirks(device_t dev) +{ + struct pci_host_generic_acpi_quirk_entry *quirk; + + quirk = pci_host_generic_acpi_quirks; + while (1) { + if (quirk->impl == 0) + break; + + if (CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK, + quirk->impl, quirk->part, quirk->var, quirk->rev) && + quirk->func != NULL) + quirk->func(dev); + + quirk++; + } +} + +static uint32_t +pci_host_generic_acpi_read_config(device_t dev, u_int bus, u_int slot, + u_int func, u_int reg, int bytes) +{ + + /* + * XXX: + * Disable AHCI on socket#2 on ThunderX boards. + */ + if (bus == 0x80 && slot == 0x10) + return ~0; + + return generic_pcie_read_config(dev, bus, slot, func, reg, bytes); +} + static int generic_pcie_acpi_route_interrupt(device_t bus, device_t dev, int pin) { @@ -178,6 +254,8 @@ pci_host_generic_acpi_alloc_resource(device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { + struct resource *res = NULL; + #if defined(NEW_PCIB) && defined(PCI_RES_BUS) struct generic_pcie_acpi_softc *sc; @@ -188,8 +266,15 @@ } #endif - return (bus_generic_alloc_resource(dev, child, type, rid, start, end, - count, flags)); + if (type == SYS_RES_MEMORY) + res = pci_host_generic_core_alloc_resource(dev, child, type, + rid, start, end, count, flags); + + if (res == NULL) + res = bus_generic_alloc_resource(dev, child, type, rid, start, end, + count, flags); + + return (res); } static int @@ -314,6 +399,7 @@ DEVMETHOD(pcib_alloc_msi, generic_pcie_acpi_alloc_msi), DEVMETHOD(pcib_release_msi, generic_pcie_acpi_release_msi), DEVMETHOD(pcib_alloc_msix, generic_pcie_acpi_alloc_msix), + DEVMETHOD(pcib_read_config, pci_host_generic_acpi_read_config), DEVMETHOD(pcib_release_msix, generic_pcie_acpi_release_msix), DEVMETHOD(pcib_map_msi, generic_pcie_acpi_map_msi), DEVMETHOD(pcib_get_id, generic_pcie_acpi_get_id), @@ -328,3 +414,33 @@ DRIVER_MODULE(pcib, acpi, generic_pcie_acpi_driver, generic_pcie_acpi_devclass, 0, 0); + +static void thunderx2_ahci_bar_quirk(device_t dev) +{ + + /* + * XXX: + * On ThunderX2, AHCI BAR2 address is wrong. It needs to precisely + * match the one described in datasheet. Fixup it unconditionally. + */ + if (device_get_unit(dev) == 0) { + device_printf(dev, "running AHCI BAR fixup\n"); + PCIB_WRITE_CONFIG(dev, 0, 16, 0, 0x18, 0x01440000, 4); + PCIB_WRITE_CONFIG(dev, 0, 16, 0, 0x1c, 0x40, 4); + PCIB_WRITE_CONFIG(dev, 0, 16, 1, 0x18, 0x01450000, 4); + PCIB_WRITE_CONFIG(dev, 0, 16, 1, 0x1c, 0x40, 4); + } +} + +static void thunderx2_ecam_base_quirk(device_t dev) +{ + struct generic_pcie_acpi_softc *sc; + + sc = device_get_softc(dev); + /* + * XXX: + * On Thunder X2, pcib16 is a beginning of second ECAM domain. + */ + if (device_get_unit(dev) == 16) + sc->base.ecam = 1; +}