aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/intel-iommu.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-24 19:24:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-24 19:24:11 -0400
commit97027da6adf2e24a4e8d3d9c0668da3006b29971 (patch)
tree7da3aa43a9e8c9be0a408b814e6f0d3106c55d66 /drivers/iommu/intel-iommu.c
parent6dd53aa4563a2c69e80a24d2cc68d484b5ea2891 (diff)
parent395e51f18d3b26619c1c462b7a1c0226846ac0a9 (diff)
Merge tag 'iommu-updates-v3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU updates from Joerg Roedel: "The most important part of these updates is the IOMMU groups code enhancement written by Alex Williamson. It abstracts the problem that a given hardware IOMMU can't isolate any given device from any other device (e.g. 32 bit PCI devices can't usually be isolated). Devices that can't be isolated are grouped together. This code is required for the upcoming VFIO framework. Another IOMMU-API change written by me is the introduction of domain attributes. This makes it easier to handle GART-like IOMMUs with the IOMMU-API because now the start-address and the size of the domain address space can be queried. Besides that there are a few cleanups and fixes for the NVidia Tegra IOMMU drivers and the reworked init-code for the AMD IOMMU. The latter is from my patch-set to support interrupt remapping. The rest of this patch-set requires x86 changes which are not mergabe yet. So full support for interrupt remapping with AMD IOMMUs will come in a future merge window." * tag 'iommu-updates-v3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (33 commits) iommu/amd: Fix hotplug with iommu=pt iommu/amd: Add missing spin_lock initialization iommu/amd: Convert iommu initialization to state machine iommu/amd: Introduce amd_iommu_init_dma routine iommu/amd: Move unmap_flush message to amd_iommu_init_dma_ops() iommu/amd: Split enable_iommus() routine iommu/amd: Introduce early_amd_iommu_init routine iommu/amd: Move informational prinks out of iommu_enable iommu/amd: Split out PCI related parts of IOMMU initialization iommu/amd: Use acpi_get_table instead of acpi_table_parse iommu/amd: Fix sparse warnings iommu/tegra: Don't call alloc_pdir with as->lock iommu/tegra: smmu: Fix unsleepable memory allocation at alloc_pdir() iommu/tegra: smmu: Remove unnecessary sanity check at alloc_pdir() iommu/exynos: Implement DOMAIN_ATTR_GEOMETRY attribute iommu/tegra: Implement DOMAIN_ATTR_GEOMETRY attribute iommu/msm: Implement DOMAIN_ATTR_GEOMETRY attribute iommu/omap: Implement DOMAIN_ATTR_GEOMETRY attribute iommu/vt-d: Implement DOMAIN_ATTR_GEOMETRY attribute iommu/amd: Implement DOMAIN_ATTR_GEOMETRY attribute ...
Diffstat (limited to 'drivers/iommu/intel-iommu.c')
-rw-r--r--drivers/iommu/intel-iommu.c93
1 files changed, 58 insertions, 35 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 2fb7d1598a68..7469b5346643 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3932,6 +3932,10 @@ static int intel_iommu_domain_init(struct iommu_domain *domain)
3932 domain_update_iommu_cap(dmar_domain); 3932 domain_update_iommu_cap(dmar_domain);
3933 domain->priv = dmar_domain; 3933 domain->priv = dmar_domain;
3934 3934
3935 domain->geometry.aperture_start = 0;
3936 domain->geometry.aperture_end = __DOMAIN_MAX_ADDR(dmar_domain->gaw);
3937 domain->geometry.force_aperture = true;
3938
3935 return 0; 3939 return 0;
3936} 3940}
3937 3941
@@ -4090,52 +4094,70 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4090 return 0; 4094 return 0;
4091} 4095}
4092 4096
4093/* 4097static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)
4094 * Group numbers are arbitrary. Device with the same group number
4095 * indicate the iommu cannot differentiate between them. To avoid
4096 * tracking used groups we just use the seg|bus|devfn of the lowest
4097 * level we're able to differentiate devices
4098 */
4099static int intel_iommu_device_group(struct device *dev, unsigned int *groupid)
4100{ 4098{
4101 struct pci_dev *pdev = to_pci_dev(dev); 4099 pci_dev_put(*from);
4102 struct pci_dev *bridge; 4100 *from = to;
4103 union { 4101}
4104 struct {
4105 u8 devfn;
4106 u8 bus;
4107 u16 segment;
4108 } pci;
4109 u32 group;
4110 } id;
4111 4102
4112 if (iommu_no_mapping(dev)) 4103#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
4113 return -ENODEV;
4114 4104
4115 id.pci.segment = pci_domain_nr(pdev->bus); 4105static int intel_iommu_add_device(struct device *dev)
4116 id.pci.bus = pdev->bus->number; 4106{
4117 id.pci.devfn = pdev->devfn; 4107 struct pci_dev *pdev = to_pci_dev(dev);
4108 struct pci_dev *bridge, *dma_pdev;
4109 struct iommu_group *group;
4110 int ret;
4118 4111
4119 if (!device_to_iommu(id.pci.segment, id.pci.bus, id.pci.devfn)) 4112 if (!device_to_iommu(pci_domain_nr(pdev->bus),
4113 pdev->bus->number, pdev->devfn))
4120 return -ENODEV; 4114 return -ENODEV;
4121 4115
4122 bridge = pci_find_upstream_pcie_bridge(pdev); 4116 bridge = pci_find_upstream_pcie_bridge(pdev);
4123 if (bridge) { 4117 if (bridge) {
4124 if (pci_is_pcie(bridge)) { 4118 if (pci_is_pcie(bridge))
4125 id.pci.bus = bridge->subordinate->number; 4119 dma_pdev = pci_get_domain_bus_and_slot(
4126 id.pci.devfn = 0; 4120 pci_domain_nr(pdev->bus),
4127 } else { 4121 bridge->subordinate->number, 0);
4128 id.pci.bus = bridge->bus->number; 4122 else
4129 id.pci.devfn = bridge->devfn; 4123 dma_pdev = pci_dev_get(bridge);
4130 } 4124 } else
4125 dma_pdev = pci_dev_get(pdev);
4126
4127 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
4128
4129 if (dma_pdev->multifunction &&
4130 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
4131 swap_pci_ref(&dma_pdev,
4132 pci_get_slot(dma_pdev->bus,
4133 PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
4134 0)));
4135
4136 while (!pci_is_root_bus(dma_pdev->bus)) {
4137 if (pci_acs_path_enabled(dma_pdev->bus->self,
4138 NULL, REQ_ACS_FLAGS))
4139 break;
4140
4141 swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self));
4142 }
4143
4144 group = iommu_group_get(&dma_pdev->dev);
4145 pci_dev_put(dma_pdev);
4146 if (!group) {
4147 group = iommu_group_alloc();
4148 if (IS_ERR(group))
4149 return PTR_ERR(group);
4131 } 4150 }
4132 4151
4133 if (!pdev->is_virtfn && iommu_group_mf) 4152 ret = iommu_group_add_device(group, dev);
4134 id.pci.devfn = PCI_DEVFN(PCI_SLOT(id.pci.devfn), 0);
4135 4153
4136 *groupid = id.group; 4154 iommu_group_put(group);
4155 return ret;
4156}
4137 4157
4138 return 0; 4158static void intel_iommu_remove_device(struct device *dev)
4159{
4160 iommu_group_remove_device(dev);
4139} 4161}
4140 4162
4141static struct iommu_ops intel_iommu_ops = { 4163static struct iommu_ops intel_iommu_ops = {
@@ -4147,7 +4169,8 @@ static struct iommu_ops intel_iommu_ops = {
4147 .unmap = intel_iommu_unmap, 4169 .unmap = intel_iommu_unmap,
4148 .iova_to_phys = intel_iommu_iova_to_phys, 4170 .iova_to_phys = intel_iommu_iova_to_phys,
4149 .domain_has_cap = intel_iommu_domain_has_cap, 4171 .domain_has_cap = intel_iommu_domain_has_cap,
4150 .device_group = intel_iommu_device_group, 4172 .add_device = intel_iommu_add_device,
4173 .remove_device = intel_iommu_remove_device,
4151 .pgsize_bitmap = INTEL_IOMMU_PGSIZES, 4174 .pgsize_bitmap = INTEL_IOMMU_PGSIZES,
4152}; 4175};
4153 4176