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); @@ -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) { 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 @@ -94,12 +94,48 @@ 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; +}; + +struct pci_host_generic_acpi_block_entry { + int impl; + int part; + int var; + int rev; + int bus; + int slot; +}; + /* 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 ACPI_STATUS pci_host_generic_acpi_parse_resource(ACPI_RESOURCE *, void *); +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} +}; + +struct pci_host_generic_acpi_block_entry pci_host_generic_acpi_blocked[] = +{ + /* ThunderX2 AHCI on second socket */ + {CPU_IMPL_CAVIUM, CPU_PART_THUNDERX2, 0, 0, 0x80, 0x10}, + {0, 0, 0, 0, 0, 0} +}; static int generic_pcie_acpi_probe(device_t dev) @@ -150,6 +186,8 @@ return (ENXIO); device_add_child(dev, "pci", -1); + pci_host_generic_acpi_apply_quirks(dev); + return (bus_generic_attach(dev)); } @@ -186,6 +224,47 @@ return (AE_OK); } +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) +{ + struct pci_host_generic_acpi_block_entry *block; + + block = pci_host_generic_acpi_blocked; + while (1) { + if (block->impl == 0) + break; + + if (CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK, + block->impl, block->part, block->var, block->rev) && + block->bus == bus && block->slot == slot) + return (~0); + + block++; + } + + 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) { @@ -345,6 +424,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), @@ -359,3 +439,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; +}