[PATCH v2 03/14] iommu/dma: Add iommu_dma_sw_map_msi()
Andrew Jones <[email protected]> Fri, 24 Jul 2026 17:12:07 +0200
| Newsgroups | dev.linux.lists.iommu,org.infradead.lists.linux-riscv,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Add a descriptor-free counterpart to iommu_dma_sw_msi(). The existing function is tied to a struct msi_desc and stores the result in the descriptor. This variant returns the IOVA directly so callers can pre-map MSI targets before any descriptor has been allocated. Callers may pass a required mapping size so MSI doorbells that must not share a larger IOMMU leaf, such as RISC-V IMSIC files, can fail before a mapping is installed. Signed-off-by: Andrew Jones <[email protected]> --- drivers/iommu/dma-iommu.c | 39 +++++++++++++++++++++++++++++++-------- drivers/iommu/dma-iommu.h | 12 ++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 9abaec0703ef..c26b071d744a 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -2234,24 +2234,47 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, return NULL; } -int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc, - phys_addr_t msi_addr) +int iommu_dma_sw_map_msi(struct iommu_domain *domain, + struct device *dev, phys_addr_t msi_addr, + size_t required_size, dma_addr_t *msi_iova, + unsigned int *msi_shift) { - struct device *dev = msi_desc_to_dev(desc); const struct iommu_dma_msi_page *msi_page; + size_t size; - if (!has_msi_cookie(domain)) { - msi_desc_set_iommu_msi_iova(desc, 0, 0); + *msi_iova = 0; + *msi_shift = 0; + + if (!has_msi_cookie(domain)) return 0; - } + + size = cookie_msi_granule(domain); + if (required_size && size != required_size) + return -EOPNOTSUPP; iommu_group_mutex_assert(dev); msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain); if (!msi_page) return -ENOMEM; - msi_desc_set_iommu_msi_iova(desc, msi_page->iova, - ilog2(cookie_msi_granule(domain))); + *msi_iova = msi_page->iova; + *msi_shift = ilog2(size); + return 0; +} + +int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc, + phys_addr_t msi_addr) +{ + struct device *dev = msi_desc_to_dev(desc); + dma_addr_t msi_iova; + unsigned int msi_shift; + int ret; + + ret = iommu_dma_sw_map_msi(domain, dev, msi_addr, 0, &msi_iova, &msi_shift); + if (ret) + return ret; + + msi_desc_set_iommu_msi_iova(desc, msi_iova, msi_shift); return 0; } diff --git a/drivers/iommu/dma-iommu.h b/drivers/iommu/dma-iommu.h index 040d00252563..3e1adeafdcac 100644 --- a/drivers/iommu/dma-iommu.h +++ b/drivers/iommu/dma-iommu.h @@ -19,6 +19,10 @@ int iommu_dma_init_fq(struct iommu_domain *domain); void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list); +int iommu_dma_sw_map_msi(struct iommu_domain *domain, + struct device *dev, phys_addr_t msi_addr, + size_t required_size, dma_addr_t *msi_iova, + unsigned int *msi_shift); int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc, phys_addr_t msi_addr); @@ -53,6 +57,14 @@ static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_he { } +static inline int iommu_dma_sw_map_msi(struct iommu_domain *domain, + struct device *dev, phys_addr_t msi_addr, + size_t required_size, dma_addr_t *msi_iova, + unsigned int *msi_shift) +{ + return -ENODEV; +} + static inline int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc, phys_addr_t msi_addr) { -- 2.43.0