pci_host_generic: Add Synopsys Designware PCIe controller quirk

Due to the quirky nature of the Synopsys Designware PCIe IP,
the type 0 configuration is broadcast and whatever device
is plugged into slot, will appear at each 32 device
positions of bus0. Mitigate the issue by filtering out
duplicated devices on this bus for both DT and ACPI cases.

Reviewed by: mw
Sponsored by: Semihalf
MFC: after 3 weeks
Differential revision: https://reviews.freebsd.org/D31887
This commit is contained in:
Pawel Anikiel 2021-09-13 16:59:40 +02:00 committed by Marcin Wojtas
parent 41ba691f92
commit 2de4c7f6d0
4 changed files with 46 additions and 0 deletions

View File

@ -185,6 +185,8 @@ generic_pcie_read_config(device_t dev, u_int bus, u_int slot,
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;

View File

@ -85,8 +85,12 @@ struct generic_pcie_core_softc {
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);

View File

@ -89,6 +89,21 @@ __FBSDID("$FreeBSD$");
#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 @@ pci_host_generic_acpi_parse_resource(ACPI_RESOURCE *res, void *arg)
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 @@ pci_host_acpi_get_ecam_resource(device_t dev)
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))

View File

@ -151,6 +151,13 @@ pci_host_generic_setup_fdt(device_t dev)
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);