aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/amd_iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iommu/amd_iommu.c')
-rw-r--r--drivers/iommu/amd_iommu.c61
1 files changed, 56 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)