diff options
Diffstat (limited to 'drivers/gpu/nvgpu/common/pmu/pmu.c')
-rw-r--r-- | drivers/gpu/nvgpu/common/pmu/pmu.c | 574 |
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 | |||
37 | static int nvgpu_pg_init_task(void *arg); | ||
38 | |||
39 | static 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 | |||
81 | exit: | ||
82 | nvgpu_log_fn(g, "%s Done, status - %d ", g->name, err); | ||
83 | return err; | ||
84 | } | ||
85 | |||
86 | static 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 | |||
110 | exit: | ||
111 | nvgpu_log_fn(g, "Done, status - %d ", err); | ||
112 | return err; | ||
113 | } | ||
114 | |||
115 | int 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 | |||
132 | exit: | ||
133 | nvgpu_log_fn(g, " %s Done, status - %d ", g->name, err); | ||
134 | return err; | ||
135 | } | ||
136 | |||
137 | static 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 | |||
158 | static 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 | |||
242 | skip_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 | |||
256 | int 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 | |||
284 | int 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 | |||
363 | static 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 | |||
394 | void 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 | |||
412 | static 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 | |||
468 | int 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 | |||
529 | void 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 | |||
538 | int 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 | |||
554 | int 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 | |||
570 | void 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 | } | ||