summaryrefslogtreecommitdiff
path: root/drivers/vfio/vfio_iommu_spapr_tce.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/vfio/vfio_iommu_spapr_tce.c')
-rw-r--r--drivers/vfio/vfio_iommu_spapr_tce.c109
1 files changed, 22 insertions, 87 deletions
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
index 60a50ce8701e..5f9e7e477078 100644
--- a/drivers/vfio/vfio_iommu_spapr_tce.c
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -364,7 +364,6 @@ static void tce_iommu_release(void *iommu_data)
if (!tbl)
continue;
- tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
tce_iommu_free_table(container, tbl);
}
@@ -720,6 +719,8 @@ static long tce_iommu_remove_window(struct tce_container *container,
BUG_ON(!tbl->it_size);
+ tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
+
/* Detach groups from IOMMUs */
list_for_each_entry(tcegrp, &container->group_list, next) {
table_group = iommu_group_get_iommudata(tcegrp->grp);
@@ -738,7 +739,6 @@ static long tce_iommu_remove_window(struct tce_container *container,
}
/* Free table */
- tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
tce_iommu_free_table(container, tbl);
container->tables[num] = NULL;
@@ -1190,52 +1190,6 @@ static long tce_iommu_ioctl(void *iommu_data,
static void tce_iommu_release_ownership(struct tce_container *container,
struct iommu_table_group *table_group)
{
- int i;
-
- for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
- struct iommu_table *tbl = container->tables[i];
-
- if (!tbl)
- continue;
-
- tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size);
- if (tbl->it_map)
- iommu_release_ownership(tbl);
-
- container->tables[i] = NULL;
- }
-}
-
-static int tce_iommu_take_ownership(struct tce_container *container,
- struct iommu_table_group *table_group)
-{
- int i, j, rc = 0;
-
- for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
- struct iommu_table *tbl = table_group->tables[i];
-
- if (!tbl || !tbl->it_map)
- continue;
-
- rc = iommu_take_ownership(tbl);
- if (rc) {
- for (j = 0; j < i; ++j)
- iommu_release_ownership(
- table_group->tables[j]);
-
- return rc;
- }
- }
-
- for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i)
- container->tables[i] = table_group->tables[i];
-
- return 0;
-}
-
-static void tce_iommu_release_ownership_ddw(struct tce_container *container,
- struct iommu_table_group *table_group)
-{
long i;
if (!table_group->ops->unset_window) {
@@ -1243,26 +1197,21 @@ static void tce_iommu_release_ownership_ddw(struct tce_container *container,
return;
}
- for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i)
- if (container->tables[i])
+ for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
+ if (container->tables[i]) {
+ tce_iommu_clear(container, container->tables[i],
+ container->tables[i]->it_offset,
+ container->tables[i]->it_size);
table_group->ops->unset_window(table_group, i);
-
- table_group->ops->release_ownership(table_group);
+ }
+ }
}
-static long tce_iommu_take_ownership_ddw(struct tce_container *container,
+static long tce_iommu_take_ownership(struct tce_container *container,
struct iommu_table_group *table_group)
{
long i, ret = 0;
- if (!table_group->ops->create_table || !table_group->ops->set_window ||
- !table_group->ops->release_ownership) {
- WARN_ON_ONCE(1);
- return -EFAULT;
- }
-
- table_group->ops->take_ownership(table_group);
-
/* Set all windows to the new group */
for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
struct iommu_table *tbl = container->tables[i];
@@ -1281,8 +1230,6 @@ release_exit:
for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i)
table_group->ops->unset_window(table_group, i);
- table_group->ops->release_ownership(table_group);
-
return ret;
}
@@ -1307,9 +1254,14 @@ static int tce_iommu_attach_group(void *iommu_data,
goto unlock_exit;
}
- if (tce_groups_attached(container) && (!table_group->ops ||
- !table_group->ops->take_ownership ||
- !table_group->ops->release_ownership)) {
+ /* v2 requires full support of dynamic DMA windows */
+ if (container->v2 && table_group->max_dynamic_windows_supported == 0) {
+ ret = -EINVAL;
+ goto unlock_exit;
+ }
+
+ /* v1 reuses TCE tables and does not share them among PEs */
+ if (!container->v2 && tce_groups_attached(container)) {
ret = -EBUSY;
goto unlock_exit;
}
@@ -1344,29 +1296,15 @@ static int tce_iommu_attach_group(void *iommu_data,
goto unlock_exit;
}
- if (!table_group->ops || !table_group->ops->take_ownership ||
- !table_group->ops->release_ownership) {
- if (container->v2) {
- ret = -EPERM;
- goto free_exit;
- }
- ret = tce_iommu_take_ownership(container, table_group);
- } else {
- if (!container->v2) {
- ret = -EPERM;
- goto free_exit;
- }
- ret = tce_iommu_take_ownership_ddw(container, table_group);
- if (!tce_groups_attached(container) && !container->tables[0])
- container->def_window_pending = true;
- }
+ ret = tce_iommu_take_ownership(container, table_group);
+ if (!tce_groups_attached(container) && !container->tables[0])
+ container->def_window_pending = true;
if (!ret) {
tcegrp->grp = iommu_group;
list_add(&tcegrp->next, &container->group_list);
}
-free_exit:
if (ret && tcegrp)
kfree(tcegrp);
@@ -1405,10 +1343,7 @@ static void tce_iommu_detach_group(void *iommu_data,
table_group = iommu_group_get_iommudata(iommu_group);
BUG_ON(!table_group);
- if (!table_group->ops || !table_group->ops->release_ownership)
- tce_iommu_release_ownership(container, table_group);
- else
- tce_iommu_release_ownership_ddw(container, table_group);
+ tce_iommu_release_ownership(container, table_group);
unlock_exit:
mutex_unlock(&container->lock);