gpu: nvgpu: Add support for guaranteed frequency

1. Check for volt margin and freq margin in VBIOS.
2. If it is valid (!255) send RPC to get margin, else ignore.
3. Get freq margin followed by volt margin.
4. Add this to requested voltage/freq based on output type.

Bug 200492048

Change-Id: I513c6cdebcc7c2db348e3be37258e7657b48eb7e
Signed-off-by: Abdul Salam <absalam@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/2021974
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: Deepak Nibade <dnibade@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Vijayakumar Subbu <vsubbu@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Abdul Salam
2019-02-26 14:26:53 +05:30
committed by mobile promotions
parent 429d313f29
commit 4c8a320f2c
11 changed files with 111 additions and 3 deletions

View File

@@ -273,6 +273,8 @@ static int devinit_get_fll_device_table(struct gk20a *g,
if (desctablesize >= FLL_DESCRIPTOR_HEADER_10_SIZE_6) {
pfllobjs->max_min_freq_mhz =
fll_desc_table_header.max_min_freq_mhz;
pfllobjs->freq_margin_vfe_idx =
fll_desc_table_header.freq_margin_vfe_idx;
} else {
pfllobjs->max_min_freq_mhz = 0;
}

View File

@@ -29,6 +29,7 @@
#include <nvgpu/timers.h>
#include <nvgpu/clk_arb.h>
#include <nvgpu/pmu/volt.h>
#include <nvgpu/pmu/perf.h>
#include "clk.h"
#include "clk_vf_point.h"
@@ -475,7 +476,7 @@ int nvgpu_clk_set_req_fll_clk_ps35(struct gk20a *g, struct nvgpu_clk_slave_freq
u32 max_clkmhz;
u16 max_ratio;
struct clk_set_info *p0_info;
u32 vmin_uv = 0;
u32 vmin_uv = 0, vmargin_uv = 0U, fmargin_mhz = 0U;
(void) memset(&change_input, 0,
sizeof(struct ctrl_perf_change_seq_change_input));
@@ -604,9 +605,23 @@ int nvgpu_clk_set_req_fll_clk_ps35(struct gk20a *g, struct nvgpu_clk_slave_freq
change_input.flags = (u32)CTRL_PERF_CHANGE_SEQ_CHANGE_FORCE;
change_input.vf_points_cache_counter = 0xFFFFFFFFU;
status = nvgpu_vfe_get_freq_margin_limit(g, &fmargin_mhz);
if (status != 0) {
nvgpu_err(g, "Failed to fetch Fmargin status=0x%x", status);
return status;
}
gpcclk_clkmhz += fmargin_mhz;
status = clk_domain_freq_to_volt(g, gpcclk_domain,
&gpcclk_clkmhz, &gpcclk_voltuv, CTRL_VOLT_DOMAIN_LOGIC);
status = nvgpu_vfe_get_volt_margin_limit(g, &vmargin_uv);
if (status != 0) {
nvgpu_err(g, "Failed to fetch Vmargin status=0x%x", status);
return status;
}
gpcclk_voltuv += vmargin_uv;
status = g->ops.pmu_ver.volt.volt_get_vmin(g, &vmin_uv);
if (status != 0) {
nvgpu_err(g, "Failed to execute Vmin get_status status=0x%x",

View File

@@ -28,6 +28,7 @@
#include <nvgpu/pmuif/ctrlclk.h>
#include <nvgpu/pmuif/ctrlvolt.h>
#include <nvgpu/pmu/perf.h>
#include <nvgpu/pmu/clk/clk.h>
#include "pmu_perf.h"
#include "vfe_equ.h"
@@ -738,3 +739,60 @@ static struct vfe_equ *construct_vfe_equ(struct gk20a *g, void *pargs)
return (struct vfe_equ *)board_obj_ptr;
}
int nvgpu_vfe_get_volt_margin_limit(struct gk20a *g, u32 *vmargin_uv)
{
struct nvgpu_pmu *pmu = &g->pmu;
struct nv_pmu_rpc_struct_perf_vfe_eval rpc;
int status = 0;
u8 vmargin_idx;
vmargin_idx = g->ops.pmu_ver.volt.volt_get_vmargin(g);
if (vmargin_idx == 0U) {
nvgpu_info(g, "Skipping volt margin idx");
return 0;
}
(void) memset(&rpc, 0, sizeof(rpc));
rpc.data.equ_idx = vmargin_idx;
rpc.data.output_type = CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_DELTA_UV;
rpc.data.var_count = 0U;
PMU_RPC_EXECUTE_CPB(status, pmu, PERF, VFE_EQU_EVAL, &rpc, 0);
if (status != 0) {
nvgpu_err(g, "Failed to execute RPC status=0x%x",
status);
return status;
}
*vmargin_uv = rpc.data.result.voltu_v;
return status;
}
int nvgpu_vfe_get_freq_margin_limit(struct gk20a *g, u32 *fmargin_mhz)
{
struct nvgpu_pmu *pmu = &g->pmu;
struct nv_pmu_rpc_struct_perf_vfe_eval rpc;
int status = 0;
u8 fmargin_idx;
struct nvgpu_avfsfllobjs *pfllobjs = &(g->clk_pmu->avfs_fllobjs);
fmargin_idx = pfllobjs->freq_margin_vfe_idx;
if (fmargin_idx == 255U) {
nvgpu_info(g, "Skipping freq margin idx");
return 0;
}
(void) memset(&rpc, 0, sizeof(rpc));
rpc.data.equ_idx = fmargin_idx;
rpc.data.output_type = CTRL_PERF_VFE_EQU_OUTPUT_TYPE_FREQ_MHZ;
rpc.data.var_count = 0U;
PMU_RPC_EXECUTE_CPB(status, pmu, PERF, VFE_EQU_EVAL, &rpc, 0);
if (status != 0) {
nvgpu_err(g, "Failed to execute RPC status=0x%x",
status);
return status;
}
*fmargin_mhz = rpc.data.result.voltu_v;
return status;
}

View File

@@ -1333,6 +1333,8 @@ static int init_pmu_fw_ver_ops(struct nvgpu_pmu *pmu, u32 app_version)
g->ops.pmu_ver.clk.clk_set_boot_clk = NULL;
g->ops.pmu_ver.volt.volt_get_vmin =
nvgpu_volt_get_vmin_tu10x;
g->ops.pmu_ver.volt.volt_get_vmargin =
nvgpu_volt_get_vmargin_tu10x;
}
} else {
g->ops.pmu_ver.get_pmu_init_msg_pmu_queue_params =

View File

@@ -413,3 +413,21 @@ int nvgpu_volt_get_vmin_tu10x(struct gk20a *g, u32 *vmin_uv)
return status;
}
u8 nvgpu_volt_get_vmargin_tu10x(struct gk20a *g)
{
struct boardobjgrp *pboardobjgrp;
struct boardobj *pboardobj = NULL;
struct voltage_rail *volt_rail = NULL;
u8 index, vmargin_uv;
pboardobjgrp = &g->perf_pmu->volt.volt_rail_metadata.volt_rails.super;
BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct boardobj *, pboardobj, index) {
volt_rail = (struct voltage_rail *)(void *)pboardobj;
if (volt_rail->volt_margin_limit_vfe_equ_idx != 255U) {
vmargin_uv = volt_rail->volt_margin_limit_vfe_equ_idx;
return vmargin_uv;
}
}
return 0U;
}

View File

@@ -98,6 +98,7 @@ struct fll_descriptor_header_10 {
u8 entry_size;
u8 entry_count;
u16 max_min_freq_mhz;
u8 freq_margin_vfe_idx;
} __packed;
#define FLL_DESCRIPTOR_ENTRY_10_SIZE 15U

View File

@@ -1045,6 +1045,7 @@ struct gpu_ops {
u8 volt_domain, u32 *pvoltage_uv);
int (*volt_send_load_cmd_to_pmu)(struct gk20a *g);
int (*volt_get_vmin)(struct gk20a *g, u32 *vmin_uv);
u8 (*volt_get_vmargin)(struct gk20a *g);
} volt;
struct {
u32 (*get_vbios_clk_domain)(u32 vbios_domain);

View File

@@ -38,6 +38,7 @@ struct nvgpu_avfsfllobjs {
u32 lut_min_voltage_uv;
u8 lut_num_entries;
u16 max_min_freq_mhz;
u8 freq_margin_vfe_idx;
};
struct nvgpu_set_fll_clk {

View File

@@ -99,6 +99,8 @@ int vfe_equ_pmu_setup(struct gk20a *g);
int vfe_var_sw_setup(struct gk20a *g);
int vfe_var_pmu_setup(struct gk20a *g);
int nvgpu_vfe_get_volt_margin_limit(struct gk20a *g, u32 *vmargin_uv);
int nvgpu_vfe_get_freq_margin_limit(struct gk20a *g, u32 *fmargin_mhz);
int nvgpu_perf_change_seq_sw_setup(struct gk20a *g);
int nvgpu_perf_change_seq_pmu_setup(struct gk20a *g);

View File

@@ -82,5 +82,6 @@ int volt_policy_sw_setup(struct gk20a *g);
int volt_policy_pmu_setup(struct gk20a *g);
int nvgpu_volt_rail_boardobj_grp_get_status(struct gk20a *g);
int nvgpu_volt_get_vmin_tu10x(struct gk20a *g, u32 *vmin_uv);
u8 nvgpu_volt_get_vmargin_tu10x(struct gk20a *g);
#endif /* NVGPU_PMU_VOLT_H */

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2016-2019, NVIDIA CORPORATION. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -59,7 +59,7 @@
* used to execute LOAD RPC.
*/
struct nv_pmu_rpc_struct_perf_load {
/*[IN/OUT] Must be first field in RPC structure */
/* [IN/OUT] Must be first field in RPC structure */
struct nv_pmu_rpc_header hdr;
bool b_load;
u32 scratch[1];
@@ -215,4 +215,11 @@ struct perf_change_seq_pmu_script {
steps[CTRL_PERF_CHANGE_SEQ_PMU_STEP_ID_MAX_STEPS];
};
struct nv_pmu_rpc_struct_perf_vfe_eval {
/*[IN/OUT] Must be first field in RPC structure */
struct nv_pmu_rpc_header hdr;
struct nv_pmu_perf_rpc_vfe_equ_eval data;
u32 scratch[1];
};
#endif /* NVGPU_PMUIF_GPMUIFPERF_H*/