Index: head/sys/arm/annapurna/alpine/alpine_pci.c =================================================================== --- head/sys/arm/annapurna/alpine/alpine_pci.c +++ head/sys/arm/annapurna/alpine/alpine_pci.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -79,7 +80,7 @@ }; DEFINE_CLASS_1(pcib, al_pcib_driver, al_pcib_methods, - sizeof(struct generic_pcie_softc), generic_pcie_driver); + sizeof(struct generic_pcie_fdt_softc), generic_pcie_fdt_driver); static devclass_t anpa_pcib_devclass; Index: head/sys/arm64/cavium/thunder_pcie_common.c =================================================================== --- head/sys/arm64/cavium/thunder_pcie_common.c +++ head/sys/arm64/cavium/thunder_pcie_common.c @@ -58,6 +58,9 @@ #include #include #include +#ifdef FDT +#include +#endif #include "thunder_pcie_common.h" Index: head/sys/arm64/cavium/thunder_pcie_fdt.c =================================================================== --- head/sys/arm64/cavium/thunder_pcie_fdt.c +++ head/sys/arm64/cavium/thunder_pcie_fdt.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include "thunder_pcie_common.h" @@ -80,7 +81,7 @@ }; DEFINE_CLASS_1(pcib, thunder_pcie_fdt_driver, thunder_pcie_fdt_methods, - sizeof(struct generic_pcie_softc), generic_pcie_driver); + sizeof(struct generic_pcie_fdt_softc), generic_pcie_fdt_driver); static devclass_t thunder_pcie_fdt_devclass; @@ -115,11 +116,11 @@ static int thunder_pcie_fdt_attach(device_t dev) { - struct generic_pcie_softc *sc; + struct generic_pcie_fdt_softc *sc; sc = device_get_softc(dev); - thunder_pcie_identify_ecam(dev, &sc->ecam); - sc->coherent = 1; + thunder_pcie_identify_ecam(dev, &sc->base.ecam); + sc->base.coherent = 1; return (pci_host_generic_attach(dev)); } Index: head/sys/conf/files.arm =================================================================== --- head/sys/conf/files.arm +++ head/sys/conf/files.arm @@ -124,7 +124,8 @@ dev/hwpmc/hwpmc_armv7.c optional hwpmc armv6 dev/iicbus/twsi/twsi.c optional twsi dev/ofw/ofwpci.c optional fdt pci -dev/pci/pci_host_generic.c optional pci_host_generic pci fdt +dev/pci/pci_host_generic.c optional pci_host_generic pci +dev/pci/pci_host_generic_fdt.c optional pci_host_generic pci fdt dev/psci/psci.c optional psci dev/psci/psci_arm.S optional psci dev/syscons/scgfbrndr.c optional sc Index: head/sys/conf/files.arm64 =================================================================== --- head/sys/conf/files.arm64 +++ head/sys/conf/files.arm64 @@ -154,8 +154,9 @@ dev/mmc/host/dwmmc_hisi.c optional dwmmc fdt soc_hisi_hi6220 dev/ofw/ofw_cpu.c optional fdt dev/ofw/ofwpci.c optional fdt pci -dev/pci/pci_host_generic.c optional pci fdt -dev/psci/psci.c optional psci +dev/pci/pci_host_generic.c optional pci +dev/pci/pci_host_generic_fdt.c optional pci fdt +dev/psci/psci.c optional psci fdt dev/psci/psci_arm64.S optional psci dev/uart/uart_cpu_arm64.c optional uart dev/uart/uart_dev_pl011.c optional uart pl011 Index: head/sys/dev/pci/pci_host_generic.h =================================================================== --- head/sys/dev/pci/pci_host_generic.h +++ head/sys/dev/pci/pci_host_generic.h @@ -48,7 +48,7 @@ #define FLAG_MEM (1 << 1) }; -struct generic_pcie_softc { +struct generic_pcie_core_softc { struct pcie_range ranges[MAX_RANGES_TUPLES]; int nranges; int coherent; @@ -62,17 +62,16 @@ device_t dev; bus_space_handle_t ioh; bus_dma_tag_t dmat; -#ifdef FDT - struct ofw_bus_iinfo pci_iinfo; -#endif }; -extern devclass_t generic_pcie_devclass; -DECLARE_CLASS(generic_pcie_driver); +DECLARE_CLASS(generic_pcie_core_driver); -struct resource *pci_host_generic_alloc_resource(device_t, +struct resource *pci_host_generic_core_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); -int pci_host_generic_attach(device_t); -int generic_pcie_get_id(device_t, device_t, enum pci_id_type, uintptr_t *); +int pci_host_generic_core_attach(device_t); +struct resource *pci_host_generic_core_alloc_resource(device_t, device_t, int, + int *, rman_res_t, rman_res_t, rman_res_t, u_int); +int pci_host_generic_core_release_resource(device_t, device_t, int, int, + struct resource *); #endif /* __PCI_HOST_GENERIC_H_ */ Index: head/sys/dev/pci/pci_host_generic.c =================================================================== --- head/sys/dev/pci/pci_host_generic.c +++ head/sys/dev/pci/pci_host_generic.c @@ -43,26 +43,14 @@ #include #include #include -#include -#include -#if defined(INTRNG) -#include -#endif - -#include -#include -#include -#include #include #include #include #include -#include #include #include -#include #include "pcib_if.h" @@ -81,24 +69,8 @@ (((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT) | \ ((reg) & PCIE_REG_MASK)) -#define PCI_IO_WINDOW_OFFSET 0x1000 - -#define SPACE_CODE_SHIFT 24 -#define SPACE_CODE_MASK 0x3 -#define SPACE_CODE_IO_SPACE 0x1 -#define PROPS_CELL_SIZE 1 -#define PCI_ADDR_CELL_SIZE 2 - -/* OFW bus interface */ -struct generic_pcie_ofw_devinfo { - struct ofw_bus_devinfo di_dinfo; - struct resource_list di_rl; -}; - /* Forward prototypes */ -static int generic_pcie_probe(device_t dev); -static int parse_pci_mem_ranges(struct generic_pcie_softc *sc); static 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, @@ -108,87 +80,17 @@ uintptr_t *result); static int generic_pcie_write_ivar(device_t dev, device_t child, int index, uintptr_t value); -static struct resource *generic_pcie_alloc_resource_ofw(device_t, device_t, - int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); -static struct resource *generic_pcie_alloc_resource_pcie(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); -static int generic_pcie_release_resource(device_t dev, device_t child, - int type, int rid, struct resource *res); -static int generic_pcie_release_resource_ofw(device_t, device_t, int, int, - struct resource *); -static int generic_pcie_release_resource_pcie(device_t, device_t, int, int, - struct resource *); -static int generic_pcie_ofw_bus_attach(device_t); -static const struct ofw_bus_devinfo *generic_pcie_ofw_get_devinfo(device_t, - device_t); - -static __inline void -get_addr_size_cells(phandle_t node, pcell_t *addr_cells, pcell_t *size_cells) -{ - - *addr_cells = 2; - /* Find address cells if present */ - OF_getencprop(node, "#address-cells", addr_cells, sizeof(*addr_cells)); - - *size_cells = 2; - /* Find size cells if present */ - OF_getencprop(node, "#size-cells", size_cells, sizeof(*size_cells)); -} - -static int -generic_pcie_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (ofw_bus_is_compatible(dev, "pci-host-ecam-generic")) { - device_set_desc(dev, "Generic PCI host controller"); - return (BUS_PROBE_GENERIC); - } - if (ofw_bus_is_compatible(dev, "arm,gem5_pcie")) { - device_set_desc(dev, "GEM5 PCIe host controller"); - return (BUS_PROBE_DEFAULT); - } - - return (ENXIO); -} int -pci_host_generic_attach(device_t dev) +pci_host_generic_core_attach(device_t dev) { - struct generic_pcie_softc *sc; - uint64_t phys_base; - uint64_t pci_base; - uint64_t size; - phandle_t node; + struct generic_pcie_core_softc *sc; int error; - int tuple; int rid; sc = device_get_softc(dev); sc->dev = dev; - /* Retrieve 'ranges' property from FDT */ - if (bootverbose) - device_printf(dev, "parsing FDT for ECAM%d:\n", - sc->ecam); - if (parse_pci_mem_ranges(sc)) - return (ENXIO); - - /* Attach OFW bus */ - if (generic_pcie_ofw_bus_attach(dev) != 0) - return (ENXIO); - - node = ofw_bus_get_node(dev); - if (sc->coherent == 0) { - sc->coherent = OF_hasprop(node, "dma-coherent"); - } - if (bootverbose) - device_printf(dev, "Bus is%s cache-coherent\n", - sc->coherent ? "" : " not"); - /* Create the parent DMA tag to pass down the coherent flag */ error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 1, 0, /* alignment, bounds */ @@ -232,111 +134,6 @@ return (error); } - for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) { - phys_base = sc->ranges[tuple].phys_base; - pci_base = sc->ranges[tuple].pci_base; - size = sc->ranges[tuple].size; - if (phys_base == 0 || size == 0) - continue; /* empty range element */ - if (sc->ranges[tuple].flags & FLAG_MEM) { - error = rman_manage_region(&sc->mem_rman, - phys_base, phys_base + size - 1); - } else if (sc->ranges[tuple].flags & FLAG_IO) { - error = rman_manage_region(&sc->io_rman, - pci_base + PCI_IO_WINDOW_OFFSET, - pci_base + PCI_IO_WINDOW_OFFSET + size - 1); - } else - continue; - if (error) { - device_printf(dev, "rman_manage_region() failed." - "error = %d\n", error); - rman_fini(&sc->mem_rman); - return (error); - } - } - - ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(cell_t)); - - device_add_child(dev, "pci", -1); - return (bus_generic_attach(dev)); -} - -static int -parse_pci_mem_ranges(struct generic_pcie_softc *sc) -{ - pcell_t pci_addr_cells, parent_addr_cells; - pcell_t attributes, size_cells; - cell_t *base_ranges; - int nbase_ranges; - phandle_t node; - int i, j, k; - int tuple; - - node = ofw_bus_get_node(sc->dev); - - OF_getencprop(node, "#address-cells", &pci_addr_cells, - sizeof(pci_addr_cells)); - OF_getencprop(node, "#size-cells", &size_cells, - sizeof(size_cells)); - OF_getencprop(OF_parent(node), "#address-cells", &parent_addr_cells, - sizeof(parent_addr_cells)); - - if (parent_addr_cells > 2 || pci_addr_cells != 3 || size_cells > 2) { - device_printf(sc->dev, - "Unexpected number of address or size cells in FDT\n"); - return (ENXIO); - } - - nbase_ranges = OF_getproplen(node, "ranges"); - sc->nranges = nbase_ranges / sizeof(cell_t) / - (parent_addr_cells + pci_addr_cells + size_cells); - base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); - OF_getencprop(node, "ranges", base_ranges, nbase_ranges); - - for (i = 0, j = 0; i < sc->nranges; i++) { - attributes = (base_ranges[j++] >> SPACE_CODE_SHIFT) & \ - SPACE_CODE_MASK; - if (attributes == SPACE_CODE_IO_SPACE) { - sc->ranges[i].flags |= FLAG_IO; - } else { - sc->ranges[i].flags |= FLAG_MEM; - } - - sc->ranges[i].pci_base = 0; - for (k = 0; k < (pci_addr_cells - 1); k++) { - sc->ranges[i].pci_base <<= 32; - sc->ranges[i].pci_base |= base_ranges[j++]; - } - sc->ranges[i].phys_base = 0; - for (k = 0; k < parent_addr_cells; k++) { - sc->ranges[i].phys_base <<= 32; - sc->ranges[i].phys_base |= base_ranges[j++]; - } - sc->ranges[i].size = 0; - for (k = 0; k < size_cells; k++) { - sc->ranges[i].size <<= 32; - sc->ranges[i].size |= base_ranges[j++]; - } - } - - for (; i < MAX_RANGES_TUPLES; i++) { - /* zero-fill remaining tuples to mark empty elements in array */ - sc->ranges[i].pci_base = 0; - sc->ranges[i].phys_base = 0; - sc->ranges[i].size = 0; - } - - if (bootverbose) { - for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) { - device_printf(sc->dev, - "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx\n", - sc->ranges[tuple].pci_base, - sc->ranges[tuple].phys_base, - sc->ranges[tuple].size); - } - } - - free(base_ranges, M_DEVBUF); return (0); } @@ -344,7 +141,7 @@ generic_pcie_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { - struct generic_pcie_softc *sc; + struct generic_pcie_core_softc *sc; bus_space_handle_t h; bus_space_tag_t t; uint64_t offset; @@ -381,7 +178,7 @@ generic_pcie_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int bytes) { - struct generic_pcie_softc *sc; + struct generic_pcie_core_softc *sc; bus_space_handle_t h; bus_space_tag_t t; uint64_t offset; @@ -420,41 +217,10 @@ } static int -generic_pcie_route_interrupt(device_t bus, device_t dev, int pin) -{ - struct generic_pcie_softc *sc; - struct ofw_pci_register reg; - uint32_t pintr, mintr[2]; - phandle_t iparent; - int intrcells; - - sc = device_get_softc(bus); - pintr = pin; - - bzero(®, sizeof(reg)); - reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | - (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | - (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); - - intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), - &sc->pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), - mintr, sizeof(mintr), &iparent); - if (intrcells) { - pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr); - return (pintr); - } - - device_printf(bus, "could not route pin %d for device %d.%d\n", - pin, pci_get_slot(dev), pci_get_function(dev)); - return (PCI_INVALID_IRQ); -} - - -static int generic_pcie_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) { - struct generic_pcie_softc *sc; + struct generic_pcie_core_softc *sc; int secondary_bus; sc = device_get_softc(dev); @@ -486,7 +252,7 @@ } static struct rman * -generic_pcie_rman(struct generic_pcie_softc *sc, int type) +generic_pcie_rman(struct generic_pcie_core_softc *sc, int type) { switch (type) { @@ -501,15 +267,21 @@ return (NULL); } -static int -generic_pcie_release_resource_pcie(device_t dev, device_t child, int type, +int +pci_host_generic_core_release_resource(device_t dev, device_t child, int type, int rid, struct resource *res) { - struct generic_pcie_softc *sc; + struct generic_pcie_core_softc *sc; struct rman *rm; sc = device_get_softc(dev); +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + if (type == PCI_RES_BUS) { + return (pci_domain_release_bus(sc->ecam, child, rid, res)); + } +#endif + rm = generic_pcie_rman(sc, type); if (rm != NULL) { KASSERT(rman_is_region_manager(res, rm), ("rman mismatch")); @@ -519,61 +291,22 @@ return (bus_generic_release_resource(dev, child, type, rid, res)); } -static int -generic_pcie_release_resource(device_t dev, device_t child, int type, - int rid, struct resource *res) +struct resource * +pci_host_generic_core_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) { -#if defined(NEW_PCIB) && defined(PCI_RES_BUS) - struct generic_pcie_softc *sc; - - if (type == PCI_RES_BUS) { - sc = device_get_softc(dev); - return (pci_domain_release_bus(sc->ecam, child, rid, res)); - } -#endif - /* For PCIe devices that do not have FDT nodes, use PCIB method */ - if ((int)ofw_bus_get_node(child) <= 0) { - return (generic_pcie_release_resource_pcie(dev, - child, type, rid, res)); - } + struct generic_pcie_core_softc *sc; + struct resource *res; + struct rman *rm; - /* For other devices use OFW method */ - return (generic_pcie_release_resource_ofw(dev, - child, type, rid, res)); -} + sc = device_get_softc(dev); -struct resource * -pci_host_generic_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) -{ #if defined(NEW_PCIB) && defined(PCI_RES_BUS) - struct generic_pcie_softc *sc; - if (type == PCI_RES_BUS) { - sc = device_get_softc(dev); return (pci_domain_alloc_bus(sc->ecam, child, rid, start, end, count, flags)); } #endif - /* For PCIe devices that do not have FDT nodes, use PCIB method */ - if ((int)ofw_bus_get_node(child) <= 0) - return (generic_pcie_alloc_resource_pcie(dev, child, type, rid, - start, end, count, flags)); - - /* For other devices use OFW method */ - return (generic_pcie_alloc_resource_ofw(dev, child, type, rid, - start, end, count, flags)); -} - -static struct resource * -generic_pcie_alloc_resource_pcie(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 generic_pcie_softc *sc; - struct resource *res; - struct rman *rm; - - sc = device_get_softc(dev); rm = generic_pcie_rman(sc, type); if (rm == NULL) @@ -612,7 +345,7 @@ generic_pcie_adjust_resource(device_t dev, device_t child, int type, struct resource *res, rman_res_t start, rman_res_t end) { - struct generic_pcie_softc *sc; + struct generic_pcie_core_softc *sc; struct rman *rm; sc = device_get_softc(dev); @@ -628,194 +361,22 @@ return (bus_generic_adjust_resource(dev, child, type, res, start, end)); } -static int -generic_pcie_activate_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) -{ - struct generic_pcie_softc *sc; - uint64_t phys_base; - uint64_t pci_base; - uint64_t size; - int found; - int res; - int i; - - sc = device_get_softc(dev); - - if ((res = rman_activate_resource(r)) != 0) - return (res); - - switch(type) { - case SYS_RES_IOPORT: - found = 0; - for (i = 0; i < MAX_RANGES_TUPLES; i++) { - pci_base = sc->ranges[i].pci_base; - phys_base = sc->ranges[i].phys_base; - size = sc->ranges[i].size; - - if ((rid > pci_base) && (rid < (pci_base + size))) { - found = 1; - break; - } - } - if (found) { - rman_set_start(r, rman_get_start(r) + phys_base); - rman_set_end(r, rman_get_end(r) + phys_base); - BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, - type, rid, r); - } else { - device_printf(dev, "Failed to activate IOPORT resource\n"); - res = 0; - } - break; - case SYS_RES_MEMORY: - BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, type, rid, r); - break; - default: - break; - } - - return (res); -} - -static int -generic_pcie_deactivate_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) -{ - struct generic_pcie_softc *sc; - vm_offset_t vaddr; - int res; - - sc = device_get_softc(dev); - - if ((res = rman_deactivate_resource(r)) != 0) - return (res); - - switch(type) { - case SYS_RES_IOPORT: - case SYS_RES_MEMORY: - vaddr = (vm_offset_t)rman_get_virtual(r); - pmap_unmapdev(vaddr, rman_get_size(r)); - break; - default: - break; - } - - return (res); -} - static bus_dma_tag_t generic_pcie_get_dma_tag(device_t dev, device_t child) { - struct generic_pcie_softc *sc; + struct generic_pcie_core_softc *sc; sc = device_get_softc(dev); return (sc->dmat); } -static int -generic_pcie_alloc_msi(device_t pci, device_t child, int count, int maxcount, - int *irqs) -{ -#if defined(INTRNG) - phandle_t msi_parent; - - ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, - NULL); - return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, - irqs)); -#else - return (ENXIO); -#endif -} - -static int -generic_pcie_release_msi(device_t pci, device_t child, int count, int *irqs) -{ -#if defined(INTRNG) - phandle_t msi_parent; - - ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, - NULL); - return (intr_release_msi(pci, child, msi_parent, count, irqs)); -#else - return (ENXIO); -#endif -} - -static int -generic_pcie_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, - uint32_t *data) -{ -#if defined(INTRNG) - phandle_t msi_parent; - - ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, - NULL); - return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); -#else - return (ENXIO); -#endif -} - -static int -generic_pcie_alloc_msix(device_t pci, device_t child, int *irq) -{ -#if defined(INTRNG) - phandle_t msi_parent; - - ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, - NULL); - return (intr_alloc_msix(pci, child, msi_parent, irq)); -#else - return (ENXIO); -#endif -} - -static int -generic_pcie_release_msix(device_t pci, device_t child, int irq) -{ -#if defined(INTRNG) - phandle_t msi_parent; - - ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, - NULL); - return (intr_release_msix(pci, child, msi_parent, irq)); -#else - return (ENXIO); -#endif -} - -int -generic_pcie_get_id(device_t pci, device_t child, enum pci_id_type type, - uintptr_t *id) -{ - phandle_t node; - uint32_t rid; - uint16_t pci_rid; - - if (type != PCI_ID_MSI) - return (pcib_get_id(pci, child, type, id)); - - node = ofw_bus_get_node(pci); - pci_rid = pci_get_rid(child); - - ofw_bus_msimap(node, pci_rid, NULL, &rid); - *id = rid; - - return (0); -} - static device_method_t generic_pcie_methods[] = { - DEVMETHOD(device_probe, generic_pcie_probe), - DEVMETHOD(device_attach, pci_host_generic_attach), + DEVMETHOD(device_attach, pci_host_generic_core_attach), DEVMETHOD(bus_read_ivar, generic_pcie_read_ivar), DEVMETHOD(bus_write_ivar, generic_pcie_write_ivar), - DEVMETHOD(bus_alloc_resource, pci_host_generic_alloc_resource), + DEVMETHOD(bus_alloc_resource, pci_host_generic_core_alloc_resource), DEVMETHOD(bus_adjust_resource, generic_pcie_adjust_resource), - DEVMETHOD(bus_release_resource, generic_pcie_release_resource), - DEVMETHOD(bus_activate_resource, generic_pcie_activate_resource), - DEVMETHOD(bus_deactivate_resource, generic_pcie_deactivate_resource), + DEVMETHOD(bus_release_resource, pci_host_generic_core_release_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), @@ -823,147 +384,11 @@ /* pcib interface */ DEVMETHOD(pcib_maxslots, generic_pcie_maxslots), - DEVMETHOD(pcib_route_interrupt, generic_pcie_route_interrupt), DEVMETHOD(pcib_read_config, generic_pcie_read_config), DEVMETHOD(pcib_write_config, generic_pcie_write_config), - DEVMETHOD(pcib_alloc_msi, generic_pcie_alloc_msi), - DEVMETHOD(pcib_release_msi, generic_pcie_release_msi), - DEVMETHOD(pcib_alloc_msix, generic_pcie_alloc_msix), - DEVMETHOD(pcib_release_msix, generic_pcie_release_msix), - DEVMETHOD(pcib_map_msi, generic_pcie_map_msi), - DEVMETHOD(pcib_get_id, generic_pcie_get_id), - - /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_devinfo, generic_pcie_ofw_get_devinfo), - DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), - DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), - DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), - DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), - DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), DEVMETHOD_END }; -static const struct ofw_bus_devinfo * -generic_pcie_ofw_get_devinfo(device_t bus __unused, device_t child) -{ - struct generic_pcie_ofw_devinfo *di; - - di = device_get_ivars(child); - return (&di->di_dinfo); -} - -static struct resource * -generic_pcie_alloc_resource_ofw(device_t bus, device_t child, int type, int *rid, - rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) -{ - struct generic_pcie_softc *sc; - struct generic_pcie_ofw_devinfo *di; - struct resource_list_entry *rle; - int i; - - sc = device_get_softc(bus); - - if (RMAN_IS_DEFAULT_RANGE(start, end)) { - if ((di = device_get_ivars(child)) == NULL) - return (NULL); - if (type == SYS_RES_IOPORT) - type = SYS_RES_MEMORY; - - /* Find defaults for this rid */ - rle = resource_list_find(&di->di_rl, type, *rid); - if (rle == NULL) - return (NULL); - - start = rle->start; - end = rle->end; - count = rle->count; - } - - if (type == SYS_RES_MEMORY) { - /* Remap through ranges property */ - for (i = 0; i < MAX_RANGES_TUPLES; i++) { - if (start >= sc->ranges[i].phys_base && end < - sc->ranges[i].pci_base + sc->ranges[i].size) { - start -= sc->ranges[i].phys_base; - start += sc->ranges[i].pci_base; - end -= sc->ranges[i].phys_base; - end += sc->ranges[i].pci_base; - break; - } - } - - if (i == MAX_RANGES_TUPLES) { - device_printf(bus, "Could not map resource " - "%#jx-%#jx\n", start, end); - return (NULL); - } - } - - return (bus_generic_alloc_resource(bus, child, type, rid, start, end, - count, flags)); -} - -static int -generic_pcie_release_resource_ofw(device_t bus, device_t child, int type, int rid, - struct resource *res) -{ - - return (bus_generic_release_resource(bus, child, type, rid, res)); -} - -/* Helper functions */ - -static int -generic_pcie_ofw_bus_attach(device_t dev) -{ - struct generic_pcie_ofw_devinfo *di; - device_t child; - phandle_t parent, node; - pcell_t addr_cells, size_cells; - - parent = ofw_bus_get_node(dev); - if (parent > 0) { - get_addr_size_cells(parent, &addr_cells, &size_cells); - /* Iterate through all bus subordinates */ - for (node = OF_child(parent); node > 0; node = OF_peer(node)) { - - /* Allocate and populate devinfo. */ - di = malloc(sizeof(*di), M_DEVBUF, M_WAITOK | M_ZERO); - if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node) != 0) { - free(di, M_DEVBUF); - continue; - } - - /* Initialize and populate resource list. */ - resource_list_init(&di->di_rl); - ofw_bus_reg_to_rl(dev, node, addr_cells, size_cells, - &di->di_rl); - ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL); - - /* Add newbus device for this FDT node */ - child = device_add_child(dev, NULL, -1); - if (child == NULL) { - resource_list_free(&di->di_rl); - ofw_bus_gen_destroy_devinfo(&di->di_dinfo); - free(di, M_DEVBUF); - continue; - } - - device_set_ivars(child, di); - } - } - - return (0); -} - -DEFINE_CLASS_0(pcib, generic_pcie_driver, - generic_pcie_methods, sizeof(struct generic_pcie_softc)); - -devclass_t generic_pcie_devclass; - -DRIVER_MODULE(pcib, simplebus, generic_pcie_driver, - generic_pcie_devclass, 0, 0); -DRIVER_MODULE(pcib, ofwbus, generic_pcie_driver, - generic_pcie_devclass, 0, 0); - +DEFINE_CLASS_0(pcib, generic_pcie_core_driver, + generic_pcie_methods, sizeof(struct generic_pcie_core_softc)); Index: head/sys/dev/pci/pci_host_generic_fdt.h =================================================================== --- head/sys/dev/pci/pci_host_generic_fdt.h +++ head/sys/dev/pci/pci_host_generic_fdt.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 Ruslan Bukin + * Copyright (c) 2015 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * $FreeBSD$ + * + */ + +#ifndef __PCI_HOST_GENERIC_FDT_H_ +#define __PCI_HOST_GENERIC_FDT_H_ + +struct generic_pcie_fdt_softc { + struct generic_pcie_core_softc base; + struct ofw_bus_iinfo pci_iinfo; +}; + +DECLARE_CLASS(generic_pcie_fdt_driver); + +struct resource *pci_host_generic_alloc_resource(device_t, + device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); +int pci_host_generic_attach(device_t); +int generic_pcie_get_id(device_t, device_t, enum pci_id_type, uintptr_t *); + +#endif /* __PCI_HOST_GENERIC_FDT_H_ */ Index: head/sys/dev/pci/pci_host_generic_fdt.c =================================================================== --- head/sys/dev/pci/pci_host_generic_fdt.c +++ head/sys/dev/pci/pci_host_generic_fdt.c @@ -0,0 +1,641 @@ +/*- + * Copyright (c) 2015 Ruslan Bukin + * Copyright (c) 2014,2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Andrew Turner under + * the sponsorship of the FreeBSD Foundation. + * + * This software was developed by Semihalf under + * the sponsorship of the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Generic ECAM PCIe driver FDT attachment */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_platform.h" + +#include +#include +#include +#include +#include +#include +#include + +#if defined(INTRNG) +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "pcib_if.h" + +#define PCI_IO_WINDOW_OFFSET 0x1000 + +#define SPACE_CODE_SHIFT 24 +#define SPACE_CODE_MASK 0x3 +#define SPACE_CODE_IO_SPACE 0x1 +#define PROPS_CELL_SIZE 1 +#define PCI_ADDR_CELL_SIZE 2 + +/* OFW bus interface */ +struct generic_pcie_ofw_devinfo { + struct ofw_bus_devinfo di_dinfo; + struct resource_list di_rl; +}; + +/* Forward prototypes */ + +static int generic_pcie_fdt_probe(device_t dev); +static int parse_pci_mem_ranges(device_t, struct generic_pcie_core_softc *); +static int generic_pcie_fdt_release_resource(device_t dev, device_t child, + int type, int rid, struct resource *res); +static int generic_pcie_ofw_bus_attach(device_t); +static const struct ofw_bus_devinfo *generic_pcie_ofw_get_devinfo(device_t, + device_t); + +static __inline void +get_addr_size_cells(phandle_t node, pcell_t *addr_cells, pcell_t *size_cells) +{ + + *addr_cells = 2; + /* Find address cells if present */ + OF_getencprop(node, "#address-cells", addr_cells, sizeof(*addr_cells)); + + *size_cells = 2; + /* Find size cells if present */ + OF_getencprop(node, "#size-cells", size_cells, sizeof(*size_cells)); +} + +static int +generic_pcie_fdt_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_is_compatible(dev, "pci-host-ecam-generic")) { + device_set_desc(dev, "Generic PCI host controller"); + return (BUS_PROBE_GENERIC); + } + if (ofw_bus_is_compatible(dev, "arm,gem5_pcie")) { + device_set_desc(dev, "GEM5 PCIe host controller"); + return (BUS_PROBE_DEFAULT); + } + + return (ENXIO); +} + +int +pci_host_generic_attach(device_t dev) +{ + struct generic_pcie_fdt_softc *sc; + uint64_t phys_base; + uint64_t pci_base; + uint64_t size; + phandle_t node; + int error; + int tuple; + + sc = device_get_softc(dev); + + /* Retrieve 'ranges' property from FDT */ + if (bootverbose) + device_printf(dev, "parsing FDT for ECAM%d:\n", sc->base.ecam); + if (parse_pci_mem_ranges(dev, &sc->base)) + return (ENXIO); + + /* Attach OFW bus */ + if (generic_pcie_ofw_bus_attach(dev) != 0) + return (ENXIO); + + node = ofw_bus_get_node(dev); + if (sc->base.coherent == 0) { + sc->base.coherent = OF_hasprop(node, "dma-coherent"); + } + if (bootverbose) + device_printf(dev, "Bus is%s cache-coherent\n", + sc->base.coherent ? "" : " not"); + + error = pci_host_generic_attach(dev); + if (error != 0) + return (error); + + for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) { + phys_base = sc->base.ranges[tuple].phys_base; + pci_base = sc->base.ranges[tuple].pci_base; + size = sc->base.ranges[tuple].size; + if (phys_base == 0 || size == 0) + continue; /* empty range element */ + if (sc->base.ranges[tuple].flags & FLAG_MEM) { + error = rman_manage_region(&sc->base.mem_rman, + phys_base, phys_base + size - 1); + } else if (sc->base.ranges[tuple].flags & FLAG_IO) { + error = rman_manage_region(&sc->base.io_rman, + pci_base + PCI_IO_WINDOW_OFFSET, + pci_base + PCI_IO_WINDOW_OFFSET + size - 1); + } else + continue; + if (error) { + device_printf(dev, "rman_manage_region() failed." + "error = %d\n", error); + rman_fini(&sc->base.mem_rman); + return (error); + } + } + + ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(cell_t)); + + device_add_child(dev, "pci", -1); + return (bus_generic_attach(dev)); +} + +static int +parse_pci_mem_ranges(device_t dev, struct generic_pcie_core_softc *sc) +{ + pcell_t pci_addr_cells, parent_addr_cells; + pcell_t attributes, size_cells; + cell_t *base_ranges; + int nbase_ranges; + phandle_t node; + int i, j, k; + int tuple; + + node = ofw_bus_get_node(dev); + + OF_getencprop(node, "#address-cells", &pci_addr_cells, + sizeof(pci_addr_cells)); + OF_getencprop(node, "#size-cells", &size_cells, + sizeof(size_cells)); + OF_getencprop(OF_parent(node), "#address-cells", &parent_addr_cells, + sizeof(parent_addr_cells)); + + if (parent_addr_cells > 2 || pci_addr_cells != 3 || size_cells > 2) { + device_printf(dev, + "Unexpected number of address or size cells in FDT\n"); + return (ENXIO); + } + + nbase_ranges = OF_getproplen(node, "ranges"); + sc->nranges = nbase_ranges / sizeof(cell_t) / + (parent_addr_cells + pci_addr_cells + size_cells); + base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); + OF_getencprop(node, "ranges", base_ranges, nbase_ranges); + + for (i = 0, j = 0; i < sc->nranges; i++) { + attributes = (base_ranges[j++] >> SPACE_CODE_SHIFT) & \ + SPACE_CODE_MASK; + if (attributes == SPACE_CODE_IO_SPACE) { + sc->ranges[i].flags |= FLAG_IO; + } else { + sc->ranges[i].flags |= FLAG_MEM; + } + + sc->ranges[i].pci_base = 0; + for (k = 0; k < (pci_addr_cells - 1); k++) { + sc->ranges[i].pci_base <<= 32; + sc->ranges[i].pci_base |= base_ranges[j++]; + } + sc->ranges[i].phys_base = 0; + for (k = 0; k < parent_addr_cells; k++) { + sc->ranges[i].phys_base <<= 32; + sc->ranges[i].phys_base |= base_ranges[j++]; + } + sc->ranges[i].size = 0; + for (k = 0; k < size_cells; k++) { + sc->ranges[i].size <<= 32; + sc->ranges[i].size |= base_ranges[j++]; + } + } + + for (; i < MAX_RANGES_TUPLES; i++) { + /* zero-fill remaining tuples to mark empty elements in array */ + sc->ranges[i].pci_base = 0; + sc->ranges[i].phys_base = 0; + sc->ranges[i].size = 0; + } + + if (bootverbose) { + for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) { + device_printf(dev, + "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx\n", + sc->ranges[tuple].pci_base, + sc->ranges[tuple].phys_base, + sc->ranges[tuple].size); + } + } + + free(base_ranges, M_DEVBUF); + return (0); +} + +static int +generic_pcie_fdt_route_interrupt(device_t bus, device_t dev, int pin) +{ + struct generic_pcie_fdt_softc *sc; + struct ofw_pci_register reg; + uint32_t pintr, mintr[2]; + phandle_t iparent; + int intrcells; + + sc = device_get_softc(bus); + pintr = pin; + + bzero(®, sizeof(reg)); + reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | + (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | + (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); + + intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), + &sc->pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), + mintr, sizeof(mintr), &iparent); + if (intrcells) { + pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr); + return (pintr); + } + + device_printf(bus, "could not route pin %d for device %d.%d\n", + pin, pci_get_slot(dev), pci_get_function(dev)); + return (PCI_INVALID_IRQ); +} + +static int +generic_pcie_fdt_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *res) +{ + +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + if (type == PCI_RES_BUS) { + return (pci_host_generic_core_release_resource(dev, child, type, + rid, res)); + } +#endif + + /* For PCIe devices that do not have FDT nodes, use PCIB method */ + if ((int)ofw_bus_get_node(child) <= 0) { + return (pci_host_generic_core_release_resource(dev, child, type, + rid, res)); + } + + /* For other devices use OFW method */ + return (bus_generic_release_resource(dev, child, type, rid, res)); +} + +struct resource * +pci_host_generic_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 generic_pcie_fdt_softc *sc; + struct generic_pcie_ofw_devinfo *di; + struct resource_list_entry *rle; + int i; + +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + if (type == PCI_RES_BUS) { + return (pci_host_generic_alloc_resource(dev, child, type, rid, + start, end, count, flags)); + } +#endif + + /* For PCIe devices that do not have FDT nodes, use PCIB method */ + if ((int)ofw_bus_get_node(child) <= 0) + return (pci_host_generic_alloc_resource(dev, child, type, rid, + start, end, count, flags)); + + /* For other devices use OFW method */ + sc = device_get_softc(dev); + + if (RMAN_IS_DEFAULT_RANGE(start, end)) { + if ((di = device_get_ivars(child)) == NULL) + return (NULL); + if (type == SYS_RES_IOPORT) + type = SYS_RES_MEMORY; + + /* Find defaults for this rid */ + rle = resource_list_find(&di->di_rl, type, *rid); + if (rle == NULL) + return (NULL); + + start = rle->start; + end = rle->end; + count = rle->count; + } + + if (type == SYS_RES_MEMORY) { + /* Remap through ranges property */ + for (i = 0; i < MAX_RANGES_TUPLES; i++) { + if (start >= sc->base.ranges[i].phys_base && + end < (sc->base.ranges[i].pci_base + + sc->base.ranges[i].size)) { + start -= sc->base.ranges[i].phys_base; + start += sc->base.ranges[i].pci_base; + end -= sc->base.ranges[i].phys_base; + end += sc->base.ranges[i].pci_base; + break; + } + } + + if (i == MAX_RANGES_TUPLES) { + device_printf(dev, "Could not map resource " + "%#jx-%#jx\n", start, end); + return (NULL); + } + } + + return (bus_generic_alloc_resource(dev, child, type, rid, start, end, + count, flags)); +} + +static int +generic_pcie_fdt_activate_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + struct generic_pcie_fdt_softc *sc; + uint64_t phys_base; + uint64_t pci_base; + uint64_t size; + int found; + int res; + int i; + + sc = device_get_softc(dev); + + if ((res = rman_activate_resource(r)) != 0) + return (res); + + switch(type) { + case SYS_RES_IOPORT: + found = 0; + for (i = 0; i < MAX_RANGES_TUPLES; i++) { + pci_base = sc->base.ranges[i].pci_base; + phys_base = sc->base.ranges[i].phys_base; + size = sc->base.ranges[i].size; + + if ((rid > pci_base) && (rid < (pci_base + size))) { + found = 1; + break; + } + } + if (found) { + rman_set_start(r, rman_get_start(r) + phys_base); + rman_set_end(r, rman_get_end(r) + phys_base); + res = BUS_ACTIVATE_RESOURCE(device_get_parent(dev), + child, type, rid, r); + } else { + device_printf(dev, + "Failed to activate IOPORT resource\n"); + res = 0; + } + break; + case SYS_RES_MEMORY: + res = BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, + type, rid, r); + break; + default: + break; + } + + return (res); +} + +static int +generic_pcie_fdt_deactivate_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + int res; + + if ((res = rman_deactivate_resource(r)) != 0) + return (res); + + switch(type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + res = BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), child, + type, rid, r); + break; + default: + break; + } + + return (res); +} + +static int +generic_pcie_fdt_alloc_msi(device_t pci, device_t child, int count, + int maxcount, int *irqs) +{ +#if defined(INTRNG) + phandle_t msi_parent; + + ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, + NULL); + return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, + irqs)); +#else + return (ENXIO); +#endif +} + +static int +generic_pcie_fdt_release_msi(device_t pci, device_t child, int count, int *irqs) +{ +#if defined(INTRNG) + phandle_t msi_parent; + + ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, + NULL); + return (intr_release_msi(pci, child, msi_parent, count, irqs)); +#else + return (ENXIO); +#endif +} + +static int +generic_pcie_fdt_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, + uint32_t *data) +{ +#if defined(INTRNG) + phandle_t msi_parent; + + ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, + NULL); + return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); +#else + return (ENXIO); +#endif +} + +static int +generic_pcie_fdt_alloc_msix(device_t pci, device_t child, int *irq) +{ +#if defined(INTRNG) + phandle_t msi_parent; + + ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, + NULL); + return (intr_alloc_msix(pci, child, msi_parent, irq)); +#else + return (ENXIO); +#endif +} + +static int +generic_pcie_fdt_release_msix(device_t pci, device_t child, int irq) +{ +#if defined(INTRNG) + phandle_t msi_parent; + + ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent, + NULL); + return (intr_release_msix(pci, child, msi_parent, irq)); +#else + return (ENXIO); +#endif +} + +int +generic_pcie_get_id(device_t pci, device_t child, enum pci_id_type type, + uintptr_t *id) +{ + phandle_t node; + uint32_t rid; + uint16_t pci_rid; + + if (type != PCI_ID_MSI) + return (pcib_get_id(pci, child, type, id)); + + node = ofw_bus_get_node(pci); + pci_rid = pci_get_rid(child); + + ofw_bus_msimap(node, pci_rid, NULL, &rid); + *id = rid; + + return (0); +} + +static const struct ofw_bus_devinfo * +generic_pcie_ofw_get_devinfo(device_t bus __unused, device_t child) +{ + struct generic_pcie_ofw_devinfo *di; + + di = device_get_ivars(child); + return (&di->di_dinfo); +} + +/* Helper functions */ + +static int +generic_pcie_ofw_bus_attach(device_t dev) +{ + struct generic_pcie_ofw_devinfo *di; + device_t child; + phandle_t parent, node; + pcell_t addr_cells, size_cells; + + parent = ofw_bus_get_node(dev); + if (parent > 0) { + get_addr_size_cells(parent, &addr_cells, &size_cells); + /* Iterate through all bus subordinates */ + for (node = OF_child(parent); node > 0; node = OF_peer(node)) { + + /* Allocate and populate devinfo. */ + di = malloc(sizeof(*di), M_DEVBUF, M_WAITOK | M_ZERO); + if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node) != 0) { + free(di, M_DEVBUF); + continue; + } + + /* Initialize and populate resource list. */ + resource_list_init(&di->di_rl); + ofw_bus_reg_to_rl(dev, node, addr_cells, size_cells, + &di->di_rl); + ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL); + + /* Add newbus device for this FDT node */ + child = device_add_child(dev, NULL, -1); + if (child == NULL) { + resource_list_free(&di->di_rl); + ofw_bus_gen_destroy_devinfo(&di->di_dinfo); + free(di, M_DEVBUF); + continue; + } + + device_set_ivars(child, di); + } + } + + return (0); +} + +static device_method_t generic_pcie_fdt_methods[] = { + DEVMETHOD(device_probe, generic_pcie_fdt_probe), + DEVMETHOD(device_attach, pci_host_generic_attach), + DEVMETHOD(bus_alloc_resource, pci_host_generic_alloc_resource), + DEVMETHOD(bus_release_resource, generic_pcie_fdt_release_resource), + DEVMETHOD(bus_activate_resource, generic_pcie_fdt_activate_resource), + DEVMETHOD(bus_deactivate_resource,generic_pcie_fdt_deactivate_resource), + + /* pcib interface */ + DEVMETHOD(pcib_route_interrupt, generic_pcie_fdt_route_interrupt), + DEVMETHOD(pcib_alloc_msi, generic_pcie_fdt_alloc_msi), + DEVMETHOD(pcib_release_msi, generic_pcie_fdt_release_msi), + DEVMETHOD(pcib_alloc_msix, generic_pcie_fdt_alloc_msix), + DEVMETHOD(pcib_release_msix, generic_pcie_fdt_release_msix), + DEVMETHOD(pcib_map_msi, generic_pcie_fdt_map_msi), + DEVMETHOD(pcib_get_id, generic_pcie_get_id), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_devinfo, generic_pcie_ofw_get_devinfo), + DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), + DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), + DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), + DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), + DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(pcib, generic_pcie_fdt_driver, generic_pcie_fdt_methods, + sizeof(struct generic_pcie_fdt_softc), generic_pcie_core_driver); + +static devclass_t generic_pcie_fdt_devclass; + +DRIVER_MODULE(pcib, simplebus, generic_pcie_fdt_driver, + generic_pcie_fdt_devclass, 0, 0); +DRIVER_MODULE(pcib, ofwbus, generic_pcie_fdt_driver, generic_pcie_fdt_devclass, + 0, 0);