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 | } |
