From a1598f27a124cb0b5263276f7098ae3a68460b61 Mon Sep 17 00:00:00 2001 From: Joshua Bakita Date: Tue, 18 Jul 2023 10:49:19 -0400 Subject: Fail reads which return the flag value for a non-existent register Also check for read success in get_runlist_iter(). --- nvdebug.h | 30 +++++++++++++++++++++--------- runlist.c | 2 ++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/nvdebug.h b/nvdebug.h index 8009b84..8db07ee 100644 --- a/nvdebug.h +++ b/nvdebug.h @@ -960,30 +960,42 @@ static inline int file2parentgpuidx(const struct file *f) { // Similar to nvgpu_readl() // (except we don't try to resolve situations where regs is NULL) static inline u32 nvdebug_readl(struct nvdebug_state *s, u32 r) { + u32 ret; if (unlikely(!s->regs || (s->g && !gk20a_regs(s->g)))) { - printk(KERN_ERR "[nvdebug] Attempted nvgpu_readl on non-existent registers!\n"); + printk(KERN_ERR "[nvdebug] nvdebug_readl: Unable to read; registers unavailable. Is GPU on?\n"); return -1; } - return readl(s->regs + r); + ret = readl(s->regs + r); + // It seems like the GPU returns this as a flag value for bad addresses + if (ret == 0xbadf5040) { + printk(KERN_ERR "[nvdebug] nvdebug_readl: Unable to read from register offset %#x; bad data\n", r); + return -1; + } + return ret; } // quadword version of nvdebug_readl() static inline u64 nvdebug_readq(struct nvdebug_state *s, u32 r) { u64 ret; if (unlikely(!s->regs || (s->g && !gk20a_regs(s->g)))) { - printk(KERN_ERR "[nvdebug] Attempted nvgpu_readl on non-existent registers!\n"); + printk(KERN_ERR "[nvdebug] nvdebug_readq: Unable to read; registers unavailable. Is GPU on?\n"); return -1; } // readq seems to always return the uppermost 32 bits as 0, so workaround with readl ret = readl(s->regs + r); ret |= ((u64)readl(s->regs + r + 4)) << 32; + // It seems like the GPU returns this as a flag value for bad addresses + if ((ret & 0xffffffffull) == 0xbadf5040ull) { + printk(KERN_ERR "[nvdebug] nvdebug_readq: Unable to read from register offset %#x; bad data\n", r); + return -1; + } return ret; } // Similar to nvgpu_writel() static inline void nvdebug_writel(struct nvdebug_state *s, u32 r, u32 v) { if (unlikely(!s->regs || (s->g && !gk20a_regs(s->g)))) { - printk(KERN_ERR "[nvdebug] Attempted nvgpu_writel on non-existent registers!\n"); + printk(KERN_ERR "[nvdebug] nvdebug_writel: Unable to write; registers unavailable. Is GPU on?\n"); return; } writel_relaxed(v, s->regs + r); @@ -994,9 +1006,9 @@ static inline void nvdebug_writel(struct nvdebug_state *s, u32 r, u32 v) { // XXX: This probably doesn't work XXX: Untested static inline void nvdebug_writeq(struct nvdebug_state *s, u32 r, u64 v) { if (unlikely(!s->regs || (s->g && !gk20a_regs(s->g)))) { - printk(KERN_ERR "[nvdebug] Attempted nvgpu_writel on non-existent registers!\n"); - return; - } - writeq_relaxed(v, s->regs + r); - wmb(); + printk(KERN_ERR "[nvdebug] nvdebug_writeq: Unable to write; registers unavailable. Is GPU on?\n"); + return; + } + writeq_relaxed(v, s->regs + r); + wmb(); } diff --git a/runlist.c b/runlist.c index 94be18e..f6a05ac 100644 --- a/runlist.c +++ b/runlist.c @@ -41,6 +41,8 @@ int get_runlist_iter(struct nvdebug_state *g, int rl_id, struct runlist_iter *rl // before because the GPU had simply gone to sleep and invalidated its // register state, so nvgpu_readl() was simply returning garbage. rl_info.raw = nvdebug_readl(g, NV_PFIFO_ENG_RUNLIST(rl_id)); + if (rl_info.raw == -1) + return -EIO; runlist_iova = ((u64)rl_base.ptr) << 12; printk(KERN_INFO "[nvdebug] Runlist %d @ %llx in %s (config raw: %x)\n", rl_id, runlist_iova, target_to_text(rl_base.target), rl_base.raw); -- cgit v1.2.2