summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c240
1 files changed, 224 insertions, 16 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 74ebbd5..96d4c59 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -4977,7 +4977,14 @@ static u64 gsp_phys_gr_last_push_va;
* fetch position shows how far the walk got. Read-only MMIO + a racy read
* of the pb page (best effort, diagnostic only); bounded per boot.
*/
-#define GSP_PHYS_PBDMA_DUMP_MAX 6u
+#define GSP_PHYS_PBDMA_DUMP_MAX 64u
+
+/*
+ * SESSION 153-CONTINUED-52: the published method block's DMA address, so the
+ * PBDMA fault dump can name the exact word the PBDMA stopped on
+ * (offset = PB_FETCH - last block DMA). Set beside gsp_phys_gr_last_words.
+ */
+static u64 gsp_phys_gr_last_pb_dma;
static const char *gsp_phys_pbdma_type_name(u32 t)
{
@@ -4987,6 +4994,32 @@ static const char *gsp_phys_pbdma_type_name(u32 t)
return names[t & 7u];
}
+/*
+ * SESSION 153-CONTINUED-52: MME fault forensics. The C597 replay's dominant
+ * failure on draw-bearing windows is a real MME exception
+ * (NV_PGRAPH_PRI_MME_HWW_ESR 0x404490 latched ILLEGAL_OPCODE /
+ * MISSING_MACRO_DATA / ... - "unknown instruction fetched from the MME
+ * Instruction RAM", see gr_error_gk104.c grErrorLogMmeException). INFO
+ * carries the faulting MME PC and the macro address; INFO2 the instruction
+ * register. Read them post-failure (the latch survives) so the exact macro
+ * fetch point is on record. Read-only; bounded by its call sites.
+ */
+static void gsp_phys_mme_regs_log(void __iomem *bar0, const char *tag)
+{
+ u32 esr, info, info2, trapped;
+
+ if (!bar0)
+ return;
+ esr = ioread32(bar0 + 0x00404490u);
+ info = ioread32(bar0 + 0x00404494u);
+ info2 = ioread32(bar0 + 0x00404498u);
+ trapped = ioread32(bar0 + 0x00400704u);
+ pr_warn("vgsp-gr: MME-REGS %s esr=%08x(pc_valid=%u illegal=%u miss=%u extra=%u) pc=%u macro_addr=0x%x info2_ir=%08x trapped=%08x\n",
+ tag, esr, (info >> 28) & 1u, (esr >> 2) & 1u,
+ (esr >> 0) & 1u, (esr >> 1) & 1u, info & 0xfffu,
+ (info >> 12) & 0xffu, info2, trapped);
+}
+
static void gsp_phys_pbdma_fault_dump(u32 chid)
{
static u32 dump_n;
@@ -5011,15 +5044,43 @@ static void gsp_phys_pbdma_fault_dump(u32 chid)
u32 pbd0 = readl(bar0 + b + 0x08cu);
u32 hdrsh = readl(bar0 + b + 0x118u);
u32 fetch64 = ((u64)(pbfhi & 0xffu) << 32) | (pbf & ~3u);
+ u32 trig;
+ const char *trig_src;
+ s64 off_words = -1;
if (!intr0 && !pbf && !hdrsh && !pbhd)
continue;
- pr_info("vgsp-gr: PB-FAULT-DUMP P%u intr0=%08x gpf=%u pbfetch=0x%llx len=%u hdr=%08x(%s m=0x%x cnt=%u sub=%u) cnt=%08x data0=%08x shadow=%08x\n",
- i, intr0, gpf, fetch64, pbfhi >> 11,
+ /*
+ * SESSION 153-CONTINUED-52: the real driver's rule for the
+ * instruction that triggered the PBDMA interrupt: if the
+ * DECODED header (PB_HEADER) type is IMMD or PB_COUNT's value
+ * field is zero, the raw instruction is PB_DATA0; otherwise it
+ * is HDR_SHADOW (fifo_tu102.c: "If the TYPE field of
+ * NV_PPBDMA_PB_HEADER is IMMD or the VALUE field of
+ * NV_PPBDMA_PB_COUNT is zero, then the raw PB instruction
+ * stored in NV_PPBDMA_PB_DATA0 is the one that triggered the
+ * interrupt. Otherwise ... HDR_SHADOW").
+ */
+ if (((pbhd >> 29) & 7u) == 4u || (pbcnt & 0x1fffu) == 0u) {
+ trig = pbd0;
+ trig_src = "DATA0";
+ } else {
+ trig = hdrsh;
+ trig_src = "HDRSHADOW";
+ }
+ if (gsp_phys_gr_last_pb_dma &&
+ fetch64 >= gsp_phys_gr_last_pb_dma &&
+ fetch64 < gsp_phys_gr_last_pb_dma +
+ (u64)gsp_phys_gr_last_words * 4u)
+ off_words = (s64)(fetch64 - gsp_phys_gr_last_pb_dma) / 4;
+ pr_info("vgsp-gr: PB-FAULT-DUMP P%u intr0=%08x gpf=%u pbfetch=0x%llx len=%u off=%lld hdr=%08x(%s m=0x%x cnt=%u sub=%u) cnt=%08x data0=%08x shadow=%08x pbhd=%08x(type=%s) TRIG=%08x(%s)\n",
+ i, intr0, gpf, fetch64, pbfhi >> 11, off_words,
hdrsh, gsp_phys_pbdma_type_name(hdrsh >> 29),
(hdrsh & 0x1fffu) << 2,
(hdrsh >> 16) & 0xfffu, (hdrsh >> 13) & 7u,
- pbcnt, pbd0, hdrsh);
+ pbcnt, pbd0, hdrsh, pbhd,
+ gsp_phys_pbdma_type_name(pbhd >> 29),
+ trig, trig_src);
}
{
struct gsp_phys_boot_chunk *pbch =
@@ -19929,12 +19990,14 @@ static bool gsp_phys_rmcall_gr_win_patch_find(u32 addr, u32 *out_data)
return false;
}
+static u32 gsp_phys_rmcall_gr_3d_last_subdrop;
+
static u32 gsp_phys_rmcall_gr_3d_patch_window(const u32 *in, u32 n, u32 *out,
u32 *out_n, u32 *n_dropped,
const struct gsp_phys_gr_submit *req,
u32 *n_shadow)
{
- u32 off = 0, wout = 0, reloc = 0, dropped = 0;
+ u32 off = 0, wout = 0, reloc = 0, dropped = 0, subdrop = 0;
*out_n = n;
*n_dropped = 0;
@@ -19943,11 +20006,38 @@ static u32 gsp_phys_rmcall_gr_3d_patch_window(const u32 *in, u32 n, u32 *out,
u32 op = (hdr >> 29) & 0x7u;
u32 cnt = (hdr >> 16) & 0xfffu;
u32 addr = (hdr & 0x1fffu) << 2;
+ u32 sub = (hdr >> 13) & 0x7u;
u32 span = 1u;
if ((op == 1 || op == 3 || op == 5) && cnt &&
off + 1u + cnt <= n)
span = 1u + cnt;
+ /*
+ * SESSION 153-CONTINUED-52: drop METHOD WRITES aimed at a
+ * non-zero subchannel. The glcore draw window ends with
+ * `2001c00d 70000000/68000000` = INC m=0x34 cnt=1 SUBCHANNEL 6
+ * (channel-class MEM_OP_D lane) two-word runs. The ladder
+ * channel has nothing bound on subchannel 6, so the physical
+ * PBDMA hands those methods to its host-software lane and
+ * raises NV_PPBDMA_INTR_0_METHOD (bit 21): the r1075 relay
+ * records `Channel ID 00000004 intr 00200000` at every launch,
+ * and the real host driver's software-method handler answers
+ * "Invalid host sofware method received" -> rcRequired ->
+ * robust-channel error recovery kills the channel mid-window
+ * (fifo_gk104.c). The methods are channel-level barriers whose
+ * effects the module's own release/fence lanes already author,
+ * so dropping them from the replay is the same call the 0x10c
+ * NOTIFY / 0x1b0 LAUNCH_DMA auto-drops make. Only count-
+ * carrying writes (op 1/3/5) are candidates: the single-word
+ * TERT encodings (op 0/2/4/7) reuse bits 15:13 as mask/type
+ * payload.
+ */
+ if ((op == 1u || op == 3u || op == 5u) && sub != 0u) {
+ dropped++;
+ subdrop++;
+ off += span;
+ continue;
+ }
if (gsp_phys_rmcall_gr_win_drop_match(addr) ||
gsp_phys_rmcall_gr_win_drop_auto_match(addr)) {
dropped++;
@@ -20213,6 +20303,7 @@ static u32 gsp_phys_rmcall_gr_3d_patch_window(const u32 *in, u32 n, u32 *out,
}
*out_n = wout;
*n_dropped = dropped;
+ gsp_phys_rmcall_gr_3d_last_subdrop = subdrop;
return reloc;
}
@@ -20462,8 +20553,8 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
u32 qmd_rel_off = 0, ch_rel_off = 0;
u32 poll = 0, w0 = 0, w1 = 0, grpoll_n = 0;
bool sem_gated = false;
- static u32 sked_prev[14];
- static u32 sked_sample[14];
+ static u32 sked_prev[20];
+ static u32 sked_sample[20];
static u32 sked_tick;
static bool sked_first;
/*
@@ -21695,8 +21786,9 @@ gr_page_unmapped:
win3d = stream_patch;
win3d_n = win_n;
- pr_info("vgsp-gr: 3D window relocated %u operand pair(s) to shadow VAs (window=%u shadow=%u dropped=%u)\n",
- nrel, win3d_n, n_shadow, ndrop);
+ pr_info("vgsp-gr: 3D window relocated %u operand pair(s) to shadow VAs (window=%u shadow=%u dropped=%u subdrop=%u)\n",
+ nrel, win3d_n, n_shadow, ndrop,
+ gsp_phys_rmcall_gr_3d_last_subdrop);
if (ndrop) {
static u32 gr3d_drop_log;
@@ -21719,7 +21811,7 @@ gr_page_unmapped:
static u32 gr3d_win_log;
u32 wi;
- if (gr3d_win_log < 10) {
+ if (gr3d_win_log < 48) {
gr3d_win_log++;
pr_info("vgsp-gr: 3D window dump h=0x%x push=0x%llx words=%u\n",
req->h_object, req->push_va, win3d_n);
@@ -21748,6 +21840,59 @@ gr_page_unmapped:
WRITE_ONCE(gsp_phys_gr_last_words, words);
WRITE_ONCE(gsp_phys_gr_last_h, req->h_object);
WRITE_ONCE(gsp_phys_gr_last_push_va, req->push_va);
+ WRITE_ONCE(gsp_phys_gr_last_pb_dma,
+ (u64)gsp_phys_chunk_page_dma(pb, 0));
+ /*
+ * SESSION 153-CONTINUED-52: stream validator for the block the engine
+ * will walk. The r1072 fault class ("Channel ID 4 intr0 00040000" =
+ * PBDMA PBENTRY, "invalid method encoding used in method",
+ * fifo_tu102.c) is raised by a method header the PBDMA refuses, or by
+ * a run whose data is not fully present so the walk desyncs into
+ * following words. Walk the exact published dwords with the FIFO DMA
+ * grammar (dev_ram.ref NV_FIFO_DMA_*: SEC_OP 31:29; 1/3/5 carry 1+cnt
+ * data words, 4/7 and TERT mask ops are single-word, 6 is RESERVED)
+ * and flag the first occurrences of a reserved encoding or a run
+ * overrunning the block. Read-only; bounded per boot.
+ */
+ {
+ static u32 blkval_log;
+ const u32 *bv = methods;
+ u32 bo = 0, nbad = 0;
+
+ if (blkval_log < 48) {
+ while (bo < words && nbad < 4) {
+ u32 h = bv[bo];
+ u32 bop = (h >> 29) & 7u;
+ u32 bcnt = (h >> 16) & 0xfffu;
+ u32 bspan = 1u;
+
+ if (bop == 1u || bop == 3u || bop == 5u)
+ bspan = 1u + bcnt;
+ if (bop == 6u) {
+ nbad++;
+ pr_warn("vgsp-gr: BLOCKVAL reserved-encoding word=%u/%u val=%08x (h=%x push=0x%llx prev=%08x %08x)\n",
+ bo, words, h, req->h_object,
+ req->push_va,
+ bo ? bv[bo - 1] : 0,
+ bo + 1 < words ?
+ bv[bo + 1] : 0);
+ }
+ if (bo + bspan > words) {
+ nbad++;
+ pr_warn("vgsp-gr: BLOCKVAL run-overrun word=%u/%u hdr=%08x span=%u (needs %u more) (h=%x push=0x%llx)\n",
+ bo, words, h, bspan,
+ bo + bspan - words,
+ req->h_object, req->push_va);
+ }
+ bo += bspan;
+ }
+ blkval_log++;
+ if (nbad)
+ pr_warn("vgsp-gr: BLOCKVAL done words=%u bad=%u (h=%x push=0x%llx)\n",
+ words, nbad, req->h_object,
+ req->push_va);
+ }
+ }
pr_info("vgsp-gr: qmd w0..3=%08x %08x %08x %08x w4..7=%08x %08x %08x %08x w23..25=%08x %08x %08x w32/33=%08x %08x w48/49=%08x %08x\n",
qmd[0], qmd[1], qmd[2], qmd[3], qmd[4], qmd[5], qmd[6], qmd[7],
qmd[23], qmd[24], qmd[25], qmd[32], qmd[33], qmd[48], qmd[49]);
@@ -22141,10 +22286,35 @@ gr_page_unmapped:
sked_sample[11] = ioread32(bar0 + 0x00409c00u);
sked_sample[12] = ioread32(bar0 + 0x00409c18u);
sked_sample[13] = ioread32(bar0 + 0x00409008u);
+ /*
+ * SESSION 153-CONTINUED-52: in-flight fault registers.
+ * The DS shader-program-header error latch (0x405840),
+ * the MME exception latch (0x404490) with its PC/macro
+ * address (0x404494) and instruction register
+ * (0x404498) are cleared by the real RM within ~ms of
+ * the fault, so the post-timeout reads are all clean.
+ * Sampling them every poll tick records the faulting
+ * values at the first change.
+ */
+ sked_sample[14] = ioread32(bar0 + 0x00405840u);
+ sked_sample[15] = ioread32(bar0 + 0x00404490u);
+ sked_sample[16] = ioread32(bar0 + 0x00404494u);
+ sked_sample[17] = ioread32(bar0 + 0x00404498u);
+ /*
+ * SESSION 153-CONTINUED-52: the PBDMA host-software
+ * METHOD latch (NV_PPBDMA_METHOD0 0x4000c0: ADDR
+ * 13:2, SUBCH 18:16, INCR 0) - the method whose
+ * delivery raises NV_PPBDMA_INTR_0_METHOD (bit 21).
+ * The real driver clears the entry when it processes
+ * the interrupt, so only an in-flight sample can name
+ * it.
+ */
+ sked_sample[18] = ioread32(bar0 + 0x004000c0u);
+ sked_sample[19] = ioread32(bar0 + 0x004000c4u);
if (sked_first ||
memcmp(sked_sample, sked_prev,
sizeof(sked_sample))) {
- pr_info("vgsp-gr: sked rec +%ums cwd0=%08x cwd1=%08x cwd2=%08x info1=%08x info2=%08x act=%08x esr=%08x grfifo=%08x fecs_cur=%08x fecs_new=%08x ctxsw1=%08x fe0=%08x fehost=%08x fecsirq=%08x\n",
+ pr_info("vgsp-gr: sked rec +%ums cwd0=%08x cwd1=%08x cwd2=%08x info1=%08x info2=%08x act=%08x esr=%08x grfifo=%08x fecs_cur=%08x fecs_new=%08x ctxsw1=%08x fe0=%08x fehost=%08x fecsirq=%08x ds_esr=%08x mme_esr=%08x mme_pc=%u mme_mac=0x%x mme_ir=%08x mth0=%08x mth1=%08x(pbaddr=0x%x sub=%u incr=%u)\n",
sked_tick *
GSP_PHYS_RMCALL_POLL_MS,
sked_sample[0], sked_sample[1],
@@ -22153,7 +22323,15 @@ gr_page_unmapped:
sked_sample[6], sked_sample[7],
sked_sample[8], sked_sample[9],
sked_sample[10], sked_sample[11],
- sked_sample[12], sked_sample[13]);
+ sked_sample[12], sked_sample[13],
+ sked_sample[14], sked_sample[15],
+ sked_sample[16] & 0xfffu,
+ (sked_sample[16] >> 12) & 0xffu,
+ sked_sample[17],
+ sked_sample[18], sked_sample[19],
+ (sked_sample[18] >> 2) << 2,
+ (sked_sample[18] >> 16) & 7u,
+ sked_sample[18] & 1u);
memcpy(sked_prev, sked_sample,
sizeof(sked_sample));
sked_first = false;
@@ -22179,6 +22357,7 @@ gr_page_unmapped:
wedge_recoveries++;
pr_warn("vgsp-gr: WEDGE-RECOVER priv-error poison seen (grfifo=0x%08x) h=0x%x push=0x%llx - TSG preempt + resched\n",
g0, req->h_object, req->push_va);
+ gsp_phys_mme_regs_log(bar0, "wedge-poison");
mutex_lock(&gsp_phys_rm_lock);
gsp_phys_gr_wedge_hard_rearm_locked(bar0);
mutex_unlock(&gsp_phys_rm_lock);
@@ -22211,7 +22390,7 @@ gr_page_unmapped:
static u32 winprobe_log;
u32 pi;
- if (winprobe_log < 10) {
+ if (winprobe_log < 64) {
winprobe_log++;
pr_info("vgsp-gr: WINPROBE +%ums push=0x%llx words=%u block_dma=0x%llx grfifo=%08x trapped=%08x trapped_lo=%08x\n",
sked_tick * GSP_PHYS_RMCALL_POLL_MS,
@@ -22226,18 +22405,33 @@ gr_page_unmapped:
u32 pbf = ioread32(bar0 + b + 0x054u);
u32 pbfhi = ioread32(bar0 + b + 0x058u);
u32 hdrsh = ioread32(bar0 + b + 0x118u);
+ u32 wbh = ioread32(bar0 + b + 0x084u);
+ u32 wbcnt = ioread32(bar0 + b + 0x088u);
+ u32 wbd0 = ioread32(bar0 + b + 0x08cu);
u64 fetch64 =
((u64)(pbfhi & 0xffu) << 32) |
(u64)(pbf & ~3u);
+ s64 woff = -1;
if (!intr0 && !gpf && !pbf && !hdrsh)
continue;
- pr_info("vgsp-gr: WINPROBE P%u intr0=%08x gp_put=%u pbfetch=0x%llx hdr=%08x(%s m=0x%x cnt=%u sub=%u)\n",
- pi, intr0, gpf, fetch64, hdrsh,
+ if (gsp_phys_gr_last_pb_dma &&
+ fetch64 >= gsp_phys_gr_last_pb_dma &&
+ fetch64 <
+ gsp_phys_gr_last_pb_dma +
+ (u64)gsp_phys_gr_last_words *
+ 4u)
+ woff = (s64)(fetch64 -
+ gsp_phys_gr_last_pb_dma) /
+ 4;
+ pr_info("vgsp-gr: WINPROBE P%u intr0=%08x gp_put=%u pbfetch=0x%llx off=%lld hdr=%08x(%s m=0x%x cnt=%u sub=%u) pbhd=%08x(type=%s) pbcnt=%08x pbd0=%08x\n",
+ pi, intr0, gpf, fetch64, woff, hdrsh,
gsp_phys_pbdma_type_name(hdrsh >> 29),
(hdrsh & 0x1fffu) << 2,
(hdrsh >> 16) & 0xfffu,
- (hdrsh >> 13) & 7u);
+ (hdrsh >> 13) & 7u, wbh,
+ gsp_phys_pbdma_type_name(wbh >> 29),
+ wbcnt, wbd0);
}
}
}
@@ -22267,6 +22461,7 @@ gr_page_unmapped:
pr_err("vgsp-gr: GR LAUNCH FAILED: wait budget crossed (qmd_rel=0x%08x want=0x%08x ch_rel=0x%08x want=0x%08x) h=0x%x push=0x%llx; ladder stopped\n",
w0, want_qmd, w1, want_ch, req->h_object,
req->push_va);
+ gsp_phys_mme_regs_log(bar0, "wait-max");
ret = -ETIMEDOUT;
goto out;
}
@@ -22278,6 +22473,7 @@ gr_page_unmapped:
pr_err("vgsp-gr: GR LAUNCH FAILED: timeout after %u ms (qmd_rel=0x%08x want=0x%08x ch_rel=0x%08x want=0x%08x) h=0x%x push=0x%llx\n",
poll_ms, w0, want_qmd, w1,
want_ch, req->h_object, req->push_va);
+ gsp_phys_mme_regs_log(bar0, "timeout");
/*
* F4-b: one-shot deposit readback at the FIRST timeout
* (the old post-mortem only ran after attempt 3, which
@@ -25979,6 +26175,18 @@ static int gsp_phys_reg_probe_show(struct seq_file *m, void *unused)
0x0040070cu);
fe_hww_esr = gsp_phys_reg_probe_line(m, bar0, "FE_HWW_ESR",
0x00404000u);
+ /*
+ * SESSION 153-CONTINUED-52: MME exception latches (see
+ * gsp_phys_mme_regs_log).
+ */
+ (void)gsp_phys_reg_probe_line(m, bar0, "PGRAPH_PRI_MME_HWW_ESR",
+ 0x00404490u);
+ (void)gsp_phys_reg_probe_line(m, bar0,
+ "PGRAPH_PRI_MME_HWW_ESR_INFO",
+ 0x00404494u);
+ (void)gsp_phys_reg_probe_line(m, bar0,
+ "PGRAPH_PRI_MME_HWW_ESR_INFO2",
+ 0x00404498u);
fe_chip_def = gsp_phys_reg_probe_line(m, bar0, "FE_CHIP_DEF_INFO",
0x00404030u);
fe_go_idle = gsp_phys_reg_probe_line(m, bar0, "FE_GO_IDLE_INFO",