summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common
diff options
context:
space:
mode:
authorMahantesh Kumbar <mkumbar@nvidia.com>2017-06-06 05:56:32 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-06-12 14:03:37 -0400
commit69dee6a648ad434b75e1a9c64b022ee45d3ff87b (patch)
treeeba316aa07b17760afb1609b331bb3cf0602e545 /drivers/gpu/nvgpu/common
parent914bb78a7dc0687b349310cc28613ea4a4c0be33 (diff)
gpu: nvgpu: reorganize PMU init
- Moved PMU init code from pmu_gk20a.c to "drivers/gpu/nvgpu/common/pmu/pmu.c" file - Moved below related methods SW/HW init, init msg handler, deinit/destroy, PMU state machine -Created HAL methods to read message queue tail & supported mutex count. -prepend with nvgpu_ for pmu init global mehtods JIRA NVGPU-56 JIRA NVGPU-92 Change-Id: Iea9efc194fefa74fb5641d2b2f4633577d2c3a47 Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com> Reviewed-on: http://git-master/r/1480002 Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/common')
-rw-r--r--drivers/gpu/nvgpu/common/linux/debug_pmu.c8
-rw-r--r--drivers/gpu/nvgpu/common/pmu/pmu.c425
2 files changed, 429 insertions, 4 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/debug_pmu.c b/drivers/gpu/nvgpu/common/linux/debug_pmu.c
index 918672db..7d9f5ac3 100644
--- a/drivers/gpu/nvgpu/common/linux/debug_pmu.c
+++ b/drivers/gpu/nvgpu/common/linux/debug_pmu.c
@@ -75,7 +75,7 @@ static int mscg_stat_show(struct seq_file *s, void *data)
75 if (err) 75 if (err)
76 return err; 76 return err;
77 77
78 gk20a_pmu_get_pg_stats(g, 78 nvgpu_pmu_get_pg_stats(g,
79 PMU_PG_ELPG_ENGINE_ID_MS, &pg_stat_data); 79 PMU_PG_ELPG_ENGINE_ID_MS, &pg_stat_data);
80 gk20a_idle(g); 80 gk20a_idle(g);
81 } 81 }
@@ -133,7 +133,7 @@ static int mscg_transitions_show(struct seq_file *s, void *data)
133 if (err) 133 if (err)
134 return err; 134 return err;
135 135
136 gk20a_pmu_get_pg_stats(g, 136 nvgpu_pmu_get_pg_stats(g,
137 PMU_PG_ELPG_ENGINE_ID_MS, &pg_stat_data); 137 PMU_PG_ELPG_ENGINE_ID_MS, &pg_stat_data);
138 gk20a_idle(g); 138 gk20a_idle(g);
139 } 139 }
@@ -169,7 +169,7 @@ static int elpg_stat_show(struct seq_file *s, void *data)
169 if (err) 169 if (err)
170 return err; 170 return err;
171 171
172 gk20a_pmu_get_pg_stats(g, 172 nvgpu_pmu_get_pg_stats(g,
173 PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &pg_stat_data); 173 PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &pg_stat_data);
174 gk20a_idle(g); 174 gk20a_idle(g);
175 } 175 }
@@ -226,7 +226,7 @@ static int elpg_transitions_show(struct seq_file *s, void *data)
226 if (err) 226 if (err)
227 return err; 227 return err;
228 228
229 gk20a_pmu_get_pg_stats(g, 229 nvgpu_pmu_get_pg_stats(g,
230 PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &pg_stat_data); 230 PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &pg_stat_data);
231 gk20a_idle(g); 231 gk20a_idle(g);
232 } 232 }
diff --git a/drivers/gpu/nvgpu/common/pmu/pmu.c b/drivers/gpu/nvgpu/common/pmu/pmu.c
new file mode 100644
index 00000000..90db07b4
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/pmu/pmu.c
@@ -0,0 +1,425 @@
1/*
2 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include <nvgpu/pmu.h>
15#include <nvgpu/dma.h>
16#include <nvgpu/log.h>
17#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
18
19#include "gk20a/gk20a.h"
20
21static int nvgpu_pg_init_task(void *arg);
22
23static int nvgpu_init_task_pg_init(struct gk20a *g)
24{
25 struct nvgpu_pmu *pmu = &g->pmu;
26 char thread_name[64];
27 int err = 0;
28
29 nvgpu_log_fn(g, " ");
30
31 nvgpu_cond_init(&pmu->pg_init.wq);
32
33 snprintf(thread_name, sizeof(thread_name),
34 "nvgpu_pg_init_%s", g->name);
35
36 err = nvgpu_thread_create(&pmu->pg_init.state_task, g,
37 nvgpu_pg_init_task, thread_name);
38 if (err)
39 nvgpu_err(g, "failed to start nvgpu_pg_init thread");
40
41 return err;
42}
43
44static int nvgpu_init_pmu_setup_sw(struct gk20a *g)
45{
46 struct nvgpu_pmu *pmu = &g->pmu;
47 struct mm_gk20a *mm = &g->mm;
48 struct vm_gk20a *vm = mm->pmu.vm;
49 unsigned int i;
50 int err = 0;
51 u8 *ptr;
52
53 nvgpu_log_fn(g, " ");
54
55 /* start with elpg disabled until first enable call */
56 pmu->elpg_refcnt = 0;
57
58 /* Create thread to handle PMU state machine */
59 nvgpu_init_task_pg_init(g);
60
61 if (pmu->sw_ready) {
62 for (i = 0; i < pmu->mutex_cnt; i++) {
63 pmu->mutex[i].id = i;
64 pmu->mutex[i].index = i;
65 }
66 nvgpu_pmu_seq_init(pmu);
67
68 nvgpu_log_fn(g, "skip init");
69 goto skip_init;
70 }
71
72 /* no infoRom script from vbios? */
73
74 /* TBD: sysmon subtask */
75
76 if (IS_ENABLED(CONFIG_TEGRA_GK20A_PERFMON))
77 pmu->perfmon_sampling_enabled = true;
78
79 pmu->mutex_cnt = g->ops.pmu.pmu_mutex_size();
80 pmu->mutex = nvgpu_kzalloc(g, pmu->mutex_cnt *
81 sizeof(struct pmu_mutex));
82 if (!pmu->mutex) {
83 err = -ENOMEM;
84 goto err;
85 }
86
87 for (i = 0; i < pmu->mutex_cnt; i++) {
88 pmu->mutex[i].id = i;
89 pmu->mutex[i].index = i;
90 }
91
92 pmu->seq = nvgpu_kzalloc(g, PMU_MAX_NUM_SEQUENCES *
93 sizeof(struct pmu_sequence));
94 if (!pmu->seq) {
95 err = -ENOMEM;
96 goto err_free_mutex;
97 }
98
99 nvgpu_pmu_seq_init(pmu);
100
101 err = nvgpu_dma_alloc_map_sys(vm, GK20A_PMU_SEQ_BUF_SIZE,
102 &pmu->seq_buf);
103 if (err) {
104 nvgpu_err(g, "failed to allocate memory");
105 goto err_free_seq;
106 }
107
108 ptr = (u8 *)pmu->seq_buf.cpu_va;
109
110 /* TBD: remove this if ZBC save/restore is handled by PMU
111 * end an empty ZBC sequence for now
112 */
113 ptr[0] = 0x16; /* opcode EXIT */
114 ptr[1] = 0; ptr[2] = 1; ptr[3] = 0;
115 ptr[4] = 0; ptr[5] = 0; ptr[6] = 0; ptr[7] = 0;
116
117 pmu->seq_buf.size = GK20A_PMU_SEQ_BUF_SIZE;
118
119 err = nvgpu_dma_alloc_map(vm, GK20A_PMU_TRACE_BUFSIZE,
120 &pmu->trace_buf);
121 if (err) {
122 nvgpu_err(g, "failed to allocate pmu trace buffer\n");
123 goto err_free_seq_buf;
124 }
125
126 pmu->sw_ready = true;
127
128skip_init:
129 nvgpu_log_fn(g, "done");
130 return 0;
131 err_free_seq_buf:
132 nvgpu_dma_unmap_free(vm, &pmu->seq_buf);
133 err_free_seq:
134 nvgpu_kfree(g, pmu->seq);
135 err_free_mutex:
136 nvgpu_kfree(g, pmu->mutex);
137 err:
138 nvgpu_log_fn(g, "fail");
139 return err;
140}
141
142static int nvgpu_init_pmu_reset_enable_hw(struct gk20a *g)
143{
144 struct nvgpu_pmu *pmu = &g->pmu;
145
146 nvgpu_log_fn(g, " ");
147
148 pmu_enable_hw(pmu, true);
149
150 return 0;
151}
152
153int nvgpu_init_pmu_support(struct gk20a *g)
154{
155 struct nvgpu_pmu *pmu = &g->pmu;
156 u32 err;
157
158 nvgpu_log_fn(g, " ");
159
160 if (pmu->initialized)
161 return 0;
162
163 err = nvgpu_init_pmu_reset_enable_hw(g);
164 if (err)
165 return err;
166
167 if (g->support_pmu) {
168 err = nvgpu_init_pmu_setup_sw(g);
169 if (err)
170 return err;
171 err = g->ops.pmu.pmu_setup_hw_and_bootstrap(g);
172 if (err)
173 return err;
174
175 nvgpu_pmu_state_change(g, PMU_STATE_STARTING, false);
176 }
177
178 return err;
179}
180
181int nvgpu_pmu_process_init_msg(struct nvgpu_pmu *pmu,
182 struct pmu_msg *msg)
183{
184 struct gk20a *g = gk20a_from_pmu(pmu);
185 struct pmu_v *pv = &g->ops.pmu_ver;
186 union pmu_init_msg_pmu *init;
187 struct pmu_sha1_gid_data gid_data;
188 u32 i, tail = 0;
189
190 nvgpu_log_fn(g, " ");
191
192 nvgpu_pmu_dbg(g, "init received\n");
193
194 g->ops.pmu.pmu_msgq_tail(pmu, &tail, QUEUE_GET);
195
196 pmu_copy_from_dmem(pmu, tail,
197 (u8 *)&msg->hdr, PMU_MSG_HDR_SIZE, 0);
198 if (msg->hdr.unit_id != PMU_UNIT_INIT) {
199 nvgpu_err(g, "expecting init msg");
200 return -EINVAL;
201 }
202
203 pmu_copy_from_dmem(pmu, tail + PMU_MSG_HDR_SIZE,
204 (u8 *)&msg->msg, msg->hdr.size - PMU_MSG_HDR_SIZE, 0);
205
206 if (msg->msg.init.msg_type != PMU_INIT_MSG_TYPE_PMU_INIT) {
207 nvgpu_err(g, "expecting init msg");
208 return -EINVAL;
209 }
210
211 tail += ALIGN(msg->hdr.size, PMU_DMEM_ALIGNMENT);
212 g->ops.pmu.pmu_msgq_tail(pmu, &tail, QUEUE_SET);
213
214 init = pv->get_pmu_msg_pmu_init_msg_ptr(&(msg->msg.init));
215 if (!pmu->gid_info.valid) {
216
217 pmu_copy_from_dmem(pmu,
218 pv->get_pmu_init_msg_pmu_sw_mg_off(init),
219 (u8 *)&gid_data,
220 sizeof(struct pmu_sha1_gid_data), 0);
221
222 pmu->gid_info.valid =
223 (*(u32 *)gid_data.signature == PMU_SHA1_GID_SIGNATURE);
224
225 if (pmu->gid_info.valid) {
226
227 BUG_ON(sizeof(pmu->gid_info.gid) !=
228 sizeof(gid_data.gid));
229
230 memcpy(pmu->gid_info.gid, gid_data.gid,
231 sizeof(pmu->gid_info.gid));
232 }
233 }
234
235 for (i = 0; i < PMU_QUEUE_COUNT; i++)
236 nvgpu_pmu_queue_init(pmu, i, init);
237
238 if (!nvgpu_alloc_initialized(&pmu->dmem)) {
239 /* Align start and end addresses */
240 u32 start = ALIGN(pv->get_pmu_init_msg_pmu_sw_mg_off(init),
241 PMU_DMEM_ALLOC_ALIGNMENT);
242 u32 end = (pv->get_pmu_init_msg_pmu_sw_mg_off(init) +
243 pv->get_pmu_init_msg_pmu_sw_mg_size(init)) &
244 ~(PMU_DMEM_ALLOC_ALIGNMENT - 1);
245 u32 size = end - start;
246
247 nvgpu_bitmap_allocator_init(g, &pmu->dmem, "gk20a_pmu_dmem",
248 start, size, PMU_DMEM_ALLOC_ALIGNMENT, 0);
249 }
250
251 pmu->pmu_ready = true;
252
253 nvgpu_pmu_state_change(g, PMU_STATE_INIT_RECEIVED, true);
254
255 nvgpu_pmu_dbg(g, "init received end\n");
256
257 return 0;
258}
259
260static void pmu_setup_hw_enable_elpg(struct gk20a *g)
261{
262 struct nvgpu_pmu *pmu = &g->pmu;
263
264 nvgpu_log_fn(g, " ");
265
266 pmu->initialized = true;
267 nvgpu_pmu_state_change(g, PMU_STATE_STARTED, false);
268
269 if (g->ops.pmu_ver.is_pmu_zbc_save_supported) {
270 /* Save zbc table after PMU is initialized. */
271 pmu->zbc_ready = true;
272 gk20a_pmu_save_zbc(g, 0xf);
273 }
274
275 if (g->elpg_enabled) {
276 /* Init reg with prod values*/
277 if (g->ops.pmu.pmu_setup_elpg)
278 g->ops.pmu.pmu_setup_elpg(g);
279 gk20a_pmu_enable_elpg(g);
280 }
281
282 nvgpu_udelay(50);
283
284 /* Enable AELPG */
285 if (g->aelpg_enabled) {
286 gk20a_aelpg_init(g);
287 gk20a_aelpg_init_and_enable(g, PMU_AP_CTRL_ID_GRAPHICS);
288 }
289}
290
291void nvgpu_pmu_state_change(struct gk20a *g, u32 pmu_state,
292 bool post_change_event)
293{
294 struct nvgpu_pmu *pmu = &g->pmu;
295
296 nvgpu_pmu_dbg(g, "pmu_state - %d", pmu_state);
297
298 pmu->pmu_state = pmu_state;
299
300 if (post_change_event) {
301 pmu->pg_init.state_change = true;
302 nvgpu_cond_signal(&pmu->pg_init.wq);
303 }
304
305 /* make status visible */
306 smp_mb();
307}
308
309static int nvgpu_pg_init_task(void *arg)
310{
311 struct gk20a *g = (struct gk20a *)arg;
312 struct nvgpu_pmu *pmu = &g->pmu;
313 struct nvgpu_pg_init *pg_init = &pmu->pg_init;
314 u32 pmu_state = 0;
315
316 nvgpu_log_fn(g, "thread start");
317
318 while (true) {
319
320 NVGPU_COND_WAIT(&pg_init->wq,
321 (pg_init->state_change == true), 0);
322
323 pmu->pg_init.state_change = false;
324 pmu_state = ACCESS_ONCE(pmu->pmu_state);
325
326 if (pmu_state == PMU_STATE_EXIT) {
327 nvgpu_pmu_dbg(g, "pmu state exit");
328 break;
329 }
330
331 switch (pmu_state) {
332 case PMU_STATE_INIT_RECEIVED:
333 nvgpu_pmu_dbg(g, "pmu starting");
334 if (g->can_elpg)
335 nvgpu_pmu_init_powergating(g);
336 break;
337 case PMU_STATE_ELPG_BOOTED:
338 nvgpu_pmu_dbg(g, "elpg booted");
339 nvgpu_pmu_init_bind_fecs(g);
340 break;
341 case PMU_STATE_LOADING_PG_BUF:
342 nvgpu_pmu_dbg(g, "loaded pg buf");
343 nvgpu_pmu_setup_hw_load_zbc(g);
344 break;
345 case PMU_STATE_LOADING_ZBC:
346 nvgpu_pmu_dbg(g, "loaded zbc");
347 pmu_setup_hw_enable_elpg(g);
348 break;
349 case PMU_STATE_STARTED:
350 nvgpu_pmu_dbg(g, "PMU booted");
351 break;
352 default:
353 nvgpu_pmu_dbg(g, "invalid state");
354 break;
355 }
356
357 }
358
359 while (!nvgpu_thread_should_stop(&pg_init->state_task))
360 nvgpu_msleep(5);
361
362 nvgpu_log_fn(g, "thread exit");
363
364 return 0;
365}
366
367int nvgpu_pmu_destroy(struct gk20a *g)
368{
369 struct nvgpu_pmu *pmu = &g->pmu;
370 struct pmu_pg_stats_data pg_stat_data = { 0 };
371 struct nvgpu_timeout timeout;
372 int i;
373
374 nvgpu_log_fn(g, " ");
375
376 if (!g->support_pmu)
377 return 0;
378
379 /* make sure the pending operations are finished before we continue */
380 if (nvgpu_thread_is_running(&pmu->pg_init.state_task)) {
381
382 /* post PMU_STATE_EXIT to exit PMU state machine loop */
383 nvgpu_pmu_state_change(g, PMU_STATE_EXIT, true);
384
385 /* Make thread stop*/
386 nvgpu_thread_stop(&pmu->pg_init.state_task);
387
388 /* wait to confirm thread stopped */
389 nvgpu_timeout_init(g, &timeout, 1000, NVGPU_TIMER_RETRY_TIMER);
390 do {
391 if (!nvgpu_thread_is_running(&pmu->pg_init.state_task))
392 break;
393 nvgpu_udelay(2);
394 } while (!nvgpu_timeout_expired_msg(&timeout,
395 "timeout - waiting PMU state machine thread stop"));
396 }
397
398 nvgpu_pmu_get_pg_stats(g,
399 PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &pg_stat_data);
400
401 gk20a_pmu_disable_elpg(g);
402 pmu->initialized = false;
403
404 /* update the s/w ELPG residency counters */
405 g->pg_ingating_time_us += (u64)pg_stat_data.ingating_time;
406 g->pg_ungating_time_us += (u64)pg_stat_data.ungating_time;
407 g->pg_gating_cnt += pg_stat_data.gating_cnt;
408
409 nvgpu_mutex_acquire(&pmu->isr_mutex);
410 pmu->isr_enabled = false;
411 nvgpu_mutex_release(&pmu->isr_mutex);
412
413 for (i = 0; i < PMU_QUEUE_COUNT; i++)
414 nvgpu_mutex_destroy(&pmu->queue[i].mutex);
415
416 nvgpu_pmu_state_change(g, PMU_STATE_OFF, false);
417 pmu->pmu_ready = false;
418 pmu->perfmon_ready = false;
419 pmu->zbc_ready = false;
420 g->ops.pmu.lspmuwprinitdone = false;
421 g->ops.pmu.fecsbootstrapdone = false;
422
423 nvgpu_log_fn(g, "done");
424 return 0;
425}