diff options
Diffstat (limited to 'runlist_procfs.c')
-rw-r--r-- | runlist_procfs.c | 188 |
1 files changed, 111 insertions, 77 deletions
diff --git a/runlist_procfs.c b/runlist_procfs.c index 411f844..a6b0d94 100644 --- a/runlist_procfs.c +++ b/runlist_procfs.c | |||
@@ -6,7 +6,14 @@ | |||
6 | #define RUNLIST_PROCFS_NAME "runlist" | 6 | #define RUNLIST_PROCFS_NAME "runlist" |
7 | #define DETAILED_CHANNEL_INFO | 7 | #define DETAILED_CHANNEL_INFO |
8 | 8 | ||
9 | static int runlist_detail_seq_show_chan(struct seq_file *s, struct gk20a *g, uint32_t chid) { | 9 | /* Print channel details using PCCSR (Programmable Channel Control System RAM?) |
10 | * @param s Pointer to state from seq_file subsystem to pass to seq_printf | ||
11 | * @param g Pointer to our internal GPU state | ||
12 | * @param chid ID of channel to print details on, range [0, 512) | ||
13 | * @param prefix Text string to prefix each line with, or empty string | ||
14 | */ | ||
15 | #ifdef DETAILED_CHANNEL_INFO | ||
16 | static int runlist_detail_seq_show_chan(struct seq_file *s, struct nvdebug_state *g, uint32_t chid, char *prefix) { | ||
10 | channel_ctrl_t chan; | 17 | channel_ctrl_t chan; |
11 | char *loc_txt; | 18 | char *loc_txt; |
12 | u64 instance_ptr; | 19 | u64 instance_ptr; |
@@ -16,23 +23,37 @@ static int runlist_detail_seq_show_chan(struct seq_file *s, struct gk20a *g, uin | |||
16 | return -EIO; | 23 | return -EIO; |
17 | instance_ptr = chan.inst_ptr; | 24 | instance_ptr = chan.inst_ptr; |
18 | instance_ptr <<= 12; | 25 | instance_ptr <<= 12; |
19 | seq_printf(s, " +- Channel Info %-4d -+\n", chid); | 26 | seq_printf(s, "%s+- Channel Info %-4d -+\n", prefix, chid); |
20 | seq_printf(s, " | Enabled: %d|\n", chan.enable); | 27 | seq_printf(s, "%s| Enabled: %d|\n", prefix, chan.enable); |
21 | seq_printf(s, " | Next: %d|\n", chan.next); | 28 | seq_printf(s, "%s| Next: %d|\n", prefix, chan.next); |
22 | seq_printf(s, " | Force CTX Reload: %d|\n", chan.force_ctx_reload); | 29 | seq_printf(s, "%s| Force CTX Reload: %d|\n", prefix, chan.force_ctx_reload); |
23 | seq_printf(s, " | Enable set: %d|\n", chan.enable_set); | 30 | seq_printf(s, "%s| Enable set: %d|\n", prefix, chan.enable_set); |
24 | seq_printf(s, " | Enable clear: %d|\n", chan.enable_clear); | 31 | seq_printf(s, "%s| Enable clear: %d|\n", prefix, chan.enable_clear); |
25 | seq_printf(s, " | PBDMA Faulted: %d|\n", chan.pbdma_faulted); | 32 | seq_printf(s, "%s| PBDMA Faulted: %d|\n", prefix, chan.pbdma_faulted); |
26 | seq_printf(s, " | ENG Faulted: %d|\n", chan.eng_faulted); | 33 | seq_printf(s, "%s| ENG Faulted: %d|\n", prefix, chan.eng_faulted); |
27 | seq_printf(s, " | Status: %2d|\n", chan.status); | 34 | seq_printf(s, "%s| Status: %2d|\n", prefix, chan.status); |
28 | seq_printf(s, " | Busy: %d|\n", chan.busy); | 35 | seq_printf(s, "%s| Busy: %d|\n", prefix, chan.busy); |
29 | seq_printf(s, " | Instance PTR: |\n"); | 36 | seq_printf(s, "%s| Instance PTR: |\n", prefix); |
30 | seq_printf(s, " | %#018llx |\n", instance_ptr); | 37 | seq_printf(s, "%s| %#018llx |\n", prefix, instance_ptr); |
31 | seq_printf(s, " | %-20s|\n", loc_txt); | 38 | seq_printf(s, "%s| %-20s|\n", prefix, loc_txt); |
32 | seq_printf(s, " | Instance bound: %d|\n", chan.inst_bind); | 39 | seq_printf(s, "%s| Instance bound: %d|\n", prefix, chan.inst_bind); |
33 | seq_printf(s, " +---------------------+\n"); | 40 | // START TEMP |
41 | // "runlist_id -1 is synonym for the ENGINE_GR_GK20A runlist id" | ||
42 | // GR, GRCE, and ASYNC_CE | ||
43 | // Note that this appears to be broken?? | ||
44 | // Peek into the channel instance RAM | ||
45 | if (chan.inst_target == TARGET_SYS_MEM_COHERENT) { | ||
46 | seq_printf(s, "%s| Target Engine: %2d|\n", prefix, *(uint32_t*)phys_to_virt(instance_ptr + 4/*bytes for 32bits*/*43/*NV_RAMFC_TARGET*/) & 0x1f); | ||
47 | seq_printf(s, "%s| PDB LO: %#08x|\n", prefix, *(uint32_t*)phys_to_virt(instance_ptr + 4/*bytes for 32bits*/*128/*NV_RAMIN_PAGE_DIR_BASE_LO*/) & 0xfffff000); | ||
48 | seq_printf(s, "%s| Num subcontexts: %2ld|\n", prefix, hweight64(*(uint64_t*)phys_to_virt(instance_ptr + 4/*bytes for 32bits*/*166/*NV_RAMIN_SC_PDB_VALID*/))); | ||
49 | // This appears to be unset on Xavier | ||
50 | //seq_printf(s, "%s| PAS ID: %8ld|\n", prefix, *(uint32_t*)phys_to_virt(instance_ptr + 4/*bytes for 32bits*/*135/*NV_RAMIN_PASID*/) & 0xfffff); | ||
51 | } | ||
52 | // END TEMP | ||
53 | seq_printf(s, "%s+---------------------+\n", prefix); | ||
34 | return 0; | 54 | return 0; |
35 | } | 55 | } |
56 | #endif | ||
36 | 57 | ||
37 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) | 58 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) |
38 | // Bug workaround. See comment in runlist_file_seq_start() | 59 | // Bug workaround. See comment in runlist_file_seq_start() |
@@ -41,10 +62,14 @@ static loff_t pos_fixup; | |||
41 | 62 | ||
42 | static void *runlist_file_seq_start(struct seq_file *s, loff_t *pos) { | 63 | static void *runlist_file_seq_start(struct seq_file *s, loff_t *pos) { |
43 | static struct runlist_iter rl_iter; | 64 | static struct runlist_iter rl_iter; |
65 | struct nvdebug_state *g = &g_nvdebug_state[file2parentgpuidx(s->file)]; | ||
44 | // *pos == 0 for first call after read of file | 66 | // *pos == 0 for first call after read of file |
45 | if (*pos == 0) { | 67 | if (*pos == 0) { |
46 | int err = get_runlist_iter(&rl_iter); | 68 | int err = get_runlist_iter(g, seq2gpuidx(s), &rl_iter); |
47 | if (err) | 69 | if (err) |
70 | return ERR_PTR(err); | ||
71 | // Don't try to print an empty runlist | ||
72 | if (rl_iter.rl_info.len <= 0) | ||
48 | return NULL; | 73 | return NULL; |
49 | return &rl_iter; | 74 | return &rl_iter; |
50 | } | 75 | } |
@@ -68,12 +93,13 @@ static void* runlist_file_seq_next(struct seq_file *s, void *raw_rl_iter, | |||
68 | loff_t *pos) { | 93 | loff_t *pos) { |
69 | struct runlist_iter* rl_iter = raw_rl_iter; | 94 | struct runlist_iter* rl_iter = raw_rl_iter; |
70 | void *ret = NULL; | 95 | void *ret = NULL; |
71 | // Advance by one TSG + channels under last TSG | 96 | struct nvdebug_state *g = &g_nvdebug_state[file2parentgpuidx(s->file)]; |
72 | *pos += 1 + rl_iter->curr_tsg->tsg_length; | 97 | // Advance by one TSG or channel |
98 | (*pos)++; | ||
99 | rl_iter->curr_entry += NV_RL_ENTRY_SIZE(g); | ||
73 | // Verify we haven't reached the end of the runlist | 100 | // Verify we haven't reached the end of the runlist |
74 | // rl_info.len is the num of tsg entries + total num of channel entries | 101 | // rl_info.len is the num of tsg entries + total num of channel entries |
75 | if (*pos < rl_iter->rl_info.len) { | 102 | if (*pos < rl_iter->rl_info.len) { |
76 | rl_iter->curr_tsg = next_tsg(rl_iter->curr_tsg); | ||
77 | ret = rl_iter; | 103 | ret = rl_iter; |
78 | } | 104 | } |
79 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) | 105 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0) |
@@ -88,57 +114,57 @@ static void runlist_file_seq_stop(struct seq_file *s, void *raw_rl_iter) { | |||
88 | } | 114 | } |
89 | 115 | ||
90 | static int runlist_file_seq_show(struct seq_file *s, void *raw_rl_iter) { | 116 | static int runlist_file_seq_show(struct seq_file *s, void *raw_rl_iter) { |
91 | struct entry_tsg* tsg = ((struct runlist_iter*)raw_rl_iter)->curr_tsg; | 117 | struct runlist_iter *rl_iter = raw_rl_iter; |
92 | struct runlist_chan* chan; | 118 | void *entry = rl_iter->curr_entry; |
93 | struct gk20a *g = get_live_gk20a(); | 119 | struct nvdebug_state *g = &g_nvdebug_state[file2parentgpuidx(s->file)]; |
94 | if (!g) | 120 | if (entry_type(g, entry) == ENTRY_TYPE_TSG) { |
95 | return -EIO; | 121 | if (rl_iter->channels_left_in_tsg) { |
96 | if (tsg->entry_type != ENTRY_TYPE_TSG) { | 122 | printk(KERN_WARNING "[nvdebug] Found a TSG @ %px when %d channels were still expected under the previous TSG in the runlist!\n", entry, rl_iter->channels_left_in_tsg); |
97 | printk(KERN_WARNING "[nvdebug] Attempted to print non-TSG in tsg print logic!\n"); | 123 | return -EIO; |
98 | return -EIO; | 124 | } |
99 | } | 125 | rl_iter->channels_left_in_tsg = tsg_length(g, entry); |
100 | seq_printf(s, "+---- TSG Entry %-2d----+\n", tsg->tsgid); | 126 | seq_printf(s, "+---- TSG Entry %-3d---+\n", tsgid(g, entry)); |
101 | seq_printf(s, "| Scale: %-13d|\n", tsg->timeslice_scale); | 127 | seq_printf(s, "| Scale: %-13d|\n", timeslice_scale(g, entry)); |
102 | seq_printf(s, "| Timeout: %-11d|\n", tsg->timeslice_timeout); | 128 | seq_printf(s, "| Timeout: %-11d|\n", timeslice_timeout(g, entry)); |
103 | seq_printf(s, "+---------------------+\n"); | 129 | seq_printf(s, "| Length: %-12d|\n", tsg_length(g, entry)); |
104 | for_chan_in_tsg(chan, tsg) { | 130 | seq_printf(s, "+---------------------+\n"); |
131 | } else { | ||
132 | char *indt = ""; | ||
105 | #ifndef DETAILED_CHANNEL_INFO | 133 | #ifndef DETAILED_CHANNEL_INFO |
106 | char* loc_txt; | 134 | u64 instance_ptr = 0; |
107 | u64 instance_ptr; | ||
108 | #endif | 135 | #endif |
109 | if (chan->entry_type != ENTRY_TYPE_CHAN) { | 136 | if (rl_iter->channels_left_in_tsg) { |
110 | printk(KERN_WARNING "[nvdebug] Attempted to print non-channel in channel print logic!\n"); | 137 | indt = " "; |
111 | return -EIO; | 138 | rl_iter->channels_left_in_tsg--; |
112 | } | 139 | } |
113 | #ifdef DETAILED_CHANNEL_INFO | 140 | #ifdef DETAILED_CHANNEL_INFO |
114 | runlist_detail_seq_show_chan(s, g, chan->chid); | 141 | runlist_detail_seq_show_chan(s, g, chid(g, entry), indt); |
115 | #else | 142 | #else |
116 | loc_txt = target_to_text(chan->inst_target); | ||
117 | if (!loc_txt) { | ||
118 | printk(KERN_WARNING "[nvdebug] Invalid apature in channel print logic!\n"); | ||
119 | return -EIO; | ||
120 | } | ||
121 | // Reconstruct pointer to channel instance block | 143 | // Reconstruct pointer to channel instance block |
122 | instance_ptr = chan->inst_ptr_hi; | 144 | if (g->chip_id >= NV_CHIP_ID_VOLTA) { |
123 | instance_ptr <<= 32; | 145 | instance_ptr = ((struct gv100_runlist_chan*)entry)->inst_ptr_hi; |
124 | instance_ptr |= chan->inst_ptr_lo << 12; | 146 | instance_ptr <<= 32; |
125 | 147 | } | |
126 | seq_printf(s, " +- Channel Entry %-4d-+\n", chan->chid); | 148 | instance_ptr |= inst_ptr_lo(g, entry) << 12; |
127 | seq_printf(s, " | Runqueue Selector: %d|\n", chan->runqueue_selector); | 149 | |
128 | seq_printf(s, " | Instance PTR: |\n"); | 150 | seq_printf(s, "%s+- Channel Entry %-4d-+\n", indt, chid(g, entry)); |
129 | seq_printf(s, " | %#018llx |\n", instance_ptr); | 151 | if (g->chip_id >= NV_CHIP_ID_VOLTA) |
130 | seq_printf(s, " | %-20s|\n", loc_txt); | 152 | seq_printf(s, "%s| Runqueue Selector: %d|\n", indt, |
131 | seq_printf(s, " +---------------------+\n"); | 153 | ((struct gv100_runlist_chan*)entry)->runqueue_selector); |
154 | seq_printf(s, "%s| Instance PTR: |\n", indt); | ||
155 | seq_printf(s, "%s| %#018llx |\n", indt, instance_ptr); | ||
156 | seq_printf(s, "%s| %-20s|\n", indt, target_to_text(inst_target(g, entry))); | ||
157 | seq_printf(s, "%s+---------------------+\n", indt); | ||
132 | #endif | 158 | #endif |
133 | } | 159 | } |
134 | return 0; | 160 | return 0; |
135 | } | 161 | } |
136 | 162 | ||
137 | static const struct seq_operations runlist_file_seq_ops = { | 163 | static const struct seq_operations runlist_file_seq_ops = { |
138 | .start = runlist_file_seq_start, | 164 | .start = runlist_file_seq_start, |
139 | .next = runlist_file_seq_next, | 165 | .next = runlist_file_seq_next, |
140 | .stop = runlist_file_seq_stop, | 166 | .stop = runlist_file_seq_stop, |
141 | .show = runlist_file_seq_show, | 167 | .show = runlist_file_seq_show, |
142 | }; | 168 | }; |
143 | 169 | ||
144 | static int runlist_file_open(struct inode *inode, struct file *f) { | 170 | static int runlist_file_open(struct inode *inode, struct file *f) { |
@@ -157,6 +183,7 @@ ssize_t preempt_tsg_file_write(struct file *f, const char __user *buffer, | |||
157 | uint32_t target_tsgid; | 183 | uint32_t target_tsgid; |
158 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec | 184 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec |
159 | int err = kstrtou32_from_user(buffer, count, 0, &target_tsgid); | 185 | int err = kstrtou32_from_user(buffer, count, 0, &target_tsgid); |
186 | struct nvdebug_state *g = &g_nvdebug_state[file2gpuidx(f)]; | ||
160 | if (err) | 187 | if (err) |
161 | return err; | 188 | return err; |
162 | 189 | ||
@@ -165,7 +192,7 @@ ssize_t preempt_tsg_file_write(struct file *f, const char __user *buffer, | |||
165 | return -ERANGE; | 192 | return -ERANGE; |
166 | 193 | ||
167 | // Execute preemption | 194 | // Execute preemption |
168 | err = preempt_tsg(target_tsgid); | 195 | err = preempt_tsg(g, target_tsgid); |
169 | if (err) | 196 | if (err) |
170 | return err; | 197 | return err; |
171 | 198 | ||
@@ -181,9 +208,9 @@ ssize_t disable_channel_file_write(struct file *f, const char __user *buffer, | |||
181 | uint32_t target_channel; | 208 | uint32_t target_channel; |
182 | channel_ctrl_t chan; | 209 | channel_ctrl_t chan; |
183 | int err; | 210 | int err; |
184 | struct gk20a *g = get_live_gk20a(); | 211 | runlist_info_t rl_info; |
185 | if (!g) | 212 | runlist_disable_t rl_disable; |
186 | return -EIO; | 213 | struct nvdebug_state *g = &g_nvdebug_state[file2gpuidx(f)]; |
187 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec | 214 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec |
188 | err = kstrtou32_from_user(buffer, count, 0, &target_channel); | 215 | err = kstrtou32_from_user(buffer, count, 0, &target_channel); |
189 | if (err) | 216 | if (err) |
@@ -195,7 +222,16 @@ ssize_t disable_channel_file_write(struct file *f, const char __user *buffer, | |||
195 | // Disable channel | 222 | // Disable channel |
196 | chan.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(target_channel)); | 223 | chan.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(target_channel)); |
197 | chan.enable_clear = true; | 224 | chan.enable_clear = true; |
225 | // disable sched | ||
226 | rl_info.raw = nvdebug_readl(g, NV_PFIFO_RUNLIST); | ||
227 | rl_disable.raw = nvdebug_readl(g, NV_PFIFO_SCHED_DISABLE); | ||
228 | rl_disable.raw |= BIT(rl_info.id); | ||
229 | nvdebug_writel(g, NV_PFIFO_SCHED_DISABLE, rl_disable.raw); | ||
230 | // disable chan | ||
198 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(target_channel), chan.raw); | 231 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(target_channel), chan.raw); |
232 | // enable sched | ||
233 | rl_disable.raw &= ~BIT(rl_info.id); | ||
234 | nvdebug_writel(g, NV_PFIFO_SCHED_DISABLE, rl_disable.raw); | ||
199 | 235 | ||
200 | return count; | 236 | return count; |
201 | } | 237 | } |
@@ -209,9 +245,7 @@ ssize_t enable_channel_file_write(struct file *f, const char __user *buffer, | |||
209 | uint32_t target_channel; | 245 | uint32_t target_channel; |
210 | channel_ctrl_t chan; | 246 | channel_ctrl_t chan; |
211 | int err; | 247 | int err; |
212 | struct gk20a *g = get_live_gk20a(); | 248 | struct nvdebug_state *g = &g_nvdebug_state[file2gpuidx(f)]; |
213 | if (!g) | ||
214 | return -EIO; | ||
215 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec | 249 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec |
216 | err = kstrtou32_from_user(buffer, count, 0, &target_channel); | 250 | err = kstrtou32_from_user(buffer, count, 0, &target_channel); |
217 | if (err) | 251 | if (err) |
@@ -235,14 +269,12 @@ const struct file_operations enable_channel_file_ops = { | |||
235 | ssize_t switch_to_tsg_file_write(struct file *f, const char __user *buffer, | 269 | ssize_t switch_to_tsg_file_write(struct file *f, const char __user *buffer, |
236 | size_t count, loff_t *off) { | 270 | size_t count, loff_t *off) { |
237 | uint32_t target_tsgid; | 271 | uint32_t target_tsgid; |
238 | struct runlist_chan* chan; | 272 | struct gv100_runlist_chan* chan; |
239 | channel_ctrl_t chan_ctl; | 273 | channel_ctrl_t chan_ctl; |
240 | struct runlist_iter rl_iter; | 274 | struct runlist_iter rl_iter; |
241 | int err; | 275 | int err; |
242 | loff_t pos = 0; | 276 | loff_t pos = 0; |
243 | struct gk20a *g = get_live_gk20a(); | 277 | struct nvdebug_state *g = &g_nvdebug_state[file2gpuidx(f)]; |
244 | if (!g) | ||
245 | return -EIO; | ||
246 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec | 278 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec |
247 | err = kstrtou32_from_user(buffer, count, 0, &target_tsgid); | 279 | err = kstrtou32_from_user(buffer, count, 0, &target_tsgid); |
248 | if (err) | 280 | if (err) |
@@ -251,32 +283,34 @@ ssize_t switch_to_tsg_file_write(struct file *f, const char __user *buffer, | |||
251 | if (target_tsgid > MAX_TSGID) | 283 | if (target_tsgid > MAX_TSGID) |
252 | return -ERANGE; | 284 | return -ERANGE; |
253 | 285 | ||
254 | err = get_runlist_iter(&rl_iter); | 286 | err = get_runlist_iter(g, 0, &rl_iter); |
255 | if (err) | 287 | if (err) |
256 | return err; | 288 | return err; |
257 | 289 | ||
258 | // Iterate through all TSGs | 290 | // Iterate through all TSGs |
259 | while (pos < rl_iter.rl_info.len) { | 291 | while (pos < rl_iter.rl_info.len) { |
260 | if (rl_iter.curr_tsg->tsgid == target_tsgid) { | 292 | if (tsgid(g, rl_iter.curr_entry) == target_tsgid) { |
261 | // Enable channels of target TSG | 293 | // Enable channels of target TSG |
262 | for_chan_in_tsg(chan, rl_iter.curr_tsg) { | 294 | for_chan_in_tsg(g, chan, rl_iter.curr_entry) { |
263 | chan_ctl.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(chan->chid)); | 295 | chan_ctl.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(chan->chid)); |
264 | chan_ctl.enable_set = true; | 296 | chan_ctl.enable_set = true; |
265 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(chan->chid), chan_ctl.raw); | 297 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(chan->chid), chan_ctl.raw); |
266 | } | 298 | } |
267 | } else { | 299 | } else { |
300 | // XXX: Fix for bare channels. Maybe a "for_chan_until_tsg" macro? | ||
268 | // Disable all other channels | 301 | // Disable all other channels |
269 | for_chan_in_tsg(chan, rl_iter.curr_tsg) { | 302 | // (This is how the Jetson nvgpu driver disables TSGs) |
303 | for_chan_in_tsg(g, chan, rl_iter.curr_entry) { | ||
270 | chan_ctl.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(chan->chid)); | 304 | chan_ctl.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(chan->chid)); |
271 | chan_ctl.enable_clear = true; | 305 | chan_ctl.enable_clear = true; |
272 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(chan->chid), chan_ctl.raw); | 306 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(chan->chid), chan_ctl.raw); |
273 | } | 307 | } |
274 | } | 308 | } |
275 | pos += 1 + rl_iter.curr_tsg->tsg_length; | 309 | pos += 1 + tsg_length(g, rl_iter.curr_entry); |
276 | rl_iter.curr_tsg = next_tsg(rl_iter.curr_tsg); | 310 | rl_iter.curr_entry = next_tsg(g, rl_iter.curr_entry); |
277 | } | 311 | } |
278 | // Switch to next TSG with active channels (should be our TSG) | 312 | // Switch to next TSG with active channels (should be our TSG) |
279 | err = preempt_tsg(target_tsgid); | 313 | err = preempt_tsg(g, target_tsgid); |
280 | if (err) | 314 | if (err) |
281 | return err; | 315 | return err; |
282 | 316 | ||