summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_phys_booter.c232
1 files changed, 231 insertions, 1 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 0bafced..ca9559d 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -17126,6 +17126,222 @@ static const struct file_operations gsp_phys_guest_ram_fops = {
.llseek = no_llseek,
};
+/* ============================================================
+ * Read-only register-liveness probe (debugfs): gsp-phys-reg-probe
+ *
+ * One-shot, side-effect-free 32-bit MMIO snapshot of the BAR0 blocks that
+ * answer "is the graphics front-end / FECS / SKED present and alive":
+ * chip-level PMC access sanity, PGRAPH status, the FECS and GPCCS falcon
+ * cores and the front-end QMD-window controls. It only reads; it never
+ * writes and never touches ladder state.
+ *
+ * The device must be in D0 with memory space enabled (as during a GSP
+ * cycle); do not read after D3. Zero is a legitimate value for several of
+ * these registers (no QMD window programmed, no context resident), so the
+ * reading relies on the decoded lines and the PMC access-sanity word, not
+ * on any single raw value.
+ * ============================================================ */
+
+static u32 gsp_phys_reg_probe_line(struct seq_file *m, void __iomem *bar0,
+ const char *name, u32 addr)
+{
+ u32 value = readl(bar0 + addr);
+
+ seq_printf(m, "%-30s 0x%08x 0x%08x\n", name, addr, value);
+ return value;
+}
+
+static const char *gsp_phys_reg_probe_falcon_cpu(u32 cpuctl)
+{
+ if (cpuctl & BIT(4))
+ return "halted";
+ if (cpuctl & BIT(5))
+ return "stopped";
+ return "running";
+}
+
+static int gsp_phys_reg_probe_show(struct seq_file *m, void *unused)
+{
+ void __iomem *bar0 = gsp_phys_gpu_bar0();
+ u32 boot0, boot1, pmc_enable;
+ u32 pgraph_status, pgraph_status1, pgraph_engine, pgraph_activity0;
+ u32 pgraph_grfifo, fe_hww_esr, fe_chip_def, fe_go_idle;
+ u32 trap_addr, trap_lo, trap_hi;
+ u32 sked_hww_esr, sked_cwd0, sked_cwd1, sked_activity;
+ u32 qmdctl0, qmdctl1, qmdctl2, qmdctl3, qmdbasea0, qmdbaseb0;
+ u32 fecs_irq, fecs_cpuctl, fecs_hwcfg, fecs_hwcfg2, fecs_bootvec;
+ u32 fecs_os, fecs_cur, fecs_new, fecs_st1, fecs_stfe, fecs_host;
+ u32 fecs_mb0, fecs_mb1;
+ u32 gpccs_irq, gpccs_cpuctl, gpccs_hwcfg, gpccs_hwcfg2;
+ u32 gpccs_bootvec, gpccs_os, gpccs_mb0, gpccs_mb1;
+ u32 gsp_cpuctl, gsp_riscv, gsp_wpr2_lo, gsp_wpr2_hi;
+
+ if (!bar0)
+ return -ENODEV;
+
+ seq_puts(m, "# read-only BAR0 register-liveness snapshot (D0 only)\n");
+
+ boot0 = gsp_phys_reg_probe_line(m, bar0, "PMC_BOOT_0", 0x00000000u);
+ boot1 = gsp_phys_reg_probe_line(m, bar0, "PMC_BOOT_1", 0x00000004u);
+ pmc_enable = gsp_phys_reg_probe_line(m, bar0, "PMC_ENABLE",
+ 0x00000200u);
+ pgraph_status = gsp_phys_reg_probe_line(m, bar0, "PGRAPH_STATUS",
+ 0x00400700u);
+ pgraph_status1 = gsp_phys_reg_probe_line(m, bar0, "PGRAPH_STATUS1",
+ 0x00400604u);
+ pgraph_engine = gsp_phys_reg_probe_line(m, bar0,
+ "PGRAPH_ENGINE_STATUS",
+ 0x0040060cu);
+ pgraph_activity0 = gsp_phys_reg_probe_line(m, bar0,
+ "PGRAPH_ACTIVITY0",
+ 0x00400380u);
+ pgraph_grfifo = gsp_phys_reg_probe_line(m, bar0,
+ "PGRAPH_GRFIFO_STATUS",
+ 0x00400504u);
+ trap_addr = gsp_phys_reg_probe_line(m, bar0, "PGRAPH_TRAPPED_ADDR",
+ 0x00400704u);
+ trap_lo = gsp_phys_reg_probe_line(m, bar0, "PGRAPH_TRAPPED_DATA_LO",
+ 0x00400708u);
+ trap_hi = gsp_phys_reg_probe_line(m, bar0, "PGRAPH_TRAPPED_DATA_HI",
+ 0x0040070cu);
+ fe_hww_esr = gsp_phys_reg_probe_line(m, bar0, "FE_HWW_ESR",
+ 0x00404000u);
+ 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",
+ 0x00404194u);
+ sked_hww_esr = gsp_phys_reg_probe_line(m, bar0, "SKED_HWW_ESR",
+ 0x00407020u);
+ sked_activity = gsp_phys_reg_probe_line(m, bar0, "SKED_ACTIVITY",
+ 0x00407054u);
+ sked_cwd0 = gsp_phys_reg_probe_line(m, bar0,
+ "SKED_DEBUG_CWD_TABLE_0",
+ 0x00407060u);
+ sked_cwd1 = gsp_phys_reg_probe_line(m, bar0,
+ "SKED_DEBUG_CWD_TABLE_1",
+ 0x00407064u);
+ fecs_irq = gsp_phys_reg_probe_line(m, bar0, "FECS_IRQSTAT",
+ 0x00409008u);
+ fecs_cpuctl = gsp_phys_reg_probe_line(m, bar0, "FECS_CPUCTL",
+ 0x00409100u);
+ fecs_hwcfg = gsp_phys_reg_probe_line(m, bar0, "FECS_HWCFG",
+ 0x00409108u);
+ fecs_hwcfg2 = gsp_phys_reg_probe_line(m, bar0, "FECS_HWCFG2",
+ 0x004090f4u);
+ fecs_bootvec = gsp_phys_reg_probe_line(m, bar0, "FECS_BOOTVEC",
+ 0x00409104u);
+ fecs_os = gsp_phys_reg_probe_line(m, bar0, "FECS_OS", 0x00409080u);
+ fecs_cur = gsp_phys_reg_probe_line(m, bar0, "FECS_CURRENT_CTX",
+ 0x00409b00u);
+ fecs_new = gsp_phys_reg_probe_line(m, bar0, "FECS_NEW_CTX",
+ 0x00409b04u);
+ fecs_st1 = gsp_phys_reg_probe_line(m, bar0, "FECS_CTXSW_STATUS_1",
+ 0x00409400u);
+ fecs_stfe = gsp_phys_reg_probe_line(m, bar0,
+ "FECS_CTXSW_STATUS_FE_0",
+ 0x00409c00u);
+ fecs_host = gsp_phys_reg_probe_line(m, bar0, "FECS_HOST_INT_STATUS",
+ 0x00409c18u);
+ fecs_mb0 = gsp_phys_reg_probe_line(m, bar0, "FECS_MAILBOX0",
+ 0x00409040u);
+ fecs_mb1 = gsp_phys_reg_probe_line(m, bar0, "FECS_MAILBOX1",
+ 0x00409044u);
+ gpccs_irq = gsp_phys_reg_probe_line(m, bar0, "GPCCS_IRQSTAT",
+ 0x0041a008u);
+ gpccs_cpuctl = gsp_phys_reg_probe_line(m, bar0, "GPCCS_CPUCTL",
+ 0x0041a100u);
+ gpccs_hwcfg = gsp_phys_reg_probe_line(m, bar0, "GPCCS_HWCFG",
+ 0x0041a108u);
+ gpccs_hwcfg2 = gsp_phys_reg_probe_line(m, bar0, "GPCCS_HWCFG2",
+ 0x0041a0f4u);
+ gpccs_bootvec = gsp_phys_reg_probe_line(m, bar0, "GPCCS_BOOTVEC",
+ 0x0041a104u);
+ gpccs_os = gsp_phys_reg_probe_line(m, bar0, "GPCCS_OS",
+ 0x0041a080u);
+ gpccs_mb0 = gsp_phys_reg_probe_line(m, bar0, "GPCCS_MAILBOX0",
+ 0x0041a040u);
+ gpccs_mb1 = gsp_phys_reg_probe_line(m, bar0, "GPCCS_MAILBOX1",
+ 0x0041a044u);
+ qmdctl0 = gsp_phys_reg_probe_line(m, bar0, "FE_QMD_VIRT_CONTROL_0",
+ 0x0040a500u);
+ qmdctl1 = gsp_phys_reg_probe_line(m, bar0, "FE_QMD_VIRT_CONTROL_1",
+ 0x0040a504u);
+ qmdctl2 = gsp_phys_reg_probe_line(m, bar0, "FE_QMD_VIRT_CONTROL_2",
+ 0x0040a508u);
+ qmdctl3 = gsp_phys_reg_probe_line(m, bar0, "FE_QMD_VIRT_CONTROL_3",
+ 0x0040a50cu);
+ qmdbasea0 = gsp_phys_reg_probe_line(m, bar0, "FE_QMD_VIRT_BASEA_0",
+ 0x0040a300u);
+ qmdbaseb0 = gsp_phys_reg_probe_line(m, bar0, "FE_QMD_VIRT_BASEB_0",
+ 0x0040a400u);
+ gsp_cpuctl = gsp_phys_reg_probe_line(m, bar0, "GSP_CPUCTL",
+ 0x00110100u);
+ gsp_riscv = gsp_phys_reg_probe_line(m, bar0, "GSP_RISCV_STATUS",
+ 0x00111240u);
+ gsp_wpr2_lo = gsp_phys_reg_probe_line(m, bar0, "GSP_WPR2_ADDR_LO",
+ 0x001fa824u);
+ gsp_wpr2_hi = gsp_phys_reg_probe_line(m, bar0, "GSP_WPR2_ADDR_HI",
+ 0x001fa828u);
+
+ seq_printf(m,
+ "decode: pmc boot0 arch=0x%02x impl=0x%x major=0x%x minor=0x%x (this TU104 reads 0x164000a1; 0/0xffffffff = BAR0 not responding)\n",
+ (boot0 >> 24) & 0x1fu, (boot0 >> 20) & 0xfu,
+ (boot0 >> 4) & 0xfu, boot0 & 0xfu);
+ seq_printf(m,
+ "decode: pmc_enable pgraph=%u (bit12; 0 = PGRAPH clock gated) pfifo=%u (bit8) pwr=%u (bit13)\n",
+ (pmc_enable >> 12) & 1u, (pmc_enable >> 8) & 1u,
+ (pmc_enable >> 13) & 1u);
+ seq_printf(m,
+ "decode: pgraph engine_status=%s status=0x%08x gpc_busy=0x%08x activity0=0x%08x grfifo=0x%08x\n",
+ (pgraph_engine & 1u) ? "busy" : "idle", pgraph_status,
+ pgraph_status1, pgraph_activity0, pgraph_grfifo);
+ seq_printf(m,
+ "decode: fe chip_def max_veid=%u hww_esr=0x%08x go_idle=0x%08x trapped=0x%08x/0x%08x/0x%08x\n",
+ fe_chip_def & 0xfffu, fe_hww_esr, fe_go_idle, trap_addr,
+ trap_lo, trap_hi);
+ seq_printf(m,
+ "decode: sked hww_esr=0x%08x activity=0x%08x cwd_table0=0x%08x cwd_table1=0x%08x\n",
+ sked_hww_esr, sked_activity, sked_cwd0, sked_cwd1);
+ seq_printf(m,
+ "decode: fecs cpu=%s irqstat=0x%08x hwcfg=0x%08x imem=%u dmem=%u hwcfg2=0x%08x bootvec=0x%08x os=0x%08x\n",
+ gsp_phys_reg_probe_falcon_cpu(fecs_cpuctl), fecs_irq,
+ fecs_hwcfg, fecs_hwcfg & 0x1ffu, (fecs_hwcfg >> 9) & 0x1ffu,
+ fecs_hwcfg2, fecs_bootvec, fecs_os);
+ seq_printf(m,
+ "decode: fecs current_ctx target=%u ptr=0x%07x new_ctx=0x%08x st1=0x%08x fe0=0x%08x host_int=0x%08x mb=0x%08x/0x%08x\n",
+ (fecs_cur >> 28) & 3u, fecs_cur & 0x0fffffffu, fecs_new,
+ fecs_st1, fecs_stfe, fecs_host, fecs_mb0, fecs_mb1);
+ seq_printf(m,
+ "decode: gpccs cpu=%s irqstat=0x%08x hwcfg=0x%08x imem=%u dmem=%u hwcfg2=0x%08x bootvec=0x%08x os=0x%08x mb=0x%08x/0x%08x\n",
+ gsp_phys_reg_probe_falcon_cpu(gpccs_cpuctl), gpccs_irq,
+ gpccs_hwcfg, gpccs_hwcfg & 0x1ffu,
+ (gpccs_hwcfg >> 9) & 0x1ffu, gpccs_hwcfg2, gpccs_bootvec,
+ gpccs_os, gpccs_mb0, gpccs_mb1);
+ seq_printf(m,
+ "decode: qmd_virt ctl=0x%08x/0x%08x/0x%08x/0x%08x i2m=%u iq2m=%u pcas=%u basea0=0x%08x baseb0=0x%08x\n",
+ qmdctl0, qmdctl1, qmdctl2, qmdctl3,
+ (qmdctl0 >> 8) & 1u, (qmdctl0 >> 16) & 1u,
+ (qmdctl0 >> 24) & 1u, qmdbasea0, qmdbaseb0);
+ seq_printf(m,
+ "decode: gsp cpuctl=0x%08x riscv=0x%08x wpr2=0x%08x:0x%08x\n",
+ gsp_cpuctl, gsp_riscv, gsp_wpr2_hi, gsp_wpr2_lo);
+
+ return 0;
+}
+
+static int gsp_phys_reg_probe_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gsp_phys_reg_probe_show, NULL);
+}
+
+static const struct file_operations gsp_phys_reg_probe_fops = {
+ .owner = THIS_MODULE,
+ .open = gsp_phys_reg_probe_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
int gsp_phys_boot_debugfs_init(void)
{
struct dentry *file;
@@ -17250,7 +17466,21 @@ int gsp_phys_boot_debugfs_init(void)
err);
return (int)err;
}
- pr_info("vgsp-boot: debugfs files /sys/kernel/debug/vgsp/{gsp-phys-state read-only, gsp-phys-log-dump read-only, gsp-phys-status-drain read-only, gsp-phys-unload-rpc write-only, gsp-phys-rm-probe write-only, gsp-phys-rm-call write-only, gsp-phys-guest-gpa write-only, gsp-phys-guest-ram write-only} ready\n");
+ file = debugfs_create_file("gsp-phys-reg-probe", 0444,
+ gsp_phys_debugfs_root, NULL,
+ &gsp_phys_reg_probe_fops);
+ if (IS_ERR_OR_NULL(file)) {
+ long err = IS_ERR(file) ? PTR_ERR(file) : -ENODEV;
+
+ /*
+ * The register-liveness probe is diagnostic; the triggers,
+ * log dump, status drain and state snapshot stay registered.
+ */
+ pr_warn("vgsp-boot: debugfs file gsp-phys-reg-probe creation failed: %ld (triggers, log dump, status drain and state snapshot stay available)\n",
+ err);
+ return (int)err;
+ }
+ pr_info("vgsp-boot: debugfs files /sys/kernel/debug/vgsp/{gsp-phys-state read-only, gsp-phys-log-dump read-only, gsp-phys-status-drain read-only, gsp-phys-reg-probe read-only, gsp-phys-unload-rpc write-only, gsp-phys-rm-probe write-only, gsp-phys-rm-call write-only, gsp-phys-guest-gpa write-only, gsp-phys-guest-ram write-only} ready\n");
return 0;
}