diff options
author | Joshua Bakita <bakitajoshua@gmail.com> | 2023-10-29 13:34:18 -0400 |
---|---|---|
committer | Joshua Bakita <bakitajoshua@gmail.com> | 2023-10-29 13:34:18 -0400 |
commit | 9199cc9e3bd6070bf54e28f5311867433af3dd59 (patch) | |
tree | 9e57694f85d15c1bddc9dd22b867b3b7614f76ed | |
parent | 39f7f4047e57fc7e7e275e52657f47d3d4bb6e2a (diff) |
Support PRAMIN-based runlist access fallback (optional; on by default)
Using this may be hazardous---we don't know if some of the GPU drivers
use this after initial bring-up. If they do, and we race with them in
setting it, or we unexpectedly change it under them, arbitrary state
corruption could occur.
This is only entirely safe to use if you don't trust the GPU state
after the first use of this fallback. In limited experiments vs the
`nvgpu` (Tegra) and `nvidia` (closed-source discrete) drivers, no
ill side effects have yet been observed, but still please use with
caution.
-rw-r--r-- | runlist.c | 32 |
1 files changed, 28 insertions, 4 deletions
@@ -2,6 +2,8 @@ | |||
2 | 2 | ||
3 | #include "nvdebug.h" | 3 | #include "nvdebug.h" |
4 | 4 | ||
5 | #define FALLBACK_TO_PRAMIN | ||
6 | |||
5 | /* Get runlist head and info (incl. length) | 7 | /* Get runlist head and info (incl. length) |
6 | @param rl_iter Location at which to store output | 8 | @param rl_iter Location at which to store output |
7 | @param rl_id Which runlist to obtain? | 9 | @param rl_id Which runlist to obtain? |
@@ -61,7 +63,7 @@ int get_runlist_iter(struct nvdebug_state *g, int rl_id, struct runlist_iter *rl | |||
61 | uint32_t bar_inst_pramin_offset = vram2PRAMIN(g, (uint64_t)bar2_block.ptr << 12); | 63 | uint32_t bar_inst_pramin_offset = vram2PRAMIN(g, (uint64_t)bar2_block.ptr << 12); |
62 | if (!bar_inst_pramin_offset) { | 64 | if (!bar_inst_pramin_offset) { |
63 | printk(KERN_WARNING "[nvdebug] Unable to find instance block for BAR2/3 in the current NV_PRAMIN window. VRAM inaccessible.\n"); | 65 | printk(KERN_WARNING "[nvdebug] Unable to find instance block for BAR2/3 in the current NV_PRAMIN window. VRAM inaccessible.\n"); |
64 | return -EOPNOTSUPP; | 66 | goto attempt_pramin_access; |
65 | } | 67 | } |
66 | /* TODO: Support BAR1? | 68 | /* TODO: Support BAR1? |
67 | bar_inst_pramin_offset = vram2PRAMIN(g, bar1_block.ptr << 12); | 69 | bar_inst_pramin_offset = vram2PRAMIN(g, bar1_block.ptr << 12); |
@@ -82,12 +84,12 @@ int get_runlist_iter(struct nvdebug_state *g, int rl_id, struct runlist_iter *rl | |||
82 | // TODO: SYSMEM support for page table location | 84 | // TODO: SYSMEM support for page table location |
83 | if (pd_config.target != TARGET_VID_MEM) { | 85 | if (pd_config.target != TARGET_VID_MEM) { |
84 | printk(KERN_WARNING "[nvdebug] BAR2 PDB is in an unsupported location.\n"); | 86 | printk(KERN_WARNING "[nvdebug] BAR2 PDB is in an unsupported location.\n"); |
85 | return -EOPNOTSUPP; | 87 | goto attempt_pramin_access; |
86 | } | 88 | } |
87 | uint32_t bar_pdb_pramin_offset = vram2PRAMIN(g, bar_pdb_vram_addr); | 89 | uint32_t bar_pdb_pramin_offset = vram2PRAMIN(g, bar_pdb_vram_addr); |
88 | if (!bar_pdb_pramin_offset) { | 90 | if (!bar_pdb_pramin_offset) { |
89 | printk(KERN_WARNING "[nvdebug] Unable to find page directory BAR2/3 in the current NV_PRAMIN window. VRAM inaccessible.\n"); | 91 | printk(KERN_WARNING "[nvdebug] Unable to find page directory BAR2/3 in the current NV_PRAMIN window. VRAM inaccessible.\n"); |
90 | return -EOPNOTSUPP; | 92 | goto attempt_pramin_access; |
91 | } | 93 | } |
92 | uint64_t runlist_bar_vaddr; | 94 | uint64_t runlist_bar_vaddr; |
93 | if (pd_config.is_ver2) | 95 | if (pd_config.is_ver2) |
@@ -96,7 +98,7 @@ int get_runlist_iter(struct nvdebug_state *g, int rl_id, struct runlist_iter *rl | |||
96 | runlist_bar_vaddr = search_v1_page_directory(g, g->regs + NV_PRAMIN + bar_pdb_pramin_offset, phy2PRAMIN, runlist_iova); | 98 | runlist_bar_vaddr = search_v1_page_directory(g, g->regs + NV_PRAMIN + bar_pdb_pramin_offset, phy2PRAMIN, runlist_iova); |
97 | if (!runlist_bar_vaddr) { | 99 | if (!runlist_bar_vaddr) { |
98 | printk(KERN_WARNING "[nvdebug] Unable to find runlist mapping in BAR2/3 page tables.\n"); | 100 | printk(KERN_WARNING "[nvdebug] Unable to find runlist mapping in BAR2/3 page tables.\n"); |
99 | return -EOPNOTSUPP; | 101 | goto attempt_pramin_access; |
100 | } | 102 | } |
101 | printk(KERN_INFO "[nvdebug] Runlist @ %llx in BAR2 virtual address space.\n", runlist_bar_vaddr); | 103 | printk(KERN_INFO "[nvdebug] Runlist @ %llx in BAR2 virtual address space.\n", runlist_bar_vaddr); |
102 | /* XXX: Old test code | 104 | /* XXX: Old test code |
@@ -121,6 +123,28 @@ int get_runlist_iter(struct nvdebug_state *g, int rl_id, struct runlist_iter *rl | |||
121 | } | 123 | } |
122 | rl_iter->rl_info = rl_info; | 124 | rl_iter->rl_info = rl_info; |
123 | return 0; | 125 | return 0; |
126 | attempt_pramin_access: | ||
127 | #ifdef FALLBACK_TO_PRAMIN | ||
128 | printk(KERN_INFO "[nvdebug] Attempting to move PRAMIN window to runlist as BAR2/3-based access failed [DANGEROUS SIDE EFFECTS]!\n"); | ||
129 | bar0_window_t win; | ||
130 | win.base = (runlist_iova >> 16); | ||
131 | win.target = TARGET_VID_MEM; | ||
132 | // Shift PRAMIN window. This will cause problems if it races with driver code | ||
133 | // that tries to do the same, or expects the window not to move. | ||
134 | nvdebug_writel(g, NV_PBUS_BAR0_WINDOW, win.raw); | ||
135 | uint32_t off = vram2PRAMIN(g, runlist_iova); | ||
136 | // Workaround bug for if `off` should be zero (vram2PRAMIN normally returns | ||
137 | // this on error) | ||
138 | if (!off && (runlist_iova & 0xffffull != runlist_iova)) { | ||
139 | printk(KERN_INFO "[nvdebug] Unable to shift PRAMIN to runlist. Aborting...\n"); | ||
140 | return -EOPNOTSUPP; | ||
141 | } | ||
142 | rl_iter->curr_entry = g->regs + NV_PRAMIN + off; | ||
143 | rl_iter->rl_info = rl_info; | ||
144 | return 0; | ||
145 | #else | ||
146 | return -EOPNOTSUPP; | ||
147 | #endif // FALLBACK_TO_PRAMIN | ||
124 | } | 148 | } |
125 | 149 | ||
126 | int preempt_tsg(struct nvdebug_state *g, uint32_t tsg_id) { | 150 | int preempt_tsg(struct nvdebug_state *g, uint32_t tsg_id) { |