With async VM_BIND, the actual pgtable updates are deferred. Synchronously, a list of map/unmap ops will be generated, but the actual pgtable changes are deferred. To support that, split out op handlers and change the existing non-VM_BIND paths to use them. Note in particular, the vma itself may already be destroyed/freed by the time an UNMAP op runs (or even a MAP op if there is a later queued UNMAP). For this reason, the op handlers cannot reference the vma pointer.
Unified · Split
| @@ -8,6 +8,34 @@ · 7 unmodified lines | |||
| 8 | #include "msm_gem.h" | 8 | #include "msm_gem.h" |
| 9 | #include "msm_mmu.h" | 9 | #include "msm_mmu.h" |
| 10 | 10 | ||
| 11 | #define vm_dbg(fmt, ...) pr_debug("%s:%d: "fmt"\n", __func__, __LINE__, ##__VA_ARGS__) | ||
| 12 | |||
| 13 | /** | ||
| 14 | * struct msm_vm_map_op - create new pgtable mapping | ||
| 15 | */ | ||
| 16 | struct msm_vm_map_op { | ||
| 17 | /** @iova: start address for mapping */ | ||
| 18 | uint64_t iova; | ||
| 19 | /** @range: size of the region to map */ | ||
| 20 | uint64_t range; | ||
| 21 | /** @offset: offset into @sgt to map */ | ||
| 22 | uint64_t offset; | ||
| 23 | /** @sgt: pages to map, or NULL for a PRR mapping */ | ||
| 24 | struct sg_table *sgt; | ||
| 25 | /** @prot: the mapping protection flags */ | ||
| 26 | int prot; | ||
| 27 | }; | ||
| 28 | |||
| 29 | /** | ||
| 30 | * struct msm_vm_unmap_op - unmap a range of pages from pgtable | ||
| 31 | */ | ||
| 32 | struct msm_vm_unmap_op { | ||
| 33 | /** @iova: start address for unmap */ | ||
| 34 | uint64_t iova; | ||
| 35 | /** @range: size of region to unmap */ | ||
| 36 | uint64_t range; | ||
| 37 | }; | ||
| 38 | |||
| 11 | static void | 39 | static void |
| 12 | msm_gem_vm_free(struct drm_gpuvm *gpuvm) | 40 | msm_gem_vm_free(struct drm_gpuvm *gpuvm) |
| 13 | { | 41 | { |
| @@ -21,18 +49,36 @@ msm_gem_vm_free(struct drm_gpuvm *gpuvm) · 7 unmodified lines | |||
| 21 | kfree(vm); | 49 | kfree(vm); |
| 22 | } | 50 | } |
| 23 | 51 | ||
| 52 | static void | ||
| 53 | vm_unmap_op(struct msm_gem_vm *vm, const struct msm_vm_unmap_op *op) | ||
| 54 | { | ||
| 55 | vm_dbg("%p: %016llx %016llx", vm, op->iova, op->iova + op->range); | ||
| 56 | |||
| 57 | vm->mmu->funcs->unmap(vm->mmu, op->iova, op->range); | ||
| 58 | } | ||
| 59 | |||
| 60 | static int | ||
| 61 | vm_map_op(struct msm_gem_vm *vm, const struct msm_vm_map_op *op) | ||
| 62 | { | ||
| 63 | vm_dbg("%p: %016llx %016llx", vm, op->iova, op->iova + op->range); | ||
| 64 | |||
| 65 | return vm->mmu->funcs->map(vm->mmu, op->iova, op->sgt, op->offset, | ||
| 66 | op->range, op->prot); | ||
| 67 | } | ||
| 68 | |||
| 24 | /* Actually unmap memory for the vma */ | 69 | /* Actually unmap memory for the vma */ |
| 25 | void msm_gem_vma_unmap(struct drm_gpuva *vma) | 70 | void msm_gem_vma_unmap(struct drm_gpuva *vma) |
| 26 | { | 71 | { |
| 27 | struct msm_gem_vma *msm_vma = to_msm_vma(vma); | 72 | struct msm_gem_vma *msm_vma = to_msm_vma(vma); |
| 28 | struct msm_gem_vm *vm = to_msm_vm(vma->vm); | ||
| 29 | unsigned size = vma->va.range; | ||
| 30 | 73 | ||
| 31 | /* Don't do anything if the memory isn't mapped */ | 74 | /* Don't do anything if the memory isn't mapped */ |
| 32 | if (!msm_vma->mapped) | 75 | if (!msm_vma->mapped) |
| 33 | return; | 76 | return; |
| 34 | 77 | ||
| 35 | vm->mmu->funcs->unmap(vm->mmu, vma->va.addr, size); | 78 | vm_unmap_op(to_msm_vm(vma->vm), &(struct msm_vm_unmap_op){ |
| 79 | .iova = vma->va.addr, | ||
| 80 | .range = vma->va.range, | ||
| 81 | }); | ||
| 36 | 82 | ||
| 37 | msm_vma->mapped = false; | 83 | msm_vma->mapped = false; |
| 38 | } | 84 | } |
| @@ -42,7 +88,6 @@ int · 3 unmodified lines | |||
| 42 | msm_gem_vma_map(struct drm_gpuva *vma, int prot, struct sg_table *sgt) | 88 | msm_gem_vma_map(struct drm_gpuva *vma, int prot, struct sg_table *sgt) |
| 43 | { | 89 | { |
| 44 | struct msm_gem_vma *msm_vma = to_msm_vma(vma); | 90 | struct msm_gem_vma *msm_vma = to_msm_vma(vma); |
| 45 | struct msm_gem_vm *vm = to_msm_vm(vma->vm); | ||
| 46 | int ret; | 91 | int ret; |
| 47 | 92 | ||
| 48 | if (GEM_WARN_ON(!vma->va.addr)) | 93 | if (GEM_WARN_ON(!vma->va.addr)) |
| @@ -62,9 +107,13 @@ msm_gem_vma_map(struct drm_gpuva *vma, int prot, struct sg_table *sgt) · 13 unmodified lines | |||
| 62 | * Revisit this if we can come up with a scheme to pre-alloc pages | 107 | * Revisit this if we can come up with a scheme to pre-alloc pages |
| 63 | * for the pgtable in map/unmap ops. | 108 | * for the pgtable in map/unmap ops. |
| 64 | */ | 109 | */ |
| 65 | ret = vm->mmu->funcs->map(vm->mmu, vma->va.addr, sgt, | 110 | ret = vm_map_op(to_msm_vm(vma->vm), &(struct msm_vm_map_op){ |
| 66 | vma->gem.offset, vma->va.range, | 111 | .iova = vma->va.addr, |
| 67 | prot); | 112 | .range = vma->va.range, |
| 113 | .offset = vma->gem.offset, | ||
| 114 | .sgt = sgt, | ||
| 115 | .prot = prot, | ||
| 116 | }); | ||
| 68 | if (ret) { | 117 | if (ret) { |
| 69 | msm_vma->mapped = false; | 118 | msm_vma->mapped = false; |
| 70 | } | 119 | } |