]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
drm/xe: Set LRC addresses before guc load
authorLucas De Marchi <lucas.demarchi@intel.com>
Thu, 10 Apr 2025 04:59:34 +0000 (21:59 -0700)
committerLucas De Marchi <lucas.demarchi@intel.com>
Fri, 18 Apr 2025 01:53:38 +0000 (18:53 -0700)
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@intel.com>
Cc: John Harrison <john.c.harrison@intel.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel GPUs")
Cc: <stable@vger.kernel.org> # v6.11+
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Tested-by: Chee Yin Wong <chee.yin.wong@intel.com>
Link: https://lore.kernel.org/r/20250409-fix-guc-ads-v1-1-494135f7a5d0@intel.com
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
(cherry picked from commit c31a0b6402d15b530514eee9925adfcb8cfbb1c9)
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
drivers/gpu/drm/xe/xe_guc_ads.c

index e7c9e095a19f0539aa6fde057989e36feb5e5573..7031542a70cebcca5011c3d6a12918ad845e55ab 100644 (file)
@@ -490,24 +490,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;
        }
 }
 
@@ -857,7 +885,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);
 
@@ -883,7 +911,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);
@@ -903,18 +931,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;
@@ -931,26 +963,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;
        }
 
@@ -959,7 +974,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)