aboutsummaryrefslogtreecommitdiffstats
path: root/include/clk/clk_arb.c
diff options
context:
space:
mode:
Diffstat (limited to 'include/clk/clk_arb.c')
-rw-r--r--include/clk/clk_arb.c1087
1 files changed, 1087 insertions, 0 deletions
diff --git a/include/clk/clk_arb.c b/include/clk/clk_arb.c
new file mode 100644
index 0000000..6cf005c
--- /dev/null
+++ b/include/clk/clk_arb.c
@@ -0,0 +1,1087 @@
1/*
2 * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <nvgpu/bitops.h>
24#include <nvgpu/lock.h>
25#include <nvgpu/kmem.h>
26#include <nvgpu/atomic.h>
27#include <nvgpu/bug.h>
28#include <nvgpu/kref.h>
29#include <nvgpu/log.h>
30#include <nvgpu/barrier.h>
31#include <nvgpu/cond.h>
32#include <nvgpu/list.h>
33#include <nvgpu/clk_arb.h>
34#include <nvgpu/timers.h>
35#include <nvgpu/gk20a.h>
36
37#include "clk/clk.h"
38#include "pstate/pstate.h"
39#include "lpwr/lpwr.h"
40#include "volt/volt.h"
41
42int nvgpu_clk_notification_queue_alloc(struct gk20a *g,
43 struct nvgpu_clk_notification_queue *queue,
44 size_t events_number) {
45 queue->notifications = nvgpu_kcalloc(g, events_number,
46 sizeof(struct nvgpu_clk_notification));
47 if (!queue->notifications)
48 return -ENOMEM;
49 queue->size = events_number;
50
51 nvgpu_atomic_set(&queue->head, 0);
52 nvgpu_atomic_set(&queue->tail, 0);
53
54 return 0;
55}
56
57void nvgpu_clk_notification_queue_free(struct gk20a *g,
58 struct nvgpu_clk_notification_queue *queue) {
59 if (queue->size > 0) {
60 nvgpu_kfree(g, queue->notifications);
61 queue->size = 0;
62 nvgpu_atomic_set(&queue->head, 0);
63 nvgpu_atomic_set(&queue->tail, 0);
64 }
65}
66
67static void nvgpu_clk_arb_queue_notification(struct gk20a *g,
68 struct nvgpu_clk_notification_queue *queue,
69 u32 alarm_mask) {
70
71 u32 queue_index;
72 u64 timestamp;
73
74 queue_index = (nvgpu_atomic_inc_return(&queue->tail)) % queue->size;
75 /* get current timestamp */
76 timestamp = (u64) nvgpu_hr_timestamp();
77
78 queue->notifications[queue_index].timestamp = timestamp;
79 queue->notifications[queue_index].notification = alarm_mask;
80
81}
82
83void nvgpu_clk_arb_set_global_alarm(struct gk20a *g, u32 alarm)
84{
85 struct nvgpu_clk_arb *arb = g->clk_arb;
86
87 u64 current_mask;
88 u32 refcnt;
89 u32 alarm_mask;
90 u64 new_mask;
91
92 do {
93 current_mask = nvgpu_atomic64_read(&arb->alarm_mask);
94 /* atomic operations are strong so they do not need masks */
95
96 refcnt = ((u32) (current_mask >> 32)) + 1;
97 alarm_mask = (u32) (current_mask & ~0) | alarm;
98 new_mask = ((u64) refcnt << 32) | alarm_mask;
99
100 } while (unlikely(current_mask !=
101 (u64)nvgpu_atomic64_cmpxchg(&arb->alarm_mask,
102 current_mask, new_mask)));
103
104 nvgpu_clk_arb_queue_notification(g, &arb->notification_queue, alarm);
105}
106
107
108int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb)
109{
110 struct gk20a *g = arb->g;
111 struct nvgpu_clk_vf_table *table;
112
113 u32 i, j;
114 int status = -EINVAL;
115 u32 gpc2clk_voltuv = 0, mclk_voltuv = 0;
116 u32 gpc2clk_voltuv_sram = 0, mclk_voltuv_sram = 0;
117 u16 clk_cur;
118 u32 num_points;
119
120 struct clk_set_info *p5_info, *p0_info;
121
122 table = NV_ACCESS_ONCE(arb->current_vf_table);
123 /* make flag visible when all data has resolved in the tables */
124 nvgpu_smp_rmb();
125
126 table = (table == &arb->vf_table_pool[0]) ? &arb->vf_table_pool[1] :
127 &arb->vf_table_pool[0];
128
129 /* Get allowed memory ranges */
130 if (g->ops.clk_arb.get_arbiter_clk_range(g, CTRL_CLK_DOMAIN_GPC2CLK,
131 &arb->gpc2clk_min,
132 &arb->gpc2clk_max) < 0) {
133 nvgpu_err(g, "failed to fetch GPC2CLK range");
134 goto exit_vf_table;
135 }
136 if (g->ops.clk_arb.get_arbiter_clk_range(g, CTRL_CLK_DOMAIN_MCLK,
137 &arb->mclk_min,
138 &arb->mclk_max) < 0) {
139 nvgpu_err(g, "failed to fetch MCLK range");
140 goto exit_vf_table;
141 }
142
143 table->gpc2clk_num_points = MAX_F_POINTS;
144 table->mclk_num_points = MAX_F_POINTS;
145
146 if (g->ops.clk.clk_domain_get_f_points(arb->g, CTRL_CLK_DOMAIN_GPC2CLK,
147 &table->gpc2clk_num_points, arb->gpc2clk_f_points)) {
148 nvgpu_err(g, "failed to fetch GPC2CLK frequency points");
149 goto exit_vf_table;
150 }
151
152 if (g->ops.clk.clk_domain_get_f_points(arb->g, CTRL_CLK_DOMAIN_MCLK,
153 &table->mclk_num_points, arb->mclk_f_points)) {
154 nvgpu_err(g, "failed to fetch MCLK frequency points");
155 goto exit_vf_table;
156 }
157 if (!table->mclk_num_points || !table->gpc2clk_num_points) {
158 nvgpu_err(g, "empty queries to f points mclk %d gpc2clk %d",
159 table->mclk_num_points, table->gpc2clk_num_points);
160 status = -EINVAL;
161 goto exit_vf_table;
162 }
163
164 memset(table->mclk_points, 0,
165 table->mclk_num_points*sizeof(struct nvgpu_clk_vf_point));
166 memset(table->gpc2clk_points, 0,
167 table->gpc2clk_num_points*sizeof(struct nvgpu_clk_vf_point));
168
169 p5_info = pstate_get_clk_set_info(g,
170 CTRL_PERF_PSTATE_P5, clkwhich_mclk);
171 if (!p5_info) {
172 nvgpu_err(g, "failed to get MCLK P5 info");
173 goto exit_vf_table;
174 }
175 p0_info = pstate_get_clk_set_info(g,
176 CTRL_PERF_PSTATE_P0, clkwhich_mclk);
177 if (!p0_info) {
178 nvgpu_err(g, "failed to get MCLK P0 info");
179 goto exit_vf_table;
180 }
181
182 for (i = 0, j = 0, num_points = 0, clk_cur = 0;
183 i < table->mclk_num_points; i++) {
184
185 if ((arb->mclk_f_points[i] >= arb->mclk_min) &&
186 (arb->mclk_f_points[i] <= arb->mclk_max) &&
187 (arb->mclk_f_points[i] != clk_cur)) {
188
189 table->mclk_points[j].mem_mhz = arb->mclk_f_points[i];
190 mclk_voltuv = mclk_voltuv_sram = 0;
191
192 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_MCLK,
193 &table->mclk_points[j].mem_mhz, &mclk_voltuv,
194 CTRL_VOLT_DOMAIN_LOGIC);
195 if (status < 0) {
196 nvgpu_err(g,
197 "failed to get MCLK LOGIC voltage");
198 goto exit_vf_table;
199 }
200 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_MCLK,
201 &table->mclk_points[j].mem_mhz,
202 &mclk_voltuv_sram,
203 CTRL_VOLT_DOMAIN_SRAM);
204 if (status < 0) {
205 nvgpu_err(g, "failed to get MCLK SRAM voltage");
206 goto exit_vf_table;
207 }
208
209 table->mclk_points[j].uvolt = mclk_voltuv;
210 table->mclk_points[j].uvolt_sram = mclk_voltuv_sram;
211 clk_cur = table->mclk_points[j].mem_mhz;
212
213 if ((clk_cur >= p5_info->min_mhz) &&
214 (clk_cur <= p5_info->max_mhz))
215 VF_POINT_SET_PSTATE_SUPPORTED(
216 &table->mclk_points[j],
217 CTRL_PERF_PSTATE_P5);
218 if ((clk_cur >= p0_info->min_mhz) &&
219 (clk_cur <= p0_info->max_mhz))
220 VF_POINT_SET_PSTATE_SUPPORTED(
221 &table->mclk_points[j],