aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2011-10-21 15:56:11 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2011-11-15 06:22:30 -0500
commit70ae6f0d55bd216b2f773fa5fa5018c0490a9e50 (patch)
treed90c8d432e8f1728ccd3c54daee13d6e3e99ed49 /drivers/iommu
parent1460432cb513f0c16136ed132c20ecfbf8ccf942 (diff)
iommu/intel: Implement iommu_device_group
We generally have BDF granularity for devices, so we just need to make sure devices aren't hidden behind PCIe-to-PCI bridges. We can then make up a group number that's simply the concatenated seg|bus|dev|fn so we don't have to track them (not that users should depend on that). Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Acked-By: David Woodhouse <David.Woodhouse@intel.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/intel-iommu.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c0c7820d4c46..39ca6bb17e13 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4060,6 +4060,51 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain,
4060 return 0; 4060 return 0;
4061} 4061}
4062 4062
4063/*
4064 * Group numbers are arbitrary. Device with the same group number
4065 * indicate the iommu cannot differentiate between them. To avoid
4066 * tracking used groups we just use the seg|bus|devfn of the lowest
4067 * level we're able to differentiate devices
4068 */
4069static int intel_iommu_device_group(struct device *dev, unsigned int *groupid)
4070{
4071 struct pci_dev *pdev = to_pci_dev(dev);
4072 struct pci_dev *bridge;
4073 union {
4074 struct {
4075 u8 devfn;
4076 u8 bus;
4077 u16 segment;
4078 } pci;
4079 u32 group;
4080 } id;
4081
4082 if (iommu_no_mapping(dev))
4083 return -ENODEV;
4084
4085 id.pci.segment = pci_domain_nr(pdev->bus);
4086 id.pci.bus = pdev->bus->number;
4087 id.pci.devfn = pdev->devfn;
4088
4089 if (!device_to_iommu(id.pci.segment, id.pci.bus, id.pci.devfn))
4090 return -ENODEV;
4091
4092 bridge = pci_find_upstream_pcie_bridge(pdev);
4093 if (bridge) {
4094 if (pci_is_pcie(bridge)) {
4095 id.pci.bus = bridge->subordinate->number;
4096 id.pci.devfn = 0;
4097 } else {
4098 id.pci.bus = bridge->bus->number;
4099 id.pci.devfn = bridge->devfn;
4100 }
4101 }
4102
4103 *groupid = id.group;
4104
4105 return 0;
4106}
4107
4063static struct iommu_ops intel_iommu_ops = { 4108static struct iommu_ops intel_iommu_ops = {
4064 .domain_init = intel_iommu_domain_init, 4109 .domain_init = intel_iommu_domain_init,
4065 .domain_destroy = intel_iommu_domain_destroy, 4110 .domain_destroy = intel_iommu_domain_destroy,
@@ -4069,6 +4114,7 @@ static struct iommu_ops intel_iommu_ops = {
4069 .unmap = intel_iommu_unmap, 4114 .unmap = intel_iommu_unmap,
4070 .iova_to_phys = intel_iommu_iova_to_phys, 4115 .iova_to_phys = intel_iommu_iova_to_phys,
4071 .domain_has_cap = intel_iommu_domain_has_cap, 4116 .domain_has_cap = intel_iommu_domain_has_cap,
4117 .device_group = intel_iommu_device_group,
4072}; 4118};
4073 4119
4074static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) 4120static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)