Index: sys/dev/pci/pci.c =================================================================== --- sys/dev/pci/pci.c +++ sys/dev/pci/pci.c @@ -80,6 +80,8 @@ #include "pcib_if.h" #include "pci_if.h" +#define PCI_MAX_FUNC_ALIASES 255 + #define PCIR_IS_BIOS(cfg, reg) \ (((cfg)->hdrtype == PCIM_HDRTYPE_NORMAL && reg == PCIR_BIOS) || \ ((cfg)->hdrtype == PCIM_HDRTYPE_BRIDGE && reg == PCIR_BIOS_1)) @@ -502,6 +504,81 @@ return (retval); } +static pcicfgregs * +pci_dev_to_cfg(device_t dev) +{ + struct pci_devinfo *dinfo; + pcicfgregs *cfg; + bool found; + + found = false; + + STAILQ_FOREACH(dinfo, &pci_devq, pci_links) { + if (dinfo->cfg.dev == dev) { + found = true; + break; + } + } + + if (!found) + return (NULL); + + cfg = &dinfo->cfg; + + return (cfg); +} + +int +pci_add_dma_alias(device_t dev, uint8_t devfn_from, uint8_t nr_devfns) +{ + pcicfgregs *cfg; + + if (nr_devfns == 0) + return (EINVAL); + + if ((devfn_from + nr_devfns - 1) > PCI_MAX_FUNC_ALIASES) + return (EINVAL); + + cfg = pci_dev_to_cfg(dev); + if (cfg == NULL) + return (ENODEV); + + mtx_lock_spin(&cfg->dma_aliases_mtx); + bit_nset(cfg->dma_aliases, devfn_from, nr_devfns); + mtx_unlock_spin(&cfg->dma_aliases_mtx); + + return (0); +} + +int +pci_for_each_dma_alias(device_t dev, int (*fn)(device_t dev, + uint8_t alias, void *data), void *data) +{ + pcicfgregs *cfg; + int n; + + cfg = pci_dev_to_cfg(dev); + if (cfg == NULL) + return (ENODEV); + + if (cfg->dma_aliases == NULL) + return (ENOENT); + + mtx_lock_spin(&cfg->dma_aliases_mtx); + bit_ffs_at(cfg->dma_aliases, 0, PCI_MAX_FUNC_ALIASES, &n); + mtx_unlock_spin(&cfg->dma_aliases_mtx); + + while (n >= 0) { + fn(dev, n, data); + + mtx_lock_spin(&cfg->dma_aliases_mtx); + bit_ffs_at(cfg->dma_aliases, n + 1, PCI_MAX_FUNC_ALIASES, &n); + mtx_unlock_spin(&cfg->dma_aliases_mtx); + } + + return (0); +} + /* return base address of memory or port map */ static pci_addr_t @@ -705,6 +782,10 @@ cfg->iov = NULL; + mtx_init(&cfg->dma_aliases_mtx, "alias bit set", NULL, MTX_SPIN); + cfg->dma_aliases = bit_alloc(PCI_MAX_FUNC_ALIASES, M_DEVBUF, + M_WAITOK | M_ZERO); + pci_fixancient(cfg); pci_hdrtypedata(pcib, b, s, f, cfg); @@ -2717,6 +2798,8 @@ free(pm, M_DEVBUF); } STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); + mtx_destroy(&dinfo->cfg.dma_aliases_mtx); + free(&dinfo->cfg.dma_aliases, M_DEVBUF); free(dinfo, M_DEVBUF); /* increment the generation count */ Index: sys/dev/pci/pcivar.h =================================================================== --- sys/dev/pci/pcivar.h +++ sys/dev/pci/pcivar.h @@ -31,6 +31,7 @@ #ifndef _PCIVAR_H_ #define _PCIVAR_H_ +#include #include #include @@ -212,6 +213,9 @@ uint32_t flags; /* flags defined above */ + bitstr_t *dma_aliases; /* PCI function aliases for IOMMU. */ + struct mtx dma_aliases_mtx; /* protection for aliases bitstr */ + struct pcicfg_bridge bridge; /* Bridges */ struct pcicfg_pp pp; /* Power management */ struct pcicfg_vpd vpd; /* Vital product data */ @@ -694,6 +698,10 @@ void pci_print_faulted_dev(void); +int pci_add_dma_alias(device_t dev, uint8_t devfn_from, uint8_t nr_devfns); +int pci_for_each_dma_alias(device_t dev, int (*fn)(device_t dev, + uint8_t alias, void *data), void *data); + #endif /* _SYS_BUS_H_ */ /*