diff options
author | Joshua Bakita <bakitajoshua@gmail.com> | 2024-09-10 13:39:59 -0400 |
---|---|---|
committer | Joshua Bakita <bakitajoshua@gmail.com> | 2024-09-10 16:37:09 -0400 |
commit | 16163d89b564029cabf4842815590b0a484cc172 (patch) | |
tree | 7057eaff355b54e8a454243b14f58732be279676 /bus.c | |
parent | 8b9c6400d0c88e127be2d31ab3fb507da49f9d6f (diff) |
Add Hopper and Blackwell support to bus.c
- Handle relocation of PRAMIN window configuration register
- Handle new format for BAR2 configuration
- Catch unreadable PRAMIN configuration
Tested on A100, H100, and AD102 (RTX 6000 Ada).
Diffstat (limited to 'bus.c')
-rw-r--r-- | bus.c | 73 |
1 files changed, 57 insertions, 16 deletions
@@ -24,10 +24,11 @@ | |||
24 | /* Obtain the PRAMIN offset at which `addr` can be accessed | 24 | /* Obtain the PRAMIN offset at which `addr` can be accessed |
25 | @param addr Address to find | 25 | @param addr Address to find |
26 | @param target Which address space to use (VRAM, SYS_MEM, PEER(?)) | 26 | @param target Which address space to use (VRAM, SYS_MEM, PEER(?)) |
27 | @return positive offset or -EINVAL on invalid arguments | 27 | @return positive offset, -EINVAL on invalid arguments, or -EOPNOTSUPP on |
28 | an unsupported platform. | ||
28 | 29 | ||
29 | Note: Will move the PRAMIN window to accomodate the request. Only guarantees | 30 | Note: Will move the PRAMIN window to accomodate the request. Only guarantees |
30 | that the surrounding 64KiB window will be accessible. | 31 | that the surrounding 64-KiB-aligned window will be accessible. |
31 | Note: Moving the PRAMIN window will cause problems if it races with driver | 32 | Note: Moving the PRAMIN window will cause problems if it races with driver |
32 | code that tries to do the same, or expects the window not to move. | 33 | code that tries to do the same, or expects the window not to move. |
33 | Bugs: Untested on PEER. | 34 | Bugs: Untested on PEER. |
@@ -36,6 +37,7 @@ int addr_to_pramin_mut(struct nvdebug_state *g, | |||
36 | uint64_t addr, enum INST_TARGET target) { | 37 | uint64_t addr, enum INST_TARGET target) { |
37 | bar0_window_t window; | 38 | bar0_window_t window; |
38 | uint64_t pramin_base; | 39 | uint64_t pramin_base; |
40 | uint32_t window_reg; | ||
39 | // For us, accuracy and robustness is more important than speed | 41 | // For us, accuracy and robustness is more important than speed |
40 | // Check that the address is valid (49 bits are addressable on-GPU, but | 42 | // Check that the address is valid (49 bits are addressable on-GPU, but |
41 | // PRAMIN only supports up to 40 bits). | 43 | // PRAMIN only supports up to 40 bits). |
@@ -44,21 +46,38 @@ int addr_to_pramin_mut(struct nvdebug_state *g, | |||
44 | addr, __func__); | 46 | addr, __func__); |
45 | return -EINVAL; | 47 | return -EINVAL; |
46 | } | 48 | } |
47 | window.raw = nvdebug_readl(g, NV_PBUS_BAR0_WINDOW); | 49 | // Register relocated on Hopper and Blackwell+ |
48 | if (window.target != target) | 50 | if ((g->chip_id >= NV_CHIP_ID_HOPPER && g->chip_id < NV_CHIP_ID_ADA) || g->chip_id >= NV_CHIP_ID_BLACKWELL) |
49 | goto relocate; | 51 | window_reg = NV_XAL_EP_BAR0_WINDOW_BASE; |
52 | else | ||
53 | window_reg = NV_PBUS_BAR0_WINDOW; | ||
54 | if ((window.raw = nvdebug_readl(g, window_reg)) == -1) { | ||
55 | printk(KERN_ERR "[nvdebug] PRAMIN window configuration inaccessible; " | ||
56 | "failing %s\n", __func__); | ||
57 | return -EOPNOTSUPP; | ||
58 | } | ||
59 | if (window.target != target) { | ||
60 | // On Hopper and Blackwell+, the window always points at VID_MEM | ||
61 | if ((g->chip_id >= NV_CHIP_ID_HOPPER && g->chip_id < NV_CHIP_ID_ADA) || g->chip_id >= NV_CHIP_ID_BLACKWELL) | ||
62 | return -EOPNOTSUPP; | ||
63 | else | ||
64 | goto relocate; | ||
65 | } | ||
50 | pramin_base = ((uint64_t)window.base) << 16; | 66 | pramin_base = ((uint64_t)window.base) << 16; |
51 | if (addr < pramin_base || addr > pramin_base + NV_PRAMIN_LEN) | 67 | if (addr < pramin_base || addr > pramin_base + NV_PRAMIN_LEN) |
52 | goto relocate; | 68 | goto relocate; |
53 | return addr - pramin_base; // Guaranteed to be < 1MiB, so safe for int | 69 | return addr - pramin_base; // Guaranteed to be < 1MiB, so safe for int |
54 | relocate: | 70 | relocate: |
55 | printk(KERN_INFO "[nvdebug] Moving PRAMIN win from base %llx (%s) to %llx (%s) to accomodate %#018llx\n", pramin_base, target_to_text(window.target), (addr >> 16) << 16, target_to_text(target), addr); | 71 | printk(KERN_INFO "[nvdebug] [SIDE EFFECT] Moving PRAMIN window from base " |
72 | "%llx (%s) to %llx (%s) to accomodate %#018llx\n", | ||
73 | ((uint64_t)window.base) << 16, target_to_text(window.target), | ||
74 | (addr >> 16) << 16, target_to_text(target), addr); | ||
56 | // Move PRAMIN window to a 64KiB-aligned address | 75 | // Move PRAMIN window to a 64KiB-aligned address |
57 | window.base = (u32)(addr >> 16); // Safe, due to above range check | 76 | window.base = (u32)(addr >> 16); // Safe, due to above range check |
58 | window.target = target; | 77 | window.target = target; |
59 | nvdebug_writel(g, NV_PBUS_BAR0_WINDOW, window.raw); | 78 | nvdebug_writel(g, window_reg, window.raw); |
60 | // Wait for the window to move by re-reading (as done in nvgpu driver) | 79 | // Wait for the window to move by re-reading (as done in nvgpu driver) |
61 | (void) nvdebug_readl(g, NV_PBUS_BAR0_WINDOW); | 80 | (void) nvdebug_readl(g, window_reg); |
62 | return (int)(addr & 0xffffull); | 81 | return (int)(addr & 0xffffull); |
63 | } | 82 | } |
64 | 83 | ||
@@ -72,7 +91,9 @@ relocate: | |||
72 | */ | 91 | */ |
73 | int get_bar2_pdb(struct nvdebug_state *g, page_dir_config_t* pd) { | 92 | int get_bar2_pdb(struct nvdebug_state *g, page_dir_config_t* pd) { |
74 | int ret; | 93 | int ret; |
75 | bar_config_block_t bar2_block; | 94 | uint64_t bar2_ptr; |
95 | enum INST_TARGET bar2_target; | ||
96 | bool bar2_is_virtual; | ||
76 | 97 | ||
77 | if (!pd) | 98 | if (!pd) |
78 | return -EINVAL; | 99 | return -EINVAL; |
@@ -85,17 +106,37 @@ int get_bar2_pdb(struct nvdebug_state *g, page_dir_config_t* pd) { | |||
85 | // hierarchy used to translate BAR2 offsets to VRAM or SYS_MEM addresses. | 106 | // hierarchy used to translate BAR2 offsets to VRAM or SYS_MEM addresses. |
86 | 107 | ||
87 | // Determine location of BAR2 instance block | 108 | // Determine location of BAR2 instance block |
88 | if ((bar2_block.raw = nvdebug_readl(g, NV_PBUS_BAR2_BLOCK)) == -1) { | 109 | if ((g->chip_id >= NV_CHIP_ID_HOPPER && g->chip_id < NV_CHIP_ID_ADA) || g->chip_id >= NV_CHIP_ID_BLACKWELL) { |
89 | printk(KERN_ERR "[nvdebug] Unable to read BAR2/3 configuration! BAR2/3 inaccessible.\n"); | 110 | // Register layout updated on Hopper and Blackwell+ to support 52-bit |
90 | return -EOPNOTSUPP; | 111 | // instance block pointers (vs. 40 bits before) |
112 | bar_config_block_gh100_t bar2_block; | ||
113 | if ((bar2_block.raw = nvdebug_readq(g, NV_VIRTUAL_FUNCTION_PRIV_FUNC_BAR2_BLOCK)) == -1) { | ||
114 | printk(KERN_ERR "[nvdebug] Unable to read BAR2/3 configuration! BAR2/3 inaccessible.\n"); | ||
115 | return -EOPNOTSUPP; | ||
116 | } | ||
117 | bar2_ptr = (uint64_t)bar2_block.ptr << 12; | ||
118 | bar2_target = bar2_block.target; | ||
119 | bar2_is_virtual = bar2_block.is_virtual; | ||
120 | } else { | ||
121 | bar_config_block_t bar2_block; | ||
122 | if ((bar2_block.raw = nvdebug_readl(g, NV_PBUS_BAR2_BLOCK)) == -1) { | ||
123 | printk(KERN_ERR "[nvdebug] Unable to read BAR2/3 configuration! BAR2/3 inaccessible.\n"); | ||
124 | return -EOPNOTSUPP; | ||
125 | } | ||
126 | bar2_ptr = (uint64_t)bar2_block.ptr << 12; | ||
127 | bar2_target = bar2_block.target; | ||
128 | bar2_is_virtual = bar2_block.is_virtual; | ||
91 | } | 129 | } |
92 | printk(KERN_INFO "[nvdebug] BAR2 inst block @ %llx in %s's %s address space.\n", ((u64)bar2_block.ptr) << 12, target_to_text(bar2_block.target), bar2_block.is_virtual ? "virtual" : "physical"); | 130 | printk(KERN_INFO "[nvdebug] BAR2 inst block @ %llx in %s's %s address space.\n", bar2_ptr, target_to_text(bar2_target), bar2_is_virtual ? "virtual" : "physical"); |
93 | // Setup PRAMIN to point at the BAR2 instance block | 131 | // Setup PRAMIN to point at the BAR2 instance block |
94 | if ((ret = addr_to_pramin_mut(g, (uint64_t)bar2_block.ptr << 12, bar2_block.target)) < 0) { | 132 | // TODO: This won't work if the instance block is in SYS_MEM on Hopper or |
95 | printk(KERN_ERR "[nvdebug] Invalid BAR2/3 Instance Block configuration! BAR2/3 inaccessible.\n"); | 133 | // Blackwell+. Going through the I/O MMU appears to be fairly |
134 | // reliable, so I need to switch to using that logic whenever | ||
135 | // SYS_MEM may be accessed. | ||
136 | if ((ret = addr_to_pramin_mut(g, bar2_ptr, bar2_target)) < 0) { | ||
137 | printk(KERN_ERR "[nvdebug] Unable to access BAR2/3 Instance Block configuration via PRAMIN! BAR2/3 inaccessible.\n"); | ||
96 | return ret; | 138 | return ret; |
97 | } | 139 | } |
98 | printk(KERN_INFO "[nvdebug] BAR2 inst block at off %x in PRAMIN\n", ret); | ||
99 | // Pull the page directory base configuration from the instance block | 140 | // Pull the page directory base configuration from the instance block |
100 | if ((pd->raw = nvdebug_readq(g, NV_PRAMIN + ret + NV_PRAMIN_PDB_CONFIG_OFF)) == -1) { | 141 | if ((pd->raw = nvdebug_readq(g, NV_PRAMIN + ret + NV_PRAMIN_PDB_CONFIG_OFF)) == -1) { |
101 | printk(KERN_ERR "[nvdebug] Unable to read BAR2/3 PDB configuration! BAR2/3 inaccessible.\n"); | 142 | printk(KERN_ERR "[nvdebug] Unable to read BAR2/3 PDB configuration! BAR2/3 inaccessible.\n"); |