diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-08 13:07:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-08 13:07:13 -0500 |
commit | e3a00f68e426df24a5fb98956a1bd1b23943aa1e (patch) | |
tree | e796e9bc0d11ed988e5d7c5ec8e2b31e8a5e1987 | |
parent | b58ec8b5824717875b844a9e8cc62fc6eb5fd289 (diff) | |
parent | bea64033dd7b5fb6296eda8266acab6364ce1554 (diff) |
Merge tag 'iommu-fixes-v4.9-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU fixes from Joerg Roedel:
- Four patches from Robin Murphy fix several issues with the recently
merged generic DT-bindings support for arm-smmu drivers
- A fix for a dead-lock issue in the VT-d driver, which shows up on
iommu hotplug
* tag 'iommu-fixes-v4.9-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
iommu/vt-d: Fix dead-locks in disable_dmar_iommu() path
iommu/arm-smmu: Fix out-of-bounds dereference
iommu/arm-smmu: Check that iommu_fwspecs are ours
iommu/arm-smmu: Don't inadvertently reject multiple SMMUv3s
iommu/arm-smmu: Work around ARM DMA configuration
-rw-r--r-- | drivers/iommu/arm-smmu-v3.c | 25 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu.c | 16 | ||||
-rw-r--r-- | drivers/iommu/intel-iommu.c | 14 |
3 files changed, 43 insertions, 12 deletions
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 15c01c3cd540..e6f9b2d745ca 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c | |||
@@ -2636,17 +2636,26 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) | |||
2636 | /* And we're up. Go go go! */ | 2636 | /* And we're up. Go go go! */ |
2637 | of_iommu_set_ops(dev->of_node, &arm_smmu_ops); | 2637 | of_iommu_set_ops(dev->of_node, &arm_smmu_ops); |
2638 | #ifdef CONFIG_PCI | 2638 | #ifdef CONFIG_PCI |
2639 | pci_request_acs(); | 2639 | if (pci_bus_type.iommu_ops != &arm_smmu_ops) { |
2640 | ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops); | 2640 | pci_request_acs(); |
2641 | if (ret) | 2641 | ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops); |
2642 | return ret; | 2642 | if (ret) |
2643 | return ret; | ||
2644 | } | ||
2643 | #endif | 2645 | #endif |
2644 | #ifdef CONFIG_ARM_AMBA | 2646 | #ifdef CONFIG_ARM_AMBA |
2645 | ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops); | 2647 | if (amba_bustype.iommu_ops != &arm_smmu_ops) { |
2646 | if (ret) | 2648 | ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops); |
2647 | return ret; | 2649 | if (ret) |
2650 | return ret; | ||
2651 | } | ||
2648 | #endif | 2652 | #endif |
2649 | return bus_set_iommu(&platform_bus_type, &arm_smmu_ops); | 2653 | if (platform_bus_type.iommu_ops != &arm_smmu_ops) { |
2654 | ret = bus_set_iommu(&platform_bus_type, &arm_smmu_ops); | ||
2655 | if (ret) | ||
2656 | return ret; | ||
2657 | } | ||
2658 | return 0; | ||
2650 | } | 2659 | } |
2651 | 2660 | ||
2652 | static int arm_smmu_device_remove(struct platform_device *pdev) | 2661 | static int arm_smmu_device_remove(struct platform_device *pdev) |
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index c841eb7a1a74..8f7281444551 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c | |||
@@ -324,8 +324,10 @@ struct arm_smmu_master_cfg { | |||
324 | #define INVALID_SMENDX -1 | 324 | #define INVALID_SMENDX -1 |
325 | #define __fwspec_cfg(fw) ((struct arm_smmu_master_cfg *)fw->iommu_priv) | 325 | #define __fwspec_cfg(fw) ((struct arm_smmu_master_cfg *)fw->iommu_priv) |
326 | #define fwspec_smmu(fw) (__fwspec_cfg(fw)->smmu) | 326 | #define fwspec_smmu(fw) (__fwspec_cfg(fw)->smmu) |
327 | #define fwspec_smendx(fw, i) \ | ||
328 | (i >= fw->num_ids ? INVALID_SMENDX : __fwspec_cfg(fw)->smendx[i]) | ||
327 | #define for_each_cfg_sme(fw, i, idx) \ | 329 | #define for_each_cfg_sme(fw, i, idx) \ |
328 | for (i = 0; idx = __fwspec_cfg(fw)->smendx[i], i < fw->num_ids; ++i) | 330 | for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i) |
329 | 331 | ||
330 | struct arm_smmu_device { | 332 | struct arm_smmu_device { |
331 | struct device *dev; | 333 | struct device *dev; |
@@ -1228,6 +1230,16 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) | |||
1228 | return -ENXIO; | 1230 | return -ENXIO; |
1229 | } | 1231 | } |
1230 | 1232 | ||
1233 | /* | ||
1234 | * FIXME: The arch/arm DMA API code tries to attach devices to its own | ||
1235 | * domains between of_xlate() and add_device() - we have no way to cope | ||
1236 | * with that, so until ARM gets converted to rely on groups and default | ||
1237 | * domains, just say no (but more politely than by dereferencing NULL). | ||
1238 | * This should be at least a WARN_ON once that's sorted. | ||
1239 | */ | ||
1240 | if (!fwspec->iommu_priv) | ||
1241 | return -ENODEV; | ||
1242 | |||
1231 | smmu = fwspec_smmu(fwspec); | 1243 | smmu = fwspec_smmu(fwspec); |
1232 | /* Ensure that the domain is finalised */ | 1244 | /* Ensure that the domain is finalised */ |
1233 | ret = arm_smmu_init_domain_context(domain, smmu); | 1245 | ret = arm_smmu_init_domain_context(domain, smmu); |
@@ -1390,7 +1402,7 @@ static int arm_smmu_add_device(struct device *dev) | |||
1390 | fwspec = dev->iommu_fwspec; | 1402 | fwspec = dev->iommu_fwspec; |
1391 | if (ret) | 1403 | if (ret) |
1392 | goto out_free; | 1404 | goto out_free; |
1393 | } else if (fwspec) { | 1405 | } else if (fwspec && fwspec->ops == &arm_smmu_ops) { |
1394 | smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode)); | 1406 | smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode)); |
1395 | } else { | 1407 | } else { |
1396 | return -ENODEV; | 1408 | return -ENODEV; |
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index a4407eabf0e6..3965e73db51c 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
@@ -1711,6 +1711,7 @@ static void disable_dmar_iommu(struct intel_iommu *iommu) | |||
1711 | if (!iommu->domains || !iommu->domain_ids) | 1711 | if (!iommu->domains || !iommu->domain_ids) |
1712 | return; | 1712 | return; |
1713 | 1713 | ||
1714 | again: | ||
1714 | spin_lock_irqsave(&device_domain_lock, flags); | 1715 | spin_lock_irqsave(&device_domain_lock, flags); |
1715 | list_for_each_entry_safe(info, tmp, &device_domain_list, global) { | 1716 | list_for_each_entry_safe(info, tmp, &device_domain_list, global) { |
1716 | struct dmar_domain *domain; | 1717 | struct dmar_domain *domain; |
@@ -1723,10 +1724,19 @@ static void disable_dmar_iommu(struct intel_iommu *iommu) | |||
1723 | 1724 | ||
1724 | domain = info->domain; | 1725 | domain = info->domain; |
1725 | 1726 | ||
1726 | dmar_remove_one_dev_info(domain, info->dev); | 1727 | __dmar_remove_one_dev_info(info); |
1727 | 1728 | ||
1728 | if (!domain_type_is_vm_or_si(domain)) | 1729 | if (!domain_type_is_vm_or_si(domain)) { |
1730 | /* | ||
1731 | * The domain_exit() function can't be called under | ||
1732 | * device_domain_lock, as it takes this lock itself. | ||
1733 | * So release the lock here and re-run the loop | ||
1734 | * afterwards. | ||
1735 | */ | ||
1736 | spin_unlock_irqrestore(&device_domain_lock, flags); | ||
1729 | domain_exit(domain); | 1737 | domain_exit(domain); |
1738 | goto again; | ||
1739 | } | ||
1730 | } | 1740 | } |
1731 | spin_unlock_irqrestore(&device_domain_lock, flags); | 1741 | spin_unlock_irqrestore(&device_domain_lock, flags); |
1732 | 1742 | ||