- W/a fix for multi-cast registers (Roper)

- Fix xe_sync initialization issues (Shuicheng)
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEbSBwaO7dZQkcLOKj+mJfZA7rE8oFAmmgRf0ACgkQ+mJfZA7r
 E8rjQQf/YdxpWjxWAe9s6e9IdYGJhwpKtDuY/Mvkfl8+Fs2jkmlkR4/49Ho5Mg+s
 9aE2KT6+GE7XVSIoj0EegwOn1et39YhsRxdXsBsFzyQuPxq74dc5+ItF2cWk9WAK
 uVm5JGirTUxvHkozAJI34fvlxjD+Y3wvPUQRBPDIl2inRViv+G8dAfhAidHjvrwf
 RGD5M+KKrWCGO4C88nAS8ytTQBmnECszx1Wi/iTz7/eBFYLHj3EOE1f2tlEKNxEj
 bMuyB7Cef7I4L87DK1vPMGZxCf1de/sXMiSdk3RjAagoiB6eM5fEwCv03J2SLIXi
 h7tolqG+upTHY9p+4vM4VXhKihqWKA==
 =9b3+
 -----END PGP SIGNATURE-----

Merge tag 'drm-xe-fixes-2026-02-26' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-fixes

- W/a fix for multi-cast registers (Roper)
- Fix xe_sync initialization issues (Shuicheng)

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patch.msgid.link/aaBGHy_0RLGGIBP5@intel.com
This commit is contained in:
Dave Airlie 2026-02-27 09:13:40 +10:00
commit 82a499d2ca
3 changed files with 81 additions and 21 deletions

View File

@ -96,6 +96,12 @@
#define ENABLE_SEMAPHORE_POLL_BIT REG_BIT(13)
#define RING_CMD_CCTL(base) XE_REG((base) + 0xc4, XE_REG_OPTION_MASKED)
#define CS_MMIO_GROUP_INSTANCE_SELECT(base) XE_REG((base) + 0xcc)
#define SELECTIVE_READ_ADDRESSING REG_BIT(30)
#define SELECTIVE_READ_GROUP REG_GENMASK(29, 23)
#define SELECTIVE_READ_INSTANCE REG_GENMASK(22, 16)
/*
* CMD_CCTL read/write fields take a MOCS value and _not_ a table index.
* The lsb of each can be considered a separate enabling bit for encryption.

View File

@ -210,11 +210,15 @@ static int emit_nop_job(struct xe_gt *gt, struct xe_exec_queue *q)
return ret;
}
/* Dwords required to emit a RMW of a register */
#define EMIT_RMW_DW 20
static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
{
struct xe_reg_sr *sr = &q->hwe->reg_lrc;
struct xe_hw_engine *hwe = q->hwe;
struct xe_reg_sr *sr = &hwe->reg_lrc;
struct xe_reg_sr_entry *entry;
int count_rmw = 0, count = 0, ret;
int count_rmw = 0, count_rmw_mcr = 0, count = 0, ret;
unsigned long idx;
struct xe_bb *bb;
size_t bb_len = 0;
@ -224,6 +228,8 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
xa_for_each(&sr->xa, idx, entry) {
if (entry->reg.masked || entry->clr_bits == ~0)
++count;
else if (entry->reg.mcr)
++count_rmw_mcr;
else
++count_rmw;
}
@ -231,17 +237,35 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
if (count)
bb_len += count * 2 + 1;
if (count_rmw)
bb_len += count_rmw * 20 + 7;
/*
* RMW of MCR registers is the same as a normal RMW, except an
* additional LRI (3 dwords) is required per register to steer the read
* to a nom-terminated instance.
*
* We could probably shorten the batch slightly by eliding the
* steering for consecutive MCR registers that have the same
* group/instance target, but it's not worth the extra complexity to do
* so.
*/
bb_len += count_rmw * EMIT_RMW_DW;
bb_len += count_rmw_mcr * (EMIT_RMW_DW + 3);
if (q->hwe->class == XE_ENGINE_CLASS_RENDER)
/*
* After doing all RMW, we need 7 trailing dwords to clean up,
* plus an additional 3 dwords to reset steering if any of the
* registers were MCR.
*/
if (count_rmw || count_rmw_mcr)
bb_len += 7 + (count_rmw_mcr ? 3 : 0);
if (hwe->class == XE_ENGINE_CLASS_RENDER)
/*
* Big enough to emit all of the context's 3DSTATE via
* xe_lrc_emit_hwe_state_instructions()
*/
bb_len += xe_gt_lrc_size(gt, q->hwe->class) / sizeof(u32);
bb_len += xe_gt_lrc_size(gt, hwe->class) / sizeof(u32);
xe_gt_dbg(gt, "LRC %s WA job: %zu dwords\n", q->hwe->name, bb_len);
xe_gt_dbg(gt, "LRC %s WA job: %zu dwords\n", hwe->name, bb_len);
bb = xe_bb_new(gt, bb_len, false);
if (IS_ERR(bb))
@ -276,13 +300,23 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
}
}
if (count_rmw) {
/* Emit MI_MATH for each RMW reg: 20dw per reg + 7 trailing dw */
if (count_rmw || count_rmw_mcr) {
xa_for_each(&sr->xa, idx, entry) {
if (entry->reg.masked || entry->clr_bits == ~0)
continue;
if (entry->reg.mcr) {
struct xe_reg_mcr reg = { .__reg.raw = entry->reg.raw };
u8 group, instance;
xe_gt_mcr_get_nonterminated_steering(gt, reg, &group, &instance);
*cs++ = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(1);
*cs++ = CS_MMIO_GROUP_INSTANCE_SELECT(hwe->mmio_base).addr;
*cs++ = SELECTIVE_READ_ADDRESSING |
REG_FIELD_PREP(SELECTIVE_READ_GROUP, group) |
REG_FIELD_PREP(SELECTIVE_READ_INSTANCE, instance);
}
*cs++ = MI_LOAD_REGISTER_REG | MI_LRR_DST_CS_MMIO;
*cs++ = entry->reg.addr;
*cs++ = CS_GPR_REG(0, 0).addr;
@ -308,8 +342,9 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
*cs++ = CS_GPR_REG(0, 0).addr;
*cs++ = entry->reg.addr;
xe_gt_dbg(gt, "REG[%#x] = ~%#x|%#x\n",
entry->reg.addr, entry->clr_bits, entry->set_bits);
xe_gt_dbg(gt, "REG[%#x] = ~%#x|%#x%s\n",
entry->reg.addr, entry->clr_bits, entry->set_bits,
entry->reg.mcr ? " (MCR)" : "");
}
/* reset used GPR */
@ -321,6 +356,13 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
*cs++ = 0;
*cs++ = CS_GPR_REG(0, 2).addr;
*cs++ = 0;
/* reset steering */
if (count_rmw_mcr) {
*cs++ = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(1);
*cs++ = CS_MMIO_GROUP_INSTANCE_SELECT(q->hwe->mmio_base).addr;
*cs++ = 0;
}
}
cs = xe_lrc_emit_hwe_state_instructions(q, cs);

View File

@ -146,8 +146,10 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
if (!signal) {
sync->fence = drm_syncobj_fence_get(sync->syncobj);
if (XE_IOCTL_DBG(xe, !sync->fence))
return -EINVAL;
if (XE_IOCTL_DBG(xe, !sync->fence)) {
err = -EINVAL;
goto free_sync;
}
}
break;
@ -167,17 +169,21 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
if (signal) {
sync->chain_fence = dma_fence_chain_alloc();
if (!sync->chain_fence)
return -ENOMEM;
if (!sync->chain_fence) {
err = -ENOMEM;
goto free_sync;
}
} else {
sync->fence = drm_syncobj_fence_get(sync->syncobj);
if (XE_IOCTL_DBG(xe, !sync->fence))
return -EINVAL;
if (XE_IOCTL_DBG(xe, !sync->fence)) {
err = -EINVAL;
goto free_sync;
}
err = dma_fence_chain_find_seqno(&sync->fence,
sync_in.timeline_value);
if (err)
return err;
goto free_sync;
}
break;
@ -200,8 +206,10 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
if (XE_IOCTL_DBG(xe, IS_ERR(sync->ufence)))
return PTR_ERR(sync->ufence);
sync->ufence_chain_fence = dma_fence_chain_alloc();
if (!sync->ufence_chain_fence)
return -ENOMEM;
if (!sync->ufence_chain_fence) {
err = -ENOMEM;
goto free_sync;
}
sync->ufence_syncobj = ufence_syncobj;
}
@ -216,6 +224,10 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
sync->timeline_value = sync_in.timeline_value;
return 0;
free_sync:
xe_sync_entry_cleanup(sync);
return err;
}
ALLOW_ERROR_INJECTION(xe_sync_entry_parse, ERRNO);