diff options
| -rw-r--r-- | drivers/iommu/dma-iommu.c | 54 |
1 files changed, 25 insertions, 29 deletions
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index f05f3cf90756..ddcbbdb5d658 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c | |||
| @@ -167,40 +167,16 @@ EXPORT_SYMBOL(iommu_put_dma_cookie); | |||
| 167 | * @list: Reserved region list from iommu_get_resv_regions() | 167 | * @list: Reserved region list from iommu_get_resv_regions() |
| 168 | * | 168 | * |
| 169 | * IOMMU drivers can use this to implement their .get_resv_regions callback | 169 | * IOMMU drivers can use this to implement their .get_resv_regions callback |
| 170 | * for general non-IOMMU-specific reservations. Currently, this covers host | 170 | * for general non-IOMMU-specific reservations. Currently, this covers GICv3 |
| 171 | * bridge windows for PCI devices and GICv3 ITS region reservation on ACPI | 171 | * ITS region reservation on ACPI based ARM platforms that may require HW MSI |
| 172 | * based ARM platforms that may require HW MSI reservation. | 172 | * reservation. |
| 173 | */ | 173 | */ |
| 174 | void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list) | 174 | void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list) |
| 175 | { | 175 | { |
| 176 | struct pci_host_bridge *bridge; | ||
| 177 | struct resource_entry *window; | ||
| 178 | |||
| 179 | if (!is_of_node(dev->iommu_fwspec->iommu_fwnode) && | ||
| 180 | iort_iommu_msi_get_resv_regions(dev, list) < 0) | ||
| 181 | return; | ||
| 182 | |||
| 183 | if (!dev_is_pci(dev)) | ||
| 184 | return; | ||
| 185 | |||
| 186 | bridge = pci_find_host_bridge(to_pci_dev(dev)->bus); | ||
| 187 | resource_list_for_each_entry(window, &bridge->windows) { | ||
| 188 | struct iommu_resv_region *region; | ||
| 189 | phys_addr_t start; | ||
| 190 | size_t length; | ||
| 191 | |||
| 192 | if (resource_type(window->res) != IORESOURCE_MEM) | ||
| 193 | continue; | ||
| 194 | 176 | ||
| 195 | start = window->res->start - window->offset; | 177 | if (!is_of_node(dev->iommu_fwspec->iommu_fwnode)) |
| 196 | length = window->res->end - window->res->start + 1; | 178 | iort_iommu_msi_get_resv_regions(dev, list); |
| 197 | region = iommu_alloc_resv_region(start, length, 0, | ||
| 198 | IOMMU_RESV_RESERVED); | ||
| 199 | if (!region) | ||
| 200 | return; | ||
| 201 | 179 | ||
| 202 | list_add_tail(®ion->list, list); | ||
| 203 | } | ||
| 204 | } | 180 | } |
| 205 | EXPORT_SYMBOL(iommu_dma_get_resv_regions); | 181 | EXPORT_SYMBOL(iommu_dma_get_resv_regions); |
| 206 | 182 | ||
| @@ -229,6 +205,23 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie, | |||
| 229 | return 0; | 205 | return 0; |
| 230 | } | 206 | } |
| 231 | 207 | ||
| 208 | static void iova_reserve_pci_windows(struct pci_dev *dev, | ||
| 209 | struct iova_domain *iovad) | ||
| 210 | { | ||
| 211 | struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus); | ||
| 212 | struct resource_entry *window; | ||
| 213 | unsigned long lo, hi; | ||
| 214 | |||
| 215 | resource_list_for_each_entry(window, &bridge->windows) { | ||
| 216 | if (resource_type(window->res) != IORESOURCE_MEM) | ||
| 217 | continue; | ||
| 218 | |||
| 219 | lo = iova_pfn(iovad, window->res->start - window->offset); | ||
| 220 | hi = iova_pfn(iovad, window->res->end - window->offset); | ||
| 221 | reserve_iova(iovad, lo, hi); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 232 | static int iova_reserve_iommu_regions(struct device *dev, | 225 | static int iova_reserve_iommu_regions(struct device *dev, |
| 233 | struct iommu_domain *domain) | 226 | struct iommu_domain *domain) |
| 234 | { | 227 | { |
| @@ -238,6 +231,9 @@ static int iova_reserve_iommu_regions(struct device *dev, | |||
| 238 | LIST_HEAD(resv_regions); | 231 | LIST_HEAD(resv_regions); |
| 239 | int ret = 0; | 232 | int ret = 0; |
| 240 | 233 | ||
| 234 | if (dev_is_pci(dev)) | ||
| 235 | iova_reserve_pci_windows(to_pci_dev(dev), iovad); | ||
| 236 | |||
| 241 | iommu_get_resv_regions(dev, &resv_regions); | 237 | iommu_get_resv_regions(dev, &resv_regions); |
| 242 | list_for_each_entry(region, &resv_regions, list) { | 238 | list_for_each_entry(region, &resv_regions, list) { |
| 243 | unsigned long lo, hi; | 239 | unsigned long lo, hi; |
