Skip to content

Commit a7a47a5

Browse files
unerligetursulin
authored andcommitted
drm/i915/reset: Add additional steps for Wa_22011802037 for execlist backend
For execlists backend, current implementation of Wa_22011802037 is to stop the CS before doing a reset of the engine. This WA was further extended to wait for any pending MI FORCE WAKEUPs before issuing a reset. Add the extended steps in the execlist path of reset. In addition, extend the WA to gen11. v2: (Tvrtko) - Clarify comments, commit message, fix typos - Use IS_GRAPHICS_VER for gen 11/12 checks v3: (Daneile) - Drop changes to intel_ring_submission since WA does not apply to it - Log an error if MSG IDLE is not defined for an engine Signed-off-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com> Fixes: f6aa0d7 ("drm/i915: Add Wa_22011802037 force cs halt") Acked-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Signed-off-by: John Harrison <John.C.Harrison@Intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20220621192105.2100585-1-umesh.nerlige.ramappa@intel.com (cherry picked from commit 0667429) Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
1 parent e0dccc3 commit a7a47a5

File tree

5 files changed

+103
-79
lines changed

5 files changed

+103
-79
lines changed

drivers/gpu/drm/i915/gt/intel_engine.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ int intel_ring_submission_setup(struct intel_engine_cs *engine);
201201
int intel_engine_stop_cs(struct intel_engine_cs *engine);
202202
void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine);
203203

204+
void intel_engine_wait_for_pending_mi_fw(struct intel_engine_cs *engine);
205+
204206
void intel_engine_set_hwsp_writemask(struct intel_engine_cs *engine, u32 mask);
205207

206208
u64 intel_engine_get_active_head(const struct intel_engine_cs *engine);

drivers/gpu/drm/i915/gt/intel_engine_cs.c

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,10 +1282,10 @@ static int __intel_engine_stop_cs(struct intel_engine_cs *engine,
12821282
intel_uncore_write_fw(uncore, mode, _MASKED_BIT_ENABLE(STOP_RING));
12831283

12841284
/*
1285-
* Wa_22011802037 : gen12, Prior to doing a reset, ensure CS is
1285+
* Wa_22011802037 : gen11, gen12, Prior to doing a reset, ensure CS is
12861286
* stopped, set ring stop bit and prefetch disable bit to halt CS
12871287
*/
1288-
if (GRAPHICS_VER(engine->i915) == 12)
1288+
if (IS_GRAPHICS_VER(engine->i915, 11, 12))
12891289
intel_uncore_write_fw(uncore, RING_MODE_GEN7(engine->mmio_base),
12901290
_MASKED_BIT_ENABLE(GEN12_GFX_PREFETCH_DISABLE));
12911291

@@ -1308,6 +1308,18 @@ int intel_engine_stop_cs(struct intel_engine_cs *engine)
13081308
return -ENODEV;
13091309

13101310
ENGINE_TRACE(engine, "\n");
1311+
/*
1312+
* TODO: Find out why occasionally stopping the CS times out. Seen
1313+
* especially with gem_eio tests.
1314+
*
1315+
* Occasionally trying to stop the cs times out, but does not adversely
1316+
* affect functionality. The timeout is set as a config parameter that
1317+
* defaults to 100ms. In most cases the follow up operation is to wait
1318+
* for pending MI_FORCE_WAKES. The assumption is that this timeout is
1319+
* sufficient for any pending MI_FORCEWAKEs to complete. Once root
1320+
* caused, the caller must check and handle the return from this
1321+
* function.
1322+
*/
13111323
if (__intel_engine_stop_cs(engine, 1000, stop_timeout(engine))) {
13121324
ENGINE_TRACE(engine,
13131325
"timed out on STOP_RING -> IDLE; HEAD:%04x, TAIL:%04x\n",
@@ -1334,6 +1346,78 @@ void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine)
13341346
ENGINE_WRITE_FW(engine, RING_MI_MODE, _MASKED_BIT_DISABLE(STOP_RING));
13351347
}
13361348

1349+
static u32 __cs_pending_mi_force_wakes(struct intel_engine_cs *engine)
1350+
{
1351+
static const i915_reg_t _reg[I915_NUM_ENGINES] = {
1352+
[RCS0] = MSG_IDLE_CS,
1353+
[BCS0] = MSG_IDLE_BCS,
1354+
[VCS0] = MSG_IDLE_VCS0,
1355+
[VCS1] = MSG_IDLE_VCS1,
1356+
[VCS2] = MSG_IDLE_VCS2,
1357+
[VCS3] = MSG_IDLE_VCS3,
1358+
[VCS4] = MSG_IDLE_VCS4,
1359+
[VCS5] = MSG_IDLE_VCS5,
1360+
[VCS6] = MSG_IDLE_VCS6,
1361+
[VCS7] = MSG_IDLE_VCS7,
1362+
[VECS0] = MSG_IDLE_VECS0,
1363+
[VECS1] = MSG_IDLE_VECS1,
1364+
[VECS2] = MSG_IDLE_VECS2,
1365+
[VECS3] = MSG_IDLE_VECS3,
1366+
[CCS0] = MSG_IDLE_CS,
1367+
[CCS1] = MSG_IDLE_CS,
1368+
[CCS2] = MSG_IDLE_CS,
1369+
[CCS3] = MSG_IDLE_CS,
1370+
};
1371+
u32 val;
1372+
1373+
if (!_reg[engine->id].reg) {
1374+
drm_err(&engine->i915->drm,
1375+
"MSG IDLE undefined for engine id %u\n", engine->id);
1376+
return 0;
1377+
}
1378+
1379+
val = intel_uncore_read(engine->uncore, _reg[engine->id]);
1380+
1381+
/* bits[29:25] & bits[13:9] >> shift */
1382+
return (val & (val >> 16) & MSG_IDLE_FW_MASK) >> MSG_IDLE_FW_SHIFT;
1383+
}
1384+
1385+
static void __gpm_wait_for_fw_complete(struct intel_gt *gt, u32 fw_mask)
1386+
{
1387+
int ret;
1388+
1389+
/* Ensure GPM receives fw up/down after CS is stopped */
1390+
udelay(1);
1391+
1392+
/* Wait for forcewake request to complete in GPM */
1393+
ret = __intel_wait_for_register_fw(gt->uncore,
1394+
GEN9_PWRGT_DOMAIN_STATUS,
1395+
fw_mask, fw_mask, 5000, 0, NULL);
1396+
1397+
/* Ensure CS receives fw ack from GPM */
1398+
udelay(1);
1399+
1400+
if (ret)
1401+
GT_TRACE(gt, "Failed to complete pending forcewake %d\n", ret);
1402+
}
1403+
1404+
/*
1405+
* Wa_22011802037:gen12: In addition to stopping the cs, we need to wait for any
1406+
* pending MI_FORCE_WAKEUP requests that the CS has initiated to complete. The
1407+
* pending status is indicated by bits[13:9] (masked by bits[29:25]) in the
1408+
* MSG_IDLE register. There's one MSG_IDLE register per reset domain. Since we
1409+
* are concerned only with the gt reset here, we use a logical OR of pending
1410+
* forcewakeups from all reset domains and then wait for them to complete by
1411+
* querying PWRGT_DOMAIN_STATUS.
1412+
*/
1413+
void intel_engine_wait_for_pending_mi_fw(struct intel_engine_cs *engine)
1414+
{
1415+
u32 fw_pending = __cs_pending_mi_force_wakes(engine);
1416+
1417+
if (fw_pending)
1418+
__gpm_wait_for_fw_complete(engine->gt, fw_pending);
1419+
}
1420+
13371421
static u32
13381422
read_subslice_reg(const struct intel_engine_cs *engine,
13391423
int slice, int subslice, i915_reg_t reg)

drivers/gpu/drm/i915/gt/intel_execlists_submission.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2968,6 +2968,13 @@ static void execlists_reset_prepare(struct intel_engine_cs *engine)
29682968
ring_set_paused(engine, 1);
29692969
intel_engine_stop_cs(engine);
29702970

2971+
/*
2972+
* Wa_22011802037:gen11/gen12: In addition to stopping the cs, we need
2973+
* to wait for any pending mi force wakeups
2974+
*/
2975+
if (IS_GRAPHICS_VER(engine->i915, 11, 12))
2976+
intel_engine_wait_for_pending_mi_fw(engine);
2977+
29712978
engine->execlists.reset_ccid = active_ccid(engine);
29722979
}
29732980

drivers/gpu/drm/i915/gt/uc/intel_guc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc)
310310
if (IS_DG2(gt->i915))
311311
flags |= GUC_WA_DUAL_QUEUE;
312312

313-
/* Wa_22011802037: graphics version 12 */
314-
if (GRAPHICS_VER(gt->i915) == 12)
313+
/* Wa_22011802037: graphics version 11/12 */
314+
if (IS_GRAPHICS_VER(gt->i915, 11, 12))
315315
flags |= GUC_WA_PRE_PARSER;
316316

317317
/* Wa_16011777198:dg2 */

drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c

Lines changed: 6 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,87 +1578,18 @@ static void guc_reset_state(struct intel_context *ce, u32 head, bool scrub)
15781578
lrc_update_regs(ce, engine, head);
15791579
}
15801580

1581-
static u32 __cs_pending_mi_force_wakes(struct intel_engine_cs *engine)
1582-
{
1583-
static const i915_reg_t _reg[I915_NUM_ENGINES] = {
1584-
[RCS0] = MSG_IDLE_CS,
1585-
[BCS0] = MSG_IDLE_BCS,
1586-
[VCS0] = MSG_IDLE_VCS0,
1587-
[VCS1] = MSG_IDLE_VCS1,
1588-
[VCS2] = MSG_IDLE_VCS2,
1589-
[VCS3] = MSG_IDLE_VCS3,
1590-
[VCS4] = MSG_IDLE_VCS4,
1591-
[VCS5] = MSG_IDLE_VCS5,
1592-
[VCS6] = MSG_IDLE_VCS6,
1593-
[VCS7] = MSG_IDLE_VCS7,
1594-
[VECS0] = MSG_IDLE_VECS0,
1595-
[VECS1] = MSG_IDLE_VECS1,
1596-
[VECS2] = MSG_IDLE_VECS2,
1597-
[VECS3] = MSG_IDLE_VECS3,
1598-
[CCS0] = MSG_IDLE_CS,
1599-
[CCS1] = MSG_IDLE_CS,
1600-
[CCS2] = MSG_IDLE_CS,
1601-
[CCS3] = MSG_IDLE_CS,
1602-
};
1603-
u32 val;
1604-
1605-
if (!_reg[engine->id].reg)
1606-
return 0;
1607-
1608-
val = intel_uncore_read(engine->uncore, _reg[engine->id]);
1609-
1610-
/* bits[29:25] & bits[13:9] >> shift */
1611-
return (val & (val >> 16) & MSG_IDLE_FW_MASK) >> MSG_IDLE_FW_SHIFT;
1612-
}
1613-
1614-
static void __gpm_wait_for_fw_complete(struct intel_gt *gt, u32 fw_mask)
1615-
{
1616-
int ret;
1617-
1618-
/* Ensure GPM receives fw up/down after CS is stopped */
1619-
udelay(1);
1620-
1621-
/* Wait for forcewake request to complete in GPM */
1622-
ret = __intel_wait_for_register_fw(gt->uncore,
1623-
GEN9_PWRGT_DOMAIN_STATUS,
1624-
fw_mask, fw_mask, 5000, 0, NULL);
1625-
1626-
/* Ensure CS receives fw ack from GPM */
1627-
udelay(1);
1628-
1629-
if (ret)
1630-
GT_TRACE(gt, "Failed to complete pending forcewake %d\n", ret);
1631-
}
1632-
1633-
/*
1634-
* Wa_22011802037:gen12: In addition to stopping the cs, we need to wait for any
1635-
* pending MI_FORCE_WAKEUP requests that the CS has initiated to complete. The
1636-
* pending status is indicated by bits[13:9] (masked by bits[ 29:25]) in the
1637-
* MSG_IDLE register. There's one MSG_IDLE register per reset domain. Since we
1638-
* are concerned only with the gt reset here, we use a logical OR of pending
1639-
* forcewakeups from all reset domains and then wait for them to complete by
1640-
* querying PWRGT_DOMAIN_STATUS.
1641-
*/
16421581
static void guc_engine_reset_prepare(struct intel_engine_cs *engine)
16431582
{
1644-
u32 fw_pending;
1645-
1646-
if (GRAPHICS_VER(engine->i915) != 12)
1583+
if (!IS_GRAPHICS_VER(engine->i915, 11, 12))
16471584
return;
16481585

1649-
/*
1650-
* Wa_22011802037
1651-
* TODO: Occasionally trying to stop the cs times out, but does not
1652-
* adversely affect functionality. The timeout is set as a config
1653-
* parameter that defaults to 100ms. Assuming that this timeout is
1654-
* sufficient for any pending MI_FORCEWAKEs to complete, ignore the
1655-
* timeout returned here until it is root caused.
1656-
*/
16571586
intel_engine_stop_cs(engine);
16581587

1659-
fw_pending = __cs_pending_mi_force_wakes(engine);
1660-
if (fw_pending)
1661-
__gpm_wait_for_fw_complete(engine->gt, fw_pending);
1588+
/*
1589+
* Wa_22011802037:gen11/gen12: In addition to stopping the cs, we need
1590+
* to wait for any pending mi force wakeups
1591+
*/
1592+
intel_engine_wait_for_pending_mi_fw(engine);
16621593
}
16631594

16641595
static void guc_reset_nop(struct intel_engine_cs *engine)

0 commit comments

Comments
 (0)