diff --git a/sys/dev/pci/pci_host_generic.h b/sys/dev/pci/pci_host_generic.h --- a/sys/dev/pci/pci_host_generic.h +++ b/sys/dev/pci/pci_host_generic.h @@ -85,8 +85,12 @@ device_t dev; bus_space_handle_t ioh; bus_dma_tag_t dmat; + uint32_t quirks; }; +/* Quirks */ +#define PCIE_ECAM_DESIGNWARE_QUIRK (1 << 0) + DECLARE_CLASS(generic_pcie_core_driver); int pci_host_generic_core_attach(device_t); diff --git a/sys/dev/pci/pci_host_generic.c b/sys/dev/pci/pci_host_generic.c --- a/sys/dev/pci/pci_host_generic.c +++ b/sys/dev/pci/pci_host_generic.c @@ -185,6 +185,8 @@ if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) return (~0U); + if ((sc->quirks & PCIE_ECAM_DESIGNWARE_QUIRK) && bus == 0 && slot > 0) + return (~0U); offset = PCIE_ADDR_OFFSET(bus - sc->bus_start, slot, func, reg); t = sc->bst; diff --git a/sys/dev/pci/pci_host_generic_acpi.c b/sys/dev/pci/pci_host_generic_acpi.c --- a/sys/dev/pci/pci_host_generic_acpi.c +++ b/sys/dev/pci/pci_host_generic_acpi.c @@ -89,6 +89,21 @@ #define PROPS_CELL_SIZE 1 #define PCI_ADDR_CELL_SIZE 2 +static struct { + char oem_id[ACPI_OEM_ID_SIZE + 1]; + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; + uint32_t quirks; +} pci_acpi_quirks[] = { + { "MRVL ", "CN9130 ", PCIE_ECAM_DESIGNWARE_QUIRK }, + { "MRVL ", "CN913X ", PCIE_ECAM_DESIGNWARE_QUIRK }, + { "MVEBU ", "ARMADA7K", PCIE_ECAM_DESIGNWARE_QUIRK }, + { "MVEBU ", "ARMADA8K", PCIE_ECAM_DESIGNWARE_QUIRK }, + { "MVEBU ", "CN9130 ", PCIE_ECAM_DESIGNWARE_QUIRK }, + { "MVEBU ", "CN9131 ", PCIE_ECAM_DESIGNWARE_QUIRK }, + { "MVEBU ", "CN9132 ", PCIE_ECAM_DESIGNWARE_QUIRK }, + { 0 }, +}; + /* Forward prototypes */ static int generic_pcie_acpi_probe(device_t dev); @@ -170,6 +185,23 @@ return (AE_OK); } +static void +pci_host_acpi_get_oem_quirks(struct generic_pcie_acpi_softc *sc, + ACPI_TABLE_HEADER *hdr) +{ + int i; + + for (i = 0; pci_acpi_quirks[i].quirks; i++) { + if (memcmp(hdr->OemId, pci_acpi_quirks[i].oem_id, + ACPI_OEM_ID_SIZE) != 0) + continue; + if (memcmp(hdr->OemTableId, pci_acpi_quirks[i].oem_table_id, + ACPI_OEM_TABLE_ID_SIZE) != 0) + continue; + sc->base.quirks |= pci_acpi_quirks[i].quirks; + } +} + static int pci_host_acpi_get_ecam_resource(device_t dev) { @@ -209,6 +241,7 @@ sc->base.bus_start, sc->base.bus_end); return (ENXIO); } + pci_host_acpi_get_oem_quirks(sc, hdr); } else { status = acpi_GetInteger(handle, "_CBA", &val); if (ACPI_SUCCESS(status)) diff --git a/sys/dev/pci/pci_host_generic_fdt.c b/sys/dev/pci/pci_host_generic_fdt.c --- a/sys/dev/pci/pci_host_generic_fdt.c +++ b/sys/dev/pci/pci_host_generic_fdt.c @@ -151,6 +151,13 @@ if (error != 0) return (error); + if (ofw_bus_is_compatible(dev, "marvell,armada8k-pcie-ecam") || + ofw_bus_is_compatible(dev, "socionext,synquacer-pcie-ecam") || + ofw_bus_is_compatible(dev, "snps,dw-pcie-ecam")) { + device_set_desc(dev, "Synopsys DesignWare PCIe Controller"); + sc->base.quirks |= PCIE_ECAM_DESIGNWARE_QUIRK; + } + ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(cell_t)); return (0);