gpu: nvgpu: PG engines init/allow/disallow update

- pmu_init_powergating loops & init multiple
  PG engines based on PG engines supported
- generalize pg init param HAL to support
  multiple PG-engine init based on PG engine
  parameter
- HAL's to return supported PG engines on chip &
  its sub features of engine.
- Send Allow/Disallow for PG engines which are
  enabled & supported.
- Added defines for pg engines

JIRA DNVGPU-71

Change-Id: I236601e092e519a269fcb17c7d1c523a4b51405f
Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com>
Reviewed-on: http://git-master/r/1247409
(cherry-picked from commit 1c138cc475bac7d3c3fbbd5fb18cfcb2e7fdf67a)
Reviewed-on: http://git-master/r/1269319
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Mahantesh Kumbar
2016-11-03 15:21:43 +05:30
committed by mobile promotions
parent d301c02246
commit 75e52218ce
5 changed files with 172 additions and 75 deletions

View File

@@ -606,8 +606,10 @@ struct gpu_ops {
void (*pmu_elpg_statistics)(struct gk20a *g,
u32 *ingating_time, u32 *ungating_time,
u32 *gating_cnt);
int (*pmu_pg_grinit_param)(struct gk20a *g,
u8 grfeaturemask);
int (*pmu_pg_init_param)(struct gk20a *g, u32 pg_engine_id);
u32 (*pmu_pg_supported_engines_list)(struct gk20a *g);
u32 (*pmu_pg_engines_feature_list)(struct gk20a *g,
u32 pg_engine_id);
int (*send_lrf_tex_ltc_dram_overide_en_dis_cmd)
(struct gk20a *g, u32 mask);
void (*dump_secure_fuses)(struct gk20a *g);

View File

@@ -3048,9 +3048,6 @@ skip_init:
return err;
}
static void pmu_handle_pg_elpg_msg(struct gk20a *g, struct pmu_msg *msg,
void *param, u32 handle, u32 status);
static void pmu_handle_pg_buf_config_msg(struct gk20a *g, struct pmu_msg *msg,
void *param, u32 handle, u32 status)
{
@@ -3274,6 +3271,19 @@ static bool gk20a_is_pmu_supported(struct gk20a *g)
return true;
}
u32 gk20a_pmu_pg_engines_list(struct gk20a *g)
{
return BIT(PMU_PG_ELPG_ENGINE_ID_GRAPHICS);
}
u32 gk20a_pmu_pg_feature_list(struct gk20a *g, u32 pg_engine_id)
{
if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
return PMU_PG_FEATURE_GR_POWER_GATING_ENABLED;
return 0;
}
void gk20a_init_pmu_ops(struct gpu_ops *gops)
{
gops->pmu.is_pmu_supported = gk20a_is_pmu_supported;
@@ -3285,7 +3295,9 @@ void gk20a_init_pmu_ops(struct gpu_ops *gops)
gops->pmu.load_lsfalcon_ucode = NULL;
gops->pmu.write_dmatrfbase = gk20a_write_dmatrfbase;
gops->pmu.pmu_elpg_statistics = gk20a_pmu_elpg_statistics;
gops->pmu.pmu_pg_grinit_param = NULL;
gops->pmu.pmu_pg_init_param = NULL;
gops->pmu.pmu_pg_supported_engines_list = gk20a_pmu_pg_engines_list;
gops->pmu.pmu_pg_engines_feature_list = gk20a_pmu_pg_feature_list;
gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL;
gops->pmu.dump_secure_fuses = NULL;
gops->pmu.is_lazy_bootstrap = NULL;
@@ -3330,6 +3342,7 @@ static void pmu_handle_pg_elpg_msg(struct gk20a *g, struct pmu_msg *msg,
{
struct pmu_gk20a *pmu = param;
struct pmu_pg_msg_elpg_msg *elpg_msg = &msg->msg.pg.elpg_msg;
u32 *ack_status = param;
gk20a_dbg_fn("");
@@ -3341,18 +3354,32 @@ static void pmu_handle_pg_elpg_msg(struct gk20a *g, struct pmu_msg *msg,
switch (elpg_msg->msg) {
case PMU_PG_ELPG_MSG_INIT_ACK:
gk20a_dbg_pmu("INIT_PG is acknowledged from PMU");
gk20a_dbg_pmu("INIT_PG is ack from PMU, eng - %d",
elpg_msg->engine_id);
break;
case PMU_PG_ELPG_MSG_ALLOW_ACK:
gk20a_dbg_pmu("ALLOW is acknowledged from PMU");
pmu->elpg_stat = PMU_ELPG_STAT_ON;
gk20a_dbg_pmu("ALLOW is ack from PMU, eng - %d",
elpg_msg->engine_id);
if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
pmu->elpg_stat = PMU_ELPG_STAT_ON;
break;
case PMU_PG_ELPG_MSG_DISALLOW_ACK:
gk20a_dbg_pmu("DISALLOW is acknowledged from PMU");
pmu->elpg_stat = PMU_ELPG_STAT_OFF;
gk20a_dbg_pmu("DISALLOW is ack from PMU, eng - %d",
elpg_msg->engine_id);
if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
pmu->elpg_stat = PMU_ELPG_STAT_OFF;
else if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_MS)
*ack_status = 1;
if (pmu->pmu_state == PMU_STATE_ELPG_BOOTING) {
pmu->pmu_state = PMU_STATE_ELPG_BOOTED;
schedule_work(&pmu->pg_init);
if (g->ops.pmu.pmu_pg_engines_feature_list &&
g->ops.pmu.pmu_pg_engines_feature_list(g,
PMU_PG_ELPG_ENGINE_ID_GRAPHICS) !=
PMU_PG_FEATURE_GR_POWER_GATING_ENABLED) {
pmu->initialized = true;
pmu->pmu_state = PMU_STATE_STARTED;
} else
schedule_work(&pmu->pg_init);
}
break;
default:
@@ -3386,43 +3413,37 @@ static void pmu_handle_pg_stat_msg(struct gk20a *g, struct pmu_msg *msg,
}
}
static int pmu_init_powergating(struct gk20a *g)
static int pmu_pg_init_send(struct gk20a *g, u32 pg_engine_id)
{
struct pmu_gk20a *pmu = &g->pmu;
struct pmu_cmd cmd;
u32 seq;
u32 gr_engine_id;
gk20a_dbg_fn("");
gr_engine_id = gk20a_fifo_get_gr_engine_id(g);
if (tegra_cpu_is_asim()) {
/* TBD: calculate threshold for silicon */
gk20a_writel(g, pwr_pmu_pg_idlefilth_r(gr_engine_id),
PMU_PG_IDLE_THRESHOLD_SIM);
gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(gr_engine_id),
PMU_PG_POST_POWERUP_IDLE_THRESHOLD_SIM);
gk20a_writel(g, pwr_pmu_pg_idlefilth_r(pg_engine_id),
PMU_PG_IDLE_THRESHOLD_SIM);
gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(pg_engine_id),
PMU_PG_POST_POWERUP_IDLE_THRESHOLD_SIM);
} else {
/* TBD: calculate threshold for silicon */
gk20a_writel(g, pwr_pmu_pg_idlefilth_r(gr_engine_id),
PMU_PG_IDLE_THRESHOLD);
gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(gr_engine_id),
PMU_PG_POST_POWERUP_IDLE_THRESHOLD);
gk20a_writel(g, pwr_pmu_pg_idlefilth_r(pg_engine_id),
PMU_PG_IDLE_THRESHOLD);
gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(pg_engine_id),
PMU_PG_POST_POWERUP_IDLE_THRESHOLD);
}
gk20a_gr_wait_initialized(g);
if (g->ops.pmu.pmu_pg_grinit_param)
g->ops.pmu.pmu_pg_grinit_param(g,
PMU_PG_FEATURE_GR_POWER_GATING_ENABLED);
if (g->ops.pmu.pmu_pg_init_param)
g->ops.pmu.pmu_pg_init_param(g, pg_engine_id);
/* init ELPG */
memset(&cmd, 0, sizeof(struct pmu_cmd));
cmd.hdr.unit_id = PMU_UNIT_PG;
cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd);
cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
cmd.cmd.pg.elpg_cmd.engine_id = gr_engine_id;
cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_INIT;
gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_INIT");
@@ -3435,7 +3456,7 @@ static int pmu_init_powergating(struct gk20a *g)
cmd.hdr.unit_id = PMU_UNIT_PG;
cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_stat);
cmd.cmd.pg.stat.cmd_type = PMU_PG_CMD_ID_PG_STAT;
cmd.cmd.pg.stat.engine_id = gr_engine_id;
cmd.cmd.pg.stat.engine_id = pg_engine_id;
cmd.cmd.pg.stat.sub_cmd_id = PMU_PG_STAT_CMD_ALLOC_DMEM;
cmd.cmd.pg.stat.data = 0;
@@ -3445,20 +3466,45 @@ static int pmu_init_powergating(struct gk20a *g)
/* disallow ELPG initially
PMU ucode requires a disallow cmd before allow cmd */
pmu->elpg_stat = PMU_ELPG_STAT_OFF; /* set for wait_event PMU_ELPG_STAT_OFF */
/* set for wait_event PMU_ELPG_STAT_OFF */
if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
pmu->elpg_stat = PMU_ELPG_STAT_OFF;
memset(&cmd, 0, sizeof(struct pmu_cmd));
cmd.hdr.unit_id = PMU_UNIT_PG;
cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd);
cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
cmd.cmd.pg.elpg_cmd.engine_id = gr_engine_id;
cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_DISALLOW;
gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_DISALLOW");
gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
pmu_handle_pg_elpg_msg, pmu, &seq, ~0);
pmu_handle_pg_elpg_msg, pmu, &seq, ~0);
if (pmu->pmu_state == PMU_STATE_INIT_RECEIVED)
pmu->pmu_state = PMU_STATE_ELPG_BOOTING;
return 0;
}
static int pmu_init_powergating(struct gk20a *g)
{
struct pmu_gk20a *pmu = &g->pmu;
u32 pg_engine_id;
u32 pg_engine_id_list = 0;
gk20a_dbg_fn("");
if (g->ops.pmu.pmu_pg_supported_engines_list)
pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
gk20a_gr_wait_initialized(g);
for (pg_engine_id = PMU_PG_ELPG_ENGINE_ID_GRAPHICS;
pg_engine_id < PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE;
pg_engine_id++) {
if (BIT(pg_engine_id) & pg_engine_id_list) {
pmu_pg_init_send(g, pg_engine_id);
if (pmu->pmu_state == PMU_STATE_INIT_RECEIVED)
pmu->pmu_state = PMU_STATE_ELPG_BOOTING;
}
}
return 0;
}
@@ -4652,28 +4698,39 @@ static int gk20a_pmu_enable_elpg_locked(struct gk20a *g)
struct pmu_gk20a *pmu = &g->pmu;
struct pmu_cmd cmd;
u32 seq, status;
u32 gr_engine_id;
u32 pg_engine_id;
u32 pg_engine_id_list = 0;
gk20a_dbg_fn("");
gr_engine_id = gk20a_fifo_get_gr_engine_id(g);
if (g->ops.pmu.pmu_pg_supported_engines_list)
pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
for (pg_engine_id = PMU_PG_ELPG_ENGINE_ID_GRAPHICS;
pg_engine_id < PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE;
pg_engine_id++) {
memset(&cmd, 0, sizeof(struct pmu_cmd));
cmd.hdr.unit_id = PMU_UNIT_PG;
cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd);
cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
cmd.cmd.pg.elpg_cmd.engine_id = gr_engine_id;
cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_ALLOW;
if (BIT(pg_engine_id) & pg_engine_id_list) {
memset(&cmd, 0, sizeof(struct pmu_cmd));
cmd.hdr.unit_id = PMU_UNIT_PG;
cmd.hdr.size = PMU_CMD_HDR_SIZE +
sizeof(struct pmu_pg_cmd_elpg_cmd);
cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_ALLOW;
/* no need to wait ack for ELPG enable but set pending to sync
with follow up ELPG disable */
pmu->elpg_stat = PMU_ELPG_STAT_ON_PENDING;
/* no need to wait ack for ELPG enable but set
* pending to sync with follow up ELPG disable
*/
if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
pmu->elpg_stat = PMU_ELPG_STAT_ON_PENDING;
gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_ALLOW");
status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
pmu_handle_pg_elpg_msg, pmu, &seq, ~0);
BUG_ON(status != 0);
gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_ALLOW");
status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL,
PMU_COMMAND_QUEUE_HPQ, pmu_handle_pg_elpg_msg,
pmu, &seq, ~0);
WARN_ON(status != 0);
}
}
gk20a_dbg_fn("done");
return 0;
@@ -4729,11 +4786,17 @@ int gk20a_pmu_disable_elpg(struct gk20a *g)
struct pmu_cmd cmd;
u32 seq;
int ret = 0;
u32 gr_engine_id;
u32 pg_engine_id;
u32 pg_engine_id_list = 0;
u32 ack_status = 0;
u32 *wait_msg_cond_ptr = NULL;
u32 wait_msg_cond = 0;
void *cb_param = NULL;
gk20a_dbg_fn("");
gr_engine_id = gk20a_fifo_get_gr_engine_id(g);
if (g->ops.pmu.pmu_pg_supported_engines_list)
pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
if (!support_gk20a_pmu(g->dev))
return ret;
@@ -4778,28 +4841,49 @@ int gk20a_pmu_disable_elpg(struct gk20a *g)
goto exit_reschedule;
}
memset(&cmd, 0, sizeof(struct pmu_cmd));
cmd.hdr.unit_id = PMU_UNIT_PG;
cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd);
cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
cmd.cmd.pg.elpg_cmd.engine_id = gr_engine_id;
cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_DISALLOW;
for (pg_engine_id = PMU_PG_ELPG_ENGINE_ID_GRAPHICS;
pg_engine_id < PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE;
pg_engine_id++) {
pmu->elpg_stat = PMU_ELPG_STAT_OFF_PENDING;
if (BIT(pg_engine_id) & pg_engine_id_list) {
memset(&cmd, 0, sizeof(struct pmu_cmd));
cmd.hdr.unit_id = PMU_UNIT_PG;
cmd.hdr.size = PMU_CMD_HDR_SIZE +
sizeof(struct pmu_pg_cmd_elpg_cmd);
cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_DISALLOW;
gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_DISALLOW");
gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
pmu_handle_pg_elpg_msg, pmu, &seq, ~0);
if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
pmu->elpg_stat = PMU_ELPG_STAT_OFF_PENDING;
pmu_wait_message_cond(pmu, gk20a_get_gr_idle_timeout(g),
&pmu->elpg_stat, PMU_ELPG_STAT_OFF);
if (pmu->elpg_stat != PMU_ELPG_STAT_OFF) {
gk20a_err(dev_from_gk20a(g),
"ELPG_DISALLOW_ACK failed");
pmu_dump_elpg_stats(pmu);
pmu_dump_falcon_stats(pmu);
ret = -EBUSY;
goto exit_unlock;
if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS) {
wait_msg_cond_ptr = &pmu->elpg_stat;
wait_msg_cond = PMU_ELPG_STAT_OFF;
cb_param = pmu;
} else if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS) {
wait_msg_cond_ptr = &ack_status;
wait_msg_cond = 0x1;
cb_param = &ack_status;
}
gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_DISALLOW");
gk20a_pmu_cmd_post(g, &cmd, NULL, NULL,
PMU_COMMAND_QUEUE_HPQ, pmu_handle_pg_elpg_msg,
cb_param, &seq, ~0);
pmu_wait_message_cond(pmu,
gk20a_get_gr_idle_timeout(g),
wait_msg_cond_ptr, wait_msg_cond);
if (*wait_msg_cond_ptr != wait_msg_cond) {
gk20a_err(dev_from_gk20a(g),
"ELPG_DISALLOW_ACK failed");
pmu_dump_elpg_stats(pmu);
pmu_dump_falcon_stats(pmu);
ret = -EBUSY;
goto exit_unlock;
}
}
}
exit_reschedule:

View File

@@ -615,6 +615,10 @@ struct pmu_pg_stats {
#define PMU_PG_IDLE_THRESHOLD 15000
#define PMU_PG_POST_POWERUP_IDLE_THRESHOLD 1000000
#define PMU_PG_ELPG_ENGINE_ID_GRAPHICS (0x00000000)
#define PMU_PG_ELPG_ENGINE_ID_MS (0x00000004)
#define PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE (0x00000005)
/* state transition :
OFF => [OFF_ON_PENDING optional] => ON_PENDING => ON => OFF
ON => OFF is always synchronized */
@@ -771,6 +775,9 @@ int gk20a_pmu_cmd_post(struct gk20a *g, struct pmu_cmd *cmd, struct pmu_msg *msg
int gk20a_pmu_enable_elpg(struct gk20a *g);
int gk20a_pmu_disable_elpg(struct gk20a *g);
u32 gk20a_pmu_pg_engines_list(struct gk20a *g);
u32 gk20a_pmu_pg_feature_list(struct gk20a *g, u32 pg_engine_id);
void gk20a_pmu_save_zbc(struct gk20a *g, u32 entries);
int gk20a_pmu_perfmon_enable(struct gk20a *g, bool enable);

View File

@@ -156,7 +156,9 @@ void gm206_init_pmu_ops(struct gpu_ops *gops)
gops->pmu.fecsbootstrapdone = false;
gops->pmu.write_dmatrfbase = gm20b_write_dmatrfbase;
gops->pmu.pmu_elpg_statistics = NULL;
gops->pmu.pmu_pg_grinit_param = NULL;
gops->pmu.pmu_pg_init_param = NULL;
gops->pmu.pmu_pg_supported_engines_list = NULL;
gops->pmu.pmu_pg_engines_feature_list = NULL;
gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL;
gops->pmu.dump_secure_fuses = NULL;
gops->pmu.reset = gk20a_pmu_reset;

View File

@@ -285,7 +285,9 @@ void gm20b_init_pmu_ops(struct gpu_ops *gops)
gops->pmu.fecsbootstrapdone = false;
gops->pmu.write_dmatrfbase = gm20b_write_dmatrfbase;
gops->pmu.pmu_elpg_statistics = gk20a_pmu_elpg_statistics;
gops->pmu.pmu_pg_grinit_param = NULL;
gops->pmu.pmu_pg_init_param = NULL;
gops->pmu.pmu_pg_supported_engines_list = gk20a_pmu_pg_engines_list;
gops->pmu.pmu_pg_engines_feature_list = gk20a_pmu_pg_feature_list;
gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL;
gops->pmu.dump_secure_fuses = pmu_dump_security_fuses_gm20b;
gops->pmu.reset = gk20a_pmu_reset;