summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/nvgpu_common.c
diff options
context:
space:
mode:
authorAlex Waterman <alexw@nvidia.com>2017-01-12 21:18:49 -0500
committerVarun Colbert <vcolbert@nvidia.com>2017-02-13 21:14:34 -0500
commitb9194a1c3300e505d22fba97136dd305300397f0 (patch)
treec9c5366fb8dbca742200e2c8f85650ef8cc46859 /drivers/gpu/nvgpu/common/nvgpu_common.c
parented35f0a4042074463bf52ba04583fde680d1d389 (diff)
gpu: nvgpu: Organize nvgpu_common.[ch]
Move nvgpu_common.c to drivers/gpu/nvgpu/common since it is a common C file to all drivers. Similarly move nvgpu_common.h to drivers/gpu/nvgpu/include/nvgpu since this follows the new include guidelines. Bug 1799159 Change-Id: I00ebed289973b27704c2cff073526e36505bf699 Signed-off-by: Alex Waterman <alexw@nvidia.com> Reviewed-on: http://git-master/r/1284612 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/common/nvgpu_common.c')
-rw-r--r--drivers/gpu/nvgpu/common/nvgpu_common.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/nvgpu_common.c b/drivers/gpu/nvgpu/common/nvgpu_common.c
new file mode 100644
index 00000000..80f1cca0
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/nvgpu_common.c
@@ -0,0 +1,277 @@
1/*
2 * Copyright (c) 2016-2017, 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
17#include <linux/dma-mapping.h>
18#include <linux/firmware.h>
19
20#include "gk20a/gk20a_scale.h"
21#include "gk20a/gk20a.h"
22
23#include <nvgpu/nvgpu_common.h>
24
25#define EMC3D_DEFAULT_RATIO 750
26
27static void nvgpu_init_vars(struct gk20a *g)
28{
29 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
30
31 init_waitqueue_head(&g->sw_irq_stall_last_handled_wq);
32 init_waitqueue_head(&g->sw_irq_nonstall_last_handled_wq);
33 gk20a_init_gr(g);
34
35 init_rwsem(&g->busy_lock);
36
37 spin_lock_init(&g->mc_enable_lock);
38
39 mutex_init(&platform->railgate_lock);
40 mutex_init(&g->dbg_sessions_lock);
41 mutex_init(&g->client_lock);
42 mutex_init(&g->ch_wdt_lock);
43 mutex_init(&g->poweroff_lock);
44
45 g->regs_saved = g->regs;
46 g->bar1_saved = g->bar1;
47
48 g->emc3d_ratio = EMC3D_DEFAULT_RATIO;
49
50 /* Set DMA parameters to allow larger sgt lists */
51 g->dev->dma_parms = &g->dma_parms;
52 dma_set_max_seg_size(g->dev, UINT_MAX);
53
54 INIT_LIST_HEAD(&g->pending_sema_waits);
55 raw_spin_lock_init(&g->pending_sema_waits_lock);
56}
57
58static void nvgpu_init_timeout(struct gk20a *g)
59{
60 g->gr_idle_timeout_default = CONFIG_GK20A_DEFAULT_TIMEOUT;
61 if (tegra_platform_is_silicon())
62 g->timeouts_enabled = true;
63}
64
65static void nvgpu_init_timeslice(struct gk20a *g)
66{
67 g->runlist_interleave = true;
68
69 g->timeslice_low_priority_us = 1300;
70 g->timeslice_medium_priority_us = 2600;
71 g->timeslice_high_priority_us = 5200;
72
73 g->min_timeslice_us = 1000;
74 g->max_timeslice_us = 50000;
75}
76
77static void nvgpu_init_pm_vars(struct gk20a *g)
78{
79 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
80
81 /*
82 * Set up initial power settings. For non-slicon platforms, disable
83 * power features and for silicon platforms, read from platform data
84 */
85 g->slcg_enabled =
86 tegra_platform_is_silicon() ? platform->enable_slcg : false;
87 g->blcg_enabled =
88 tegra_platform_is_silicon() ? platform->enable_blcg : false;
89 g->elcg_enabled =
90 tegra_platform_is_silicon() ? platform->enable_elcg : false;
91 g->elpg_enabled =
92 tegra_platform_is_silicon() ? platform->enable_elpg : false;
93 g->aelpg_enabled =
94 tegra_platform_is_silicon() ? platform->enable_aelpg : false;
95 g->mscg_enabled =
96 tegra_platform_is_silicon() ? platform->enable_mscg : false;
97
98 /* set default values to aelpg parameters */
99 g->pmu.aelpg_param[0] = APCTRL_SAMPLING_PERIOD_PG_DEFAULT_US;
100 g->pmu.aelpg_param[1] = APCTRL_MINIMUM_IDLE_FILTER_DEFAULT_US;
101 g->pmu.aelpg_param[2] = APCTRL_MINIMUM_TARGET_SAVING_DEFAULT_US;
102 g->pmu.aelpg_param[3] = APCTRL_POWER_BREAKEVEN_DEFAULT_US;
103 g->pmu.aelpg_param[4] = APCTRL_CYCLES_PER_SAMPLE_MAX_DEFAULT;
104}
105
106static void nvgpu_init_mm_vars(struct gk20a *g)
107{
108 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
109
110 g->mm.bypass_smmu = platform->bypass_smmu;
111 g->mm.disable_bigpage = platform->disable_bigpage;
112 g->mm.vidmem_is_vidmem = platform->vidmem_is_vidmem;
113}
114
115int nvgpu_probe(struct gk20a *g,
116 const char *debugfs_symlink,
117 const char *interface_name,
118 struct class *class)
119{
120 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
121 int err = 0;
122
123 nvgpu_init_vars(g);
124 nvgpu_init_timeout(g);
125 nvgpu_init_timeslice(g);
126 nvgpu_init_pm_vars(g);
127
128 /* Initialize the platform interface. */
129 err = platform->probe(g->dev);
130 if (err) {
131 dev_err(g->dev, "platform probe failed");
132 return err;
133 }
134
135 /* platform probe can defer do user init only if probe succeeds */
136 err = gk20a_user_init(g->dev, interface_name, class);
137 if (err)
138 return err;
139
140
141 /* Initialise scaling */
142 if (IS_ENABLED(CONFIG_GK20A_DEVFREQ))
143 gk20a_scale_init(g->dev);
144
145 err = gk20a_secure_page_alloc(g->dev);
146 if (err)
147 dev_err(g->dev,
148 "failed to allocate secure buffer %d\n", err);
149
150 if (platform->late_probe) {
151 err = platform->late_probe(g->dev);
152 if (err) {
153 dev_err(g->dev, "late probe failed");
154 return err;
155 }
156 }
157
158 nvgpu_init_mm_vars(g);
159
160 gk20a_create_sysfs(g->dev);
161 gk20a_debug_init(g->dev, debugfs_symlink);
162
163 g->dbg_regops_tmp_buf = kzalloc(SZ_4K, GFP_KERNEL);
164 if (!g->dbg_regops_tmp_buf) {
165 dev_err(g->dev, "couldn't allocate regops tmp buf");
166 return -ENOMEM;
167 }
168 g->dbg_regops_tmp_buf_ops =
169 SZ_4K / sizeof(g->dbg_regops_tmp_buf[0]);
170
171 g->remove_support = gk20a_remove_support;
172
173 return 0;
174}
175
176static const struct firmware *do_request_firmware(struct device *dev,
177 const char *prefix, const char *fw_name, int flags)
178{
179 const struct firmware *fw;
180 char *fw_path = NULL;
181 int path_len, err;
182
183 if (prefix) {
184 path_len = strlen(prefix) + strlen(fw_name);
185 path_len += 2; /* for the path separator and zero terminator*/
186
187 fw_path = kzalloc(sizeof(*fw_path) * path_len, GFP_KERNEL);
188 if (!fw_path)
189 return NULL;
190
191 sprintf(fw_path, "%s/%s", prefix, fw_name);
192 fw_name = fw_path;
193 }
194
195#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
196 err = request_firmware(&fw, fw_name, dev);
197#else
198 if (flags & NVGPU_REQUEST_FIRMWARE_NO_WARN)
199 err = request_firmware_direct(&fw, fw_name, dev);
200 else
201 err = request_firmware(&fw, fw_name, dev);
202#endif
203
204 kfree(fw_path);
205 if (err)
206 return NULL;
207 return fw;
208}
209
210/* This is a simple wrapper around request_firmware that takes 'fw_name' and
211 * applies an IP specific relative path prefix to it. The caller is
212 * responsible for calling release_firmware later. */
213const struct firmware *nvgpu_request_firmware(struct gk20a *g,
214 const char *fw_name,
215 int flags)
216{
217 struct device *dev = g->dev;
218 const struct firmware *fw;
219
220 /* current->fs is NULL when calling from SYS_EXIT.
221 Add a check here to prevent crash in request_firmware */
222 if (!current->fs || !fw_name)
223 return NULL;
224
225 BUG_ON(!g->ops.name);
226 fw = do_request_firmware(dev, g->ops.name, fw_name, flags);
227
228#ifdef CONFIG_TEGRA_GK20A
229 /* TO BE REMOVED - Support loading from legacy SOC specific path. */
230 if (!fw && !(flags & NVGPU_REQUEST_FIRMWARE_NO_SOC)) {
231 struct gk20a_platform *platform = gk20a_get_platform(dev);
232 fw = do_request_firmware(dev,
233 platform->soc_name, fw_name, flags);
234 }
235#endif
236
237 return fw;
238}
239
240/**
241 * cyclic_delta - Returns delta of cyclic integers a and b.
242 *
243 * @a - First integer
244 * @b - Second integer
245 *
246 * Note: if a is ahead of b, delta is positive.
247 */
248static int cyclic_delta(int a, int b)
249{
250 return a - b;
251}
252
253/**
254 * nvgpu_wait_for_deferred_interrupts - Wait for interrupts to complete
255 *
256 * @g - The GPU to wait on.
257 *
258 * Waits until all interrupt handlers that have been scheduled to run have
259 * completed.
260 */
261void nvgpu_wait_for_deferred_interrupts(struct gk20a *g)
262{
263 int stall_irq_threshold = atomic_read(&g->hw_irq_stall_count);
264 int nonstall_irq_threshold = atomic_read(&g->hw_irq_nonstall_count);
265
266 /* wait until all stalling irqs are handled */
267 wait_event(g->sw_irq_stall_last_handled_wq,
268 cyclic_delta(stall_irq_threshold,
269 atomic_read(&g->sw_irq_stall_last_handled))
270 <= 0);
271
272 /* wait until all non-stalling irqs are handled */
273 wait_event(g->sw_irq_nonstall_last_handled_wq,
274 cyclic_delta(nonstall_irq_threshold,
275 atomic_read(&g->sw_irq_nonstall_last_handled))
276 <= 0);
277}