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(>->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;
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:
.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,
.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,
.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,
.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,
.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,
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;