aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/intel-iommu.c
diff options
context:
space:
mode:
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