mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-02 16:44:59 +00:00
vfio/type1: implement interfaces to update vaddr
Implement VFIO_DMA_UNMAP_FLAG_VADDR, VFIO_DMA_MAP_FLAG_VADDR, and VFIO_UPDATE_VADDR. This is a partial implementation. Blocking is added in a subsequent patch. Signed-off-by: Steve Sistare <steven.sistare@oracle.com> Reviewed-by: Cornelia Huck <cohuck@redhat.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
40ae9b807b
commit
c3cbab24db
@ -69,6 +69,7 @@ struct vfio_iommu {
|
|||||||
struct rb_root dma_list;
|
struct rb_root dma_list;
|
||||||
struct blocking_notifier_head notifier;
|
struct blocking_notifier_head notifier;
|
||||||
unsigned int dma_avail;
|
unsigned int dma_avail;
|
||||||
|
unsigned int vaddr_invalid_count;
|
||||||
uint64_t pgsize_bitmap;
|
uint64_t pgsize_bitmap;
|
||||||
bool v2;
|
bool v2;
|
||||||
bool nesting;
|
bool nesting;
|
||||||
@ -92,6 +93,7 @@ struct vfio_dma {
|
|||||||
int prot; /* IOMMU_READ/WRITE */
|
int prot; /* IOMMU_READ/WRITE */
|
||||||
bool iommu_mapped;
|
bool iommu_mapped;
|
||||||
bool lock_cap; /* capable(CAP_IPC_LOCK) */
|
bool lock_cap; /* capable(CAP_IPC_LOCK) */
|
||||||
|
bool vaddr_invalid;
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
struct rb_root pfn_list; /* Ex-user pinned pfn list */
|
struct rb_root pfn_list; /* Ex-user pinned pfn list */
|
||||||
unsigned long *bitmap;
|
unsigned long *bitmap;
|
||||||
@ -974,6 +976,8 @@ static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
|
|||||||
vfio_unlink_dma(iommu, dma);
|
vfio_unlink_dma(iommu, dma);
|
||||||
put_task_struct(dma->task);
|
put_task_struct(dma->task);
|
||||||
vfio_dma_bitmap_free(dma);
|
vfio_dma_bitmap_free(dma);
|
||||||
|
if (dma->vaddr_invalid)
|
||||||
|
iommu->vaddr_invalid_count--;
|
||||||
kfree(dma);
|
kfree(dma);
|
||||||
iommu->dma_avail++;
|
iommu->dma_avail++;
|
||||||
}
|
}
|
||||||
@ -1104,7 +1108,8 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
|
|||||||
dma_addr_t iova = unmap->iova;
|
dma_addr_t iova = unmap->iova;
|
||||||
unsigned long size = unmap->size;
|
unsigned long size = unmap->size;
|
||||||
bool unmap_all = unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL;
|
bool unmap_all = unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL;
|
||||||
struct rb_node *n;
|
bool invalidate_vaddr = unmap->flags & VFIO_DMA_UNMAP_FLAG_VADDR;
|
||||||
|
struct rb_node *n, *first_n;
|
||||||
|
|
||||||
mutex_lock(&iommu->lock);
|
mutex_lock(&iommu->lock);
|
||||||
|
|
||||||
@ -1175,7 +1180,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
n = vfio_find_dma_first_node(iommu, iova, size);
|
n = first_n = vfio_find_dma_first_node(iommu, iova, size);
|
||||||
|
|
||||||
while (n) {
|
while (n) {
|
||||||
dma = rb_entry(n, struct vfio_dma, node);
|
dma = rb_entry(n, struct vfio_dma, node);
|
||||||
@ -1191,6 +1196,27 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
|
|||||||
if (dma->task->mm != current->mm)
|
if (dma->task->mm != current->mm)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (invalidate_vaddr) {
|
||||||
|
if (dma->vaddr_invalid) {
|
||||||
|
struct rb_node *last_n = n;
|
||||||
|
|
||||||
|
for (n = first_n; n != last_n; n = rb_next(n)) {
|
||||||
|
dma = rb_entry(n,
|
||||||
|
struct vfio_dma, node);
|
||||||
|
dma->vaddr_invalid = false;
|
||||||
|
iommu->vaddr_invalid_count--;
|
||||||
|
}
|
||||||
|
ret = -EINVAL;
|
||||||
|
unmapped = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dma->vaddr_invalid = true;
|
||||||
|
iommu->vaddr_invalid_count++;
|
||||||
|
unmapped += dma->size;
|
||||||
|
n = rb_next(n);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!RB_EMPTY_ROOT(&dma->pfn_list)) {
|
if (!RB_EMPTY_ROOT(&dma->pfn_list)) {
|
||||||
struct vfio_iommu_type1_dma_unmap nb_unmap;
|
struct vfio_iommu_type1_dma_unmap nb_unmap;
|
||||||
|
|
||||||
@ -1330,6 +1356,7 @@ static bool vfio_iommu_iova_dma_valid(struct vfio_iommu *iommu,
|
|||||||
static int vfio_dma_do_map(struct vfio_iommu *iommu,
|
static int vfio_dma_do_map(struct vfio_iommu *iommu,
|
||||||
struct vfio_iommu_type1_dma_map *map)
|
struct vfio_iommu_type1_dma_map *map)
|
||||||
{
|
{
|
||||||
|
bool set_vaddr = map->flags & VFIO_DMA_MAP_FLAG_VADDR;
|
||||||
dma_addr_t iova = map->iova;
|
dma_addr_t iova = map->iova;
|
||||||
unsigned long vaddr = map->vaddr;
|
unsigned long vaddr = map->vaddr;
|
||||||
size_t size = map->size;
|
size_t size = map->size;
|
||||||
@ -1347,13 +1374,16 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
|
|||||||
if (map->flags & VFIO_DMA_MAP_FLAG_READ)
|
if (map->flags & VFIO_DMA_MAP_FLAG_READ)
|
||||||
prot |= IOMMU_READ;
|
prot |= IOMMU_READ;
|
||||||
|
|
||||||
|
if ((prot && set_vaddr) || (!prot && !set_vaddr))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&iommu->lock);
|
mutex_lock(&iommu->lock);
|
||||||
|
|
||||||
pgsize = (size_t)1 << __ffs(iommu->pgsize_bitmap);
|
pgsize = (size_t)1 << __ffs(iommu->pgsize_bitmap);
|
||||||
|
|
||||||
WARN_ON((pgsize - 1) & PAGE_MASK);
|
WARN_ON((pgsize - 1) & PAGE_MASK);
|
||||||
|
|
||||||
if (!prot || !size || (size | iova | vaddr) & (pgsize - 1)) {
|
if (!size || (size | iova | vaddr) & (pgsize - 1)) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
@ -1364,7 +1394,20 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
|
|||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vfio_find_dma(iommu, iova, size)) {
|
dma = vfio_find_dma(iommu, iova, size);
|
||||||
|
if (set_vaddr) {
|
||||||
|
if (!dma) {
|
||||||
|
ret = -ENOENT;
|
||||||
|
} else if (!dma->vaddr_invalid || dma->iova != iova ||
|
||||||
|
dma->size != size) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
} else {
|
||||||
|
dma->vaddr = vaddr;
|
||||||
|
dma->vaddr_invalid = false;
|
||||||
|
iommu->vaddr_invalid_count--;
|
||||||
|
}
|
||||||
|
goto out_unlock;
|
||||||
|
} else if (dma) {
|
||||||
ret = -EEXIST;
|
ret = -EEXIST;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
@ -2549,6 +2592,7 @@ static int vfio_iommu_type1_check_extension(struct vfio_iommu *iommu,
|
|||||||
case VFIO_TYPE1v2_IOMMU:
|
case VFIO_TYPE1v2_IOMMU:
|
||||||
case VFIO_TYPE1_NESTING_IOMMU:
|
case VFIO_TYPE1_NESTING_IOMMU:
|
||||||
case VFIO_UNMAP_ALL:
|
case VFIO_UNMAP_ALL:
|
||||||
|
case VFIO_UPDATE_VADDR:
|
||||||
return 1;
|
return 1;
|
||||||
case VFIO_DMA_CC_IOMMU:
|
case VFIO_DMA_CC_IOMMU:
|
||||||
if (!iommu)
|
if (!iommu)
|
||||||
@ -2720,7 +2764,8 @@ static int vfio_iommu_type1_map_dma(struct vfio_iommu *iommu,
|
|||||||
{
|
{
|
||||||
struct vfio_iommu_type1_dma_map map;
|
struct vfio_iommu_type1_dma_map map;
|
||||||
unsigned long minsz;
|
unsigned long minsz;
|
||||||
uint32_t mask = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
|
uint32_t mask = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE |
|
||||||
|
VFIO_DMA_MAP_FLAG_VADDR;
|
||||||
|
|
||||||
minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
|
minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
|
||||||
|
|
||||||
@ -2739,6 +2784,7 @@ static int vfio_iommu_type1_unmap_dma(struct vfio_iommu *iommu,
|
|||||||
struct vfio_iommu_type1_dma_unmap unmap;
|
struct vfio_iommu_type1_dma_unmap unmap;
|
||||||
struct vfio_bitmap bitmap = { 0 };
|
struct vfio_bitmap bitmap = { 0 };
|
||||||
uint32_t mask = VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP |
|
uint32_t mask = VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP |
|
||||||
|
VFIO_DMA_UNMAP_FLAG_VADDR |
|
||||||
VFIO_DMA_UNMAP_FLAG_ALL;
|
VFIO_DMA_UNMAP_FLAG_ALL;
|
||||||
unsigned long minsz;
|
unsigned long minsz;
|
||||||
int ret;
|
int ret;
|
||||||
@ -2752,7 +2798,8 @@ static int vfio_iommu_type1_unmap_dma(struct vfio_iommu *iommu,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if ((unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) &&
|
if ((unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) &&
|
||||||
(unmap.flags & VFIO_DMA_UNMAP_FLAG_ALL))
|
(unmap.flags & (VFIO_DMA_UNMAP_FLAG_ALL |
|
||||||
|
VFIO_DMA_UNMAP_FLAG_VADDR)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {
|
if (unmap.flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {
|
||||||
|
Loading…
Reference in New Issue
Block a user