diff options
| author | Joshua Bakita <bakitajoshua@gmail.com> | 2024-09-19 12:50:02 -0400 |
|---|---|---|
| committer | Joshua Bakita <bakitajoshua@gmail.com> | 2024-09-19 13:59:56 -0400 |
| commit | 48f9e45b9d9ebfca7d3c673597f7fbed9427a5af (patch) | |
| tree | d63c3863e9b187fb1f62d2f3c58b8c6a9568b6cc /runlist.c | |
| parent | ac0113ab52d2ca12a5c10feeaa887d10c37ee4f1 (diff) | |
Ampere: disable/enable_channel, preempt/switch_to_tsg, and resubmit_runlist
**Modifes the user API from `echo 1 > /proc/gpuX/switch_to_tsg` to
`echo 1 > /proc/gpuX/runlist0/switch_to_tsg` to switch to TSG 1 on
runlist 0 on GPU X for pre-Ampere GPUs (for example).**
Feature changes:
- switch_to_tsg only makes sense on a per-runlist level. Before, this
always operated on runlist0; this commit allows operating on any
runlist by moving the API to the per-runlist paths.
- On Ampere+, channel and TSG IDs are per-runlist, and no longer
GPU-global. Consequently, the disable/enable_channel and
preempt_tsg APIs have been moved from GPU-global to per-runlist
paths on Ampere+.
Bug fixes:
- `preempt_runlist()` is now supported on Maxwell and Pascal.
- `resubmit_runlist()` detects too-old GPUs.
- MAX_CHID corrected from 512 to 511 and documented.
- switch_to_tsg now includes a runlist resubmit, which appears to be
necessary on Turing+ GPUs.
Tested on GK104 (Quadro K5000), GM204 (GTX 970), GP106 (GTX 1060 3GB),
GP104 (GTX 1080 Ti), GP10B (Jetson TX2), GV11B (Jetson Xavier), GV100
(Titan V), TU102 (RTX 2080 Ti), and AD102 (RTX 6000 Ada).
Diffstat (limited to 'runlist.c')
| -rw-r--r-- | runlist.c | 69 |
1 files changed, 56 insertions, 13 deletions
| @@ -169,24 +169,35 @@ attempt_pramin_access: | |||
| 169 | 169 | ||
| 170 | /* Trigger a preempt of the specified TSG | 170 | /* Trigger a preempt of the specified TSG |
| 171 | @param tsg_id ID of TSG to preempt. | 171 | @param tsg_id ID of TSG to preempt. |
| 172 | @param rl_id Which channel RAM address space to search? | ||
| 172 | @return 0 or -errno on error | 173 | @return 0 or -errno on error |
| 173 | 174 | ||
| 174 | Note: If no other TSGs exist in the associated runlist, this TSG may | 175 | Note: If no other TSGs exist in the associated runlist, this TSG may |
| 175 | continue executing, unless NV_PFIFO_SCHED_DISABLE is set, or all the | 176 | continue executing, unless NV_PFIFO_SCHED_DISABLE is set, or all the |
| 176 | channels of the TSG to be preempted are disabled. | 177 | channels of the TSG to be preempted are disabled. |
| 177 | */ | 178 | */ |
| 178 | int preempt_tsg(struct nvdebug_state *g, uint32_t tsg_id) { | 179 | int preempt_tsg(struct nvdebug_state *g, uint32_t rl_id, uint32_t tsg_id) { |
| 179 | pfifo_preempt_t pfifo_preempt; | 180 | pfifo_preempt_t preempt; |
| 181 | // Fermi does not support time-slice groups | ||
| 180 | if (g->chip_id < NV_CHIP_ID_KEPLER) | 182 | if (g->chip_id < NV_CHIP_ID_KEPLER) |
| 181 | return -EOPNOTSUPP; | 183 | return -EOPNOTSUPP; |
| 182 | 184 | ||
| 183 | pfifo_preempt.raw = 0; | 185 | preempt.raw = 0; |
| 184 | pfifo_preempt.id = tsg_id; | 186 | preempt.id = tsg_id; |
| 185 | pfifo_preempt.is_pending = 0; | 187 | preempt.type = PREEMPT_TYPE_TSG; |
| 186 | pfifo_preempt.type = PREEMPT_TYPE_TSG; | ||
| 187 | 188 | ||
| 188 | // Actually trigger the preemption | 189 | // Actually trigger the preemption |
| 189 | nvdebug_writel(g, NV_PFIFO_PREEMPT, pfifo_preempt.raw); | 190 | if (g->chip_id < NV_CHIP_ID_AMPERE) { |
| 191 | nvdebug_writel(g, NV_PFIFO_PREEMPT, preempt.raw); | ||
| 192 | } else { | ||
| 193 | uint32_t runlist_reg_base; | ||
| 194 | int err; | ||
| 195 | // As TSG and channel IDs are namespaced per-runlist starting with | ||
| 196 | // Ampere, the PREEMPT register is also per-runlist. | ||
| 197 | if ((err = get_runlist_ram(g, rl_id, &runlist_reg_base))) | ||
| 198 | return err; | ||
| 199 | nvdebug_writel(g, runlist_reg_base + NV_RUNLIST_PREEMPT_GA100, preempt.raw); | ||
| 200 | } | ||
| 190 | return 0; | 201 | return 0; |
| 191 | } | 202 | } |
| 192 | 203 | ||
| @@ -195,18 +206,38 @@ int preempt_tsg(struct nvdebug_state *g, uint32_t tsg_id) { | |||
| 195 | @return 0 or -errno on error | 206 | @return 0 or -errno on error |
| 196 | */ | 207 | */ |
| 197 | int preempt_runlist(struct nvdebug_state *g, uint32_t rl_id) { | 208 | int preempt_runlist(struct nvdebug_state *g, uint32_t rl_id) { |
| 198 | runlist_preempt_t rl_preempt; | 209 | // The runlist preempt register does not exist on Kepler (tested gk104) |
| 199 | if (g->chip_id < NV_CHIP_ID_VOLTA) | 210 | if (g->chip_id < NV_CHIP_ID_MAXWELL) |
| 200 | return -EOPNOTSUPP; | 211 | return -EOPNOTSUPP; |
| 201 | 212 | ||
| 202 | // Overwrite, as the register contains nothing to preserve | 213 | // Write to trigger the preemption (the register contains nothing to |
| 203 | rl_preempt.raw = BIT(rl_id); | 214 | // preserve, and can thus just be overwritten) |
| 204 | nvdebug_writel(g, NV_PFIFO_RUNLIST_PREEMPT, rl_preempt.raw); | 215 | if (g->chip_id < NV_CHIP_ID_AMPERE) { |
| 216 | runlist_preempt_t rl_preempt; | ||
| 217 | rl_preempt.raw = BIT(rl_id); | ||
| 218 | nvdebug_writel(g, NV_PFIFO_RUNLIST_PREEMPT, rl_preempt.raw); | ||
| 219 | } else { | ||
| 220 | int err; | ||
| 221 | uint32_t runlist_regs_base; | ||
| 222 | pfifo_preempt_t preempt; | ||
| 223 | // The RUNLIST_PREEMPT register was deleted, and the _PREEMPT register | ||
| 224 | // was extended to support runlist-level preemptions starting on Ampere | ||
| 225 | preempt.id = rl_id; | ||
| 226 | preempt.type = PREEMPT_TYPE_RUNLIST; | ||
| 227 | // The preempt register is scoped per-runlist on Ampere+ | ||
| 228 | if ((err = get_runlist_ram(g, rl_id, &runlist_regs_base))) | ||
| 229 | return err; | ||
| 230 | nvdebug_writel(g, runlist_regs_base + NV_RUNLIST_PREEMPT_GA100, preempt.raw); | ||
| 231 | } | ||
| 205 | return 0; | 232 | return 0; |
| 206 | } | 233 | } |
| 207 | 234 | ||
| 208 | // Read and write runlist configuration, triggering a resubmit | 235 | // Read and write runlist configuration, triggering a resubmit |
| 209 | int resubmit_runlist(struct nvdebug_state *g, uint32_t rl_id) { | 236 | int resubmit_runlist(struct nvdebug_state *g, uint32_t rl_id) { |
| 237 | // Necessary registers do not exist pre-Fermi | ||
| 238 | if (g->chip_id < NV_CHIP_ID_FERMI) | ||
| 239 | return -EOPNOTSUPP; | ||
| 240 | |||
| 210 | if (g->chip_id < NV_CHIP_ID_TURING) { | 241 | if (g->chip_id < NV_CHIP_ID_TURING) { |
| 211 | eng_runlist_gf100_t rl; | 242 | eng_runlist_gf100_t rl; |
| 212 | if (rl_id > MAX_RUNLISTS_GF100) | 243 | if (rl_id > MAX_RUNLISTS_GF100) |
| @@ -223,7 +254,19 @@ int resubmit_runlist(struct nvdebug_state *g, uint32_t rl_id) { | |||
| 223 | return -EIO; | 254 | return -EIO; |
| 224 | nvdebug_writeq(g, NV_PFIFO_RUNLIST_SUBMIT_TU102(rl_id), submit.raw); | 255 | nvdebug_writeq(g, NV_PFIFO_RUNLIST_SUBMIT_TU102(rl_id), submit.raw); |
| 225 | } else { | 256 | } else { |
| 226 | return -EOPNOTSUPP; | 257 | int err; |
| 258 | uint32_t runlist_pri_base; | ||
| 259 | runlist_submit_tu102_t submit; | ||
| 260 | if ((err = get_runlist_ram(g, rl_id, &runlist_pri_base)) < 0) | ||
| 261 | return err; | ||
| 262 | if ((submit.raw = nvdebug_readq(g, runlist_pri_base + NV_RUNLIST_SUBMIT_GA100)) == -1) | ||
| 263 | return -EIO; | ||
| 264 | // On Ampere, this does not appear to trigger a preempt of the | ||
| 265 | // currently-running channel (even if the currently running channel | ||
| 266 | // becomes disabled), but will cause newly re-enabled channels | ||
| 267 | // (at least if nothing else is pending) to become ready (tested on | ||
| 268 | // Jetson Orin). | ||
| 269 | nvdebug_writeq(g, runlist_pri_base + NV_RUNLIST_SUBMIT_GA100, submit.raw); | ||
| 227 | } | 270 | } |
| 228 | return 0; | 271 | return 0; |
| 229 | } | 272 | } |
