@@ -211,6 +211,11 @@ struct __guc_capture_ads_cache {
211211
212212struct xe_guc_state_capture {
213213 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 ;
214219 struct __guc_capture_ads_cache ads_cache [GUC_CAPTURE_LIST_INDEX_MAX ]
215220 [GUC_STATE_CAPTURE_TYPE_MAX ]
216221 [GUC_CAPTURE_LIST_CLASS_MAX ];
@@ -245,14 +250,156 @@ guc_capture_get_one_list(const struct __guc_mmio_reg_descr_group *reglists,
245250 return NULL ;
246251}
247252
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+
248393static int
249394guc_capture_list_init (struct xe_guc * guc , u32 owner , u32 type ,
250395 enum guc_capture_list_class_type capture_class , struct guc_mmio_reg * ptr ,
251396 u16 num_entries )
252397{
253- u32 i = 0 ;
398+ u32 ptr_idx = 0 , list_idx = 0 ;
254399 const struct __guc_mmio_reg_descr_group * reglists = guc -> capture -> reglists ;
400+ struct __guc_mmio_reg_descr_group * extlists = guc -> capture -> extlists ;
255401 const struct __guc_mmio_reg_descr_group * match ;
402+ u32 list_num ;
256403
257404 if (!reglists )
258405 return - ENODEV ;
@@ -261,16 +408,28 @@ guc_capture_list_init(struct xe_guc *guc, u32 owner, u32 type,
261408 if (!match )
262409 return - ENODATA ;
263410
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 ;
269417 }
270418
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 );
274433
275434 return 0 ;
276435}
@@ -280,12 +439,22 @@ guc_cap_list_num_regs(struct xe_guc *guc, u32 owner, u32 type,
280439 enum guc_capture_list_class_type capture_class )
281440{
282441 const struct __guc_mmio_reg_descr_group * match ;
442+ int num_regs = 0 ;
283443
284444 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 ;
287456
288- return match -> num_regs ;
457+ return num_regs ;
289458}
290459
291460static int
@@ -500,14 +669,31 @@ size_t xe_guc_capture_ads_input_worst_size(struct xe_guc *guc)
500669 return PAGE_ALIGN (total_size );
501670}
502671
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+
503689/**
504690 * xe_guc_capture_init - Init for GuC register capture
505691 * @guc: The GuC object
506692 *
507693 * Init for GuC register capture, alloc memory for capture data structure.
508694 *
509695 * Returns: 0 if success.
510- -ENOMEM if out of memory
696+ * -ENOMEM if out of memory
511697 */
512698int xe_guc_capture_init (struct xe_guc * guc )
513699{
0 commit comments