diff options
-rw-r--r-- | drivers/iommu/Kconfig | 1 | ||||
-rw-r--r-- | drivers/iommu/dma-iommu.c | 46 | ||||
-rw-r--r-- | include/linux/dma-iommu.h | 25 |
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 | ||
99 | config FSL_PAMU | 100 | config 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 | ||
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) |
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 | |||
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))) { | ||
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 | */ | ||
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 | |||
74 | void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg); | 87 | void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg); |
75 | void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list); | 88 | void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list); |
76 | 89 | ||
77 | #else | 90 | #else |
78 | 91 | ||
79 | struct iommu_domain; | 92 | struct iommu_domain; |
93 | struct msi_desc; | ||
80 | struct msi_msg; | 94 | struct msi_msg; |
81 | struct device; | 95 | struct device; |
82 | 96 | ||
@@ -99,6 +113,17 @@ static inline void iommu_put_dma_cookie(struct iommu_domain *domain) | |||
99 | { | 113 | { |
100 | } | 114 | } |
101 | 115 | ||
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 | |||
102 | static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) | 127 | static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) |
103 | { | 128 | { |
104 | } | 129 | } |