aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2012-10-09 00:50:00 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2012-10-24 11:30:22 -0400
commit78bfa9f395f6bbab168b83f69b99659818517b02 (patch)
tree91cd012948d767c6e4747312c0b87031ca1f8d64 /drivers/iommu
parentce7ac4abf2401dfdcb1ac4c7277dab8ed90c8788 (diff)
iommu/amd: Properly account for virtual aliases in IOMMU groups
An alias doesn't always point to a physical device. When this happens we must first verify that the IOMMU group isn't rooted in a device above the alias. In this case the alias is effectively just another quirk for the devices aliased to it. Alternatively, the virtual alias itself may be the root of the IOMMU group. To support this, allow a group to be hosted on the alias dev_data for use by anything that might have the same alias. Signed-off-by: Alex williamson <alex.williamson@redhat.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/amd_iommu.c61
-rw-r--r--drivers/iommu/amd_iommu_types.h1
2 files changed, 57 insertions, 5 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 7fa97a5e3eaf..cb63cc5d94d7 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -140,6 +140,9 @@ static void free_dev_data(struct iommu_dev_data *dev_data)
140 list_del(&dev_data->dev_data_list); 140 list_del(&dev_data->dev_data_list);
141 spin_unlock_irqrestore(&dev_data_list_lock, flags); 141 spin_unlock_irqrestore(&dev_data_list_lock, flags);
142 142
143 if (dev_data->group)
144 iommu_group_put(dev_data->group);
145
143 kfree(dev_data); 146 kfree(dev_data);
144} 147}
145 148
@@ -343,11 +346,25 @@ static int use_pdev_iommu_group(struct pci_dev *pdev, struct device *dev)
343 return ret; 346 return ret;
344} 347}
345 348
349static int use_dev_data_iommu_group(struct iommu_dev_data *dev_data,
350 struct device *dev)
351{
352 if (!dev_data->group) {
353 struct iommu_group *group = iommu_group_alloc();
354 if (IS_ERR(group))
355 return PTR_ERR(group);
356
357 dev_data->group = group;
358 }
359
360 return iommu_group_add_device(dev_data->group, dev);
361}
362
346static int init_iommu_group(struct device *dev) 363static int init_iommu_group(struct device *dev)
347{ 364{
348 struct iommu_dev_data *dev_data; 365 struct iommu_dev_data *dev_data;
349 struct iommu_group *group; 366 struct iommu_group *group;
350 struct pci_dev *dma_pdev = NULL; 367 struct pci_dev *dma_pdev;
351 int ret; 368 int ret;
352 369
353 group = iommu_group_get(dev); 370 group = iommu_group_get(dev);
@@ -362,18 +379,52 @@ static int init_iommu_group(struct device *dev)
362 379
363 if (dev_data->alias_data) { 380 if (dev_data->alias_data) {
364 u16 alias; 381 u16 alias;
382 struct pci_bus *bus;
383
384 if (dev_data->alias_data->group)
385 goto use_group;
365 386
387 /*
388 * If the alias device exists, it's effectively just a first
389 * level quirk for finding the DMA source.
390 */
366 alias = amd_iommu_alias_table[dev_data->devid]; 391 alias = amd_iommu_alias_table[dev_data->devid];
367 dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); 392 dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff);
368 } 393 if (dma_pdev) {
394 dma_pdev = get_isolation_root(dma_pdev);
395 goto use_pdev;
396 }
397
398 /*
399 * If the alias is virtual, try to find a parent device
400 * and test whether the IOMMU group is actualy rooted above
401 * the alias. Be careful to also test the parent device if
402 * we think the alias is the root of the group.
403 */
404 bus = pci_find_bus(0, alias >> 8);
405 if (!bus)
406 goto use_group;
407
408 bus = find_hosted_bus(bus);
409 if (IS_ERR(bus) || !bus->self)
410 goto use_group;
369 411
370 if (!dma_pdev) 412 dma_pdev = get_isolation_root(pci_dev_get(bus->self));
371 dma_pdev = pci_dev_get(to_pci_dev(dev)); 413 if (dma_pdev != bus->self || (dma_pdev->multifunction &&
414 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)))
415 goto use_pdev;
416
417 pci_dev_put(dma_pdev);
418 goto use_group;
419 }
372 420
373 dma_pdev = get_isolation_root(dma_pdev); 421 dma_pdev = get_isolation_root(pci_dev_get(to_pci_dev(dev)));
422use_pdev:
374 ret = use_pdev_iommu_group(dma_pdev, dev); 423 ret = use_pdev_iommu_group(dma_pdev, dev);
375 pci_dev_put(dma_pdev); 424 pci_dev_put(dma_pdev);
376 return ret; 425 return ret;
426use_group:
427 return use_dev_data_iommu_group(dev_data->alias_data, dev);
377} 428}
378 429
379static int iommu_init_device(struct device *dev) 430static int iommu_init_device(struct device *dev)
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index c9aa3d079ff0..e38ab438bb34 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -426,6 +426,7 @@ struct iommu_dev_data {
426 struct iommu_dev_data *alias_data;/* The alias dev_data */ 426 struct iommu_dev_data *alias_data;/* The alias dev_data */
427 struct protection_domain *domain; /* Domain the device is bound to */ 427 struct protection_domain *domain; /* Domain the device is bound to */
428 atomic_t bind; /* Domain attach reference count */ 428 atomic_t bind; /* Domain attach reference count */
429 struct iommu_group *group; /* IOMMU group for virtual aliases */
429 u16 devid; /* PCI Device ID */ 430 u16 devid; /* PCI Device ID */
430 bool iommu_v2; /* Device can make use of IOMMUv2 */ 431 bool iommu_v2; /* Device can make use of IOMMUv2 */
431 bool passthrough; /* Default for device is pt_domain */ 432 bool passthrough; /* Default for device is pt_domain */