Index: sys/dev/ofw/ofw_bus_subr.h =================================================================== --- sys/dev/ofw/ofw_bus_subr.h +++ sys/dev/ofw/ofw_bus_subr.h @@ -92,8 +92,9 @@ int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *, void *, void *, int, phandle_t *); -/* Routines for processing msi maps */ +/* Routines for processing msi and iommu maps. */ int ofw_bus_msimap(phandle_t, uint16_t, phandle_t *, uint32_t *); +int ofw_bus_iommu_map(phandle_t, uint16_t, phandle_t *, uint32_t *); /* Routines for parsing device-tree data into resource lists. */ int ofw_bus_reg_to_rl(device_t, phandle_t, pcell_t, pcell_t, Index: sys/dev/ofw/ofw_bus_subr.c =================================================================== --- sys/dev/ofw/ofw_bus_subr.c +++ sys/dev/ofw/ofw_bus_subr.c @@ -491,6 +491,50 @@ return (err); } +int +ofw_bus_iommu_map(phandle_t node, uint16_t pci_rid, phandle_t *iommu_parent, + uint32_t *iommu_rid) +{ + pcell_t mask, iommu_base, rid_base, rid_length; + uint32_t masked_rid; + pcell_t map[4]; + ssize_t len; + int err, i; + + len = OF_getproplen(node, "iommu-map"); + if (len <= 0) + return (ENOENT); + if (len > sizeof(map)) + return (ENOMEM); + + len = OF_getencprop(node, "iommu-map", map, 16); + + err = ENOENT; + mask = 0xffffffff; + OF_getencprop(node, "iommu-map-mask", &mask, sizeof(mask)); + + masked_rid = pci_rid & mask; + for (i = 0; i < len; i += 4) { + rid_base = map[i + 0]; + rid_length = map[i + 3]; + + if (masked_rid < rid_base || + masked_rid >= (rid_base + rid_length)) + continue; + + iommu_base = map[i + 2]; + + if (iommu_parent != NULL) + *iommu_parent = map[i + 1]; + if (iommu_rid != NULL) + *iommu_rid = masked_rid - rid_base + iommu_base; + err = 0; + break; + } + + return (err); +} + static int ofw_bus_reg_to_rl_helper(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, struct resource_list *rl, const char *reg_source) Index: sys/dev/pci/pci.c =================================================================== --- sys/dev/pci/pci.c +++ sys/dev/pci/pci.c @@ -138,6 +138,8 @@ static int pci_get_id_method(device_t dev, device_t child, enum pci_id_type type, uintptr_t *rid); +static int pci_get_iommu_method(device_t dev, device_t child, + uint32_t *id, uint32_t *xref); static struct pci_devinfo * pci_fill_devinfo(device_t pcib, device_t bus, int d, int b, int s, int f, uint16_t vid, uint16_t did); @@ -213,6 +215,7 @@ DEVMETHOD(pci_msix_pba_bar, pci_msix_pba_bar_method), DEVMETHOD(pci_msix_table_bar, pci_msix_table_bar_method), DEVMETHOD(pci_get_id, pci_get_id_method), + DEVMETHOD(pci_get_iommu, pci_get_iommu_method), DEVMETHOD(pci_alloc_devinfo, pci_alloc_devinfo_method), DEVMETHOD(pci_child_added, pci_child_added_method), #ifdef PCI_IOV @@ -6327,6 +6330,13 @@ return (PCIB_GET_ID(device_get_parent(dev), child, type, id)); } +static int +pci_get_iommu_method(device_t dev, device_t child, uint32_t *id, uint32_t *xref) +{ + + return (PCIB_GET_IOMMU(device_get_parent(dev), child, id, xref)); +} + /* Find the upstream port of a given PCI device in a root complex. */ device_t pci_find_pcie_root_port(device_t dev) Index: sys/dev/pci/pci_host_generic_fdt.c =================================================================== --- sys/dev/pci/pci_host_generic_fdt.c +++ sys/dev/pci/pci_host_generic_fdt.c @@ -373,6 +373,28 @@ #endif } +static int +generic_pcie_get_iommu(device_t pci, device_t child, uint32_t *id, + uint32_t *xref) +{ + uint32_t iommu_rid; + uint32_t iommu_xref; + uint16_t pci_rid; + phandle_t node; + int err; + + node = ofw_bus_get_node(pci); + pci_rid = pci_get_rid(child); + + err = ofw_bus_iommu_map(node, pci_rid, &iommu_xref, &iommu_rid); + if (err == 0) { + *id = iommu_rid; + *xref = iommu_xref; + } + + return (err); +} + int generic_pcie_get_id(device_t pci, device_t child, enum pci_id_type type, uintptr_t *id) @@ -466,6 +488,7 @@ 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), + DEVMETHOD(pcib_get_iommu, generic_pcie_get_iommu), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), DEVMETHOD(ofw_bus_get_devinfo, generic_pcie_ofw_get_devinfo), Index: sys/dev/pci/pci_if.m =================================================================== --- sys/dev/pci/pci_if.m +++ sys/dev/pci/pci_if.m @@ -250,6 +250,13 @@ uintptr_t *id; }; +METHOD int get_iommu { + device_t dev; + device_t child; + uint32_t *id; + uint32_t *xref; +}; + METHOD struct pci_devinfo * alloc_devinfo { device_t dev; }; Index: sys/dev/pci/pcib_if.m =================================================================== --- sys/dev/pci/pcib_if.m +++ sys/dev/pci/pcib_if.m @@ -186,6 +186,16 @@ uintptr_t *id; } DEFAULT pcib_get_id; +# +# Return the IOMMU Identifier and IOMMU Reference for the device. +# +METHOD int get_iommu { + device_t pcib; + device_t dev; + uint32_t *id; + uint32_t *xref; +} DEFAULT pcib_get_iommu; + # # Enable Alternative RID Interpretation if both the downstream port (pcib) # and the endpoint device (dev) both support it. Index: sys/dev/pci/pcib_private.h =================================================================== --- sys/dev/pci/pcib_private.h +++ sys/dev/pci/pcib_private.h @@ -197,6 +197,7 @@ int pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data); int pcib_get_id(device_t pcib, device_t dev, enum pci_id_type type, uintptr_t *id); +int pcib_get_iommu(device_t pcib, device_t dev, uint32_t *id, uint32_t *xref); void pcib_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot, int *func); int pcib_request_feature(device_t dev, enum pci_feature feature); Index: sys/dev/pci/pcib_support.c =================================================================== --- sys/dev/pci/pcib_support.c +++ sys/dev/pci/pcib_support.c @@ -70,6 +70,13 @@ return (0); } +int +pcib_get_iommu(device_t pcib, device_t dev, uint32_t *id, uint32_t *xref) +{ + + return (PCI_GET_IOMMU(device_get_parent(pcib), dev, id, xref)); +} + void pcib_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot, int *func) Index: sys/dev/pci/pcivar.h =================================================================== --- sys/dev/pci/pcivar.h +++ sys/dev/pci/pcivar.h @@ -639,6 +639,12 @@ return (PCI_GET_ID(device_get_parent(dev), dev, type, id)); } +static __inline int +pci_get_iommu(device_t dev, uint32_t *id, uint32_t *xref) +{ + return (PCI_GET_IOMMU(device_get_parent(dev), dev, id, xref)); +} + /* * This is the deprecated interface, there is no way to tell the difference * between a failure and a valid value that happens to be the same as the