diff options
author | Joshua Bakita <jbakita@cs.unc.edu> | 2021-09-23 12:49:27 -0400 |
---|---|---|
committer | Joshua Bakita <jbakita@cs.unc.edu> | 2021-09-23 12:49:27 -0400 |
commit | 0596e479ffcca43957f8d32127cea5527460b983 (patch) | |
tree | 2ea671a4df3def4a72ac3edbce645ff661150cb7 /runlist_procfs.c | |
parent | a7564070dcdf75de4f848af936e3d76ed01833e1 (diff) |
Add APIs to enable/disable a channel and switch to or preempt a specific TSG
Adds:
- /proc/preempt_tsg which takes a TSG ID
- /proc/disable_channel which takes a channel ID
- /proc/enable_channel which takes a channel ID
- /proc/switch_to_tsg which takes a TSG ID
Also significantly expands documentation and structs available in
nvdebug.h.
Diffstat (limited to 'runlist_procfs.c')
-rw-r--r-- | runlist_procfs.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/runlist_procfs.c b/runlist_procfs.c index 183eab6..411f844 100644 --- a/runlist_procfs.c +++ b/runlist_procfs.c | |||
@@ -151,3 +151,138 @@ const struct file_operations runlist_file_ops = { | |||
151 | .llseek = seq_lseek, | 151 | .llseek = seq_lseek, |
152 | .release = seq_release, | 152 | .release = seq_release, |
153 | }; | 153 | }; |
154 | |||
155 | ssize_t preempt_tsg_file_write(struct file *f, const char __user *buffer, | ||
156 | size_t count, loff_t *off) { | ||
157 | uint32_t target_tsgid; | ||
158 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec | ||
159 | int err = kstrtou32_from_user(buffer, count, 0, &target_tsgid); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
163 | // TSG IDs are a 12-bit field, so make sure the request is in-range | ||
164 | if (target_tsgid > MAX_TSGID) | ||
165 | return -ERANGE; | ||
166 | |||
167 | // Execute preemption | ||
168 | err = preempt_tsg(target_tsgid); | ||
169 | if (err) | ||
170 | return err; | ||
171 | |||
172 | return count; | ||
173 | } | ||
174 | |||
175 | const struct file_operations preempt_tsg_file_ops = { | ||
176 | .write = preempt_tsg_file_write, | ||
177 | }; | ||
178 | |||
179 | ssize_t disable_channel_file_write(struct file *f, const char __user *buffer, | ||
180 | size_t count, loff_t *off) { | ||
181 | uint32_t target_channel; | ||
182 | channel_ctrl_t chan; | ||
183 | int err; | ||
184 | struct gk20a *g = get_live_gk20a(); | ||
185 | if (!g) | ||
186 | return -EIO; | ||
187 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec | ||
188 | err = kstrtou32_from_user(buffer, count, 0, &target_channel); | ||
189 | if (err) | ||
190 | return err; | ||
191 | |||
192 | if (target_channel > MAX_CHID) | ||
193 | return -ERANGE; | ||
194 | |||
195 | // Disable channel | ||
196 | chan.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(target_channel)); | ||
197 | chan.enable_clear = true; | ||
198 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(target_channel), chan.raw); | ||
199 | |||
200 | return count; | ||
201 | } | ||
202 | |||
203 | const struct file_operations disable_channel_file_ops = { | ||
204 | .write = disable_channel_file_write, | ||
205 | }; | ||
206 | |||
207 | ssize_t enable_channel_file_write(struct file *f, const char __user *buffer, | ||
208 | size_t count, loff_t *off) { | ||
209 | uint32_t target_channel; | ||
210 | channel_ctrl_t chan; | ||
211 | int err; | ||
212 | struct gk20a *g = get_live_gk20a(); | ||
213 | if (!g) | ||
214 | return -EIO; | ||
215 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec | ||
216 | err = kstrtou32_from_user(buffer, count, 0, &target_channel); | ||
217 | if (err) | ||
218 | return err; | ||
219 | |||
220 | if (target_channel > MAX_CHID) | ||
221 | return -ERANGE; | ||
222 | |||
223 | // Disable channel | ||
224 | chan.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(target_channel)); | ||
225 | chan.enable_set = true; | ||
226 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(target_channel), chan.raw); | ||
227 | |||
228 | return count; | ||
229 | } | ||
230 | |||
231 | const struct file_operations enable_channel_file_ops = { | ||
232 | .write = enable_channel_file_write, | ||
233 | }; | ||
234 | |||
235 | ssize_t switch_to_tsg_file_write(struct file *f, const char __user *buffer, | ||
236 | size_t count, loff_t *off) { | ||
237 | uint32_t target_tsgid; | ||
238 | struct runlist_chan* chan; | ||
239 | channel_ctrl_t chan_ctl; | ||
240 | struct runlist_iter rl_iter; | ||
241 | int err; | ||
242 | loff_t pos = 0; | ||
243 | struct gk20a *g = get_live_gk20a(); | ||
244 | if (!g) | ||
245 | return -EIO; | ||
246 | // Passing 0 as the base to kstrtou32 indicates autodetect hex/octal/dec | ||
247 | err = kstrtou32_from_user(buffer, count, 0, &target_tsgid); | ||
248 | if (err) | ||
249 | return err; | ||
250 | |||
251 | if (target_tsgid > MAX_TSGID) | ||
252 | return -ERANGE; | ||
253 | |||
254 | err = get_runlist_iter(&rl_iter); | ||
255 | if (err) | ||
256 | return err; | ||
257 | |||
258 | // Iterate through all TSGs | ||
259 | while (pos < rl_iter.rl_info.len) { | ||
260 | if (rl_iter.curr_tsg->tsgid == target_tsgid) { | ||
261 | // Enable channels of target TSG | ||
262 | for_chan_in_tsg(chan, rl_iter.curr_tsg) { | ||
263 | chan_ctl.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(chan->chid)); | ||
264 | chan_ctl.enable_set = true; | ||
265 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(chan->chid), chan_ctl.raw); | ||
266 | } | ||
267 | } else { | ||
268 | // Disable all other channels | ||
269 | for_chan_in_tsg(chan, rl_iter.curr_tsg) { | ||
270 | chan_ctl.raw = nvdebug_readq(g, NV_PCCSR_CHANNEL_INST(chan->chid)); | ||
271 | chan_ctl.enable_clear = true; | ||
272 | nvdebug_writeq(g, NV_PCCSR_CHANNEL_INST(chan->chid), chan_ctl.raw); | ||
273 | } | ||
274 | } | ||
275 | pos += 1 + rl_iter.curr_tsg->tsg_length; | ||
276 | rl_iter.curr_tsg = next_tsg(rl_iter.curr_tsg); | ||
277 | } | ||
278 | // Switch to next TSG with active channels (should be our TSG) | ||
279 | err = preempt_tsg(target_tsgid); | ||
280 | if (err) | ||
281 | return err; | ||
282 | |||
283 | return count; | ||
284 | } | ||
285 | |||
286 | const struct file_operations switch_to_tsg_file_ops = { | ||
287 | .write = switch_to_tsg_file_write, | ||
288 | }; | ||