diff options
Diffstat (limited to 'drivers/gpu/nvgpu/pmgr/pwrmonitor.c')
-rw-r--r-- | drivers/gpu/nvgpu/pmgr/pwrmonitor.c | 370 |
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 | |||
31 | static 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 | |||
57 | static 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 | |||
80 | static 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 | |||
102 | static bool _pwr_channel_implements(struct pwr_channel *pchannel, | ||
103 | u8 type) | ||
104 | { | ||
105 | return (type == BOARDOBJ_GET_TYPE(pchannel)); | ||
106 | } | ||
107 | |||
108 | static 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 | |||
139 | done: | ||
140 | return status; | ||
141 | } | ||
142 | |||
143 | static 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 | |||
177 | static 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 | |||
294 | done: | ||
295 | gk20a_dbg_info(" done status %x", status); | ||
296 | return status; | ||
297 | } | ||
298 | |||
299 | u32 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 | |||
367 | done: | ||
368 | gk20a_dbg_info(" done status %x", status); | ||
369 | return status; | ||
370 | } | ||