summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Grall <julien.grall@arm.com>2019-05-01 09:58:19 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2019-05-03 10:19:46 -0400
commitece6e6f0218b7777e650bf93728130ae6f4feb7d (patch)
tree40260544d7b400f04aa5f89df961c55aac8ac96e
parentaaebdf8d68479f78d9f72b239684f70fbb0722c6 (diff)
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>
-rw-r--r--drivers/iommu/Kconfig1
-rw-r--r--drivers/iommu/dma-iommu.c46
-rw-r--r--include/linux/dma-iommu.h25
3 files changed, 63 insertions, 9 deletions
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 6f07f3b21816..eb1c8cd243f9 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -94,6 +94,7 @@ config IOMMU_DMA
94 bool 94 bool
95 select IOMMU_API 95 select IOMMU_API
96 select IOMMU_IOVA 96 select IOMMU_IOVA
97 select IRQ_MSI_IOMMU
97 select NEED_SG_DMA_LENGTH 98 select NEED_SG_DMA_LENGTH
98 99
99config FSL_PAMU 100config FSL_PAMU
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 77aabe637a60..f847904098f7 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -888,17 +888,18 @@ out_free_page:
888 return NULL; 888 return NULL;
889} 889}
890 890
891void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) 891int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr)
892{ 892{
893 struct device *dev = msi_desc_to_dev(irq_get_msi_desc(irq)); 893 struct device *dev = msi_desc_to_dev(desc);
894 struct iommu_domain *domain = iommu_get_domain_for_dev(dev); 894 struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
895 struct iommu_dma_cookie *cookie; 895 struct iommu_dma_cookie *cookie;
896 struct iommu_dma_msi_page *msi_page; 896 struct iommu_dma_msi_page *msi_page;
897 phys_addr_t msi_addr = (u64)msg->address_hi << 32 | msg->address_lo;
898 unsigned long flags; 897 unsigned long flags;
899 898
900 if (!domain || !domain->iova_cookie) 899 if (!domain || !domain->iova_cookie) {
901 return; 900 desc->iommu_cookie = NULL;
901 return 0;
902 }
902 903
903 cookie = domain->iova_cookie; 904 cookie = domain->iova_cookie;
904 905
@@ -911,7 +912,36 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
911 msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain); 912 msi_page = iommu_dma_get_msi_page(dev, msi_addr, domain);
912 spin_unlock_irqrestore(&cookie->msi_lock, flags); 913 spin_unlock_irqrestore(&cookie->msi_lock, flags);
913 914
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
922void 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
939void 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))) {
915 /* 945 /*
916 * We're called from a void callback, so the best we can do is 946 * We're called from a void callback, so the best we can do is
917 * 'fail' by filling the message with obviously bogus values. 947 * '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)
922 msg->address_lo = ~0U; 952 msg->address_lo = ~0U;
923 msg->data = ~0U; 953 msg->data = ~0U;
924 } else { 954 } else {
925 msg->address_hi = upper_32_bits(msi_page->iova); 955 iommu_dma_compose_msi_msg(desc, msg);
926 msg->address_lo &= cookie_msi_granule(cookie) - 1;
927 msg->address_lo += lower_32_bits(msi_page->iova);
928 } 956 }
929} 957}
diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h
index e760dc5d1fa8..0b781a98ee73 100644
--- a/include/linux/dma-iommu.h
+++ b/include/linux/dma-iommu.h
@@ -71,12 +71,26 @@ void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
71 size_t size, enum dma_data_direction dir, unsigned long attrs); 71 size_t size, enum dma_data_direction dir, unsigned long attrs);
72 72
73/* The DMA API isn't _quite_ the whole story, though... */ 73/* 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 */
81int iommu_dma_prepare_msi(struct msi_desc *desc, phys_addr_t msi_addr);
82
83/* Update the MSI message if required. */
84void iommu_dma_compose_msi_msg(struct msi_desc *desc,
85 struct msi_msg *msg);
86
74void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg); 87void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg);
75void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list); 88void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
76 89
77#else 90#else
78 91
79struct iommu_domain; 92struct iommu_domain;
93struct msi_desc;
80struct msi_msg; 94struct msi_msg;
81struct device; 95struct device;
82 96
@@ -99,6 +113,17 @@ static inline void iommu_put_dma_cookie(struct iommu_domain *domain)
99{ 113{
100} 114}
101 115
116static inline int iommu_dma_prepare_msi(struct msi_desc *desc,
117 phys_addr_t msi_addr)
118{
119 return 0;
120}
121
122static inline void iommu_dma_compose_msi_msg(struct msi_desc *desc,
123 struct msi_msg *msg)
124{
125}
126
102static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) 127static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg)
103{ 128{
104} 129}