- DRM_GPUVM_SM_MAP_OPS_FLAG_SPLIT_MADVISE: This flag is used by drm_gpuvm_sm_map_ops_create to iterate over GPUVMA's in the user-provided range and split the existing non-GEM object VMA if the start or end of the input range lies within it. The operations can create up to 2 REMAPS and 2 MAPs. The purpose of this operation is to be used by the Xe driver to assign attributes to GPUVMA's within the user-defined range. Unlike drm_gpuvm_sm_map_ops_flags in default mode, the operation with this flag will never have UNMAPs and merges, and can be without any final operations.
v2 - use drm_gpuvm_sm_map_ops_create with flags instead of defining new ops_create (Danilo) - Add doc (Danilo) v3 - Fix doc - Fix unmapping check v4 - Fix mapping for non madvise ops v5 - Fix mapping (Matthew Brost) - Rebase on top of struct changes Cc: Danilo Krummrich <d...@redhat.com> Cc: Matthew Brost <matthew.br...@intel.com> Cc: Boris Brezillon <bbrezil...@kernel.org> Cc: <dri-devel@lists.freedesktop.org> Signed-off-by: Himal Prasad Ghimiray<himal.prasad.ghimi...@intel.com> --- drivers/gpu/drm/drm_gpuvm.c | 87 +++++++++++++++++++++++++++++++------ include/drm/drm_gpuvm.h | 11 ++++- 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index f04d80a3a63b..2aeae8c2296f 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -2110,6 +2110,8 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, { struct drm_gpuva *va, *next; u64 req_end = req->va.addr + req->va.range; + bool is_madvise_ops = (req->flags & DRM_GPUVM_SM_MAP_OPS_FLAG_SPLIT_MADVISE); + bool needs_map = !is_madvise_ops; int ret; if (unlikely(!drm_gpuvm_range_valid(gpuvm, req->va.addr, req->va.range))) @@ -2122,26 +2124,35 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, u64 range = va->va.range; u64 end = addr + range; bool merge = !!va->gem.obj; + bool skip_madvise_ops = is_madvise_ops && merge; + needs_map = !is_madvise_ops; if (addr == req->va.addr) { merge &= obj == req->gem.obj && offset == req->gem.offset; if (end == req_end) { - ret = op_unmap_cb(ops, priv, va, merge); - if (ret) - return ret; + if (!is_madvise_ops) { + ret = op_unmap_cb(ops, priv, va, merge); + if (ret) + return ret; + } break; } if (end < req_end) { - ret = op_unmap_cb(ops, priv, va, merge); - if (ret) - return ret; + if (!is_madvise_ops) { + ret = op_unmap_cb(ops, priv, va, merge); + if (ret) + return ret; + } continue; } if (end > req_end) { + if (skip_madvise_ops) + break; + struct drm_gpuva_op_map n = { .va.addr = req_end, .va.range = range - req->va.range, @@ -2156,6 +2167,9 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, ret = op_remap_cb(ops, priv, NULL, &n, &u); if (ret) return ret; + + if (is_madvise_ops) + needs_map = true; break; } } else if (addr < req->va.addr) { @@ -2173,20 +2187,45 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, u.keep = merge; if (end == req_end) { + if (skip_madvise_ops) + break; + ret = op_remap_cb(ops, priv, &p, NULL, &u); if (ret) return ret; + + if (is_madvise_ops) + needs_map = true; + break; } if (end < req_end) { + if (skip_madvise_ops) + continue; + ret = op_remap_cb(ops, priv, &p, NULL, &u); if (ret) return ret; + + if (is_madvise_ops) { + struct drm_gpuva_op_map map_req = { + .va.addr = req->va.addr, + .va.range = end - req->va.addr, + }; + + ret = op_map_cb(ops, priv, &map_req); + if (ret) + return ret; + } + continue; } if (end > req_end) { + if (skip_madvise_ops) + break; + struct drm_gpuva_op_map n = { .va.addr = req_end, .va.range = end - req_end, @@ -2198,6 +2237,9 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, ret = op_remap_cb(ops, priv, &p, &n, &u); if (ret) return ret; + + if (is_madvise_ops) + needs_map = true; break; } } else if (addr > req->va.addr) { @@ -2206,20 +2248,29 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, (addr - req->va.addr); if (end == req_end) { - ret = op_unmap_cb(ops, priv, va, merge); - if (ret) - return ret; + if (!is_madvise_ops) { + ret = op_unmap_cb(ops, priv, va, merge); + if (ret) + return ret; + } + break; } if (end < req_end) { - ret = op_unmap_cb(ops, priv, va, merge); - if (ret) - return ret; + if (!is_madvise_ops) { + ret = op_unmap_cb(ops, priv, va, merge); + if (ret) + return ret; + } + continue; } if (end > req_end) { + if (skip_madvise_ops) + break; + struct drm_gpuva_op_map n = { .va.addr = req_end, .va.range = end - req_end, @@ -2234,12 +2285,20 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, ret = op_remap_cb(ops, priv, NULL, &n, &u); if (ret) return ret; + + if (is_madvise_ops) { + struct drm_gpuva_op_map map_req = { + .va.addr = addr, + .va.range = req_end - addr, + }; + + return op_map_cb(ops, priv, &map_req); + } break; } } } - - return op_map_cb(ops, priv, req); + return needs_map ? op_map_cb(ops, priv, req) : 0; } static int diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index 75c616fdc119..a8e9f70501ef 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -811,10 +811,19 @@ enum drm_gpuva_op_type { }; /** DOC: flags for struct drm_gpuva_op_map - * %DRM_GPUVM_SM_MAP_OPS_FLAG_NONE DEFAULT split and merge, + * %DRM_GPUVM_SM_MAP_OPS_FLAG_NONE: DEFAULT split and merge, * It cannot be combined with other flags. + * + * %DRM_GPUVM_SM_MAP_OPS_FLAG_SPLIT_MADVISE: This flag is used by + * drm_gpuvm_sm_map_ops_create to iterate over GPUVMA's in the user-provided + * range and split the existing non-GEM object VMA if the start or end of + * the input range lies within it. The operations can create up to 2 REMAPS + * and 2 MAPs. Unlike DRM_GPUVM_SM_MAP_OPS_FLAG_NONE flag, the operation with + * this flag will never have UNMAPs and merges, and can be without any final + * operations. */ #define DRM_GPUVM_SM_MAP_OPS_FLAG_NONE 0 +#define DRM_GPUVM_SM_MAP_OPS_FLAG_SPLIT_MADVISE BIT(0) /** * struct drm_gpuva_op_map - GPU VA map operation -- 2.34.1