summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/pmu/pmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/pmu/pmu.c')
-rw-r--r--drivers/gpu/nvgpu/common/pmu/pmu.c574
1 files changed, 574 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/pmu/pmu.c b/drivers/gpu/nvgpu/common/pmu/pmu.c
new file mode 100644
index 00000000..3447f40d
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/pmu/pmu.c
@@ -0,0 +1,574 @@
1/*
2 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <nvgpu/pmu.h>
24#include <nvgpu/dma.h>
25#include <nvgpu/log.h>
26#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
27#include <nvgpu/enabled.h>
28#include <nvgpu/barrier.h>
29#include <nvgpu/timers.h>
30#include <nvgpu/bug.h>
31
32#include "gk20a/gk20a.h"
33
34#define PMU_MEM_SCRUBBING_TIMEOUT_MAX 1000
35#define PMU_MEM_SCRUBBING_TIMEOUT_DEFAULT 10
36
37static int nvgpu_pg_init_task(void *arg);
38
39static int pmu_enable_hw(struct nvgpu_pmu *pmu, bool enable)
40{
41 struct gk20a *g = pmu->g;
42 struct nvgpu_timeout timeout;
43 int err = 0;
44
45 nvgpu_log_fn(g, " %s ", g->name);
46
47 if (enable) {
48 /* bring PMU falcon/engine out of reset */
49 g->ops.pmu.reset_engine(g, true);
50
51 if (g->ops.clock_gating.slcg_pmu_load_gating_prod)
52 g->ops.clock_gating.slcg_pmu_load_gating_prod(g,
53 g->slcg_enabled);
54
55 if (g->ops.clock_gating.blcg_pmu_load_gating_prod)
56 g->ops.clock_gating.blcg_pmu_load_gating_prod(g,
57 g->blcg_enabled);
58
59 /* check for PMU IMEM/DMEM scrubbing complete status */
60 nvgpu_timeout_init(g, &timeout,
61 PMU_MEM_SCRUBBING_TIMEOUT_MAX /
62 PMU_MEM_SCRUBBING_TIMEOUT_DEFAULT,
63 NVGPU_TIMER_RETRY_TIMER);
64 do {
65 if (nvgpu_flcn_get_mem_scrubbing_status(pmu->flcn))
66 goto exit;
67
68 nvgpu_udelay(PMU_MEM_SCRUBBING_TIMEOUT_DEFAULT);
69 } while (!nvgpu_timeout_expired(&timeout));
70
71 /* keep PMU falcon/engine in reset
72 * if IMEM/DMEM scrubbing fails
73 */
74 g->ops.pmu.reset_engine(g, false);
75 nvgpu_err(g, "Falcon mem scrubbing timeout");
76 err = -ETIMEDOUT;
77 } else
78 /* keep PMU falcon/engine in reset */
79 g->ops.pmu.reset_engine(g, false);
80
81exit:
82 nvgpu_log_fn(g, "%s Done, status - %d ", g->name, err);
83 return err;
84}
85
86static int pmu_enable(struct nvgpu_pmu *pmu, bool enable)
87{
88 struct gk20a *g = pmu->g;
89 int err = 0;
90
91 nvgpu_log_fn(g, " ");
92
93 if (!enable) {
94 if (!g->ops.pmu.is_engine_in_reset(g)) {
95 pmu_enable_irq(pmu, false);
96 pmu_enable_hw(pmu, false);
97 }
98 } else {
99 err = pmu_enable_hw(pmu, true);
100 if (err)
101 goto exit;
102
103 err = nvgpu_flcn_wait_idle(pmu->flcn);
104 if (err)
105 goto exit;
106
107 pmu_enable_irq(pmu, true);
108 }
109
110exit:
111 nvgpu_log_fn(g, "Done, status - %d ", err);
112 return err;
113}
114
115int nvgpu_pmu_reset(struct gk20a *g)
116{
117 struct nvgpu_pmu *pmu = &g->pmu;
118 int err = 0;
119
120 nvgpu_log_fn(g, " %s ", g->name);
121
122 err = nvgpu_flcn_wait_idle(pmu->flcn);
123 if (err)
124 goto exit;
125
126 err = pmu_enable(pmu, false);
127 if (err)
128 goto exit;
129
130 err = pmu_enable(pmu, true);
131
132exit:
133 nvgpu_log_fn(g, " %s Done, status - %d ", g->name, err);
134 return err;
135}
136
137static int nvgpu_init_task_pg_init(struct gk20a *g)
138{
139 struct nvgpu_pmu *pmu = &g->pmu;
140 char thread_name[64];
141 int err = 0;
142
143 nvgpu_log_fn(g, " ");
144
145 nvgpu_cond_init(&pmu->pg_init.wq);
146
147 snprintf(thread_name, sizeof(thread_name),
148 "nvgpu_pg_init_%s", g->name);
149
150 err = nvgpu_thread_create(&pmu->pg_init.state_task, g,
151 nvgpu_pg_init_task, thread_name);
152 if (err)
153 nvgpu_err(g, "failed to start nvgpu_pg_init thread");
154
155 return err;
156}
157
158static int nvgpu_init_pmu_setup_sw(struct gk20a *g)
159{
160 struct nvgpu_pmu *pmu = &g->pmu;
161 struct mm_gk20a *mm = &g->mm;
162 struct vm_gk20a *vm = mm->pmu.vm;
163 unsigned int i;
164 int err = 0;
165 u8 *ptr;
166
167 nvgpu_log_fn(g, " ");
168
169 /* start with elpg disabled until first enable call */
170 pmu->elpg_refcnt = 0;
171
172 /* Create thread to handle PMU state machine */
173 nvgpu_init_task_pg_init(g);
174
175 if (pmu->sw_ready) {
176 for (i = 0; i < pmu->mutex_cnt; i++) {
177 pmu->mutex[i].id = i;
178 pmu->mutex[i].index = i;
179 }
180 nvgpu_pmu_seq_init(pmu);
181
182 nvgpu_log_fn(g, "skip init");
183 goto skip_init;
184 }
185
186 /* no infoRom script from vbios? */
187
188 /* TBD: sysmon subtask */
189
190 if (IS_ENABLED(CONFIG_TEGRA_GK20A_PERFMON))
191 pmu->perfmon_sampling_enabled = true;
192
193 pmu->mutex_cnt = g->ops.pmu.pmu_mutex_size();
194 pmu->mutex = nvgpu_kzalloc(g, pmu->mutex_cnt *
195 sizeof(struct pmu_mutex));
196 if (!pmu->mutex) {
197 err = -ENOMEM;
198 goto err;
199 }
200
201 for (i = 0; i < pmu->mutex_cnt; i++) {
202 pmu->mutex[i].id = i;
203 pmu->mutex[i].index = i;
204 }
205
206 pmu->seq = nvgpu_kzalloc(g, PMU_MAX_NUM_SEQUENCES *
207 sizeof(struct pmu_sequence));
208 if (!pmu->seq) {
209 err = -ENOMEM;
210 goto err_free_mutex;
211 }
212
213 nvgpu_pmu_seq_init(pmu);
214
215 err = nvgpu_dma_alloc_map_sys(vm, GK20A_PMU_SEQ_BUF_SIZE,
216 &pmu->seq_buf);
217 if (err) {
218 nvgpu_err(g, "failed to allocate memory");
219 goto err_free_seq;
220 }
221
222 ptr = (u8 *)pmu->seq_buf.cpu_va;
223
224 /* TBD: remove this if ZBC save/restore is handled by PMU
225 * end an empty ZBC sequence for now
226 */
227 ptr[0] = 0x16; /* opcode EXIT */
228 ptr[1] = 0; ptr[2] = 1; ptr[3] = 0;
229 ptr[4] = 0; ptr[5] = 0; ptr[6] = 0; ptr[7] = 0;
230
231 pmu->seq_buf.size = GK20A_PMU_SEQ_BUF_SIZE;
232
233 err = nvgpu_dma_alloc_map(vm, GK20A_PMU_TRACE_BUFSIZE,
234 &pmu->trace_buf);
235 if (err) {
236 nvgpu_err(g, "failed to allocate pmu trace buffer\n");
237 goto err_free_seq_buf;
238 }
239
240 pmu->sw_ready = true;
241
242skip_init:
243 nvgpu_log_fn(g, "done");
244 return 0;
245 err_free_seq_buf:
246 nvgpu_dma_unmap_free(vm, &pmu->seq_buf);
247 err_free_seq:
248 nvgpu_kfree(g, pmu->seq);
249 err_free_mutex:
250 nvgpu_kfree(g, pmu->mutex);
251 err:
252 nvgpu_log_fn(g, "fail");
253 return err;
254}
255
256int nvgpu_init_pmu_support(struct gk20a *g)
257{
258 struct nvgpu_pmu *pmu = &g->pmu;
259 u32 err;
260
261 nvgpu_log_fn(g, " ");
262
263 if (pmu->initialized)
264 return 0;
265
266 err = pmu_enable_hw(pmu, true);
267 if (err)
268 return err;
269
270 if (g->support_pmu) {
271 err = nvgpu_init_pmu_setup_sw(g);
272 if (err)
273 return err;
274 err = g->ops.pmu.pmu_setup_hw_and_bootstrap(g);
275 if (err)
276 return err;
277
278 nvgpu_pmu_state_change(g, PMU_STATE_STARTING, false);
279 }
280
281 return err;
282}
283
284int nvgpu_pmu_process_init_msg(struct nvgpu_pmu *pmu,
285 struct pmu_msg *msg)
286{
287 struct gk20a *g = gk20a_from_pmu(pmu);
288 struct pmu_v *pv = &g->ops.pmu_ver;
289 union pmu_init_msg_pmu *init;
290 struct pmu_sha1_gid_data gid_data;
291 u32 i, tail = 0;
292
293 nvgpu_log_fn(g, " ");
294
295 nvgpu_pmu_dbg(g, "init received\n");
296
297 g->ops.pmu.pmu_msgq_tail(pmu, &tail, QUEUE_GET);
298
299 nvgpu_flcn_copy_from_dmem(pmu->flcn, tail,
300 (u8 *)&msg->hdr, PMU_MSG_HDR_SIZE, 0);
301 if (msg->hdr.unit_id != PMU_UNIT_INIT) {
302 nvgpu_err(g, "expecting init msg");
303 return -EINVAL;
304 }
305
306 nvgpu_flcn_copy_from_dmem(pmu->flcn, tail + PMU_MSG_HDR_SIZE,
307 (u8 *)&msg->msg, msg->hdr.size - PMU_MSG_HDR_SIZE, 0);
308
309 if (msg->msg.init.msg_type != PMU_INIT_MSG_TYPE_PMU_INIT) {
310 nvgpu_err(g, "expecting init msg");
311 return -EINVAL;
312 }
313
314 tail += ALIGN(msg->hdr.size, PMU_DMEM_ALIGNMENT);
315 g->ops.pmu.pmu_msgq_tail(pmu, &tail, QUEUE_SET);
316
317 init = pv->get_pmu_msg_pmu_init_msg_ptr(&(msg->msg.init));
318 if (!pmu->gid_info.valid) {
319
320 nvgpu_flcn_copy_from_dmem(pmu->flcn,
321 pv->get_pmu_init_msg_pmu_sw_mg_off(init),
322 (u8 *)&gid_data,
323 sizeof(struct pmu_sha1_gid_data), 0);
324
325 pmu->gid_info.valid =
326 (*(u32 *)gid_data.signature == PMU_SHA1_GID_SIGNATURE);
327
328 if (pmu->gid_info.valid) {
329
330 BUG_ON(sizeof(pmu->gid_info.gid) !=
331 sizeof(gid_data.gid));
332
333 memcpy(pmu->gid_info.gid, gid_data.gid,
334 sizeof(pmu->gid_info.gid));
335 }
336 }
337
338 for (i = 0; i < PMU_QUEUE_COUNT; i++)
339 nvgpu_pmu_queue_init(pmu, i, init);
340
341 if (!nvgpu_alloc_initialized(&pmu->dmem)) {
342 /* Align start and end addresses */
343 u32 start = ALIGN(pv->get_pmu_init_msg_pmu_sw_mg_off(init),
344 PMU_DMEM_ALLOC_ALIGNMENT);
345 u32 end = (pv->get_pmu_init_msg_pmu_sw_mg_off(init) +
346 pv->get_pmu_init_msg_pmu_sw_mg_size(init)) &
347 ~(PMU_DMEM_ALLOC_ALIGNMENT - 1);
348 u32 size = end - start;
349
350 nvgpu_bitmap_allocator_init(g, &pmu->dmem, "gk20a_pmu_dmem",
351 start, size, PMU_DMEM_ALLOC_ALIGNMENT, 0);
352 }
353
354 pmu->pmu_ready = true;
355
356 nvgpu_pmu_state_change(g, PMU_STATE_INIT_RECEIVED, true);
357
358 nvgpu_pmu_dbg(g, "init received end\n");
359
360 return 0;
361}
362
363static void pmu_setup_hw_enable_elpg(struct gk20a *g)
364{
365 struct nvgpu_pmu *pmu = &g->pmu;
366
367 nvgpu_log_fn(g, " ");
368
369 pmu->initialized = true;
370 nvgpu_pmu_state_change(g, PMU_STATE_STARTED, false);
371
372 if (nvgpu_is_enabled(g, NVGPU_PMU_ZBC_SAVE)) {
373 /* Save zbc table after PMU is initialized. */
374 pmu->zbc_ready = true;
375 gk20a_pmu_save_zbc(g, 0xf);
376 }
377
378 if (g->elpg_enabled) {
379 /* Init reg with prod values*/
380 if (g->ops.pmu.pmu_setup_elpg)
381 g->ops.pmu.pmu_setup_elpg(g);
382 nvgpu_pmu_enable_elpg(g);
383 }
384
385 nvgpu_udelay(50);
386
387 /* Enable AELPG */
388 if (g->aelpg_enabled) {
389 nvgpu_aelpg_init(g);
390 nvgpu_aelpg_init_and_enable(g, PMU_AP_CTRL_ID_GRAPHICS);
391 }
392}
393
394void nvgpu_pmu_state_change(struct gk20a *g, u32 pmu_state,
395 bool post_change_event)
396{
397 struct nvgpu_pmu *pmu = &g->pmu;
398
399 nvgpu_pmu_dbg(g, "pmu_state - %d", pmu_state);
400
401 pmu->pmu_state = pmu_state;
402
403 if (post_change_event) {
404 pmu->pg_init.state_change = true;
405 nvgpu_cond_signal(&pmu->pg_init.wq);
406 }
407
408 /* make status visible */
409 nvgpu_smp_mb();
410}
411
412static int nvgpu_pg_init_task(void *arg)
413{
414 struct gk20a *g = (struct gk20a *)arg;
415 struct nvgpu_pmu *pmu = &g->pmu;
416 struct nvgpu_pg_init *pg_init = &pmu->pg_init;
417 u32 pmu_state = 0;
418
419 nvgpu_log_fn(g, "thread start");
420
421 while (true) {
422
423 NVGPU_COND_WAIT_INTERRUPTIBLE(&pg_init->wq,
424 (pg_init->state_change == true), 0);
425
426 pmu->pg_init.state_change = false;
427 pmu_state = NV_ACCESS_ONCE(pmu->pmu_state);
428
429 if (pmu_state == PMU_STATE_EXIT) {
430 nvgpu_pmu_dbg(g, "pmu state exit");
431 break;
432 }
433
434 switch (pmu_state) {
435 case PMU_STATE_INIT_RECEIVED:
436 nvgpu_pmu_dbg(g, "pmu starting");
437 if (g->can_elpg)
438 nvgpu_pmu_init_powergating(g);
439 break;
440 case PMU_STATE_ELPG_BOOTED:
441 nvgpu_pmu_dbg(g, "elpg booted");
442 nvgpu_pmu_init_bind_fecs(g);
443 break;
444 case PMU_STATE_LOADING_PG_BUF:
445 nvgpu_pmu_dbg(g, "loaded pg buf");
446 nvgpu_pmu_setup_hw_load_zbc(g);
447 break;
448 case PMU_STATE_LOADING_ZBC:
449 nvgpu_pmu_dbg(g, "loaded zbc");
450 pmu_setup_hw_enable_elpg(g);
451 nvgpu_pmu_dbg(g, "PMU booted, thread exiting");
452 return 0;
453 default:
454 nvgpu_pmu_dbg(g, "invalid state");
455 break;
456 }
457
458 }
459
460 while (!nvgpu_thread_should_stop(&pg_init->state_task))
461 nvgpu_usleep_range(5000, 5100);
462
463 nvgpu_log_fn(g, "thread exit");
464
465 return 0;
466}
467
468int nvgpu_pmu_destroy(struct gk20a *g)
469{
470 struct nvgpu_pmu *pmu = &g->pmu;
471 struct pmu_pg_stats_data pg_stat_data = { 0 };
472 struct nvgpu_timeout timeout;
473 int i;
474
475 nvgpu_log_fn(g, " ");
476
477 if (!g->support_pmu)
478 return 0;
479
480 /* make sure the pending operations are finished before we continue */
481 if (nvgpu_thread_is_running(&pmu->pg_init.state_task)) {
482
483 /* post PMU_STATE_EXIT to exit PMU state machine loop */
484 nvgpu_pmu_state_change(g, PMU_STATE_EXIT, true);
485
486 /* Make thread stop*/
487 nvgpu_thread_stop(&pmu->pg_init.state_task);
488
489 /* wait to confirm thread stopped */
490 nvgpu_timeout_init(g, &timeout, 1000, NVGPU_TIMER_RETRY_TIMER);
491 do {
492 if (!nvgpu_thread_is_running(&pmu->pg_init.state_task))
493 break;
494 nvgpu_udelay(2);
495 } while (!nvgpu_timeout_expired_msg(&timeout,
496 "timeout - waiting PMU state machine thread stop"));
497 }
498
499 nvgpu_pmu_get_pg_stats(g,
500 PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &pg_stat_data);
501
502 if (nvgpu_pmu_disable_elpg(g))
503 nvgpu_err(g, "failed to set disable elpg");
504 pmu->initialized = false;
505
506 /* update the s/w ELPG residency counters */
507 g->pg_ingating_time_us += (u64)pg_stat_data.ingating_time;
508 g->pg_ungating_time_us += (u64)pg_stat_data.ungating_time;
509 g->pg_gating_cnt += pg_stat_data.gating_cnt;
510
511 nvgpu_mutex_acquire(&pmu->isr_mutex);
512 pmu->isr_enabled = false;
513 nvgpu_mutex_release(&pmu->isr_mutex);
514
515 for (i = 0; i < PMU_QUEUE_COUNT; i++)
516 nvgpu_mutex_destroy(&pmu->queue[i].mutex);
517
518 nvgpu_pmu_state_change(g, PMU_STATE_OFF, false);
519 pmu->pmu_ready = false;
520 pmu->perfmon_ready = false;
521 pmu->zbc_ready = false;
522 g->pmu_lsf_pmu_wpr_init_done = false;
523 __nvgpu_set_enabled(g, NVGPU_PMU_FECS_BOOTSTRAP_DONE, false);
524
525 nvgpu_log_fn(g, "done");
526 return 0;
527}
528
529void nvgpu_pmu_surface_describe(struct gk20a *g, struct nvgpu_mem *mem,
530 struct flcn_mem_desc_v0 *fb)
531{
532 fb->address.lo = u64_lo32(mem->gpu_va);
533 fb->address.hi = u64_hi32(mem->gpu_va);
534 fb->params = ((u32)mem->size & 0xFFFFFF);
535 fb->params |= (GK20A_PMU_DMAIDX_VIRT << 24);
536}
537
538int nvgpu_pmu_vidmem_surface_alloc(struct gk20a *g, struct nvgpu_mem *mem,
539 u32 size)
540{
541 struct mm_gk20a *mm = &g->mm;
542 struct vm_gk20a *vm = mm->pmu.vm;
543 int err;
544
545 err = nvgpu_dma_alloc_map_vid(vm, size, mem);
546 if (err) {
547 nvgpu_err(g, "memory allocation failed");
548 return -ENOMEM;
549 }
550
551 return 0;
552}
553
554int nvgpu_pmu_sysmem_surface_alloc(struct gk20a *g, struct nvgpu_mem *mem,
555 u32 size)
556{
557 struct mm_gk20a *mm = &g->mm;
558 struct vm_gk20a *vm = mm->pmu.vm;
559 int err;
560
561 err = nvgpu_dma_alloc_map_sys(vm, size, mem);
562 if (err) {
563 nvgpu_err(g, "failed to allocate memory\n");
564 return -ENOMEM;
565 }
566
567 return 0;
568}
569
570void nvgpu_pmu_surface_free(struct gk20a *g, struct nvgpu_mem *mem)
571{
572 nvgpu_dma_free(g, mem);
573 memset(mem, 0, sizeof(struct nvgpu_mem));
574}