Skip to content

Commit baf1638

Browse files
hghimirambrost05
authored andcommitted
drm/gpuvm: Introduce drm_gpuvm_madvise_ops_create
This ops is used to iterate over GPUVA's in the user-provided range and split the existing sparse VMA's if the start or end of the input range lies within it. The operations can create up to 2 REMAPS and 2 MAPs. The primary use case is for drivers to assign attributes to GPU VAs in the specified range without performing unmaps or merging mappings, supporting fine-grained control over sparse va's. Cc: Danilo Krummrich <dakr@kernel.org> Cc: Matthew Brost <matthew.brost@intel.com> Cc: Boris Brezillon <bbrezillon@kernel.org> Cc: <dri-devel@lists.freedesktop.org> Signed-off-by: Himal Prasad Ghimiray<himal.prasad.ghimiray@intel.com> Reviewed-by: Matthew Brost <matthew.brost@intel.com> Acked-by: Danilo Krummrich <dakr@kernel.org> Signed-off-by: Matthew Brost <matthew.brost@intel.com> Link: https://lore.kernel.org/r/20250819162058.2777306-4-himal.prasad.ghimiray@intel.com
1 parent 3309323 commit baf1638

2 files changed

Lines changed: 191 additions & 37 deletions

File tree

drivers/gpu/drm/drm_gpuvm.c

Lines changed: 188 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,71 @@
420420
* new: |-----------|-----| (b.bo_offset=m,a.bo_offset=n+2)
421421
*/
422422

423+
/**
424+
* DOC: Madvise Logic - Splitting and Traversal
425+
*
426+
* This logic handles GPU VA range updates by generating remap and map operations
427+
* without performing unmaps or merging existing mappings.
428+
*
429+
* 1) The requested range lies entirely within a single drm_gpuva. The logic splits
430+
* the existing mapping at the start and end boundaries and inserts a new map.
431+
*
432+
* ::
433+
* a start end b
434+
* pre: |-----------------------|
435+
* drm_gpuva1
436+
*
437+
* a start end b
438+
* new: |-----|=========|-------|
439+
* remap map remap
440+
*
441+
* one REMAP and one MAP : Same behaviour as SPLIT and MERGE
442+
*
443+
* 2) The requested range spans multiple drm_gpuva regions. The logic traverses
444+
* across boundaries, remapping the start and end segments, and inserting two
445+
* map operations to cover the full range.
446+
*
447+
* :: a start b c end d
448+
* pre: |------------------|--------------|------------------|
449+
* drm_gpuva1 drm_gpuva2 drm_gpuva3
450+
*
451+
* a start b c end d
452+
* new: |-------|==========|--------------|========|---------|
453+
* remap1 map1 drm_gpuva2 map2 remap2
454+
*
455+
* two REMAPS and two MAPS
456+
*
457+
* 3) Either start or end lies within a drm_gpuva. A single remap and map operation
458+
* are generated to update the affected portion.
459+
*
460+
*
461+
* :: a/start b c end d
462+
* pre: |------------------|--------------|------------------|
463+
* drm_gpuva1 drm_gpuva2 drm_gpuva3
464+
*
465+
* a/start b c end d
466+
* new: |------------------|--------------|========|---------|
467+
* drm_gpuva1 drm_gpuva2 map1 remap1
468+
*
469+
* :: a start b c/end d
470+
* pre: |------------------|--------------|------------------|
471+
* drm_gpuva1 drm_gpuva2 drm_gpuva3
472+
*
473+
* a start b c/end d
474+
* new: |-------|==========|--------------|------------------|
475+
* remap1 map1 drm_gpuva2 drm_gpuva3
476+
*
477+
* one REMAP and one MAP
478+
*
479+
* 4) Both start and end align with existing drm_gpuva boundaries. No operations
480+
* are needed as the range is already covered.
481+
*
482+
* 5) No existing drm_gpuvas. No operations.
483+
*
484+
* Unlike drm_gpuvm_sm_map_ops_create, this logic avoids unmaps and merging,
485+
* focusing solely on remap and map operations for efficient traversal and update.
486+
*/
487+
423488
/**
424489
* DOC: Locking
425490
*
@@ -2063,6 +2128,9 @@ op_map_cb(const struct drm_gpuvm_ops *fn, void *priv,
20632128
{
20642129
struct drm_gpuva_op op = {};
20652130

2131+
if (!req)
2132+
return 0;
2133+
20662134
op.op = DRM_GPUVA_OP_MAP;
20672135
op.map.va.addr = req->map.va.addr;
20682136
op.map.va.range = req->map.va.range;
@@ -2092,10 +2160,13 @@ op_remap_cb(const struct drm_gpuvm_ops *fn, void *priv,
20922160

20932161
static int
20942162
op_unmap_cb(const struct drm_gpuvm_ops *fn, void *priv,
2095-
struct drm_gpuva *va, bool merge)
2163+
struct drm_gpuva *va, bool merge, bool madvise)
20962164
{
20972165
struct drm_gpuva_op op = {};
20982166

2167+
if (madvise)
2168+
return 0;
2169+
20992170
op.op = DRM_GPUVA_OP_UNMAP;
21002171
op.unmap.va = va;
21012172
op.unmap.keep = merge;
@@ -2106,11 +2177,12 @@ op_unmap_cb(const struct drm_gpuvm_ops *fn, void *priv,
21062177
static int
21072178
__drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
21082179
const struct drm_gpuvm_ops *ops, void *priv,
2109-
const struct drm_gpuvm_map_req *req)
2180+
const struct drm_gpuvm_map_req *req,
2181+
bool madvise)
21102182
{
21112183
struct drm_gem_object *req_obj = req->map.gem.obj;
2184+
const struct drm_gpuvm_map_req *op_map = madvise ? NULL : req;
21122185
struct drm_gpuva *va, *next;
2113-
21142186
u64 req_offset = req->map.gem.offset;
21152187
u64 req_range = req->map.va.range;
21162188
u64 req_addr = req->map.va.addr;
@@ -2128,19 +2200,22 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
21282200
u64 end = addr + range;
21292201
bool merge = !!va->gem.obj;
21302202

2203+
if (madvise && obj)
2204+
continue;
2205+
21312206
if (addr == req_addr) {
21322207
merge &= obj == req_obj &&
21332208
offset == req_offset;
21342209

21352210
if (end == req_end) {
2136-
ret = op_unmap_cb(ops, priv, va, merge);
2211+
ret = op_unmap_cb(ops, priv, va, merge, madvise);
21372212
if (ret)
21382213
return ret;
21392214
break;
21402215
}
21412216

21422217
if (end < req_end) {
2143-
ret = op_unmap_cb(ops, priv, va, merge);
2218+
ret = op_unmap_cb(ops, priv, va, merge, madvise);
21442219
if (ret)
21452220
return ret;
21462221
continue;
@@ -2161,6 +2236,9 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
21612236
ret = op_remap_cb(ops, priv, NULL, &n, &u);
21622237
if (ret)
21632238
return ret;
2239+
2240+
if (madvise)
2241+
op_map = req;
21642242
break;
21652243
}
21662244
} else if (addr < req_addr) {
@@ -2181,13 +2259,28 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
21812259
ret = op_remap_cb(ops, priv, &p, NULL, &u);
21822260
if (ret)
21832261
return ret;
2262+
2263+
if (madvise)
2264+
op_map = req;
21842265
break;
21852266
}
21862267

21872268
if (end < req_end) {
21882269
ret = op_remap_cb(ops, priv, &p, NULL, &u);
21892270
if (ret)
21902271
return ret;
2272+
2273+
if (madvise) {
2274+
struct drm_gpuvm_map_req map_req = {
2275+
.map.va.addr = req_addr,
2276+
.map.va.range = end - req_addr,
2277+
};
2278+
2279+
ret = op_map_cb(ops, priv, &map_req);
2280+
if (ret)
2281+
return ret;
2282+
}
2283+
21912284
continue;
21922285
}
21932286

@@ -2203,6 +2296,9 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
22032296
ret = op_remap_cb(ops, priv, &p, &n, &u);
22042297
if (ret)
22052298
return ret;
2299+
2300+
if (madvise)
2301+
op_map = req;
22062302
break;
22072303
}
22082304
} else if (addr > req_addr) {
@@ -2211,16 +2307,18 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
22112307
(addr - req_addr);
22122308

22132309
if (end == req_end) {
2214-
ret = op_unmap_cb(ops, priv, va, merge);
2310+
ret = op_unmap_cb(ops, priv, va, merge, madvise);
22152311
if (ret)
22162312
return ret;
2313+
22172314
break;
22182315
}
22192316

22202317
if (end < req_end) {
2221-
ret = op_unmap_cb(ops, priv, va, merge);
2318+
ret = op_unmap_cb(ops, priv, va, merge, madvise);
22222319
if (ret)
22232320
return ret;
2321+
22242322
continue;
22252323
}
22262324

@@ -2239,12 +2337,20 @@ __drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm,
22392337
ret = op_remap_cb(ops, priv, NULL, &n, &u);
22402338
if (ret)
22412339
return ret;
2340+
2341+
if (madvise) {
2342+
struct drm_gpuvm_map_req map_req = {
2343+
.map.va.addr = addr,
2344+
.map.va.range = req_end - addr,
2345+
};
2346+
2347+
return op_map_cb(ops, priv, &map_req);
2348+
}
22422349
break;
22432350
}
22442351
}
22452352
}
2246-
2247-
return op_map_cb(ops, priv, req);
2353+
return op_map_cb(ops, priv, op_map);
22482354
}
22492355

22502356
static int
@@ -2296,7 +2402,7 @@ __drm_gpuvm_sm_unmap(struct drm_gpuvm *gpuvm,
22962402
if (ret)
22972403
return ret;
22982404
} else {
2299-
ret = op_unmap_cb(ops, priv, va, false);
2405+
ret = op_unmap_cb(ops, priv, va, false, false);
23002406
if (ret)
23012407
return ret;
23022408
}
@@ -2345,7 +2451,7 @@ drm_gpuvm_sm_map(struct drm_gpuvm *gpuvm, void *priv,
23452451
ops->sm_step_unmap)))
23462452
return -EINVAL;
23472453

2348-
return __drm_gpuvm_sm_map(gpuvm, ops, priv, req);
2454+
return __drm_gpuvm_sm_map(gpuvm, ops, priv, req, false);
23492455
}
23502456
EXPORT_SYMBOL_GPL(drm_gpuvm_sm_map);
23512457

@@ -2483,7 +2589,7 @@ drm_gpuvm_sm_map_exec_lock(struct drm_gpuvm *gpuvm,
24832589
return ret;
24842590
}
24852591

2486-
return __drm_gpuvm_sm_map(gpuvm, &lock_ops, exec, req);
2592+
return __drm_gpuvm_sm_map(gpuvm, &lock_ops, exec, req, false);
24872593

24882594
}
24892595
EXPORT_SYMBOL_GPL(drm_gpuvm_sm_map_exec_lock);
@@ -2602,6 +2708,38 @@ static const struct drm_gpuvm_ops gpuvm_list_ops = {
26022708
.sm_step_unmap = drm_gpuva_sm_step,
26032709
};
26042710

2711+
static struct drm_gpuva_ops *
2712+
__drm_gpuvm_sm_map_ops_create(struct drm_gpuvm *gpuvm,
2713+
const struct drm_gpuvm_map_req *req,
2714+
bool madvise)
2715+
{
2716+
struct drm_gpuva_ops *ops;
2717+
struct {
2718+
struct drm_gpuvm *vm;
2719+
struct drm_gpuva_ops *ops;
2720+
} args;
2721+
int ret;
2722+
2723+
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
2724+
if (unlikely(!ops))
2725+
return ERR_PTR(-ENOMEM);
2726+
2727+
INIT_LIST_HEAD(&ops->list);
2728+
2729+
args.vm = gpuvm;
2730+
args.ops = ops;
2731+
2732+
ret = __drm_gpuvm_sm_map(gpuvm, &gpuvm_list_ops, &args, req, madvise);
2733+
if (ret)
2734+
goto err_free_ops;
2735+
2736+
return ops;
2737+
2738+
err_free_ops:
2739+
drm_gpuva_ops_free(gpuvm, ops);
2740+
return ERR_PTR(ret);
2741+
}
2742+
26052743
/**
26062744
* drm_gpuvm_sm_map_ops_create() - creates the &drm_gpuva_ops to split and merge
26072745
* @gpuvm: the &drm_gpuvm representing the GPU VA space
@@ -2635,34 +2773,47 @@ struct drm_gpuva_ops *
26352773
drm_gpuvm_sm_map_ops_create(struct drm_gpuvm *gpuvm,
26362774
const struct drm_gpuvm_map_req *req)
26372775
{
2638-
struct drm_gpuva_ops *ops;
2639-
struct {
2640-
struct drm_gpuvm *vm;
2641-
struct drm_gpuva_ops *ops;
2642-
} args;
2643-
int ret;
2644-
2645-
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
2646-
if (unlikely(!ops))
2647-
return ERR_PTR(-ENOMEM);
2648-
2649-
INIT_LIST_HEAD(&ops->list);
2650-
2651-
args.vm = gpuvm;
2652-
args.ops = ops;
2653-
2654-
ret = __drm_gpuvm_sm_map(gpuvm, &gpuvm_list_ops, &args, req);
2655-
if (ret)
2656-
goto err_free_ops;
2657-
2658-
return ops;
2659-
2660-
err_free_ops:
2661-
drm_gpuva_ops_free(gpuvm, ops);
2662-
return ERR_PTR(ret);
2776+
return __drm_gpuvm_sm_map_ops_create(gpuvm, req, false);
26632777
}
26642778
EXPORT_SYMBOL_GPL(drm_gpuvm_sm_map_ops_create);
26652779

2780+
/**
2781+
* drm_gpuvm_madvise_ops_create() - creates the &drm_gpuva_ops to split
2782+
* @gpuvm: the &drm_gpuvm representing the GPU VA space
2783+
* @req: map request arguments
2784+
*
2785+
* This function creates a list of operations to perform splitting
2786+
* of existent mapping(s) at start or end, based on the request map.
2787+
*
2788+
* The list can be iterated with &drm_gpuva_for_each_op and must be processed
2789+
* in the given order. It can contain map and remap operations, but it
2790+
* also can be empty if no operation is required, e.g. if the requested mapping
2791+
* already exists is the exact same way.
2792+
*
2793+
* There will be no unmap operations, a maximum of two remap operations and two
2794+
* map operations. The two map operations correspond to: one from start to the
2795+
* end of drm_gpuvaX, and another from the start of drm_gpuvaY to end.
2796+
*
2797+
* Note that before calling this function again with another mapping request it
2798+
* is necessary to update the &drm_gpuvm's view of the GPU VA space. The
2799+
* previously obtained operations must be either processed or abandoned. To
2800+
* update the &drm_gpuvm's view of the GPU VA space drm_gpuva_insert(),
2801+
* drm_gpuva_destroy_locked() and/or drm_gpuva_destroy_unlocked() should be
2802+
* used.
2803+
*
2804+
* After the caller finished processing the returned &drm_gpuva_ops, they must
2805+
* be freed with &drm_gpuva_ops_free.
2806+
*
2807+
* Returns: a pointer to the &drm_gpuva_ops on success, an ERR_PTR on failure
2808+
*/
2809+
struct drm_gpuva_ops *
2810+
drm_gpuvm_madvise_ops_create(struct drm_gpuvm *gpuvm,
2811+
const struct drm_gpuvm_map_req *req)
2812+
{
2813+
return __drm_gpuvm_sm_map_ops_create(gpuvm, req, true);
2814+
}
2815+
EXPORT_SYMBOL_GPL(drm_gpuvm_madvise_ops_create);
2816+
26662817
/**
26672818
* drm_gpuvm_sm_unmap_ops_create() - creates the &drm_gpuva_ops to split on
26682819
* unmap

include/drm/drm_gpuvm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,9 @@ struct drm_gpuvm_map_req {
10621062
struct drm_gpuva_ops *
10631063
drm_gpuvm_sm_map_ops_create(struct drm_gpuvm *gpuvm,
10641064
const struct drm_gpuvm_map_req *req);
1065+
struct drm_gpuva_ops *
1066+
drm_gpuvm_madvise_ops_create(struct drm_gpuvm *gpuvm,
1067+
const struct drm_gpuvm_map_req *req);
10651068

10661069
struct drm_gpuva_ops *
10671070
drm_gpuvm_sm_unmap_ops_create(struct drm_gpuvm *gpuvm,

0 commit comments

Comments
 (0)