diff options
| author | Joshua Bakita <jbakita@cs.unc.edu> | 2024-04-08 15:35:54 -0400 |
|---|---|---|
| committer | Joshua Bakita <jbakita@cs.unc.edu> | 2024-04-08 17:09:13 -0400 |
| commit | 47506870790989b5e2d9a6128711d96c487f0d7b (patch) | |
| tree | 98c09b9464af4c4a983f75b17568aa5ca919d886 /runlist_procfs.c | |
| parent | 14cb76b1a7e93a5f3900ea7696071dcc281a3586 (diff) | |
Heavily refactor runlist code for correctness and Turing support
- Support differently-formatted runlist registers on Turing
- Support different runlist register offsets on Turing
- Fix incorrect indenting when printing the runlist
- Fix `preempt_tsg` and `switch_to_tsg` API implementations to
correctly interface with the hardware (previously, they would try
to disable scheduling for the last-updated runlist pointer, which
was nonsense, and just an artifact of my early misunderstandings
of how the NV_PFIFO_RUNLIST* registers worked).
- Remove misused NV_PFIFO_RUNLIST and NV_PFIFO_RUNLIST_BASE registers
- Refactor `runlist.c` to use the APIs from `bus.c`
Diffstat (limited to 'runlist_procfs.c')
| -rw-r--r-- | runlist_procfs.c | 52 |
1 files changed, 22 insertions, 30 deletions
diff --git a/runlist_procfs.c b/runlist_procfs.c index f7f937d..7dedee3 100644 --- a/runlist_procfs.c +++ b/runlist_procfs.c | |||
| @@ -69,12 +69,12 @@ static void *runlist_file_seq_start(struct seq_file *s, loff_t *pos) { | |||
| 69 | if (err) | 69 | if (err) |
| 70 | return ERR_PTR(err); | 70 | return ERR_PTR(err); |
| 71 | // Don't try to print an empty runlist | 71 | // Don't try to print an empty runlist |
| 72 | if (rl_iter.rl_info.len <= 0) | 72 | if (rl_iter.len <= 0) |
| 73 | return NULL; | 73 | return NULL; |
| 74 | return &rl_iter; | 74 | return &rl_iter; |
| 75 | } | 75 | } |
| 76 | // If we're resuming an earlier print | 76 | // If we're resuming an earlier print |
| 77 | if (*pos < rl_iter.rl_info.len) { | 77 | if (*pos < rl_iter.len) { |
| 78 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) | 78 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) |
| 79 | // There's a nasty bug prior to 4.19-rc1 that if the buffer overflows, the | 79 | // There's a nasty bug prior to 4.19-rc1 that if the buffer overflows, the |
| 80 | // last update to `pos` is not saved. Work around that here by reloading a | 80 | // last update to `pos` is not saved. Work around that here by reloading a |
| @@ -98,14 +98,16 @@ static void* runlist_file_seq_next(struct seq_file *s, void *raw_rl_iter, | |||
| 98 | (*pos)++; | 98 | (*pos)++; |
| 99 | rl_iter->curr_entry += NV_RL_ENTRY_SIZE(g); | 99 | rl_iter->curr_entry += NV_RL_ENTRY_SIZE(g); |
| 100 | // Verify we haven't reached the end of the runlist | 100 | // Verify we haven't reached the end of the runlist |
| 101 | // rl_info.len is the num of tsg entries + total num of channel entries | 101 | // len is the num of tsg entries + total num of channel entries |
| 102 | if (*pos < rl_iter->rl_info.len) { | 102 | if (*pos < rl_iter->len) { |
| 103 | ret = rl_iter; | 103 | ret = rl_iter; |
| 104 | } | 104 | } |
| 105 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) | 105 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) |
| 106 | // Bug workaround. See comment in runlist_file_seq_start() | 106 | // Bug workaround. See comment in runlist_file_seq_start() |
| 107 | pos_fixup = ret ? *pos : 0; | 107 | pos_fixup = ret ? *pos : 0; |
| 108 | #endif | 108 | #endif |
| 109 | if (rl_iter->entries_left_in_tsg) | ||
| 110 | rl_iter->entries_left_in_tsg--; | ||
| 109 | return ret; | 111 | return ret; |
| 110 | } | 112 | } |
| 111 | 113 | ||
| @@ -113,17 +115,19 @@ static void runlist_file_seq_stop(struct seq_file *s, void *raw_rl_iter) { | |||
| 113 | // No cleanup needed | 115 | // No cleanup needed |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 118 | // _show() must be idempotent. This function will be rerun if the seq_printf | ||
| 119 | // buffer was too small. | ||
| 116 | static int runlist_file_seq_show(struct seq_file *s, void *raw_rl_iter) { | 120 | static int runlist_file_seq_show(struct seq_file *s, void *raw_rl_iter) { |
| 117 | struct runlist_iter *rl_iter = raw_rl_iter; | 121 | struct runlist_iter *rl_iter = raw_rl_iter; |
| 118 | void *entry = rl_iter->curr_entry; | 122 | void *entry = rl_iter->curr_entry; |
| 119 | struct nvdebug_state *g = &g_nvdebug_state[file2parentgpuidx(s->file)]; | 123 | struct nvdebug_state *g = &g_nvdebug_state[file2parentgpuidx(s->file)]; |
| 120 | if (entry_type(g, entry) == ENTRY_TYPE_TSG) { | 124 | if (entry_type(g, entry) == ENTRY_TYPE_TSG) { |
| 121 | if (rl_iter->channels_left_in_tsg) { | 125 | if (rl_iter->entries_left_in_tsg) { |
| 122 | printk(KERN_WARNING "[nvdebug] Found TSG ID%d @ %px when %d channels were still expected under the previous TSG in the runlist!\n", tsgid(g, entry), entry, rl_iter->channels_left_in_tsg); | 126 | printk(KERN_WARNING "[nvdebug] Found TSG ID%d @ %px when %d channels were still expected under the previous TSG in the runlist!\n", tsgid(g, entry), entry, rl_iter->entries_left_in_tsg); |
| 123 | while (rl_iter->channels_left_in_tsg--) | 127 | while (rl_iter->entries_left_in_tsg--) |
| 124 | seq_printf(s, "[missing channel]\n"); | 128 | seq_printf(s, "[missing channel]\n"); |
| 125 | } | 129 | } |
| 126 | rl_iter->channels_left_in_tsg = tsg_length(g, entry); | 130 | rl_iter->entries_left_in_tsg = tsg_length(g, entry) + 1; |
| 127 | seq_printf(s, "+---- TSG Entry %-3d---+\n", tsgid(g, entry)); | 131 | seq_printf(s, "+---- TSG Entry %-3d---+\n", tsgid(g, entry)); |
| 128 | seq_printf(s, "| Scale: %-13d|\n", timeslice_scale(g, entry)); | 132 | seq_printf(s, "| Scale: %-13d|\n", timeslice_scale(g, entry)); |
| 129 | seq_printf(s, "| Timeout: %-11d|\n", timeslice_timeout(g, entry)); | 133 | seq_printf(s, "| Timeout: %-11d|\n", timeslice_timeout(g, entry)); |
| @@ -134,10 +138,8 @@ static int runlist_file_seq_show(struct seq_file *s, void *raw_rl_iter) { | |||
| 134 | #ifndef DETAILED_CHANNEL_INFO | 138 | #ifndef DETAILED_CHANNEL_INFO |
| 135 | u64 instance_ptr = 0; | 139 | u64 instance_ptr = 0; |
| 136 | #endif | 140 | #endif |
| 137 | if (rl_iter->channels_left_in_tsg) { | 141 | if (rl_iter->entries_left_in_tsg) |
| 138 | indt = " "; | 142 | indt = " "; |
| 139 | rl_iter->channels_left_in_tsg--; | ||
| 140 | } | ||
| 141 | #ifdef DETAILED_CHANNEL_INFO | 143 | #ifdef DETAILED_CHANNEL_INFO |
| 142 | runlist_detail_seq_show_chan(s, g, chid(g, entry), indt); | 144 | runlist_detail_seq_show_chan(s, g, chid(g, entry), indt); |
| 143 | #else | 145 | #else |
| @@ -193,8 +195,7 @@ ssize_t preempt_tsg_file_write(struct file *f, const char __user *buffer, | |||
| 193 | return -ERANGE; | 195 | return -ERANGE; |
| 194 | 196 | ||
| 195 | // Execute preemption | 197 | // Execute preemption |
| 196 | err = preempt_tsg(g, target_tsgid); | 198 | if ((err = preempt_tsg(g, target_tsgid))) |
| 197 | if (err) | ||
| 198 | return err; | 199 | return err; |
| 199 | 200 | ||
| 200 | return count; | 201 | return count; |
| @@ -210,8 +211,6 @@ ssize_t disable_channel_file_write(struct file *f, const char __user *buffer, | |||
| 210 | uint32_t target_channel; | 211 | uint32_t target_channel; |
| 211 | channel_ctrl_t chan; | 212 | channel_ctrl_t chan; |
| 212 | int err; | 213 | int err; |
| 213 | runlist_info_t rl_info; | ||
| 214 | runlist_disable_t rl_disable; | ||
| 215 | struct nvdebug_state *g = &g_nvdebug_state[file2gpuidx(f)]; | 214 | struct nvdebug_state *g = &g_nvdebug_state[file2gpuidx(f)]; |
| 216 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec | 215 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec |
| 217 | err = kstrtou32_from_user(buffer, count, 0, &target_channel); | 216 | err = kstrtou32_from_user(buffer, count, 0, &target_channel); |
| @@ -221,19 +220,12 @@ ssize_t disable_channel_file_write(struct file *f, const char __user *buffer, | |||
| 221 | if (target_channel > MAX_CHID) | 220 | if (target_channel > MAX_CHID) |
| 222 | return -ERANGE; | 221 | return -ERANGE; |
| 223 | 222 | ||
| 224 | // Disable channel | 223 | // Read current configuration |
| 225 | chan.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(target_channel)); | 224 | if ((chan.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(target_channel))) == -1) |
| 225 | return -EIO; | ||
| 226 | // Request disablement | ||
| 226 | chan.enable_clear = true; | 227 | chan.enable_clear = true; |
| 227 | // disable sched | ||
| 228 | rl_info.raw = nvdebug_readl(g, NV_PFIFO_RUNLIST); | ||
| 229 | rl_disable.raw = nvdebug_readl(g, NV_PFIFO_SCHED_DISABLE); | ||
| 230 | rl_disable.raw |= BIT(rl_info.id); | ||
| 231 | nvdebug_writel(g, NV_PFIFO_SCHED_DISABLE, rl_disable.raw); | ||
| 232 | // disable chan | ||
| 233 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(target_channel), chan.raw); | 228 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(target_channel), chan.raw); |
| 234 | // enable sched | ||
| 235 | rl_disable.raw &= ~BIT(rl_info.id); | ||
| 236 | nvdebug_writel(g, NV_PFIFO_SCHED_DISABLE, rl_disable.raw); | ||
| 237 | 229 | ||
| 238 | return count; | 230 | return count; |
| 239 | } | 231 | } |
| @@ -270,6 +262,7 @@ struct file_operations enable_channel_file_ops = { | |||
| 270 | .llseek = default_llseek, | 262 | .llseek = default_llseek, |
| 271 | }; | 263 | }; |
| 272 | 264 | ||
| 265 | // Note: Operates only on runlist 0 (Compute/Graphics) | ||
| 273 | ssize_t switch_to_tsg_file_write(struct file *f, const char __user *buffer, | 266 | ssize_t switch_to_tsg_file_write(struct file *f, const char __user *buffer, |
| 274 | size_t count, loff_t *off) { | 267 | size_t count, loff_t *off) { |
| 275 | uint32_t target_tsgid; | 268 | uint32_t target_tsgid; |
| @@ -292,7 +285,7 @@ ssize_t switch_to_tsg_file_write(struct file *f, const char __user *buffer, | |||
| 292 | return err; | 285 | return err; |
| 293 | 286 | ||
| 294 | // Iterate through all TSGs | 287 | // Iterate through all TSGs |
| 295 | while (pos < rl_iter.rl_info.len) { | 288 | while (pos < rl_iter.len) { |
| 296 | if (tsgid(g, rl_iter.curr_entry) == target_tsgid) { | 289 | if (tsgid(g, rl_iter.curr_entry) == target_tsgid) { |
| 297 | // Enable channels of target TSG | 290 | // Enable channels of target TSG |
| 298 | for_chan_in_tsg(g, chan, rl_iter.curr_entry) { | 291 | for_chan_in_tsg(g, chan, rl_iter.curr_entry) { |
| @@ -313,9 +306,8 @@ ssize_t switch_to_tsg_file_write(struct file *f, const char __user *buffer, | |||
| 313 | pos += 1 + tsg_length(g, rl_iter.curr_entry); | 306 | pos += 1 + tsg_length(g, rl_iter.curr_entry); |
| 314 | rl_iter.curr_entry = next_tsg(g, rl_iter.curr_entry); | 307 | rl_iter.curr_entry = next_tsg(g, rl_iter.curr_entry); |
| 315 | } | 308 | } |
| 316 | // Switch to next TSG with active channels (should be our TSG) | 309 | // Trigger a runlist-level preempt to switch to `target_tsgid` |
| 317 | err = preempt_tsg(g, target_tsgid); | 310 | if ((err = preempt_runlist(g, 0))) |
| 318 | if (err) | ||
| 319 | return err; | 311 | return err; |
| 320 | 312 | ||
| 321 | return count; | 313 | return count; |
