diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2016-12-27 05:01:00 -0500 |
---|---|---|
committer | Deepak Nibade <dnibade@nvidia.com> | 2016-12-27 05:35:06 -0500 |
commit | 7a81883a0d70c3a43ad2841ac235f6dc344c60fb (patch) | |
tree | 92923d2efccf90d1961071fa9acde59178a0d688 /drivers/gpu/nvgpu/pmgr/pwrpolicy.c | |
parent | 505b442551a2e27aa3bc9e608c5a2bc9fccecbc4 (diff) | |
parent | 2aa3c85f8e82b3c07c39e677663abd3687c1822a (diff) |
Merge remote-tracking branch 'remotes/origin/dev/merge-nvgpu-t18x-into-nvgpu' into dev-kernel
Merge T186 - gp10b/gp106 code into common nvgpu repo
Bug 200266498
Change-Id: Ibf100ee38010cbed85c149b69b99147256f9a005
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/pmgr/pwrpolicy.c')
-rw-r--r-- | drivers/gpu/nvgpu/pmgr/pwrpolicy.c | 765 |
1 files changed, 765 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/pmgr/pwrpolicy.c b/drivers/gpu/nvgpu/pmgr/pwrpolicy.c new file mode 100644 index 00000000..d7926773 --- /dev/null +++ b/drivers/gpu/nvgpu/pmgr/pwrpolicy.c | |||
@@ -0,0 +1,765 @@ | |||
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 "pwrpolicy.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 | |||
24 | #define _pwr_policy_limitarboutputget_helper(p_limit_arb) (p_limit_arb)->output | ||
25 | #define _pwr_policy_limitdeltaapply(limit, delta) ((u32)max(((s32)limit) + (delta), 0)) | ||
26 | |||
27 | static u32 _pwr_policy_limitarbinputset_helper(struct gk20a *g, | ||
28 | struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb, | ||
29 | u8 client_idx, | ||
30 | u32 limit_value) | ||
31 | { | ||
32 | u8 indx; | ||
33 | bool b_found = false; | ||
34 | u32 status = 0; | ||
35 | u32 output = limit_value; | ||
36 | |||
37 | for (indx = 0; indx< p_limit_arb->num_inputs; indx++) { | ||
38 | if (p_limit_arb->inputs[indx].pwr_policy_idx == client_idx) { | ||
39 | p_limit_arb->inputs[indx].limit_value = limit_value; | ||
40 | b_found = true; | ||
41 | } else if (p_limit_arb->b_arb_max) { | ||
42 | output = max(output, p_limit_arb->inputs[indx].limit_value); | ||
43 | } else { | ||
44 | output = min(output, p_limit_arb->inputs[indx].limit_value); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | if (!b_found) { | ||
49 | if (p_limit_arb->num_inputs < | ||
50 | CTRL_PMGR_PWR_POLICY_MAX_LIMIT_INPUTS) { | ||
51 | p_limit_arb->inputs[ | ||
52 | p_limit_arb->num_inputs].pwr_policy_idx = client_idx; | ||
53 | p_limit_arb->inputs[ | ||
54 | p_limit_arb->num_inputs].limit_value = limit_value; | ||
55 | p_limit_arb->num_inputs++; | ||
56 | } else { | ||
57 | gk20a_err(g->dev, "No entries remaining for clientIdx=%d", | ||
58 | client_idx); | ||
59 | status = -EINVAL; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | if (!status) { | ||
64 | p_limit_arb->output = output; | ||
65 | } | ||
66 | |||
67 | return status; | ||
68 | } | ||
69 | |||
70 | static u32 _pwr_policy_limitid_translate(struct gk20a *g, | ||
71 | struct pwr_policy *ppolicy, | ||
72 | enum pwr_policy_limit_id limit_id, | ||
73 | struct ctrl_pmgr_pwr_policy_limit_arbitration **p_limit_arb, | ||
74 | struct ctrl_pmgr_pwr_policy_limit_arbitration **p_limit_arb_sec) | ||
75 | { | ||
76 | u32 status = 0; | ||
77 | |||
78 | switch (limit_id) { | ||
79 | case PWR_POLICY_LIMIT_ID_MIN: | ||
80 | *p_limit_arb = &ppolicy->limit_arb_min; | ||
81 | break; | ||
82 | |||
83 | case PWR_POLICY_LIMIT_ID_RATED: | ||
84 | *p_limit_arb = &ppolicy->limit_arb_rated; | ||
85 | |||
86 | if (p_limit_arb_sec != NULL) { | ||
87 | *p_limit_arb_sec = &ppolicy->limit_arb_curr; | ||
88 | } | ||
89 | break; | ||
90 | |||
91 | case PWR_POLICY_LIMIT_ID_MAX: | ||
92 | *p_limit_arb = &ppolicy->limit_arb_max; | ||
93 | break; | ||
94 | |||
95 | case PWR_POLICY_LIMIT_ID_CURR: | ||
96 | *p_limit_arb = &ppolicy->limit_arb_curr; | ||
97 | break; | ||
98 | |||
99 | case PWR_POLICY_LIMIT_ID_BATT: | ||
100 | *p_limit_arb = &ppolicy->limit_arb_batt; | ||
101 | break; | ||
102 | |||
103 | default: | ||
104 | gk20a_err(g->dev, "Unsupported limitId=%d", | ||
105 | limit_id); | ||
106 | status = -EINVAL; | ||
107 | break; | ||
108 | } | ||
109 | |||
110 | return status; | ||
111 | } | ||
112 | |||
113 | static u32 _pwr_policy_limitarbinputset(struct gk20a *g, | ||
114 | struct pwr_policy *ppolicy, | ||
115 | enum pwr_policy_limit_id limit_id, | ||
116 | u8 client_idx, | ||
117 | u32 limit) | ||
118 | { | ||
119 | u32 status = 0; | ||
120 | struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb = NULL; | ||
121 | struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb_sec = NULL; | ||
122 | |||
123 | status = _pwr_policy_limitid_translate(g, | ||
124 | ppolicy, | ||
125 | limit_id, | ||
126 | &p_limit_arb, | ||
127 | &p_limit_arb_sec); | ||
128 | if (status) { | ||
129 | goto exit; | ||
130 | } | ||
131 | |||
132 | status = _pwr_policy_limitarbinputset_helper(g, p_limit_arb, client_idx, limit); | ||
133 | if (status) { | ||
134 | gk20a_err(g->dev, | ||
135 | "Error setting client limit value: status=0x%08x, limitId=0x%x, clientIdx=0x%x, limit=%d", | ||
136 | status, limit_id, client_idx, limit); | ||
137 | goto exit; | ||
138 | } | ||
139 | |||
140 | if (NULL != p_limit_arb_sec) { | ||
141 | status = _pwr_policy_limitarbinputset_helper(g, p_limit_arb_sec, | ||
142 | CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, | ||
143 | _pwr_policy_limitarboutputget_helper(p_limit_arb)); | ||
144 | } | ||
145 | |||
146 | exit: | ||
147 | return status; | ||
148 | } | ||
149 | |||
150 | static inline void _pwr_policy_limitarbconstruct( | ||
151 | struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb, | ||
152 | bool b_arb_max) | ||
153 | { | ||
154 | p_limit_arb->num_inputs = 0; | ||
155 | p_limit_arb->b_arb_max = b_arb_max; | ||
156 | } | ||
157 | |||
158 | static u32 _pwr_policy_limitarboutputget(struct gk20a *g, | ||
159 | struct pwr_policy *ppolicy, | ||
160 | enum pwr_policy_limit_id limit_id) | ||
161 | { | ||
162 | u32 status = 0; | ||
163 | struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb = NULL; | ||
164 | |||
165 | status = _pwr_policy_limitid_translate(g, | ||
166 | ppolicy, | ||
167 | limit_id, | ||
168 | &p_limit_arb, | ||
169 | NULL); | ||
170 | if (status) { | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | return _pwr_policy_limitarboutputget_helper(p_limit_arb); | ||
175 | } | ||
176 | |||
177 | static u32 _pwr_domains_pmudatainit_hw_threshold(struct gk20a *g, | ||
178 | struct boardobj *board_obj_ptr, | ||
179 | struct nv_pmu_boardobj *ppmudata) | ||
180 | { | ||
181 | struct nv_pmu_pmgr_pwr_policy_hw_threshold *pmu_hw_threshold_data; | ||
182 | struct pwr_policy_hw_threshold *p_hw_threshold; | ||
183 | struct pwr_policy *p_pwr_policy; | ||
184 | struct nv_pmu_pmgr_pwr_policy *pmu_pwr_policy; | ||
185 | u32 status = 0; | ||
186 | |||
187 | status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
188 | if (status) { | ||
189 | gk20a_err(dev_from_gk20a(g), | ||
190 | "error updating pmu boardobjgrp for pwr sensor 0x%x", | ||
191 | status); | ||
192 | status = -ENOMEM; | ||
193 | goto done; | ||
194 | } | ||
195 | |||
196 | p_hw_threshold = (struct pwr_policy_hw_threshold *)board_obj_ptr; | ||
197 | pmu_hw_threshold_data = (struct nv_pmu_pmgr_pwr_policy_hw_threshold *) ppmudata; | ||
198 | pmu_pwr_policy = (struct nv_pmu_pmgr_pwr_policy *) ppmudata; | ||
199 | p_pwr_policy = (struct pwr_policy *)&(p_hw_threshold->super.super); | ||
200 | |||
201 | pmu_pwr_policy->ch_idx = 0; | ||
202 | pmu_pwr_policy->limit_unit = p_pwr_policy->limit_unit; | ||
203 | pmu_pwr_policy->num_limit_inputs = p_pwr_policy->num_limit_inputs; | ||
204 | |||
205 | pmu_pwr_policy->limit_min = _pwr_policy_limitdeltaapply( | ||
206 | _pwr_policy_limitarboutputget(g, p_pwr_policy, | ||
207 | PWR_POLICY_LIMIT_ID_MIN), | ||
208 | p_pwr_policy->limit_delta); | ||
209 | |||
210 | pmu_pwr_policy->limit_max = _pwr_policy_limitdeltaapply( | ||
211 | _pwr_policy_limitarboutputget(g, p_pwr_policy, | ||
212 | PWR_POLICY_LIMIT_ID_MAX), | ||
213 | p_pwr_policy->limit_delta); | ||
214 | |||
215 | pmu_pwr_policy->limit_curr = _pwr_policy_limitdeltaapply( | ||
216 | _pwr_policy_limitarboutputget(g, p_pwr_policy, | ||
217 | PWR_POLICY_LIMIT_ID_CURR), | ||
218 | p_pwr_policy->limit_delta); | ||
219 | |||
220 | memcpy(&pmu_pwr_policy->integral, &p_pwr_policy->integral, | ||
221 | sizeof(struct ctrl_pmgr_pwr_policy_info_integral)); | ||
222 | |||
223 | pmu_pwr_policy->sample_mult = p_pwr_policy->sample_mult; | ||
224 | pmu_pwr_policy->filter_type = p_pwr_policy->filter_type; | ||
225 | pmu_pwr_policy->filter_param = p_pwr_policy->filter_param; | ||
226 | |||
227 | pmu_hw_threshold_data->threshold_idx = p_hw_threshold->threshold_idx; | ||
228 | pmu_hw_threshold_data->low_threshold_idx = p_hw_threshold->low_threshold_idx; | ||
229 | pmu_hw_threshold_data->b_use_low_threshold = p_hw_threshold->b_use_low_threshold; | ||
230 | pmu_hw_threshold_data->low_threshold_value = p_hw_threshold->low_threshold_value; | ||
231 | |||
232 | if (BOARDOBJ_GET_TYPE(board_obj_ptr) == | ||
233 | CTRL_PMGR_PWR_POLICY_TYPE_SW_THRESHOLD) { | ||
234 | struct nv_pmu_pmgr_pwr_policy_sw_threshold *pmu_sw_threshold_data; | ||
235 | struct pwr_policy_sw_threshold *p_sw_threshold; | ||
236 | |||
237 | p_sw_threshold = (struct pwr_policy_sw_threshold *)board_obj_ptr; | ||
238 | pmu_sw_threshold_data = | ||
239 | (struct nv_pmu_pmgr_pwr_policy_sw_threshold *) ppmudata; | ||
240 | pmu_sw_threshold_data->event_id = | ||
241 | p_sw_threshold->event_id; | ||
242 | } | ||
243 | done: | ||
244 | return status; | ||
245 | } | ||
246 | |||
247 | static struct boardobj *construct_pwr_policy(struct gk20a *g, | ||
248 | void *pargs, u16 pargs_size, u8 type) | ||
249 | { | ||
250 | struct boardobj *board_obj_ptr = NULL; | ||
251 | u32 status; | ||
252 | struct pwr_policy_hw_threshold *pwrpolicyhwthreshold; | ||
253 | struct pwr_policy *pwrpolicy; | ||
254 | struct pwr_policy *pwrpolicyparams = (struct pwr_policy*)pargs; | ||
255 | struct pwr_policy_hw_threshold *hwthreshold = (struct pwr_policy_hw_threshold*)pargs; | ||
256 | |||
257 | status = boardobj_construct_super(g, &board_obj_ptr, | ||
258 | pargs_size, pargs); | ||
259 | if (status) | ||
260 | return NULL; | ||
261 | |||
262 | pwrpolicyhwthreshold = (struct pwr_policy_hw_threshold*)board_obj_ptr; | ||
263 | pwrpolicy = (struct pwr_policy *)board_obj_ptr; | ||
264 | |||
265 | /* Set Super class interfaces */ | ||
266 | board_obj_ptr->pmudatainit = _pwr_domains_pmudatainit_hw_threshold; | ||
267 | |||
268 | pwrpolicy->ch_idx = pwrpolicyparams->ch_idx; | ||
269 | pwrpolicy->num_limit_inputs = 0; | ||
270 | pwrpolicy->limit_unit = pwrpolicyparams->limit_unit; | ||
271 | pwrpolicy->filter_type = (enum ctrl_pmgr_pwr_policy_filter_type)(pwrpolicyparams->filter_type); | ||
272 | pwrpolicy->sample_mult = pwrpolicyparams->sample_mult; | ||
273 | switch (pwrpolicy->filter_type) | ||
274 | { | ||
275 | case CTRL_PMGR_PWR_POLICY_FILTER_TYPE_NONE: | ||
276 | break; | ||
277 | |||
278 | case CTRL_PMGR_PWR_POLICY_FILTER_TYPE_BLOCK: | ||
279 | pwrpolicy->filter_param.block.block_size = | ||
280 | pwrpolicyparams->filter_param.block.block_size; | ||
281 | break; | ||
282 | |||
283 | case CTRL_PMGR_PWR_POLICY_FILTER_TYPE_MOVING_AVERAGE: | ||
284 | pwrpolicy->filter_param.moving_avg.window_size = | ||
285 | pwrpolicyparams->filter_param.moving_avg.window_size; | ||
286 | break; | ||
287 | |||
288 | case CTRL_PMGR_PWR_POLICY_FILTER_TYPE_IIR: | ||
289 | pwrpolicy->filter_param.iir.divisor = pwrpolicyparams->filter_param.iir.divisor; | ||
290 | break; | ||
291 | |||
292 | default: | ||
293 | gk20a_err(g->dev, | ||
294 | "Error: unrecognized Power Policy filter type: %d.\n", | ||
295 | pwrpolicy->filter_type); | ||
296 | } | ||
297 | |||
298 | _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_curr, false); | ||
299 | |||
300 | pwrpolicy->limit_delta = 0; | ||
301 | |||
302 | _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_min, true); | ||
303 | status = _pwr_policy_limitarbinputset(g, | ||
304 | pwrpolicy, | ||
305 | PWR_POLICY_LIMIT_ID_MIN, | ||
306 | CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, | ||
307 | pwrpolicyparams->limit_min); | ||
308 | |||
309 | _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_max, false); | ||
310 | status = _pwr_policy_limitarbinputset(g, | ||
311 | pwrpolicy, | ||
312 | PWR_POLICY_LIMIT_ID_MAX, | ||
313 | CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, | ||
314 | pwrpolicyparams->limit_max); | ||
315 | |||
316 | _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_rated, false); | ||
317 | status = _pwr_policy_limitarbinputset(g, | ||
318 | pwrpolicy, | ||
319 | PWR_POLICY_LIMIT_ID_RATED, | ||
320 | CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, | ||
321 | pwrpolicyparams->limit_rated); | ||
322 | |||
323 | _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_batt, false); | ||
324 | status = _pwr_policy_limitarbinputset(g, | ||
325 | pwrpolicy, | ||
326 | PWR_POLICY_LIMIT_ID_BATT, | ||
327 | CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, | ||
328 | ((pwrpolicyparams->limit_batt != 0) ? | ||
329 | pwrpolicyparams->limit_batt: | ||
330 | CTRL_PMGR_PWR_POLICY_LIMIT_MAX)); | ||
331 | |||
332 | memcpy(&pwrpolicy->integral, &pwrpolicyparams->integral, | ||
333 | sizeof(struct ctrl_pmgr_pwr_policy_info_integral)); | ||
334 | |||
335 | pwrpolicyhwthreshold->threshold_idx = hwthreshold->threshold_idx; | ||
336 | pwrpolicyhwthreshold->b_use_low_threshold = hwthreshold->b_use_low_threshold; | ||
337 | pwrpolicyhwthreshold->low_threshold_idx = hwthreshold->low_threshold_idx; | ||
338 | pwrpolicyhwthreshold->low_threshold_value = hwthreshold->low_threshold_value; | ||
339 | |||
340 | if (type == CTRL_PMGR_PWR_POLICY_TYPE_SW_THRESHOLD) { | ||
341 | struct pwr_policy_sw_threshold *pwrpolicyswthreshold; | ||
342 | struct pwr_policy_sw_threshold *swthreshold = | ||
343 | (struct pwr_policy_sw_threshold*)pargs; | ||
344 | |||
345 | pwrpolicyswthreshold = (struct pwr_policy_sw_threshold*)board_obj_ptr; | ||
346 | pwrpolicyswthreshold->event_id = swthreshold->event_id; | ||
347 | } | ||
348 | |||
349 | gk20a_dbg_info(" Done"); | ||
350 | |||
351 | return board_obj_ptr; | ||
352 | } | ||
353 | |||
354 | static u32 _pwr_policy_construct_WAR_policy(struct gk20a *g, | ||
355 | struct pmgr_pwr_policy *ppwrpolicyobjs, | ||
356 | union pwr_policy_data_union *ppwrpolicydata, | ||
357 | u16 pwr_policy_size, | ||
358 | u32 hw_threshold_policy_index, | ||
359 | u32 obj_index) | ||
360 | { | ||
361 | u32 status = 0; | ||
362 | struct boardobj *boardobj; | ||
363 | |||
364 | if (!(hw_threshold_policy_index & 0x1)) { | ||
365 | /* CRIT policy */ | ||
366 | ppwrpolicydata->pwrpolicy.limit_min = 1000; | ||
367 | ppwrpolicydata->pwrpolicy.limit_rated = 20000; | ||
368 | ppwrpolicydata->pwrpolicy.limit_max = 20000; | ||
369 | ppwrpolicydata->hw_threshold.threshold_idx = 0; | ||
370 | } else { | ||
371 | /* WARN policy */ | ||
372 | ppwrpolicydata->pwrpolicy.limit_min = 1000; | ||
373 | ppwrpolicydata->pwrpolicy.limit_rated = 11600; | ||
374 | ppwrpolicydata->pwrpolicy.limit_max = 11600; | ||
375 | ppwrpolicydata->hw_threshold.threshold_idx = 1; | ||
376 | } | ||
377 | |||
378 | boardobj = construct_pwr_policy(g, ppwrpolicydata, | ||
379 | pwr_policy_size, ppwrpolicydata->boardobj.type); | ||
380 | |||
381 | if (!boardobj) { | ||
382 | gk20a_err(dev_from_gk20a(g), | ||
383 | "unable to create pwr policy for type %d", ppwrpolicydata->boardobj.type); | ||
384 | status = -EINVAL; | ||
385 | goto done; | ||
386 | } | ||
387 | |||
388 | status = boardobjgrp_objinsert(&ppwrpolicyobjs->pwr_policies.super, | ||
389 | boardobj, obj_index); | ||
390 | |||
391 | if (status) { | ||
392 | gk20a_err(dev_from_gk20a(g), | ||
393 | "unable to insert pwr policy boardobj for %d", obj_index); | ||
394 | status = -EINVAL; | ||
395 | goto done; | ||
396 | } | ||
397 | done: | ||
398 | return status; | ||
399 | } | ||
400 | |||
401 | static u32 _pwr_policy_construct_WAR_SW_Threshold_policy(struct gk20a *g, | ||
402 | struct pmgr_pwr_policy *ppwrpolicyobjs, | ||
403 | union pwr_policy_data_union *ppwrpolicydata, | ||
404 | u16 pwr_policy_size, | ||
405 | u32 obj_index) | ||
406 | { | ||
407 | u32 status = 0; | ||
408 | struct boardobj *boardobj; | ||
409 | |||
410 | /* WARN policy */ | ||
411 | ppwrpolicydata->pwrpolicy.limit_unit = 0; | ||
412 | ppwrpolicydata->pwrpolicy.limit_min = 10000; | ||
413 | ppwrpolicydata->pwrpolicy.limit_rated = 100000; | ||
414 | ppwrpolicydata->pwrpolicy.limit_max = 100000; | ||
415 | ppwrpolicydata->sw_threshold.threshold_idx = 1; | ||
416 | ppwrpolicydata->pwrpolicy.filter_type = | ||
417 | CTRL_PMGR_PWR_POLICY_FILTER_TYPE_MOVING_AVERAGE; | ||
418 | ppwrpolicydata->pwrpolicy.sample_mult = 5; | ||
419 | |||
420 | /* Filled the entry.filterParam value in the filterParam */ | ||
421 | ppwrpolicydata->pwrpolicy.filter_param.moving_avg.window_size = 10; | ||
422 | |||
423 | ppwrpolicydata->sw_threshold.event_id = 0x01; | ||
424 | |||
425 | ppwrpolicydata->boardobj.type = CTRL_PMGR_PWR_POLICY_TYPE_SW_THRESHOLD; | ||
426 | |||
427 | boardobj = construct_pwr_policy(g, ppwrpolicydata, | ||
428 | pwr_policy_size, ppwrpolicydata->boardobj.type); | ||
429 | |||
430 | if (!boardobj) { | ||
431 | gk20a_err(dev_from_gk20a(g), | ||
432 | "unable to create pwr policy for type %d", ppwrpolicydata->boardobj.type); | ||
433 | status = -EINVAL; | ||
434 | goto done; | ||
435 | } | ||
436 | |||
437 | status = boardobjgrp_objinsert(&ppwrpolicyobjs->pwr_policies.super, | ||
438 | boardobj, obj_index); | ||
439 | |||
440 | if (status) { | ||
441 | gk20a_err(dev_from_gk20a(g), | ||
442 | "unable to insert pwr policy boardobj for %d", obj_index); | ||
443 | status = -EINVAL; | ||
444 | goto done; | ||
445 | } | ||
446 | done: | ||
447 | return status; | ||
448 | } | ||
449 | |||
450 | static u32 devinit_get_pwr_policy_table(struct gk20a *g, | ||
451 | struct pmgr_pwr_policy *ppwrpolicyobjs) | ||
452 | { | ||
453 | u32 status = 0; | ||
454 | u8 *pwr_policy_table_ptr = NULL; | ||
455 | u8 *curr_pwr_policy_table_ptr = NULL; | ||
456 | struct boardobj *boardobj; | ||
457 | struct pwr_policy_3x_header_struct pwr_policy_table_header = { 0 }; | ||
458 | struct pwr_policy_3x_entry_struct pwr_policy_table_entry = { 0 }; | ||
459 | u32 index; | ||
460 | u32 obj_index = 0; | ||
461 | u16 pwr_policy_size; | ||
462 | bool integral_control = false; | ||
463 | u32 hw_threshold_policy_index = 0; | ||
464 | u32 sw_threshold_policy_index = 0; | ||
465 | union pwr_policy_data_union pwr_policy_data; | ||
466 | |||
467 | gk20a_dbg_info(""); | ||
468 | |||
469 | if (g->ops.bios.get_perf_table_ptrs != NULL) { | ||
470 | pwr_policy_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g, | ||
471 | g->bios.perf_token, POWER_CAPPING_TABLE); | ||
472 | if (pwr_policy_table_ptr == NULL) { | ||
473 | status = -EINVAL; | ||
474 | goto done; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | memcpy(&pwr_policy_table_header.version, | ||
479 | (pwr_policy_table_ptr), | ||
480 | 14); | ||
481 | |||
482 | memcpy(&pwr_policy_table_header.d2_limit, | ||
483 | (pwr_policy_table_ptr + 14), | ||
484 | (VBIOS_POWER_POLICY_3X_ENTRY_SIZE_2E - 14)); | ||
485 | |||
486 | if (pwr_policy_table_header.version != | ||
487 | VBIOS_POWER_POLICY_VERSION_3X) { | ||
488 | status = -EINVAL; | ||
489 | goto done; | ||
490 | } | ||
491 | |||
492 | if (pwr_policy_table_header.header_size < | ||
493 | VBIOS_POWER_POLICY_3X_HEADER_SIZE_25) { | ||
494 | status = -EINVAL; | ||
495 | goto done; | ||
496 | } | ||
497 | |||
498 | if (pwr_policy_table_header.table_entry_size != | ||
499 | VBIOS_POWER_POLICY_3X_ENTRY_SIZE_2E) { | ||
500 | status = -EINVAL; | ||
501 | goto done; | ||
502 | } | ||
503 | |||
504 | curr_pwr_policy_table_ptr = (pwr_policy_table_ptr + | ||
505 | VBIOS_POWER_POLICY_3X_HEADER_SIZE_25); | ||
506 | |||
507 | for (index = 0; index < pwr_policy_table_header.num_table_entries; | ||
508 | index++) { | ||
509 | u8 class_type; | ||
510 | |||
511 | curr_pwr_policy_table_ptr += (pwr_policy_table_header.table_entry_size * index); | ||
512 | |||
513 | pwr_policy_table_entry.flags0 = *curr_pwr_policy_table_ptr; | ||
514 | pwr_policy_table_entry.ch_idx = *(curr_pwr_policy_table_ptr + 1); | ||
515 | |||
516 | memcpy(&pwr_policy_table_entry.limit_min, | ||
517 | (curr_pwr_policy_table_ptr + 2), | ||
518 | 35); | ||
519 | |||
520 | memcpy(&pwr_policy_table_entry.ratio_min, | ||
521 | (curr_pwr_policy_table_ptr + 2 + 35), | ||
522 | 4); | ||
523 | |||
524 | pwr_policy_table_entry.sample_mult = | ||
525 | *(curr_pwr_policy_table_ptr + 2 + 35 + 4); | ||
526 | |||
527 | memcpy(&pwr_policy_table_entry.filter_param, | ||
528 | (curr_pwr_policy_table_ptr + 2 + 35 + 4 + 1), | ||
529 | 4); | ||
530 | |||
531 | class_type = (u8)BIOS_GET_FIELD( | ||
532 | pwr_policy_table_entry.flags0, | ||
533 | NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS0_CLASS); | ||
534 | |||
535 | if (class_type == NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS0_CLASS_HW_THRESHOLD) { | ||
536 | ppwrpolicyobjs->version = CTRL_PMGR_PWR_POLICY_TABLE_VERSION_3X; | ||
537 | ppwrpolicyobjs->base_sample_period = (u16) | ||
538 | pwr_policy_table_header.base_sample_period; | ||
539 | ppwrpolicyobjs->min_client_sample_period = (u16) | ||
540 | pwr_policy_table_header.min_client_sample_period; | ||
541 | ppwrpolicyobjs->low_sampling_mult = | ||
542 | pwr_policy_table_header.low_sampling_mult; | ||
543 | |||
544 | ppwrpolicyobjs->policy_idxs[1] = | ||
545 | (u8)pwr_policy_table_header.tgp_policy_idx; | ||
546 | ppwrpolicyobjs->policy_idxs[0] = | ||
547 | (u8)pwr_policy_table_header.rtp_policy_idx; | ||
548 | ppwrpolicyobjs->policy_idxs[2] = | ||
549 | pwr_policy_table_header.mxm_policy_idx; | ||
550 | ppwrpolicyobjs->policy_idxs[3] = | ||
551 | pwr_policy_table_header.dnotifier_policy_idx; | ||
552 | ppwrpolicyobjs->ext_limits[0].limit = | ||
553 | pwr_policy_table_header.d2_limit; | ||
554 | ppwrpolicyobjs->ext_limits[1].limit = | ||
555 | pwr_policy_table_header.d3_limit; | ||
556 | ppwrpolicyobjs->ext_limits[2].limit = | ||
557 | pwr_policy_table_header.d4_limit; | ||
558 | ppwrpolicyobjs->ext_limits[3].limit = | ||
559 | pwr_policy_table_header.d5_limit; | ||
560 | ppwrpolicyobjs->policy_idxs[4] = | ||
561 | pwr_policy_table_header.pwr_tgt_policy_idx; | ||
562 | ppwrpolicyobjs->policy_idxs[5] = | ||
563 | pwr_policy_table_header.pwr_tgt_floor_policy_idx; | ||
564 | ppwrpolicyobjs->policy_idxs[6] = | ||
565 | pwr_policy_table_header.sm_bus_policy_idx; | ||
566 | |||
567 | integral_control = (bool)BIOS_GET_FIELD( | ||
568 | pwr_policy_table_entry.flags1, | ||
569 | NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS1_INTEGRAL_CONTROL); | ||
570 | |||
571 | if (integral_control == 0x01) { | ||
572 | pwr_policy_data.pwrpolicy.integral.past_sample_count = (u8) | ||
573 | pwr_policy_table_entry.past_length; | ||
574 | pwr_policy_data.pwrpolicy.integral.next_sample_count = (u8) | ||
575 | pwr_policy_table_entry.next_length; | ||
576 | pwr_policy_data.pwrpolicy.integral.ratio_limit_max = (u16) | ||
577 | pwr_policy_table_entry.ratio_max; | ||
578 | pwr_policy_data.pwrpolicy.integral.ratio_limit_min = (u16) | ||
579 | pwr_policy_table_entry.ratio_min; | ||
580 | } else { | ||
581 | memset(&(pwr_policy_data.pwrpolicy.integral), 0x0, | ||
582 | sizeof(struct ctrl_pmgr_pwr_policy_info_integral)); | ||
583 | } | ||
584 | pwr_policy_data.hw_threshold.threshold_idx = (u8) | ||
585 | BIOS_GET_FIELD( | ||
586 | pwr_policy_table_entry.param0, | ||
587 | NV_VBIOS_POWER_POLICY_3X_ENTRY_PARAM0_HW_THRESHOLD_THRES_IDX); | ||
588 | |||
589 | pwr_policy_data.hw_threshold.b_use_low_threshold = | ||
590 | BIOS_GET_FIELD( | ||
591 | pwr_policy_table_entry.param0, | ||
592 | NV_VBIOS_POWER_POLICY_3X_ENTRY_PARAM0_HW_THRESHOLD_LOW_THRESHOLD_USE); | ||
593 | |||
594 | if (pwr_policy_data.hw_threshold.b_use_low_threshold) { | ||
595 | pwr_policy_data.hw_threshold.low_threshold_idx = (u8) | ||
596 | BIOS_GET_FIELD( | ||
597 | pwr_policy_table_entry.param0, | ||
598 | NV_VBIOS_POWER_POLICY_3X_ENTRY_PARAM0_HW_THRESHOLD_LOW_THRESHOLD_IDX); | ||
599 | |||
600 | pwr_policy_data.hw_threshold.low_threshold_value = (u16) | ||
601 | BIOS_GET_FIELD( | ||
602 | pwr_policy_table_entry.param1, | ||
603 | NV_VBIOS_POWER_POLICY_3X_ENTRY_PARAM1_HW_THRESHOLD_LOW_THRESHOLD_VAL); | ||
604 | } | ||
605 | |||
606 | pwr_policy_size = sizeof(struct pwr_policy_hw_threshold); | ||
607 | } else | ||
608 | continue; | ||
609 | |||
610 | /* Initialize data for the parent class */ | ||
611 | pwr_policy_data.boardobj.type = CTRL_PMGR_PWR_POLICY_TYPE_HW_THRESHOLD; | ||
612 | pwr_policy_data.pwrpolicy.ch_idx = (u8)pwr_policy_table_entry.ch_idx; | ||
613 | pwr_policy_data.pwrpolicy.limit_unit = (u8) | ||
614 | BIOS_GET_FIELD( | ||
615 | pwr_policy_table_entry.flags0, | ||
616 | NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS0_LIMIT_UNIT); | ||
617 | pwr_policy_data.pwrpolicy.filter_type = (u8) | ||
618 | BIOS_GET_FIELD( | ||
619 | pwr_policy_table_entry.flags1, | ||
620 | NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS1_FILTER_TYPE); | ||
621 | pwr_policy_data.pwrpolicy.limit_min = pwr_policy_table_entry.limit_min; | ||
622 | pwr_policy_data.pwrpolicy.limit_rated = pwr_policy_table_entry.limit_rated; | ||
623 | pwr_policy_data.pwrpolicy.limit_max = pwr_policy_table_entry.limit_max; | ||
624 | pwr_policy_data.pwrpolicy.limit_batt = pwr_policy_table_entry.limit_batt; | ||
625 | |||
626 | pwr_policy_data.pwrpolicy.sample_mult = (u8)pwr_policy_table_entry.sample_mult; | ||
627 | |||
628 | /* Filled the entry.filterParam value in the filterParam */ | ||
629 | pwr_policy_data.pwrpolicy.filter_param.block.block_size = 0; | ||
630 | pwr_policy_data.pwrpolicy.filter_param.moving_avg.window_size = 0; | ||
631 | pwr_policy_data.pwrpolicy.filter_param.iir.divisor = 0; | ||
632 | |||
633 | hw_threshold_policy_index |= | ||
634 | BIT(pwr_policy_data.hw_threshold.threshold_idx); | ||
635 | |||
636 | boardobj = construct_pwr_policy(g, &pwr_policy_data, | ||
637 | pwr_policy_size, pwr_policy_data.boardobj.type); | ||
638 | |||
639 | if (!boardobj) { | ||
640 | gk20a_err(dev_from_gk20a(g), | ||
641 | "unable to create pwr policy for %d type %d", index, pwr_policy_data.boardobj.type); | ||
642 | status = -EINVAL; | ||
643 | goto done; | ||
644 | } | ||
645 | |||
646 | status = boardobjgrp_objinsert(&ppwrpolicyobjs->pwr_policies.super, | ||
647 | boardobj, obj_index); | ||
648 | |||
649 | if (status) { | ||
650 | gk20a_err(dev_from_gk20a(g), | ||
651 | "unable to insert pwr policy boardobj for %d", index); | ||
652 | status = -EINVAL; | ||
653 | goto done; | ||
654 | } | ||
655 | |||
656 | ++obj_index; | ||
657 | } | ||
658 | |||
659 | if (hw_threshold_policy_index && | ||
660 | (hw_threshold_policy_index < 0x3)) { | ||
661 | status = _pwr_policy_construct_WAR_policy(g, | ||
662 | ppwrpolicyobjs, | ||
663 | &pwr_policy_data, | ||
664 | pwr_policy_size, | ||
665 | hw_threshold_policy_index, | ||
666 | obj_index); | ||
667 | if (status) { | ||
668 | gk20a_err(dev_from_gk20a(g), | ||
669 | "unable to construct_WAR_policy"); | ||
670 | status = -EINVAL; | ||
671 | goto done; | ||
672 | } | ||
673 | ++obj_index; | ||
674 | } | ||
675 | |||
676 | if (!sw_threshold_policy_index) { | ||
677 | status = _pwr_policy_construct_WAR_SW_Threshold_policy(g, | ||
678 | ppwrpolicyobjs, | ||
679 | &pwr_policy_data, | ||
680 | sizeof(struct pwr_policy_sw_threshold), | ||
681 | obj_index); | ||
682 | if (status) { | ||
683 | gk20a_err(dev_from_gk20a(g), | ||
684 | "unable to construct_WAR_policy"); | ||
685 | status = -EINVAL; | ||
686 | goto done; | ||
687 | } | ||
688 | ++obj_index; | ||
689 | } | ||
690 | |||
691 | done: | ||
692 | gk20a_dbg_info(" done status %x", status); | ||
693 | return status; | ||
694 | } | ||
695 | |||
696 | u32 pmgr_policy_sw_setup(struct gk20a *g) | ||
697 | { | ||
698 | u32 status; | ||
699 | struct boardobjgrp *pboardobjgrp = NULL; | ||
700 | struct pwr_policy *ppolicy; | ||
701 | struct pmgr_pwr_policy *ppwrpolicyobjs; | ||
702 | u8 indx = 0; | ||
703 | |||
704 | /* Construct the Super Class and override the Interfaces */ | ||
705 | status = boardobjgrpconstruct_e32( | ||
706 | &g->pmgr_pmu.pmgr_policyobjs.pwr_policies); | ||
707 | if (status) { | ||
708 | gk20a_err(dev_from_gk20a(g), | ||
709 | "error creating boardobjgrp for pmgr policy, status - 0x%x", | ||
710 | status); | ||
711 | goto done; | ||
712 | } | ||
713 | |||
714 | status = boardobjgrpconstruct_e32( | ||
715 | &g->pmgr_pmu.pmgr_policyobjs.pwr_policy_rels); | ||
716 | if (status) { | ||
717 | gk20a_err(dev_from_gk20a(g), | ||
718 | "error creating boardobjgrp for pmgr policy rels, status - 0x%x", | ||
719 | status); | ||
720 | goto done; | ||
721 | } | ||
722 | |||
723 | status = boardobjgrpconstruct_e32( | ||
724 | &g->pmgr_pmu.pmgr_policyobjs.pwr_violations); | ||
725 | if (status) { | ||
726 | gk20a_err(dev_from_gk20a(g), | ||
727 | "error creating boardobjgrp for pmgr violations, status - 0x%x", | ||
728 | status); | ||
729 | goto done; | ||
730 | } | ||
731 | |||
732 | memset(g->pmgr_pmu.pmgr_policyobjs.policy_idxs, CTRL_PMGR_PWR_POLICY_INDEX_INVALID, | ||
733 | sizeof(u8) * CTRL_PMGR_PWR_POLICY_IDX_NUM_INDEXES); | ||
734 | |||
735 | /* Initialize external power limit policy indexes to _INVALID/0xFF */ | ||
736 | for (indx = 0; indx < PWR_POLICY_EXT_POWER_STATE_ID_COUNT; indx++) { | ||
737 | g->pmgr_pmu.pmgr_policyobjs.ext_limits[indx].policy_table_idx = | ||
738 | CTRL_PMGR_PWR_POLICY_INDEX_INVALID; | ||
739 | } | ||
740 | |||
741 | /* Initialize external power state to _D1 */ | ||
742 | g->pmgr_pmu.pmgr_policyobjs.ext_power_state = 0xFFFFFFFF; | ||
743 | |||
744 | ppwrpolicyobjs = &(g->pmgr_pmu.pmgr_policyobjs); | ||
745 | pboardobjgrp = &(g->pmgr_pmu.pmgr_policyobjs.pwr_policies.super); | ||
746 | |||
747 | status = devinit_get_pwr_policy_table(g, ppwrpolicyobjs); | ||
748 | if (status) | ||
749 | goto done; | ||
750 | |||
751 | g->pmgr_pmu.pmgr_policyobjs.b_enabled = true; | ||
752 | |||
753 | BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct pwr_policy *, ppolicy, indx) { | ||
754 | PMGR_PWR_POLICY_INCREMENT_LIMIT_INPUT_COUNT(ppolicy); | ||
755 | } | ||
756 | |||
757 | g->pmgr_pmu.pmgr_policyobjs.global_ceiling.values[0] = | ||
758 | 0xFF; | ||
759 | |||
760 | g->pmgr_pmu.pmgr_policyobjs.client_work_item.b_pending = false; | ||
761 | |||
762 | done: | ||
763 | gk20a_dbg_info(" done status %x", status); | ||
764 | return status; | ||
765 | } | ||