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)
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEbSBwaO7dZQkcLOKj+mJfZA7rE8oFAmq1KCQACgkQ+mJfZA7r
 E8pjZAgAoGb4wVoZ9Qm1qCWRXiUJWoD63X9/s0cYe9qDoStsfJ3oppKuuy6A2lZQ
 SvaTLExbRLtYJiPU0RWQcphiay5lnjQzkjIrGMt8cMA/9fVPgdXfL13PXeJuJ4yM
 uQzv9+eWuptjyHxNbCuW0pEnxWZ8yyR/lMbyX68+hdJl7TgSDWHEllTkv8+xuNPn
 APyIizk69bI3VPzBcl0GcoW3VOtabgUzZiWkuuehuVf+Bl2vwZElRScjLq5gNZ3x
 IzNOQPE1z6d0v2drK/bk7SzfEt41o/J9RqKnoBguhW66XFbRU3/sVn924yCpThHQ
 74e9Wa2DP2pdJZ6htJcnrNRl9ZNi9A==
 =cXRT
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Dave Airlie 2026-09-25 16:50:02 +10:00
commit c5d1690ff1
9 changed files with 129 additions and 27 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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));
/*

View File

@ -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,

View File

@ -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++);

View File

@ -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(hwe->gt)) && XE_GT_WA(gt, 16023105232)) {
idledly = xe_mmio_read32(&gt->mmio, RING_IDLEDLY(hwe->mmio_base));
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;
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);
}
}
}

View File

@ -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; \
})
/**

View File

@ -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);

View File

@ -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)