summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/regops_gk20a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/regops_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/regops_gk20a.c736
1 files changed, 736 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/regops_gk20a.c b/drivers/gpu/nvgpu/gk20a/regops_gk20a.c
new file mode 100644
index 00000000..e7aeaa54
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/regops_gk20a.c
@@ -0,0 +1,736 @@
1/*
2 * Tegra GK20A GPU Debugger Driver Register Ops
3 *
4 * Copyright (c) 2013-2017, NVIDIA CORPORATION. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25#include <linux/err.h>
26#include <uapi/linux/nvgpu.h>
27
28#include "gk20a.h"
29#include "gr_gk20a.h"
30#include "dbg_gpu_gk20a.h"
31#include "regops_gk20a.h"
32
33#include <nvgpu/log.h>
34#include <nvgpu/bsearch.h>
35#include <nvgpu/bug.h>
36
37static int regop_bsearch_range_cmp(const void *pkey, const void *pelem)
38{
39 u32 key = *(u32 *)pkey;
40 struct regop_offset_range *prange = (struct regop_offset_range *)pelem;
41 if (key < prange->base)
42 return -1;
43 else if (prange->base <= key && key < (prange->base +
44 (prange->count * 4U)))
45 return 0;
46 return 1;
47}
48
49static inline bool linear_search(u32 offset, const u32 *list, int size)
50{
51 int i;
52 for (i = 0; i < size; i++)
53 if (list[i] == offset)
54 return true;
55 return false;
56}
57
58static const struct regop_offset_range gk20a_global_whitelist_ranges[] = {
59 { 0x000004f0, 1 },
60 { 0x00001a00, 3 },
61 { 0x0000259c, 1 },
62 { 0x0000280c, 1 },
63 { 0x00009400, 1 },
64 { 0x00009410, 1 },
65 { 0x00022430, 7 },
66 { 0x00022548, 1 },
67 { 0x00100c18, 3 },
68 { 0x00100c84, 1 },
69 { 0x00100cc4, 1 },
70 { 0x00106640, 1 },
71 { 0x0010a0a8, 1 },
72 { 0x0010a4f0, 1 },
73 { 0x0010e064, 1 },
74 { 0x0010e164, 1 },
75 { 0x0010e490, 1 },
76 { 0x00110100, 1 },
77 { 0x00140028, 1 },
78 { 0x001408dc, 1 },
79 { 0x00140a5c, 1 },
80 { 0x001410dc, 1 },
81 { 0x0014125c, 1 },
82 { 0x0017e028, 1 },
83 { 0x0017e8dc, 1 },
84 { 0x0017ea5c, 1 },
85 { 0x0017f0dc, 1 },
86 { 0x0017f25c, 1 },
87 { 0x00180000, 68 },
88 { 0x00180200, 68 },
89 { 0x001a0000, 68 },
90 { 0x001b0000, 68 },
91 { 0x001b0200, 68 },
92 { 0x001b0400, 68 },
93 { 0x001b0600, 68 },
94 { 0x001b4000, 3 },
95 { 0x001b4010, 3 },
96 { 0x001b4020, 3 },
97 { 0x001b4040, 3 },
98 { 0x001b4050, 3 },
99 { 0x001b4060, 4 },
100 { 0x001b4074, 11 },
101 { 0x001b40a4, 1 },
102 { 0x001b4100, 6 },
103 { 0x001b4124, 2 },
104 { 0x001b8000, 7 },
105 { 0x001bc000, 7 },
106 { 0x001be000, 7 },
107 { 0x00400500, 1 },
108 { 0x00400700, 1 },
109 { 0x0040415c, 1 },
110 { 0x00405850, 1 },
111 { 0x00405908, 1 },
112 { 0x00405b40, 1 },
113 { 0x00405b50, 1 },
114 { 0x00406024, 1 },
115 { 0x00407010, 1 },
116 { 0x00407808, 1 },
117 { 0x0040803c, 1 },
118 { 0x0040880c, 1 },
119 { 0x00408910, 1 },
120 { 0x00408984, 1 },
121 { 0x004090a8, 1 },
122 { 0x004098a0, 1 },
123 { 0x0041000c, 1 },
124 { 0x00410110, 1 },
125 { 0x00410184, 1 },
126 { 0x00418384, 1 },
127 { 0x004184a0, 1 },
128 { 0x00418604, 1 },
129 { 0x00418680, 1 },
130 { 0x00418714, 1 },
131 { 0x0041881c, 1 },
132 { 0x004188c8, 2 },
133 { 0x00418b04, 1 },
134 { 0x00418c04, 1 },
135 { 0x00418c64, 2 },
136 { 0x00418c88, 1 },
137 { 0x00418cb4, 2 },
138 { 0x00418d00, 1 },
139 { 0x00418d28, 2 },
140 { 0x00418e08, 1 },
141 { 0x00418e1c, 2 },
142 { 0x00418f08, 1 },
143 { 0x00418f20, 2 },
144 { 0x00419000, 1 },
145 { 0x0041900c, 1 },
146 { 0x00419018, 1 },
147 { 0x00419854, 1 },
148 { 0x00419ab0, 1 },
149 { 0x00419ab8, 3 },
150 { 0x00419ac8, 1 },
151 { 0x00419c0c, 1 },
152 { 0x00419c8c, 3 },
153 { 0x00419ca8, 1 },
154 { 0x00419d08, 2 },
155 { 0x00419e00, 1 },
156 { 0x00419e0c, 1 },
157 { 0x00419e14, 2 },
158 { 0x00419e24, 2 },
159 { 0x00419e34, 2 },
160 { 0x00419e44, 4 },
161 { 0x00419ea4, 1 },
162 { 0x00419eb0, 1 },
163 { 0x0041a0a0, 1 },
164 { 0x0041a0a8, 1 },
165 { 0x0041a17c, 1 },
166 { 0x0041a890, 2 },
167 { 0x0041a8a0, 3 },
168 { 0x0041a8b0, 2 },
169 { 0x0041b014, 1 },
170 { 0x0041b0a0, 1 },
171 { 0x0041b0cc, 1 },
172 { 0x0041b0e8, 2 },
173 { 0x0041b1dc, 1 },
174 { 0x0041b1f8, 2 },
175 { 0x0041be14, 1 },
176 { 0x0041bea0, 1 },
177 { 0x0041becc, 1 },
178 { 0x0041bee8, 2 },
179 { 0x0041bfdc, 1 },
180 { 0x0041bff8, 2 },
181 { 0x0041c054, 1 },
182 { 0x0041c2b0, 1 },
183 { 0x0041c2b8, 3 },
184 { 0x0041c2c8, 1 },
185 { 0x0041c40c, 1 },
186 { 0x0041c48c, 3 },
187 { 0x0041c4a8, 1 },
188 { 0x0041c508, 2 },
189 { 0x0041c600, 1 },
190 { 0x0041c60c, 1 },
191 { 0x0041c614, 2 },
192 { 0x0041c624, 2 },
193 { 0x0041c634, 2 },
194 { 0x0041c644, 4 },
195 { 0x0041c6a4, 1 },
196 { 0x0041c6b0, 1 },
197 { 0x00500384, 1 },
198 { 0x005004a0, 1 },
199 { 0x00500604, 1 },
200 { 0x00500680, 1 },
201 { 0x00500714, 1 },
202 { 0x0050081c, 1 },
203 { 0x005008c8, 2 },
204 { 0x00500b04, 1 },
205 { 0x00500c04, 1 },
206 { 0x00500c64, 2 },
207 { 0x00500c88, 1 },
208 { 0x00500cb4, 2 },
209 { 0x00500d00, 1 },
210 { 0x00500d28, 2 },
211 { 0x00500e08, 1 },
212 { 0x00500e1c, 2 },
213 { 0x00500f08, 1 },
214 { 0x00500f20, 2 },
215 { 0x00501000, 1 },
216 { 0x0050100c, 1 },
217 { 0x00501018, 1 },
218 { 0x00501854, 1 },
219 { 0x00501ab0, 1 },
220 { 0x00501ab8, 3 },
221 { 0x00501ac8, 1 },
222 { 0x00501c0c, 1 },
223 { 0x00501c8c, 3 },
224 { 0x00501ca8, 1 },
225 { 0x00501d08, 2 },
226 { 0x00501e00, 1 },
227 { 0x00501e0c, 1 },
228 { 0x00501e14, 2 },
229 { 0x00501e24, 2 },
230 { 0x00501e34, 2 },
231 { 0x00501e44, 4 },
232 { 0x00501ea4, 1 },
233 { 0x00501eb0, 1 },
234 { 0x005020a0, 1 },
235 { 0x005020a8, 1 },
236 { 0x0050217c, 1 },
237 { 0x00502890, 2 },
238 { 0x005028a0, 3 },
239 { 0x005028b0, 2 },
240 { 0x00503014, 1 },
241 { 0x005030a0, 1 },
242 { 0x005030cc, 1 },
243 { 0x005030e8, 2 },
244 { 0x005031dc, 1 },
245 { 0x005031f8, 2 },
246 { 0x00503e14, 1 },
247 { 0x00503ea0, 1 },
248 { 0x00503ecc, 1 },
249 { 0x00503ee8, 2 },
250 { 0x00503fdc, 1 },
251 { 0x00503ff8, 2 },
252 { 0x00504054, 1 },
253 { 0x005042b0, 1 },
254 { 0x005042b8, 3 },
255 { 0x005042c8, 1 },
256 { 0x0050440c, 1 },
257 { 0x0050448c, 3 },
258 { 0x005044a8, 1 },
259 { 0x00504508, 2 },
260 { 0x00504600, 1 },
261 { 0x0050460c, 1 },
262 { 0x00504614, 2 },
263 { 0x00504624, 2 },
264 { 0x00504634, 2 },
265 { 0x00504644, 4 },
266 { 0x005046a4, 1 },
267 { 0x005046b0, 1 },
268};
269static const u32 gk20a_global_whitelist_ranges_count =
270 ARRAY_SIZE(gk20a_global_whitelist_ranges);
271
272/* context */
273
274static const struct regop_offset_range gk20a_context_whitelist_ranges[] = {
275 { 0x0000280c, 1 },
276 { 0x00100cc4, 1 },
277 { 0x00400500, 1 },
278 { 0x00405b40, 1 },
279 { 0x00419000, 1 },
280 { 0x00419c8c, 3 },
281 { 0x00419d08, 2 },
282 { 0x00419e04, 3 },
283 { 0x00419e14, 2 },
284 { 0x00419e24, 2 },
285 { 0x00419e34, 2 },
286 { 0x00419e44, 4 },
287 { 0x00419e58, 6 },
288 { 0x00419e84, 5 },
289 { 0x00419ea4, 1 },
290 { 0x00419eac, 2 },
291 { 0x00419f30, 8 },
292 { 0x0041c48c, 3 },
293 { 0x0041c508, 2 },
294 { 0x0041c604, 3 },
295 { 0x0041c614, 2 },
296 { 0x0041c624, 2 },
297 { 0x0041c634, 2 },
298 { 0x0041c644, 4 },
299 { 0x0041c658, 6 },
300 { 0x0041c684, 5 },
301 { 0x0041c6a4, 1 },
302 { 0x0041c6ac, 2 },
303 { 0x0041c730, 8 },
304 { 0x00501000, 1 },
305 { 0x00501c8c, 3 },
306 { 0x00501d08, 2 },
307 { 0x00501e04, 3 },
308 { 0x00501e14, 2 },
309 { 0x00501e24, 2 },
310 { 0x00501e34, 2 },
311 { 0x00501e44, 4 },
312 { 0x00501e58, 6 },
313 { 0x00501e84, 5 },
314 { 0x00501ea4, 1 },
315 { 0x00501eac, 2 },
316 { 0x00501f30, 8 },
317 { 0x0050448c, 3 },
318 { 0x00504508, 2 },
319 { 0x00504604, 3 },
320 { 0x00504614, 2 },
321 { 0x00504624, 2 },
322 { 0x00504634, 2 },
323 { 0x00504644, 4 },
324 { 0x00504658, 6 },
325 { 0x00504684, 5 },
326 { 0x005046a4, 1 },
327 { 0x005046ac, 2 },
328 { 0x00504730, 8 },
329};
330static const u32 gk20a_context_whitelist_ranges_count =
331 ARRAY_SIZE(gk20a_context_whitelist_ranges);
332
333/* runcontrol */
334static const u32 gk20a_runcontrol_whitelist[] = {
335 0x00419e10,
336 0x0041c610,
337 0x00501e10,
338 0x00504610,
339};
340static const u32 gk20a_runcontrol_whitelist_count =
341 ARRAY_SIZE(gk20a_runcontrol_whitelist);
342
343static const struct regop_offset_range gk20a_runcontrol_whitelist_ranges[] = {
344 { 0x00419e10, 1 },
345 { 0x0041c610, 1 },
346 { 0x00501e10, 1 },
347 { 0x00504610, 1 },
348};
349static const u32 gk20a_runcontrol_whitelist_ranges_count =
350 ARRAY_SIZE(gk20a_runcontrol_whitelist_ranges);
351
352
353/* quad ctl */
354static const u32 gk20a_qctl_whitelist[] = {
355 0x00504670,
356 0x00504674,
357 0x00504678,
358 0x0050467c,
359 0x00504680,
360 0x00504730,
361 0x00504734,
362 0x00504738,
363 0x0050473c,
364};
365static const u32 gk20a_qctl_whitelist_count =
366 ARRAY_SIZE(gk20a_qctl_whitelist);
367
368static const struct regop_offset_range gk20a_qctl_whitelist_ranges[] = {
369 { 0x00504670, 1 },
370 { 0x00504730, 4 },
371};
372static const u32 gk20a_qctl_whitelist_ranges_count =
373 ARRAY_SIZE(gk20a_qctl_whitelist_ranges);
374
375
376
377
378static bool validate_reg_ops(struct dbg_session_gk20a *dbg_s,
379 u32 *ctx_rd_count, u32 *ctx_wr_count,
380 struct nvgpu_dbg_gpu_reg_op *ops,
381 u32 op_count);
382
383
384int exec_regops_gk20a(struct dbg_session_gk20a *dbg_s,
385 struct nvgpu_dbg_gpu_reg_op *ops,
386 u64 num_ops)
387{
388 int err = 0;
389 unsigned int i;
390 struct channel_gk20a *ch = NULL;
391 struct gk20a *g = dbg_s->g;
392 /*struct gr_gk20a *gr = &g->gr;*/
393 u32 data32_lo = 0, data32_hi = 0;
394 u32 ctx_rd_count = 0, ctx_wr_count = 0;
395 bool skip_read_lo, skip_read_hi;
396 bool ok;
397
398 gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
399
400 ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
401
402 /* For vgpu, the regops routines need to be handled in the
403 * context of the server and support for that does not exist.
404 *
405 * The two users of the regops interface are the compute driver
406 * and tools. The compute driver will work without a functional
407 * regops implementation, so we return -ENOSYS. This will allow
408 * compute apps to run with vgpu. Tools will not work in this
409 * configuration and are not required to work at this time. */
410 if (g->is_virtual)
411 return -ENOSYS;
412
413 ok = validate_reg_ops(dbg_s,
414 &ctx_rd_count, &ctx_wr_count,
415 ops, num_ops);
416
417 if (!ok) {
418 nvgpu_err(g, "invalid op(s)");
419 err = -EINVAL;
420 /* each op has its own err/status */
421 goto clean_up;
422 }
423
424 for (i = 0; i < num_ops; i++) {
425 /* if it isn't global then it is done in the ctx ops... */
426 if (ops[i].type != REGOP(TYPE_GLOBAL))
427 continue;
428
429 switch (ops[i].op) {
430
431 case REGOP(READ_32):
432 ops[i].value_hi = 0;
433 ops[i].value_lo = gk20a_readl(g, ops[i].offset);
434 gk20a_dbg(gpu_dbg_gpu_dbg, "read_32 0x%08x from 0x%08x",
435 ops[i].value_lo, ops[i].offset);
436
437 break;
438
439 case REGOP(READ_64):
440 ops[i].value_lo = gk20a_readl(g, ops[i].offset);
441 ops[i].value_hi =
442 gk20a_readl(g, ops[i].offset + 4);
443
444 gk20a_dbg(gpu_dbg_gpu_dbg, "read_64 0x%08x:%08x from 0x%08x",
445 ops[i].value_hi, ops[i].value_lo,
446 ops[i].offset);
447 break;
448
449 case REGOP(WRITE_32):
450 case REGOP(WRITE_64):
451 /* some of this appears wonky/unnecessary but
452 we've kept it for compat with existing
453 debugger code. just in case... */
454 skip_read_lo = skip_read_hi = false;
455 if (ops[i].and_n_mask_lo == ~(u32)0) {
456 data32_lo = ops[i].value_lo;
457 skip_read_lo = true;
458 }
459
460 if ((ops[i].op == REGOP(WRITE_64)) &&
461 (ops[i].and_n_mask_hi == ~(u32)0)) {
462 data32_hi = ops[i].value_hi;
463 skip_read_hi = true;
464 }
465
466 /* read first 32bits */
467 if (unlikely(skip_read_lo == false)) {
468 data32_lo = gk20a_readl(g, ops[i].offset);
469 data32_lo &= ~ops[i].and_n_mask_lo;
470 data32_lo |= ops[i].value_lo;
471 }
472
473 /* if desired, read second 32bits */
474 if ((ops[i].op == REGOP(WRITE_64)) &&
475 !skip_read_hi) {
476 data32_hi = gk20a_readl(g, ops[i].offset + 4);
477 data32_hi &= ~ops[i].and_n_mask_hi;
478 data32_hi |= ops[i].value_hi;
479 }
480
481 /* now update first 32bits */
482 gk20a_writel(g, ops[i].offset, data32_lo);
483 gk20a_dbg(gpu_dbg_gpu_dbg, "Wrote 0x%08x to 0x%08x ",
484 data32_lo, ops[i].offset);
485 /* if desired, update second 32bits */
486 if (ops[i].op == REGOP(WRITE_64)) {
487 gk20a_writel(g, ops[i].offset + 4, data32_hi);
488 gk20a_dbg(gpu_dbg_gpu_dbg, "Wrote 0x%08x to 0x%08x ",
489 data32_hi, ops[i].offset + 4);
490
491 }
492
493
494 break;
495
496 /* shouldn't happen as we've already screened */
497 default:
498 BUG();
499 err = -EINVAL;
500 goto clean_up;
501 break;
502 }
503 }
504
505 if (ctx_wr_count | ctx_rd_count) {
506 err = gr_gk20a_exec_ctx_ops(ch, ops, num_ops,
507 ctx_wr_count, ctx_rd_count);
508 if (err) {
509 nvgpu_warn(g, "failed to perform ctx ops\n");
510 goto clean_up;
511 }
512 }
513
514 clean_up:
515 gk20a_dbg(gpu_dbg_gpu_dbg, "ret=%d", err);
516 return err;
517
518}
519
520
521static int validate_reg_op_info(struct dbg_session_gk20a *dbg_s,
522 struct nvgpu_dbg_gpu_reg_op *op)
523{
524 int err = 0;
525
526 op->status = REGOP(STATUS_SUCCESS);
527
528 switch (op->op) {
529 case REGOP(READ_32):
530 case REGOP(READ_64):
531 case REGOP(WRITE_32):
532 case REGOP(WRITE_64):
533 break;
534 default:
535 op->status |= REGOP(STATUS_UNSUPPORTED_OP);
536 err = -EINVAL;
537 break;
538 }
539
540 switch (op->type) {
541 case REGOP(TYPE_GLOBAL):
542 case REGOP(TYPE_GR_CTX):
543 case REGOP(TYPE_GR_CTX_TPC):
544 case REGOP(TYPE_GR_CTX_SM):
545 case REGOP(TYPE_GR_CTX_CROP):
546 case REGOP(TYPE_GR_CTX_ZROP):
547 case REGOP(TYPE_GR_CTX_QUAD):
548 break;
549 /*
550 case NVGPU_DBG_GPU_REG_OP_TYPE_FB:
551 */
552 default:
553 op->status |= REGOP(STATUS_INVALID_TYPE);
554 err = -EINVAL;
555 break;
556 }
557
558 return err;
559}
560
561static bool check_whitelists(struct dbg_session_gk20a *dbg_s,
562 struct nvgpu_dbg_gpu_reg_op *op, u32 offset)
563{
564 struct gk20a *g = dbg_s->g;
565 bool valid = false;
566 struct channel_gk20a *ch;
567
568 ch = nvgpu_dbg_gpu_get_session_channel(dbg_s);
569
570 if (op->type == REGOP(TYPE_GLOBAL)) {
571 /* search global list */
572 valid = g->ops.regops.get_global_whitelist_ranges &&
573 !!bsearch(&offset,
574 g->ops.regops.get_global_whitelist_ranges(),
575 g->ops.regops.get_global_whitelist_ranges_count(),
576 sizeof(*g->ops.regops.get_global_whitelist_ranges()),
577 regop_bsearch_range_cmp);
578
579 /* if debug session and channel is bound search context list */
580 if ((!valid) && (!dbg_s->is_profiler && ch)) {
581 /* binary search context list */
582 valid = g->ops.regops.get_context_whitelist_ranges &&
583 !!bsearch(&offset,
584 g->ops.regops.get_context_whitelist_ranges(),
585 g->ops.regops.get_context_whitelist_ranges_count(),
586 sizeof(*g->ops.regops.get_context_whitelist_ranges()),
587 regop_bsearch_range_cmp);
588 }
589
590 /* if debug session and channel is bound search runcontrol list */
591 if ((!valid) && (!dbg_s->is_profiler && ch)) {
592 valid = g->ops.regops.get_runcontrol_whitelist &&
593 linear_search(offset,
594 g->ops.regops.get_runcontrol_whitelist(),
595 g->ops.regops.get_runcontrol_whitelist_count());
596 }
597 } else if (op->type == REGOP(TYPE_GR_CTX)) {
598 /* it's a context-relative op */
599 if (!ch) {
600 nvgpu_err(dbg_s->g, "can't perform ctx regop unless bound");
601 op->status = REGOP(STATUS_UNSUPPORTED_OP);
602 return valid;
603 }
604
605 /* binary search context list */
606 valid = g->ops.regops.get_context_whitelist_ranges &&
607 !!bsearch(&offset,
608 g->ops.regops.get_context_whitelist_ranges(),
609 g->ops.regops.get_context_whitelist_ranges_count(),
610 sizeof(*g->ops.regops.get_context_whitelist_ranges()),
611 regop_bsearch_range_cmp);
612
613 /* if debug session and channel is bound search runcontrol list */
614 if ((!valid) && (!dbg_s->is_profiler && ch)) {
615 valid = g->ops.regops.get_runcontrol_whitelist &&
616 linear_search(offset,
617 g->ops.regops.get_runcontrol_whitelist(),
618 g->ops.regops.get_runcontrol_whitelist_count());
619 }
620
621 } else if (op->type == REGOP(TYPE_GR_CTX_QUAD)) {
622 valid = g->ops.regops.get_qctl_whitelist &&
623 linear_search(offset,
624 g->ops.regops.get_qctl_whitelist(),
625 g->ops.regops.get_qctl_whitelist_count());
626 }
627
628 return valid;
629}
630
631/* note: the op here has already been through validate_reg_op_info */
632static int validate_reg_op_offset(struct dbg_session_gk20a *dbg_s,
633 struct nvgpu_dbg_gpu_reg_op *op)
634{
635 int err;
636 u32 buf_offset_lo, buf_offset_addr, num_offsets, offset;
637 bool valid = false;
638
639 op->status = 0;
640 offset = op->offset;
641
642 /* support only 24-bit 4-byte aligned offsets */
643 if (offset & 0xFF000003) {
644 nvgpu_err(dbg_s->g, "invalid regop offset: 0x%x", offset);
645 op->status |= REGOP(STATUS_INVALID_OFFSET);
646 return -EINVAL;
647 }
648
649 valid = check_whitelists(dbg_s, op, offset);
650 if ((op->op == REGOP(READ_64) || op->op == REGOP(WRITE_64)) && valid)
651 valid = check_whitelists(dbg_s, op, offset + 4);
652
653 if (valid && (op->type != REGOP(TYPE_GLOBAL))) {
654 err = gr_gk20a_get_ctx_buffer_offsets(dbg_s->g,
655 op->offset,
656 1,
657 &buf_offset_lo,
658 &buf_offset_addr,
659 &num_offsets,
660 op->type == REGOP(TYPE_GR_CTX_QUAD),
661 op->quad);
662 if (err) {
663 err = gr_gk20a_get_pm_ctx_buffer_offsets(dbg_s->g,
664 op->offset,
665 1,
666 &buf_offset_lo,
667 &buf_offset_addr,
668 &num_offsets);
669
670 if (err) {
671 op->status |= REGOP(STATUS_INVALID_OFFSET);
672 return -EINVAL;
673 }
674 }
675 if (!num_offsets) {
676 op->status |= REGOP(STATUS_INVALID_OFFSET);
677 return -EINVAL;
678 }
679 }
680
681 if (!valid) {
682 nvgpu_err(dbg_s->g, "invalid regop offset: 0x%x", offset);
683 op->status |= REGOP(STATUS_INVALID_OFFSET);
684 return -EINVAL;
685 }
686
687 return 0;
688}
689
690static bool validate_reg_ops(struct dbg_session_gk20a *dbg_s,
691 u32 *ctx_rd_count, u32 *ctx_wr_count,
692 struct nvgpu_dbg_gpu_reg_op *ops,
693 u32 op_count)
694{
695 u32 i;
696 int err;
697 bool ok = true;
698 struct gk20a *g = dbg_s->g;
699
700 /* keep going until the end so every op can get
701 * a separate error code if needed */
702 for (i = 0; i < op_count; i++) {
703
704 err = validate_reg_op_info(dbg_s, &ops[i]);
705 ok &= !err;
706
707 if (reg_op_is_gr_ctx(ops[i].type)) {
708 if (reg_op_is_read(ops[i].op))
709 (*ctx_rd_count)++;
710 else
711 (*ctx_wr_count)++;
712 }
713
714 /* if "allow_all" flag enabled, dont validate offset */
715 if (!g->allow_all) {
716 err = validate_reg_op_offset(dbg_s, &ops[i]);
717 ok &= !err;
718 }
719 }
720
721 gk20a_dbg(gpu_dbg_gpu_dbg, "ctx_wrs:%d ctx_rds:%d",
722 *ctx_wr_count, *ctx_rd_count);
723
724 return ok;
725}
726
727/* exported for tools like cyclestats, etc */
728bool is_bar0_global_offset_whitelisted_gk20a(struct gk20a *g, u32 offset)
729{
730 bool valid = !!bsearch(&offset,
731 g->ops.regops.get_global_whitelist_ranges(),
732 g->ops.regops.get_global_whitelist_ranges_count(),
733 sizeof(*g->ops.regops.get_global_whitelist_ranges()),
734 regop_bsearch_range_cmp);
735 return valid;
736}