summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/pmgr/pwrmonitor.c
diff options
context:
space:
mode:
authorLakshmanan M <lm@nvidia.com>2016-09-08 13:28:19 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:50 -0500
commit90f80a282eff04412858361df35c2f88372e88cb (patch)
tree4de1169e9bc3f02416a01c933175b613f9ccbdfd /drivers/gpu/nvgpu/pmgr/pwrmonitor.c
parentcb78f5aa749fcea198851ae4adf6e3acd47b37ac (diff)
gpu: nvgpu: Add pmgr support
This CL covers the following implementation, 1) Power Sensor Table parsing. 2) Power Topology Table parsing. 3) Add debugfs interface to get the current power(mW), current(mA) and voltage(uV) information from PMU. 4) Power Policy Table Parsing 5) Implement PMU boardobj interface for pmgr module. 6) Over current protection. JIRA DNVGPU-47 Change-Id: I7b1eefacc4f0a9824ab94ec8dcebefe81b7660d3 Signed-off-by: Lakshmanan M <lm@nvidia.com> Reviewed-on: http://git-master/r/1217189 (cherry picked from commit ecd0b16316cb4110118c6677f5f03e02921c29b6) Reviewed-on: http://git-master/r/1241953 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/gpu/nvgpu/pmgr/pwrmonitor.c')
-rw-r--r--drivers/gpu/nvgpu/pmgr/pwrmonitor.c365
1 files changed, 365 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/pmgr/pwrmonitor.c b/drivers/gpu/nvgpu/pmgr/pwrmonitor.c
new file mode 100644
index 00000000..c28751fd
--- /dev/null
+++ b/drivers/gpu/nvgpu/pmgr/pwrmonitor.c
@@ -0,0 +1,365 @@
1/*
2 * Copyright (c) 2016, 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 "gk20a/gk20a.h"
15#include "pwrdev.h"
16#include "include/bios.h"
17#include "boardobj/boardobjgrp.h"
18#include "boardobj/boardobjgrp_e32.h"
19#include "pmuif/gpmuifboardobj.h"
20#include "pmuif/gpmuifpmgr.h"
21#include "gm206/bios_gm206.h"
22#include "gk20a/pmu_gk20a.h"
23
24static u32 _pwr_channel_pmudata_instget(struct gk20a *g,
25 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
26 struct nv_pmu_boardobj **ppboardobjpmudata,
27 u8 idx)
28{
29 struct nv_pmu_pmgr_pwr_channel_desc *ppmgrchannel =
30 (struct nv_pmu_pmgr_pwr_channel_desc *)pmuboardobjgrp;
31
32 gk20a_dbg_info("");
33
34 /*check whether pmuboardobjgrp has a valid boardobj in index*/
35 if (((u32)BIT(idx) &
36 ppmgrchannel->hdr.data.super.obj_mask.super.data[0]) == 0)
37 return -EINVAL;
38
39 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
40 &ppmgrchannel->channels[idx].data.board_obj;
41
42 /* handle Global/common data here as we need index */
43 ppmgrchannel->channels[idx].data.pwr_channel.ch_idx = idx;
44
45 gk20a_dbg_info(" Done");
46
47 return 0;
48}
49
50static u32 _pwr_channel_rels_pmudata_instget(struct gk20a *g,
51 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
52 struct nv_pmu_boardobj **ppboardobjpmudata,
53 u8 idx)
54{
55 struct nv_pmu_pmgr_pwr_chrelationship_desc *ppmgrchrels =
56 (struct nv_pmu_pmgr_pwr_chrelationship_desc *)pmuboardobjgrp;
57
58 gk20a_dbg_info("");
59
60 /*check whether pmuboardobjgrp has a valid boardobj in index*/
61 if (((u32)BIT(idx) &
62 ppmgrchrels->hdr.data.super.obj_mask.super.data[0]) == 0)
63 return -EINVAL;
64
65 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
66 &ppmgrchrels->ch_rels[idx].data.board_obj;
67
68 gk20a_dbg_info(" Done");
69
70 return 0;
71}
72
73static u32 _pwr_channel_state_init(struct gk20a *g)
74{
75 u8 indx = 0;
76 struct pwr_channel *pchannel;
77 u32 objmask =
78 g->pmgr_pmu.pmgr_monitorobjs.pwr_channels.super.objmask;
79
80 /* Initialize each PWR_CHANNEL's dependent channel mask */
81 BOARDOBJGRP_FOR_EACH_INDEX_IN_MASK(32, indx, objmask) {
82 pchannel = PMGR_PWR_MONITOR_GET_PWR_CHANNEL(g, indx);
83 if (pchannel == NULL) {
84 gk20a_err(dev_from_gk20a(g),
85 "PMGR_PWR_MONITOR_GET_PWR_CHANNEL-failed %d", indx);
86 return -EINVAL;
87 }
88 pchannel->dependent_ch_mask =0;
89 }
90 BOARDOBJGRP_FOR_EACH_INDEX_IN_MASK_END
91
92 return 0;
93}
94
95static bool _pwr_channel_implements(struct pwr_channel *pchannel,
96 u8 type)
97{
98 return (type == BOARDOBJ_GET_TYPE(pchannel));
99}
100
101static u32 _pwr_domains_pmudatainit_sensor(struct gk20a *g,
102 struct boardobj *board_obj_ptr,
103 struct nv_pmu_boardobj *ppmudata)
104{
105 struct nv_pmu_pmgr_pwr_channel_sensor *pmu_sensor_data;
106 struct pwr_channel_sensor *sensor;
107 u32 status = 0;
108
109 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
110 if (status) {
111 gk20a_err(dev_from_gk20a(g),
112 "error updating pmu boardobjgrp for pwr sensor 0x%x",
113 status);
114 goto done;
115 }
116
117 sensor = (struct pwr_channel_sensor *)board_obj_ptr;
118 pmu_sensor_data = (struct nv_pmu_pmgr_pwr_channel_sensor *) ppmudata;
119
120 pmu_sensor_data->super.pwr_rail = sensor->super.pwr_rail;
121 pmu_sensor_data->super.volt_fixedu_v = sensor->super.volt_fixed_uv;
122 pmu_sensor_data->super.pwr_corr_slope = sensor->super.pwr_corr_slope;
123 pmu_sensor_data->super.pwr_corr_offsetm_w = sensor->super.pwr_corr_offset_mw;
124 pmu_sensor_data->super.curr_corr_slope = sensor->super.curr_corr_slope;
125 pmu_sensor_data->super.curr_corr_offsetm_a = sensor->super.curr_corr_offset_ma;
126 pmu_sensor_data->super.dependent_ch_mask = sensor->super.dependent_ch_mask;
127 pmu_sensor_data->super.ch_idx = 0;
128
129 pmu_sensor_data->pwr_dev_idx = sensor->pwr_dev_idx;
130 pmu_sensor_data->pwr_dev_prov_idx = sensor->pwr_dev_prov_idx;
131
132done:
133 return status;
134}
135
136static struct boardobj *construct_pwr_topology(struct gk20a *g,
137 void *pargs, u16 pargs_size, u8 type)
138{
139 struct boardobj *board_obj_ptr = NULL;
140 u32 status;
141 struct pwr_channel_sensor *pwrchannel;
142 struct pwr_channel_sensor *sensor = (struct pwr_channel_sensor*)pargs;
143
144 status = boardobj_construct_super(g, &board_obj_ptr,
145 pargs_size, pargs);
146 if (status)
147 return NULL;
148
149 pwrchannel = (struct pwr_channel_sensor*)board_obj_ptr;
150
151 /* Set Super class interfaces */
152 board_obj_ptr->pmudatainit = _pwr_domains_pmudatainit_sensor;
153
154 pwrchannel->super.pwr_rail = sensor->super.pwr_rail;
155 pwrchannel->super.volt_fixed_uv = sensor->super.volt_fixed_uv;
156 pwrchannel->super.pwr_corr_slope = sensor->super.pwr_corr_slope;
157 pwrchannel->super.pwr_corr_offset_mw = sensor->super.pwr_corr_offset_mw;
158 pwrchannel->super.curr_corr_slope = sensor->super.curr_corr_slope;
159 pwrchannel->super.curr_corr_offset_ma = sensor->super.curr_corr_offset_ma;
160 pwrchannel->super.dependent_ch_mask = 0;
161
162 pwrchannel->pwr_dev_idx = sensor->pwr_dev_idx;
163 pwrchannel->pwr_dev_prov_idx = sensor->pwr_dev_prov_idx;
164
165 gk20a_dbg_info(" Done");
166
167 return board_obj_ptr;
168}
169
170static u32 devinit_get_pwr_topology_table(struct gk20a *g,
171 struct pmgr_pwr_monitor *ppwrmonitorobjs)
172{
173 u32 status = 0;
174 u8 *pwr_topology_table_ptr = NULL;
175 u8 *curr_pwr_topology_table_ptr = NULL;
176 struct boardobj *boardobj;
177 struct pwr_topology_2x_header pwr_topology_table_header = { 0 };
178 struct pwr_topology_2x_entry pwr_topology_table_entry = { 0 };
179 u32 index;
180 u32 obj_index = 0;
181 u16 pwr_topology_size;
182 union {
183 struct boardobj boardobj;
184 struct pwr_channel pwrchannel;
185 struct pwr_channel_sensor sensor;
186 } pwr_topology_data;
187
188 gk20a_dbg_info("");
189
190 if (g->ops.bios.get_perf_table_ptrs != NULL) {
191 pwr_topology_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
192 g->bios.perf_token, POWER_TOPOLOGY_TABLE);
193 if (pwr_topology_table_ptr == NULL) {
194 status = -EINVAL;
195 goto done;
196 }
197 }
198
199 memcpy(&pwr_topology_table_header, pwr_topology_table_ptr,
200 VBIOS_POWER_TOPOLOGY_2X_HEADER_SIZE_06);
201
202 if (pwr_topology_table_header.version !=
203 VBIOS_POWER_TOPOLOGY_VERSION_2X) {
204 status = -EINVAL;
205 goto done;
206 }
207
208 g->pmgr_pmu.pmgr_monitorobjs.b_is_topology_tbl_ver_1x = false;
209
210 if (pwr_topology_table_header.header_size <
211 VBIOS_POWER_TOPOLOGY_2X_HEADER_SIZE_06) {
212 status = -EINVAL;
213 goto done;
214 }
215
216 if (pwr_topology_table_header.table_entry_size !=
217 VBIOS_POWER_TOPOLOGY_2X_ENTRY_SIZE_16) {
218 status = -EINVAL;
219 goto done;
220 }
221
222 curr_pwr_topology_table_ptr = (pwr_topology_table_ptr +
223 VBIOS_POWER_TOPOLOGY_2X_HEADER_SIZE_06);
224
225 for (index = 0; index < pwr_topology_table_header.num_table_entries;
226 index++) {
227 u8 class_type;
228
229 curr_pwr_topology_table_ptr += (pwr_topology_table_header.table_entry_size * index);
230
231 pwr_topology_table_entry.flags0 = *curr_pwr_topology_table_ptr;
232 pwr_topology_table_entry.pwr_rail = *(curr_pwr_topology_table_ptr + 1);
233
234 memcpy(&pwr_topology_table_entry.param0,
235 (curr_pwr_topology_table_ptr + 2),
236 (VBIOS_POWER_TOPOLOGY_2X_ENTRY_SIZE_16 - 2));
237
238 class_type = (u8)BIOS_GET_FIELD(
239 pwr_topology_table_entry.flags0,
240 NV_VBIOS_POWER_TOPOLOGY_2X_ENTRY_FLAGS0_CLASS);
241
242 if (class_type == NV_VBIOS_POWER_TOPOLOGY_2X_ENTRY_FLAGS0_CLASS_SENSOR) {
243 pwr_topology_data.sensor.pwr_dev_idx = (u8)BIOS_GET_FIELD(
244 pwr_topology_table_entry.param1,
245 NV_VBIOS_POWER_TOPOLOGY_2X_ENTRY_PARAM1_SENSOR_INDEX);
246 pwr_topology_data.sensor.pwr_dev_prov_idx = (u8)BIOS_GET_FIELD(
247 pwr_topology_table_entry.param1,
248 NV_VBIOS_POWER_TOPOLOGY_2X_ENTRY_PARAM1_SENSOR_PROVIDER_INDEX);
249
250 pwr_topology_size = sizeof(struct pwr_channel_sensor);
251 } else
252 continue;
253
254 /* Initialize data for the parent class */
255 pwr_topology_data.boardobj.type = CTRL_PMGR_PWR_CHANNEL_TYPE_SENSOR;
256 pwr_topology_data.pwrchannel.pwr_rail = (u8)pwr_topology_table_entry.pwr_rail;
257 pwr_topology_data.pwrchannel.volt_fixed_uv = pwr_topology_table_entry.param0;
258 pwr_topology_data.pwrchannel.pwr_corr_slope = (1 << 12);
259 pwr_topology_data.pwrchannel.pwr_corr_offset_mw = 0;
260 pwr_topology_data.pwrchannel.curr_corr_slope =
261 (u32)pwr_topology_table_entry.curr_corr_slope;
262 pwr_topology_data.pwrchannel.curr_corr_offset_ma =
263 (s32)pwr_topology_table_entry.curr_corr_offset;
264
265 boardobj = construct_pwr_topology(g, &pwr_topology_data,
266 pwr_topology_size, pwr_topology_data.boardobj.type);
267
268 if (!boardobj) {
269 gk20a_err(dev_from_gk20a(g),
270 "unable to create pwr topology for %d type %d",
271 index, pwr_topology_data.boardobj.type);
272 status = -EINVAL;
273 goto done;
274 }
275
276 status = boardobjgrp_objinsert(&ppwrmonitorobjs->pwr_channels.super,
277 boardobj, obj_index);
278
279 if (status) {
280 gk20a_err(dev_from_gk20a(g),
281 "unable to insert pwr topology boardobj for %d", index);
282 status = -EINVAL;
283 goto done;
284 }
285
286 ++obj_index;
287 }
288
289done:
290 gk20a_dbg_info(" done status %x", status);
291 return status;
292}
293
294u32 pmgr_monitor_sw_setup(struct gk20a *g)
295{
296 u32 status;
297 struct boardobjgrp *pboardobjgrp = NULL;
298 struct pwr_channel *pchannel;
299 struct pmgr_pwr_monitor *ppwrmonitorobjs;
300 u8 indx = 0;
301
302 /* Construct the Super Class and override the Interfaces */
303 status = boardobjgrpconstruct_e32(
304 &g->pmgr_pmu.pmgr_monitorobjs.pwr_channels);
305 if (status) {
306 gk20a_err(dev_from_gk20a(g),
307 "error creating boardobjgrp for pmgr channel, status - 0x%x",
308 status);
309 goto done;
310 }
311
312 pboardobjgrp = &(g->pmgr_pmu.pmgr_monitorobjs.pwr_channels.super);
313
314 /* Override the Interfaces */
315 pboardobjgrp->pmudatainstget = _pwr_channel_pmudata_instget;
316
317 /* Construct the Super Class and override the Interfaces */
318 status = boardobjgrpconstruct_e32(
319 &g->pmgr_pmu.pmgr_monitorobjs.pwr_ch_rels);
320 if (status) {
321 gk20a_err(dev_from_gk20a(g),
322 "error creating boardobjgrp for pmgr channel relationship, status - 0x%x",
323 status);
324 goto done;
325 }
326
327 pboardobjgrp = &(g->pmgr_pmu.pmgr_monitorobjs.pwr_ch_rels.super);
328
329 /* Override the Interfaces */
330 pboardobjgrp->pmudatainstget = _pwr_channel_rels_pmudata_instget;
331
332 /* Initialize the Total GPU Power Channel Mask to 0 */
333 g->pmgr_pmu.pmgr_monitorobjs.pmu_data.channels.hdr.data.total_gpu_power_channel_mask = 0;
334 g->pmgr_pmu.pmgr_monitorobjs.total_gpu_channel_idx =
335 CTRL_PMGR_PWR_CHANNEL_INDEX_INVALID;
336
337 /* Supported topology table version 1.0 */
338 g->pmgr_pmu.pmgr_monitorobjs.b_is_topology_tbl_ver_1x = true;
339
340 ppwrmonitorobjs = &(g->pmgr_pmu.pmgr_monitorobjs);
341
342 status = devinit_get_pwr_topology_table(g, ppwrmonitorobjs);
343 if (status)
344 goto done;
345
346 status = _pwr_channel_state_init(g);
347 if (status)
348 goto done;
349
350 /* Initialise physicalChannelMask */
351 g->pmgr_pmu.pmgr_monitorobjs.physical_channel_mask = 0;
352
353 pboardobjgrp = &g->pmgr_pmu.pmgr_monitorobjs.pwr_channels.super;
354
355 BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct pwr_channel *, pchannel, indx) {
356 if (_pwr_channel_implements(pchannel,
357 CTRL_PMGR_PWR_CHANNEL_TYPE_SENSOR)) {
358 g->pmgr_pmu.pmgr_monitorobjs.physical_channel_mask |= BIT(indx);
359 }
360 }
361
362done:
363 gk20a_dbg_info(" done status %x", status);
364 return status;
365}