summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDebarshi Dutta <ddutta@nvidia.com>2018-06-26 06:11:12 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-09-04 10:25:41 -0400
commit16ad9f537979c5f3717fc5781b1c2fad22a76f96 (patch)
tree2a150c50983180051fa5ecc942764e081961d787
parentf125d1b681c324d5d58abcc42fac1301e1faa921 (diff)
gpu: nvgpu: move gp106 specific clk_arbiter code into HAL
Currently, clock arbiter code is extensively using dgpu specific implementation. This patch restructures the clk_arbiter code and moves gp106 specific code into HAL. Following changes are made in this patch 1) clk_domain_get_f_points is now invoked via HAL for gp106 i.e. g->ops.clk.clk_domain_get_f_points. 2) moved nvgpu_clk_arb_change_vf_point and other related static functions to clk_arb_gp106.c. 3) Instead of only checking if get_arbiter_clk_domain is empty, a check for support_clk_freq_controller is also added. This is to enable the clk_arbiter based on support from both the OS and the chips. Bug 2061372 Change-Id: I65b0a4e02145a86fbbfb420ed591b1fa3c86f6dc Signed-off-by: Debarshi Dutta <ddutta@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1774279 Reviewed-by: svc-misra-checker <svc-misra-checker@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Deepak Nibade <dnibade@nvidia.com> Reviewed-by: Vijayakumar Subbu <vsubbu@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r--drivers/gpu/nvgpu/boardobj/boardobj.h1
-rw-r--r--drivers/gpu/nvgpu/boardobj/boardobjgrp.h3
-rw-r--r--drivers/gpu/nvgpu/clk/clk.c31
-rw-r--r--drivers/gpu/nvgpu/clk/clk.h8
-rw-r--r--drivers/gpu/nvgpu/clk/clk_arb.c668
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h7
-rw-r--r--drivers/gpu/nvgpu/gp106/clk_arb_gp106.c649
-rw-r--r--drivers/gpu/nvgpu/gp106/clk_arb_gp106.h8
-rw-r--r--drivers/gpu/nvgpu/gp106/clk_gp106.c33
-rw-r--r--drivers/gpu/nvgpu/gp106/clk_gp106.h7
-rw-r--r--drivers/gpu/nvgpu/gp106/hal_gp106.c5
-rw-r--r--drivers/gpu/nvgpu/include/nvgpu/clk_arb.h12
-rw-r--r--drivers/gpu/nvgpu/os/posix/clk_arb.c46
13 files changed, 790 insertions, 688 deletions
diff --git a/drivers/gpu/nvgpu/boardobj/boardobj.h b/drivers/gpu/nvgpu/boardobj/boardobj.h
index a433fda8..8fc8d1cc 100644
--- a/drivers/gpu/nvgpu/boardobj/boardobj.h
+++ b/drivers/gpu/nvgpu/boardobj/boardobj.h
@@ -28,6 +28,7 @@
28#include "ctrl/ctrlboardobj.h" 28#include "ctrl/ctrlboardobj.h"
29 29
30struct boardobj; 30struct boardobj;
31struct nvgpu_list_node;
31 32
32/* 33/*
33* check whether the specified BOARDOBJ object implements the queried 34* check whether the specified BOARDOBJ object implements the queried
diff --git a/drivers/gpu/nvgpu/boardobj/boardobjgrp.h b/drivers/gpu/nvgpu/boardobj/boardobjgrp.h
index 3c28963c..8fc7136f 100644
--- a/drivers/gpu/nvgpu/boardobj/boardobjgrp.h
+++ b/drivers/gpu/nvgpu/boardobj/boardobjgrp.h
@@ -25,6 +25,9 @@
25 25
26struct boardobjgrp; 26struct boardobjgrp;
27struct gk20a; 27struct gk20a;
28struct nvgpu_list_node;
29struct pmu_surface;
30
28 31
29/* ------------------------ Includes ----------------------------------------*/ 32/* ------------------------ Includes ----------------------------------------*/
30#include "ctrl/ctrlboardobj.h" 33#include "ctrl/ctrlboardobj.h"
diff --git a/drivers/gpu/nvgpu/clk/clk.c b/drivers/gpu/nvgpu/clk/clk.c
index 49087468..731124f7 100644
--- a/drivers/gpu/nvgpu/clk/clk.c
+++ b/drivers/gpu/nvgpu/clk/clk.c
@@ -869,34 +869,3 @@ u32 clk_domain_get_f_or_v(
869 } 869 }
870 return status; 870 return status;
871} 871}
872
873u32 clk_domain_get_f_points(
874 struct gk20a *g,
875 u32 clkapidomain,
876 u32 *pfpointscount,
877 u16 *pfreqpointsinmhz
878)
879{
880 u32 status = -EINVAL;
881 struct clk_domain *pdomain;
882 u8 i;
883 struct clk_pmupstate *pclk = &g->clk_pmu;
884
885 if (pfpointscount == NULL)
886 return -EINVAL;
887
888 if ((pfreqpointsinmhz == NULL) && (*pfpointscount != 0))
889 return -EINVAL;
890
891 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
892 struct clk_domain *, pdomain, i) {
893 if (pdomain->api_domain == clkapidomain) {
894 status = pdomain->clkdomainclkgetfpoints(g, pclk,
895 pdomain, pfpointscount,
896 pfreqpointsinmhz,
897 CLK_PROG_VFE_ENTRY_LOGIC);
898 return status;
899 }
900 }
901 return status;
902}
diff --git a/drivers/gpu/nvgpu/clk/clk.h b/drivers/gpu/nvgpu/clk/clk.h
index cd65f6f5..afff6963 100644
--- a/drivers/gpu/nvgpu/clk/clk.h
+++ b/drivers/gpu/nvgpu/clk/clk.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * general clock structures & definitions 2 * general clock structures & definitions
3 * 3 *
4 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. 4 * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
5 * 5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a 6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"), 7 * copy of this software and associated documentation files (the "Software"),
@@ -127,12 +127,6 @@ u32 clk_domain_get_f_or_v(
127 u32 *pvoltuv, 127 u32 *pvoltuv,
128 u8 railidx 128 u8 railidx
129); 129);
130u32 clk_domain_get_f_points(
131 struct gk20a *g,
132 u32 clkapidomain,
133 u32 *fpointscount,
134 u16 *freqpointsinmhz
135);
136int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk); 130int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
137int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk); 131int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
138int clk_pmu_freq_controller_load(struct gk20a *g, bool bload, u8 bit_idx); 132int clk_pmu_freq_controller_load(struct gk20a *g, bool bload, u8 bit_idx);
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.c b/drivers/gpu/nvgpu/clk/clk_arb.c
index 357a1416..983a82f9 100644
--- a/drivers/gpu/nvgpu/clk/clk_arb.c
+++ b/drivers/gpu/nvgpu/clk/clk_arb.c
@@ -78,7 +78,7 @@ static void nvgpu_clk_arb_queue_notification(struct gk20a *g,
78 78
79} 79}
80 80
81static void nvgpu_clk_arb_set_global_alarm(struct gk20a *g, u32 alarm) 81void nvgpu_clk_arb_set_global_alarm(struct gk20a *g, u32 alarm)
82{ 82{
83 struct nvgpu_clk_arb *arb = g->clk_arb; 83 struct nvgpu_clk_arb *arb = g->clk_arb;
84 84
@@ -103,7 +103,7 @@ static void nvgpu_clk_arb_set_global_alarm(struct gk20a *g, u32 alarm)
103} 103}
104 104
105 105
106static int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb) 106int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb)
107{ 107{
108 struct gk20a *g = arb->g; 108 struct gk20a *g = arb->g;
109 struct nvgpu_clk_vf_table *table; 109 struct nvgpu_clk_vf_table *table;
@@ -117,7 +117,6 @@ static int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb)
117 117
118 struct clk_set_info *p5_info, *p0_info; 118 struct clk_set_info *p5_info, *p0_info;
119 119
120
121 table = NV_ACCESS_ONCE(arb->current_vf_table); 120 table = NV_ACCESS_ONCE(arb->current_vf_table);
122 /* make flag visible when all data has resolved in the tables */ 121 /* make flag visible when all data has resolved in the tables */
123 nvgpu_smp_rmb(); 122 nvgpu_smp_rmb();
@@ -142,13 +141,13 @@ static int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb)
142 table->gpc2clk_num_points = MAX_F_POINTS; 141 table->gpc2clk_num_points = MAX_F_POINTS;
143 table->mclk_num_points = MAX_F_POINTS; 142 table->mclk_num_points = MAX_F_POINTS;
144 143
145 if (clk_domain_get_f_points(arb->g, CTRL_CLK_DOMAIN_GPC2CLK, 144 if (g->ops.clk.clk_domain_get_f_points(arb->g, CTRL_CLK_DOMAIN_GPC2CLK,
146 &table->gpc2clk_num_points, arb->gpc2clk_f_points)) { 145 &table->gpc2clk_num_points, arb->gpc2clk_f_points)) {
147 nvgpu_err(g, "failed to fetch GPC2CLK frequency points"); 146 nvgpu_err(g, "failed to fetch GPC2CLK frequency points");
148 goto exit_vf_table; 147 goto exit_vf_table;
149 } 148 }
150 149
151 if (clk_domain_get_f_points(arb->g, CTRL_CLK_DOMAIN_MCLK, 150 if (g->ops.clk.clk_domain_get_f_points(arb->g, CTRL_CLK_DOMAIN_MCLK,
152 &table->mclk_num_points, arb->mclk_f_points)) { 151 &table->mclk_num_points, arb->mclk_f_points)) {
153 nvgpu_err(g, "failed to fetch MCLK frequency points"); 152 nvgpu_err(g, "failed to fetch MCLK frequency points");
154 goto exit_vf_table; 153 goto exit_vf_table;
@@ -427,185 +426,7 @@ static void nvgpu_clk_arb_run_vf_table_cb(struct nvgpu_clk_arb *arb)
427 nvgpu_clk_arb_update_vf_table(arb); 426 nvgpu_clk_arb_update_vf_table(arb);
428} 427}
429 428
430static u8 nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb, 429u32 nvgpu_clk_arb_notify(struct nvgpu_clk_dev *dev,
431 u16 *gpc2clk, u16 *sys2clk, u16 *xbar2clk, u16 *mclk,
432 u32 *voltuv, u32 *voltuv_sram, u32 *nuvmin, u32 *nuvmin_sram)
433{
434 u16 gpc2clk_target, mclk_target;
435 u32 gpc2clk_voltuv, gpc2clk_voltuv_sram;
436 u32 mclk_voltuv, mclk_voltuv_sram;
437 u32 pstate = VF_POINT_INVALID_PSTATE;
438 struct nvgpu_clk_vf_table *table;
439 u32 index, index_mclk;
440 struct nvgpu_clk_vf_point *mclk_vf = NULL;
441
442 do {
443 gpc2clk_target = *gpc2clk;
444 mclk_target = *mclk;
445 gpc2clk_voltuv = 0;
446 gpc2clk_voltuv_sram = 0;
447 mclk_voltuv = 0;
448 mclk_voltuv_sram = 0;
449
450 table = NV_ACCESS_ONCE(arb->current_vf_table);
451 /* pointer to table can be updated by callback */
452 nvgpu_smp_rmb();
453
454 if (!table)
455 continue;
456 if ((!table->gpc2clk_num_points) || (!table->mclk_num_points)) {
457 nvgpu_err(arb->g, "found empty table");
458 goto find_exit;
459 }
460 /* First we check MCLK to find out which PSTATE we are
461 * are requesting, and from there try to find the minimum
462 * GPC2CLK on the same PSTATE that satisfies the request.
463 * If no GPC2CLK can be found, then we need to up the PSTATE
464 */
465
466recalculate_vf_point:
467 for (index = 0; index < table->mclk_num_points; index++) {
468 if (table->mclk_points[index].mem_mhz >= mclk_target) {
469 mclk_vf = &table->mclk_points[index];
470 break;
471 }
472 }
473 if (index == table->mclk_num_points) {
474 mclk_vf = &table->mclk_points[index-1];
475 index = table->mclk_num_points - 1;
476 }
477 index_mclk = index;
478
479 /* round up the freq requests */
480 for (index = 0; index < table->gpc2clk_num_points; index++) {
481 pstate = VF_POINT_COMMON_PSTATE(
482 &table->gpc2clk_points[index], mclk_vf);
483
484 if ((table->gpc2clk_points[index].gpc_mhz >=
485 gpc2clk_target) &&
486 (pstate != VF_POINT_INVALID_PSTATE)) {
487 gpc2clk_target =
488 table->gpc2clk_points[index].gpc_mhz;
489 *sys2clk =
490 table->gpc2clk_points[index].sys_mhz;
491 *xbar2clk =
492 table->gpc2clk_points[index].xbar_mhz;
493
494 gpc2clk_voltuv =
495 table->gpc2clk_points[index].uvolt;
496 gpc2clk_voltuv_sram =
497 table->gpc2clk_points[index].uvolt_sram;
498 break;
499 }
500 }
501
502 if (index == table->gpc2clk_num_points) {
503 pstate = VF_POINT_COMMON_PSTATE(
504 &table->gpc2clk_points[index-1], mclk_vf);
505 if (pstate != VF_POINT_INVALID_PSTATE) {
506 gpc2clk_target =
507 table->gpc2clk_points[index-1].gpc_mhz;
508 *sys2clk =
509 table->gpc2clk_points[index-1].sys_mhz;
510 *xbar2clk =
511 table->gpc2clk_points[index-1].xbar_mhz;
512
513 gpc2clk_voltuv =
514 table->gpc2clk_points[index-1].uvolt;
515 gpc2clk_voltuv_sram =
516 table->gpc2clk_points[index-1].
517 uvolt_sram;
518 } else if (index_mclk >= table->mclk_num_points - 1) {
519 /* There is no available combination of MCLK
520 * and GPC2CLK, we need to fail this
521 */
522 gpc2clk_target = 0;
523 mclk_target = 0;
524 pstate = VF_POINT_INVALID_PSTATE;
525 goto find_exit;
526 } else {
527 /* recalculate with higher PSTATE */
528 gpc2clk_target = *gpc2clk;
529 mclk_target = table->mclk_points[index_mclk+1].
530 mem_mhz;
531 goto recalculate_vf_point;
532 }
533 }
534
535 mclk_target = mclk_vf->mem_mhz;
536 mclk_voltuv = mclk_vf->uvolt;
537 mclk_voltuv_sram = mclk_vf->uvolt_sram;
538
539 } while (!table ||
540 (NV_ACCESS_ONCE(arb->current_vf_table) != table));
541
542find_exit:
543 *voltuv = gpc2clk_voltuv > mclk_voltuv ? gpc2clk_voltuv : mclk_voltuv;
544 *voltuv_sram = gpc2clk_voltuv_sram > mclk_voltuv_sram ?
545 gpc2clk_voltuv_sram : mclk_voltuv_sram;
546 /* noise unaware vmin */
547 *nuvmin = mclk_voltuv;
548 *nuvmin_sram = mclk_voltuv_sram;
549 *gpc2clk = gpc2clk_target;
550 *mclk = mclk_target;
551 return pstate;
552}
553
554static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target,
555 u16 sys2clk_target, u16 xbar2clk_target, u16 mclk_target, u32 voltuv,
556 u32 voltuv_sram)
557{
558 struct set_fll_clk fllclk;
559 struct nvgpu_clk_arb *arb = g->clk_arb;
560 int status;
561
562 fllclk.gpc2clkmhz = gpc2clk_target;
563 fllclk.sys2clkmhz = sys2clk_target;
564 fllclk.xbar2clkmhz = xbar2clk_target;
565
566 fllclk.voltuv = voltuv;
567
568 /* if voltage ascends we do:
569 * (1) FLL change
570 * (2) Voltage change
571 * (3) MCLK change
572 * If it goes down
573 * (1) MCLK change
574 * (2) Voltage change
575 * (3) FLL change
576 */
577
578 /* descending */
579 if (voltuv < arb->voltuv_actual) {
580 status = g->ops.clk.mclk_change(g, mclk_target);
581 if (status < 0)
582 return status;
583
584 status = volt_set_voltage(g, voltuv, voltuv_sram);
585 if (status < 0)
586 return status;
587
588 status = clk_set_fll_clks(g, &fllclk);
589 if (status < 0)
590 return status;
591 } else {
592 status = clk_set_fll_clks(g, &fllclk);
593 if (status < 0)
594 return status;
595
596 status = volt_set_voltage(g, voltuv, voltuv_sram);
597 if (status < 0)
598 return status;
599
600 status = g->ops.clk.mclk_change(g, mclk_target);
601 if (status < 0)
602 return status;
603 }
604
605 return 0;
606}
607
608static u32 nvgpu_clk_arb_notify(struct nvgpu_clk_dev *dev,
609 struct nvgpu_clk_arb_target *target, 430 struct nvgpu_clk_arb_target *target,
610 u32 alarm) { 431 u32 alarm) {
611 432
@@ -704,7 +525,7 @@ static u32 nvgpu_clk_arb_notify(struct nvgpu_clk_dev *dev,
704 return new_alarms_reported; 525 return new_alarms_reported;
705} 526}
706 527
707static void nvgpu_clk_arb_clear_global_alarm(struct gk20a *g, u32 alarm) 528void nvgpu_clk_arb_clear_global_alarm(struct gk20a *g, u32 alarm)
708{ 529{
709 struct nvgpu_clk_arb *arb = g->clk_arb; 530 struct nvgpu_clk_arb *arb = g->clk_arb;
710 531
@@ -726,318 +547,20 @@ static void nvgpu_clk_arb_clear_global_alarm(struct gk20a *g, u32 alarm)
726 current_mask, new_mask))); 547 current_mask, new_mask)));
727} 548}
728 549
729static void nvgpu_clk_arb_run_arbiter_cb(struct nvgpu_clk_arb *arb)
730{
731 struct nvgpu_clk_session *session;
732 struct nvgpu_clk_dev *dev;
733 struct nvgpu_clk_dev *tmp;
734 struct nvgpu_clk_arb_target *target, *actual;
735 struct gk20a *g = arb->g;
736
737 u32 pstate = VF_POINT_INVALID_PSTATE;
738 u32 voltuv, voltuv_sram;
739 bool mclk_set, gpc2clk_set;
740 u32 nuvmin, nuvmin_sram;
741
742 u32 alarms_notified = 0;
743 u32 current_alarm;
744 int status = 0;
745
746 /* Temporary variables for checking target frequency */
747 u16 gpc2clk_target, sys2clk_target, xbar2clk_target, mclk_target;
748 u16 gpc2clk_session_target, mclk_session_target;
749
750#ifdef CONFIG_DEBUG_FS
751 u64 t0, t1;
752 struct nvgpu_clk_arb_debug *debug;
753
754#endif
755
756 clk_arb_dbg(g, " ");
757
758 /* bail out if gpu is down */
759 if (nvgpu_atomic64_read(&arb->alarm_mask) & EVENT(ALARM_GPU_LOST))
760 goto exit_arb;
761
762#ifdef CONFIG_DEBUG_FS
763 g->ops.ptimer.read_ptimer(g, &t0);
764#endif
765
766 /* Only one arbiter should be running */
767 gpc2clk_target = 0;
768 mclk_target = 0;
769
770 nvgpu_spinlock_acquire(&arb->sessions_lock);
771 nvgpu_list_for_each_entry(session, &arb->sessions,
772 nvgpu_clk_session, link) {
773 if (!session->zombie) {
774 mclk_set = false;
775 gpc2clk_set = false;
776 target = (session->target == &session->target_pool[0] ?
777 &session->target_pool[1] :
778 &session->target_pool[0]);
779 nvgpu_spinlock_acquire(&session->session_lock);
780 if (!nvgpu_list_empty(&session->targets)) {
781 /* Copy over state */
782 target->mclk = session->target->mclk;
783 target->gpc2clk = session->target->gpc2clk;
784 /* Query the latest committed request */
785 nvgpu_list_for_each_entry_safe(dev, tmp, &session->targets,
786 nvgpu_clk_dev, node) {
787 if (!mclk_set && dev->mclk_target_mhz) {
788 target->mclk =
789 dev->mclk_target_mhz;
790 mclk_set = true;
791 }
792 if (!gpc2clk_set &&
793 dev->gpc2clk_target_mhz) {
794 target->gpc2clk =
795 dev->gpc2clk_target_mhz;
796 gpc2clk_set = true;
797 }
798 nvgpu_ref_get(&dev->refcount);
799 nvgpu_list_del(&dev->node);
800 nvgpu_spinlock_acquire(&arb->requests_lock);
801 nvgpu_list_add(&dev->node, &arb->requests);
802 nvgpu_spinlock_release(&arb->requests_lock);
803 }
804 session->target = target;
805 }
806 nvgpu_spinlock_release(&session->session_lock);
807
808 mclk_target = mclk_target > session->target->mclk ?
809 mclk_target : session->target->mclk;
810
811 gpc2clk_target =
812 gpc2clk_target > session->target->gpc2clk ?
813 gpc2clk_target : session->target->gpc2clk;
814 }
815 }
816 nvgpu_spinlock_release(&arb->sessions_lock);
817
818 gpc2clk_target = (gpc2clk_target > 0) ? gpc2clk_target :
819 arb->gpc2clk_default_mhz;
820
821 if (gpc2clk_target < arb->gpc2clk_min)
822 gpc2clk_target = arb->gpc2clk_min;
823
824 if (gpc2clk_target > arb->gpc2clk_max)
825 gpc2clk_target = arb->gpc2clk_max;
826
827 mclk_target = (mclk_target > 0) ? mclk_target :
828 arb->mclk_default_mhz;
829
830 if (mclk_target < arb->mclk_min)
831 mclk_target = arb->mclk_min;
832
833 if (mclk_target > arb->mclk_max)
834 mclk_target = arb->mclk_max;
835
836 sys2clk_target = 0;
837 xbar2clk_target = 0;
838
839 gpc2clk_session_target = gpc2clk_target;
840 mclk_session_target = mclk_target;
841
842 /* Query the table for the closest vf point to program */
843 pstate = nvgpu_clk_arb_find_vf_point(arb, &gpc2clk_target,
844 &sys2clk_target, &xbar2clk_target, &mclk_target, &voltuv,
845 &voltuv_sram, &nuvmin, &nuvmin_sram);
846
847 if (pstate == VF_POINT_INVALID_PSTATE) {
848 arb->status = -EINVAL;
849 /* make status visible */
850 nvgpu_smp_mb();
851 goto exit_arb;
852 }
853
854 if ((gpc2clk_target < gpc2clk_session_target) ||
855 (mclk_target < mclk_session_target))
856 nvgpu_clk_arb_set_global_alarm(g,
857 EVENT(ALARM_TARGET_VF_NOT_POSSIBLE));
858
859 if ((arb->actual->gpc2clk == gpc2clk_target) &&
860 (arb->actual->mclk == mclk_target) &&
861 (arb->voltuv_actual == voltuv)) {
862 goto exit_arb;
863 }
864
865 /* Program clocks */
866 /* A change in both mclk of gpc2clk may require a change in voltage */
867
868 nvgpu_mutex_acquire(&arb->pstate_lock);
869 status = nvgpu_lpwr_disable_pg(g, false);
870
871 status = clk_pmu_freq_controller_load(g, false,
872 CTRL_CLK_CLK_FREQ_CONTROLLER_ID_ALL);
873 if (status < 0) {
874 arb->status = status;
875 nvgpu_mutex_release(&arb->pstate_lock);
876
877 /* make status visible */
878 nvgpu_smp_mb();
879 goto exit_arb;
880 }
881 status = volt_set_noiseaware_vmin(g, nuvmin, nuvmin_sram);
882 if (status < 0) {
883 arb->status = status;
884 nvgpu_mutex_release(&arb->pstate_lock);
885
886 /* make status visible */
887 nvgpu_smp_mb();
888 goto exit_arb;
889 }
890
891 status = nvgpu_clk_arb_change_vf_point(g, gpc2clk_target,
892 sys2clk_target, xbar2clk_target, mclk_target, voltuv,
893 voltuv_sram);
894 if (status < 0) {
895 arb->status = status;
896 nvgpu_mutex_release(&arb->pstate_lock);
897
898 /* make status visible */
899 nvgpu_smp_mb();
900 goto exit_arb;
901 }
902
903 status = clk_pmu_freq_controller_load(g, true,
904 CTRL_CLK_CLK_FREQ_CONTROLLER_ID_ALL);
905 if (status < 0) {
906 arb->status = status;
907 nvgpu_mutex_release(&arb->pstate_lock);
908
909 /* make status visible */
910 nvgpu_smp_mb();
911 goto exit_arb;
912 }
913
914 status = nvgpu_lwpr_mclk_change(g, pstate);
915 if (status < 0) {
916 arb->status = status;
917 nvgpu_mutex_release(&arb->pstate_lock);
918
919 /* make status visible */
920 nvgpu_smp_mb();
921 goto exit_arb;
922 }
923
924 actual = NV_ACCESS_ONCE(arb->actual) == &arb->actual_pool[0] ?
925 &arb->actual_pool[1] : &arb->actual_pool[0];
926
927 /* do not reorder this pointer */
928 nvgpu_smp_rmb();
929 actual->gpc2clk = gpc2clk_target;
930 actual->mclk = mclk_target;
931 arb->voltuv_actual = voltuv;
932 actual->pstate = pstate;
933 arb->status = status;
934
935 /* Make changes visible to other threads */
936 nvgpu_smp_wmb();
937 arb->actual = actual;
938
939 status = nvgpu_lpwr_enable_pg(g, false);
940 if (status < 0) {
941 arb->status = status;
942 nvgpu_mutex_release(&arb->pstate_lock);
943
944 /* make status visible */
945 nvgpu_smp_mb();
946 goto exit_arb;
947 }
948
949 /* status must be visible before atomic inc */
950 nvgpu_smp_wmb();
951 nvgpu_atomic_inc(&arb->req_nr);
952
953 /* Unlock pstate change for PG */
954 nvgpu_mutex_release(&arb->pstate_lock);
955
956 /* VF Update complete */
957 nvgpu_clk_arb_set_global_alarm(g, EVENT(VF_UPDATE));
958
959 nvgpu_cond_signal_interruptible(&arb->request_wq);
960
961#ifdef CONFIG_DEBUG_FS
962 g->ops.ptimer.read_ptimer(g, &t1);
963
964 debug = arb->debug == &arb->debug_pool[0] ?
965 &arb->debug_pool[1] : &arb->debug_pool[0];
966
967 memcpy(debug, arb->debug, sizeof(arb->debug_pool[0]));
968 debug->switch_num++;
969
970 if (debug->switch_num == 1) {
971 debug->switch_max = debug->switch_min =
972 debug->switch_avg = (t1-t0)/1000;
973 debug->switch_std = 0;
974 } else {
975 s64 prev_avg;
976 s64 curr = (t1-t0)/1000;
977
978 debug->switch_max = curr > debug->switch_max ?
979 curr : debug->switch_max;
980 debug->switch_min = debug->switch_min ?
981 (curr < debug->switch_min ?
982 curr : debug->switch_min) : curr;
983 prev_avg = debug->switch_avg;
984 debug->switch_avg = (curr +
985 (debug->switch_avg * (debug->switch_num-1))) /
986 debug->switch_num;
987 debug->switch_std +=
988 (curr - debug->switch_avg) * (curr - prev_avg);
989 }
990 /* commit changes before exchanging debug pointer */
991 nvgpu_smp_wmb();
992 arb->debug = debug;
993#endif
994
995exit_arb:
996 if (status < 0) {
997 nvgpu_err(g, "Error in arbiter update");
998 nvgpu_clk_arb_set_global_alarm(g,
999 EVENT(ALARM_CLOCK_ARBITER_FAILED));
1000 }
1001
1002 current_alarm = (u32) nvgpu_atomic64_read(&arb->alarm_mask);
1003 /* notify completion for all requests */
1004 nvgpu_spinlock_acquire(&arb->requests_lock);
1005 nvgpu_list_for_each_entry_safe(dev, tmp, &arb->requests,
1006 nvgpu_clk_dev, node) {
1007 nvgpu_atomic_set(&dev->poll_mask, NVGPU_POLLIN | NVGPU_POLLRDNORM);
1008 nvgpu_clk_arb_event_post_event(dev);
1009 nvgpu_ref_put(&dev->refcount, nvgpu_clk_arb_free_fd);
1010 nvgpu_list_del(&dev->node);
1011 }
1012 nvgpu_spinlock_release(&arb->requests_lock);
1013
1014 nvgpu_atomic_set(&arb->notification_queue.head,
1015 nvgpu_atomic_read(&arb->notification_queue.tail));
1016 /* notify event for all users */
1017 nvgpu_spinlock_acquire(&arb->users_lock);
1018 nvgpu_list_for_each_entry(dev, &arb->users, nvgpu_clk_dev, link) {
1019 alarms_notified |=
1020 nvgpu_clk_arb_notify(dev, arb->actual, current_alarm);
1021 }
1022 nvgpu_spinlock_release(&arb->users_lock);
1023
1024 /* clear alarms */
1025 nvgpu_clk_arb_clear_global_alarm(g, alarms_notified &
1026 ~EVENT(ALARM_GPU_LOST));
1027}
1028
1029/* 550/*
1030 * Process one scheduled work item. 551 * Process one scheduled work item.
1031 */ 552 */
1032static void nvgpu_clk_arb_worker_process_item( 553static void nvgpu_clk_arb_worker_process_item(
1033 struct nvgpu_clk_arb_work_item *work_item) 554 struct nvgpu_clk_arb_work_item *work_item)
1034{ 555{
1035 clk_arb_dbg(work_item->arb->g, " "); 556 struct gk20a *g = work_item->arb->g;
557
558 clk_arb_dbg(g, " ");
1036 559
1037 if (work_item->item_type == CLK_ARB_WORK_UPDATE_VF_TABLE) 560 if (work_item->item_type == CLK_ARB_WORK_UPDATE_VF_TABLE)
1038 nvgpu_clk_arb_run_vf_table_cb(work_item->arb); 561 nvgpu_clk_arb_run_vf_table_cb(work_item->arb);
1039 else if (work_item->item_type == CLK_ARB_WORK_UPDATE_ARB) 562 else if (work_item->item_type == CLK_ARB_WORK_UPDATE_ARB)
1040 nvgpu_clk_arb_run_arbiter_cb(work_item->arb); 563 g->ops.clk_arb.clk_arb_run_arbiter_cb(work_item->arb);
1041} 564}
1042 565
1043/** 566/**
@@ -1204,7 +727,7 @@ void nvgpu_clk_arb_worker_enqueue(struct gk20a *g,
1204/** 727/**
1205 * Initialize the clk arb worker's metadata and start the background thread. 728 * Initialize the clk arb worker's metadata and start the background thread.
1206 */ 729 */
1207static int nvgpu_clk_arb_worker_init(struct gk20a *g) 730int nvgpu_clk_arb_worker_init(struct gk20a *g)
1208{ 731{
1209 int err; 732 int err;
1210 733
@@ -1227,149 +750,12 @@ error_check:
1227 750
1228int nvgpu_clk_arb_init_arbiter(struct gk20a *g) 751int nvgpu_clk_arb_init_arbiter(struct gk20a *g)
1229{ 752{
1230 struct nvgpu_clk_arb *arb; 753 if (!g->ops.clk.support_clk_freq_controller ||
1231 u16 default_mhz; 754 !g->ops.clk_arb.get_arbiter_clk_domains) {
1232 int err;
1233 int index;
1234 struct nvgpu_clk_vf_table *table;
1235
1236 clk_arb_dbg(g, " ");
1237
1238 if (!g->ops.clk_arb.get_arbiter_clk_domains)
1239 return 0; 755 return 0;
1240
1241 arb = nvgpu_kzalloc(g, sizeof(struct nvgpu_clk_arb));
1242 if (!arb)
1243 return -ENOMEM;
1244
1245 err = nvgpu_mutex_init(&arb->pstate_lock);
1246 if (err)
1247 goto mutex_fail;
1248 nvgpu_spinlock_init(&arb->sessions_lock);
1249 nvgpu_spinlock_init(&arb->users_lock);
1250 nvgpu_spinlock_init(&arb->requests_lock);
1251
1252 arb->mclk_f_points = nvgpu_kcalloc(g, MAX_F_POINTS, sizeof(u16));
1253 if (!arb->mclk_f_points) {
1254 err = -ENOMEM;
1255 goto init_fail;
1256 }
1257
1258 arb->gpc2clk_f_points = nvgpu_kcalloc(g, MAX_F_POINTS, sizeof(u16));
1259 if (!arb->gpc2clk_f_points) {
1260 err = -ENOMEM;
1261 goto init_fail;
1262 }
1263
1264 for (index = 0; index < 2; index++) {
1265 table = &arb->vf_table_pool[index];
1266 table->gpc2clk_num_points = MAX_F_POINTS;
1267 table->mclk_num_points = MAX_F_POINTS;
1268
1269 table->gpc2clk_points = nvgpu_kcalloc(g, MAX_F_POINTS,
1270 sizeof(struct nvgpu_clk_vf_point));
1271 if (!table->gpc2clk_points) {
1272 err = -ENOMEM;
1273 goto init_fail;
1274 }
1275
1276
1277 table->mclk_points = nvgpu_kcalloc(g, MAX_F_POINTS,
1278 sizeof(struct nvgpu_clk_vf_point));
1279 if (!table->mclk_points) {
1280 err = -ENOMEM;
1281 goto init_fail;
1282 }
1283 }
1284
1285 g->clk_arb = arb;
1286 arb->g = g;
1287
1288 err = g->ops.clk_arb.get_arbiter_clk_default(g,
1289 CTRL_CLK_DOMAIN_MCLK, &default_mhz);
1290 if (err < 0) {
1291 err = -EINVAL;
1292 goto init_fail;
1293 } 756 }
1294 757
1295 arb->mclk_default_mhz = default_mhz; 758 return g->ops.clk_arb.arbiter_clk_init(g);
1296
1297 err = g->ops.clk_arb.get_arbiter_clk_default(g,
1298 CTRL_CLK_DOMAIN_GPC2CLK, &default_mhz);
1299 if (err < 0) {
1300 err = -EINVAL;
1301 goto init_fail;
1302 }
1303
1304 arb->gpc2clk_default_mhz = default_mhz;
1305
1306 arb->actual = &arb->actual_pool[0];
1307
1308 nvgpu_atomic_set(&arb->req_nr, 0);
1309
1310 nvgpu_atomic64_set(&arb->alarm_mask, 0);
1311 err = nvgpu_clk_notification_queue_alloc(g, &arb->notification_queue,
1312 DEFAULT_EVENT_NUMBER);
1313 if (err < 0)
1314 goto init_fail;
1315
1316 nvgpu_init_list_node(&arb->users);
1317 nvgpu_init_list_node(&arb->sessions);
1318 nvgpu_init_list_node(&arb->requests);
1319
1320 nvgpu_cond_init(&arb->request_wq);
1321
1322 nvgpu_init_list_node(&arb->update_vf_table_work_item.worker_item);
1323 nvgpu_init_list_node(&arb->update_arb_work_item.worker_item);
1324 arb->update_vf_table_work_item.arb = arb;
1325 arb->update_arb_work_item.arb = arb;
1326 arb->update_vf_table_work_item.item_type = CLK_ARB_WORK_UPDATE_VF_TABLE;
1327 arb->update_arb_work_item.item_type = CLK_ARB_WORK_UPDATE_ARB;
1328
1329 err = nvgpu_clk_arb_worker_init(g);
1330 if (err < 0)
1331 goto init_fail;
1332
1333#ifdef CONFIG_DEBUG_FS
1334 arb->debug = &arb->debug_pool[0];
1335
1336 if (!arb->debugfs_set) {
1337 if (nvgpu_clk_arb_debugfs_init(g))
1338 arb->debugfs_set = true;
1339 }
1340#endif
1341 err = clk_vf_point_cache(g);
1342 if (err < 0)
1343 goto init_fail;
1344
1345 err = nvgpu_clk_arb_update_vf_table(arb);
1346 if (err < 0)
1347 goto init_fail;
1348 do {
1349 /* Check that first run is completed */
1350 nvgpu_smp_mb();
1351 NVGPU_COND_WAIT_INTERRUPTIBLE(&arb->request_wq,
1352 nvgpu_atomic_read(&arb->req_nr), 0);
1353 } while (!nvgpu_atomic_read(&arb->req_nr));
1354
1355
1356 return arb->status;
1357
1358init_fail:
1359 nvgpu_kfree(g, arb->gpc2clk_f_points);
1360 nvgpu_kfree(g, arb->mclk_f_points);
1361
1362 for (index = 0; index < 2; index++) {
1363 nvgpu_kfree(g, arb->vf_table_pool[index].gpc2clk_points);
1364 nvgpu_kfree(g, arb->vf_table_pool[index].mclk_points);
1365 }
1366
1367 nvgpu_mutex_destroy(&arb->pstate_lock);
1368
1369mutex_fail:
1370 nvgpu_kfree(g, arb);
1371
1372 return err;
1373} 759}
1374 760
1375void nvgpu_clk_arb_send_thermal_alarm(struct gk20a *g) 761void nvgpu_clk_arb_send_thermal_alarm(struct gk20a *g)
@@ -1396,22 +782,10 @@ static void nvgpu_clk_arb_worker_deinit(struct gk20a *g)
1396void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g) 782void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g)
1397{ 783{
1398 struct nvgpu_clk_arb *arb = g->clk_arb; 784 struct nvgpu_clk_arb *arb = g->clk_arb;
1399 int index;
1400 785
1401 if (arb) { 786 if (arb) {
1402 nvgpu_clk_arb_worker_deinit(g); 787 nvgpu_clk_arb_worker_deinit(g);
1403 788 g->ops.clk_arb.clk_arb_cleanup(g->clk_arb);
1404 nvgpu_kfree(g, arb->gpc2clk_f_points);
1405 nvgpu_kfree(g, arb->mclk_f_points);
1406
1407 for (index = 0; index < 2; index++) {
1408 nvgpu_kfree(g,
1409 arb->vf_table_pool[index].gpc2clk_points);
1410 nvgpu_kfree(g, arb->vf_table_pool[index].mclk_points);
1411 }
1412 nvgpu_mutex_destroy(&g->clk_arb->pstate_lock);
1413 nvgpu_kfree(g, g->clk_arb);
1414 g->clk_arb = NULL;
1415 } 789 }
1416} 790}
1417 791
@@ -1423,8 +797,10 @@ int nvgpu_clk_arb_init_session(struct gk20a *g,
1423 797
1424 clk_arb_dbg(g, " "); 798 clk_arb_dbg(g, " ");
1425 799
1426 if (!g->ops.clk_arb.get_arbiter_clk_domains) 800 if (!g->ops.clk.support_clk_freq_controller ||
801 !g->ops.clk_arb.get_arbiter_clk_domains) {
1427 return 0; 802 return 0;
803 }
1428 804
1429 session = nvgpu_kzalloc(g, sizeof(struct nvgpu_clk_session)); 805 session = nvgpu_kzalloc(g, sizeof(struct nvgpu_clk_session));
1430 if (!session) 806 if (!session)
@@ -1576,16 +952,16 @@ int nvgpu_clk_arb_get_arbiter_clk_f_points(struct gk20a *g,
1576 952
1577 switch (api_domain) { 953 switch (api_domain) {
1578 case NVGPU_CLK_DOMAIN_GPCCLK: 954 case NVGPU_CLK_DOMAIN_GPCCLK:
1579 err = clk_domain_get_f_points(g, CTRL_CLK_DOMAIN_GPC2CLK, 955 err = g->ops.clk.clk_domain_get_f_points(g,
1580 max_points, fpoints); 956 CTRL_CLK_DOMAIN_GPC2CLK, max_points, fpoints);
1581 if (err || !fpoints) 957 if (err || !fpoints)
1582 return err; 958 return err;
1583 for (i = 0; i < *max_points; i++) 959 for (i = 0; i < *max_points; i++)
1584 fpoints[i] /= 2; 960 fpoints[i] /= 2;
1585 return 0; 961 return 0;
1586 case NVGPU_CLK_DOMAIN_MCLK: 962 case NVGPU_CLK_DOMAIN_MCLK:
1587 return clk_domain_get_f_points(g, CTRL_CLK_DOMAIN_MCLK, 963 return g->ops.clk.clk_domain_get_f_points(g,
1588 max_points, fpoints); 964 CTRL_CLK_DOMAIN_MCLK, max_points, fpoints);
1589 default: 965 default:
1590 return -EINVAL; 966 return -EINVAL;
1591 } 967 }
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index ac1226fc..bdf3a168 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -41,6 +41,7 @@ struct nvgpu_nvhost_dev;
41struct nvgpu_cpu_time_correlation_sample; 41struct nvgpu_cpu_time_correlation_sample;
42struct nvgpu_mem_sgt; 42struct nvgpu_mem_sgt;
43struct nvgpu_warpstate; 43struct nvgpu_warpstate;
44struct nvgpu_clk_session;
44struct nvgpu_clk_arb; 45struct nvgpu_clk_arb;
45#ifdef CONFIG_GK20A_CTXSW_TRACE 46#ifdef CONFIG_GK20A_CTXSW_TRACE
46struct nvgpu_gpu_ctxsw_trace_filter; 47struct nvgpu_gpu_ctxsw_trace_filter;
@@ -1083,6 +1084,9 @@ struct gpu_ops {
1083 int (*init_clk_support)(struct gk20a *g); 1084 int (*init_clk_support)(struct gk20a *g);
1084 int (*suspend_clk_support)(struct gk20a *g); 1085 int (*suspend_clk_support)(struct gk20a *g);
1085 u32 (*get_crystal_clk_hz)(struct gk20a *g); 1086 u32 (*get_crystal_clk_hz)(struct gk20a *g);
1087 int (*clk_domain_get_f_points)(struct gk20a *g,
1088 u32 clkapidomain, u32 *pfpointscount,
1089 u16 *pfreqpointsinmhz);
1086 unsigned long (*measure_freq)(struct gk20a *g, u32 api_domain); 1090 unsigned long (*measure_freq)(struct gk20a *g, u32 api_domain);
1087 unsigned long (*get_rate)(struct gk20a *g, u32 api_domain); 1091 unsigned long (*get_rate)(struct gk20a *g, u32 api_domain);
1088 int (*set_rate)(struct gk20a *g, u32 api_domain, unsigned long rate); 1092 int (*set_rate)(struct gk20a *g, u32 api_domain, unsigned long rate);
@@ -1107,15 +1111,18 @@ struct gpu_ops {
1107 bool support_lpwr_pg; 1111 bool support_lpwr_pg;
1108 } clk; 1112 } clk;
1109 struct { 1113 struct {
1114 int (*arbiter_clk_init)(struct gk20a *g);
1110 u32 (*get_arbiter_clk_domains)(struct gk20a *g); 1115 u32 (*get_arbiter_clk_domains)(struct gk20a *g);
1111 int (*get_arbiter_clk_range)(struct gk20a *g, u32 api_domain, 1116 int (*get_arbiter_clk_range)(struct gk20a *g, u32 api_domain,
1112 u16 *min_mhz, u16 *max_mhz); 1117 u16 *min_mhz, u16 *max_mhz);
1113 int (*get_arbiter_clk_default)(struct gk20a *g, u32 api_domain, 1118 int (*get_arbiter_clk_default)(struct gk20a *g, u32 api_domain,
1114 u16 *default_mhz); 1119 u16 *default_mhz);
1120 void (*clk_arb_run_arbiter_cb)(struct nvgpu_clk_arb *arb);
1115 /* This function is inherently unsafe to call while 1121 /* This function is inherently unsafe to call while
1116 * arbiter is running arbiter must be blocked 1122 * arbiter is running arbiter must be blocked
1117 * before calling this function */ 1123 * before calling this function */
1118 int (*get_current_pstate)(struct gk20a *g); 1124 int (*get_current_pstate)(struct gk20a *g);
1125 void (*clk_arb_cleanup)(struct nvgpu_clk_arb *arb);
1119 } clk_arb; 1126 } clk_arb;
1120 struct { 1127 struct {
1121 int (*handle_pmu_perf_event)(struct gk20a *g, void *pmu_msg); 1128 int (*handle_pmu_perf_event)(struct gk20a *g, void *pmu_msg);
diff --git a/drivers/gpu/nvgpu/gp106/clk_arb_gp106.c b/drivers/gpu/nvgpu/gp106/clk_arb_gp106.c
index ca8015d6..860344d0 100644
--- a/drivers/gpu/nvgpu/gp106/clk_arb_gp106.c
+++ b/drivers/gpu/nvgpu/gp106/clk_arb_gp106.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. 2 * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
3 * 3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a 4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"), 5 * copy of this software and associated documentation files (the "Software"),
@@ -21,6 +21,7 @@
21 */ 21 */
22 22
23#include "gk20a/gk20a.h" 23#include "gk20a/gk20a.h"
24#include <nvgpu/clk_arb.h>
24 25
25#include "clk_arb_gp106.h" 26#include "clk_arb_gp106.h"
26 27
@@ -109,3 +110,649 @@ int gp106_get_arbiter_clk_default(struct gk20a *g, u32 api_domain,
109 110
110 return 0; 111 return 0;
111} 112}
113
114int gp106_init_clk_arbiter(struct gk20a *g)
115{
116 struct nvgpu_clk_arb *arb;
117 u16 default_mhz;
118 int err;
119 int index;
120 struct nvgpu_clk_vf_table *table;
121
122 clk_arb_dbg(g, " ");
123
124 arb = nvgpu_kzalloc(g, sizeof(struct nvgpu_clk_arb));
125 if (!arb)
126 return -ENOMEM;
127
128 err = nvgpu_mutex_init(&arb->pstate_lock);
129 if (err)
130 goto mutex_fail;
131 nvgpu_spinlock_init(&arb->sessions_lock);
132 nvgpu_spinlock_init(&arb->users_lock);
133 nvgpu_spinlock_init(&arb->requests_lock);
134
135 arb->mclk_f_points = nvgpu_kcalloc(g, MAX_F_POINTS, sizeof(u16));
136 if (!arb->mclk_f_points) {
137 err = -ENOMEM;
138 goto init_fail;
139 }
140
141 arb->gpc2clk_f_points = nvgpu_kcalloc(g, MAX_F_POINTS, sizeof(u16));
142 if (!arb->gpc2clk_f_points) {
143 err = -ENOMEM;
144 goto init_fail;
145 }
146
147 for (index = 0; index < 2; index++) {
148 table = &arb->vf_table_pool[index];
149 table->gpc2clk_num_points = MAX_F_POINTS;
150 table->mclk_num_points = MAX_F_POINTS;
151
152 table->gpc2clk_points = nvgpu_kcalloc(g, MAX_F_POINTS,
153 sizeof(struct nvgpu_clk_vf_point));
154 if (!table->gpc2clk_points) {
155 err = -ENOMEM;
156 goto init_fail;
157 }
158
159
160 table->mclk_points = nvgpu_kcalloc(g, MAX_F_POINTS,
161 sizeof(struct nvgpu_clk_vf_point));
162 if (!table->mclk_points) {
163 err = -ENOMEM;
164 goto init_fail;
165 }
166 }
167
168 g->clk_arb = arb;
169 arb->g = g;
170
171 err = g->ops.clk_arb.get_arbiter_clk_default(g,
172 CTRL_CLK_DOMAIN_MCLK, &default_mhz);
173 if (err < 0) {
174 err = -EINVAL;
175 goto init_fail;
176 }
177
178 arb->mclk_default_mhz = default_mhz;
179
180 err = g->ops.clk_arb.get_arbiter_clk_default(g,
181 CTRL_CLK_DOMAIN_GPC2CLK, &default_mhz);
182 if (err < 0) {
183 err = -EINVAL;
184 goto init_fail;
185 }
186
187 arb->gpc2clk_default_mhz = default_mhz;
188
189 arb->actual = &arb->actual_pool[0];
190
191 nvgpu_atomic_set(&arb->req_nr, 0);
192
193 nvgpu_atomic64_set(&arb->alarm_mask, 0);
194 err = nvgpu_clk_notification_queue_alloc(g, &arb->notification_queue,
195 DEFAULT_EVENT_NUMBER);
196 if (err < 0)
197 goto init_fail;
198
199 nvgpu_init_list_node(&arb->users);
200 nvgpu_init_list_node(&arb->sessions);
201 nvgpu_init_list_node(&arb->requests);
202
203 nvgpu_cond_init(&arb->request_wq);
204
205 nvgpu_init_list_node(&arb->update_vf_table_work_item.worker_item);
206 nvgpu_init_list_node(&arb->update_arb_work_item.worker_item);
207 arb->update_vf_table_work_item.arb = arb;
208 arb->update_arb_work_item.arb = arb;
209 arb->update_vf_table_work_item.item_type = CLK_ARB_WORK_UPDATE_VF_TABLE;
210 arb->update_arb_work_item.item_type = CLK_ARB_WORK_UPDATE_ARB;
211
212 err = nvgpu_clk_arb_worker_init(g);
213 if (err < 0)
214 goto init_fail;
215
216#ifdef CONFIG_DEBUG_FS
217 arb->debug = &arb->debug_pool[0];
218
219 if (!arb->debugfs_set) {
220 if (nvgpu_clk_arb_debugfs_init(g))
221 arb->debugfs_set = true;
222 }
223#endif
224 err = clk_vf_point_cache(g);
225 if (err < 0)
226 goto init_fail;
227
228 err = nvgpu_clk_arb_update_vf_table(arb);
229 if (err < 0)
230 goto init_fail;
231 do {
232 /* Check that first run is completed */
233 nvgpu_smp_mb();
234 NVGPU_COND_WAIT_INTERRUPTIBLE(&arb->request_wq,
235 nvgpu_atomic_read(&arb->req_nr), 0);
236 } while (!nvgpu_atomic_read(&arb->req_nr));
237
238
239 return arb->status;
240
241init_fail:
242 nvgpu_kfree(g, arb->gpc2clk_f_points);
243 nvgpu_kfree(g, arb->mclk_f_points);
244
245 for (index = 0; index < 2; index++) {
246 nvgpu_kfree(g, arb->vf_table_pool[index].gpc2clk_points);
247 nvgpu_kfree(g, arb->vf_table_pool[index].mclk_points);
248 }
249
250 nvgpu_mutex_destroy(&arb->pstate_lock);
251
252mutex_fail:
253 nvgpu_kfree(g, arb);
254
255 return err;
256}
257
258static u8 nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb,
259 u16 *gpc2clk, u16 *sys2clk, u16 *xbar2clk, u16 *mclk,
260 u32 *voltuv, u32 *voltuv_sram, u32 *nuvmin, u32 *nuvmin_sram)
261{
262 u16 gpc2clk_target, mclk_target;
263 u32 gpc2clk_voltuv, gpc2clk_voltuv_sram;
264 u32 mclk_voltuv, mclk_voltuv_sram;
265 u32 pstate = VF_POINT_INVALID_PSTATE;
266 struct nvgpu_clk_vf_table *table;
267 u32 index, index_mclk;
268 struct nvgpu_clk_vf_point *mclk_vf = NULL;
269
270 do {
271 gpc2clk_target = *gpc2clk;
272 mclk_target = *mclk;
273 gpc2clk_voltuv = 0;
274 gpc2clk_voltuv_sram = 0;
275 mclk_voltuv = 0;
276 mclk_voltuv_sram = 0;
277
278 table = NV_ACCESS_ONCE(arb->current_vf_table);
279 /* pointer to table can be updated by callback */
280 nvgpu_smp_rmb();
281
282 if (!table)
283 continue;
284 if ((!table->gpc2clk_num_points) || (!table->mclk_num_points)) {
285 nvgpu_err(arb->g, "found empty table");
286 goto find_exit;
287 }
288 /* First we check MCLK to find out which PSTATE we are
289 * are requesting, and from there try to find the minimum
290 * GPC2CLK on the same PSTATE that satisfies the request.
291 * If no GPC2CLK can be found, then we need to up the PSTATE
292 */
293
294recalculate_vf_point:
295 for (index = 0; index < table->mclk_num_points; index++) {
296 if (table->mclk_points[index].mem_mhz >= mclk_target) {
297 mclk_vf = &table->mclk_points[index];
298 break;
299 }
300 }
301 if (index == table->mclk_num_points) {
302 mclk_vf = &table->mclk_points[index-1];
303 index = table->mclk_num_points - 1;
304 }
305 index_mclk = index;
306
307 /* round up the freq requests */
308 for (index = 0; index < table->gpc2clk_num_points; index++) {
309 pstate = VF_POINT_COMMON_PSTATE(
310 &table->gpc2clk_points[index], mclk_vf);
311
312 if ((table->gpc2clk_points[index].gpc_mhz >=
313 gpc2clk_target) &&
314 (pstate != VF_POINT_INVALID_PSTATE)) {
315 gpc2clk_target =
316 table->gpc2clk_points[index].gpc_mhz;
317 *sys2clk =
318 table->gpc2clk_points[index].sys_mhz;
319 *xbar2clk =
320 table->gpc2clk_points[index].xbar_mhz;
321
322 gpc2clk_voltuv =
323 table->gpc2clk_points[index].uvolt;
324 gpc2clk_voltuv_sram =
325 table->gpc2clk_points[index].uvolt_sram;
326 break;
327 }
328 }
329
330 if (index == table->gpc2clk_num_points) {
331 pstate = VF_POINT_COMMON_PSTATE(
332 &table->gpc2clk_points[index-1], mclk_vf);
333 if (pstate != VF_POINT_INVALID_PSTATE) {
334 gpc2clk_target =
335 table->gpc2clk_points[index-1].gpc_mhz;
336 *sys2clk =
337 table->gpc2clk_points[index-1].sys_mhz;
338 *xbar2clk =
339 table->gpc2clk_points[index-1].xbar_mhz;
340
341 gpc2clk_voltuv =
342 table->gpc2clk_points[index-1].uvolt;
343 gpc2clk_voltuv_sram =
344 table->gpc2clk_points[index-1].
345 uvolt_sram;
346 } else if (index_mclk >= table->mclk_num_points - 1) {
347 /* There is no available combination of MCLK
348 * and GPC2CLK, we need to fail this
349 */
350 gpc2clk_target = 0;
351 mclk_target = 0;
352 pstate = VF_POINT_INVALID_PSTATE;
353 goto find_exit;
354 } else {
355 /* recalculate with higher PSTATE */
356 gpc2clk_target = *gpc2clk;
357 mclk_target = table->mclk_points[index_mclk+1].
358 mem_mhz;
359 goto recalculate_vf_point;
360 }
361 }
362
363 mclk_target = mclk_vf->mem_mhz;
364 mclk_voltuv = mclk_vf->uvolt;
365 mclk_voltuv_sram = mclk_vf->uvolt_sram;
366
367 } while (!table ||
368 (NV_ACCESS_ONCE(arb->current_vf_table) != table));
369
370find_exit:
371 *voltuv = gpc2clk_voltuv > mclk_voltuv ? gpc2clk_voltuv : mclk_voltuv;
372 *voltuv_sram = gpc2clk_voltuv_sram > mclk_voltuv_sram ?
373 gpc2clk_voltuv_sram : mclk_voltuv_sram;
374 /* noise unaware vmin */
375 *nuvmin = mclk_voltuv;
376 *nuvmin_sram = mclk_voltuv_sram;
377 *gpc2clk = gpc2clk_target < *gpc2clk ? gpc2clk_target : *gpc2clk;
378 *mclk = mclk_target;
379 return pstate;
380}
381
382static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target,
383 u16 sys2clk_target, u16 xbar2clk_target, u16 mclk_target, u32 voltuv,
384 u32 voltuv_sram)
385{
386 struct set_fll_clk fllclk;
387 struct nvgpu_clk_arb *arb = g->clk_arb;
388 int status;
389
390 fllclk.gpc2clkmhz = gpc2clk_target;
391 fllclk.sys2clkmhz = sys2clk_target;
392 fllclk.xbar2clkmhz = xbar2clk_target;
393
394 fllclk.voltuv = voltuv;
395
396 /* if voltage ascends we do:
397 * (1) FLL change
398 * (2) Voltage change
399 * (3) MCLK change
400 * If it goes down
401 * (1) MCLK change
402 * (2) Voltage change
403 * (3) FLL change
404 */
405
406 /* descending */
407 if (voltuv < arb->voltuv_actual) {
408 status = g->ops.clk.mclk_change(g, mclk_target);
409 if (status < 0)
410 return status;
411
412 status = volt_set_voltage(g, voltuv, voltuv_sram);
413 if (status < 0)
414 return status;
415
416 status = clk_set_fll_clks(g, &fllclk);
417 if (status < 0)
418 return status;
419 } else {
420 status = clk_set_fll_clks(g, &fllclk);
421 if (status < 0)
422 return status;
423
424 status = volt_set_voltage(g, voltuv, voltuv_sram);
425 if (status < 0)
426 return status;
427
428 status = g->ops.clk.mclk_change(g, mclk_target);
429 if (status < 0)
430 return status;
431 }
432
433 return 0;
434}
435
436void gp106_clk_arb_run_arbiter_cb(struct nvgpu_clk_arb *arb)
437{
438 struct nvgpu_clk_session *session;
439 struct nvgpu_clk_dev *dev;
440 struct nvgpu_clk_dev *tmp;
441 struct nvgpu_clk_arb_target *target, *actual;
442 struct gk20a *g = arb->g;
443
444 u32 pstate = VF_POINT_INVALID_PSTATE;
445 u32 voltuv, voltuv_sram;
446 bool mclk_set, gpc2clk_set;
447 u32 nuvmin, nuvmin_sram;
448
449 u32 alarms_notified = 0;
450 u32 current_alarm;
451 int status = 0;
452
453 /* Temporary variables for checking target frequency */
454 u16 gpc2clk_target, sys2clk_target, xbar2clk_target, mclk_target;
455 u16 gpc2clk_session_target, mclk_session_target;
456
457#ifdef CONFIG_DEBUG_FS
458 u64 t0, t1;
459 struct nvgpu_clk_arb_debug *debug;
460
461#endif
462
463 clk_arb_dbg(g, " ");
464
465 /* bail out if gpu is down */
466 if (nvgpu_atomic64_read(&arb->alarm_mask) & EVENT(ALARM_GPU_LOST))
467 goto exit_arb;
468
469#ifdef CONFIG_DEBUG_FS
470 g->ops.ptimer.read_ptimer(g, &t0);
471#endif
472
473 /* Only one arbiter should be running */
474 gpc2clk_target = 0;
475 mclk_target = 0;
476
477 nvgpu_spinlock_acquire(&arb->sessions_lock);
478 nvgpu_list_for_each_entry(session, &arb->sessions,
479 nvgpu_clk_session, link) {
480 if (!session->zombie) {
481 mclk_set = false;
482 gpc2clk_set = false;
483 target = (session->target == &session->target_pool[0] ?
484 &session->target_pool[1] :
485 &session->target_pool[0]);
486 nvgpu_spinlock_acquire(&session->session_lock);
487 if (!nvgpu_list_empty(&session->targets)) {
488 /* Copy over state */
489 target->mclk = session->target->mclk;
490 target->gpc2clk = session->target->gpc2clk;
491 /* Query the latest committed request */
492 nvgpu_list_for_each_entry_safe(dev, tmp,
493 &session->targets, nvgpu_clk_dev, node) {
494 if (!mclk_set && dev->mclk_target_mhz) {
495 target->mclk =
496 dev->mclk_target_mhz;
497 mclk_set = true;
498 }
499 if (!gpc2clk_set &&
500 dev->gpc2clk_target_mhz) {
501 target->gpc2clk =
502 dev->gpc2clk_target_mhz;
503 gpc2clk_set = true;
504 }
505 nvgpu_ref_get(&dev->refcount);
506 nvgpu_list_del(&dev->node);
507 nvgpu_spinlock_acquire(
508 &arb->requests_lock);
509 nvgpu_list_add(
510 &dev->node, &arb->requests);
511 nvgpu_spinlock_release(&arb->requests_lock);
512 }
513 session->target = target;
514 }
515 nvgpu_spinlock_release(
516 &session->session_lock);
517
518 mclk_target = mclk_target > session->target->mclk ?
519 mclk_target : session->target->mclk;
520
521 gpc2clk_target =
522 gpc2clk_target > session->target->gpc2clk ?
523 gpc2clk_target : session->target->gpc2clk;
524 }
525 }
526 nvgpu_spinlock_release(&arb->sessions_lock);
527
528 gpc2clk_target = (gpc2clk_target > 0) ? gpc2clk_target :
529 arb->gpc2clk_default_mhz;
530
531 if (gpc2clk_target < arb->gpc2clk_min)
532 gpc2clk_target = arb->gpc2clk_min;
533
534 if (gpc2clk_target > arb->gpc2clk_max)
535 gpc2clk_target = arb->gpc2clk_max;
536
537 mclk_target = (mclk_target > 0) ? mclk_target :
538 arb->mclk_default_mhz;
539
540 if (mclk_target < arb->mclk_min)
541 mclk_target = arb->mclk_min;
542
543 if (mclk_target > arb->mclk_max)
544 mclk_target = arb->mclk_max;
545
546 sys2clk_target = 0;
547 xbar2clk_target = 0;
548
549 gpc2clk_session_target = gpc2clk_target;
550 mclk_session_target = mclk_target;
551
552 /* Query the table for the closest vf point to program */
553 pstate = nvgpu_clk_arb_find_vf_point(arb, &gpc2clk_target,
554 &sys2clk_target, &xbar2clk_target, &mclk_target, &voltuv,
555 &voltuv_sram, &nuvmin, &nuvmin_sram);
556
557 if (pstate == VF_POINT_INVALID_PSTATE) {
558 arb->status = -EINVAL;
559 /* make status visible */
560 nvgpu_smp_mb();
561 goto exit_arb;
562 }
563
564 if ((gpc2clk_target < gpc2clk_session_target) ||
565 (mclk_target < mclk_session_target))
566 nvgpu_clk_arb_set_global_alarm(g,
567 EVENT(ALARM_TARGET_VF_NOT_POSSIBLE));
568
569 if ((arb->actual->gpc2clk == gpc2clk_target) &&
570 (arb->actual->mclk == mclk_target) &&
571 (arb->voltuv_actual == voltuv)) {
572 goto exit_arb;
573 }
574
575 /* Program clocks */
576 /* A change in both mclk of gpc2clk may require a change in voltage */
577
578 nvgpu_mutex_acquire(&arb->pstate_lock);
579 status = nvgpu_lpwr_disable_pg(g, false);
580
581 status = clk_pmu_freq_controller_load(g, false,
582 CTRL_CLK_CLK_FREQ_CONTROLLER_ID_ALL);
583 if (status < 0) {
584 arb->status = status;
585 nvgpu_mutex_release(&arb->pstate_lock);
586
587 /* make status visible */
588 nvgpu_smp_mb();
589 goto exit_arb;
590 }
591 status = volt_set_noiseaware_vmin(g, nuvmin, nuvmin_sram);
592 if (status < 0) {
593 arb->status = status;
594 nvgpu_mutex_release(&arb->pstate_lock);
595
596 /* make status visible */
597 nvgpu_smp_mb();
598 goto exit_arb;
599 }
600
601 status = nvgpu_clk_arb_change_vf_point(g, gpc2clk_target,
602 sys2clk_target, xbar2clk_target, mclk_target, voltuv,
603 voltuv_sram);
604 if (status < 0) {
605 arb->status = status;
606 nvgpu_mutex_release(&arb->pstate_lock);
607
608 /* make status visible */
609 nvgpu_smp_mb();
610 goto exit_arb;
611 }
612
613 status = clk_pmu_freq_controller_load(g, true,
614 CTRL_CLK_CLK_FREQ_CONTROLLER_ID_ALL);
615 if (status < 0) {
616 arb->status = status;
617 nvgpu_mutex_release(&arb->pstate_lock);
618
619 /* make status visible */
620 nvgpu_smp_mb();
621 goto exit_arb;
622 }
623
624 status = nvgpu_lwpr_mclk_change(g, pstate);
625 if (status < 0) {
626 arb->status = status;
627 nvgpu_mutex_release(&arb->pstate_lock);
628
629 /* make status visible */
630 nvgpu_smp_mb();
631 goto exit_arb;
632 }
633
634 actual = NV_ACCESS_ONCE(arb->actual) == &arb->actual_pool[0] ?
635 &arb->actual_pool[1] : &arb->actual_pool[0];
636
637 /* do not reorder this pointer */
638 nvgpu_smp_rmb();
639 actual->gpc2clk = gpc2clk_target;
640 actual->mclk = mclk_target;
641 arb->voltuv_actual = voltuv;
642 actual->pstate = pstate;
643 arb->status = status;
644
645 /* Make changes visible to other threads */
646 nvgpu_smp_wmb();
647 arb->actual = actual;
648
649 status = nvgpu_lpwr_enable_pg(g, false);
650 if (status < 0) {
651 arb->status = status;
652 nvgpu_mutex_release(&arb->pstate_lock);
653
654 /* make status visible */
655 nvgpu_smp_mb();
656 goto exit_arb;
657 }
658
659 /* status must be visible before atomic inc */
660 nvgpu_smp_wmb();
661 nvgpu_atomic_inc(&arb->req_nr);
662
663 /* Unlock pstate change for PG */
664 nvgpu_mutex_release(&arb->pstate_lock);
665
666 /* VF Update complete */
667 nvgpu_clk_arb_set_global_alarm(g, EVENT(VF_UPDATE));
668
669 nvgpu_cond_signal_interruptible(&arb->request_wq);
670
671#ifdef CONFIG_DEBUG_FS
672 g->ops.ptimer.read_ptimer(g, &t1);
673
674 debug = arb->debug == &arb->debug_pool[0] ?
675 &arb->debug_pool[1] : &arb->debug_pool[0];
676
677 memcpy(debug, arb->debug, sizeof(arb->debug_pool[0]));
678 debug->switch_num++;
679
680 if (debug->switch_num == 1) {
681 debug->switch_max = debug->switch_min =
682 debug->switch_avg = (t1-t0)/1000;
683 debug->switch_std = 0;
684 } else {
685 s64 prev_avg;
686 s64 curr = (t1-t0)/1000;
687
688 debug->switch_max = curr > debug->switch_max ?
689 curr : debug->switch_max;
690 debug->switch_min = debug->switch_min ?
691 (curr < debug->switch_min ?
692 curr : debug->switch_min) : curr;
693 prev_avg = debug->switch_avg;
694 debug->switch_avg = (curr +
695 (debug->switch_avg * (debug->switch_num-1))) /
696 debug->switch_num;
697 debug->switch_std +=
698 (curr - debug->switch_avg) * (curr - prev_avg);
699 }
700 /* commit changes before exchanging debug pointer */
701 nvgpu_smp_wmb();
702 arb->debug = debug;
703#endif
704
705exit_arb:
706 if (status < 0) {
707 nvgpu_err(g, "Error in arbiter update");
708 nvgpu_clk_arb_set_global_alarm(g,
709 EVENT(ALARM_CLOCK_ARBITER_FAILED));
710 }
711
712 current_alarm = (u32) nvgpu_atomic64_read(&arb->alarm_mask);
713 /* notify completion for all requests */
714 nvgpu_spinlock_acquire(&arb->requests_lock);
715 nvgpu_list_for_each_entry_safe(dev, tmp, &arb->requests,
716 nvgpu_clk_dev, node) {
717 nvgpu_atomic_set(&dev->poll_mask,
718 NVGPU_POLLIN | NVGPU_POLLRDNORM);
719 nvgpu_clk_arb_event_post_event(dev);
720 nvgpu_ref_put(&dev->refcount, nvgpu_clk_arb_free_fd);
721 nvgpu_list_del(&dev->node);
722 }
723 nvgpu_spinlock_release(&arb->requests_lock);
724
725 nvgpu_atomic_set(&arb->notification_queue.head,
726 nvgpu_atomic_read(&arb->notification_queue.tail));
727 /* notify event for all users */
728 nvgpu_spinlock_acquire(&arb->users_lock);
729 nvgpu_list_for_each_entry(dev, &arb->users, nvgpu_clk_dev, link) {
730 alarms_notified |=
731 nvgpu_clk_arb_notify(dev, arb->actual, current_alarm);
732 }
733 nvgpu_spinlock_release(&arb->users_lock);
734
735 /* clear alarms */
736 nvgpu_clk_arb_clear_global_alarm(g, alarms_notified &
737 ~EVENT(ALARM_GPU_LOST));
738}
739
740void gp106_clk_arb_cleanup(struct nvgpu_clk_arb *arb)
741{
742 struct gk20a *g = arb->g;
743 int index;
744
745 nvgpu_kfree(g, arb->gpc2clk_f_points);
746 nvgpu_kfree(g, arb->mclk_f_points);
747
748 for (index = 0; index < 2; index++) {
749 nvgpu_kfree(g,
750 arb->vf_table_pool[index].gpc2clk_points);
751 nvgpu_kfree(g, arb->vf_table_pool[index].mclk_points);
752 }
753
754 nvgpu_mutex_destroy(&g->clk_arb->pstate_lock);
755 nvgpu_kfree(g, g->clk_arb);
756
757 g->clk_arb = NULL;
758} \ No newline at end of file
diff --git a/drivers/gpu/nvgpu/gp106/clk_arb_gp106.h b/drivers/gpu/nvgpu/gp106/clk_arb_gp106.h
index fc4657f5..e2b2834c 100644
--- a/drivers/gpu/nvgpu/gp106/clk_arb_gp106.h
+++ b/drivers/gpu/nvgpu/gp106/clk_arb_gp106.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. 2 * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
3 * 3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a 4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"), 5 * copy of this software and associated documentation files (the "Software"),
@@ -22,10 +22,16 @@
22#ifndef CLK_ARB_GP106_H 22#ifndef CLK_ARB_GP106_H
23#define CLK_ARB_GP106_H 23#define CLK_ARB_GP106_H
24 24
25struct nvgpu_clk_session;
26struct nvgpu_clk_arb;
27
25u32 gp106_get_arbiter_clk_domains(struct gk20a *g); 28u32 gp106_get_arbiter_clk_domains(struct gk20a *g);
26int gp106_get_arbiter_clk_range(struct gk20a *g, u32 api_domain, 29int gp106_get_arbiter_clk_range(struct gk20a *g, u32 api_domain,
27 u16 *min_mhz, u16 *max_mhz); 30 u16 *min_mhz, u16 *max_mhz);
28int gp106_get_arbiter_clk_default(struct gk20a *g, u32 api_domain, 31int gp106_get_arbiter_clk_default(struct gk20a *g, u32 api_domain,
29 u16 *default_mhz); 32 u16 *default_mhz);
33int gp106_init_clk_arbiter(struct gk20a *g);
34void gp106_clk_arb_run_arbiter_cb(struct nvgpu_clk_arb *arb);
35void gp106_clk_arb_cleanup(struct nvgpu_clk_arb *arb);
30 36
31#endif /* CLK_ARB_GP106_H */ 37#endif /* CLK_ARB_GP106_H */
diff --git a/drivers/gpu/nvgpu/gp106/clk_gp106.c b/drivers/gpu/nvgpu/gp106/clk_gp106.c
index 24b07112..dd7a2dd6 100644
--- a/drivers/gpu/nvgpu/gp106/clk_gp106.c
+++ b/drivers/gpu/nvgpu/gp106/clk_gp106.c
@@ -32,7 +32,9 @@
32#include <nvgpu/list.h> 32#include <nvgpu/list.h>
33#include <nvgpu/clk_arb.h> 33#include <nvgpu/clk_arb.h>
34#include <nvgpu/timers.h> 34#include <nvgpu/timers.h>
35#include <nvgpu/pmu.h>
35 36
37#include "clk/clk.h"
36#include "gk20a/gk20a.h" 38#include "gk20a/gk20a.h"
37#include "gp106/mclk_gp106.h" 39#include "gp106/mclk_gp106.h"
38 40
@@ -243,6 +245,37 @@ read_err:
243 245
244} 246}
245 247
248int gp106_clk_domain_get_f_points(
249 struct gk20a *g,
250 u32 clkapidomain,
251 u32 *pfpointscount,
252 u16 *pfreqpointsinmhz)
253{
254 int status = -EINVAL;
255 struct clk_domain *pdomain;
256 u8 i;
257 struct clk_pmupstate *pclk = &g->clk_pmu;
258
259 if (pfpointscount == NULL)
260 return -EINVAL;
261
262 if ((pfreqpointsinmhz == NULL) && (*pfpointscount != 0))
263 return -EINVAL;
264
265 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
266 struct clk_domain *, pdomain, i) {
267 if (pdomain->api_domain == clkapidomain) {
268 status = pdomain->clkdomainclkgetfpoints(g, pclk,
269 pdomain, pfpointscount,
270 pfreqpointsinmhz,
271 CLK_PROG_VFE_ENTRY_LOGIC);
272 return status;
273 }
274 }
275 return status;
276}
277
278
246#ifdef CONFIG_DEBUG_FS 279#ifdef CONFIG_DEBUG_FS
247static int gp106_get_rate_show(void *data , u64 *val) { 280static int gp106_get_rate_show(void *data , u64 *val) {
248 struct namemap_cfg *c = (struct namemap_cfg *) data; 281 struct namemap_cfg *c = (struct namemap_cfg *) data;
diff --git a/drivers/gpu/nvgpu/gp106/clk_gp106.h b/drivers/gpu/nvgpu/gp106/clk_gp106.h
index 97baa224..b7ab3164 100644
--- a/drivers/gpu/nvgpu/gp106/clk_gp106.h
+++ b/drivers/gpu/nvgpu/gp106/clk_gp106.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. 2 * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
3 * 3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a 4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"), 5 * copy of this software and associated documentation files (the "Software"),
@@ -56,5 +56,10 @@ int gp106_init_clk_support(struct gk20a *g);
56u32 gp106_crystal_clk_hz(struct gk20a *g); 56u32 gp106_crystal_clk_hz(struct gk20a *g);
57unsigned long gp106_clk_measure_freq(struct gk20a *g, u32 api_domain); 57unsigned long gp106_clk_measure_freq(struct gk20a *g, u32 api_domain);
58int gp106_suspend_clk_support(struct gk20a *g); 58int gp106_suspend_clk_support(struct gk20a *g);
59int gp106_clk_domain_get_f_points(
60 struct gk20a *g,
61 u32 clkapidomain,
62 u32 *pfpointscount,
63 u16 *pfreqpointsinmhz);
59 64
60#endif /* CLK_GP106_H */ 65#endif /* CLK_GP106_H */
diff --git a/drivers/gpu/nvgpu/gp106/hal_gp106.c b/drivers/gpu/nvgpu/gp106/hal_gp106.c
index 78a3ea63..167bfaac 100644
--- a/drivers/gpu/nvgpu/gp106/hal_gp106.c
+++ b/drivers/gpu/nvgpu/gp106/hal_gp106.c
@@ -675,6 +675,7 @@ static const struct gpu_ops gp106_ops = {
675 .get_crystal_clk_hz = gp106_crystal_clk_hz, 675 .get_crystal_clk_hz = gp106_crystal_clk_hz,
676 .measure_freq = gp106_clk_measure_freq, 676 .measure_freq = gp106_clk_measure_freq,
677 .suspend_clk_support = gp106_suspend_clk_support, 677 .suspend_clk_support = gp106_suspend_clk_support,
678 .clk_domain_get_f_points = gp106_clk_domain_get_f_points,
678 .mclk_init = gp106_mclk_init, 679 .mclk_init = gp106_mclk_init,
679 .mclk_change = gp106_mclk_change, 680 .mclk_change = gp106_mclk_change,
680 .mclk_deinit = gp106_mclk_deinit, 681 .mclk_deinit = gp106_mclk_deinit,
@@ -684,6 +685,9 @@ static const struct gpu_ops gp106_ops = {
684 .get_arbiter_clk_range = gp106_get_arbiter_clk_range, 685 .get_arbiter_clk_range = gp106_get_arbiter_clk_range,
685 .get_arbiter_clk_default = gp106_get_arbiter_clk_default, 686 .get_arbiter_clk_default = gp106_get_arbiter_clk_default,
686 .get_current_pstate = nvgpu_clk_arb_get_current_pstate, 687 .get_current_pstate = nvgpu_clk_arb_get_current_pstate,
688 .arbiter_clk_init = gp106_init_clk_arbiter,
689 .clk_arb_run_arbiter_cb = gp106_clk_arb_run_arbiter_cb,
690 .clk_arb_cleanup = gp106_clk_arb_cleanup,
687 }, 691 },
688 .regops = { 692 .regops = {
689 .exec_regops = exec_regops_gk20a, 693 .exec_regops = exec_regops_gk20a,
@@ -849,6 +853,7 @@ int gp106_init_hal(struct gk20a *g)
849 gops->clk.mclk_init = gp106_ops.clk.mclk_init; 853 gops->clk.mclk_init = gp106_ops.clk.mclk_init;
850 gops->clk.mclk_change = gp106_ops.clk.mclk_change; 854 gops->clk.mclk_change = gp106_ops.clk.mclk_change;
851 gops->clk.mclk_deinit = gp106_ops.clk.mclk_deinit; 855 gops->clk.mclk_deinit = gp106_ops.clk.mclk_deinit;
856 gops->clk.clk_domain_get_f_points = gp106_ops.clk.clk_domain_get_f_points;
852 857
853 gops->clk_arb = gp106_ops.clk_arb; 858 gops->clk_arb = gp106_ops.clk_arb;
854 gops->regops = gp106_ops.regops; 859 gops->regops = gp106_ops.regops;
diff --git a/drivers/gpu/nvgpu/include/nvgpu/clk_arb.h b/drivers/gpu/nvgpu/include/nvgpu/clk_arb.h
index 328e03b5..e63545df 100644
--- a/drivers/gpu/nvgpu/include/nvgpu/clk_arb.h
+++ b/drivers/gpu/nvgpu/include/nvgpu/clk_arb.h
@@ -287,6 +287,10 @@ nvgpu_clk_arb_work_item_from_worker_item(struct nvgpu_list_node *node)
287void nvgpu_clk_arb_worker_enqueue(struct gk20a *g, 287void nvgpu_clk_arb_worker_enqueue(struct gk20a *g,
288 struct nvgpu_clk_arb_work_item *work_item); 288 struct nvgpu_clk_arb_work_item *work_item);
289 289
290int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb);
291
292int nvgpu_clk_arb_worker_init(struct gk20a *g);
293
290int nvgpu_clk_arb_init_arbiter(struct gk20a *g); 294int nvgpu_clk_arb_init_arbiter(struct gk20a *g);
291 295
292int nvgpu_clk_arb_get_arbiter_clk_range(struct gk20a *g, u32 api_domain, 296int nvgpu_clk_arb_get_arbiter_clk_range(struct gk20a *g, u32 api_domain,
@@ -338,12 +342,20 @@ void nvgpu_clk_arb_pstate_change_lock(struct gk20a *g, bool lock);
338 342
339void nvgpu_clk_arb_send_thermal_alarm(struct gk20a *g); 343void nvgpu_clk_arb_send_thermal_alarm(struct gk20a *g);
340 344
345void nvgpu_clk_arb_set_global_alarm(struct gk20a *g, u32 alarm);
346
341void nvgpu_clk_arb_schedule_alarm(struct gk20a *g, u32 alarm); 347void nvgpu_clk_arb_schedule_alarm(struct gk20a *g, u32 alarm);
342 348
349void nvgpu_clk_arb_clear_global_alarm(struct gk20a *g, u32 alarm);
350
343void nvgpu_clk_arb_free_session(struct nvgpu_ref *refcount); 351void nvgpu_clk_arb_free_session(struct nvgpu_ref *refcount);
344 352
345void nvgpu_clk_arb_free_fd(struct nvgpu_ref *refcount); 353void nvgpu_clk_arb_free_fd(struct nvgpu_ref *refcount);
346 354
355u32 nvgpu_clk_arb_notify(struct nvgpu_clk_dev *dev,
356 struct nvgpu_clk_arb_target *target,
357 u32 alarm);
358
347int nvgpu_clk_notification_queue_alloc(struct gk20a *g, 359int nvgpu_clk_notification_queue_alloc(struct gk20a *g,
348 struct nvgpu_clk_notification_queue *queue, 360 struct nvgpu_clk_notification_queue *queue,
349 size_t events_number); 361 size_t events_number);
diff --git a/drivers/gpu/nvgpu/os/posix/clk_arb.c b/drivers/gpu/nvgpu/os/posix/clk_arb.c
index 2214b37b..63ab0f13 100644
--- a/drivers/gpu/nvgpu/os/posix/clk_arb.c
+++ b/drivers/gpu/nvgpu/os/posix/clk_arb.c
@@ -42,6 +42,16 @@ int nvgpu_clk_arb_get_arbiter_clk_range(struct gk20a *g, u32 api_domain,
42 return -ENOSYS; 42 return -ENOSYS;
43} 43}
44 44
45int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb)
46{
47 return -ENOSYS;
48}
49
50int nvgpu_clk_arb_worker_init(struct gk20a *g)
51{
52 return -ENOSYS;
53}
54
45int nvgpu_clk_arb_get_arbiter_actual_mhz(struct gk20a *g, 55int nvgpu_clk_arb_get_arbiter_actual_mhz(struct gk20a *g,
46 u32 api_domain, u16 *actual_mhz) 56 u32 api_domain, u16 *actual_mhz)
47{ 57{
@@ -54,7 +64,6 @@ int nvgpu_clk_arb_get_arbiter_effective_mhz(struct gk20a *g,
54 return -ENOSYS; 64 return -ENOSYS;
55} 65}
56 66
57
58int nvgpu_clk_arb_get_arbiter_clk_f_points(struct gk20a *g, 67int nvgpu_clk_arb_get_arbiter_clk_f_points(struct gk20a *g,
59 u32 api_domain, 68 u32 api_domain,
60 u32 *max_points, u16 *fpoints) 69 u32 *max_points, u16 *fpoints)
@@ -127,6 +136,17 @@ int nvgpu_clk_arb_install_request_fd(struct gk20a *g,
127 return -ENOSYS; 136 return -ENOSYS;
128} 137}
129 138
139u32 nvgpu_clk_arb_notify(struct nvgpu_clk_dev *dev,
140 struct nvgpu_clk_arb_target *target,
141 u32 alarm)
142{
143 return 0;
144}
145
146void nvgpu_clk_arb_free_fd(struct nvgpu_ref *refcount)
147{
148}
149
130void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g) 150void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g)
131{ 151{
132} 152}
@@ -147,3 +167,27 @@ void nvgpu_clk_arb_send_thermal_alarm(struct gk20a *g)
147void nvgpu_clk_arb_schedule_alarm(struct gk20a *g, u32 alarm) 167void nvgpu_clk_arb_schedule_alarm(struct gk20a *g, u32 alarm)
148{ 168{
149} 169}
170
171void nvgpu_clk_arb_set_global_alarm(struct gk20a *g, u32 alarm)
172{
173}
174
175void nvgpu_clk_arb_clear_global_alarm(struct gk20a *g, u32 alarm)
176{
177}
178
179void nvgpu_clk_arb_event_post_event(struct nvgpu_clk_dev *dev)
180{
181}
182
183void nvgpu_clk_arb_worker_enqueue(struct gk20a *g,
184 struct nvgpu_clk_arb_work_item *work_item)
185{
186}
187
188int nvgpu_clk_notification_queue_alloc(struct gk20a *g,
189 struct nvgpu_clk_notification_queue *queue,
190 size_t events_number)
191{
192 return -ENOSYS;
193}