[PATCH] drm/xe: Set LRC addresses before guc load
Wong, Chee Yin
chee.yin.wong at intel.com
Thu Apr 10 11:29:45 UTC 2025
Hi,
I have tested this patch, no Yellow Bang observed in Windows VM. Able to
run 3D and media workloads in Windows VM.
Tested-by: Wong, Chee Yin <chee.yin.wong at intel.com>
Best regards,
Chee Yin
On 10/4/2025 12:59 pm, Lucas De Marchi wrote:
> The metadata saved in the ADS is read by GuC when it's initialized.
>
> Saving the addresses to the LRCs when they are populated is too late as
>
> GuC will keep using the old ones.
>
>
>
> This was causing GuC to use the RCS LRC for any engine class. It's not a
>
> big problem on a Linux-only scenario since the they are used by GuC only
>
> on media engines when the watchdog is triggered. However, in a
>
> virtualization scenario with Windows as the VF, it causes the wrong LRCs
>
> to be loaded as the watchdog is used for all engines.
>
>
>
> Fix it by letting guc_golden_lrc_init() initialize the metadata, like
>
> other *_init() functions, and later guc_golden_lrc_populate() to copy
>
> the LRCs to the right places. The former is called before the second GuC
>
> load, while the latter is called after LRCs have been recorded.
>
>
>
> Cc: Chee Yin Wong <chee.yin.wong at intel.com>
>
> Cc: John Harrison <john.c.harrison at intel.com>
>
> Cc: Matt Roper <matthew.d.roper at intel.com>
>
> Cc: Matthew Brost <matthew.brost at intel.com>
>
> Signed-off-by: Lucas De Marchi <lucas.demarchi at intel.com>
>
> ---
>
> drivers/gpu/drm/xe/xe_guc_ads.c | 75 ++++++++++++++++++++++++-----------------
>
> 1 file changed, 45 insertions(+), 30 deletions(-)
>
>
>
> diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c
>
> index 88400f249e614..2a227213c37ff 100644
>
> --- a/drivers/gpu/drm/xe/xe_guc_ads.c
>
> +++ b/drivers/gpu/drm/xe/xe_guc_ads.c
>
> @@ -491,24 +491,52 @@ static void fill_engine_enable_masks(struct xe_gt *gt,
>
> engine_enable_mask(gt, XE_ENGINE_CLASS_OTHER));
>
> }
>
>
>
> -static void guc_prep_golden_lrc_null(struct xe_guc_ads *ads)
>
> +/*
>
> + * Write the offsets corresponding to the golden LRCs. The actual data is
>
> + * populated later by guc_golden_lrc_populate()
>
> + */
>
> +static void guc_golden_lrc_init(struct xe_guc_ads *ads)
>
> {
>
> struct xe_device *xe = ads_to_xe(ads);
>
> + struct xe_gt *gt = ads_to_gt(ads);
>
> struct iosys_map info_map = IOSYS_MAP_INIT_OFFSET(ads_to_map(ads),
>
> offsetof(struct __guc_ads_blob, system_info));
>
> - u8 guc_class;
>
> + size_t alloc_size, real_size;
>
> + u32 addr_ggtt, offset;
>
> + int class;
>
> +
>
> + offset = guc_ads_golden_lrc_offset(ads);
>
> + addr_ggtt = xe_bo_ggtt_addr(ads->bo) + offset;
>
> +
>
> + for (class = 0; class < XE_ENGINE_CLASS_MAX; ++class) {
>
> + u8 guc_class;
>
> +
>
> + guc_class = xe_engine_class_to_guc_class(class);
>
>
>
> - for (guc_class = 0; guc_class <= GUC_MAX_ENGINE_CLASSES; ++guc_class) {
>
> if (!info_map_read(xe, &info_map,
>
> engine_enabled_masks[guc_class]))
>
> continue;
>
>
>
> + real_size = xe_gt_lrc_size(gt, class);
>
> + alloc_size = PAGE_ALIGN(real_size);
>
> +
>
> + /*
>
> + * This interface is slightly confusing. We need to pass the
>
> + * base address of the full golden context and the size of just
>
> + * the engine state, which is the section of the context image
>
> + * that starts after the execlists LRC registers. This is
>
> + * required to allow the GuC to restore just the engine state
>
> + * when a watchdog reset occurs.
>
> + * We calculate the engine state size by removing the size of
>
> + * what comes before it in the context image (which is identical
>
> + * on all engines).
>
> + */
>
> ads_blob_write(ads, ads.eng_state_size[guc_class],
>
> - guc_ads_golden_lrc_size(ads) -
>
> - xe_lrc_skip_size(xe));
>
> + real_size - xe_lrc_skip_size(xe));
>
> ads_blob_write(ads, ads.golden_context_lrca[guc_class],
>
> - xe_bo_ggtt_addr(ads->bo) +
>
> - guc_ads_golden_lrc_offset(ads));
>
> + addr_ggtt);
>
> +
>
> + addr_ggtt += alloc_size;
>
> }
>
> }
>
>
>
> @@ -858,7 +886,7 @@ void xe_guc_ads_populate_minimal(struct xe_guc_ads *ads)
>
>
>
> xe_map_memset(ads_to_xe(ads), ads_to_map(ads), 0, 0, ads->bo->size);
>
> guc_policies_init(ads);
>
> - guc_prep_golden_lrc_null(ads);
>
> + guc_golden_lrc_init(ads);
>
> guc_mapping_table_init_invalid(gt, &info_map);
>
> guc_doorbell_init(ads);
>
>
>
> @@ -884,7 +912,7 @@ void xe_guc_ads_populate(struct xe_guc_ads *ads)
>
> guc_policies_init(ads);
>
> fill_engine_enable_masks(gt, &info_map);
>
> guc_mmio_reg_state_init(ads);
>
> - guc_prep_golden_lrc_null(ads);
>
> + guc_golden_lrc_init(ads);
>
> guc_mapping_table_init(gt, &info_map);
>
> guc_capture_prep_lists(ads);
>
> guc_doorbell_init(ads);
>
> @@ -904,18 +932,22 @@ void xe_guc_ads_populate(struct xe_guc_ads *ads)
>
> guc_ads_private_data_offset(ads));
>
> }
>
>
>
> -static void guc_populate_golden_lrc(struct xe_guc_ads *ads)
>
> +/*
>
> + * After the golden LRC's are recorded for each engine class by the first
>
> + * submission, copy them to the ADS, as initialized earlier by
>
> + * guc_golden_lrc_init().
>
> + */
>
> +static void guc_golden_lrc_populate(struct xe_guc_ads *ads)
>
> {
>
> struct xe_device *xe = ads_to_xe(ads);
>
> struct xe_gt *gt = ads_to_gt(ads);
>
> struct iosys_map info_map = IOSYS_MAP_INIT_OFFSET(ads_to_map(ads),
>
> offsetof(struct __guc_ads_blob, system_info));
>
> size_t total_size = 0, alloc_size, real_size;
>
> - u32 addr_ggtt, offset;
>
> + u32 offset;
>
> int class;
>
>
>
> offset = guc_ads_golden_lrc_offset(ads);
>
> - addr_ggtt = xe_bo_ggtt_addr(ads->bo) + offset;
>
>
>
> for (class = 0; class < XE_ENGINE_CLASS_MAX; ++class) {
>
> u8 guc_class;
>
> @@ -932,26 +964,9 @@ static void guc_populate_golden_lrc(struct xe_guc_ads *ads)
>
> alloc_size = PAGE_ALIGN(real_size);
>
> total_size += alloc_size;
>
>
>
> - /*
>
> - * This interface is slightly confusing. We need to pass the
>
> - * base address of the full golden context and the size of just
>
> - * the engine state, which is the section of the context image
>
> - * that starts after the execlists LRC registers. This is
>
> - * required to allow the GuC to restore just the engine state
>
> - * when a watchdog reset occurs.
>
> - * We calculate the engine state size by removing the size of
>
> - * what comes before it in the context image (which is identical
>
> - * on all engines).
>
> - */
>
> - ads_blob_write(ads, ads.eng_state_size[guc_class],
>
> - real_size - xe_lrc_skip_size(xe));
>
> - ads_blob_write(ads, ads.golden_context_lrca[guc_class],
>
> - addr_ggtt);
>
> -
>
> xe_map_memcpy_to(xe, ads_to_map(ads), offset,
>
> gt->default_lrc[class], real_size);
>
>
>
> - addr_ggtt += alloc_size;
>
> offset += alloc_size;
>
> }
>
>
>
> @@ -960,7 +975,7 @@ static void guc_populate_golden_lrc(struct xe_guc_ads *ads)
>
>
>
> void xe_guc_ads_populate_post_load(struct xe_guc_ads *ads)
>
> {
>
> - guc_populate_golden_lrc(ads);
>
> + guc_golden_lrc_populate(ads);
>
> }
>
>
>
> static int guc_ads_action_update_policies(struct xe_guc_ads *ads, u32 policy_offset)
>
>
>
>
>
>
>
More information about the Intel-xe
mailing list