summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorThomas Fleury <tfleury@nvidia.com>2016-09-13 17:23:45 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:51 -0500
commit3d9c33c5953e383527c7e4af594adfe0c82b5788 (patch)
tree6de4ae86667c763ed0deef3add9336b570ca15ff /drivers
parentc320ccfa952a2796db27d97111791bcbeff9f5c7 (diff)
gpu: nvgpu: clk arbiter skeleton
Add clock arbiter skeleton with support of clock sessions, notifications on clock changes, request numbering, and asynchronous handling of clock requests. Provides minimum behaviour to allow unit tests implementation. Actual arbitration and clock settings will be done separately. For now, dummy arbiter keeps last requested target mhz. Actual arbiter may move to a lockless implementation. Jira DNVGPU-125 Change-Id: I6a8e443fb0d15dc5f1993e7260256d71acddd106 Signed-off-by: Thomas Fleury <tfleury@nvidia.com> Reviewed-on: http://git-master/r/1223476 (cherry picked from commit cb130825d84e4124d273bd443e2b62d493377461) Reviewed-on: http://git-master/r/1243105 GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/nvgpu/Makefile.nvgpu-t18x2
-rw-r--r--drivers/gpu/nvgpu/clk/clk_arb.c387
-rw-r--r--drivers/gpu/nvgpu/clk/clk_arb.h63
-rw-r--r--drivers/gpu/nvgpu/gp106/clk_arb_gp106.c95
-rw-r--r--drivers/gpu/nvgpu/gp106/clk_arb_gp106.h21
-rw-r--r--drivers/gpu/nvgpu/gp106/clk_gp106.c1
-rw-r--r--drivers/gpu/nvgpu/gp106/hal_gp106.c2
-rw-r--r--drivers/gpu/nvgpu/pstate/pstate.c40
-rw-r--r--drivers/gpu/nvgpu/pstate/pstate.h9
9 files changed, 618 insertions, 2 deletions
diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
index bb19d595..a096a438 100644
--- a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
+++ b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
@@ -38,11 +38,13 @@ nvgpu-y += \
38 $(nvgpu-t18x)/clk/clk_domain.o \ 38 $(nvgpu-t18x)/clk/clk_domain.o \
39 $(nvgpu-t18x)/clk/clk_prog.o \ 39 $(nvgpu-t18x)/clk/clk_prog.o \
40 $(nvgpu-t18x)/clk/clk_vf_point.o \ 40 $(nvgpu-t18x)/clk/clk_vf_point.o \
41 $(nvgpu-t18x)/clk/clk_arb.o \
41 $(nvgpu-t18x)/perf/vfe_var.o \ 42 $(nvgpu-t18x)/perf/vfe_var.o \
42 $(nvgpu-t18x)/perf/vfe_equ.o \ 43 $(nvgpu-t18x)/perf/vfe_equ.o \
43 $(nvgpu-t18x)/perf/perf.o \ 44 $(nvgpu-t18x)/perf/perf.o \
44 $(nvgpu-t18x)/clk/clk.o \ 45 $(nvgpu-t18x)/clk/clk.o \
45 $(nvgpu-t18x)/gp106/clk_gp106.o \ 46 $(nvgpu-t18x)/gp106/clk_gp106.o \
47 $(nvgpu-t18x)/gp106/clk_arb_gp106.o \
46 $(nvgpu-t18x)/gp106/gp106_gating_reglist.o \ 48 $(nvgpu-t18x)/gp106/gp106_gating_reglist.o \
47 $(nvgpu-t18x)/gp106/xve_gp106.o \ 49 $(nvgpu-t18x)/gp106/xve_gp106.o \
48 $(nvgpu-t18x)/gp106/therm_gp106.o \ 50 $(nvgpu-t18x)/gp106/therm_gp106.o \
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.c b/drivers/gpu/nvgpu/clk/clk_arb.c
new file mode 100644
index 00000000..1d02c7d7
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_arb.c
@@ -0,0 +1,387 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15
16#include <linux/cdev.h>
17#include <linux/file.h>
18#include <linux/anon_inodes.h>
19#include <linux/nvgpu.h>
20#include <linux/bitops.h>
21
22#include "clk/clk_arb.h"
23
24static int nvgpu_clk_arb_release_session_dev(struct inode *inode, struct file *filp);
25static unsigned int nvgpu_clk_arb_poll_session_dev(struct file *filp, poll_table *wait);
26
27static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work);
28
29struct nvgpu_clk_arb {
30 struct mutex wlock;
31 struct mutex users_lock;
32 struct list_head users;
33 u32 gpc2clk_current_mhz;
34 u32 gpc2clk_target_mhz;
35 u32 gpc2clk_default_mhz;
36 u32 mclk_current_mhz;
37 u32 mclk_target_mhz;
38 u32 mclk_default_mhz;
39 atomic_t usercount;
40 struct work_struct update_fn_work;
41
42 atomic_t req_nr; /* for allocations */
43 atomic_t last_req_nr; /* last completed by arbiter */
44};
45
46struct nvgpu_clk_session {
47 struct gk20a *g;
48 int fd;
49 atomic_t req_nr;
50 struct kref refcount;
51 wait_queue_head_t readout_wq;
52 atomic_t poll_mask;
53 struct list_head user;
54 u32 gpc2clk_target_mhz;
55 u32 mclk_target_mhz;
56};
57
58const struct file_operations clk_dev_ops = {
59 .owner = THIS_MODULE,
60 .release = nvgpu_clk_arb_release_session_dev,
61 .poll = nvgpu_clk_arb_poll_session_dev,
62};
63
64int nvgpu_clk_arb_init_arbiter(struct gk20a *g)
65{
66 struct nvgpu_clk_arb *arb;
67 u16 default_mhz;
68 int err;
69
70 gk20a_dbg_fn("");
71
72 if (!g->ops.clk_arb.get_arbiter_clk_domains)
73 return 0;
74
75 arb = kzalloc(sizeof(struct nvgpu_clk_arb), GFP_KERNEL);
76 if (!arb)
77 return -ENOMEM;
78
79 g->clk_arb = arb;
80
81 mutex_init(&arb->wlock);
82 mutex_init(&arb->users_lock);
83
84 err = g->ops.clk_arb.get_arbiter_clk_default(g,
85 NVGPU_GPU_CLK_DOMAIN_MCLK, &default_mhz);
86 if (err)
87 return -EINVAL;
88
89 arb->mclk_target_mhz = default_mhz;
90 arb->mclk_current_mhz = default_mhz;
91 arb->mclk_default_mhz = default_mhz;
92
93 err = g->ops.clk_arb.get_arbiter_clk_default(g,
94 NVGPU_GPU_CLK_DOMAIN_GPC2CLK, &default_mhz);
95 if (err)
96 return -EINVAL;
97
98 arb->gpc2clk_target_mhz = default_mhz;
99 arb->gpc2clk_current_mhz = default_mhz;
100 arb->gpc2clk_default_mhz = default_mhz;
101
102 atomic_set(&arb->usercount, 0);
103 atomic_set(&arb->req_nr, 0);
104 atomic_set(&arb->last_req_nr, 0);
105
106 INIT_LIST_HEAD(&arb->users);
107 INIT_WORK(&arb->update_fn_work, nvgpu_clk_arb_run_arbiter_cb);
108
109 return 0;
110}
111
112void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g)
113{
114 kfree(g->clk_arb);
115}
116
117
118int nvgpu_clk_arb_install_session_fd(struct gk20a *g,
119 struct nvgpu_clk_session *session)
120{
121 struct file *file;
122 char *name;
123 int fd;
124 int err;
125
126 gk20a_dbg_fn("");
127
128 if (session->fd >= 0)
129 goto done;
130
131 fd = get_unused_fd_flags(O_RDWR);
132 if (fd < 0)
133 return fd;
134
135 name = kasprintf(GFP_KERNEL, "%s-clk-fd%d", dev_name(g->dev), fd);
136 file = anon_inode_getfile(name, &clk_dev_ops, session, O_RDWR);
137 kfree(name);
138 if (IS_ERR(file)) {
139 err = PTR_ERR(file);
140 goto clean_up_fd;
141 }
142
143 BUG_ON(file->private_data != session);
144
145 fd_install(fd, file);
146 kref_get(&session->refcount);
147
148 session->fd = fd;
149done:
150 return session->fd;
151
152clean_up_fd:
153 put_unused_fd(fd);
154
155 return err;
156}
157
158int nvgpu_clk_arb_init_session(struct gk20a *g,
159 struct nvgpu_clk_session **_session)
160{
161 struct nvgpu_clk_arb *arb = g->clk_arb;
162 struct nvgpu_clk_session *session = *(_session);
163
164 gk20a_dbg_fn("");
165
166 *_session = NULL;
167
168 if (!g->ops.clk_arb.get_arbiter_clk_domains)
169 return 0;
170
171 session = kzalloc(sizeof(struct nvgpu_clk_session), GFP_KERNEL);
172 if (!session)
173 return -ENOMEM;
174 session->g = g;
175 session->fd = -1;
176
177 kref_init(&session->refcount);
178 init_waitqueue_head(&session->readout_wq);
179
180 atomic_set(&session->poll_mask, 0);
181 atomic_set(&session->req_nr, 0);
182
183 mutex_lock(&arb->users_lock);
184 list_add_tail(&session->user, &arb->users);
185 mutex_unlock(&arb->users_lock);
186 atomic_inc(&arb->usercount);
187
188 mutex_lock(&arb->wlock);
189 session->mclk_target_mhz = arb->mclk_default_mhz;
190 session->gpc2clk_target_mhz = arb->gpc2clk_default_mhz;
191 mutex_unlock(&arb->wlock);
192
193 *_session = session;
194
195 return 0;
196}
197
198void nvgpu_clk_arb_free_session(struct kref *refcount)
199{
200 struct nvgpu_clk_session *session = container_of(refcount,
201 struct nvgpu_clk_session, refcount);
202 struct gk20a *g = session->g;
203 struct nvgpu_clk_arb *arb = g->clk_arb;
204
205 mutex_lock(&arb->users_lock);
206 list_del_init(&session->user);
207 mutex_unlock(&arb->users_lock);
208
209 if (atomic_dec_and_test(&arb->usercount))
210 nvgpu_clk_arb_apply_session_constraints(g, NULL);
211
212 kfree(session);
213}
214
215void nvgpu_clk_arb_cleanup_session(struct gk20a *g,
216 struct nvgpu_clk_session *session)
217{
218 kref_put(&session->refcount, nvgpu_clk_arb_free_session);
219}
220
221static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work)
222{
223 struct nvgpu_clk_arb *arb =
224 container_of(work, struct nvgpu_clk_arb, update_fn_work);
225 struct nvgpu_clk_session *session;
226
227 mutex_lock(&arb->wlock);
228
229 /* TODO: loop up higher or equal VF points */
230
231 arb->mclk_current_mhz = arb->mclk_target_mhz;
232 arb->gpc2clk_current_mhz = arb->gpc2clk_target_mhz;
233
234 /* TODO: actually program the clocks */
235
236 atomic_set(&arb->last_req_nr, atomic_read(&arb->req_nr));
237 mutex_unlock(&arb->wlock);
238
239 mutex_lock(&arb->users_lock);
240 list_for_each_entry(session, &arb->users, user) {
241 atomic_set(&session->poll_mask, POLLIN | POLLRDNORM);
242 wake_up_interruptible(&session->readout_wq);
243 }
244 mutex_unlock(&arb->users_lock);
245
246}
247
248void nvgpu_clk_arb_apply_session_constraints(struct gk20a *g,
249 struct nvgpu_clk_session *session)
250{
251 struct nvgpu_clk_arb *arb = g->clk_arb;
252
253 mutex_lock(&arb->wlock);
254 atomic_inc(&arb->req_nr);
255
256 /* TODO: arbitration between users.
257 For now, last session to run arbiter wins.
258 */
259
260 if (session) {
261 arb->mclk_target_mhz = session->mclk_target_mhz;
262 arb->gpc2clk_target_mhz = session->gpc2clk_target_mhz;
263
264 atomic_set(&session->req_nr, atomic_read(&arb->req_nr));
265 } else {
266 arb->mclk_target_mhz = arb->mclk_default_mhz;
267 arb->gpc2clk_target_mhz = arb->gpc2clk_default_mhz;
268 }
269 mutex_unlock(&arb->wlock);
270
271 schedule_work(&arb->update_fn_work);
272}
273
274static unsigned int nvgpu_clk_arb_poll_session_dev(struct file *filp, poll_table *wait)
275{
276 struct nvgpu_clk_session *session = filp->private_data;
277
278 gk20a_dbg_fn("");
279
280 poll_wait(filp, &session->readout_wq, wait);
281 return atomic_xchg(&session->poll_mask, 0);
282}
283
284static int nvgpu_clk_arb_release_session_dev(struct inode *inode, struct file *filp)
285{
286 struct nvgpu_clk_session *session = filp->private_data;
287 struct gk20a *g = session->g;
288
289 session->fd = -1;
290 nvgpu_clk_arb_cleanup_session(g, session);
291
292 return 0;
293}
294
295int nvgpu_clk_arb_set_session_target_mhz(struct nvgpu_clk_session *session,
296 u32 api_domain, u16 target_mhz)
297{
298
299 gk20a_dbg_fn("domain=0x%08x target_mhz=%u", api_domain, target_mhz);
300
301 switch (api_domain) {
302 case NVGPU_GPU_CLK_DOMAIN_MCLK:
303 session->mclk_target_mhz = target_mhz;
304 return 0;
305
306 case NVGPU_GPU_CLK_DOMAIN_GPC2CLK:
307 session->gpc2clk_target_mhz = target_mhz;
308 return 0;
309
310 default:
311 return -EINVAL;
312 }
313}
314
315int nvgpu_clk_arb_get_session_target_mhz(struct nvgpu_clk_session *session,
316 u32 api_domain, u16 *target_mhz)
317{
318 switch (api_domain) {
319 case NVGPU_GPU_CLK_DOMAIN_MCLK:
320 *target_mhz = session->mclk_target_mhz;
321 return 0;
322
323 case NVGPU_GPU_CLK_DOMAIN_GPC2CLK:
324 *target_mhz = session->gpc2clk_target_mhz;
325 return 0;
326
327 default:
328 *target_mhz = 0;
329 return -EINVAL;
330 }
331}
332
333int nvgpu_clk_arb_get_arbiter_actual_mhz(struct gk20a *g,
334 u32 api_domain, u16 *actual_mhz)
335{
336 struct nvgpu_clk_arb *arb = g->clk_arb;
337 int err = 0;
338
339 mutex_lock(&arb->wlock);
340 switch (api_domain) {
341 case NVGPU_GPU_CLK_DOMAIN_MCLK:
342 *actual_mhz = arb->mclk_current_mhz;
343 break;
344
345 case NVGPU_GPU_CLK_DOMAIN_GPC2CLK:
346 *actual_mhz = arb->gpc2clk_current_mhz;
347 break;
348
349 default:
350 *actual_mhz = 0;
351 err = -EINVAL;
352 }
353 mutex_unlock(&arb->wlock);
354
355 return err;
356}
357
358u32 nvgpu_clk_arb_get_arbiter_req_nr(struct gk20a *g)
359{
360 struct nvgpu_clk_arb *arb = g->clk_arb;
361
362 return atomic_read(&arb->last_req_nr);
363}
364
365int nvgpu_clk_arb_get_arbiter_clk_range(struct gk20a *g, u32 api_domain,
366 u16 *min_mhz, u16 *max_mhz)
367{
368 return g->ops.clk_arb.get_arbiter_clk_range(g, api_domain,
369 min_mhz, max_mhz);
370}
371
372u32 nvgpu_clk_arb_get_arbiter_clk_domains(struct gk20a *g)
373{
374 return g->ops.clk_arb.get_arbiter_clk_domains(g);
375}
376
377u32 nvgpu_clk_arb_get_session_req_nr(struct gk20a *g,
378 struct nvgpu_clk_session *session)
379{
380 return atomic_read(&session->req_nr);
381}
382
383int nvgpu_clk_arb_get_arbiter_clk_f_points(struct gk20a *g,
384 u32 api_domain, u32 *max_points, u16 *fpoints)
385{
386 return (int)clk_domain_get_f_points(g, api_domain, max_points, fpoints);
387}
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.h b/drivers/gpu/nvgpu/clk/clk_arb.h
new file mode 100644
index 00000000..9981041b
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_arb.h
@@ -0,0 +1,63 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15
16#ifndef _CLK_ARB_H_
17#define _CLK_ARB_H_
18
19struct nvgpu_clk_arb;
20struct nvgpu_clk_session;
21
22int nvgpu_clk_arb_init_arbiter(struct gk20a *g);
23
24int nvgpu_clk_arb_get_arbiter_clk_range(struct gk20a *g, u32 api_domain,
25 u16 *min_mhz, u16 *max_mhz);
26
27int nvgpu_clk_arb_get_arbiter_actual_mhz(struct gk20a *g,
28 u32 api_domain, u16 *actual_mhz);
29
30int nvgpu_clk_arb_get_arbiter_clk_f_points(struct gk20a *g,
31 u32 api_domain, u32 *max_points, u16 *fpoints);
32
33u32 nvgpu_clk_arb_get_arbiter_req_nr(struct gk20a *g);
34
35u32 nvgpu_clk_arb_get_arbiter_clk_domains(struct gk20a *g);
36
37void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g);
38
39int nvgpu_clk_arb_install_session_fd(struct gk20a *g,
40 struct nvgpu_clk_session *session);
41
42int nvgpu_clk_arb_init_session(struct gk20a *g,
43 struct nvgpu_clk_session **_session);
44
45void nvgpu_clk_arb_cleanup_session(struct gk20a *g,
46 struct nvgpu_clk_session *session);
47
48void nvgpu_clk_arb_apply_session_constraints(struct gk20a *g,
49 struct nvgpu_clk_session *session);
50
51int nvgpu_clk_arb_set_session_target_mhz(struct nvgpu_clk_session *session,
52 u32 api_domain, u16 target_mhz);
53
54int nvgpu_clk_arb_get_session_target_mhz(struct nvgpu_clk_session *session,
55 u32 api_domain, u16 *target_mhz);
56
57u32 nvgpu_clk_arb_get_session_req_nr(struct gk20a *g,
58 struct nvgpu_clk_session *session);
59
60
61
62#endif /* _CLK_ARB_H_ */
63
diff --git a/drivers/gpu/nvgpu/gp106/clk_arb_gp106.c b/drivers/gpu/nvgpu/gp106/clk_arb_gp106.c
new file mode 100644
index 00000000..d1cbb32b
--- /dev/null
+++ b/drivers/gpu/nvgpu/gp106/clk_arb_gp106.c
@@ -0,0 +1,95 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15
16#include "clk/clk_arb.h"
17#include "clk_arb_gp106.h"
18
19static u32 gp106_get_arbiter_clk_domains(struct gk20a *g)
20{
21 (void)g;
22 return (CTRL_CLK_DOMAIN_MCLK|CTRL_CLK_DOMAIN_GPC2CLK);
23}
24
25static int gp106_get_arbiter_clk_range(struct gk20a *g, u32 api_domain,
26 u16 *min_mhz, u16 *max_mhz)
27{
28 enum nv_pmu_clk_clkwhich clkwhich;
29 struct clk_set_info *p0_info;
30 struct clk_set_info *p5_info;
31
32 switch (api_domain) {
33 case CTRL_CLK_DOMAIN_MCLK:
34 clkwhich = clkwhich_mclk;
35 break;
36
37 case CTRL_CLK_DOMAIN_GPC2CLK:
38 clkwhich = clkwhich_gpc2clk;
39 break;
40
41 default:
42 return -EINVAL;
43 }
44
45 p5_info = pstate_get_clk_set_info(g,
46 CTRL_PERF_PSTATE_P5, clkwhich);
47 if (!p5_info)
48 return -EINVAL;
49
50 p0_info = pstate_get_clk_set_info(g,
51 CTRL_PERF_PSTATE_P0, clkwhich);
52 if (!p0_info)
53 return -EINVAL;
54
55 *min_mhz = p5_info->min_mhz;
56 *max_mhz = p0_info->max_mhz;
57
58 return 0;
59}
60
61static int gp106_get_arbiter_clk_default(struct gk20a *g, u32 api_domain,
62 u16 *default_mhz)
63{
64 enum nv_pmu_clk_clkwhich clkwhich;
65 struct clk_set_info *p0_info;
66
67 switch (api_domain) {
68 case CTRL_CLK_DOMAIN_MCLK:
69 clkwhich = clkwhich_mclk;
70 break;
71
72 case CTRL_CLK_DOMAIN_GPC2CLK:
73 clkwhich = clkwhich_gpc2clk;
74 break;
75
76 default:
77 return -EINVAL;
78 }
79
80 p0_info = pstate_get_clk_set_info(g,
81 CTRL_PERF_PSTATE_P0, clkwhich);
82 if (!p0_info)
83 return -EINVAL;
84
85 *default_mhz = p0_info->max_mhz;
86
87 return 0;
88}
89
90void gp106_init_clk_arb_ops(struct gpu_ops *gops)
91{
92 gops->clk_arb.get_arbiter_clk_domains = gp106_get_arbiter_clk_domains;
93 gops->clk_arb.get_arbiter_clk_range = gp106_get_arbiter_clk_range;
94 gops->clk_arb.get_arbiter_clk_default = gp106_get_arbiter_clk_default;
95}
diff --git a/drivers/gpu/nvgpu/gp106/clk_arb_gp106.h b/drivers/gpu/nvgpu/gp106/clk_arb_gp106.h
new file mode 100644
index 00000000..a9877199
--- /dev/null
+++ b/drivers/gpu/nvgpu/gp106/clk_arb_gp106.h
@@ -0,0 +1,21 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#ifndef CLK_ARB_GP106_H
17#define CLK_ARB_GP106_H
18
19void gp106_init_clk_arb_ops(struct gpu_ops *gops);
20
21#endif /* CLK_ARB_GP106_H */
diff --git a/drivers/gpu/nvgpu/gp106/clk_gp106.c b/drivers/gpu/nvgpu/gp106/clk_gp106.c
index 39c308a3..85dde69f 100644
--- a/drivers/gpu/nvgpu/gp106/clk_gp106.c
+++ b/drivers/gpu/nvgpu/gp106/clk_gp106.c
@@ -27,6 +27,7 @@
27#include "gk20a/gk20a.h" 27#include "gk20a/gk20a.h"
28#include "hw_trim_gp106.h" 28#include "hw_trim_gp106.h"
29#include "clk_gp106.h" 29#include "clk_gp106.h"
30#include "clk/clk_arb.h"
30 31
31#define gk20a_dbg_clk(fmt, arg...) \ 32#define gk20a_dbg_clk(fmt, arg...) \
32 gk20a_dbg(gpu_dbg_clk, fmt, ##arg) 33 gk20a_dbg(gpu_dbg_clk, fmt, ##arg)
diff --git a/drivers/gpu/nvgpu/gp106/hal_gp106.c b/drivers/gpu/nvgpu/gp106/hal_gp106.c
index 0f926be8..dc27cdae 100644
--- a/drivers/gpu/nvgpu/gp106/hal_gp106.c
+++ b/drivers/gpu/nvgpu/gp106/hal_gp106.c
@@ -37,6 +37,7 @@
37#include "gm20b/fifo_gm20b.h" 37#include "gm20b/fifo_gm20b.h"
38#include "gm20b/pmu_gm20b.h" 38#include "gm20b/pmu_gm20b.h"
39#include "gp106/clk_gp106.h" 39#include "gp106/clk_gp106.h"
40#include "gp106/clk_arb_gp106.h"
40 41
41#include "gp106/mm_gp106.h" 42#include "gp106/mm_gp106.h"
42#include "gp106/pmu_gp106.h" 43#include "gp106/pmu_gp106.h"
@@ -210,6 +211,7 @@ int gp106_init_hal(struct gk20a *g)
210 gk20a_init_debug_ops(gops); 211 gk20a_init_debug_ops(gops);
211 gk20a_init_dbg_session_ops(gops); 212 gk20a_init_dbg_session_ops(gops);
212 gp106_init_clk_ops(gops); 213 gp106_init_clk_ops(gops);
214 gp106_init_clk_arb_ops(gops);
213 gp106_init_regops(gops); 215 gp106_init_regops(gops);
214 gp10b_init_cde_ops(gops); 216 gp10b_init_cde_ops(gops);
215 gk20a_init_tsg_ops(gops); 217 gk20a_init_tsg_ops(gops);
diff --git a/drivers/gpu/nvgpu/pstate/pstate.c b/drivers/gpu/nvgpu/pstate/pstate.c
index e9b9775e..0dc15201 100644
--- a/drivers/gpu/nvgpu/pstate/pstate.c
+++ b/drivers/gpu/nvgpu/pstate/pstate.c
@@ -234,7 +234,7 @@ static int parse_pstate_entry_5x(struct gk20a *g,
234 memset(pstate, 0, sizeof(struct pstate)); 234 memset(pstate, 0, sizeof(struct pstate));
235 pstate->super.type = CTRL_PERF_PSTATE_TYPE_3X; 235 pstate->super.type = CTRL_PERF_PSTATE_TYPE_3X;
236 pstate->num = 0x0F - entry->pstate_level; 236 pstate->num = 0x0F - entry->pstate_level;
237 pstate->clklist.clksetinfolistsize = hdr->clock_entry_count; 237 pstate->clklist.num_info = hdr->clock_entry_count;
238 238
239 gk20a_dbg_info("pstate P%u", pstate->num); 239 gk20a_dbg_info("pstate P%u", pstate->num);
240 240
@@ -357,3 +357,41 @@ static int pstate_sw_setup(struct gk20a *g)
357done: 357done:
358 return err; 358 return err;
359} 359}
360
361static struct pstate *pstate_find(struct gk20a *g, u32 num)
362{
363 struct pstates *pstates = &(g->perf_pmu.pstatesobjs);
364 struct pstate *pstate;
365 u8 i;
366
367 gk20a_dbg_info("pstates = %p", pstates);
368
369 BOARDOBJGRP_FOR_EACH(&pstates->super.super,
370 struct pstate *, pstate, i) {
371 gk20a_dbg_info("pstate=%p num=%u (looking for num=%u)",
372 pstate, pstate->num, num);
373 if (pstate->num == num)
374 return pstate;
375 }
376 return NULL;
377}
378
379struct clk_set_info *pstate_get_clk_set_info(struct gk20a *g,
380 u32 pstate_num, enum nv_pmu_clk_clkwhich clkwhich)
381{
382 struct pstate *pstate = pstate_find(g, pstate_num);
383 struct clk_set_info *info;
384 u32 clkidx;
385
386 gk20a_dbg_info("pstate = %p", pstate);
387
388 if (!pstate)
389 return NULL;
390
391 for (clkidx = 0; clkidx < pstate->clklist.num_info; clkidx++) {
392 info = &pstate->clklist.clksetinfo[clkidx];
393 if (info->clkwhich == clkwhich)
394 return info;
395 }
396 return NULL;
397}
diff --git a/drivers/gpu/nvgpu/pstate/pstate.h b/drivers/gpu/nvgpu/pstate/pstate.h
index 11fa4c77..4ae72aa9 100644
--- a/drivers/gpu/nvgpu/pstate/pstate.h
+++ b/drivers/gpu/nvgpu/pstate/pstate.h
@@ -20,6 +20,10 @@
20 20
21#define CTRL_PERF_PSTATE_TYPE_3X 0x3 21#define CTRL_PERF_PSTATE_TYPE_3X 0x3
22 22
23#define CTRL_PERF_PSTATE_P0 0
24#define CTRL_PERF_PSTATE_P5 5
25#define CTRL_PERF_PSTATE_P8 8
26
23#define CLK_SET_INFO_MAX_SIZE (32) 27#define CLK_SET_INFO_MAX_SIZE (32)
24 28
25struct clk_set_info { 29struct clk_set_info {
@@ -30,7 +34,7 @@ struct clk_set_info {
30}; 34};
31 35
32struct clk_set_info_list { 36struct clk_set_info_list {
33 u32 clksetinfolistsize; 37 u32 num_info;
34 struct clk_set_info clksetinfo[CLK_SET_INFO_MAX_SIZE]; 38 struct clk_set_info clksetinfo[CLK_SET_INFO_MAX_SIZE];
35}; 39};
36 40
@@ -48,4 +52,7 @@ struct pstates {
48int gk20a_init_pstate_support(struct gk20a *g); 52int gk20a_init_pstate_support(struct gk20a *g);
49int gk20a_init_pstate_pmu_support(struct gk20a *g); 53int gk20a_init_pstate_pmu_support(struct gk20a *g);
50 54
55struct clk_set_info *pstate_get_clk_set_info(struct gk20a *g, u32 pstate_num,
56 enum nv_pmu_clk_clkwhich clkwhich);
57
51#endif /* __PSTATE_H__ */ 58#endif /* __PSTATE_H__ */