diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 2 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/pmu_gk20a.c | 140 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/pmu_gk20a.h | 5 |
3 files changed, 131 insertions, 16 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 782469df..d444447d 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h | |||
@@ -603,7 +603,7 @@ struct gpu_ops { | |||
603 | int (*init_wpr_region)(struct gk20a *g); | 603 | int (*init_wpr_region)(struct gk20a *g); |
604 | int (*load_lsfalcon_ucode)(struct gk20a *g, u32 falconidmask); | 604 | int (*load_lsfalcon_ucode)(struct gk20a *g, u32 falconidmask); |
605 | void (*write_dmatrfbase)(struct gk20a *g, u32 addr); | 605 | void (*write_dmatrfbase)(struct gk20a *g, u32 addr); |
606 | void (*pmu_elpg_statistics)(struct gk20a *g, | 606 | void (*pmu_elpg_statistics)(struct gk20a *g, u32 pg_engine_id, |
607 | u32 *ingating_time, u32 *ungating_time, | 607 | u32 *ingating_time, u32 *ungating_time, |
608 | u32 *gating_cnt); | 608 | u32 *gating_cnt); |
609 | int (*pmu_pg_init_param)(struct gk20a *g, u32 pg_engine_id); | 609 | int (*pmu_pg_init_param)(struct gk20a *g, u32 pg_engine_id); |
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c index 2b847008..e221be11 100644 --- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c | |||
@@ -47,7 +47,8 @@ | |||
47 | gk20a_dbg(gpu_dbg_pmu, fmt, ##arg) | 47 | gk20a_dbg(gpu_dbg_pmu, fmt, ##arg) |
48 | 48 | ||
49 | static int gk20a_pmu_get_elpg_residency_gating(struct gk20a *g, | 49 | static int gk20a_pmu_get_elpg_residency_gating(struct gk20a *g, |
50 | u32 *ingating_time, u32 *ungating_time, u32 *gating_cnt); | 50 | u32 pg_engine_id, u32 *ingating_time, |
51 | u32 *ungating_time, u32 *gating_cnt); | ||
51 | static void ap_callback_init_and_enable_ctrl( | 52 | static void ap_callback_init_and_enable_ctrl( |
52 | struct gk20a *g, struct pmu_msg *msg, | 53 | struct gk20a *g, struct pmu_msg *msg, |
53 | void *param, u32 seq_desc, u32 status); | 54 | void *param, u32 seq_desc, u32 status); |
@@ -3411,7 +3412,8 @@ static void pmu_handle_pg_stat_msg(struct gk20a *g, struct pmu_msg *msg, | |||
3411 | switch (msg->msg.pg.stat.sub_msg_id) { | 3412 | switch (msg->msg.pg.stat.sub_msg_id) { |
3412 | case PMU_PG_STAT_MSG_RESP_DMEM_OFFSET: | 3413 | case PMU_PG_STAT_MSG_RESP_DMEM_OFFSET: |
3413 | gk20a_dbg_pmu("ALLOC_DMEM_OFFSET is acknowledged from PMU"); | 3414 | gk20a_dbg_pmu("ALLOC_DMEM_OFFSET is acknowledged from PMU"); |
3414 | pmu->stat_dmem_offset = msg->msg.pg.stat.data; | 3415 | pmu->stat_dmem_offset[msg->msg.pg.stat.engine_id] = |
3416 | msg->msg.pg.stat.data; | ||
3415 | break; | 3417 | break; |
3416 | default: | 3418 | default: |
3417 | break; | 3419 | break; |
@@ -3456,7 +3458,7 @@ static int pmu_pg_init_send(struct gk20a *g, u32 pg_engine_id) | |||
3456 | pmu_handle_pg_elpg_msg, pmu, &seq, ~0); | 3458 | pmu_handle_pg_elpg_msg, pmu, &seq, ~0); |
3457 | 3459 | ||
3458 | /* alloc dmem for powergating state log */ | 3460 | /* alloc dmem for powergating state log */ |
3459 | pmu->stat_dmem_offset = 0; | 3461 | pmu->stat_dmem_offset[pg_engine_id] = 0; |
3460 | memset(&cmd, 0, sizeof(struct pmu_cmd)); | 3462 | memset(&cmd, 0, sizeof(struct pmu_cmd)); |
3461 | cmd.hdr.unit_id = PMU_UNIT_PG; | 3463 | cmd.hdr.unit_id = PMU_UNIT_PG; |
3462 | cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_stat); | 3464 | cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_stat); |
@@ -4122,7 +4124,8 @@ static void pmu_dump_elpg_stats(struct pmu_gk20a *pmu) | |||
4122 | struct gk20a *g = gk20a_from_pmu(pmu); | 4124 | struct gk20a *g = gk20a_from_pmu(pmu); |
4123 | struct pmu_pg_stats stats; | 4125 | struct pmu_pg_stats stats; |
4124 | 4126 | ||
4125 | pmu_copy_from_dmem(pmu, pmu->stat_dmem_offset, | 4127 | pmu_copy_from_dmem(pmu, |
4128 | pmu->stat_dmem_offset[PMU_PG_ELPG_ENGINE_ID_GRAPHICS], | ||
4126 | (u8 *)&stats, sizeof(struct pmu_pg_stats), 0); | 4129 | (u8 *)&stats, sizeof(struct pmu_pg_stats), 0); |
4127 | 4130 | ||
4128 | gk20a_dbg_pmu("pg_entry_start_timestamp : 0x%016llx", | 4131 | gk20a_dbg_pmu("pg_entry_start_timestamp : 0x%016llx", |
@@ -4965,7 +4968,8 @@ int gk20a_pmu_destroy(struct gk20a *g) | |||
4965 | /* make sure the pending operations are finished before we continue */ | 4968 | /* make sure the pending operations are finished before we continue */ |
4966 | cancel_work_sync(&pmu->pg_init); | 4969 | cancel_work_sync(&pmu->pg_init); |
4967 | 4970 | ||
4968 | gk20a_pmu_get_elpg_residency_gating(g, &elpg_ingating_time, | 4971 | gk20a_pmu_get_elpg_residency_gating(g, |
4972 | PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &elpg_ingating_time, | ||
4969 | &elpg_ungating_time, &gating_cnt); | 4973 | &elpg_ungating_time, &gating_cnt); |
4970 | 4974 | ||
4971 | gk20a_pmu_disable_elpg(g); | 4975 | gk20a_pmu_disable_elpg(g); |
@@ -5044,14 +5048,15 @@ void gk20a_pmu_reset_load_counters(struct gk20a *g) | |||
5044 | gk20a_idle(g->dev); | 5048 | gk20a_idle(g->dev); |
5045 | } | 5049 | } |
5046 | 5050 | ||
5047 | void gk20a_pmu_elpg_statistics(struct gk20a *g, | 5051 | void gk20a_pmu_elpg_statistics(struct gk20a *g, u32 pg_engine_id, |
5048 | u32 *ingating_time, u32 *ungating_time, u32 *gating_cnt) | 5052 | u32 *ingating_time, u32 *ungating_time, u32 *gating_cnt) |
5049 | { | 5053 | { |
5050 | struct pmu_gk20a *pmu = &g->pmu; | 5054 | struct pmu_gk20a *pmu = &g->pmu; |
5051 | struct pmu_pg_stats stats; | 5055 | struct pmu_pg_stats stats; |
5052 | 5056 | ||
5053 | pmu_copy_from_dmem(pmu, pmu->stat_dmem_offset, | 5057 | pmu_copy_from_dmem(pmu, |
5054 | (u8 *)&stats, sizeof(struct pmu_pg_stats), 0); | 5058 | pmu->stat_dmem_offset[pg_engine_id], |
5059 | (u8 *)&stats, sizeof(struct pmu_pg_stats), 0); | ||
5055 | 5060 | ||
5056 | *ingating_time = stats.pg_ingating_time_us; | 5061 | *ingating_time = stats.pg_ingating_time_us; |
5057 | *ungating_time = stats.pg_ungating_time_us; | 5062 | *ungating_time = stats.pg_ungating_time_us; |
@@ -5059,9 +5064,11 @@ void gk20a_pmu_elpg_statistics(struct gk20a *g, | |||
5059 | } | 5064 | } |
5060 | 5065 | ||
5061 | static int gk20a_pmu_get_elpg_residency_gating(struct gk20a *g, | 5066 | static int gk20a_pmu_get_elpg_residency_gating(struct gk20a *g, |
5062 | u32 *ingating_time, u32 *ungating_time, u32 *gating_cnt) | 5067 | u32 pg_engine_id, u32 *ingating_time, |
5068 | u32 *ungating_time, u32 *gating_cnt) | ||
5063 | { | 5069 | { |
5064 | struct pmu_gk20a *pmu = &g->pmu; | 5070 | struct pmu_gk20a *pmu = &g->pmu; |
5071 | u32 pg_engine_id_list = 0; | ||
5065 | 5072 | ||
5066 | if (!pmu->initialized) { | 5073 | if (!pmu->initialized) { |
5067 | *ingating_time = 0; | 5074 | *ingating_time = 0; |
@@ -5070,8 +5077,13 @@ static int gk20a_pmu_get_elpg_residency_gating(struct gk20a *g, | |||
5070 | return 0; | 5077 | return 0; |
5071 | } | 5078 | } |
5072 | 5079 | ||
5073 | g->ops.pmu.pmu_elpg_statistics(g, ingating_time, | 5080 | if (g->ops.pmu.pmu_pg_supported_engines_list) |
5074 | ungating_time, gating_cnt); | 5081 | pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g); |
5082 | |||
5083 | if (BIT(pg_engine_id) & pg_engine_id_list) | ||
5084 | g->ops.pmu.pmu_elpg_statistics(g, pg_engine_id, | ||
5085 | ingating_time, | ||
5086 | ungating_time, gating_cnt); | ||
5075 | 5087 | ||
5076 | return 0; | 5088 | return 0; |
5077 | } | 5089 | } |
@@ -5224,6 +5236,94 @@ int gk20a_aelpg_init_and_enable(struct gk20a *g, u8 ctrl_id) | |||
5224 | } | 5236 | } |
5225 | 5237 | ||
5226 | #ifdef CONFIG_DEBUG_FS | 5238 | #ifdef CONFIG_DEBUG_FS |
5239 | static int mscg_residency_show(struct seq_file *s, void *data) | ||
5240 | { | ||
5241 | struct gk20a *g = s->private; | ||
5242 | u32 ingating_time = 0; | ||
5243 | u32 ungating_time = 0; | ||
5244 | u32 gating_cnt; | ||
5245 | u64 total_ingating, total_ungating, residency, divisor, dividend; | ||
5246 | int err; | ||
5247 | |||
5248 | /* Don't unnecessarily power on the device */ | ||
5249 | if (g->power_on) { | ||
5250 | err = gk20a_busy(g->dev); | ||
5251 | if (err) | ||
5252 | return err; | ||
5253 | |||
5254 | gk20a_pmu_get_elpg_residency_gating(g, | ||
5255 | PMU_PG_ELPG_ENGINE_ID_MS, &ingating_time, | ||
5256 | &ungating_time, &gating_cnt); | ||
5257 | gk20a_idle(g->dev); | ||
5258 | } | ||
5259 | total_ingating = g->pg_ingating_time_us + (u64)ingating_time; | ||
5260 | total_ungating = g->pg_ungating_time_us + (u64)ungating_time; | ||
5261 | divisor = total_ingating + total_ungating; | ||
5262 | |||
5263 | /* We compute the residency on a scale of 1000 */ | ||
5264 | dividend = total_ingating * 1000; | ||
5265 | |||
5266 | if (divisor) | ||
5267 | residency = div64_u64(dividend, divisor); | ||
5268 | else | ||
5269 | residency = 0; | ||
5270 | |||
5271 | seq_printf(s, "Time in MSCG: %llu us\n" | ||
5272 | "Time out of MSCG: %llu us\n" | ||
5273 | "MSCG residency ratio: %llu\n", | ||
5274 | total_ingating, total_ungating, residency); | ||
5275 | return 0; | ||
5276 | |||
5277 | } | ||
5278 | |||
5279 | static int mscg_residency_open(struct inode *inode, struct file *file) | ||
5280 | { | ||
5281 | return single_open(file, mscg_residency_show, inode->i_private); | ||
5282 | } | ||
5283 | |||
5284 | static const struct file_operations mscg_residency_fops = { | ||
5285 | .open = mscg_residency_open, | ||
5286 | .read = seq_read, | ||
5287 | .llseek = seq_lseek, | ||
5288 | .release = single_release, | ||
5289 | }; | ||
5290 | |||
5291 | static int mscg_transitions_show(struct seq_file *s, void *data) | ||
5292 | { | ||
5293 | struct gk20a *g = s->private; | ||
5294 | u32 ingating_time, ungating_time, total_gating_cnt; | ||
5295 | u32 gating_cnt = 0; | ||
5296 | int err; | ||
5297 | |||
5298 | if (g->power_on) { | ||
5299 | err = gk20a_busy(g->dev); | ||
5300 | if (err) | ||
5301 | return err; | ||
5302 | |||
5303 | gk20a_pmu_get_elpg_residency_gating(g, | ||
5304 | PMU_PG_ELPG_ENGINE_ID_MS, &ingating_time, | ||
5305 | &ungating_time, &gating_cnt); | ||
5306 | gk20a_idle(g->dev); | ||
5307 | } | ||
5308 | total_gating_cnt = g->pg_gating_cnt + gating_cnt; | ||
5309 | |||
5310 | seq_printf(s, "%u\n", total_gating_cnt); | ||
5311 | return 0; | ||
5312 | |||
5313 | } | ||
5314 | |||
5315 | static int mscg_transitions_open(struct inode *inode, struct file *file) | ||
5316 | { | ||
5317 | return single_open(file, mscg_transitions_show, inode->i_private); | ||
5318 | } | ||
5319 | |||
5320 | static const struct file_operations mscg_transitions_fops = { | ||
5321 | .open = mscg_transitions_open, | ||
5322 | .read = seq_read, | ||
5323 | .llseek = seq_lseek, | ||
5324 | .release = single_release, | ||
5325 | }; | ||
5326 | |||
5227 | static int elpg_residency_show(struct seq_file *s, void *data) | 5327 | static int elpg_residency_show(struct seq_file *s, void *data) |
5228 | { | 5328 | { |
5229 | struct gk20a *g = s->private; | 5329 | struct gk20a *g = s->private; |
@@ -5239,7 +5339,8 @@ static int elpg_residency_show(struct seq_file *s, void *data) | |||
5239 | if (err) | 5339 | if (err) |
5240 | return err; | 5340 | return err; |
5241 | 5341 | ||
5242 | gk20a_pmu_get_elpg_residency_gating(g, &ingating_time, | 5342 | gk20a_pmu_get_elpg_residency_gating(g, |
5343 | PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &ingating_time, | ||
5243 | &ungating_time, &gating_cnt); | 5344 | &ungating_time, &gating_cnt); |
5244 | gk20a_idle(g->dev); | 5345 | gk20a_idle(g->dev); |
5245 | } | 5346 | } |
@@ -5287,7 +5388,8 @@ static int elpg_transitions_show(struct seq_file *s, void *data) | |||
5287 | if (err) | 5388 | if (err) |
5288 | return err; | 5389 | return err; |
5289 | 5390 | ||
5290 | gk20a_pmu_get_elpg_residency_gating(g, &ingating_time, | 5391 | gk20a_pmu_get_elpg_residency_gating(g, |
5392 | PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &ingating_time, | ||
5291 | &ungating_time, &gating_cnt); | 5393 | &ungating_time, &gating_cnt); |
5292 | gk20a_idle(g->dev); | 5394 | gk20a_idle(g->dev); |
5293 | } | 5395 | } |
@@ -5465,6 +5567,18 @@ int gk20a_pmu_debugfs_init(struct device *dev) | |||
5465 | struct gk20a *g = get_gk20a(dev); | 5567 | struct gk20a *g = get_gk20a(dev); |
5466 | 5568 | ||
5467 | d = debugfs_create_file( | 5569 | d = debugfs_create_file( |
5570 | "mscg_residency", S_IRUGO|S_IWUSR, platform->debugfs, g, | ||
5571 | &mscg_residency_fops); | ||
5572 | if (!d) | ||
5573 | goto err_out; | ||
5574 | |||
5575 | d = debugfs_create_file( | ||
5576 | "mscg_transitions", S_IRUGO, platform->debugfs, g, | ||
5577 | &mscg_transitions_fops); | ||
5578 | if (!d) | ||
5579 | goto err_out; | ||
5580 | |||
5581 | d = debugfs_create_file( | ||
5468 | "elpg_residency", S_IRUGO|S_IWUSR, platform->debugfs, g, | 5582 | "elpg_residency", S_IRUGO|S_IWUSR, platform->debugfs, g, |
5469 | &elpg_residency_fops); | 5583 | &elpg_residency_fops); |
5470 | if (!d) | 5584 | if (!d) |
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h index 56300dc8..cf4f3b52 100644 --- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h | |||
@@ -618,6 +618,7 @@ struct pmu_pg_stats { | |||
618 | #define PMU_PG_ELPG_ENGINE_ID_GRAPHICS (0x00000000) | 618 | #define PMU_PG_ELPG_ENGINE_ID_GRAPHICS (0x00000000) |
619 | #define PMU_PG_ELPG_ENGINE_ID_MS (0x00000004) | 619 | #define PMU_PG_ELPG_ENGINE_ID_MS (0x00000004) |
620 | #define PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE (0x00000005) | 620 | #define PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE (0x00000005) |
621 | #define PMU_PG_ELPG_ENGINE_MAX PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE | ||
621 | 622 | ||
622 | /* state transition : | 623 | /* state transition : |
623 | OFF => [OFF_ON_PENDING optional] => ON_PENDING => ON => OFF | 624 | OFF => [OFF_ON_PENDING optional] => ON_PENDING => ON => OFF |
@@ -715,7 +716,7 @@ struct pmu_gk20a { | |||
715 | 716 | ||
716 | u32 zbc_save_done; | 717 | u32 zbc_save_done; |
717 | 718 | ||
718 | u32 stat_dmem_offset; | 719 | u32 stat_dmem_offset[PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE]; |
719 | 720 | ||
720 | u32 elpg_stat; | 721 | u32 elpg_stat; |
721 | 722 | ||
@@ -823,7 +824,7 @@ int pmu_wait_message_cond(struct pmu_gk20a *pmu, u32 timeout_ms, | |||
823 | u32 *var, u32 val); | 824 | u32 *var, u32 val); |
824 | void pmu_handle_fecs_boot_acr_msg(struct gk20a *g, struct pmu_msg *msg, | 825 | void pmu_handle_fecs_boot_acr_msg(struct gk20a *g, struct pmu_msg *msg, |
825 | void *param, u32 handle, u32 status); | 826 | void *param, u32 handle, u32 status); |
826 | void gk20a_pmu_elpg_statistics(struct gk20a *g, | 827 | void gk20a_pmu_elpg_statistics(struct gk20a *g, u32 pg_engine_id, |
827 | u32 *ingating_time, u32 *ungating_time, u32 *gating_cnt); | 828 | u32 *ingating_time, u32 *ungating_time, u32 *gating_cnt); |
828 | int gk20a_pmu_reset(struct gk20a *g); | 829 | int gk20a_pmu_reset(struct gk20a *g); |
829 | int pmu_idle(struct pmu_gk20a *pmu); | 830 | int pmu_idle(struct pmu_gk20a *pmu); |