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