aboutsummaryrefslogtreecommitdiffstats
path: root/nvdebug_linux.c
blob: 1d76bc90ab513a240d6f122e6c8df66beea68864 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/* Copyright 2024 Joshua Bakita
 * Implementation of Kernel-specific function implementations
 */
#include "nvdebug_linux.h"
#include <asm/io.h> // For read[l,q] and write[l,q]

// Similar to nvgpu_readl()
// (except we don't try to resolve situations where regs is NULL)
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] nvdebug_readl: Unable to read; registers unavailable. Is GPU on?\n");
		return -1;
	}
	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()
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] 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()
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] nvdebug_writel: Unable to write; registers unavailable. Is GPU on?\n");
		return;
	}
	writel_relaxed(v, s->regs + r);
	wmb();
}

// quadword version of nvdebug_writel()
// XXX: This probably doesn't work XXX: Untested
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] nvdebug_writeq: Unable to write; registers unavailable. Is GPU on?\n");
		return;
	}
	writeq_relaxed(v, s->regs + r);
	wmb();
}