mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 17:01:14 +00:00
vfio/spapr: Add a helper to create default DMA window
There is already a helper to create a DMA window which does allocate a table and programs it to the IOMMU group. However tce_iommu_take_ownership_ddw() did not use it and did these 2 calls itself to simplify error path. Since we are going to delay the default window creation till the default window is accessed/removed or new window is added, we need a helper to create a default window from all these cases. This adds tce_iommu_create_default_window(). Since it relies on a VFIO container to have at least one IOMMU group (for future use), this changes tce_iommu_attach_group() to add a group to the container first and then call the new helper. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Acked-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
39701e56f5
commit
6f01cc692a
1 changed files with 42 additions and 45 deletions
|
@ -710,6 +710,29 @@ static long tce_iommu_remove_window(struct tce_container *container,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static long tce_iommu_create_default_window(struct tce_container *container)
|
||||
{
|
||||
long ret;
|
||||
__u64 start_addr = 0;
|
||||
struct tce_iommu_group *tcegrp;
|
||||
struct iommu_table_group *table_group;
|
||||
|
||||
if (!tce_groups_attached(container))
|
||||
return -ENODEV;
|
||||
|
||||
tcegrp = list_first_entry(&container->group_list,
|
||||
struct tce_iommu_group, next);
|
||||
table_group = iommu_group_get_iommudata(tcegrp->grp);
|
||||
if (!table_group)
|
||||
return -ENODEV;
|
||||
|
||||
ret = tce_iommu_create_window(container, IOMMU_PAGE_SHIFT_4K,
|
||||
table_group->tce32_size, 1, &start_addr);
|
||||
WARN_ON_ONCE(!ret && start_addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long tce_iommu_ioctl(void *iommu_data,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
|
@ -1100,9 +1123,6 @@ static void tce_iommu_release_ownership_ddw(struct tce_container *container,
|
|||
static long tce_iommu_take_ownership_ddw(struct tce_container *container,
|
||||
struct iommu_table_group *table_group)
|
||||
{
|
||||
long i, ret = 0;
|
||||
struct iommu_table *tbl = NULL;
|
||||
|
||||
if (!table_group->ops->create_table || !table_group->ops->set_window ||
|
||||
!table_group->ops->release_ownership) {
|
||||
WARN_ON_ONCE(1);
|
||||
|
@ -1111,47 +1131,7 @@ static long tce_iommu_take_ownership_ddw(struct tce_container *container,
|
|||
|
||||
table_group->ops->take_ownership(table_group);
|
||||
|
||||
/*
|
||||
* If it the first group attached, check if there is
|
||||
* a default DMA window and create one if none as
|
||||
* the userspace expects it to exist.
|
||||
*/
|
||||
if (!tce_groups_attached(container) && !container->tables[0]) {
|
||||
ret = tce_iommu_create_table(container,
|
||||
table_group,
|
||||
0, /* window number */
|
||||
IOMMU_PAGE_SHIFT_4K,
|
||||
table_group->tce32_size,
|
||||
1, /* default levels */
|
||||
&tbl);
|
||||
if (ret)
|
||||
goto release_exit;
|
||||
else
|
||||
container->tables[0] = tbl;
|
||||
}
|
||||
|
||||
/* Set all windows to the new group */
|
||||
for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
|
||||
tbl = container->tables[i];
|
||||
|
||||
if (!tbl)
|
||||
continue;
|
||||
|
||||
/* Set the default window to a new group */
|
||||
ret = table_group->ops->set_window(table_group, i, tbl);
|
||||
if (ret)
|
||||
goto release_exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int tce_iommu_attach_group(void *iommu_data,
|
||||
|
@ -1161,6 +1141,7 @@ static int tce_iommu_attach_group(void *iommu_data,
|
|||
struct tce_container *container = iommu_data;
|
||||
struct iommu_table_group *table_group;
|
||||
struct tce_iommu_group *tcegrp = NULL;
|
||||
bool create_default_window = false;
|
||||
|
||||
mutex_lock(&container->lock);
|
||||
|
||||
|
@ -1203,14 +1184,30 @@ static int tce_iommu_attach_group(void *iommu_data,
|
|||
}
|
||||
|
||||
if (!table_group->ops || !table_group->ops->take_ownership ||
|
||||
!table_group->ops->release_ownership)
|
||||
!table_group->ops->release_ownership) {
|
||||
ret = tce_iommu_take_ownership(container, table_group);
|
||||
else
|
||||
} else {
|
||||
ret = tce_iommu_take_ownership_ddw(container, table_group);
|
||||
if (!tce_groups_attached(container) && !container->tables[0])
|
||||
create_default_window = true;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
tcegrp->grp = iommu_group;
|
||||
list_add(&tcegrp->next, &container->group_list);
|
||||
/*
|
||||
* If it the first group attached, check if there is
|
||||
* a default DMA window and create one if none as
|
||||
* the userspace expects it to exist.
|
||||
*/
|
||||
if (create_default_window) {
|
||||
ret = tce_iommu_create_default_window(container);
|
||||
if (ret) {
|
||||
list_del(&tcegrp->next);
|
||||
tce_iommu_release_ownership_ddw(container,
|
||||
table_group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unlock_exit:
|
||||
|
|
Loading…
Reference in a new issue