summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/pmu_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/pmu_gk20a.c830
1 files changed, 830 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
new file mode 100644
index 00000000..d8478b2d
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
@@ -0,0 +1,830 @@
1/*
2 * GK20A PMU (aka. gPMU outside gk20a context)
3 *
4 * Copyright (c) 2011-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 <uapi/linux/nvgpu.h>
26
27#include <nvgpu/nvgpu_common.h>
28#include <nvgpu/timers.h>
29#include <nvgpu/kmem.h>
30#include <nvgpu/dma.h>
31#include <nvgpu/log.h>
32#include <nvgpu/bug.h>
33#include <nvgpu/firmware.h>
34#include <nvgpu/falcon.h>
35#include <nvgpu/mm.h>
36
37#include "gk20a.h"
38#include "gr_gk20a.h"
39
40#include <nvgpu/hw/gk20a/hw_mc_gk20a.h>
41#include <nvgpu/hw/gk20a/hw_pwr_gk20a.h>
42#include <nvgpu/hw/gk20a/hw_top_gk20a.h>
43
44#ifdef CONFIG_TEGRA_19x_GPU
45#include "nvgpu_gpuid_t19x.h"
46#endif
47
48#define gk20a_dbg_pmu(fmt, arg...) \
49 gk20a_dbg(gpu_dbg_pmu, fmt, ##arg)
50
51bool nvgpu_find_hex_in_string(char *strings, struct gk20a *g, u32 *hex_pos)
52{
53 u32 i = 0, j = strlen(strings);
54
55 for (; i < j; i++) {
56 if (strings[i] == '%')
57 if (strings[i + 1] == 'x' || strings[i + 1] == 'X') {
58 *hex_pos = i;
59 return true;
60 }
61 }
62 *hex_pos = -1;
63 return false;
64}
65
66static void print_pmu_trace(struct nvgpu_pmu *pmu)
67{
68 struct gk20a *g = pmu->g;
69 u32 i = 0, j = 0, k, l, m, count;
70 char part_str[40], buf[0x40];
71 void *tracebuffer;
72 char *trace;
73 u32 *trace1;
74
75 /* allocate system memory to copy pmu trace buffer */
76 tracebuffer = nvgpu_kzalloc(g, GK20A_PMU_TRACE_BUFSIZE);
77 if (tracebuffer == NULL)
78 return;
79
80 /* read pmu traces into system memory buffer */
81 nvgpu_mem_rd_n(g, &pmu->trace_buf, 0, tracebuffer,
82 GK20A_PMU_TRACE_BUFSIZE);
83
84 trace = (char *)tracebuffer;
85 trace1 = (u32 *)tracebuffer;
86
87 nvgpu_err(g, "dump PMU trace buffer");
88 for (i = 0; i < GK20A_PMU_TRACE_BUFSIZE; i += 0x40) {
89 for (j = 0; j < 0x40; j++)
90 if (trace1[(i / 4) + j])
91 break;
92 if (j == 0x40)
93 break;
94 count = scnprintf(buf, 0x40, "Index %x: ", trace1[(i / 4)]);
95 l = 0;
96 m = 0;
97 while (nvgpu_find_hex_in_string((trace+i+20+m), g, &k)) {
98 if (k >= 40)
99 break;
100 strncpy(part_str, (trace+i+20+m), k);
101 part_str[k] = 0;
102 count += scnprintf((buf + count), 0x40, "%s0x%x",
103 part_str, trace1[(i / 4) + 1 + l]);
104 l++;
105 m += k + 2;
106 }
107
108 scnprintf((buf + count), 0x40, "%s", (trace+i+20+m));
109 nvgpu_err(g, "%s", buf);
110 }
111
112 nvgpu_kfree(g, tracebuffer);
113}
114
115void pmu_enable_irq(struct nvgpu_pmu *pmu, bool enable)
116{
117 struct gk20a *g = gk20a_from_pmu(pmu);
118 u32 intr_mask;
119 u32 intr_dest;
120
121 gk20a_dbg_fn("");
122
123 g->ops.mc.intr_unit_config(g, MC_INTR_UNIT_DISABLE, true,
124 mc_intr_mask_0_pmu_enabled_f());
125 g->ops.mc.intr_unit_config(g, MC_INTR_UNIT_DISABLE, false,
126 mc_intr_mask_1_pmu_enabled_f());
127
128 nvgpu_flcn_set_irq(pmu->flcn, false, 0x0, 0x0);
129
130 if (enable) {
131 /* dest 0=falcon, 1=host; level 0=irq0, 1=irq1 */
132 intr_dest = pwr_falcon_irqdest_host_gptmr_f(0) |
133 pwr_falcon_irqdest_host_wdtmr_f(1) |
134 pwr_falcon_irqdest_host_mthd_f(0) |
135 pwr_falcon_irqdest_host_ctxsw_f(0) |
136 pwr_falcon_irqdest_host_halt_f(1) |
137 pwr_falcon_irqdest_host_exterr_f(0) |
138 pwr_falcon_irqdest_host_swgen0_f(1) |
139 pwr_falcon_irqdest_host_swgen1_f(0) |
140 pwr_falcon_irqdest_host_ext_f(0xff) |
141 pwr_falcon_irqdest_target_gptmr_f(1) |
142 pwr_falcon_irqdest_target_wdtmr_f(0) |
143 pwr_falcon_irqdest_target_mthd_f(0) |
144 pwr_falcon_irqdest_target_ctxsw_f(0) |
145 pwr_falcon_irqdest_target_halt_f(0) |
146 pwr_falcon_irqdest_target_exterr_f(0) |
147 pwr_falcon_irqdest_target_swgen0_f(0) |
148 pwr_falcon_irqdest_target_swgen1_f(0) |
149 pwr_falcon_irqdest_target_ext_f(0xff);
150
151 /* 0=disable, 1=enable */
152 intr_mask = pwr_falcon_irqmset_gptmr_f(1) |
153 pwr_falcon_irqmset_wdtmr_f(1) |
154 pwr_falcon_irqmset_mthd_f(0) |
155 pwr_falcon_irqmset_ctxsw_f(0) |
156 pwr_falcon_irqmset_halt_f(1) |
157 pwr_falcon_irqmset_exterr_f(1) |
158 pwr_falcon_irqmset_swgen0_f(1) |
159 pwr_falcon_irqmset_swgen1_f(1);
160
161 nvgpu_flcn_set_irq(pmu->flcn, true, intr_mask, intr_dest);
162
163 g->ops.mc.intr_unit_config(g, MC_INTR_UNIT_ENABLE, true,
164 mc_intr_mask_0_pmu_enabled_f());
165 }
166
167 gk20a_dbg_fn("done");
168}
169
170
171
172int pmu_bootstrap(struct nvgpu_pmu *pmu)
173{
174 struct gk20a *g = gk20a_from_pmu(pmu);
175 struct mm_gk20a *mm = &g->mm;
176 struct pmu_ucode_desc *desc = pmu->desc;
177 u64 addr_code, addr_data, addr_load;
178 u32 i, blocks, addr_args;
179
180 gk20a_dbg_fn("");
181
182 gk20a_writel(g, pwr_falcon_itfen_r(),
183 gk20a_readl(g, pwr_falcon_itfen_r()) |
184 pwr_falcon_itfen_ctxen_enable_f());
185 gk20a_writel(g, pwr_pmu_new_instblk_r(),
186 pwr_pmu_new_instblk_ptr_f(
187 nvgpu_inst_block_addr(g, &mm->pmu.inst_block) >> 12) |
188 pwr_pmu_new_instblk_valid_f(1) |
189 pwr_pmu_new_instblk_target_sys_coh_f());
190
191 /* TBD: load all other surfaces */
192 g->ops.pmu_ver.set_pmu_cmdline_args_trace_size(
193 pmu, GK20A_PMU_TRACE_BUFSIZE);
194 g->ops.pmu_ver.set_pmu_cmdline_args_trace_dma_base(pmu);
195 g->ops.pmu_ver.set_pmu_cmdline_args_trace_dma_idx(
196 pmu, GK20A_PMU_DMAIDX_VIRT);
197
198 g->ops.pmu_ver.set_pmu_cmdline_args_cpu_freq(pmu,
199 g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_PWRCLK));
200
201 addr_args = (pwr_falcon_hwcfg_dmem_size_v(
202 gk20a_readl(g, pwr_falcon_hwcfg_r()))
203 << GK20A_PMU_DMEM_BLKSIZE2) -
204 g->ops.pmu_ver.get_pmu_cmdline_args_size(pmu);
205
206 nvgpu_flcn_copy_to_dmem(pmu->flcn, addr_args,
207 (u8 *)(g->ops.pmu_ver.get_pmu_cmdline_args_ptr(pmu)),
208 g->ops.pmu_ver.get_pmu_cmdline_args_size(pmu), 0);
209
210 gk20a_writel(g, pwr_falcon_dmemc_r(0),
211 pwr_falcon_dmemc_offs_f(0) |
212 pwr_falcon_dmemc_blk_f(0) |
213 pwr_falcon_dmemc_aincw_f(1));
214
215 addr_code = u64_lo32((pmu->ucode.gpu_va +
216 desc->app_start_offset +
217 desc->app_resident_code_offset) >> 8) ;
218 addr_data = u64_lo32((pmu->ucode.gpu_va +
219 desc->app_start_offset +
220 desc->app_resident_data_offset) >> 8);
221 addr_load = u64_lo32((pmu->ucode.gpu_va +
222 desc->bootloader_start_offset) >> 8);
223
224 gk20a_writel(g, pwr_falcon_dmemd_r(0), GK20A_PMU_DMAIDX_UCODE);
225 gk20a_writel(g, pwr_falcon_dmemd_r(0), addr_code);
226 gk20a_writel(g, pwr_falcon_dmemd_r(0), desc->app_size);
227 gk20a_writel(g, pwr_falcon_dmemd_r(0), desc->app_resident_code_size);
228 gk20a_writel(g, pwr_falcon_dmemd_r(0), desc->app_imem_entry);
229 gk20a_writel(g, pwr_falcon_dmemd_r(0), addr_data);
230 gk20a_writel(g, pwr_falcon_dmemd_r(0), desc->app_resident_data_size);
231 gk20a_writel(g, pwr_falcon_dmemd_r(0), addr_code);
232 gk20a_writel(g, pwr_falcon_dmemd_r(0), 0x1);
233 gk20a_writel(g, pwr_falcon_dmemd_r(0), addr_args);
234
235 g->ops.pmu.write_dmatrfbase(g,
236 addr_load - (desc->bootloader_imem_offset >> 8));
237
238 blocks = ((desc->bootloader_size + 0xFF) & ~0xFF) >> 8;
239
240 for (i = 0; i < blocks; i++) {
241 gk20a_writel(g, pwr_falcon_dmatrfmoffs_r(),
242 desc->bootloader_imem_offset + (i << 8));
243 gk20a_writel(g, pwr_falcon_dmatrffboffs_r(),
244 desc->bootloader_imem_offset + (i << 8));
245 gk20a_writel(g, pwr_falcon_dmatrfcmd_r(),
246 pwr_falcon_dmatrfcmd_imem_f(1) |
247 pwr_falcon_dmatrfcmd_write_f(0) |
248 pwr_falcon_dmatrfcmd_size_f(6) |
249 pwr_falcon_dmatrfcmd_ctxdma_f(GK20A_PMU_DMAIDX_UCODE));
250 }
251
252 nvgpu_flcn_bootstrap(g->pmu.flcn, desc->bootloader_entry_point);
253
254 gk20a_writel(g, pwr_falcon_os_r(), desc->app_version);
255
256 return 0;
257}
258
259void gk20a_pmu_pg_idle_counter_config(struct gk20a *g, u32 pg_engine_id)
260{
261 gk20a_writel(g, pwr_pmu_pg_idlefilth_r(pg_engine_id),
262 PMU_PG_IDLE_THRESHOLD);
263 gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(pg_engine_id),
264 PMU_PG_POST_POWERUP_IDLE_THRESHOLD);
265}
266
267int gk20a_pmu_mutex_acquire(struct nvgpu_pmu *pmu, u32 id, u32 *token)
268{
269 struct gk20a *g = gk20a_from_pmu(pmu);
270 struct pmu_mutex *mutex;
271 u32 data, owner, max_retry;
272
273 if (!pmu->initialized)
274 return -EINVAL;
275
276 BUG_ON(!token);
277 BUG_ON(!PMU_MUTEX_ID_IS_VALID(id));
278 BUG_ON(id > pmu->mutex_cnt);
279
280 mutex = &pmu->mutex[id];
281
282 owner = pwr_pmu_mutex_value_v(
283 gk20a_readl(g, pwr_pmu_mutex_r(mutex->index)));
284
285 if (*token != PMU_INVALID_MUTEX_OWNER_ID && *token == owner) {
286 BUG_ON(mutex->ref_cnt == 0);
287 gk20a_dbg_pmu("already acquired by owner : 0x%08x", *token);
288 mutex->ref_cnt++;
289 return 0;
290 }
291
292 max_retry = 40;
293 do {
294 data = pwr_pmu_mutex_id_value_v(
295 gk20a_readl(g, pwr_pmu_mutex_id_r()));
296 if (data == pwr_pmu_mutex_id_value_init_v() ||
297 data == pwr_pmu_mutex_id_value_not_avail_v()) {
298 nvgpu_warn(g,
299 "fail to generate mutex token: val 0x%08x",
300 owner);
301 nvgpu_usleep_range(20, 40);
302 continue;
303 }
304
305 owner = data;
306 gk20a_writel(g, pwr_pmu_mutex_r(mutex->index),
307 pwr_pmu_mutex_value_f(owner));
308
309 data = pwr_pmu_mutex_value_v(
310 gk20a_readl(g, pwr_pmu_mutex_r(mutex->index)));
311
312 if (owner == data) {
313 mutex->ref_cnt = 1;
314 gk20a_dbg_pmu("mutex acquired: id=%d, token=0x%x",
315 mutex->index, *token);
316 *token = owner;
317 return 0;
318 } else {
319 gk20a_dbg_info("fail to acquire mutex idx=0x%08x",
320 mutex->index);
321
322 data = gk20a_readl(g, pwr_pmu_mutex_id_release_r());
323 data = set_field(data,
324 pwr_pmu_mutex_id_release_value_m(),
325 pwr_pmu_mutex_id_release_value_f(owner));
326 gk20a_writel(g, pwr_pmu_mutex_id_release_r(), data);
327
328 nvgpu_usleep_range(20, 40);
329 continue;
330 }
331 } while (max_retry-- > 0);
332
333 return -EBUSY;
334}
335
336int gk20a_pmu_mutex_release(struct nvgpu_pmu *pmu, u32 id, u32 *token)
337{
338 struct gk20a *g = gk20a_from_pmu(pmu);
339 struct pmu_mutex *mutex;
340 u32 owner, data;
341
342 if (!pmu->initialized)
343 return -EINVAL;
344
345 BUG_ON(!token);
346 BUG_ON(!PMU_MUTEX_ID_IS_VALID(id));
347 BUG_ON(id > pmu->mutex_cnt);
348
349 mutex = &pmu->mutex[id];
350
351 owner = pwr_pmu_mutex_value_v(
352 gk20a_readl(g, pwr_pmu_mutex_r(mutex->index)));
353
354 if (*token != owner) {
355 nvgpu_err(g, "requester 0x%08x NOT match owner 0x%08x",
356 *token, owner);
357 return -EINVAL;
358 }
359
360 if (--mutex->ref_cnt > 0)
361 return -EBUSY;
362
363 gk20a_writel(g, pwr_pmu_mutex_r(mutex->index),
364 pwr_pmu_mutex_value_initial_lock_f());
365
366 data = gk20a_readl(g, pwr_pmu_mutex_id_release_r());
367 data = set_field(data, pwr_pmu_mutex_id_release_value_m(),
368 pwr_pmu_mutex_id_release_value_f(owner));
369 gk20a_writel(g, pwr_pmu_mutex_id_release_r(), data);
370
371 gk20a_dbg_pmu("mutex released: id=%d, token=0x%x",
372 mutex->index, *token);
373
374 return 0;
375}
376
377int gk20a_pmu_queue_head(struct nvgpu_pmu *pmu, struct pmu_queue *queue,
378 u32 *head, bool set)
379{
380 struct gk20a *g = gk20a_from_pmu(pmu);
381 u32 queue_head_size = 0;
382
383 if (g->ops.pmu.pmu_get_queue_head_size)
384 queue_head_size = g->ops.pmu.pmu_get_queue_head_size();
385
386 BUG_ON(!head || !queue_head_size);
387
388 if (PMU_IS_COMMAND_QUEUE(queue->id)) {
389
390 if (queue->index >= queue_head_size)
391 return -EINVAL;
392
393 if (!set)
394 *head = pwr_pmu_queue_head_address_v(
395 gk20a_readl(g,
396 g->ops.pmu.pmu_get_queue_head(queue->index)));
397 else
398 gk20a_writel(g,
399 g->ops.pmu.pmu_get_queue_head(queue->index),
400 pwr_pmu_queue_head_address_f(*head));
401 } else {
402 if (!set)
403 *head = pwr_pmu_msgq_head_val_v(
404 gk20a_readl(g, pwr_pmu_msgq_head_r()));
405 else
406 gk20a_writel(g,
407 pwr_pmu_msgq_head_r(),
408 pwr_pmu_msgq_head_val_f(*head));
409 }
410
411 return 0;
412}
413
414int gk20a_pmu_queue_tail(struct nvgpu_pmu *pmu, struct pmu_queue *queue,
415 u32 *tail, bool set)
416{
417 struct gk20a *g = gk20a_from_pmu(pmu);
418 u32 queue_tail_size = 0;
419
420 if (g->ops.pmu.pmu_get_queue_tail_size)
421 queue_tail_size = g->ops.pmu.pmu_get_queue_tail_size();
422
423 BUG_ON(!tail || !queue_tail_size);
424
425 if (PMU_IS_COMMAND_QUEUE(queue->id)) {
426
427 if (queue->index >= queue_tail_size)
428 return -EINVAL;
429
430 if (!set)
431 *tail = pwr_pmu_queue_tail_address_v(
432 gk20a_readl(g,
433 g->ops.pmu.pmu_get_queue_tail(queue->index)));
434 else
435 gk20a_writel(g,
436 g->ops.pmu.pmu_get_queue_tail(queue->index),
437 pwr_pmu_queue_tail_address_f(*tail));
438
439 } else {
440 if (!set)
441 *tail = pwr_pmu_msgq_tail_val_v(
442 gk20a_readl(g, pwr_pmu_msgq_tail_r()));
443 else
444 gk20a_writel(g,
445 pwr_pmu_msgq_tail_r(),
446 pwr_pmu_msgq_tail_val_f(*tail));
447 }
448
449 return 0;
450}
451
452void gk20a_pmu_msgq_tail(struct nvgpu_pmu *pmu, u32 *tail, bool set)
453{
454 struct gk20a *g = gk20a_from_pmu(pmu);
455 u32 queue_tail_size = 0;
456
457 if (g->ops.pmu.pmu_get_queue_tail_size)
458 queue_tail_size = g->ops.pmu.pmu_get_queue_tail_size();
459
460 BUG_ON(!tail || !queue_tail_size);
461
462 if (!set)
463 *tail = pwr_pmu_msgq_tail_val_v(
464 gk20a_readl(g, pwr_pmu_msgq_tail_r()));
465 else
466 gk20a_writel(g,
467 pwr_pmu_msgq_tail_r(),
468 pwr_pmu_msgq_tail_val_f(*tail));
469}
470
471int gk20a_init_pmu_setup_hw1(struct gk20a *g)
472{
473 struct nvgpu_pmu *pmu = &g->pmu;
474 int err = 0;
475
476 gk20a_dbg_fn("");
477
478 nvgpu_mutex_acquire(&pmu->isr_mutex);
479 nvgpu_flcn_reset(pmu->flcn);
480 pmu->isr_enabled = true;
481 nvgpu_mutex_release(&pmu->isr_mutex);
482
483 /* setup apertures - virtual */
484 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_UCODE),
485 pwr_fbif_transcfg_mem_type_virtual_f());
486 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_VIRT),
487 pwr_fbif_transcfg_mem_type_virtual_f());
488 /* setup apertures - physical */
489 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_VID),
490 pwr_fbif_transcfg_mem_type_physical_f() |
491 pwr_fbif_transcfg_target_local_fb_f());
492 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_COH),
493 pwr_fbif_transcfg_mem_type_physical_f() |
494 pwr_fbif_transcfg_target_coherent_sysmem_f());
495 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_NCOH),
496 pwr_fbif_transcfg_mem_type_physical_f() |
497 pwr_fbif_transcfg_target_noncoherent_sysmem_f());
498
499 err = g->ops.pmu.pmu_nsbootstrap(pmu);
500
501 return err;
502
503}
504
505void gk20a_write_dmatrfbase(struct gk20a *g, u32 addr)
506{
507 gk20a_writel(g, pwr_falcon_dmatrfbase_r(), addr);
508}
509
510bool gk20a_pmu_is_engine_in_reset(struct gk20a *g)
511{
512 u32 pmc_enable;
513 bool status = false;
514
515 pmc_enable = gk20a_readl(g, mc_enable_r());
516 if (mc_enable_pwr_v(pmc_enable) ==
517 mc_enable_pwr_disabled_v())
518 status = true;
519
520 return status;
521}
522
523int gk20a_pmu_engine_reset(struct gk20a *g, bool do_reset)
524{
525 if (do_reset)
526 g->ops.mc.enable(g, mc_enable_pwr_enabled_f());
527 else
528 g->ops.mc.disable(g, mc_enable_pwr_enabled_f());
529
530 return 0;
531}
532
533bool gk20a_is_pmu_supported(struct gk20a *g)
534{
535 return true;
536}
537
538u32 gk20a_pmu_pg_engines_list(struct gk20a *g)
539{
540 return BIT(PMU_PG_ELPG_ENGINE_ID_GRAPHICS);
541}
542
543u32 gk20a_pmu_pg_feature_list(struct gk20a *g, u32 pg_engine_id)
544{
545 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
546 return PMU_PG_FEATURE_GR_POWER_GATING_ENABLED;
547
548 return 0;
549}
550
551static void pmu_handle_zbc_msg(struct gk20a *g, struct pmu_msg *msg,
552 void *param, u32 handle, u32 status)
553{
554 struct nvgpu_pmu *pmu = param;
555 gk20a_dbg_pmu("reply ZBC_TABLE_UPDATE");
556 pmu->zbc_save_done = 1;
557}
558
559void gk20a_pmu_save_zbc(struct gk20a *g, u32 entries)
560{
561 struct nvgpu_pmu *pmu = &g->pmu;
562 struct pmu_cmd cmd;
563 u32 seq;
564
565 if (!pmu->pmu_ready || !entries || !pmu->zbc_ready)
566 return;
567
568 memset(&cmd, 0, sizeof(struct pmu_cmd));
569 cmd.hdr.unit_id = PMU_UNIT_PG;
570 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_zbc_cmd);
571 cmd.cmd.zbc.cmd_type = g->pmu_ver_cmd_id_zbc_table_update;
572 cmd.cmd.zbc.entry_mask = ZBC_MASK(entries);
573
574 pmu->zbc_save_done = 0;
575
576 gk20a_dbg_pmu("cmd post ZBC_TABLE_UPDATE");
577 nvgpu_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
578 pmu_handle_zbc_msg, pmu, &seq, ~0);
579 pmu_wait_message_cond(pmu, gk20a_get_gr_idle_timeout(g),
580 &pmu->zbc_save_done, 1);
581 if (!pmu->zbc_save_done)
582 nvgpu_err(g, "ZBC save timeout");
583}
584
585int nvgpu_pmu_handle_therm_event(struct nvgpu_pmu *pmu,
586 struct nv_pmu_therm_msg *msg)
587{
588 gk20a_dbg_fn("");
589
590 switch (msg->msg_type) {
591 case NV_PMU_THERM_MSG_ID_EVENT_HW_SLOWDOWN_NOTIFICATION:
592#ifdef CONFIG_ARCH_TEGRA_18x_SOC
593 if (msg->hw_slct_msg.mask == BIT(NV_PMU_THERM_EVENT_THERMAL_1))
594 nvgpu_clk_arb_schedule_alarm(gk20a_from_pmu(pmu),
595 (0x1UL << NVGPU_GPU_EVENT_ALARM_THERMAL_ABOVE_THRESHOLD));
596 else
597#endif
598 gk20a_dbg_pmu("Unwanted/Unregistered thermal event received %d",
599 msg->hw_slct_msg.mask);
600 break;
601 default:
602 gk20a_dbg_pmu("unkown therm event received %d", msg->msg_type);
603 break;
604 }
605
606 return 0;
607}
608
609void gk20a_pmu_dump_elpg_stats(struct nvgpu_pmu *pmu)
610{
611 struct gk20a *g = gk20a_from_pmu(pmu);
612
613 gk20a_dbg_pmu("pwr_pmu_idle_mask_supp_r(3): 0x%08x",
614 gk20a_readl(g, pwr_pmu_idle_mask_supp_r(3)));
615 gk20a_dbg_pmu("pwr_pmu_idle_mask_1_supp_r(3): 0x%08x",
616 gk20a_readl(g, pwr_pmu_idle_mask_1_supp_r(3)));
617 gk20a_dbg_pmu("pwr_pmu_idle_ctrl_supp_r(3): 0x%08x",
618 gk20a_readl(g, pwr_pmu_idle_ctrl_supp_r(3)));
619 gk20a_dbg_pmu("pwr_pmu_pg_idle_cnt_r(0): 0x%08x",
620 gk20a_readl(g, pwr_pmu_pg_idle_cnt_r(0)));
621 gk20a_dbg_pmu("pwr_pmu_pg_intren_r(0): 0x%08x",
622 gk20a_readl(g, pwr_pmu_pg_intren_r(0)));
623
624 gk20a_dbg_pmu("pwr_pmu_idle_count_r(3): 0x%08x",
625 gk20a_readl(g, pwr_pmu_idle_count_r(3)));
626 gk20a_dbg_pmu("pwr_pmu_idle_count_r(4): 0x%08x",
627 gk20a_readl(g, pwr_pmu_idle_count_r(4)));
628 gk20a_dbg_pmu("pwr_pmu_idle_count_r(7): 0x%08x",
629 gk20a_readl(g, pwr_pmu_idle_count_r(7)));
630}
631
632void gk20a_pmu_dump_falcon_stats(struct nvgpu_pmu *pmu)
633{
634 struct gk20a *g = gk20a_from_pmu(pmu);
635 unsigned int i;
636
637 for (i = 0; i < pwr_pmu_mailbox__size_1_v(); i++)
638 nvgpu_err(g, "pwr_pmu_mailbox_r(%d) : 0x%x",
639 i, gk20a_readl(g, pwr_pmu_mailbox_r(i)));
640
641 for (i = 0; i < pwr_pmu_debug__size_1_v(); i++)
642 nvgpu_err(g, "pwr_pmu_debug_r(%d) : 0x%x",
643 i, gk20a_readl(g, pwr_pmu_debug_r(i)));
644
645 i = gk20a_readl(g, pwr_pmu_bar0_error_status_r());
646 nvgpu_err(g, "pwr_pmu_bar0_error_status_r : 0x%x", i);
647 if (i != 0) {
648 nvgpu_err(g, "pwr_pmu_bar0_addr_r : 0x%x",
649 gk20a_readl(g, pwr_pmu_bar0_addr_r()));
650 nvgpu_err(g, "pwr_pmu_bar0_data_r : 0x%x",
651 gk20a_readl(g, pwr_pmu_bar0_data_r()));
652 nvgpu_err(g, "pwr_pmu_bar0_timeout_r : 0x%x",
653 gk20a_readl(g, pwr_pmu_bar0_timeout_r()));
654 nvgpu_err(g, "pwr_pmu_bar0_ctl_r : 0x%x",
655 gk20a_readl(g, pwr_pmu_bar0_ctl_r()));
656 }
657
658 i = gk20a_readl(g, pwr_pmu_bar0_fecs_error_r());
659 nvgpu_err(g, "pwr_pmu_bar0_fecs_error_r : 0x%x", i);
660
661 i = gk20a_readl(g, pwr_falcon_exterrstat_r());
662 nvgpu_err(g, "pwr_falcon_exterrstat_r : 0x%x", i);
663 if (pwr_falcon_exterrstat_valid_v(i) ==
664 pwr_falcon_exterrstat_valid_true_v()) {
665 nvgpu_err(g, "pwr_falcon_exterraddr_r : 0x%x",
666 gk20a_readl(g, pwr_falcon_exterraddr_r()));
667 nvgpu_err(g, "pmc_enable : 0x%x",
668 gk20a_readl(g, mc_enable_r()));
669 }
670
671 /* Print PMU F/W debug prints */
672 print_pmu_trace(pmu);
673}
674
675bool gk20a_pmu_is_interrupted(struct nvgpu_pmu *pmu)
676{
677 struct gk20a *g = gk20a_from_pmu(pmu);
678 u32 servicedpmuint;
679
680 servicedpmuint = pwr_falcon_irqstat_halt_true_f() |
681 pwr_falcon_irqstat_exterr_true_f() |
682 pwr_falcon_irqstat_swgen0_true_f();
683
684 if (gk20a_readl(g, pwr_falcon_irqstat_r()) & servicedpmuint)
685 return true;
686
687 return false;
688}
689
690void gk20a_pmu_isr(struct gk20a *g)
691{
692 struct nvgpu_pmu *pmu = &g->pmu;
693 struct pmu_queue *queue;
694 u32 intr, mask;
695 bool recheck = false;
696
697 gk20a_dbg_fn("");
698
699 nvgpu_mutex_acquire(&pmu->isr_mutex);
700 if (!pmu->isr_enabled) {
701 nvgpu_mutex_release(&pmu->isr_mutex);
702 return;
703 }
704
705 mask = gk20a_readl(g, pwr_falcon_irqmask_r()) &
706 gk20a_readl(g, pwr_falcon_irqdest_r());
707
708 intr = gk20a_readl(g, pwr_falcon_irqstat_r());
709
710 gk20a_dbg_pmu("received falcon interrupt: 0x%08x", intr);
711
712 intr = gk20a_readl(g, pwr_falcon_irqstat_r()) & mask;
713 if (!intr || pmu->pmu_state == PMU_STATE_OFF) {
714 gk20a_writel(g, pwr_falcon_irqsclr_r(), intr);
715 nvgpu_mutex_release(&pmu->isr_mutex);
716 return;
717 }
718
719 if (intr & pwr_falcon_irqstat_halt_true_f()) {
720 nvgpu_err(g, "pmu halt intr not implemented");
721 nvgpu_pmu_dump_falcon_stats(pmu);
722 if (gk20a_readl(g, pwr_pmu_mailbox_r
723 (PMU_MODE_MISMATCH_STATUS_MAILBOX_R)) ==
724 PMU_MODE_MISMATCH_STATUS_VAL)
725 if (g->ops.pmu.dump_secure_fuses)
726 g->ops.pmu.dump_secure_fuses(g);
727 }
728 if (intr & pwr_falcon_irqstat_exterr_true_f()) {
729 nvgpu_err(g,
730 "pmu exterr intr not implemented. Clearing interrupt.");
731 nvgpu_pmu_dump_falcon_stats(pmu);
732
733 gk20a_writel(g, pwr_falcon_exterrstat_r(),
734 gk20a_readl(g, pwr_falcon_exterrstat_r()) &
735 ~pwr_falcon_exterrstat_valid_m());
736 }
737 if (intr & pwr_falcon_irqstat_swgen0_true_f()) {
738 nvgpu_pmu_process_message(pmu);
739 recheck = true;
740 }
741
742 gk20a_writel(g, pwr_falcon_irqsclr_r(), intr);
743
744 if (recheck) {
745 queue = &pmu->queue[PMU_MESSAGE_QUEUE];
746 if (!nvgpu_pmu_queue_is_empty(pmu, queue))
747 gk20a_writel(g, pwr_falcon_irqsset_r(),
748 pwr_falcon_irqsset_swgen0_set_f());
749 }
750
751 nvgpu_mutex_release(&pmu->isr_mutex);
752}
753
754void gk20a_pmu_init_perfmon_counter(struct gk20a *g)
755{
756 u32 data;
757
758 /* use counter #3 for GR && CE2 busy cycles */
759 gk20a_writel(g, pwr_pmu_idle_mask_r(3),
760 pwr_pmu_idle_mask_gr_enabled_f() |
761 pwr_pmu_idle_mask_ce_2_enabled_f());
762
763 /* disable idle filtering for counters 3 and 6 */
764 data = gk20a_readl(g, pwr_pmu_idle_ctrl_r(3));
765 data = set_field(data, pwr_pmu_idle_ctrl_value_m() |
766 pwr_pmu_idle_ctrl_filter_m(),
767 pwr_pmu_idle_ctrl_value_busy_f() |
768 pwr_pmu_idle_ctrl_filter_disabled_f());
769 gk20a_writel(g, pwr_pmu_idle_ctrl_r(3), data);
770
771 /* use counter #6 for total cycles */
772 data = gk20a_readl(g, pwr_pmu_idle_ctrl_r(6));
773 data = set_field(data, pwr_pmu_idle_ctrl_value_m() |
774 pwr_pmu_idle_ctrl_filter_m(),
775 pwr_pmu_idle_ctrl_value_always_f() |
776 pwr_pmu_idle_ctrl_filter_disabled_f());
777 gk20a_writel(g, pwr_pmu_idle_ctrl_r(6), data);
778
779 /*
780 * We don't want to disturb counters #3 and #6, which are used by
781 * perfmon, so we add wiring also to counters #1 and #2 for
782 * exposing raw counter readings.
783 */
784 gk20a_writel(g, pwr_pmu_idle_mask_r(1),
785 pwr_pmu_idle_mask_gr_enabled_f() |
786 pwr_pmu_idle_mask_ce_2_enabled_f());
787
788 data = gk20a_readl(g, pwr_pmu_idle_ctrl_r(1));
789 data = set_field(data, pwr_pmu_idle_ctrl_value_m() |
790 pwr_pmu_idle_ctrl_filter_m(),
791 pwr_pmu_idle_ctrl_value_busy_f() |
792 pwr_pmu_idle_ctrl_filter_disabled_f());
793 gk20a_writel(g, pwr_pmu_idle_ctrl_r(1), data);
794
795 data = gk20a_readl(g, pwr_pmu_idle_ctrl_r(2));
796 data = set_field(data, pwr_pmu_idle_ctrl_value_m() |
797 pwr_pmu_idle_ctrl_filter_m(),
798 pwr_pmu_idle_ctrl_value_always_f() |
799 pwr_pmu_idle_ctrl_filter_disabled_f());
800 gk20a_writel(g, pwr_pmu_idle_ctrl_r(2), data);
801}
802
803u32 gk20a_pmu_read_idle_counter(struct gk20a *g, u32 counter_id)
804{
805 return pwr_pmu_idle_count_value_v(
806 gk20a_readl(g, pwr_pmu_idle_count_r(counter_id)));
807}
808
809void gk20a_pmu_reset_idle_counter(struct gk20a *g, u32 counter_id)
810{
811 gk20a_writel(g, pwr_pmu_idle_count_r(counter_id),
812 pwr_pmu_idle_count_reset_f(1));
813}
814
815void gk20a_pmu_elpg_statistics(struct gk20a *g, u32 pg_engine_id,
816 struct pmu_pg_stats_data *pg_stat_data)
817{
818 struct nvgpu_pmu *pmu = &g->pmu;
819 struct pmu_pg_stats stats;
820
821 nvgpu_flcn_copy_from_dmem(pmu->flcn,
822 pmu->stat_dmem_offset[pg_engine_id],
823 (u8 *)&stats, sizeof(struct pmu_pg_stats), 0);
824
825 pg_stat_data->ingating_time = stats.pg_ingating_time_us;
826 pg_stat_data->ungating_time = stats.pg_ungating_time_us;
827 pg_stat_data->gating_cnt = stats.pg_gating_cnt;
828 pg_stat_data->avg_entry_latency_us = stats.pg_avg_entry_time_us;
829 pg_stat_data->avg_exit_latency_us = stats.pg_avg_exit_time_us;
830}