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; |