]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/xe: Read VF GMD_ID with a specifically-allocated dummy GT
authorMatt Roper <matthew.d.roper@intel.com>
Mon, 13 Oct 2025 20:09:50 +0000 (13:09 -0700)
committerMatt Roper <matthew.d.roper@intel.com>
Tue, 14 Oct 2025 14:44:57 +0000 (07:44 -0700)
SRIOV VF initialization has a bit of a chicken and egg design problem.
Determining the IP version of the graphics and media IPs can't be done
via direct register reads as it is on PF or native and instead requires
querying the GuC.  However initialization of the GT, including its GuC,
needs to wait until after we know the IP versions so that the proper
initialization steps for the platform/IP are followed.

Currently the (somewhat hacky) solution is to manually fill out just
enough fields in tile 0's primary GT structure to make it look as if the
GT has been initialized so that the GuC can be partially initialized and
queried to obtain the GMD_ID values.  When the GT gets properly
initialized during the regular flows, the hacked-up values will get
overwritten as part of the general initialization flows.

Rather than using tile 0's primary GT structure to hold the hacked up
values for querying every GT on every tile, instead allocate a dedicated
dummy structure.  This will allow us to move the tile->primary_gt's
allocation to a more consistent place later in the initialization flow
in future patches (i.e., we shouldn't even allocate this GT structure if
the GT is disabled/unavailable).  It also helps ensure there can't be
any accidental leakage of initialization or state between the dummy
initialization for GMD_ID and the real driver initialization of the GT.

v2:
 - Initialize gt->tile for temporary GT.  (CI, Michal)
 - Use scope-based cleanup handler to free temp GT.  (Michal)
 - Propagate actual error code from xe_gt_sriov_vf_bootstrap() rather
   than just setting IP version to 0.0 now that read_gmdid() can return
   an error.  (Michal)
v3:
 - Explicitly initialize gt to NULL, just in case something else gets
   inserted before the kzalloc() in the future.  (Lucas)

Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Link: https://lore.kernel.org/r/20251013200944.2499947-32-matthew.d.roper@intel.com
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
drivers/gpu/drm/xe/tests/xe_pci.c
drivers/gpu/drm/xe/xe_pci.c

index 663a79ec960d9f30a48604d6914bffda3c6d2003..f3179b31f13e3ae05697fbd5f10babb3202e9a07 100644 (file)
@@ -311,8 +311,8 @@ const void *xe_pci_id_gen_param(struct kunit *test, const void *prev, char *desc
 }
 EXPORT_SYMBOL_IF_KUNIT(xe_pci_id_gen_param);
 
-static void fake_read_gmdid(struct xe_device *xe, enum xe_gmdid_type type,
-                           u32 *ver, u32 *revid)
+static int fake_read_gmdid(struct xe_device *xe, enum xe_gmdid_type type,
+                          u32 *ver, u32 *revid)
 {
        struct kunit *test = kunit_get_current_test();
        struct xe_pci_fake_data *data = test->priv;
@@ -324,6 +324,8 @@ static void fake_read_gmdid(struct xe_device *xe, enum xe_gmdid_type type,
                *ver = data->graphics_verx100;
                *revid = xe_step_to_gmdid(data->step.graphics);
        }
+
+       return 0;
 }
 
 static void fake_xe_info_probe_tile_count(struct xe_device *xe)
index 3769456a72ad0850361d6ce66c90c1dbb5e79774..f54b7963b9baa4ba965bf57e55b3f905cd86a832 100644 (file)
@@ -464,7 +464,7 @@ enum xe_gmdid_type {
        GMDID_MEDIA
 };
 
-static void read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver, u32 *revid)
+static int read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver, u32 *revid)
 {
        struct xe_mmio *mmio = xe_root_tile_mmio(xe);
        struct xe_reg gmdid_reg = GMD_ID;
@@ -473,22 +473,24 @@ static void read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver,
        KUNIT_STATIC_STUB_REDIRECT(read_gmdid, xe, type, ver, revid);
 
        if (IS_SRIOV_VF(xe)) {
-               struct xe_gt *gt = xe_root_mmio_gt(xe);
-
                /*
                 * To get the value of the GMDID register, VFs must obtain it
                 * from the GuC using MMIO communication.
                 *
-                * Note that at this point the xe_gt is not fully uninitialized
-                * and only basic access to MMIO registers is possible. To use
-                * our existing GuC communication functions we must perform at
-                * least basic xe_gt and xe_guc initialization.
-                *
-                * Since to obtain the value of GMDID_MEDIA we need to use the
-                * media GuC, temporarily tweak the gt type.
+                * Note that at this point the GTs are not initialized and only
+                * tile-level access to MMIO registers is possible. To use our
+                * existing GuC communication functions we must create a dummy
+                * GT structure and perform at least basic xe_gt and xe_guc
+                * initialization.
                 */
-               xe_gt_assert(gt, gt->info.type == XE_GT_TYPE_UNINITIALIZED);
+               struct xe_gt *gt __free(kfree) = NULL;
+               int err;
+
+               gt = kzalloc(sizeof(*gt), GFP_KERNEL);
+               if (!gt)
+                       return -ENOMEM;
 
+               gt->tile = &xe->tiles[0];
                if (type == GMDID_MEDIA) {
                        gt->info.id = 1;
                        gt->info.type = XE_GT_TYPE_MEDIA;
@@ -500,15 +502,11 @@ static void read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver,
                xe_gt_mmio_init(gt);
                xe_guc_comm_init_early(&gt->uc.guc);
 
-               /* Don't bother with GMDID if failed to negotiate the GuC ABI */
-               val = xe_gt_sriov_vf_bootstrap(gt) ? 0 : xe_gt_sriov_vf_gmdid(gt);
+               err = xe_gt_sriov_vf_bootstrap(gt);
+               if (err)
+                       return err;
 
-               /*
-                * Only undo xe_gt.info here, the remaining changes made above
-                * will be overwritten as part of the regular initialization.
-                */
-               gt->info.id = 0;
-               gt->info.type = XE_GT_TYPE_UNINITIALIZED;
+               val = xe_gt_sriov_vf_gmdid(gt);
        } else {
                /*
                 * GMD_ID is a GT register, but at this point in the driver
@@ -526,6 +524,8 @@ static void read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver,
 
        *ver = REG_FIELD_GET(GMD_ID_ARCH_MASK, val) * 100 + REG_FIELD_GET(GMD_ID_RELEASE_MASK, val);
        *revid = REG_FIELD_GET(GMD_ID_REVID, val);
+
+       return 0;
 }
 
 static const struct xe_ip *find_graphics_ip(unsigned int verx100)
@@ -552,18 +552,21 @@ static const struct xe_ip *find_media_ip(unsigned int verx100)
  * Read IP version from hardware and select graphics/media IP descriptors
  * based on the result.
  */
-static void handle_gmdid(struct xe_device *xe,
-                        const struct xe_ip **graphics_ip,
-                        const struct xe_ip **media_ip,
-                        u32 *graphics_revid,
-                        u32 *media_revid)
+static int handle_gmdid(struct xe_device *xe,
+                       const struct xe_ip **graphics_ip,
+                       const struct xe_ip **media_ip,
+                       u32 *graphics_revid,
+                       u32 *media_revid)
 {
        u32 ver;
+       int ret;
 
        *graphics_ip = NULL;
        *media_ip = NULL;
 
-       read_gmdid(xe, GMDID_GRAPHICS, &ver, graphics_revid);
+       ret = read_gmdid(xe, GMDID_GRAPHICS, &ver, graphics_revid);
+       if (ret)
+               return ret;
 
        *graphics_ip = find_graphics_ip(ver);
        if (!*graphics_ip) {
@@ -571,16 +574,21 @@ static void handle_gmdid(struct xe_device *xe,
                        ver / 100, ver % 100);
        }
 
-       read_gmdid(xe, GMDID_MEDIA, &ver, media_revid);
+       ret = read_gmdid(xe, GMDID_MEDIA, &ver, media_revid);
+       if (ret)
+               return ret;
+
        /* Media may legitimately be fused off / not present */
        if (ver == 0)
-               return;
+               return 0;
 
        *media_ip = find_media_ip(ver);
        if (!*media_ip) {
                drm_err(&xe->drm, "Hardware reports unknown media version %u.%02u\n",
                        ver / 100, ver % 100);
        }
+
+       return 0;
 }
 
 /*
@@ -691,6 +699,7 @@ static int xe_info_init(struct xe_device *xe,
        const struct xe_media_desc *media_desc;
        struct xe_tile *tile;
        struct xe_gt *gt;
+       int ret;
        u8 id;
 
        /*
@@ -706,8 +715,11 @@ static int xe_info_init(struct xe_device *xe,
                xe->info.step = xe_step_pre_gmdid_get(xe);
        } else {
                xe_assert(xe, !desc->pre_gmdid_media_ip);
-               handle_gmdid(xe, &graphics_ip, &media_ip,
-                            &graphics_gmdid_revid, &media_gmdid_revid);
+               ret = handle_gmdid(xe, &graphics_ip, &media_ip,
+                                  &graphics_gmdid_revid, &media_gmdid_revid);
+               if (ret)
+                       return ret;
+
                xe->info.step = xe_step_gmdid_get(xe,
                                                  graphics_gmdid_revid,
                                                  media_gmdid_revid);