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
20932161static int
20942162op_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,
21062177static 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
22502356static 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}
23502456EXPORT_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}
24892595EXPORT_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 *
26352773drm_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}
26642778EXPORT_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
0 commit comments