diff options
Diffstat (limited to 'drivers/gpu/nvgpu/clk')
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_arb.c | 102 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_arb.h | 5 |
2 files changed, 67 insertions, 40 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.c b/drivers/gpu/nvgpu/clk/clk_arb.c index 3f35fac7..c440dc3b 100644 --- a/drivers/gpu/nvgpu/clk/clk_arb.c +++ b/drivers/gpu/nvgpu/clk/clk_arb.c | |||
@@ -44,14 +44,6 @@ static void nvgpu_clk_arb_free_session(struct kref *refcount); | |||
44 | static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target, | 44 | static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target, |
45 | u16 sys2clk_target, u16 xbar2clk_target, u16 mclk_target, u32 voltuv, | 45 | u16 sys2clk_target, u16 xbar2clk_target, u16 mclk_target, u32 voltuv, |
46 | u32 voltuv_sram); | 46 | u32 voltuv_sram); |
47 | static int nvgpu_clk_arb_change_vf_point_prefix(struct gk20a *g, | ||
48 | u16 gpc2clk_target, u16 sys2clk_target, u16 xbar2clk_target, | ||
49 | u16 mclk_target, u32 voltuv, u32 voltuv_sram, u32 nuvmin, | ||
50 | u32 nuvmin_sram); | ||
51 | static int nvgpu_clk_arb_change_vf_point_postfix(struct gk20a *g, | ||
52 | u16 gpc2clk_target, u16 sys2clk_target, u16 xbar2clk_target, | ||
53 | u16 mclk_target, u32 voltuv, u32 voltuv_sram, u32 nuvmin, | ||
54 | u32 nuvmin_sram); | ||
55 | static u8 nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb, | 47 | static u8 nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb, |
56 | u16 *gpc2clk, u16 *sys2clk, u16 *xbar2clk, u16 *mclk, | 48 | u16 *gpc2clk, u16 *sys2clk, u16 *xbar2clk, u16 *mclk, |
57 | u32 *voltuv, u32 *voltuv_sram, u32 *nuvmin, u32 *nuvmin_sram); | 49 | u32 *voltuv, u32 *voltuv_sram, u32 *nuvmin, u32 *nuvmin_sram); |
@@ -105,6 +97,7 @@ struct nvgpu_clk_arb { | |||
105 | spinlock_t sessions_lock; | 97 | spinlock_t sessions_lock; |
106 | spinlock_t users_lock; | 98 | spinlock_t users_lock; |
107 | 99 | ||
100 | struct mutex pstate_lock; | ||
108 | struct list_head users; | 101 | struct list_head users; |
109 | struct list_head sessions; | 102 | struct list_head sessions; |
110 | struct llist_head requests; | 103 | struct llist_head requests; |
@@ -235,6 +228,7 @@ int nvgpu_clk_arb_init_arbiter(struct gk20a *g) | |||
235 | g->clk_arb = arb; | 228 | g->clk_arb = arb; |
236 | arb->g = g; | 229 | arb->g = g; |
237 | 230 | ||
231 | mutex_init(&arb->pstate_lock); | ||
238 | spin_lock_init(&arb->sessions_lock); | 232 | spin_lock_init(&arb->sessions_lock); |
239 | spin_lock_init(&arb->users_lock); | 233 | spin_lock_init(&arb->users_lock); |
240 | 234 | ||
@@ -943,12 +937,23 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work) | |||
943 | /* Program clocks */ | 937 | /* Program clocks */ |
944 | /* A change in both mclk of gpc2clk may require a change in voltage */ | 938 | /* A change in both mclk of gpc2clk may require a change in voltage */ |
945 | 939 | ||
946 | status = nvgpu_clk_arb_change_vf_point_prefix(g, gpc2clk_target, | 940 | mutex_lock(&arb->pstate_lock); |
947 | sys2clk_target, xbar2clk_target, mclk_target, voltuv, | 941 | status = nvgpu_lpwr_disable_pg(g, false); |
948 | voltuv_sram, nuvmin, nuvmin_sram); | ||
949 | 942 | ||
943 | status = clk_pmu_freq_controller_load(g, false); | ||
944 | if (status < 0) { | ||
945 | arb->status = status; | ||
946 | mutex_unlock(&arb->pstate_lock); | ||
947 | |||
948 | /* make status visible */ | ||
949 | smp_mb(); | ||
950 | goto exit_arb; | ||
951 | } | ||
952 | status = volt_set_noiseaware_vmin(g, nuvmin, nuvmin_sram); | ||
950 | if (status < 0) { | 953 | if (status < 0) { |
951 | arb->status = status; | 954 | arb->status = status; |
955 | mutex_unlock(&arb->pstate_lock); | ||
956 | |||
952 | /* make status visible */ | 957 | /* make status visible */ |
953 | smp_mb(); | 958 | smp_mb(); |
954 | goto exit_arb; | 959 | goto exit_arb; |
@@ -957,20 +962,30 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work) | |||
957 | status = nvgpu_clk_arb_change_vf_point(g, gpc2clk_target, | 962 | status = nvgpu_clk_arb_change_vf_point(g, gpc2clk_target, |
958 | sys2clk_target, xbar2clk_target, mclk_target, voltuv, | 963 | sys2clk_target, xbar2clk_target, mclk_target, voltuv, |
959 | voltuv_sram); | 964 | voltuv_sram); |
960 | |||
961 | if (status < 0) { | 965 | if (status < 0) { |
962 | arb->status = status; | 966 | arb->status = status; |
967 | mutex_unlock(&arb->pstate_lock); | ||
968 | |||
963 | /* make status visible */ | 969 | /* make status visible */ |
964 | smp_mb(); | 970 | smp_mb(); |
965 | goto exit_arb; | 971 | goto exit_arb; |
966 | } | 972 | } |
967 | 973 | ||
968 | status = nvgpu_clk_arb_change_vf_point_postfix(g, gpc2clk_target, | 974 | status = clk_pmu_freq_controller_load(g, true); |
969 | sys2clk_target, xbar2clk_target, mclk_target, voltuv, | 975 | if (status < 0) { |
970 | voltuv_sram, nuvmin, nuvmin_sram); | 976 | arb->status = status; |
977 | mutex_unlock(&arb->pstate_lock); | ||
978 | |||
979 | /* make status visible */ | ||
980 | smp_mb(); | ||
981 | goto exit_arb; | ||
982 | } | ||
971 | 983 | ||
984 | status = nvgpu_lwpr_mclk_change(g, pstate); | ||
972 | if (status < 0) { | 985 | if (status < 0) { |
973 | arb->status = status; | 986 | arb->status = status; |
987 | mutex_unlock(&arb->pstate_lock); | ||
988 | |||
974 | /* make status visible */ | 989 | /* make status visible */ |
975 | smp_mb(); | 990 | smp_mb(); |
976 | goto exit_arb; | 991 | goto exit_arb; |
@@ -991,15 +1006,24 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work) | |||
991 | smp_wmb(); | 1006 | smp_wmb(); |
992 | xchg(&arb->actual, actual); | 1007 | xchg(&arb->actual, actual); |
993 | 1008 | ||
1009 | status = nvgpu_lpwr_enable_pg(g, false); | ||
1010 | if (status < 0) { | ||
1011 | arb->status = status; | ||
1012 | mutex_unlock(&arb->pstate_lock); | ||
1013 | |||
1014 | /* make status visible */ | ||
1015 | smp_mb(); | ||
1016 | goto exit_arb; | ||
1017 | } | ||
1018 | |||
994 | /* status must be visible before atomic inc */ | 1019 | /* status must be visible before atomic inc */ |
995 | smp_wmb(); | 1020 | smp_wmb(); |
996 | atomic_inc(&arb->req_nr); | 1021 | atomic_inc(&arb->req_nr); |
997 | 1022 | ||
998 | wake_up_interruptible(&arb->request_wq); | 1023 | /* Unlock pstate change for PG */ |
1024 | mutex_unlock(&arb->pstate_lock); | ||
999 | 1025 | ||
1000 | if (status < 0) | 1026 | wake_up_interruptible(&arb->request_wq); |
1001 | gk20a_err(dev_from_gk20a(g), | ||
1002 | "Error in arbiter update"); | ||
1003 | 1027 | ||
1004 | #ifdef CONFIG_DEBUG_FS | 1028 | #ifdef CONFIG_DEBUG_FS |
1005 | g->ops.read_ptimer(g, &t1); | 1029 | g->ops.read_ptimer(g, &t1); |
@@ -1036,6 +1060,9 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work) | |||
1036 | #endif | 1060 | #endif |
1037 | 1061 | ||
1038 | exit_arb: | 1062 | exit_arb: |
1063 | if (status < 0) | ||
1064 | gk20a_err(dev_from_gk20a(g), | ||
1065 | "Error in arbiter update"); | ||
1039 | 1066 | ||
1040 | /* notify completion for all requests */ | 1067 | /* notify completion for all requests */ |
1041 | head = llist_del_all(&arb->requests); | 1068 | head = llist_del_all(&arb->requests); |
@@ -1300,6 +1327,7 @@ recalculate_vf_point: | |||
1300 | } | 1327 | } |
1301 | if (index == table->mclk_num_points) { | 1328 | if (index == table->mclk_num_points) { |
1302 | mclk_vf = &table->mclk_points[index-1]; | 1329 | mclk_vf = &table->mclk_points[index-1]; |
1330 | index = table->mclk_num_points - 1; | ||
1303 | } | 1331 | } |
1304 | index_mclk = index; | 1332 | index_mclk = index; |
1305 | 1333 | ||
@@ -1378,28 +1406,11 @@ find_exit: | |||
1378 | return pstate; | 1406 | return pstate; |
1379 | } | 1407 | } |
1380 | 1408 | ||
1381 | static int nvgpu_clk_arb_change_vf_point_prefix(struct gk20a *g, | 1409 | /* This function is inherently unsafe to call while arbiter is running |
1382 | u16 gpc2clk_target, u16 sys2clk_target, u16 xbar2clk_target, | 1410 | * arbiter must be blocked before calling this function */ |
1383 | u16 mclk_target, u32 voltuv, u32 voltuv_sram, u32 nuvmin, | 1411 | int nvgpu_clk_arb_get_current_pstate(struct gk20a *g) |
1384 | u32 nuvmin_sram) | ||
1385 | { | ||
1386 | |||
1387 | int status; | ||
1388 | |||
1389 | status = clk_pmu_freq_controller_load(g, false); | ||
1390 | if (status < 0) | ||
1391 | return status; | ||
1392 | |||
1393 | status = volt_set_noiseaware_vmin(g, nuvmin, nuvmin_sram); | ||
1394 | return status; | ||
1395 | } | ||
1396 | |||
1397 | static int nvgpu_clk_arb_change_vf_point_postfix(struct gk20a *g, | ||
1398 | u16 gpc2clk_target, u16 sys2clk_target, u16 xbar2clk_target, | ||
1399 | u16 mclk_target, u32 voltuv, u32 voltuv_sram, u32 nuvmin, | ||
1400 | u32 nuvmin_sram) | ||
1401 | { | 1412 | { |
1402 | return clk_pmu_freq_controller_load(g, true); | 1413 | return ACCESS_ONCE(g->clk_arb->actual->pstate); |
1403 | } | 1414 | } |
1404 | 1415 | ||
1405 | static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target, | 1416 | static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target, |
@@ -1456,6 +1467,17 @@ static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target, | |||
1456 | return 0; | 1467 | return 0; |
1457 | } | 1468 | } |
1458 | 1469 | ||
1470 | void nvgpu_clk_arb_pstate_change_lock(struct gk20a *g, bool lock) | ||
1471 | { | ||
1472 | struct nvgpu_clk_arb *arb = g->clk_arb; | ||
1473 | |||
1474 | if (lock) | ||
1475 | mutex_lock(&arb->pstate_lock); | ||
1476 | else | ||
1477 | mutex_unlock(&arb->pstate_lock); | ||
1478 | |||
1479 | } | ||
1480 | |||
1459 | #ifdef CONFIG_DEBUG_FS | 1481 | #ifdef CONFIG_DEBUG_FS |
1460 | static int nvgpu_clk_arb_stats_show(struct seq_file *s, void *unused) | 1482 | static int nvgpu_clk_arb_stats_show(struct seq_file *s, void *unused) |
1461 | { | 1483 | { |
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.h b/drivers/gpu/nvgpu/clk/clk_arb.h index 8355dac5..700804b3 100644 --- a/drivers/gpu/nvgpu/clk/clk_arb.h +++ b/drivers/gpu/nvgpu/clk/clk_arb.h | |||
@@ -62,5 +62,10 @@ int nvgpu_clk_arb_install_request_fd(struct gk20a *g, | |||
62 | struct nvgpu_clk_session *session, int *event_fd); | 62 | struct nvgpu_clk_session *session, int *event_fd); |
63 | 63 | ||
64 | void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g); | 64 | void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g); |
65 | |||
66 | int nvgpu_clk_arb_get_current_pstate(struct gk20a *g); | ||
67 | |||
68 | void nvgpu_clk_arb_pstate_change_lock(struct gk20a *g, bool lock); | ||
69 | |||
65 | #endif /* _CLK_ARB_H_ */ | 70 | #endif /* _CLK_ARB_H_ */ |
66 | 71 | ||