Skip to content

Commit 288683c

Browse files
committed
iommu: Make iommu_dma_prepare_msi() into a generic operation
SW_MSI supports IOMMU to translate an MSI message before the MSI message is delivered to the interrupt controller. On such systems, an iommu_domain must have a translation for the MSI message for interrupts to work. The IRQ subsystem will call into IOMMU to request that a physical page be set up to receive MSI messages, and the IOMMU then sets an IOVA that maps to that physical page. Ultimately the IOVA is programmed into the device via the msi_msg. Generalize this by allowing iommu_domain owners to provide implementations of this mapping. Add a function pointer in struct iommu_domain to allow a domain owner to provide its own implementation. Have dma-iommu supply its implementation for IOMMU_DOMAIN_DMA types during the iommu_get_dma_cookie() path. For IOMMU_DOMAIN_UNMANAGED types used by VFIO (and iommufd for now), have the same iommu_dma_sw_msi set as well in the iommu_get_msi_cookie() path. Hold the group mutex while in iommu_dma_prepare_msi() to ensure the domain doesn't change or become freed while running. Races with IRQ operations from VFIO and domain changes from iommufd are possible here. Replace the msi_prepare_lock with a lockdep assertion for the group mutex as documentation. For the dmau_iommu.c each iommu_domain is unique to a group. Link: https://patch.msgid.link/r/4ca696150d2baee03af27c4ddefdb7b0b0280e7b.1740014950.git.nicolinc@nvidia.com Signed-off-by: Nicolin Chen <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 9349887 commit 288683c

File tree

3 files changed

+73
-33
lines changed

3 files changed

+73
-33
lines changed

drivers/iommu/dma-iommu.c

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/memremap.h>
2525
#include <linux/mm.h>
2626
#include <linux/mutex.h>
27+
#include <linux/msi.h>
2728
#include <linux/of_iommu.h>
2829
#include <linux/pci.h>
2930
#include <linux/scatterlist.h>
@@ -102,6 +103,9 @@ static int __init iommu_dma_forcedac_setup(char *str)
102103
}
103104
early_param("iommu.forcedac", iommu_dma_forcedac_setup);
104105

106+
static int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
107+
phys_addr_t msi_addr);
108+
105109
/* Number of entries per flush queue */
106110
#define IOVA_DEFAULT_FQ_SIZE 256
107111
#define IOVA_SINGLE_FQ_SIZE 32768
@@ -398,6 +402,7 @@ int iommu_get_dma_cookie(struct iommu_domain *domain)
398402
return -ENOMEM;
399403

400404
mutex_init(&domain->iova_cookie->mutex);
405+
iommu_domain_set_sw_msi(domain, iommu_dma_sw_msi);
401406
return 0;
402407
}
403408

@@ -429,6 +434,7 @@ int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base)
429434

430435
cookie->msi_iova = base;
431436
domain->iova_cookie = cookie;
437+
iommu_domain_set_sw_msi(domain, iommu_dma_sw_msi);
432438
return 0;
433439
}
434440
EXPORT_SYMBOL(iommu_get_msi_cookie);
@@ -443,6 +449,9 @@ void iommu_put_dma_cookie(struct iommu_domain *domain)
443449
struct iommu_dma_cookie *cookie = domain->iova_cookie;
444450
struct iommu_dma_msi_page *msi, *tmp;
445451

452+
if (domain->sw_msi != iommu_dma_sw_msi)
453+
return;
454+
446455
if (!cookie)
447456
return;
448457

@@ -1800,33 +1809,19 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
18001809
return NULL;
18011810
}
18021811

1803-
/**
1804-
* iommu_dma_prepare_msi() - Map the MSI page in the IOMMU domain
1805-
* @desc: MSI descriptor, will store the MSI page
1806-
* @msi_addr: MSI target address to be mapped
1807-
*
1808-
* Return: 0 on success or negative error code if the mapping failed.
1809-
*/
1810-
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
1812+
static int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
1813+
phys_addr_t msi_addr)
18111814
{
18121815
struct device *dev = msi_desc_to_dev(desc);
1813-
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
1814-
struct iommu_dma_msi_page *msi_page;
1815-
static DEFINE_MUTEX(msi_prepare_lock); /* see below */
1816+
const struct iommu_dma_msi_page *msi_page;
18161817

1817-
if (!domain || !domain->iova_cookie) {
1818+
if (!domain->iova_cookie) {
18181819
msi_desc_set_iommu_msi_iova(desc, 0, 0);
18191820
return 0;
18201821
}
18211822

1822-
/*
1823-
* In fact the whole prepare operation should already be serialised by
1824-
* irq_domain_mutex further up the callchain, but that's pretty subtle
1825-
* on its own, so consider this locking as failsafe documentation...
1826-
*/
1827-
mutex_lock(&msi_prepare_lock);
1823+
iommu_group_mutex_assert(dev);
18281824
msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain);
1829-
mutex_unlock(&msi_prepare_lock);
18301825
if (!msi_page)
18311826
return -ENOMEM;
18321827

drivers/iommu/iommu.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3596,3 +3596,32 @@ int iommu_replace_group_handle(struct iommu_group *group,
35963596
return ret;
35973597
}
35983598
EXPORT_SYMBOL_NS_GPL(iommu_replace_group_handle, "IOMMUFD_INTERNAL");
3599+
3600+
#if IS_ENABLED(CONFIG_IRQ_MSI_IOMMU)
3601+
/**
3602+
* iommu_dma_prepare_msi() - Map the MSI page in the IOMMU domain
3603+
* @desc: MSI descriptor, will store the MSI page
3604+
* @msi_addr: MSI target address to be mapped
3605+
*
3606+
* The implementation of sw_msi() should take msi_addr and map it to
3607+
* an IOVA in the domain and call msi_desc_set_iommu_msi_iova() with the
3608+
* mapping information.
3609+
*
3610+
* Return: 0 on success or negative error code if the mapping failed.
3611+
*/
3612+
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
3613+
{
3614+
struct device *dev = msi_desc_to_dev(desc);
3615+
struct iommu_group *group = dev->iommu_group;
3616+
int ret = 0;
3617+
3618+
if (!group)
3619+
return 0;
3620+
3621+
mutex_lock(&group->mutex);
3622+
if (group->domain && group->domain->sw_msi)
3623+
ret = group->domain->sw_msi(group->domain, desc, msi_addr);
3624+
mutex_unlock(&group->mutex);
3625+
return ret;
3626+
}
3627+
#endif /* CONFIG_IRQ_MSI_IOMMU */

include/linux/iommu.h

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ struct iommu_dma_cookie;
4444
struct iommu_fault_param;
4545
struct iommufd_ctx;
4646
struct iommufd_viommu;
47+
struct msi_desc;
48+
struct msi_msg;
4749

4850
#define IOMMU_FAULT_PERM_READ (1 << 0) /* read */
4951
#define IOMMU_FAULT_PERM_WRITE (1 << 1) /* write */
@@ -216,6 +218,12 @@ struct iommu_domain {
216218
struct iommu_domain_geometry geometry;
217219
struct iommu_dma_cookie *iova_cookie;
218220
int (*iopf_handler)(struct iopf_group *group);
221+
222+
#if IS_ENABLED(CONFIG_IRQ_MSI_IOMMU)
223+
int (*sw_msi)(struct iommu_domain *domain, struct msi_desc *desc,
224+
phys_addr_t msi_addr);
225+
#endif
226+
219227
void *fault_data;
220228
union {
221229
struct {
@@ -234,6 +242,16 @@ struct iommu_domain {
234242
};
235243
};
236244

245+
static inline void iommu_domain_set_sw_msi(
246+
struct iommu_domain *domain,
247+
int (*sw_msi)(struct iommu_domain *domain, struct msi_desc *desc,
248+
phys_addr_t msi_addr))
249+
{
250+
#if IS_ENABLED(CONFIG_IRQ_MSI_IOMMU)
251+
domain->sw_msi = sw_msi;
252+
#endif
253+
}
254+
237255
static inline bool iommu_is_dma_domain(struct iommu_domain *domain)
238256
{
239257
return domain->type & __IOMMU_DOMAIN_DMA_API;
@@ -1470,6 +1488,18 @@ static inline ioasid_t iommu_alloc_global_pasid(struct device *dev)
14701488
static inline void iommu_free_global_pasid(ioasid_t pasid) {}
14711489
#endif /* CONFIG_IOMMU_API */
14721490

1491+
#ifdef CONFIG_IRQ_MSI_IOMMU
1492+
#ifdef CONFIG_IOMMU_API
1493+
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr);
1494+
#else
1495+
static inline int iommu_dma_prepare_msi(struct msi_desc *desc,
1496+
phys_addr_t msi_addr)
1497+
{
1498+
return 0;
1499+
}
1500+
#endif /* CONFIG_IOMMU_API */
1501+
#endif /* CONFIG_IRQ_MSI_IOMMU */
1502+
14731503
#if IS_ENABLED(CONFIG_LOCKDEP) && IS_ENABLED(CONFIG_IOMMU_API)
14741504
void iommu_group_mutex_assert(struct device *dev);
14751505
#else
@@ -1503,26 +1533,12 @@ static inline void iommu_debugfs_setup(void) {}
15031533
#endif
15041534

15051535
#ifdef CONFIG_IOMMU_DMA
1506-
#include <linux/msi.h>
1507-
15081536
int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base);
1509-
1510-
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr);
1511-
15121537
#else /* CONFIG_IOMMU_DMA */
1513-
1514-
struct msi_desc;
1515-
struct msi_msg;
1516-
15171538
static inline int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base)
15181539
{
15191540
return -ENODEV;
15201541
}
1521-
1522-
static inline int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
1523-
{
1524-
return 0;
1525-
}
15261542
#endif /* CONFIG_IOMMU_DMA */
15271543

15281544
/*

0 commit comments

Comments
 (0)