]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/xe: Track pre-production workaround support
authorMatt Roper <matthew.d.roper@intel.com>
Fri, 12 Dec 2025 18:14:12 +0000 (10:14 -0800)
committerMatt Roper <matthew.d.roper@intel.com>
Sat, 13 Dec 2025 05:17:10 +0000 (21:17 -0800)
When we're initially enabling driver support for a new platform/IP, we
usually implement all workarounds documented in the WA database in the
driver.  Many of those workarounds are restricted to early steppings
that only showed up in pre-production hardware (i.e., internal test
chips that are not available to the general public).  Since the
workarounds for early, pre-production steppings tend to be some of the
ugliest and most complicated workarounds, we generally want to eliminate
them and simplify the code once the platform has launched and our
internal usage of those pre-production parts have been phased out.

Let's add a flag to the device info that tracks which platforms still
have support for pre-production workarounds for so that we can print a
warning and taint if someone tries to load the driver on a
pre-production part for a platform without pre-production workarounds.
This will help our internal users understand the likely problems they'll
encounter if they try to load the driver on an old pre-production
device.

The Xe behavior here is similar to what we've done for many years on
i915 (see intel_detect_preproduction_hw()), except that instead of
manually coding up ranges of device steppings that we believe to be
pre-production hardware, Xe will use the hardware's own production vs
pre-production fusing status, which we can read from the FUSE2 register.
This fuse didn't exist on older Intel hardware, but should be present on
all platforms supported by the Xe driver.

Going forward, let's set the expectation that we'll start looking into
removing pre-production workarounds for a platform around the time that
platforms of the next major IP stepping are having their force_probe
requirement lifted.  This timing is just a rough guideline; there may be
cases where some instances of pre-production parts are still being
actively used in CI farms, internal device pools, etc. and we'll need to
wait a bit longer for those to be swapped out.

v2:
 - Fix inverted forcewake check

v3:
 - Invert flag and add it to the platforms on which we still have
   pre-prod workarounds.  (Jani, Lucas)

v4:
 - Avoid checking pre-production on VF since they don't have access to
   the FUSE2 register.

Bspec: 78271, 52544
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Link: https://patch.msgid.link/20251212181411.294854-3-matthew.d.roper@intel.com
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
drivers/gpu/drm/xe/regs/xe_gt_regs.h
drivers/gpu/drm/xe/xe_device.c
drivers/gpu/drm/xe/xe_device_types.h
drivers/gpu/drm/xe/xe_pci.c
drivers/gpu/drm/xe/xe_pci_types.h

index 917a088c28f24aebde08a611b3a82f228d81311c..93643da57428a80d260bbf0d264203367d30b880 100644 (file)
 
 #define MIRROR_FUSE1                           XE_REG(0x911c)
 
+#define FUSE2                                  XE_REG(0x9120)
+#define   PRODUCTION_HW                                REG_BIT(2)
+
 #define MIRROR_L3BANK_ENABLE                   XE_REG(0x9130)
 #define   XE3_L3BANK_ENABLE                    REG_GENMASK(31, 0)
 
index 339b9aef9499bfb6ae3a8c8c64aabbcbf1ca09c1..cdaa1c1e73f523fcf4aa15f02eb257bdd087dc0f 100644 (file)
@@ -804,6 +804,61 @@ static int probe_has_flat_ccs(struct xe_device *xe)
        return 0;
 }
 
+/*
+ * Detect if the driver is being run on pre-production hardware.  We don't
+ * keep workarounds for pre-production hardware long term, so print an
+ * error and add taint if we're being loaded on a pre-production platform
+ * for which the pre-prod workarounds have already been removed.
+ *
+ * The general policy is that we'll remove any workarounds that only apply to
+ * pre-production hardware around the time force_probe restrictions are lifted
+ * for a platform of the next major IP generation (for example, Xe2 pre-prod
+ * workarounds should be removed around the time the first Xe3 platforms have
+ * force_probe lifted).
+ */
+static void detect_preproduction_hw(struct xe_device *xe)
+{
+       struct xe_gt *gt;
+       int id;
+
+       /*
+        * SR-IOV VFs don't have access to the FUSE2 register, so we can't
+        * check pre-production status there.  But the host OS will notice
+        * and report the pre-production status, which should be enough to
+        * help us catch mistaken use of pre-production hardware.
+        */
+       if (IS_SRIOV_VF(xe))
+               return;
+
+       /*
+        * The "SW_CAP" fuse contains a bit indicating whether the device is a
+        * production or pre-production device.  This fuse is reflected through
+        * the GT "FUSE2" register, even though the contents of the fuse are
+        * not GT-specific.  Every GT's reflection of this fuse should show the
+        * same value, so we'll just use the first available GT for lookup.
+        */
+       for_each_gt(gt, xe, id)
+               break;
+
+       if (!gt)
+               return;
+
+       CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT);
+       if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT)) {
+               xe_gt_err(gt, "Forcewake failure; cannot determine production/pre-production hw status.\n");
+               return;
+       }
+
+       if (xe_mmio_read32(&gt->mmio, FUSE2) & PRODUCTION_HW)
+               return;
+
+       xe_info(xe, "Pre-production hardware detected.\n");
+       if (!xe->info.has_pre_prod_wa) {
+               xe_err(xe, "Pre-production workarounds for this platform have already been removed.\n");
+               add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK);
+       }
+}
+
 int xe_device_probe(struct xe_device *xe)
 {
        struct xe_tile *tile;
@@ -974,6 +1029,8 @@ int xe_device_probe(struct xe_device *xe)
        if (err)
                goto err_unregister_display;
 
+       detect_preproduction_hw(xe);
+
        return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe);
 
 err_unregister_display:
index 918739f85366c9f6ea62a48e77cb07f1165ecbd1..85700533db5299a242e5bac3e6ec036b0301b9b4 100644 (file)
@@ -327,6 +327,8 @@ struct xe_device {
                u8 has_mert:1;
                /** @info.has_page_reclaim_hw_assist: Device supports page reclamation feature */
                u8 has_page_reclaim_hw_assist:1;
+               /** @info.has_pre_prod_wa: Pre-production workarounds still present in driver */
+               u8 has_pre_prod_wa:1;
                /** @info.has_pxp: Device has PXP support */
                u8 has_pxp:1;
                /** @info.has_range_tlb_inval: Has range based TLB invalidations */
index 7ff2eb96b841a58f40048ea298b3b867b68842fb..179797e875b7de639cf97f0d9e552d80a510b65c 100644 (file)
@@ -347,6 +347,7 @@ static const struct xe_device_desc lnl_desc = {
        .dma_mask_size = 46,
        .has_display = true,
        .has_flat_ccs = 1,
+       .has_pre_prod_wa = 1,
        .has_pxp = true,
        .has_mem_copy_instr = true,
        .max_gt_per_tile = 2,
@@ -369,6 +370,7 @@ static const struct xe_device_desc bmg_desc = {
        .has_heci_cscfi = 1,
        .has_i2c = true,
        .has_late_bind = true,
+       .has_pre_prod_wa = 1,
        .has_sriov = true,
        .has_mem_copy_instr = true,
        .max_gt_per_tile = 2,
@@ -388,6 +390,7 @@ static const struct xe_device_desc ptl_desc = {
        .has_flat_ccs = 1,
        .has_sriov = true,
        .has_mem_copy_instr = true,
+       .has_pre_prod_wa = 1,
        .max_gt_per_tile = 2,
        .needs_scratch = true,
        .needs_shared_vf_gt_wq = true,
@@ -401,6 +404,7 @@ static const struct xe_device_desc nvls_desc = {
        .has_display = true,
        .has_flat_ccs = 1,
        .has_mem_copy_instr = true,
+       .has_pre_prod_wa = 1,
        .max_gt_per_tile = 2,
        .require_force_probe = true,
        .va_bits = 48,
@@ -416,6 +420,7 @@ static const struct xe_device_desc cri_desc = {
        .has_i2c = true,
        .has_mbx_power_limits = true,
        .has_mert = true,
+       .has_pre_prod_wa = 1,
        .has_sriov = true,
        .max_gt_per_tile = 2,
        .require_force_probe = true,
@@ -685,6 +690,7 @@ static int xe_info_init_early(struct xe_device *xe,
        xe->info.has_llc = desc->has_llc;
        xe->info.has_mert = desc->has_mert;
        xe->info.has_page_reclaim_hw_assist = desc->has_page_reclaim_hw_assist;
+       xe->info.has_pre_prod_wa = desc->has_pre_prod_wa;
        xe->info.has_pxp = desc->has_pxp;
        xe->info.has_sriov = xe_configfs_primary_gt_allowed(to_pci_dev(xe->drm.dev)) &&
                desc->has_sriov;
index 602efc5c12523e5ef9ae394934c79da59502ffb7..3bb51d1559513d7612a7055d1a1bbf3acea1cad1 100644 (file)
@@ -50,6 +50,7 @@ struct xe_device_desc {
        u8 has_mbx_power_limits:1;
        u8 has_mem_copy_instr:1;
        u8 has_mert:1;
+       u8 has_pre_prod_wa:1;
        u8 has_page_reclaim_hw_assist:1;
        u8 has_pxp:1;
        u8 has_sriov:1;