From 90f80a282eff04412858361df35c2f88372e88cb Mon Sep 17 00:00:00 2001 From: Lakshmanan M Date: Thu, 8 Sep 2016 22:58:19 +0530 Subject: 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 Reviewed-on: http://git-master/r/1217189 (cherry picked from commit ecd0b16316cb4110118c6677f5f03e02921c29b6) Reviewed-on: http://git-master/r/1241953 Reviewed-by: Terje Bergstrom GVS: Gerrit_Virtual_Submit --- drivers/gpu/nvgpu/pmgr/pwrpolicy.c | 680 +++++++++++++++++++++++++++++++++++++ 1 file changed, 680 insertions(+) create mode 100644 drivers/gpu/nvgpu/pmgr/pwrpolicy.c (limited to 'drivers/gpu/nvgpu/pmgr/pwrpolicy.c') diff --git a/drivers/gpu/nvgpu/pmgr/pwrpolicy.c b/drivers/gpu/nvgpu/pmgr/pwrpolicy.c new file mode 100644 index 00000000..bec13b0c --- /dev/null +++ b/drivers/gpu/nvgpu/pmgr/pwrpolicy.c @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "gk20a/gk20a.h" +#include "pwrpolicy.h" +#include "include/bios.h" +#include "boardobj/boardobjgrp.h" +#include "boardobj/boardobjgrp_e32.h" +#include "pmuif/gpmuifboardobj.h" +#include "pmuif/gpmuifpmgr.h" +#include "gm206/bios_gm206.h" +#include "gk20a/pmu_gk20a.h" + +#define _pwr_policy_limitarboutputget_helper(p_limit_arb) (p_limit_arb)->output +#define _pwr_policy_limitdeltaapply(limit, delta) ((u32)max(((s32)limit) + (delta), 0)) + +static u32 _pwr_policy_limitarbinputset_helper(struct gk20a *g, + struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb, + u8 client_idx, + u32 limit_value) +{ + u8 indx; + bool b_found = false; + u32 status = 0; + u32 output = limit_value; + + for (indx = 0; indx< p_limit_arb->num_inputs; indx++) { + if (p_limit_arb->inputs[indx].pwr_policy_idx == client_idx) { + p_limit_arb->inputs[indx].limit_value = limit_value; + b_found = true; + } else if (p_limit_arb->b_arb_max) { + output = max(output, p_limit_arb->inputs[indx].limit_value); + } else { + output = min(output, p_limit_arb->inputs[indx].limit_value); + } + } + + if (!b_found) { + if (p_limit_arb->num_inputs < + CTRL_PMGR_PWR_POLICY_MAX_LIMIT_INPUTS) { + p_limit_arb->inputs[ + p_limit_arb->num_inputs].pwr_policy_idx = client_idx; + p_limit_arb->inputs[ + p_limit_arb->num_inputs].limit_value = limit_value; + p_limit_arb->num_inputs++; + } else { + gk20a_err(g->dev, "No entries remaining for clientIdx=%d", + client_idx); + status = -EINVAL; + } + } + + if (!status) { + p_limit_arb->output = output; + } + + return status; +} + +static u32 _pwr_policy_limitid_translate(struct gk20a *g, + struct pwr_policy *ppolicy, + enum pwr_policy_limit_id limit_id, + struct ctrl_pmgr_pwr_policy_limit_arbitration **p_limit_arb, + struct ctrl_pmgr_pwr_policy_limit_arbitration **p_limit_arb_sec) +{ + u32 status = 0; + + switch (limit_id) { + case PWR_POLICY_LIMIT_ID_MIN: + *p_limit_arb = &ppolicy->limit_arb_min; + break; + + case PWR_POLICY_LIMIT_ID_RATED: + *p_limit_arb = &ppolicy->limit_arb_rated; + + if (p_limit_arb_sec != NULL) { + *p_limit_arb_sec = &ppolicy->limit_arb_curr; + } + break; + + case PWR_POLICY_LIMIT_ID_MAX: + *p_limit_arb = &ppolicy->limit_arb_max; + break; + + case PWR_POLICY_LIMIT_ID_CURR: + *p_limit_arb = &ppolicy->limit_arb_curr; + break; + + case PWR_POLICY_LIMIT_ID_BATT: + *p_limit_arb = &ppolicy->limit_arb_batt; + break; + + default: + gk20a_err(g->dev, "Unsupported limitId=%d", + limit_id); + status = -EINVAL; + break; + } + + return status; +} + +static u32 _pwr_policy_limitarbinputset(struct gk20a *g, + struct pwr_policy *ppolicy, + enum pwr_policy_limit_id limit_id, + u8 client_idx, + u32 limit) +{ + u32 status = 0; + struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb = NULL; + struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb_sec = NULL; + + status = _pwr_policy_limitid_translate(g, + ppolicy, + limit_id, + &p_limit_arb, + &p_limit_arb_sec); + if (status) { + goto exit; + } + + status = _pwr_policy_limitarbinputset_helper(g, p_limit_arb, client_idx, limit); + if (status) { + gk20a_err(g->dev, + "Error setting client limit value: status=0x%08x, limitId=0x%x, clientIdx=0x%x, limit=%d", + status, limit_id, client_idx, limit); + goto exit; + } + + if (NULL != p_limit_arb_sec) { + status = _pwr_policy_limitarbinputset_helper(g, p_limit_arb_sec, + CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, + _pwr_policy_limitarboutputget_helper(p_limit_arb)); + } + +exit: + return status; +} + +static inline void _pwr_policy_limitarbconstruct( + struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb, + bool b_arb_max) +{ + p_limit_arb->num_inputs = 0; + p_limit_arb->b_arb_max = b_arb_max; +} + +static u32 _pwr_policy_limitarboutputget(struct gk20a *g, + struct pwr_policy *ppolicy, + enum pwr_policy_limit_id limit_id) +{ + u32 status = 0; + struct ctrl_pmgr_pwr_policy_limit_arbitration *p_limit_arb = NULL; + + status = _pwr_policy_limitid_translate(g, + ppolicy, + limit_id, + &p_limit_arb, + NULL); + if (status) { + return 0; + } + + return _pwr_policy_limitarboutputget_helper(p_limit_arb); +} + +static u32 _pwr_domains_pmudatainit_hw_threshold(struct gk20a *g, + struct boardobj *board_obj_ptr, + struct nv_pmu_boardobj *ppmudata) +{ + struct nv_pmu_pmgr_pwr_policy_hw_threshold *pmu_hw_threshold_data; + struct pwr_policy_hw_threshold *p_hw_threshold; + struct pwr_policy *p_pwr_policy; + struct nv_pmu_pmgr_pwr_policy *pmu_pwr_policy; + u32 status = 0; + + status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata); + if (status) { + gk20a_err(dev_from_gk20a(g), + "error updating pmu boardobjgrp for pwr sensor 0x%x", + status); + status = -ENOMEM; + goto done; + } + + p_hw_threshold = (struct pwr_policy_hw_threshold *)board_obj_ptr; + pmu_hw_threshold_data = (struct nv_pmu_pmgr_pwr_policy_hw_threshold *) ppmudata; + pmu_pwr_policy = (struct nv_pmu_pmgr_pwr_policy *) ppmudata; + p_pwr_policy = (struct pwr_policy *)&(p_hw_threshold->super.super); + + pmu_pwr_policy->ch_idx = 0; + pmu_pwr_policy->limit_unit = p_pwr_policy->limit_unit; + pmu_pwr_policy->num_limit_inputs = p_pwr_policy->num_limit_inputs; + + pmu_pwr_policy->limit_min = _pwr_policy_limitdeltaapply( + _pwr_policy_limitarboutputget(g, p_pwr_policy, + PWR_POLICY_LIMIT_ID_MIN), + p_pwr_policy->limit_delta); + + pmu_pwr_policy->limit_max = _pwr_policy_limitdeltaapply( + _pwr_policy_limitarboutputget(g, p_pwr_policy, + PWR_POLICY_LIMIT_ID_MAX), + p_pwr_policy->limit_delta); + + pmu_pwr_policy->limit_curr = _pwr_policy_limitdeltaapply( + _pwr_policy_limitarboutputget(g, p_pwr_policy, + PWR_POLICY_LIMIT_ID_CURR), + p_pwr_policy->limit_delta); + + memcpy(&pmu_pwr_policy->integral, &p_pwr_policy->integral, + sizeof(struct ctrl_pmgr_pwr_policy_info_integral)); + + pmu_pwr_policy->sample_mult = p_pwr_policy->sample_mult; + pmu_pwr_policy->filter_type = p_pwr_policy->filter_type; + pmu_pwr_policy->filter_param = p_pwr_policy->filter_param; + + pmu_hw_threshold_data->threshold_idx = p_hw_threshold->threshold_idx; + pmu_hw_threshold_data->low_threshold_idx = p_hw_threshold->low_threshold_idx; + pmu_hw_threshold_data->b_use_low_threshold = p_hw_threshold->b_use_low_threshold; + pmu_hw_threshold_data->low_threshold_value = p_hw_threshold->low_threshold_value; + +done: + return status; +} + +static struct boardobj *construct_pwr_policy(struct gk20a *g, + void *pargs, u16 pargs_size, u8 type) +{ + struct boardobj *board_obj_ptr = NULL; + u32 status; + struct pwr_policy_hw_threshold *pwrpolicyhwthreshold; + struct pwr_policy *pwrpolicy; + struct pwr_policy *pwrpolicyparams = (struct pwr_policy*)pargs; + struct pwr_policy_hw_threshold *hwthreshold = (struct pwr_policy_hw_threshold*)pargs; + + status = boardobj_construct_super(g, &board_obj_ptr, + pargs_size, pargs); + if (status) + return NULL; + + pwrpolicyhwthreshold = (struct pwr_policy_hw_threshold*)board_obj_ptr; + pwrpolicy = (struct pwr_policy *)board_obj_ptr; + + /* Set Super class interfaces */ + board_obj_ptr->pmudatainit = _pwr_domains_pmudatainit_hw_threshold; + + pwrpolicy->ch_idx = pwrpolicyparams->ch_idx; + pwrpolicy->num_limit_inputs = 0; + pwrpolicy->limit_unit = pwrpolicyparams->limit_unit; + pwrpolicy->filter_type = (enum ctrl_pmgr_pwr_policy_filter_type)(pwrpolicyparams->filter_type); + pwrpolicy->sample_mult = pwrpolicyparams->sample_mult; + switch (pwrpolicy->filter_type) + { + case CTRL_PMGR_PWR_POLICY_FILTER_TYPE_NONE: + break; + + case CTRL_PMGR_PWR_POLICY_FILTER_TYPE_BLOCK: + pwrpolicy->filter_param.block.block_size = + pwrpolicyparams->filter_param.block.block_size; + break; + + case CTRL_PMGR_PWR_POLICY_FILTER_TYPE_MOVING_AVERAGE: + pwrpolicy->filter_param.moving_avg.window_size = + pwrpolicyparams->filter_param.moving_avg.window_size; + break; + + case CTRL_PMGR_PWR_POLICY_FILTER_TYPE_IIR: + pwrpolicy->filter_param.iir.divisor = pwrpolicyparams->filter_param.iir.divisor; + break; + + default: + gk20a_err(g->dev, + "Error: unrecognized Power Policy filter type: %d.\n", + pwrpolicy->filter_type); + } + + _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_curr, false); + + pwrpolicy->limit_delta = 0; + + _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_min, true); + status = _pwr_policy_limitarbinputset(g, + pwrpolicy, + PWR_POLICY_LIMIT_ID_MIN, + CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, + pwrpolicyparams->limit_min); + + _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_max, false); + status = _pwr_policy_limitarbinputset(g, + pwrpolicy, + PWR_POLICY_LIMIT_ID_MAX, + CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, + pwrpolicyparams->limit_max); + + _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_rated, false); + status = _pwr_policy_limitarbinputset(g, + pwrpolicy, + PWR_POLICY_LIMIT_ID_RATED, + CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, + pwrpolicyparams->limit_rated); + + _pwr_policy_limitarbconstruct(&pwrpolicy->limit_arb_batt, false); + status = _pwr_policy_limitarbinputset(g, + pwrpolicy, + PWR_POLICY_LIMIT_ID_BATT, + CTRL_PMGR_PWR_POLICY_LIMIT_INPUT_CLIENT_IDX_RM, + ((pwrpolicyparams->limit_batt != 0) ? + pwrpolicyparams->limit_batt: + CTRL_PMGR_PWR_POLICY_LIMIT_MAX)); + + memcpy(&pwrpolicy->integral, &pwrpolicyparams->integral, + sizeof(struct ctrl_pmgr_pwr_policy_info_integral)); + + pwrpolicyhwthreshold->threshold_idx = hwthreshold->threshold_idx; + pwrpolicyhwthreshold->b_use_low_threshold = hwthreshold->b_use_low_threshold; + pwrpolicyhwthreshold->low_threshold_idx = hwthreshold->low_threshold_idx; + pwrpolicyhwthreshold->low_threshold_value = hwthreshold->low_threshold_value; + + gk20a_dbg_info(" Done"); + + return board_obj_ptr; +} + +static u32 _pwr_policy_construct_WAR_policy(struct gk20a *g, + struct pmgr_pwr_policy *ppwrpolicyobjs, + union pwr_policy_data_union *ppwrpolicydata, + u16 pwr_policy_size, + u32 hw_threshold_policy_index, + u32 obj_index) +{ + u32 status = 0; + struct boardobj *boardobj; + + if (!(hw_threshold_policy_index & 0x1)) { + /* CRIT policy */ + ppwrpolicydata->pwrpolicy.limit_min = 1000; + ppwrpolicydata->pwrpolicy.limit_rated = 20000; + ppwrpolicydata->pwrpolicy.limit_max = 20000; + ppwrpolicydata->hw_threshold.threshold_idx = 0; + } else { + /* WARN policy */ + ppwrpolicydata->pwrpolicy.limit_min = 1000; + ppwrpolicydata->pwrpolicy.limit_rated = 11600; + ppwrpolicydata->pwrpolicy.limit_max = 11600; + ppwrpolicydata->hw_threshold.threshold_idx = 1; + } + + boardobj = construct_pwr_policy(g, ppwrpolicydata, + pwr_policy_size, ppwrpolicydata->boardobj.type); + + if (!boardobj) { + gk20a_err(dev_from_gk20a(g), + "unable to create pwr policy for type %d", ppwrpolicydata->boardobj.type); + status = -EINVAL; + goto done; + } + + status = boardobjgrp_objinsert(&ppwrpolicyobjs->pwr_policies.super, + boardobj, obj_index); + + if (status) { + gk20a_err(dev_from_gk20a(g), + "unable to insert pwr policy boardobj for %d", obj_index); + status = -EINVAL; + goto done; + } +done: + return status; +} + +static u32 devinit_get_pwr_policy_table(struct gk20a *g, + struct pmgr_pwr_policy *ppwrpolicyobjs) +{ + u32 status = 0; + u8 *pwr_policy_table_ptr = NULL; + u8 *curr_pwr_policy_table_ptr = NULL; + struct boardobj *boardobj; + struct pwr_policy_3x_header_struct pwr_policy_table_header = { 0 }; + struct pwr_policy_3x_entry_struct pwr_policy_table_entry = { 0 }; + u32 index; + u32 obj_index = 0; + u16 pwr_policy_size; + bool integral_control = false; + u32 hw_threshold_policy_index = 0; + union pwr_policy_data_union pwr_policy_data; + + gk20a_dbg_info(""); + + if (g->ops.bios.get_perf_table_ptrs != NULL) { + pwr_policy_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g, + g->bios.perf_token, POWER_CAPPING_TABLE); + if (pwr_policy_table_ptr == NULL) { + status = -EINVAL; + goto done; + } + } + + memcpy(&pwr_policy_table_header.version, + (pwr_policy_table_ptr), + 14); + + memcpy(&pwr_policy_table_header.d2_limit, + (pwr_policy_table_ptr + 14), + (VBIOS_POWER_POLICY_3X_ENTRY_SIZE_2E - 14)); + + if (pwr_policy_table_header.version != + VBIOS_POWER_POLICY_VERSION_3X) { + status = -EINVAL; + goto done; + } + + if (pwr_policy_table_header.header_size < + VBIOS_POWER_POLICY_3X_HEADER_SIZE_25) { + status = -EINVAL; + goto done; + } + + if (pwr_policy_table_header.table_entry_size != + VBIOS_POWER_POLICY_3X_ENTRY_SIZE_2E) { + status = -EINVAL; + goto done; + } + + curr_pwr_policy_table_ptr = (pwr_policy_table_ptr + + VBIOS_POWER_POLICY_3X_HEADER_SIZE_25); + + for (index = 0; index < pwr_policy_table_header.num_table_entries; + index++) { + u8 class_type; + + curr_pwr_policy_table_ptr += (pwr_policy_table_header.table_entry_size * index); + + pwr_policy_table_entry.flags0 = *curr_pwr_policy_table_ptr; + pwr_policy_table_entry.ch_idx = *(curr_pwr_policy_table_ptr + 1); + + memcpy(&pwr_policy_table_entry.limit_min, + (curr_pwr_policy_table_ptr + 2), + 35); + + memcpy(&pwr_policy_table_entry.ratio_min, + (curr_pwr_policy_table_ptr + 2 + 35), + 4); + + pwr_policy_table_entry.sample_mult = + *(curr_pwr_policy_table_ptr + 2 + 35 + 4); + + memcpy(&pwr_policy_table_entry.filter_param, + (curr_pwr_policy_table_ptr + 2 + 35 + 4 + 1), + 4); + + class_type = (u8)BIOS_GET_FIELD( + pwr_policy_table_entry.flags0, + NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS0_CLASS); + + if (class_type == NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS0_CLASS_HW_THRESHOLD) { + ppwrpolicyobjs->version = CTRL_PMGR_PWR_POLICY_TABLE_VERSION_3X; + ppwrpolicyobjs->base_sample_period = (u16) + pwr_policy_table_header.base_sample_period; + ppwrpolicyobjs->min_client_sample_period = (u16) + pwr_policy_table_header.min_client_sample_period; + ppwrpolicyobjs->low_sampling_mult = + pwr_policy_table_header.low_sampling_mult; + + ppwrpolicyobjs->policy_idxs[1] = + (u8)pwr_policy_table_header.tgp_policy_idx; + ppwrpolicyobjs->policy_idxs[0] = + (u8)pwr_policy_table_header.rtp_policy_idx; + ppwrpolicyobjs->policy_idxs[2] = + pwr_policy_table_header.mxm_policy_idx; + ppwrpolicyobjs->policy_idxs[3] = + pwr_policy_table_header.dnotifier_policy_idx; + ppwrpolicyobjs->ext_limits[0].limit = + pwr_policy_table_header.d2_limit; + ppwrpolicyobjs->ext_limits[1].limit = + pwr_policy_table_header.d3_limit; + ppwrpolicyobjs->ext_limits[2].limit = + pwr_policy_table_header.d4_limit; + ppwrpolicyobjs->ext_limits[3].limit = + pwr_policy_table_header.d5_limit; + ppwrpolicyobjs->policy_idxs[4] = + pwr_policy_table_header.pwr_tgt_policy_idx; + ppwrpolicyobjs->policy_idxs[5] = + pwr_policy_table_header.pwr_tgt_floor_policy_idx; + ppwrpolicyobjs->policy_idxs[6] = + pwr_policy_table_header.sm_bus_policy_idx; + + integral_control = (bool)BIOS_GET_FIELD( + pwr_policy_table_entry.flags1, + NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS1_INTEGRAL_CONTROL); + + if (integral_control == 0x01) { + pwr_policy_data.pwrpolicy.integral.past_sample_count = (u8) + pwr_policy_table_entry.past_length; + pwr_policy_data.pwrpolicy.integral.next_sample_count = (u8) + pwr_policy_table_entry.next_length; + pwr_policy_data.pwrpolicy.integral.ratio_limit_max = (u16) + pwr_policy_table_entry.ratio_max; + pwr_policy_data.pwrpolicy.integral.ratio_limit_min = (u16) + pwr_policy_table_entry.ratio_min; + } else { + memset(&(pwr_policy_data.pwrpolicy.integral), 0x0, + sizeof(struct ctrl_pmgr_pwr_policy_info_integral)); + } + pwr_policy_data.hw_threshold.threshold_idx = (u8) + BIOS_GET_FIELD( + pwr_policy_table_entry.param0, + NV_VBIOS_POWER_POLICY_3X_ENTRY_PARAM0_HW_THRESHOLD_THRES_IDX); + + pwr_policy_data.hw_threshold.b_use_low_threshold = + BIOS_GET_FIELD( + pwr_policy_table_entry.param0, + NV_VBIOS_POWER_POLICY_3X_ENTRY_PARAM0_HW_THRESHOLD_LOW_THRESHOLD_USE); + + if (pwr_policy_data.hw_threshold.b_use_low_threshold) { + pwr_policy_data.hw_threshold.low_threshold_idx = (u8) + BIOS_GET_FIELD( + pwr_policy_table_entry.param0, + NV_VBIOS_POWER_POLICY_3X_ENTRY_PARAM0_HW_THRESHOLD_LOW_THRESHOLD_IDX); + + pwr_policy_data.hw_threshold.low_threshold_value = (u16) + BIOS_GET_FIELD( + pwr_policy_table_entry.param1, + NV_VBIOS_POWER_POLICY_3X_ENTRY_PARAM1_HW_THRESHOLD_LOW_THRESHOLD_VAL); + } + + pwr_policy_size = sizeof(struct pwr_policy_hw_threshold); + } else + continue; + + /* Initialize data for the parent class */ + pwr_policy_data.boardobj.type = CTRL_PMGR_PWR_POLICY_TYPE_HW_THRESHOLD; + pwr_policy_data.pwrpolicy.ch_idx = (u8)pwr_policy_table_entry.ch_idx; + pwr_policy_data.pwrpolicy.limit_unit = (u8) + BIOS_GET_FIELD( + pwr_policy_table_entry.flags0, + NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS0_LIMIT_UNIT); + pwr_policy_data.pwrpolicy.filter_type = (u8) + BIOS_GET_FIELD( + pwr_policy_table_entry.flags1, + NV_VBIOS_POWER_POLICY_3X_ENTRY_FLAGS1_FILTER_TYPE); + pwr_policy_data.pwrpolicy.limit_min = pwr_policy_table_entry.limit_min; + pwr_policy_data.pwrpolicy.limit_rated = pwr_policy_table_entry.limit_rated; + pwr_policy_data.pwrpolicy.limit_max = pwr_policy_table_entry.limit_max; + pwr_policy_data.pwrpolicy.limit_batt = pwr_policy_table_entry.limit_batt; + + pwr_policy_data.pwrpolicy.sample_mult = (u8)pwr_policy_table_entry.sample_mult; + + /* Filled the entry.filterParam value in the filterParam */ + pwr_policy_data.pwrpolicy.filter_param.block.block_size = 0; + pwr_policy_data.pwrpolicy.filter_param.moving_avg.window_size = 0; + pwr_policy_data.pwrpolicy.filter_param.iir.divisor = 0; + + hw_threshold_policy_index |= + BIT(pwr_policy_data.hw_threshold.threshold_idx); + + boardobj = construct_pwr_policy(g, &pwr_policy_data, + pwr_policy_size, pwr_policy_data.boardobj.type); + + if (!boardobj) { + gk20a_err(dev_from_gk20a(g), + "unable to create pwr policy for %d type %d", index, pwr_policy_data.boardobj.type); + status = -EINVAL; + goto done; + } + + status = boardobjgrp_objinsert(&ppwrpolicyobjs->pwr_policies.super, + boardobj, obj_index); + + if (status) { + gk20a_err(dev_from_gk20a(g), + "unable to insert pwr policy boardobj for %d", index); + status = -EINVAL; + goto done; + } + + ++obj_index; + } + + if (hw_threshold_policy_index && + (hw_threshold_policy_index < 0x3)) { + status = _pwr_policy_construct_WAR_policy(g, + ppwrpolicyobjs, + &pwr_policy_data, + pwr_policy_size, + hw_threshold_policy_index, + obj_index); + if (status) { + gk20a_err(dev_from_gk20a(g), + "unable to construct_WAR_policy"); + status = -EINVAL; + goto done; + } + ++obj_index; + } + +done: + gk20a_dbg_info(" done status %x", status); + return status; +} + +u32 pmgr_policy_sw_setup(struct gk20a *g) +{ + u32 status; + struct boardobjgrp *pboardobjgrp = NULL; + struct pwr_policy *ppolicy; + struct pmgr_pwr_policy *ppwrpolicyobjs; + u8 indx = 0; + + /* Construct the Super Class and override the Interfaces */ + status = boardobjgrpconstruct_e32( + &g->pmgr_pmu.pmgr_policyobjs.pwr_policies); + if (status) { + gk20a_err(dev_from_gk20a(g), + "error creating boardobjgrp for pmgr policy, status - 0x%x", + status); + goto done; + } + + status = boardobjgrpconstruct_e32( + &g->pmgr_pmu.pmgr_policyobjs.pwr_policy_rels); + if (status) { + gk20a_err(dev_from_gk20a(g), + "error creating boardobjgrp for pmgr policy rels, status - 0x%x", + status); + goto done; + } + + status = boardobjgrpconstruct_e32( + &g->pmgr_pmu.pmgr_policyobjs.pwr_violations); + if (status) { + gk20a_err(dev_from_gk20a(g), + "error creating boardobjgrp for pmgr violations, status - 0x%x", + status); + goto done; + } + + memset(g->pmgr_pmu.pmgr_policyobjs.policy_idxs, CTRL_PMGR_PWR_POLICY_INDEX_INVALID, + sizeof(u8) * CTRL_PMGR_PWR_POLICY_IDX_NUM_INDEXES); + + /* Initialize external power limit policy indexes to _INVALID/0xFF */ + for (indx = 0; indx < PWR_POLICY_EXT_POWER_STATE_ID_COUNT; indx++) { + g->pmgr_pmu.pmgr_policyobjs.ext_limits[indx].policy_table_idx = + CTRL_PMGR_PWR_POLICY_INDEX_INVALID; + } + + /* Initialize external power state to _D1 */ + g->pmgr_pmu.pmgr_policyobjs.ext_power_state = 0xFFFFFFFF; + + ppwrpolicyobjs = &(g->pmgr_pmu.pmgr_policyobjs); + pboardobjgrp = &(g->pmgr_pmu.pmgr_policyobjs.pwr_policies.super); + + status = devinit_get_pwr_policy_table(g, ppwrpolicyobjs); + if (status) + goto done; + + g->pmgr_pmu.pmgr_policyobjs.b_enabled = true; + + BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct pwr_policy *, ppolicy, indx) { + PMGR_PWR_POLICY_INCREMENT_LIMIT_INPUT_COUNT(ppolicy); + } + + g->pmgr_pmu.pmgr_policyobjs.global_ceiling.values[0] = + 0xFF; + + g->pmgr_pmu.pmgr_policyobjs.client_work_item.b_pending = false; + +done: + gk20a_dbg_info(" done status %x", status); + return status; +} -- cgit v1.2.2 From 776ab920a7a4d31c6180e7dcb9f3fcea611e92bd Mon Sep 17 00:00:00 2001 From: Lakshmanan M Date: Fri, 7 Oct 2016 14:30:12 +0530 Subject: gpu: nvgpu: Add SW_THRESHOLD policy support Added SW_THRESHOLD policy support for over power protection. JIRA DNVGPU-70 Change-Id: I7a9d202619c997d6cab6fb750db7f3018229b2fd Signed-off-by: Lakshmanan M Reviewed-on: http://git-master/r/1233055 (cherry picked from commit b233c74b9ba4a3802f111757aecf24a27c830fc1) Reviewed-on: http://git-master/r/1241960 Reviewed-by: Terje Bergstrom GVS: Gerrit_Virtual_Submit --- drivers/gpu/nvgpu/pmgr/pwrpolicy.c | 85 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) (limited to 'drivers/gpu/nvgpu/pmgr/pwrpolicy.c') diff --git a/drivers/gpu/nvgpu/pmgr/pwrpolicy.c b/drivers/gpu/nvgpu/pmgr/pwrpolicy.c index bec13b0c..d7926773 100644 --- a/drivers/gpu/nvgpu/pmgr/pwrpolicy.c +++ b/drivers/gpu/nvgpu/pmgr/pwrpolicy.c @@ -229,6 +229,17 @@ static u32 _pwr_domains_pmudatainit_hw_threshold(struct gk20a *g, pmu_hw_threshold_data->b_use_low_threshold = p_hw_threshold->b_use_low_threshold; pmu_hw_threshold_data->low_threshold_value = p_hw_threshold->low_threshold_value; + if (BOARDOBJ_GET_TYPE(board_obj_ptr) == + CTRL_PMGR_PWR_POLICY_TYPE_SW_THRESHOLD) { + struct nv_pmu_pmgr_pwr_policy_sw_threshold *pmu_sw_threshold_data; + struct pwr_policy_sw_threshold *p_sw_threshold; + + p_sw_threshold = (struct pwr_policy_sw_threshold *)board_obj_ptr; + pmu_sw_threshold_data = + (struct nv_pmu_pmgr_pwr_policy_sw_threshold *) ppmudata; + pmu_sw_threshold_data->event_id = + p_sw_threshold->event_id; + } done: return status; } @@ -326,6 +337,15 @@ static struct boardobj *construct_pwr_policy(struct gk20a *g, pwrpolicyhwthreshold->low_threshold_idx = hwthreshold->low_threshold_idx; pwrpolicyhwthreshold->low_threshold_value = hwthreshold->low_threshold_value; + if (type == CTRL_PMGR_PWR_POLICY_TYPE_SW_THRESHOLD) { + struct pwr_policy_sw_threshold *pwrpolicyswthreshold; + struct pwr_policy_sw_threshold *swthreshold = + (struct pwr_policy_sw_threshold*)pargs; + + pwrpolicyswthreshold = (struct pwr_policy_sw_threshold*)board_obj_ptr; + pwrpolicyswthreshold->event_id = swthreshold->event_id; + } + gk20a_dbg_info(" Done"); return board_obj_ptr; @@ -378,6 +398,55 @@ done: return status; } +static u32 _pwr_policy_construct_WAR_SW_Threshold_policy(struct gk20a *g, + struct pmgr_pwr_policy *ppwrpolicyobjs, + union pwr_policy_data_union *ppwrpolicydata, + u16 pwr_policy_size, + u32 obj_index) +{ + u32 status = 0; + struct boardobj *boardobj; + + /* WARN policy */ + ppwrpolicydata->pwrpolicy.limit_unit = 0; + ppwrpolicydata->pwrpolicy.limit_min = 10000; + ppwrpolicydata->pwrpolicy.limit_rated = 100000; + ppwrpolicydata->pwrpolicy.limit_max = 100000; + ppwrpolicydata->sw_threshold.threshold_idx = 1; + ppwrpolicydata->pwrpolicy.filter_type = + CTRL_PMGR_PWR_POLICY_FILTER_TYPE_MOVING_AVERAGE; + ppwrpolicydata->pwrpolicy.sample_mult = 5; + + /* Filled the entry.filterParam value in the filterParam */ + ppwrpolicydata->pwrpolicy.filter_param.moving_avg.window_size = 10; + + ppwrpolicydata->sw_threshold.event_id = 0x01; + + ppwrpolicydata->boardobj.type = CTRL_PMGR_PWR_POLICY_TYPE_SW_THRESHOLD; + + boardobj = construct_pwr_policy(g, ppwrpolicydata, + pwr_policy_size, ppwrpolicydata->boardobj.type); + + if (!boardobj) { + gk20a_err(dev_from_gk20a(g), + "unable to create pwr policy for type %d", ppwrpolicydata->boardobj.type); + status = -EINVAL; + goto done; + } + + status = boardobjgrp_objinsert(&ppwrpolicyobjs->pwr_policies.super, + boardobj, obj_index); + + if (status) { + gk20a_err(dev_from_gk20a(g), + "unable to insert pwr policy boardobj for %d", obj_index); + status = -EINVAL; + goto done; + } +done: + return status; +} + static u32 devinit_get_pwr_policy_table(struct gk20a *g, struct pmgr_pwr_policy *ppwrpolicyobjs) { @@ -392,6 +461,7 @@ static u32 devinit_get_pwr_policy_table(struct gk20a *g, u16 pwr_policy_size; bool integral_control = false; u32 hw_threshold_policy_index = 0; + u32 sw_threshold_policy_index = 0; union pwr_policy_data_union pwr_policy_data; gk20a_dbg_info(""); @@ -603,6 +673,21 @@ static u32 devinit_get_pwr_policy_table(struct gk20a *g, ++obj_index; } + if (!sw_threshold_policy_index) { + status = _pwr_policy_construct_WAR_SW_Threshold_policy(g, + ppwrpolicyobjs, + &pwr_policy_data, + sizeof(struct pwr_policy_sw_threshold), + obj_index); + if (status) { + gk20a_err(dev_from_gk20a(g), + "unable to construct_WAR_policy"); + status = -EINVAL; + goto done; + } + ++obj_index; + } + done: gk20a_dbg_info(" done status %x", status); return status; -- cgit v1.2.2