Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alex Williamson and committed by
Joerg Roedel
78bfa9f3 ce7ac4ab

+57 -5
+56 -5
drivers/iommu/amd_iommu.c
··· 140 140 list_del(&dev_data->dev_data_list); 141 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 146 kfree(dev_data); 144 147 } 145 148 ··· 346 343 return ret; 347 344 } 348 345 346 + static int use_dev_data_iommu_group(struct iommu_dev_data *dev_data, 347 + struct device *dev) 348 + { 349 + if (!dev_data->group) { 350 + struct iommu_group *group = iommu_group_alloc(); 351 + if (IS_ERR(group)) 352 + return PTR_ERR(group); 353 + 354 + dev_data->group = group; 355 + } 356 + 357 + return iommu_group_add_device(dev_data->group, dev); 358 + } 359 + 349 360 static int init_iommu_group(struct device *dev) 350 361 { 351 362 struct iommu_dev_data *dev_data; 352 363 struct iommu_group *group; 353 - struct pci_dev *dma_pdev = NULL; 364 + struct pci_dev *dma_pdev; 354 365 int ret; 355 366 356 367 group = iommu_group_get(dev); ··· 379 362 380 363 if (dev_data->alias_data) { 381 364 u16 alias; 365 + struct pci_bus *bus; 382 366 367 + if (dev_data->alias_data->group) 368 + goto use_group; 369 + 370 + /* 371 + * If the alias device exists, it's effectively just a first 372 + * level quirk for finding the DMA source. 373 + */ 383 374 alias = amd_iommu_alias_table[dev_data->devid]; 384 375 dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); 376 + if (dma_pdev) { 377 + dma_pdev = get_isolation_root(dma_pdev); 378 + goto use_pdev; 379 + } 380 + 381 + /* 382 + * If the alias is virtual, try to find a parent device 383 + * and test whether the IOMMU group is actualy rooted above 384 + * the alias. Be careful to also test the parent device if 385 + * we think the alias is the root of the group. 386 + */ 387 + bus = pci_find_bus(0, alias >> 8); 388 + if (!bus) 389 + goto use_group; 390 + 391 + bus = find_hosted_bus(bus); 392 + if (IS_ERR(bus) || !bus->self) 393 + goto use_group; 394 + 395 + dma_pdev = get_isolation_root(pci_dev_get(bus->self)); 396 + if (dma_pdev != bus->self || (dma_pdev->multifunction && 397 + !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))) 398 + goto use_pdev; 399 + 400 + pci_dev_put(dma_pdev); 401 + goto use_group; 385 402 } 386 403 387 - if (!dma_pdev) 388 - dma_pdev = pci_dev_get(to_pci_dev(dev)); 389 - 390 - dma_pdev = get_isolation_root(dma_pdev); 404 + dma_pdev = get_isolation_root(pci_dev_get(to_pci_dev(dev))); 405 + use_pdev: 391 406 ret = use_pdev_iommu_group(dma_pdev, dev); 392 407 pci_dev_put(dma_pdev); 393 408 return ret; 409 + use_group: 410 + return use_dev_data_iommu_group(dev_data->alias_data, dev); 394 411 } 395 412 396 413 static int iommu_init_device(struct device *dev)
+1
drivers/iommu/amd_iommu_types.h
··· 426 426 struct iommu_dev_data *alias_data;/* The alias dev_data */ 427 427 struct protection_domain *domain; /* Domain the device is bound to */ 428 428 atomic_t bind; /* Domain attach reference count */ 429 + struct iommu_group *group; /* IOMMU group for virtual aliases */ 429 430 u16 devid; /* PCI Device ID */ 430 431 bool iommu_v2; /* Device can make use of IOMMUv2 */ 431 432 bool passthrough; /* Default for device is pt_domain */