summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-09-25 16:50:02 +1000
committerDave Airlie <airlied@redhat.com>2026-09-25 16:50:21 +1000
commitc5d1690ff144fce4b7cebe877d2ef1d1b5eb6aa2 (patch)
tree3be950a4d69d141665fa622733e1fbca2c298875 /drivers
parentfd0ba310f9ab6faa0059d9649564ac97e67ad137 (diff)
parentcc319238e3f6668f867beb381ce93727c69b7317 (diff)
downloadlinux-c5d1690ff144fce4b7cebe877d2ef1d1b5eb6aa2.tar.gz
linux-c5d1690ff144fce4b7cebe877d2ef1d1b5eb6aa2.zip
Merge tag 'drm-xe-fixes-2026-09-24' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-fixes
Fixes in: - CRI throttle reasons report (Sk) - TLB invalidation at wedge (Shuicheng) - SVM eviction and VM close (Brost) - Display corruption on LNL on Xen PV (Szymon) - W/a fix and addition (Tilak) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patch.msgid.link/arUoUf9LpsJpJouN@intel.com
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/xe/regs/xe_gt_regs.h1
-rw-r--r--drivers/gpu/drm/xe/xe_bo.c7
-rw-r--r--drivers/gpu/drm/xe/xe_bo.h19
-rw-r--r--drivers/gpu/drm/xe/xe_gt_throttle.c5
-rw-r--r--drivers/gpu/drm/xe/xe_guc_ads.c2
-rw-r--r--drivers/gpu/drm/xe/xe_hw_engine.c96
-rw-r--r--drivers/gpu/drm/xe/xe_tlb_inval.c3
-rw-r--r--drivers/gpu/drm/xe/xe_vm.c21
-rw-r--r--drivers/gpu/drm/xe/xe_wa_oob.rules2
9 files changed, 129 insertions, 27 deletions
diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 08251c7a1a4b..247a736a54aa 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -651,6 +651,7 @@
#define MEM_THERMAL_MASK REG_BIT(2)
#define VR_THERMAL_MASK REG_BIT(3)
#define ICCMAX_MASK REG_BIT(4)
+#define PWRBRK_MASK REG_BIT(5)
#define SOC_AVG_THERMAL_MASK REG_BIT(6)
#define FASTVMODE_MASK REG_BIT(7)
#define PSYS_PL1_MASK REG_BIT(12)
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
index dde309821237..b4921a627ff3 100644
--- a/drivers/gpu/drm/xe/xe_bo.c
+++ b/drivers/gpu/drm/xe/xe_bo.c
@@ -1037,6 +1037,13 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
} else {
drm_dbg(&xe->drm, "Evict system allocator BO failed=%pe\n",
ERR_PTR(ret));
+ /*
+ * The semantic we want upon SVM eviction failure
+ * because of racing access is keep walking for
+ * eviction, which is -ENOSPC.
+ */
+ if (ret == -EBUSY)
+ ret = -ENOSPC;
}
goto out;
diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h
index e8081af5bfc1..152bfcffe399 100644
--- a/drivers/gpu/drm/xe/xe_bo.h
+++ b/drivers/gpu/drm/xe/xe_bo.h
@@ -9,6 +9,8 @@
#include <drm/drm_prime.h>
#include <drm/ttm/ttm_tt.h>
+#include <xen/xen.h>
+
#include "xe_bo_types.h"
#include "xe_ggtt.h"
#include "xe_macros.h"
@@ -575,6 +577,23 @@ static inline unsigned int xe_sg_segment_size(struct device *dev)
struct scatterlist __maybe_unused sg;
size_t max = BIT_ULL(sizeof(sg.length) * 8) - 1;
+ /*
+ * For Xen PV guests pages aren't contiguous in DMA (machine) address
+ * space. The DMA API takes care of that both in dma_alloc_* (by
+ * calling into the hypervisor to make the pages contiguous) and in
+ * dma_map_* (by bounce buffering). But xe (like i915, see commit
+ * 78a07fe777c4) ignores the coherency aspects of the DMA API and thus
+ * can't cope with bounce buffering actually happening, so add a hack
+ * here to force small allocations and mappings when running in PV
+ * mode on Xen.
+ *
+ * Note this will still break if bounce buffering is required for other
+ * reasons, like confidential computing hypervisors or PCIe root ports
+ * with addressing limitations.
+ */
+ if (xen_pv_domain())
+ return PAGE_SIZE;
+
max = min_t(size_t, max, dma_max_mapping_size(dev));
/*
diff --git a/drivers/gpu/drm/xe/xe_gt_throttle.c b/drivers/gpu/drm/xe/xe_gt_throttle.c
index 1e7e3a31aa69..c0af5484611d 100644
--- a/drivers/gpu/drm/xe/xe_gt_throttle.c
+++ b/drivers/gpu/drm/xe/xe_gt_throttle.c
@@ -39,7 +39,7 @@
* - ``reason_mem_thermal``: Memory thermal
* - ``reason_vr_thermal``: VR thermal
* - ``reason_iccmax``: ICCMAX
- * - ``reason_ratl``: RATL thermal algorithm
+ * - ``reason_pwrbrk``: Power brake
* - ``reason_soc_avg_thermal``: SoC average temp
* - ``reason_fastvmode``: VR is hitting FastVMode
* - ``reason_psys_pl1``: PSYS PL1
@@ -200,6 +200,7 @@ static THROTTLE_ATTR_RO(reason_psys_pl1, PSYS_PL1_MASK);
static THROTTLE_ATTR_RO(reason_psys_pl2, PSYS_PL2_MASK);
static THROTTLE_ATTR_RO(reason_p0_freq, P0_FREQ_MASK);
static THROTTLE_ATTR_RO(reason_psys_crit, PSYS_CRIT_MASK);
+static THROTTLE_ATTR_RO(reason_pwrbrk, PWRBRK_MASK);
static struct attribute *cri_throttle_attrs[] = {
/* Common */
@@ -209,12 +210,12 @@ static struct attribute *cri_throttle_attrs[] = {
&attr_reason_pl2.attr.attr,
&attr_reason_pl4.attr.attr,
&attr_reason_prochot.attr.attr,
- &attr_reason_ratl.attr.attr,
/* CRI */
&attr_reason_vr_thermal.attr.attr,
&attr_reason_soc_thermal.attr.attr,
&attr_reason_mem_thermal.attr.attr,
&attr_reason_iccmax.attr.attr,
+ &attr_reason_pwrbrk.attr.attr,
&attr_reason_soc_avg_thermal.attr.attr,
&attr_reason_fastvmode.attr.attr,
&attr_reason_psys_pl1.attr.attr,
diff --git a/drivers/gpu/drm/xe/xe_guc_ads.c b/drivers/gpu/drm/xe/xe_guc_ads.c
index ff8eee3831aa..58a3f6293ce4 100644
--- a/drivers/gpu/drm/xe/xe_guc_ads.c
+++ b/drivers/gpu/drm/xe/xe_guc_ads.c
@@ -864,7 +864,7 @@ static unsigned int guc_mmio_regset_write(struct xe_guc_ads *ads,
}
}
- if (XE_GT_WA(hwe->gt, 16023105232))
+ if (XE_GT_WA(hwe->gt, 16023105232) || XE_GT_WA(hwe->gt, 14025941587))
guc_mmio_regset_write_one(ads, regset_map,
RING_IDLEDLY(hwe->mmio_base),
count++);
diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
index 010499766fce..9680d2a5adec 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.c
+++ b/drivers/gpu/drm/xe/xe_hw_engine.c
@@ -585,28 +585,102 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe,
xe_reg_whitelist_process_engine(hwe);
}
+static u32 idledly_floor_ticks(u32 idledly_ns, u32 idledly_units_ps)
+{
+ return DIV_ROUND_DOWN_ULL((u64)idledly_ns * 1000, idledly_units_ps);
+}
+
static void adjust_idledly(struct xe_hw_engine *hwe)
{
struct xe_gt *gt = hwe->gt;
- u32 idledly, maxcnt;
+ u32 idledly, idledly_hw, idledly_reg_val, maxcnt;
u32 idledly_units_ps = 8 * gt->info.timestamp_base;
u32 maxcnt_units_ns = 640;
- bool inhibit_switch = 0;
+ bool inhibit_switch = false;
+ bool wa_applied = false;
+ bool clamped_below_maxcnt = false;
+
+ if ((!IS_SRIOV_VF(gt_to_xe(gt)) && XE_GT_WA(gt, 16023105232)) ||
+ XE_GT_WA(gt, 14025941587)) {
+ u32 mincnt_idledly_ns = 5000;
+
+ /* xe_gt_clock_init() warns and zeroes timestamp_base on unknown crystal clock. */
+ if (!idledly_units_ps)
+ return;
- if (!IS_SRIOV_VF(gt_to_xe(hwe->gt)) && XE_GT_WA(gt, 16023105232)) {
- idledly = xe_mmio_read32(&gt->mmio, RING_IDLEDLY(hwe->mmio_base));
+ idledly_reg_val = xe_mmio_read32(&gt->mmio, RING_IDLEDLY(hwe->mmio_base));
maxcnt = xe_mmio_read32(&gt->mmio, RING_PWRCTX_MAXCNT(hwe->mmio_base));
- inhibit_switch = idledly & INHIBIT_SWITCH_UNTIL_PREEMPTED;
- idledly = REG_FIELD_GET(IDLE_DELAY, idledly);
- idledly = DIV_ROUND_CLOSEST(idledly * idledly_units_ps, 1000);
+ inhibit_switch = idledly_reg_val & INHIBIT_SWITCH_UNTIL_PREEMPTED;
+ idledly = REG_FIELD_GET(IDLE_DELAY, idledly_reg_val);
+ idledly = DIV_ROUND_CLOSEST_ULL((u64)idledly * idledly_units_ps, 1000);
+ idledly_hw = idledly;
maxcnt = REG_FIELD_GET(IDLE_WAIT_TIME, maxcnt);
maxcnt *= maxcnt_units_ns;
- if (xe_gt_WARN_ON(gt, idledly >= maxcnt || inhibit_switch)) {
- idledly = DIV_ROUND_CLOSEST(((maxcnt - 1) * 1000),
- idledly_units_ps);
- xe_mmio_write32(&gt->mmio, RING_IDLEDLY(hwe->mmio_base), idledly);
+ /*
+ * Wa_14025941587 is applied before Wa_16023105232, which takes
+ * priority if the two ever conflict (not expected in practice).
+ */
+ if (XE_GT_WA(gt, 14025941587) &&
+ idledly < mincnt_idledly_ns) {
+ idledly = mincnt_idledly_ns;
+ wa_applied = true;
+ }
+
+ if (XE_GT_WA(gt, 16023105232)) {
+ /* Clear the inhibit switch without disturbing a valid delay. */
+ if (inhibit_switch) {
+ idledly_reg_val &= ~INHIBIT_SWITCH_UNTIL_PREEMPTED;
+ wa_applied = true;
+ }
+
+ /* Warn only on the value read from hardware. */
+ xe_gt_WARN_ON(gt, idledly_hw >= maxcnt);
+
+ if (idledly >= maxcnt) {
+ /* maxcnt may be 0 if IDLE_WAIT_TIME is unprogrammed. */
+ idledly = maxcnt ? maxcnt - 1 : 0;
+ clamped_below_maxcnt = true;
+ wa_applied = true;
+ }
+ }
+
+ if (wa_applied) {
+ u32 idledly_ticks;
+
+ /*
+ * Wa_16023105232 requires idledly < maxcnt, so floor
+ * that clamp; otherwise round up to guarantee the
+ * Wa_14025941587 minimum survives tick quantization.
+ */
+ if (clamped_below_maxcnt)
+ idledly_ticks = idledly_floor_ticks(idledly, idledly_units_ps);
+ else
+ idledly_ticks = DIV_ROUND_UP_ULL((u64)idledly * 1000,
+ idledly_units_ps);
+
+ /*
+ * Tick quantization can still push the rounded-up value
+ * to/above maxcnt; re-floor here so Wa_16023105232 keeps
+ * priority even in that case.
+ */
+ if (!clamped_below_maxcnt && XE_GT_WA(gt, 16023105232) &&
+ (u64)idledly_ticks * idledly_units_ps >= (u64)maxcnt * 1000) {
+ xe_gt_dbg(gt, "idledly %s: %u ticks would exceed maxcnt=%u, so flooring\n",
+ hwe->name, idledly_ticks, maxcnt);
+ idledly = maxcnt ? maxcnt - 1 : 0;
+ idledly_ticks = idledly_floor_ticks(idledly, idledly_units_ps);
+ }
+
+ idledly_reg_val &= ~IDLE_DELAY;
+ idledly_reg_val |= REG_FIELD_PREP(IDLE_DELAY, idledly_ticks);
+ xe_gt_dbg(gt, "idledly %s: set %u max=%u inh=%u ts=%u\n",
+ hwe->name, idledly, maxcnt,
+ !!inhibit_switch, gt->info.timestamp_base);
+ xe_mmio_write32(&gt->mmio,
+ RING_IDLEDLY(hwe->mmio_base),
+ idledly_reg_val);
}
}
}
diff --git a/drivers/gpu/drm/xe/xe_tlb_inval.c b/drivers/gpu/drm/xe/xe_tlb_inval.c
index bbd21d393062..67b205bf1291 100644
--- a/drivers/gpu/drm/xe/xe_tlb_inval.c
+++ b/drivers/gpu/drm/xe/xe_tlb_inval.c
@@ -280,7 +280,8 @@ static void xe_tlb_inval_fence_prep(struct xe_tlb_inval_fence *fence)
xe_tlb_inval_fence_signal_unlocked((__fence)); \
mutex_unlock(&(__tlb_inval)->seqno_lock); \
\
- __ret == -ECANCELED ? 0 : __ret; \
+ /* Undelivered: fence already signalled, report done */ \
+ (__ret == -ECANCELED || __ret == -ENOTRECOVERABLE) ? 0 : __ret; \
})
/**
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 23952ad8951e..ef20e205a734 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -1947,21 +1947,13 @@ void xe_vm_close_and_put(struct xe_vm *vm)
vma->gpuva.flags |= XE_VMA_DESTROYED;
}
- /*
- * All vm operations will add shared fences to resv.
- * The only exception is eviction for a shared object,
- * but even so, the unbind when evicted would still
- * install a fence to resv. Hence it's safe to
- * destroy the pagetables immediately.
- */
- xe_vm_free_scratch(vm);
- xe_vm_pt_destroy(vm);
xe_vm_unlock(vm);
/*
- * VM is now dead, cannot re-add nodes to vm->vmas if it's NULL
- * Since we hold a refcount to the bo, we can remove and free
- * the members safely without locking.
+ * Unlink and destroy all contested external-BO VMAs before destroying
+ * the page tables. Otherwise, concurrent eviction holding only bo->resv
+ * can walk the BO's VMAs and attempt to invalidate/zap page tables that
+ * have already been freed.
*/
list_for_each_entry_safe(vma, next_vma, &contested,
combined_links.destroy) {
@@ -1969,6 +1961,11 @@ void xe_vm_close_and_put(struct xe_vm *vm)
xe_vma_destroy_unlocked(vma);
}
+ xe_vm_lock(vm, false);
+ xe_vm_free_scratch(vm);
+ xe_vm_pt_destroy(vm);
+ xe_vm_unlock(vm);
+
xe_svm_fini(vm);
up_write(&vm->lock);
diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules
index dd69ad07f7a9..3001155f8d09 100644
--- a/drivers/gpu/drm/xe/xe_wa_oob.rules
+++ b/drivers/gpu/drm/xe/xe_wa_oob.rules
@@ -72,3 +72,5 @@
16029897822 MEDIA_VERSION(3500)
GRAPHICS_VERSION(3510)
14027054324 GRAPHICS_VERSION(3511)
+14025941587 GRAPHICS_VERSION_RANGE(2001, 3511), FUNC(xe_rtp_match_not_sriov_vf)
+ MEDIA_VERSION_RANGE(1301, 3503), FUNC(xe_rtp_match_not_sriov_vf)