summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common
diff options
context:
space:
mode:
authorMahantesh Kumbar <mkumbar@nvidia.com>2017-06-13 05:51:56 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-06-15 14:18:51 -0400
commit77e2cbab237637f71367df25384164b8c936a31a (patch)
tree64ccc10c4c6aa3eddbcac1d697d50b860247bf57 /drivers/gpu/nvgpu/common
parent7d16f7e52c0f8ce8604e992a617a3f98545fcf07 (diff)
gpu: nvgpu: reorganize PMU perfmon
-Moved perfmon code from pmu_gk20a.c to "drivers/gpu/nvgpu/common/pmu/pmu_perfmon.c" file -Moved below related methods perfmon init, start/stop sampling, load counter read/write/reset, perfmon event handler - prepend with nvgpu_ for perfmon global methods by replacing gk20a_ JURA NVGPU-56 JURA NVGPU-98 Change-Id: Idbcdf63ebd76da170e609cc401b320a42110cd7b Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com> Reviewed-on: http://git-master/r/1501418 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/common')
-rw-r--r--drivers/gpu/nvgpu/common/pmu/pmu_perfmon.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/pmu/pmu_perfmon.c b/drivers/gpu/nvgpu/common/pmu/pmu_perfmon.c
new file mode 100644
index 00000000..e28e53a0
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/pmu/pmu_perfmon.c
@@ -0,0 +1,271 @@
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/log.h>
16#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
17
18#include "gk20a/gk20a.h"
19
20#ifdef CONFIG_TEGRA_19x_GPU
21#include "nvgpu_gpuid_t19x.h"
22#endif
23
24static u8 get_perfmon_id(struct nvgpu_pmu *pmu)
25{
26 struct gk20a *g = gk20a_from_pmu(pmu);
27 u32 ver = g->gpu_characteristics.arch + g->gpu_characteristics.impl;
28 u8 unit_id;
29
30 switch (ver) {
31 case GK20A_GPUID_GK20A:
32 case GK20A_GPUID_GM20B:
33 unit_id = PMU_UNIT_PERFMON;
34 break;
35 case NVGPU_GPUID_GP10B:
36 case NVGPU_GPUID_GP104:
37 case NVGPU_GPUID_GP106:
38 unit_id = PMU_UNIT_PERFMON_T18X;
39 break;
40#if defined(CONFIG_TEGRA_19x_GPU)
41 case TEGRA_19x_GPUID:
42 unit_id = PMU_UNIT_PERFMON_T18X;
43 break;
44#endif
45 default:
46 unit_id = PMU_UNIT_INVALID;
47 nvgpu_err(g, "no support for %x", ver);
48 WARN_ON(1);
49 }
50
51 return unit_id;
52}
53
54int nvgpu_pmu_init_perfmon(struct nvgpu_pmu *pmu)
55{
56 struct gk20a *g = gk20a_from_pmu(pmu);
57 struct pmu_v *pv = &g->ops.pmu_ver;
58 struct pmu_cmd cmd;
59 struct pmu_payload payload;
60 u32 seq;
61
62 nvgpu_log_fn(g, " ");
63
64 pmu->perfmon_ready = 0;
65
66 gk20a_pmu_init_perfmon_counter(g);
67
68 if (!pmu->sample_buffer)
69 pmu->sample_buffer = nvgpu_alloc(&pmu->dmem,
70 2 * sizeof(u16));
71 if (!pmu->sample_buffer) {
72 nvgpu_err(g, "failed to allocate perfmon sample buffer");
73 return -ENOMEM;
74 }
75
76 /* init PERFMON */
77 memset(&cmd, 0, sizeof(struct pmu_cmd));
78
79 cmd.hdr.unit_id = get_perfmon_id(pmu);
80 if (cmd.hdr.unit_id == PMU_UNIT_INVALID) {
81 nvgpu_err(g, "failed to get perfmon UNIT ID, command skipped");
82 return -EINVAL;
83 }
84
85 cmd.hdr.size = PMU_CMD_HDR_SIZE + pv->get_pmu_perfmon_cmd_init_size();
86 cmd.cmd.perfmon.cmd_type = PMU_PERFMON_CMD_ID_INIT;
87 /* buffer to save counter values for pmu perfmon */
88 pv->perfmon_cmd_init_set_sample_buffer(&cmd.cmd.perfmon,
89 (u16)pmu->sample_buffer);
90 /* number of sample periods below lower threshold
91 * before pmu triggers perfmon decrease event
92 * TBD: = 15
93 */
94 pv->perfmon_cmd_init_set_dec_cnt(&cmd.cmd.perfmon, 15);
95 /* index of base counter, aka. always ticking counter */
96 pv->perfmon_cmd_init_set_base_cnt_id(&cmd.cmd.perfmon, 6);
97 /* microseconds interval between pmu polls perf counters */
98 pv->perfmon_cmd_init_set_samp_period_us(&cmd.cmd.perfmon, 16700);
99 /* number of perfmon counters
100 * counter #3 (GR and CE2) for gk20a
101 */
102 pv->perfmon_cmd_init_set_num_cnt(&cmd.cmd.perfmon, 1);
103 /* moving average window for sample periods
104 * TBD: = 3000000 / sample_period_us = 17
105 */
106 pv->perfmon_cmd_init_set_mov_avg(&cmd.cmd.perfmon, 17);
107
108 memset(&payload, 0, sizeof(struct pmu_payload));
109 payload.in.buf = pv->get_perfmon_cntr_ptr(pmu);
110 payload.in.size = pv->get_perfmon_cntr_sz(pmu);
111 payload.in.offset = pv->get_perfmon_cmd_init_offsetofvar(COUNTER_ALLOC);
112
113 nvgpu_pmu_dbg(g, "cmd post PMU_PERFMON_CMD_ID_INIT");
114 gk20a_pmu_cmd_post(g, &cmd, NULL, &payload, PMU_COMMAND_QUEUE_LPQ,
115 NULL, NULL, &seq, ~0);
116
117 return 0;
118}
119
120int nvgpu_pmu_perfmon_start_sampling(struct nvgpu_pmu *pmu)
121{
122 struct gk20a *g = gk20a_from_pmu(pmu);
123 struct pmu_v *pv = &g->ops.pmu_ver;
124 struct pmu_cmd cmd;
125 struct pmu_payload payload;
126 u32 seq;
127
128 /* PERFMON Start */
129 memset(&cmd, 0, sizeof(struct pmu_cmd));
130 cmd.hdr.unit_id = get_perfmon_id(pmu);
131 if (cmd.hdr.unit_id == PMU_UNIT_INVALID) {
132 nvgpu_err(g, "failed to get perfmon UNIT ID, command skipped");
133 return -EINVAL;
134 }
135 cmd.hdr.size = PMU_CMD_HDR_SIZE + pv->get_pmu_perfmon_cmd_start_size();
136 pv->perfmon_start_set_cmd_type(&cmd.cmd.perfmon,
137 PMU_PERFMON_CMD_ID_START);
138 pv->perfmon_start_set_group_id(&cmd.cmd.perfmon,
139 PMU_DOMAIN_GROUP_PSTATE);
140 pv->perfmon_start_set_state_id(&cmd.cmd.perfmon,
141 pmu->perfmon_state_id[PMU_DOMAIN_GROUP_PSTATE]);
142
143 pv->perfmon_start_set_flags(&cmd.cmd.perfmon,
144 PMU_PERFMON_FLAG_ENABLE_INCREASE |
145 PMU_PERFMON_FLAG_ENABLE_DECREASE |
146 PMU_PERFMON_FLAG_CLEAR_PREV);
147
148 memset(&payload, 0, sizeof(struct pmu_payload));
149
150 /* TBD: PMU_PERFMON_PCT_TO_INC * 100 */
151 pv->set_perfmon_cntr_ut(pmu, 3000); /* 30% */
152 /* TBD: PMU_PERFMON_PCT_TO_DEC * 100 */
153 pv->set_perfmon_cntr_lt(pmu, 1000); /* 10% */
154 pv->set_perfmon_cntr_valid(pmu, true);
155
156 payload.in.buf = pv->get_perfmon_cntr_ptr(pmu);
157 payload.in.size = pv->get_perfmon_cntr_sz(pmu);
158 payload.in.offset =
159 pv->get_perfmon_cmd_start_offsetofvar(COUNTER_ALLOC);
160
161 nvgpu_pmu_dbg(g, "cmd post PMU_PERFMON_CMD_ID_START");
162 gk20a_pmu_cmd_post(g, &cmd, NULL, &payload, PMU_COMMAND_QUEUE_LPQ,
163 NULL, NULL, &seq, ~0);
164
165 return 0;
166}
167
168int nvgpu_pmu_perfmon_stop_sampling(struct nvgpu_pmu *pmu)
169{
170 struct gk20a *g = gk20a_from_pmu(pmu);
171 struct pmu_cmd cmd;
172 u32 seq;
173
174 /* PERFMON Stop */
175 memset(&cmd, 0, sizeof(struct pmu_cmd));
176 cmd.hdr.unit_id = get_perfmon_id(pmu);
177 if (cmd.hdr.unit_id == PMU_UNIT_INVALID) {
178 nvgpu_err(g, "failed to get perfmon UNIT ID, command skipped");
179 return -EINVAL;
180 }
181 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_perfmon_cmd_stop);
182 cmd.cmd.perfmon.stop.cmd_type = PMU_PERFMON_CMD_ID_STOP;
183
184 nvgpu_pmu_dbg(g, "cmd post PMU_PERFMON_CMD_ID_STOP");
185 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_LPQ,
186 NULL, NULL, &seq, ~0);
187 return 0;
188}
189
190int nvgpu_pmu_load_norm(struct gk20a *g, u32 *load)
191{
192 *load = g->pmu.load_shadow;
193 return 0;
194}
195
196int nvgpu_pmu_load_update(struct gk20a *g)
197{
198 struct nvgpu_pmu *pmu = &g->pmu;
199 u16 load = 0;
200
201 if (!pmu->perfmon_ready) {
202 pmu->load_shadow = 0;
203 return 0;
204 }
205
206 pmu_copy_from_dmem(pmu, pmu->sample_buffer, (u8 *)&load, 2, 0);
207 pmu->load_shadow = load / 10;
208 pmu->load_avg = (((9*pmu->load_avg) + pmu->load_shadow) / 10);
209
210 return 0;
211}
212
213void nvgpu_pmu_get_load_counters(struct gk20a *g, u32 *busy_cycles,
214 u32 *total_cycles)
215{
216 if (!g->power_on || gk20a_busy(g)) {
217 *busy_cycles = 0;
218 *total_cycles = 0;
219 return;
220 }
221
222 *busy_cycles = gk20a_pmu_read_idle_counter(g, 1);
223 *total_cycles = gk20a_pmu_read_idle_counter(g, 2);
224
225 gk20a_idle(g);
226}
227
228void nvgpu_pmu_reset_load_counters(struct gk20a *g)
229{
230 if (!g->power_on || gk20a_busy(g))
231 return;
232
233 gk20a_pmu_reset_idle_counter(g, 2);
234 gk20a_pmu_reset_idle_counter(g, 1);
235
236 gk20a_idle(g);
237}
238
239int nvgpu_pmu_handle_perfmon_event(struct nvgpu_pmu *pmu,
240 struct pmu_perfmon_msg *msg)
241{
242 struct gk20a *g = gk20a_from_pmu(pmu);
243
244 nvgpu_log_fn(g, " ");
245
246 switch (msg->msg_type) {
247 case PMU_PERFMON_MSG_ID_INCREASE_EVENT:
248 nvgpu_pmu_dbg(g, "perfmon increase event: ");
249 nvgpu_pmu_dbg(g, "state_id %d, ground_id %d, pct %d",
250 msg->gen.state_id, msg->gen.group_id, msg->gen.data);
251 (pmu->perfmon_events_cnt)++;
252 break;
253 case PMU_PERFMON_MSG_ID_DECREASE_EVENT:
254 nvgpu_pmu_dbg(g, "perfmon decrease event: ");
255 nvgpu_pmu_dbg(g, "state_id %d, ground_id %d, pct %d",
256 msg->gen.state_id, msg->gen.group_id, msg->gen.data);
257 (pmu->perfmon_events_cnt)++;
258 break;
259 case PMU_PERFMON_MSG_ID_INIT_EVENT:
260 pmu->perfmon_ready = 1;
261 nvgpu_pmu_dbg(g, "perfmon init event");
262 break;
263 default:
264 break;
265 }
266
267 /* restart sampling */
268 if (pmu->perfmon_sampling_enabled)
269 return nvgpu_pmu_perfmon_start_sampling(pmu);
270 return 0;
271}