summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
diff options
context:
space:
mode:
authorMahantesh Kumbar <mkumbar@nvidia.com>2017-06-07 12:56:00 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-06-13 16:19:47 -0400
commitc18364d0c4b3fb6581f937c018cd01fc329601bb (patch)
tree923ab682435379dc8bad7852c49725bf7f0f5286 /drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
parent45355f00e7de9068f403682044f550026fa7e86e (diff)
gpu: nvgpu: moved pg out from pmu_gk20a.c/h
- moved pg related code to pmu_pg.c under common/pmu folder PG state machine support methods PG ACK handlers AELPG methods PG enable/disable methods -prepended with nvgpu_ for elpg/aelpg global methods by replacing gk20a_ JIRA NVGPU-97 Change-Id: I2148a69ff86b5c5d43c521ff6e241db84afafd82 Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com> Reviewed-on: http://git-master/r/1498363 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/pmu_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/pmu_gk20a.c692
1 files changed, 9 insertions, 683 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
index 247b38a5..32303c6e 100644
--- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
@@ -41,10 +41,6 @@
41#define PMU_MEM_SCRUBBING_TIMEOUT_MAX 1000 41#define PMU_MEM_SCRUBBING_TIMEOUT_MAX 1000
42#define PMU_MEM_SCRUBBING_TIMEOUT_DEFAULT 10 42#define PMU_MEM_SCRUBBING_TIMEOUT_DEFAULT 10
43 43
44static void ap_callback_init_and_enable_ctrl(
45 struct gk20a *g, struct pmu_msg *msg,
46 void *param, u32 seq_desc, u32 status);
47
48bool nvgpu_find_hex_in_string(char *strings, struct gk20a *g, u32 *hex_pos) 44bool nvgpu_find_hex_in_string(char *strings, struct gk20a *g, u32 *hex_pos)
49{ 45{
50 u32 i = 0, j = strlen(strings); 46 u32 i = 0, j = strlen(strings);
@@ -488,6 +484,14 @@ int pmu_bootstrap(struct nvgpu_pmu *pmu)
488 return 0; 484 return 0;
489} 485}
490 486
487void gk20a_pmu_pg_idle_counter_config(struct gk20a *g, u32 pg_engine_id)
488{
489 gk20a_writel(g, pwr_pmu_pg_idlefilth_r(pg_engine_id),
490 PMU_PG_IDLE_THRESHOLD);
491 gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(pg_engine_id),
492 PMU_PG_POST_POWERUP_IDLE_THRESHOLD);
493}
494
491int gk20a_pmu_mutex_acquire(struct nvgpu_pmu *pmu, u32 id, u32 *token) 495int gk20a_pmu_mutex_acquire(struct nvgpu_pmu *pmu, u32 id, u32 *token)
492{ 496{
493 struct gk20a *g = gk20a_from_pmu(pmu); 497 struct gk20a *g = gk20a_from_pmu(pmu);
@@ -692,30 +696,6 @@ void gk20a_pmu_msgq_tail(struct nvgpu_pmu *pmu, u32 *tail, bool set)
692 pwr_pmu_msgq_tail_val_f(*tail)); 696 pwr_pmu_msgq_tail_val_f(*tail));
693} 697}
694 698
695static void pmu_handle_pg_buf_config_msg(struct gk20a *g, struct pmu_msg *msg,
696 void *param, u32 handle, u32 status)
697{
698 struct nvgpu_pmu *pmu = param;
699 struct pmu_pg_msg_eng_buf_stat *eng_buf_stat = &msg->msg.pg.eng_buf_stat;
700
701 gk20a_dbg_fn("");
702
703 gk20a_dbg_pmu("reply PMU_PG_CMD_ID_ENG_BUF_LOAD PMU_PGENG_GR_BUFFER_IDX_FECS");
704 if (status != 0) {
705 nvgpu_err(g, "PGENG cmd aborted");
706 /* TBD: disable ELPG */
707 return;
708 }
709
710 pmu->buf_loaded = (eng_buf_stat->status == PMU_PG_MSG_ENG_BUF_LOADED);
711 if ((!pmu->buf_loaded) &&
712 (pmu->pmu_state == PMU_STATE_LOADING_PG_BUF))
713 nvgpu_err(g, "failed to load PGENG buffer");
714 else {
715 nvgpu_pmu_state_change(g, pmu->pmu_state, true);
716 }
717}
718
719static int gk20a_init_pmu_setup_hw1(struct gk20a *g) 699static int gk20a_init_pmu_setup_hw1(struct gk20a *g)
720{ 700{
721 struct nvgpu_pmu *pmu = &g->pmu; 701 struct nvgpu_pmu *pmu = &g->pmu;
@@ -750,80 +730,6 @@ static int gk20a_init_pmu_setup_hw1(struct gk20a *g)
750 730
751} 731}
752 732
753int nvgpu_pmu_init_bind_fecs(struct gk20a *g)
754{
755 struct nvgpu_pmu *pmu = &g->pmu;
756 struct pmu_cmd cmd;
757 u32 desc;
758 int err = 0;
759 u32 gr_engine_id;
760
761 gk20a_dbg_fn("");
762
763 gr_engine_id = gk20a_fifo_get_gr_engine_id(g);
764
765 memset(&cmd, 0, sizeof(struct pmu_cmd));
766 cmd.hdr.unit_id = PMU_UNIT_PG;
767 cmd.hdr.size = PMU_CMD_HDR_SIZE +
768 g->ops.pmu_ver.pg_cmd_eng_buf_load_size(&cmd.cmd.pg);
769 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_cmd_type(&cmd.cmd.pg,
770 PMU_PG_CMD_ID_ENG_BUF_LOAD);
771 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_engine_id(&cmd.cmd.pg,
772 gr_engine_id);
773 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_buf_idx(&cmd.cmd.pg,
774 PMU_PGENG_GR_BUFFER_IDX_FECS);
775 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_buf_size(&cmd.cmd.pg,
776 pmu->pg_buf.size);
777 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_dma_base(&cmd.cmd.pg,
778 u64_lo32(pmu->pg_buf.gpu_va));
779 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_dma_offset(&cmd.cmd.pg,
780 (u8)(pmu->pg_buf.gpu_va & 0xFF));
781 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_dma_idx(&cmd.cmd.pg,
782 PMU_DMAIDX_VIRT);
783
784 pmu->buf_loaded = false;
785 gk20a_dbg_pmu("cmd post PMU_PG_CMD_ID_ENG_BUF_LOAD PMU_PGENG_GR_BUFFER_IDX_FECS");
786 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_LPQ,
787 pmu_handle_pg_buf_config_msg, pmu, &desc, ~0);
788 nvgpu_pmu_state_change(g, PMU_STATE_LOADING_PG_BUF, false);
789 return err;
790}
791
792void nvgpu_pmu_setup_hw_load_zbc(struct gk20a *g)
793{
794 struct nvgpu_pmu *pmu = &g->pmu;
795 struct pmu_cmd cmd;
796 u32 desc;
797 u32 gr_engine_id;
798
799 gr_engine_id = gk20a_fifo_get_gr_engine_id(g);
800
801 memset(&cmd, 0, sizeof(struct pmu_cmd));
802 cmd.hdr.unit_id = PMU_UNIT_PG;
803 cmd.hdr.size = PMU_CMD_HDR_SIZE +
804 g->ops.pmu_ver.pg_cmd_eng_buf_load_size(&cmd.cmd.pg);
805 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_cmd_type(&cmd.cmd.pg,
806 PMU_PG_CMD_ID_ENG_BUF_LOAD);
807 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_engine_id(&cmd.cmd.pg,
808 gr_engine_id);
809 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_buf_idx(&cmd.cmd.pg,
810 PMU_PGENG_GR_BUFFER_IDX_ZBC);
811 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_buf_size(&cmd.cmd.pg,
812 pmu->seq_buf.size);
813 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_dma_base(&cmd.cmd.pg,
814 u64_lo32(pmu->seq_buf.gpu_va));
815 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_dma_offset(&cmd.cmd.pg,
816 (u8)(pmu->seq_buf.gpu_va & 0xFF));
817 g->ops.pmu_ver.pg_cmd_eng_buf_load_set_dma_idx(&cmd.cmd.pg,
818 PMU_DMAIDX_VIRT);
819
820 pmu->buf_loaded = false;
821 gk20a_dbg_pmu("cmd post PMU_PG_CMD_ID_ENG_BUF_LOAD PMU_PGENG_GR_BUFFER_IDX_ZBC");
822 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_LPQ,
823 pmu_handle_pg_buf_config_msg, pmu, &desc, ~0);
824 nvgpu_pmu_state_change(g, PMU_STATE_LOADING_ZBC, false);
825}
826
827static void gk20a_write_dmatrfbase(struct gk20a *g, u32 addr) 733static void gk20a_write_dmatrfbase(struct gk20a *g, u32 addr)
828{ 734{
829 gk20a_writel(g, pwr_falcon_dmatrfbase_r(), addr); 735 gk20a_writel(g, pwr_falcon_dmatrfbase_r(), addr);
@@ -896,184 +802,6 @@ void gk20a_init_pmu_ops(struct gpu_ops *gops)
896 gops->pmu.reset = gk20a_pmu_reset; 802 gops->pmu.reset = gk20a_pmu_reset;
897} 803}
898 804
899static void pmu_handle_pg_elpg_msg(struct gk20a *g, struct pmu_msg *msg,
900 void *param, u32 handle, u32 status)
901{
902 struct nvgpu_pmu *pmu = param;
903 struct pmu_pg_msg_elpg_msg *elpg_msg = &msg->msg.pg.elpg_msg;
904
905 gk20a_dbg_fn("");
906
907 if (status != 0) {
908 nvgpu_err(g, "ELPG cmd aborted");
909 /* TBD: disable ELPG */
910 return;
911 }
912
913 switch (elpg_msg->msg) {
914 case PMU_PG_ELPG_MSG_INIT_ACK:
915 gk20a_dbg_pmu("INIT_PG is ack from PMU, eng - %d",
916 elpg_msg->engine_id);
917 break;
918 case PMU_PG_ELPG_MSG_ALLOW_ACK:
919 gk20a_dbg_pmu("ALLOW is ack from PMU, eng - %d",
920 elpg_msg->engine_id);
921 if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
922 pmu->elpg_stat = PMU_ELPG_STAT_ON;
923 else if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_MS)
924 pmu->mscg_transition_state = PMU_ELPG_STAT_ON;
925 break;
926 case PMU_PG_ELPG_MSG_DISALLOW_ACK:
927 gk20a_dbg_pmu("DISALLOW is ack from PMU, eng - %d",
928 elpg_msg->engine_id);
929
930 if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
931 pmu->elpg_stat = PMU_ELPG_STAT_OFF;
932 else if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_MS)
933 pmu->mscg_transition_state = PMU_ELPG_STAT_OFF;
934
935 if (pmu->pmu_state == PMU_STATE_ELPG_BOOTING) {
936 if (g->ops.pmu.pmu_pg_engines_feature_list &&
937 g->ops.pmu.pmu_pg_engines_feature_list(g,
938 PMU_PG_ELPG_ENGINE_ID_GRAPHICS) !=
939 PMU_PG_FEATURE_GR_POWER_GATING_ENABLED) {
940 pmu->initialized = true;
941 nvgpu_pmu_state_change(g, PMU_STATE_STARTED,
942 false);
943 WRITE_ONCE(pmu->mscg_stat, PMU_MSCG_DISABLED);
944 /* make status visible */
945 smp_mb();
946 } else
947 nvgpu_pmu_state_change(g, PMU_STATE_ELPG_BOOTED,
948 true);
949 }
950 break;
951 default:
952 nvgpu_err(g,
953 "unsupported ELPG message : 0x%04x", elpg_msg->msg);
954 }
955
956 return;
957}
958
959static void pmu_handle_pg_stat_msg(struct gk20a *g, struct pmu_msg *msg,
960 void *param, u32 handle, u32 status)
961{
962 struct nvgpu_pmu *pmu = param;
963
964 gk20a_dbg_fn("");
965
966 if (status != 0) {
967 nvgpu_err(g, "ELPG cmd aborted");
968 /* TBD: disable ELPG */
969 return;
970 }
971
972 switch (msg->msg.pg.stat.sub_msg_id) {
973 case PMU_PG_STAT_MSG_RESP_DMEM_OFFSET:
974 gk20a_dbg_pmu("ALLOC_DMEM_OFFSET is acknowledged from PMU");
975 pmu->stat_dmem_offset[msg->msg.pg.stat.engine_id] =
976 msg->msg.pg.stat.data;
977 break;
978 default:
979 break;
980 }
981}
982
983static int pmu_pg_init_send(struct gk20a *g, u32 pg_engine_id)
984{
985 struct nvgpu_pmu *pmu = &g->pmu;
986 struct pmu_cmd cmd;
987 u32 seq;
988
989 gk20a_dbg_fn("");
990
991 gk20a_writel(g, pwr_pmu_pg_idlefilth_r(pg_engine_id),
992 PMU_PG_IDLE_THRESHOLD);
993 gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(pg_engine_id),
994 PMU_PG_POST_POWERUP_IDLE_THRESHOLD);
995
996 if (g->ops.pmu.pmu_pg_init_param)
997 g->ops.pmu.pmu_pg_init_param(g, pg_engine_id);
998
999 /* init ELPG */
1000 memset(&cmd, 0, sizeof(struct pmu_cmd));
1001 cmd.hdr.unit_id = PMU_UNIT_PG;
1002 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd);
1003 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
1004 cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
1005 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_INIT;
1006
1007 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_INIT");
1008 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
1009 pmu_handle_pg_elpg_msg, pmu, &seq, ~0);
1010
1011 /* alloc dmem for powergating state log */
1012 pmu->stat_dmem_offset[pg_engine_id] = 0;
1013 memset(&cmd, 0, sizeof(struct pmu_cmd));
1014 cmd.hdr.unit_id = PMU_UNIT_PG;
1015 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_stat);
1016 cmd.cmd.pg.stat.cmd_type = PMU_PG_CMD_ID_PG_STAT;
1017 cmd.cmd.pg.stat.engine_id = pg_engine_id;
1018 cmd.cmd.pg.stat.sub_cmd_id = PMU_PG_STAT_CMD_ALLOC_DMEM;
1019 cmd.cmd.pg.stat.data = 0;
1020
1021 gk20a_dbg_pmu("cmd post PMU_PG_STAT_CMD_ALLOC_DMEM");
1022 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_LPQ,
1023 pmu_handle_pg_stat_msg, pmu, &seq, ~0);
1024
1025 /* disallow ELPG initially
1026 PMU ucode requires a disallow cmd before allow cmd */
1027 /* set for wait_event PMU_ELPG_STAT_OFF */
1028 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
1029 pmu->elpg_stat = PMU_ELPG_STAT_OFF;
1030 else if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS)
1031 pmu->mscg_transition_state = PMU_ELPG_STAT_OFF;
1032 memset(&cmd, 0, sizeof(struct pmu_cmd));
1033 cmd.hdr.unit_id = PMU_UNIT_PG;
1034 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd);
1035 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
1036 cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
1037 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_DISALLOW;
1038
1039 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_DISALLOW");
1040 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
1041 pmu_handle_pg_elpg_msg, pmu, &seq, ~0);
1042
1043 return 0;
1044}
1045
1046int nvgpu_pmu_init_powergating(struct gk20a *g)
1047{
1048 struct nvgpu_pmu *pmu = &g->pmu;
1049 u32 pg_engine_id;
1050 u32 pg_engine_id_list = 0;
1051
1052 gk20a_dbg_fn("");
1053
1054 if (g->ops.pmu.pmu_pg_supported_engines_list)
1055 pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
1056
1057 gk20a_gr_wait_initialized(g);
1058
1059 for (pg_engine_id = PMU_PG_ELPG_ENGINE_ID_GRAPHICS;
1060 pg_engine_id < PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE;
1061 pg_engine_id++) {
1062
1063 if (BIT(pg_engine_id) & pg_engine_id_list) {
1064 pmu_pg_init_send(g, pg_engine_id);
1065 if (pmu->pmu_state == PMU_STATE_INIT_RECEIVED)
1066 nvgpu_pmu_state_change(g,
1067 PMU_STATE_ELPG_BOOTING, false);
1068 }
1069 }
1070
1071 if (g->ops.pmu.pmu_pg_param_post_init)
1072 g->ops.pmu.pmu_pg_param_post_init(g);
1073
1074 return 0;
1075}
1076
1077static u8 get_perfmon_id(struct nvgpu_pmu *pmu) 805static u8 get_perfmon_id(struct nvgpu_pmu *pmu)
1078{ 806{
1079 struct gk20a *g = gk20a_from_pmu(pmu); 807 struct gk20a *g = gk20a_from_pmu(pmu);
@@ -1355,7 +1083,7 @@ int nvgpu_pmu_handle_therm_event(struct nvgpu_pmu *pmu,
1355 return 0; 1083 return 0;
1356} 1084}
1357 1085
1358static void pmu_dump_elpg_stats(struct nvgpu_pmu *pmu) 1086void pmu_dump_elpg_stats(struct nvgpu_pmu *pmu)
1359{ 1087{
1360 struct gk20a *g = gk20a_from_pmu(pmu); 1088 struct gk20a *g = gk20a_from_pmu(pmu);
1361 struct pmu_pg_stats stats; 1089 struct pmu_pg_stats stats;
@@ -1631,238 +1359,6 @@ void gk20a_pmu_isr(struct gk20a *g)
1631 nvgpu_mutex_release(&pmu->isr_mutex); 1359 nvgpu_mutex_release(&pmu->isr_mutex);
1632} 1360}
1633 1361
1634int gk20a_pmu_pg_global_enable(struct gk20a *g, u32 enable_pg)
1635{
1636 u32 status = 0;
1637
1638 if (enable_pg == true) {
1639 if (g->ops.pmu.pmu_pg_engines_feature_list &&
1640 g->ops.pmu.pmu_pg_engines_feature_list(g,
1641 PMU_PG_ELPG_ENGINE_ID_GRAPHICS) !=
1642 PMU_PG_FEATURE_GR_POWER_GATING_ENABLED) {
1643 if (g->ops.pmu.pmu_lpwr_enable_pg)
1644 status = g->ops.pmu.pmu_lpwr_enable_pg(g,
1645 true);
1646 } else if (g->support_pmu && g->can_elpg)
1647 status = gk20a_pmu_enable_elpg(g);
1648 } else if (enable_pg == false) {
1649 if (g->ops.pmu.pmu_pg_engines_feature_list &&
1650 g->ops.pmu.pmu_pg_engines_feature_list(g,
1651 PMU_PG_ELPG_ENGINE_ID_GRAPHICS) !=
1652 PMU_PG_FEATURE_GR_POWER_GATING_ENABLED) {
1653 if (g->ops.pmu.pmu_lpwr_disable_pg)
1654 status = g->ops.pmu.pmu_lpwr_disable_pg(g,
1655 true);
1656 } else if (g->support_pmu && g->can_elpg)
1657 status = gk20a_pmu_disable_elpg(g);
1658 }
1659
1660 return status;
1661}
1662
1663static int gk20a_pmu_enable_elpg_locked(struct gk20a *g, u32 pg_engine_id)
1664{
1665 struct nvgpu_pmu *pmu = &g->pmu;
1666 struct pmu_cmd cmd;
1667 u32 seq, status;
1668
1669 gk20a_dbg_fn("");
1670
1671 memset(&cmd, 0, sizeof(struct pmu_cmd));
1672 cmd.hdr.unit_id = PMU_UNIT_PG;
1673 cmd.hdr.size = PMU_CMD_HDR_SIZE +
1674 sizeof(struct pmu_pg_cmd_elpg_cmd);
1675 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
1676 cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
1677 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_ALLOW;
1678
1679 /* no need to wait ack for ELPG enable but set
1680 * pending to sync with follow up ELPG disable
1681 */
1682 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
1683 pmu->elpg_stat = PMU_ELPG_STAT_ON_PENDING;
1684
1685 else if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS)
1686 pmu->mscg_transition_state = PMU_ELPG_STAT_ON_PENDING;
1687
1688 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_ALLOW");
1689 status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL,
1690 PMU_COMMAND_QUEUE_HPQ, pmu_handle_pg_elpg_msg,
1691 pmu, &seq, ~0);
1692 WARN_ON(status != 0);
1693
1694 gk20a_dbg_fn("done");
1695 return 0;
1696}
1697
1698int gk20a_pmu_enable_elpg(struct gk20a *g)
1699{
1700 struct nvgpu_pmu *pmu = &g->pmu;
1701 struct gr_gk20a *gr = &g->gr;
1702 u32 pg_engine_id;
1703 u32 pg_engine_id_list = 0;
1704
1705 int ret = 0;
1706
1707 gk20a_dbg_fn("");
1708
1709 if (!g->support_pmu)
1710 return ret;
1711
1712 nvgpu_mutex_acquire(&pmu->elpg_mutex);
1713
1714 pmu->elpg_refcnt++;
1715 if (pmu->elpg_refcnt <= 0)
1716 goto exit_unlock;
1717
1718 /* something is not right if we end up in following code path */
1719 if (unlikely(pmu->elpg_refcnt > 1)) {
1720 nvgpu_warn(g,
1721 "%s(): possible elpg refcnt mismatch. elpg refcnt=%d",
1722 __func__, pmu->elpg_refcnt);
1723 WARN_ON(1);
1724 }
1725
1726 /* do NOT enable elpg until golden ctx is created,
1727 which is related with the ctx that ELPG save and restore. */
1728 if (unlikely(!gr->ctx_vars.golden_image_initialized))
1729 goto exit_unlock;
1730
1731 /* return if ELPG is already on or on_pending or off_on_pending */
1732 if (pmu->elpg_stat != PMU_ELPG_STAT_OFF)
1733 goto exit_unlock;
1734
1735 if (g->ops.pmu.pmu_pg_supported_engines_list)
1736 pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
1737
1738 for (pg_engine_id = PMU_PG_ELPG_ENGINE_ID_GRAPHICS;
1739 pg_engine_id < PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE;
1740 pg_engine_id++) {
1741
1742 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS &&
1743 ACCESS_ONCE(pmu->mscg_stat) == PMU_MSCG_DISABLED)
1744 continue;
1745
1746 if (BIT(pg_engine_id) & pg_engine_id_list)
1747 ret = gk20a_pmu_enable_elpg_locked(g, pg_engine_id);
1748 }
1749
1750exit_unlock:
1751 nvgpu_mutex_release(&pmu->elpg_mutex);
1752 gk20a_dbg_fn("done");
1753 return ret;
1754}
1755
1756int gk20a_pmu_disable_elpg(struct gk20a *g)
1757{
1758 struct nvgpu_pmu *pmu = &g->pmu;
1759 struct pmu_cmd cmd;
1760 u32 seq;
1761 int ret = 0;
1762 u32 pg_engine_id;
1763 u32 pg_engine_id_list = 0;
1764 u32 *ptr = NULL;
1765
1766 gk20a_dbg_fn("");
1767
1768 if (g->ops.pmu.pmu_pg_supported_engines_list)
1769 pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
1770
1771 if (!g->support_pmu)
1772 return ret;
1773
1774 nvgpu_mutex_acquire(&pmu->elpg_mutex);
1775
1776 pmu->elpg_refcnt--;
1777 if (pmu->elpg_refcnt > 0) {
1778 nvgpu_warn(g,
1779 "%s(): possible elpg refcnt mismatch. elpg refcnt=%d",
1780 __func__, pmu->elpg_refcnt);
1781 WARN_ON(1);
1782 ret = 0;
1783 goto exit_unlock;
1784 }
1785
1786 /* cancel off_on_pending and return */
1787 if (pmu->elpg_stat == PMU_ELPG_STAT_OFF_ON_PENDING) {
1788 pmu->elpg_stat = PMU_ELPG_STAT_OFF;
1789 ret = 0;
1790 goto exit_reschedule;
1791 }
1792 /* wait if on_pending */
1793 else if (pmu->elpg_stat == PMU_ELPG_STAT_ON_PENDING) {
1794
1795 pmu_wait_message_cond(pmu, gk20a_get_gr_idle_timeout(g),
1796 &pmu->elpg_stat, PMU_ELPG_STAT_ON);
1797
1798 if (pmu->elpg_stat != PMU_ELPG_STAT_ON) {
1799 nvgpu_err(g, "ELPG_ALLOW_ACK failed, elpg_stat=%d",
1800 pmu->elpg_stat);
1801 pmu_dump_elpg_stats(pmu);
1802 pmu_dump_falcon_stats(pmu);
1803 ret = -EBUSY;
1804 goto exit_unlock;
1805 }
1806 }
1807 /* return if ELPG is already off */
1808 else if (pmu->elpg_stat != PMU_ELPG_STAT_ON) {
1809 ret = 0;
1810 goto exit_reschedule;
1811 }
1812
1813 for (pg_engine_id = PMU_PG_ELPG_ENGINE_ID_GRAPHICS;
1814 pg_engine_id < PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE;
1815 pg_engine_id++) {
1816
1817 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS &&
1818 ACCESS_ONCE(pmu->mscg_stat) == PMU_MSCG_DISABLED)
1819 continue;
1820
1821 if (BIT(pg_engine_id) & pg_engine_id_list) {
1822 memset(&cmd, 0, sizeof(struct pmu_cmd));
1823 cmd.hdr.unit_id = PMU_UNIT_PG;
1824 cmd.hdr.size = PMU_CMD_HDR_SIZE +
1825 sizeof(struct pmu_pg_cmd_elpg_cmd);
1826 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
1827 cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
1828 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_DISALLOW;
1829
1830 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
1831 pmu->elpg_stat = PMU_ELPG_STAT_OFF_PENDING;
1832 else if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS)
1833 pmu->mscg_transition_state =
1834 PMU_ELPG_STAT_OFF_PENDING;
1835
1836 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
1837 ptr = &pmu->elpg_stat;
1838 else if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS)
1839 ptr = &pmu->mscg_transition_state;
1840
1841 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_DISALLOW");
1842 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL,
1843 PMU_COMMAND_QUEUE_HPQ, pmu_handle_pg_elpg_msg,
1844 pmu, &seq, ~0);
1845
1846 pmu_wait_message_cond(pmu,
1847 gk20a_get_gr_idle_timeout(g),
1848 ptr, PMU_ELPG_STAT_OFF);
1849 if (*ptr != PMU_ELPG_STAT_OFF) {
1850 nvgpu_err(g, "ELPG_DISALLOW_ACK failed");
1851 pmu_dump_elpg_stats(pmu);
1852 pmu_dump_falcon_stats(pmu);
1853 ret = -EBUSY;
1854 goto exit_unlock;
1855 }
1856 }
1857 }
1858
1859exit_reschedule:
1860exit_unlock:
1861 nvgpu_mutex_release(&pmu->elpg_mutex);
1862 gk20a_dbg_fn("done");
1863 return ret;
1864}
1865
1866int gk20a_pmu_perfmon_enable(struct gk20a *g, bool enable) 1362int gk20a_pmu_perfmon_enable(struct gk20a *g, bool enable)
1867{ 1363{
1868 struct nvgpu_pmu *pmu = &g->pmu; 1364 struct nvgpu_pmu *pmu = &g->pmu;
@@ -1947,173 +1443,3 @@ void gk20a_pmu_elpg_statistics(struct gk20a *g, u32 pg_engine_id,
1947 pg_stat_data->avg_entry_latency_us = stats.pg_avg_entry_time_us; 1443 pg_stat_data->avg_entry_latency_us = stats.pg_avg_entry_time_us;
1948 pg_stat_data->avg_exit_latency_us = stats.pg_avg_exit_time_us; 1444 pg_stat_data->avg_exit_latency_us = stats.pg_avg_exit_time_us;
1949} 1445}
1950
1951int nvgpu_pmu_get_pg_stats(struct gk20a *g, u32 pg_engine_id,
1952 struct pmu_pg_stats_data *pg_stat_data)
1953{
1954 struct nvgpu_pmu *pmu = &g->pmu;
1955 u32 pg_engine_id_list = 0;
1956
1957 if (!pmu->initialized) {
1958 pg_stat_data->ingating_time = 0;
1959 pg_stat_data->ungating_time = 0;
1960 pg_stat_data->gating_cnt = 0;
1961 return 0;
1962 }
1963
1964 if (g->ops.pmu.pmu_pg_supported_engines_list)
1965 pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
1966
1967 if (BIT(pg_engine_id) & pg_engine_id_list)
1968 g->ops.pmu.pmu_elpg_statistics(g, pg_engine_id,
1969 pg_stat_data);
1970
1971 return 0;
1972}
1973
1974/* Send an Adaptive Power (AP) related command to PMU */
1975int gk20a_pmu_ap_send_command(struct gk20a *g,
1976 union pmu_ap_cmd *p_ap_cmd, bool b_block)
1977{
1978 struct nvgpu_pmu *pmu = &g->pmu;
1979 /* FIXME: where is the PG structure defined?? */
1980 u32 status = 0;
1981 struct pmu_cmd cmd;
1982 u32 seq;
1983 pmu_callback p_callback = NULL;
1984
1985 memset(&cmd, 0, sizeof(struct pmu_cmd));
1986
1987 /* Copy common members */
1988 cmd.hdr.unit_id = PMU_UNIT_PG;
1989 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(union pmu_ap_cmd);
1990
1991 cmd.cmd.pg.ap_cmd.cmn.cmd_type = PMU_PG_CMD_ID_AP;
1992 cmd.cmd.pg.ap_cmd.cmn.cmd_id = p_ap_cmd->cmn.cmd_id;
1993
1994 /* Copy other members of command */
1995 switch (p_ap_cmd->cmn.cmd_id) {
1996 case PMU_AP_CMD_ID_INIT:
1997 gk20a_dbg_pmu("cmd post PMU_AP_CMD_ID_INIT");
1998 cmd.cmd.pg.ap_cmd.init.pg_sampling_period_us =
1999 p_ap_cmd->init.pg_sampling_period_us;
2000 break;
2001
2002 case PMU_AP_CMD_ID_INIT_AND_ENABLE_CTRL:
2003 gk20a_dbg_pmu("cmd post PMU_AP_CMD_ID_INIT_AND_ENABLE_CTRL");
2004 cmd.cmd.pg.ap_cmd.init_and_enable_ctrl.ctrl_id =
2005 p_ap_cmd->init_and_enable_ctrl.ctrl_id;
2006 memcpy(
2007 (void *)&(cmd.cmd.pg.ap_cmd.init_and_enable_ctrl.params),
2008 (void *)&(p_ap_cmd->init_and_enable_ctrl.params),
2009 sizeof(struct pmu_ap_ctrl_init_params));
2010
2011 p_callback = ap_callback_init_and_enable_ctrl;
2012 break;
2013
2014 case PMU_AP_CMD_ID_ENABLE_CTRL:
2015 gk20a_dbg_pmu("cmd post PMU_AP_CMD_ID_ENABLE_CTRL");
2016 cmd.cmd.pg.ap_cmd.enable_ctrl.ctrl_id =
2017 p_ap_cmd->enable_ctrl.ctrl_id;
2018 break;
2019
2020 case PMU_AP_CMD_ID_DISABLE_CTRL:
2021 gk20a_dbg_pmu("cmd post PMU_AP_CMD_ID_DISABLE_CTRL");
2022 cmd.cmd.pg.ap_cmd.disable_ctrl.ctrl_id =
2023 p_ap_cmd->disable_ctrl.ctrl_id;
2024 break;
2025
2026 case PMU_AP_CMD_ID_KICK_CTRL:
2027 gk20a_dbg_pmu("cmd post PMU_AP_CMD_ID_KICK_CTRL");
2028 cmd.cmd.pg.ap_cmd.kick_ctrl.ctrl_id =
2029 p_ap_cmd->kick_ctrl.ctrl_id;
2030 cmd.cmd.pg.ap_cmd.kick_ctrl.skip_count =
2031 p_ap_cmd->kick_ctrl.skip_count;
2032 break;
2033
2034 default:
2035 gk20a_dbg_pmu("%s: Invalid Adaptive Power command %d\n",
2036 __func__, p_ap_cmd->cmn.cmd_id);
2037 return 0x2f;
2038 }
2039
2040 status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
2041 p_callback, pmu, &seq, ~0);
2042
2043 if (status) {
2044 gk20a_dbg_pmu(
2045 "%s: Unable to submit Adaptive Power Command %d\n",
2046 __func__, p_ap_cmd->cmn.cmd_id);
2047 goto err_return;
2048 }
2049
2050 /* TODO: Implement blocking calls (b_block) */
2051
2052err_return:
2053 return status;
2054}
2055
2056static void ap_callback_init_and_enable_ctrl(
2057 struct gk20a *g, struct pmu_msg *msg,
2058 void *param, u32 seq_desc, u32 status)
2059{
2060 /* Define p_ap (i.e pointer to pmu_ap structure) */
2061 WARN_ON(!msg);
2062
2063 if (!status) {
2064 switch (msg->msg.pg.ap_msg.cmn.msg_id) {
2065 case PMU_AP_MSG_ID_INIT_ACK:
2066 gk20a_dbg_pmu("reply PMU_AP_CMD_ID_INIT");
2067 break;
2068
2069 default:
2070 gk20a_dbg_pmu(
2071 "%s: Invalid Adaptive Power Message: %x\n",
2072 __func__, msg->msg.pg.ap_msg.cmn.msg_id);
2073 break;
2074 }
2075 }
2076}
2077
2078int gk20a_aelpg_init(struct gk20a *g)
2079{
2080 int status = 0;
2081
2082 /* Remove reliance on app_ctrl field. */
2083 union pmu_ap_cmd ap_cmd;
2084
2085 /* TODO: Check for elpg being ready? */
2086 ap_cmd.init.cmd_id = PMU_AP_CMD_ID_INIT;
2087 ap_cmd.init.pg_sampling_period_us = g->pmu.aelpg_param[0];
2088
2089 status = gk20a_pmu_ap_send_command(g, &ap_cmd, false);
2090 return status;
2091}
2092
2093int gk20a_aelpg_init_and_enable(struct gk20a *g, u8 ctrl_id)
2094{
2095 int status = 0;
2096 union pmu_ap_cmd ap_cmd;
2097
2098 /* TODO: Probably check if ELPG is ready? */
2099 ap_cmd.init_and_enable_ctrl.cmd_id = PMU_AP_CMD_ID_INIT_AND_ENABLE_CTRL;
2100 ap_cmd.init_and_enable_ctrl.ctrl_id = ctrl_id;
2101 ap_cmd.init_and_enable_ctrl.params.min_idle_filter_us =
2102 g->pmu.aelpg_param[1];
2103 ap_cmd.init_and_enable_ctrl.params.min_target_saving_us =
2104 g->pmu.aelpg_param[2];
2105 ap_cmd.init_and_enable_ctrl.params.power_break_even_us =
2106 g->pmu.aelpg_param[3];
2107 ap_cmd.init_and_enable_ctrl.params.cycles_per_sample_max =
2108 g->pmu.aelpg_param[4];
2109
2110 switch (ctrl_id) {
2111 case PMU_AP_CTRL_ID_GRAPHICS:
2112 break;
2113 default:
2114 break;
2115 }
2116
2117 status = gk20a_pmu_ap_send_command(g, &ap_cmd, true);
2118 return status;
2119}