Commit 16ab8a5c authored by Alex Williamson's avatar Alex Williamson

vfio/noiommu: Don't use iommu_present() to track fake groups

Using iommu_present() to determine whether an IOMMU group is real or
fake has some problems.  First, apparently Power systems don't
register an IOMMU on the device bus, so the groups and containers get
marked as noiommu and then won't bind to their actual IOMMU driver.
Second, I expect we'll run into the same issue as we try to support
vGPUs through vfio, since they're likely to emulate this behavior of
creating an IOMMU group on a virtual device and then providing a vfio
IOMMU backend tailored to the sort of isolation they provide, which
won't necessarily be fully compatible with the IOMMU API.

The solution here is to use the existing iommudata interface to IOMMU
groups, which allows us to easily identify the fake groups we've
created for noiommu purposes.  The iommudata we set is purely
arbitrary since we're only comparing the address, so we use the
address of the noiommu switch itself.
Reported-by: default avatarAlexey Kardashevskiy <aik@ozlabs.ru>
Reviewed-by: default avatarAlexey Kardashevskiy <aik@ozlabs.ru>
Tested-by: default avatarAlexey Kardashevskiy <aik@ozlabs.ru>
Tested-by: default avatarAnatoly Burakov <anatoly.burakov@intel.com>
Tested-by: default avatarSantosh Shukla <sshukla@mvista.com>
Fixes: 03a76b60 ("vfio: Include No-IOMMU mode")
Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 92e963f5
...@@ -123,8 +123,8 @@ struct iommu_group *vfio_iommu_group_get(struct device *dev) ...@@ -123,8 +123,8 @@ struct iommu_group *vfio_iommu_group_get(struct device *dev)
/* /*
* With noiommu enabled, an IOMMU group will be created for a device * With noiommu enabled, an IOMMU group will be created for a device
* that doesn't already have one and doesn't have an iommu_ops on their * that doesn't already have one and doesn't have an iommu_ops on their
* bus. We use iommu_present() again in the main code to detect these * bus. We set iommudata simply to be able to identify these groups
* fake groups. * as special use and for reclamation later.
*/ */
if (group || !noiommu || iommu_present(dev->bus)) if (group || !noiommu || iommu_present(dev->bus))
return group; return group;
...@@ -134,6 +134,7 @@ struct iommu_group *vfio_iommu_group_get(struct device *dev) ...@@ -134,6 +134,7 @@ struct iommu_group *vfio_iommu_group_get(struct device *dev)
return NULL; return NULL;
iommu_group_set_name(group, "vfio-noiommu"); iommu_group_set_name(group, "vfio-noiommu");
iommu_group_set_iommudata(group, &noiommu, NULL);
ret = iommu_group_add_device(group, dev); ret = iommu_group_add_device(group, dev);
iommu_group_put(group); iommu_group_put(group);
if (ret) if (ret)
...@@ -158,7 +159,7 @@ EXPORT_SYMBOL_GPL(vfio_iommu_group_get); ...@@ -158,7 +159,7 @@ EXPORT_SYMBOL_GPL(vfio_iommu_group_get);
void vfio_iommu_group_put(struct iommu_group *group, struct device *dev) void vfio_iommu_group_put(struct iommu_group *group, struct device *dev)
{ {
#ifdef CONFIG_VFIO_NOIOMMU #ifdef CONFIG_VFIO_NOIOMMU
if (!iommu_present(dev->bus)) if (iommu_group_get_iommudata(group) == &noiommu)
iommu_group_remove_device(dev); iommu_group_remove_device(dev);
#endif #endif
...@@ -190,16 +191,10 @@ static long vfio_noiommu_ioctl(void *iommu_data, ...@@ -190,16 +191,10 @@ static long vfio_noiommu_ioctl(void *iommu_data,
return -ENOTTY; return -ENOTTY;
} }
static int vfio_iommu_present(struct device *dev, void *unused)
{
return iommu_present(dev->bus) ? 1 : 0;
}
static int vfio_noiommu_attach_group(void *iommu_data, static int vfio_noiommu_attach_group(void *iommu_data,
struct iommu_group *iommu_group) struct iommu_group *iommu_group)
{ {
return iommu_group_for_each_dev(iommu_group, NULL, return iommu_group_get_iommudata(iommu_group) == &noiommu ? 0 : -EINVAL;
vfio_iommu_present) ? -EINVAL : 0;
} }
static void vfio_noiommu_detach_group(void *iommu_data, static void vfio_noiommu_detach_group(void *iommu_data,
...@@ -323,8 +318,7 @@ static void vfio_group_unlock_and_free(struct vfio_group *group) ...@@ -323,8 +318,7 @@ static void vfio_group_unlock_and_free(struct vfio_group *group)
/** /**
* Group objects - create, release, get, put, search * Group objects - create, release, get, put, search
*/ */
static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group, static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
bool iommu_present)
{ {
struct vfio_group *group, *tmp; struct vfio_group *group, *tmp;
struct device *dev; struct device *dev;
...@@ -342,7 +336,9 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group, ...@@ -342,7 +336,9 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,
atomic_set(&group->container_users, 0); atomic_set(&group->container_users, 0);
atomic_set(&group->opened, 0); atomic_set(&group->opened, 0);
group->iommu_group = iommu_group; group->iommu_group = iommu_group;
group->noiommu = !iommu_present; #ifdef CONFIG_VFIO_NOIOMMU
group->noiommu = (iommu_group_get_iommudata(iommu_group) == &noiommu);
#endif
group->nb.notifier_call = vfio_iommu_group_notifier; group->nb.notifier_call = vfio_iommu_group_notifier;
...@@ -767,7 +763,7 @@ int vfio_add_group_dev(struct device *dev, ...@@ -767,7 +763,7 @@ int vfio_add_group_dev(struct device *dev,
group = vfio_group_get_from_iommu(iommu_group); group = vfio_group_get_from_iommu(iommu_group);
if (!group) { if (!group) {
group = vfio_create_group(iommu_group, iommu_present(dev->bus)); group = vfio_create_group(iommu_group);
if (IS_ERR(group)) { if (IS_ERR(group)) {
iommu_group_put(iommu_group); iommu_group_put(iommu_group);
return PTR_ERR(group); return PTR_ERR(group);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment