diff options
| -rw-r--r-- | drivers/vfio/vfio_iommu_type1.c | 55 |
1 files changed, 42 insertions, 13 deletions
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index c956b85264ae..3be1db3501cc 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c | |||
| @@ -565,7 +565,7 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data, | |||
| 565 | mutex_lock(&iommu->lock); | 565 | mutex_lock(&iommu->lock); |
| 566 | 566 | ||
| 567 | /* Fail if notifier list is empty */ | 567 | /* Fail if notifier list is empty */ |
| 568 | if ((!iommu->external_domain) || (!iommu->notifier.head)) { | 568 | if (!iommu->notifier.head) { |
| 569 | ret = -EINVAL; | 569 | ret = -EINVAL; |
| 570 | goto pin_done; | 570 | goto pin_done; |
| 571 | } | 571 | } |
| @@ -647,11 +647,6 @@ static int vfio_iommu_type1_unpin_pages(void *iommu_data, | |||
| 647 | 647 | ||
| 648 | mutex_lock(&iommu->lock); | 648 | mutex_lock(&iommu->lock); |
| 649 | 649 | ||
| 650 | if (!iommu->external_domain) { | ||
| 651 | mutex_unlock(&iommu->lock); | ||
| 652 | return -EINVAL; | ||
| 653 | } | ||
| 654 | |||
| 655 | do_accounting = !IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu); | 650 | do_accounting = !IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu); |
| 656 | for (i = 0; i < npage; i++) { | 651 | for (i = 0; i < npage; i++) { |
| 657 | struct vfio_dma *dma; | 652 | struct vfio_dma *dma; |
| @@ -1381,13 +1376,40 @@ static void vfio_iommu_detach_group(struct vfio_domain *domain, | |||
| 1381 | iommu_detach_group(domain->domain, group->iommu_group); | 1376 | iommu_detach_group(domain->domain, group->iommu_group); |
| 1382 | } | 1377 | } |
| 1383 | 1378 | ||
| 1379 | static bool vfio_bus_is_mdev(struct bus_type *bus) | ||
| 1380 | { | ||
| 1381 | struct bus_type *mdev_bus; | ||
| 1382 | bool ret = false; | ||
| 1383 | |||
| 1384 | mdev_bus = symbol_get(mdev_bus_type); | ||
| 1385 | if (mdev_bus) { | ||
| 1386 | ret = (bus == mdev_bus); | ||
| 1387 | symbol_put(mdev_bus_type); | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | return ret; | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | static int vfio_mdev_iommu_device(struct device *dev, void *data) | ||
| 1394 | { | ||
| 1395 | struct device **old = data, *new; | ||
| 1396 | |||
| 1397 | new = vfio_mdev_get_iommu_device(dev); | ||
| 1398 | if (!new || (*old && *old != new)) | ||
| 1399 | return -EINVAL; | ||
| 1400 | |||
| 1401 | *old = new; | ||
| 1402 | |||
| 1403 | return 0; | ||
| 1404 | } | ||
| 1405 | |||
| 1384 | static int vfio_iommu_type1_attach_group(void *iommu_data, | 1406 | static int vfio_iommu_type1_attach_group(void *iommu_data, |
| 1385 | struct iommu_group *iommu_group) | 1407 | struct iommu_group *iommu_group) |
| 1386 | { | 1408 | { |
| 1387 | struct vfio_iommu *iommu = iommu_data; | 1409 | struct vfio_iommu *iommu = iommu_data; |
| 1388 | struct vfio_group *group; | 1410 | struct vfio_group *group; |
| 1389 | struct vfio_domain *domain, *d; | 1411 | struct vfio_domain *domain, *d; |
| 1390 | struct bus_type *bus = NULL, *mdev_bus; | 1412 | struct bus_type *bus = NULL; |
| 1391 | int ret; | 1413 | int ret; |
| 1392 | bool resv_msi, msi_remap; | 1414 | bool resv_msi, msi_remap; |
| 1393 | phys_addr_t resv_msi_base; | 1415 | phys_addr_t resv_msi_base; |
| @@ -1422,23 +1444,30 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, | |||
| 1422 | if (ret) | 1444 | if (ret) |
| 1423 | goto out_free; | 1445 | goto out_free; |
| 1424 | 1446 | ||
| 1425 | mdev_bus = symbol_get(mdev_bus_type); | 1447 | if (vfio_bus_is_mdev(bus)) { |
| 1448 | struct device *iommu_device = NULL; | ||
| 1426 | 1449 | ||
| 1427 | if (mdev_bus) { | 1450 | group->mdev_group = true; |
| 1428 | if ((bus == mdev_bus) && !iommu_present(bus)) { | 1451 | |
| 1429 | symbol_put(mdev_bus_type); | 1452 | /* Determine the isolation type */ |
| 1453 | ret = iommu_group_for_each_dev(iommu_group, &iommu_device, | ||
| 1454 | vfio_mdev_iommu_device); | ||
| 1455 | if (ret || !iommu_device) { | ||
| 1430 | if (!iommu->external_domain) { | 1456 | if (!iommu->external_domain) { |
| 1431 | INIT_LIST_HEAD(&domain->group_list); | 1457 | INIT_LIST_HEAD(&domain->group_list); |
| 1432 | iommu->external_domain = domain; | 1458 | iommu->external_domain = domain; |
| 1433 | } else | 1459 | } else { |
| 1434 | kfree(domain); | 1460 | kfree(domain); |
| 1461 | } | ||
| 1435 | 1462 | ||
| 1436 | list_add(&group->next, | 1463 | list_add(&group->next, |
| 1437 | &iommu->external_domain->group_list); | 1464 | &iommu->external_domain->group_list); |
| 1438 | mutex_unlock(&iommu->lock); | 1465 | mutex_unlock(&iommu->lock); |
| 1466 | |||
| 1439 | return 0; | 1467 | return 0; |
| 1440 | } | 1468 | } |
| 1441 | symbol_put(mdev_bus_type); | 1469 | |
| 1470 | bus = iommu_device->bus; | ||
| 1442 | } | 1471 | } |
| 1443 | 1472 | ||
| 1444 | domain->domain = iommu_domain_alloc(bus); | 1473 | domain->domain = iommu_domain_alloc(bus); |
