summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_arb.c
diff options
context:
space:
mode:
authorDavid Nieto <dmartineznie@nvidia.com>2016-11-01 14:29:39 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:52 -0500
commit1f0a38797fbd86b5f5e7f6b43d1c81b2028a82b0 (patch)
tree605fa602651b8d42218edae322c0d52529d23450 /drivers/gpu/nvgpu/clk/clk_arb.c
parent136a9919e648fd15cc0bb4a2e3de381b29746d3a (diff)
gpu: nvgpu: prevent hang on failing arbiter init
The current code can lead to application hang when opening device on first time if the arbiter fails to set the clocks Also it solves a buffer overrun condition in case the requested frequency is above the maximum range of the VF curve bug 1835042 Change-Id: I385401ea27d5cc4bfa41b7ca2eb3a1db53138418 Signed-off-by: David Nieto <dmartineznie@nvidia.com> Reviewed-on: http://git-master/r/1245911 Reviewed-by: Thomas Fleury <tfleury@nvidia.com> Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/1268061 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk_arb.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_arb.c46
1 files changed, 29 insertions, 17 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.c b/drivers/gpu/nvgpu/clk/clk_arb.c
index 1b974d17..f3d6cfab 100644
--- a/drivers/gpu/nvgpu/clk/clk_arb.c
+++ b/drivers/gpu/nvgpu/clk/clk_arb.c
@@ -83,6 +83,7 @@ struct nvgpu_clk_arb {
83 struct llist_head requests; 83 struct llist_head requests;
84 84
85 struct gk20a *g; 85 struct gk20a *g;
86 int status;
86 87
87 struct nvgpu_clk_arb_target actual_pool[2]; 88 struct nvgpu_clk_arb_target actual_pool[2];
88 struct nvgpu_clk_arb_target *actual; 89 struct nvgpu_clk_arb_target *actual;
@@ -269,7 +270,8 @@ int nvgpu_clk_arb_init_arbiter(struct gk20a *g)
269 atomic_read(&arb->req_nr)); 270 atomic_read(&arb->req_nr));
270 } while (!atomic_read(&arb->req_nr)); 271 } while (!atomic_read(&arb->req_nr));
271 272
272 return 0; 273
274 return arb->status;
273 275
274init_fail: 276init_fail:
275 277
@@ -533,6 +535,7 @@ static int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb)
533 clk_cur = table->mclk_points[j].mhz; 535 clk_cur = table->mclk_points[j].mhz;
534 j++; 536 j++;
535 num_points++; 537 num_points++;
538
536 } 539 }
537 } 540 }
538 table->mclk_num_points = num_points; 541 table->mclk_num_points = num_points;
@@ -605,7 +608,7 @@ static void nvgpu_clk_arb_run_vf_table_cb(struct work_struct *work)
605 err = clk_vf_point_cache(g); 608 err = clk_vf_point_cache(g);
606 if (err) { 609 if (err) {
607 gk20a_err(dev_from_gk20a(g), 610 gk20a_err(dev_from_gk20a(g),
608 "failed to get GPC2CLK SRAM voltage"); 611 "failed to cache VF table");
609 return; 612 return;
610 } 613 }
611 nvgpu_clk_arb_update_vf_table(arb); 614 nvgpu_clk_arb_update_vf_table(arb);
@@ -625,7 +628,7 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work)
625 u32 voltuv, voltuv_sram; 628 u32 voltuv, voltuv_sram;
626 bool mclk_set, gpc2clk_set; 629 bool mclk_set, gpc2clk_set;
627 630
628 int status; 631 int status = 0;
629 632
630 /* Temporary variables for checking target frequency */ 633 /* Temporary variables for checking target frequency */
631 u16 gpc2clk_target, mclk_target; 634 u16 gpc2clk_target, mclk_target;
@@ -742,15 +745,21 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work)
742 actual->gpc2clk = gpc2clk_target; 745 actual->gpc2clk = gpc2clk_target;
743 actual->mclk = mclk_target; 746 actual->mclk = mclk_target;
744 arb->voltuv_actual = voltuv; 747 arb->voltuv_actual = voltuv;
748 arb->status = status;
745 749
746 /* Make changes visible to other threads */ 750 /* Make changes visible to other threads */
747 smp_wmb(); 751 smp_wmb();
748 xchg(&arb->actual, actual); 752 xchg(&arb->actual, actual);
749 753
754 /* status must be visible before atomic inc */
755 smp_wmb();
750 atomic_inc(&arb->req_nr); 756 atomic_inc(&arb->req_nr);
751 757
752 wake_up_interruptible(&arb->request_wq); 758 wake_up_interruptible(&arb->request_wq);
753 759
760 if (status < 0)
761 gk20a_err(dev_from_gk20a(g),
762 "Error in arbiter update");
754 763
755#ifdef CONFIG_DEBUG_FS 764#ifdef CONFIG_DEBUG_FS
756 g->ops.read_ptimer(g, &t1); 765 g->ops.read_ptimer(g, &t1);
@@ -1016,20 +1025,23 @@ static void nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb,
1016 struct nvgpu_clk_vf_table *table; 1025 struct nvgpu_clk_vf_table *table;
1017 u32 index; 1026 u32 index;
1018 1027
1019 gpc2clk_target = *gpc2clk;
1020 mclk_target = *mclk;
1021 gpc2clk_voltuv = 0;
1022 gpc2clk_voltuv_sram = 0;
1023 mclk_voltuv = 0;
1024 mclk_voltuv_sram = 0;
1025
1026 do { 1028 do {
1029 gpc2clk_target = *gpc2clk;
1030 mclk_target = *mclk;
1031 gpc2clk_voltuv = 0;
1032 gpc2clk_voltuv_sram = 0;
1033 mclk_voltuv = 0;
1034 mclk_voltuv_sram = 0;
1035
1027 table = ACCESS_ONCE(arb->current_vf_table); 1036 table = ACCESS_ONCE(arb->current_vf_table);
1028 /* pointer to table can be updated by callback */ 1037 /* pointer to table can be updated by callback */
1029 smp_rmb(); 1038 smp_rmb();
1030 1039
1031 if (!table) 1040 if (!table)
1032 continue; 1041 continue;
1042 if ((!table->gpc2clk_num_points) || (!table->mclk_num_points))
1043 goto find_exit;
1044
1033 /* round up the freq requests */ 1045 /* round up the freq requests */
1034 for (index = 0; index < table->gpc2clk_num_points; index++) { 1046 for (index = 0; index < table->gpc2clk_num_points; index++) {
1035 if (table->gpc2clk_points[index].mhz >= 1047 if (table->gpc2clk_points[index].mhz >=
@@ -1045,10 +1057,10 @@ static void nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb,
1045 } 1057 }
1046 1058
1047 if (index == table->gpc2clk_num_points) { 1059 if (index == table->gpc2clk_num_points) {
1048 gpc2clk_target = table->gpc2clk_points[index].mhz; 1060 gpc2clk_target = table->gpc2clk_points[index-1].mhz;
1049 gpc2clk_voltuv = table->gpc2clk_points[index].uvolt; 1061 gpc2clk_voltuv = table->gpc2clk_points[index-1].uvolt;
1050 gpc2clk_voltuv_sram = 1062 gpc2clk_voltuv_sram =
1051 table->gpc2clk_points[index].uvolt_sram; 1063 table->gpc2clk_points[index-1].uvolt_sram;
1052 } 1064 }
1053 1065
1054 for (index = 0; index < table->mclk_num_points; index++) { 1066 for (index = 0; index < table->mclk_num_points; index++) {
@@ -1061,14 +1073,15 @@ static void nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb,
1061 } 1073 }
1062 } 1074 }
1063 if (index == table->mclk_num_points) { 1075 if (index == table->mclk_num_points) {
1064 mclk_target = table->mclk_points[index].mhz; 1076 mclk_target = table->mclk_points[index-1].mhz;
1065 mclk_voltuv = table->mclk_points[index].uvolt; 1077 mclk_voltuv = table->mclk_points[index-1].uvolt;
1066 mclk_voltuv_sram = 1078 mclk_voltuv_sram =
1067 table->mclk_points[index].uvolt_sram; 1079 table->mclk_points[index-1].uvolt_sram;
1068 } 1080 }
1069 } while (!table || 1081 } while (!table ||
1070 (ACCESS_ONCE(arb->current_vf_table) != table)); 1082 (ACCESS_ONCE(arb->current_vf_table) != table));
1071 1083
1084find_exit:
1072 *voltuv = gpc2clk_voltuv > mclk_voltuv ? gpc2clk_voltuv : mclk_voltuv; 1085 *voltuv = gpc2clk_voltuv > mclk_voltuv ? gpc2clk_voltuv : mclk_voltuv;
1073 *voltuv_sram = gpc2clk_voltuv_sram > mclk_voltuv_sram ? 1086 *voltuv_sram = gpc2clk_voltuv_sram > mclk_voltuv_sram ?
1074 gpc2clk_voltuv_sram : mclk_voltuv_sram; 1087 gpc2clk_voltuv_sram : mclk_voltuv_sram;
@@ -1136,7 +1149,6 @@ static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target,
1136 status = clk_program_fll_clks(g, &fllclk); 1149 status = clk_program_fll_clks(g, &fllclk);
1137 if (status < 0) 1150 if (status < 0)
1138 return status; 1151 return status;
1139
1140 } 1152 }
1141 1153
1142 return 0; 1154 return 0;