@@ -211,6 +211,11 @@ struct __guc_capture_ads_cache {
211
211
212
212
struct xe_guc_state_capture {
213
213
const struct __guc_mmio_reg_descr_group * reglists ;
214
+ /**
215
+ * NOTE: steered registers have multiple instances depending on the HW configuration
216
+ * (slices or dual-sub-slices) and thus depends on HW fuses discovered
217
+ */
218
+ struct __guc_mmio_reg_descr_group * extlists ;
214
219
struct __guc_capture_ads_cache ads_cache [GUC_CAPTURE_LIST_INDEX_MAX ]
215
220
[GUC_STATE_CAPTURE_TYPE_MAX ]
216
221
[GUC_CAPTURE_LIST_CLASS_MAX ];
@@ -245,14 +250,156 @@ guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
245
250
return NULL ;
246
251
}
247
252
253
+ struct __ext_steer_reg {
254
+ const char * name ;
255
+ struct xe_reg_mcr reg ;
256
+ };
257
+
258
+ static const struct __ext_steer_reg xe_extregs [] = {
259
+ {"SAMPLER_INSTDONE" , SAMPLER_INSTDONE },
260
+ {"ROW_INSTDONE" , ROW_INSTDONE }
261
+ };
262
+
263
+ static const struct __ext_steer_reg xehpg_extregs [] = {
264
+ {"SC_INSTDONE" , XEHPG_SC_INSTDONE },
265
+ {"SC_INSTDONE_EXTRA" , XEHPG_SC_INSTDONE_EXTRA },
266
+ {"SC_INSTDONE_EXTRA2" , XEHPG_SC_INSTDONE_EXTRA2 },
267
+ {"INSTDONE_GEOM_SVGUNIT" , XEHPG_INSTDONE_GEOM_SVGUNIT }
268
+ };
269
+
270
+ static void __fill_ext_reg (struct __guc_mmio_reg_descr * ext ,
271
+ const struct __ext_steer_reg * extlist ,
272
+ int slice_id , int subslice_id )
273
+ {
274
+ if (!ext || !extlist )
275
+ return ;
276
+
277
+ ext -> reg = XE_REG (extlist -> reg .__reg .addr );
278
+ ext -> flags = FIELD_PREP (GUC_REGSET_STEERING_NEEDED , 1 );
279
+ ext -> flags = FIELD_PREP (GUC_REGSET_STEERING_GROUP , slice_id );
280
+ ext -> flags |= FIELD_PREP (GUC_REGSET_STEERING_INSTANCE , subslice_id );
281
+ ext -> regname = extlist -> name ;
282
+ }
283
+
284
+ static int
285
+ __alloc_ext_regs (struct drm_device * drm , struct __guc_mmio_reg_descr_group * newlist ,
286
+ const struct __guc_mmio_reg_descr_group * rootlist , int num_regs )
287
+ {
288
+ struct __guc_mmio_reg_descr * list ;
289
+
290
+ list = drmm_kzalloc (drm , num_regs * sizeof (struct __guc_mmio_reg_descr ), GFP_KERNEL );
291
+ if (!list )
292
+ return - ENOMEM ;
293
+
294
+ newlist -> list = list ;
295
+ newlist -> num_regs = num_regs ;
296
+ newlist -> owner = rootlist -> owner ;
297
+ newlist -> engine = rootlist -> engine ;
298
+ newlist -> type = rootlist -> type ;
299
+
300
+ return 0 ;
301
+ }
302
+
303
+ static int guc_capture_get_steer_reg_num (struct xe_device * xe )
304
+ {
305
+ int num = ARRAY_SIZE (xe_extregs );
306
+
307
+ if (GRAPHICS_VERx100 (xe ) >= 1255 )
308
+ num += ARRAY_SIZE (xehpg_extregs );
309
+
310
+ return num ;
311
+ }
312
+
313
+ static void guc_capture_alloc_steered_lists (struct xe_guc * guc )
314
+ {
315
+ struct xe_gt * gt = guc_to_gt (guc );
316
+ u16 slice , subslice ;
317
+ int iter , i , total = 0 ;
318
+ const struct __guc_mmio_reg_descr_group * lists = guc -> capture -> reglists ;
319
+ const struct __guc_mmio_reg_descr_group * list ;
320
+ struct __guc_mmio_reg_descr_group * extlists ;
321
+ struct __guc_mmio_reg_descr * extarray ;
322
+ bool has_xehpg_extregs = GRAPHICS_VERx100 (gt_to_xe (gt )) >= 1255 ;
323
+ struct drm_device * drm = & gt_to_xe (gt )-> drm ;
324
+ bool has_rcs_ccs = false;
325
+ struct xe_hw_engine * hwe ;
326
+ enum xe_hw_engine_id id ;
327
+
328
+ /*
329
+ * If GT has no rcs/ccs, no need to alloc steered list.
330
+ * Currently, only rcs/ccs has steering register, if in the future,
331
+ * other engine types has steering register, this condition check need
332
+ * to be extended
333
+ */
334
+ for_each_hw_engine (hwe , gt , id ) {
335
+ if (xe_engine_class_to_guc_capture_class (hwe -> class ) ==
336
+ GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE ) {
337
+ has_rcs_ccs = true;
338
+ break ;
339
+ }
340
+ }
341
+
342
+ if (!has_rcs_ccs )
343
+ return ;
344
+
345
+ /* steered registers currently only exist for the render-class */
346
+ list = guc_capture_get_one_list (lists , GUC_CAPTURE_LIST_INDEX_PF ,
347
+ GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS ,
348
+ GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE );
349
+ /*
350
+ * Skip if this platform has no engine class registers or if extlists
351
+ * was previously allocated
352
+ */
353
+ if (!list || guc -> capture -> extlists )
354
+ return ;
355
+
356
+ total = bitmap_weight (gt -> fuse_topo .g_dss_mask , sizeof (gt -> fuse_topo .g_dss_mask ) * 8 ) *
357
+ guc_capture_get_steer_reg_num (guc_to_xe (guc ));
358
+
359
+ if (!total )
360
+ return ;
361
+
362
+ /* allocate an extra for an end marker */
363
+ extlists = drmm_kzalloc (drm , 2 * sizeof (struct __guc_mmio_reg_descr_group ), GFP_KERNEL );
364
+ if (!extlists )
365
+ return ;
366
+
367
+ if (__alloc_ext_regs (drm , & extlists [0 ], list , total )) {
368
+ drmm_kfree (drm , extlists );
369
+ return ;
370
+ }
371
+
372
+ /* For steering registers, the list is generated at run-time */
373
+ extarray = (struct __guc_mmio_reg_descr * )extlists [0 ].list ;
374
+ for_each_dss_steering (iter , gt , slice , subslice ) {
375
+ for (i = 0 ; i < ARRAY_SIZE (xe_extregs ); ++ i ) {
376
+ __fill_ext_reg (extarray , & xe_extregs [i ], slice , subslice );
377
+ ++ extarray ;
378
+ }
379
+
380
+ if (has_xehpg_extregs )
381
+ for (i = 0 ; i < ARRAY_SIZE (xehpg_extregs ); ++ i ) {
382
+ __fill_ext_reg (extarray , & xehpg_extregs [i ], slice , subslice );
383
+ ++ extarray ;
384
+ }
385
+ }
386
+
387
+ extlists [0 ].num_regs = total ;
388
+
389
+ xe_gt_dbg (guc_to_gt (guc ), "capture found %d ext-regs.\n" , total );
390
+ guc -> capture -> extlists = extlists ;
391
+ }
392
+
248
393
static int
249
394
guc_capture_list_init (struct xe_guc * guc , u32 owner , u32 type ,
250
395
enum guc_capture_list_class_type capture_class , struct guc_mmio_reg * ptr ,
251
396
u16 num_entries )
252
397
{
253
- u32 i = 0 ;
398
+ u32 ptr_idx = 0 , list_idx = 0 ;
254
399
const struct __guc_mmio_reg_descr_group * reglists = guc -> capture -> reglists ;
400
+ struct __guc_mmio_reg_descr_group * extlists = guc -> capture -> extlists ;
255
401
const struct __guc_mmio_reg_descr_group * match ;
402
+ u32 list_num ;
256
403
257
404
if (!reglists )
258
405
return - ENODEV ;
@@ -261,16 +408,28 @@ guc_capture_list_init(struct xe_guc *guc, u32 owner, u32 type,
261
408
if (!match )
262
409
return - ENODATA ;
263
410
264
- for (i = 0 ; i < num_entries && i < match -> num_regs ; ++ i ) {
265
- ptr [i ].offset = match -> list [i ].reg .addr ;
266
- ptr [i ].value = 0xDEADF00D ;
267
- ptr [i ].flags = match -> list [i ].flags ;
268
- ptr [i ].mask = match -> list [i ].mask ;
411
+ list_num = match -> num_regs ;
412
+ for (list_idx = 0 ; ptr_idx < num_entries && list_idx < list_num ; ++ list_idx , ++ ptr_idx ) {
413
+ ptr [ptr_idx ].offset = match -> list [list_idx ].reg .addr ;
414
+ ptr [ptr_idx ].value = 0xDEADF00D ;
415
+ ptr [ptr_idx ].flags = match -> list [list_idx ].flags ;
416
+ ptr [ptr_idx ].mask = match -> list [list_idx ].mask ;
269
417
}
270
418
271
- if (i < num_entries )
272
- xe_gt_dbg (guc_to_gt (guc ), "Got short capture reglist init: %d out %d.\n" , i ,
273
- num_entries );
419
+ match = guc_capture_get_one_list (extlists , owner , type , capture_class );
420
+ if (match )
421
+ for (ptr_idx = list_num , list_idx = 0 ;
422
+ ptr_idx < num_entries && list_idx < match -> num_regs ;
423
+ ++ ptr_idx , ++ list_idx ) {
424
+ ptr [ptr_idx ].offset = match -> list [list_idx ].reg .addr ;
425
+ ptr [ptr_idx ].value = 0xDEADF00D ;
426
+ ptr [ptr_idx ].flags = match -> list [list_idx ].flags ;
427
+ ptr [ptr_idx ].mask = match -> list [list_idx ].mask ;
428
+ }
429
+
430
+ if (ptr_idx < num_entries )
431
+ xe_gt_dbg (guc_to_gt (guc ), "Got short capture reglist init: %d out-of %d.\n" ,
432
+ ptr_idx , num_entries );
274
433
275
434
return 0 ;
276
435
}
@@ -280,12 +439,22 @@ guc_cap_list_num_regs(struct xe_guc *guc, u32 owner, u32 type,
280
439
enum guc_capture_list_class_type capture_class )
281
440
{
282
441
const struct __guc_mmio_reg_descr_group * match ;
442
+ int num_regs = 0 ;
283
443
284
444
match = guc_capture_get_one_list (guc -> capture -> reglists , owner , type , capture_class );
285
- if (!match )
286
- return 0 ;
445
+ if (match )
446
+ num_regs = match -> num_regs ;
447
+
448
+ match = guc_capture_get_one_list (guc -> capture -> extlists , owner , type , capture_class );
449
+ if (match )
450
+ num_regs += match -> num_regs ;
451
+ else
452
+ /* Estimate steering register size for rcs/ccs */
453
+ if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE )
454
+ num_regs += guc_capture_get_steer_reg_num (guc_to_xe (guc )) *
455
+ XE_MAX_DSS_FUSE_BITS ;
287
456
288
- return match -> num_regs ;
457
+ return num_regs ;
289
458
}
290
459
291
460
static int
@@ -500,14 +669,31 @@ size_t xe_guc_capture_ads_input_worst_size(struct xe_guc *guc)
500
669
return PAGE_ALIGN (total_size );
501
670
}
502
671
672
+ /*
673
+ * xe_guc_capture_steered_list_init - Init steering register list
674
+ * @guc: The GuC object
675
+ *
676
+ * Init steering register list for GuC register capture
677
+ */
678
+ void xe_guc_capture_steered_list_init (struct xe_guc * guc )
679
+ {
680
+ /*
681
+ * For certain engine classes, there are slice and subslice
682
+ * level registers requiring steering. We allocate and populate
683
+ * these based on hw config and add it as an extension list at
684
+ * the end of the pre-populated render list.
685
+ */
686
+ guc_capture_alloc_steered_lists (guc );
687
+ }
688
+
503
689
/**
504
690
* xe_guc_capture_init - Init for GuC register capture
505
691
* @guc: The GuC object
506
692
*
507
693
* Init for GuC register capture, alloc memory for capture data structure.
508
694
*
509
695
* Returns: 0 if success.
510
- -ENOMEM if out of memory
696
+ * -ENOMEM if out of memory
511
697
*/
512
698
int xe_guc_capture_init (struct xe_guc * guc )
513
699
{
0 commit comments