aboutsummaryrefslogtreecommitdiffstats
path: root/runlist_procfs.c
diff options
context:
space:
mode:
authorJoshua Bakita <jbakita@cs.unc.edu>2024-04-08 15:35:54 -0400
committerJoshua Bakita <jbakita@cs.unc.edu>2024-04-08 17:09:13 -0400
commit47506870790989b5e2d9a6128711d96c487f0d7b (patch)
tree98c09b9464af4c4a983f75b17568aa5ca919d886 /runlist_procfs.c
parent14cb76b1a7e93a5f3900ea7696071dcc281a3586 (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.c52
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.
116static int runlist_file_seq_show(struct seq_file *s, void *raw_rl_iter) { 120static 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)
273ssize_t switch_to_tsg_file_write(struct file *f, const char __user *buffer, 266ssize_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;