Skip to content

Commit ece6e6f

Browse files
Julien GrallMarc Zyngier
authored andcommitted
iommu/dma-iommu: Split iommu_dma_map_msi_msg() in two parts
On RT, iommu_dma_map_msi_msg() may be called from non-preemptible context. This will lead to a splat with CONFIG_DEBUG_ATOMIC_SLEEP as the function is using spin_lock (they can sleep on RT). iommu_dma_map_msi_msg() is used to map the MSI page in the IOMMU PT and update the MSI message with the IOVA. Only the part to lookup for the MSI page requires to be called in preemptible context. As the MSI page cannot change over the lifecycle of the MSI interrupt, the lookup can be cached and re-used later on. iomma_dma_map_msi_msg() is now split in two functions: - iommu_dma_prepare_msi(): This function will prepare the mapping in the IOMMU and store the cookie in the structure msi_desc. This function should be called in preemptible context. - iommu_dma_compose_msi_msg(): This function will update the MSI message with the IOVA when the device is behind an IOMMU. Signed-off-by: Julien Grall <julien.grall@arm.com> Reviewed-by: Robin Murphy <robin.murphy@arm.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Acked-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent aaebdf8 commit ece6e6f

File tree

3 files changed

+63
-9
lines changed

3 files changed

+63
-9
lines changed

drivers/iommu/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ config IOMMU_DMA
9494
bool
9595
select IOMMU_API
9696
select IOMMU_IOVA
97+
select IRQ_MSI_IOMMU
9798
select NEED_SG_DMA_LENGTH
9899

99100
config FSL_PAMU

drivers/iommu/dma-iommu.c

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -888,17 +888,18 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
888888
return NULL;
889889
}
890890

891-
void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
891+
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
892892
{
893-
struct device *dev = msi_desc_to_dev(irq_get_msi_desc(irq));
893+
struct device *dev = msi_desc_to_dev(desc);
894894
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
895895
struct iommu_dma_cookie *cookie;
896896
struct iommu_dma_msi_page *msi_page;
897-
phys_addr_t msi_addr = (u64)msg->address_hi << 32 | msg->address_lo;
898897
unsigned long flags;
899898

900-
if (!domain || !domain->iova_cookie)
901-
return;
899+
if (!domain || !domain->iova_cookie) {
900+
desc->iommu_cookie = NULL;
901+
return 0;
902+
}
902903

903904
cookie = domain->iova_cookie;
904905

@@ -911,7 +912,36 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
911912
msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain);
912913
spin_unlock_irqrestore(&cookie->msi_lock, flags);
913914

914-
if (WARN_ON(!msi_page)) {
915+
msi_desc_set_iommu_cookie(desc, msi_page);
916+
917+
if (!msi_page)
918+
return -ENOMEM;
919+
return 0;
920+
}
921+
922+
void iommu_dma_compose_msi_msg(struct msi_desc *desc,
923+
struct msi_msg *msg)
924+
{
925+
struct device *dev = msi_desc_to_dev(desc);
926+
const struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
927+
const struct iommu_dma_msi_page *msi_page;
928+
929+
msi_page = msi_desc_get_iommu_cookie(desc);
930+
931+
if (!domain || !domain->iova_cookie || WARN_ON(!msi_page))
932+
return;
933+
934+
msg->address_hi = upper_32_bits(msi_page->iova);
935+
msg->address_lo &= cookie_msi_granule(domain->iova_cookie) - 1;
936+
msg->address_lo += lower_32_bits(msi_page->iova);
937+
}
938+
939+
void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
940+
{
941+
struct msi_desc *desc = irq_get_msi_desc(irq);
942+
phys_addr_t msi_addr = (u64)msg->address_hi << 32 | msg->address_lo;
943+
944+
if (WARN_ON(iommu_dma_prepare_msi(desc, msi_addr))) {
915945
/*
916946
* We're called from a void callback, so the best we can do is
917947
* 'fail' by filling the message with obviously bogus values.
@@ -922,8 +952,6 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
922952
msg->address_lo = ~0U;
923953
msg->data = ~0U;
924954
} else {
925-
msg->address_hi = upper_32_bits(msi_page->iova);
926-
msg->address_lo &= cookie_msi_granule(cookie) - 1;
927-
msg->address_lo += lower_32_bits(msi_page->iova);
955+
iommu_dma_compose_msi_msg(desc, msg);
928956
}
929957
}

include/linux/dma-iommu.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,26 @@ void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
7171
size_t size, enum dma_data_direction dir, unsigned long attrs);
7272

7373
/* The DMA API isn't _quite_ the whole story, though... */
74+
/*
75+
* iommu_dma_prepare_msi() - Map the MSI page in the IOMMU device
76+
*
77+
* The MSI page will be stored in @desc.
78+
*
79+
* Return: 0 on success otherwise an error describing the failure.
80+
*/
81+
int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr);
82+
83+
/* Update the MSI message if required. */
84+
void iommu_dma_compose_msi_msg(struct msi_desc *desc,
85+
struct msi_msg *msg);
86+
7487
void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg);
7588
void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
7689

7790
#else
7891

7992
struct iommu_domain;
93+
struct msi_desc;
8094
struct msi_msg;
8195
struct device;
8296

@@ -99,6 +113,17 @@ static inline void iommu_put_dma_cookie(struct iommu_domain *domain)
99113
{
100114
}
101115

116+
static inline int iommu_dma_prepare_msi(struct msi_desc *desc,
117+
phys_addr_t msi_addr)
118+
{
119+
return 0;
120+
}
121+
122+
static inline void iommu_dma_compose_msi_msg(struct msi_desc *desc,
123+
struct msi_msg *msg)
124+
{
125+
}
126+
102127
static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
103128
{
104129
}

0 commit comments

Comments
 (0)