diff options
Diffstat (limited to 'drivers/gpu/nvgpu/common')
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/driver_common.c (renamed from drivers/gpu/nvgpu/common/nvgpu_common.c) | 16 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/module.c | 1052 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/module.h | 22 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/pci.c | 511 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/pci.h | 27 |
5 files changed, 1627 insertions, 1 deletions
diff --git a/drivers/gpu/nvgpu/common/nvgpu_common.c b/drivers/gpu/nvgpu/common/linux/driver_common.c index 0c812d34..5c96b4e8 100644 --- a/drivers/gpu/nvgpu/common/nvgpu_common.c +++ b/drivers/gpu/nvgpu/common/linux/driver_common.c | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | #include "gk20a/gk20a_scale.h" | 25 | #include "gk20a/gk20a_scale.h" |
26 | #include "gk20a/gk20a.h" | 26 | #include "gk20a/gk20a.h" |
27 | #include "gk20a/gr_gk20a.h" | 27 | #include "module.h" |
28 | 28 | ||
29 | #define EMC3D_DEFAULT_RATIO 750 | 29 | #define EMC3D_DEFAULT_RATIO 750 |
30 | 30 | ||
@@ -124,6 +124,20 @@ static void nvgpu_init_mm_vars(struct gk20a *g) | |||
124 | nvgpu_mutex_init(&g->mm.priv_lock); | 124 | nvgpu_mutex_init(&g->mm.priv_lock); |
125 | } | 125 | } |
126 | 126 | ||
127 | static int gk20a_secure_page_alloc(struct device *dev) | ||
128 | { | ||
129 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
130 | int err = 0; | ||
131 | |||
132 | if (platform->secure_page_alloc) { | ||
133 | err = platform->secure_page_alloc(dev); | ||
134 | if (!err) | ||
135 | platform->secure_alloc_ready = true; | ||
136 | } | ||
137 | |||
138 | return err; | ||
139 | } | ||
140 | |||
127 | int nvgpu_probe(struct gk20a *g, | 141 | int nvgpu_probe(struct gk20a *g, |
128 | const char *debugfs_symlink, | 142 | const char *debugfs_symlink, |
129 | const char *interface_name, | 143 | const char *interface_name, |
diff --git a/drivers/gpu/nvgpu/common/linux/module.c b/drivers/gpu/nvgpu/common/linux/module.c new file mode 100644 index 00000000..2cbf996b --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/module.c | |||
@@ -0,0 +1,1052 @@ | |||
1 | /* | ||
2 | * GK20A Graphics | ||
3 | * | ||
4 | * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/of_device.h> | ||
22 | #include <linux/of_platform.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/pm_runtime.h> | ||
25 | #include <linux/reset.h> | ||
26 | #include <linux/platform/tegra/common.h> | ||
27 | |||
28 | #include <nvgpu/kmem.h> | ||
29 | #include <nvgpu/nvgpu_common.h> | ||
30 | #include <nvgpu/soc.h> | ||
31 | |||
32 | #include "gk20a/gk20a.h" | ||
33 | #include "vgpu/vgpu.h" | ||
34 | #include "gk20a/gk20a_scale.h" | ||
35 | #include "gk20a/ctxsw_trace_gk20a.h" | ||
36 | #include "pci.h" | ||
37 | #include "module.h" | ||
38 | #ifdef CONFIG_TEGRA_19x_GPU | ||
39 | #include "nvgpu_gpuid_t19x.h" | ||
40 | #endif | ||
41 | |||
42 | #define CLASS_NAME "nvidia-gpu" | ||
43 | /* TODO: Change to e.g. "nvidia-gpu%s" once we have symlinks in place. */ | ||
44 | |||
45 | #define GK20A_WAIT_FOR_IDLE_MS 2000 | ||
46 | |||
47 | #define CREATE_TRACE_POINTS | ||
48 | #include <trace/events/gk20a.h> | ||
49 | |||
50 | void gk20a_busy_noresume(struct device *dev) | ||
51 | { | ||
52 | pm_runtime_get_noresume(dev); | ||
53 | } | ||
54 | |||
55 | int gk20a_busy(struct gk20a *g) | ||
56 | { | ||
57 | int ret = 0; | ||
58 | struct device *dev; | ||
59 | |||
60 | if (!g) | ||
61 | return -ENODEV; | ||
62 | |||
63 | atomic_inc(&g->usage_count); | ||
64 | |||
65 | down_read(&g->busy_lock); | ||
66 | |||
67 | if (!gk20a_can_busy(g)) { | ||
68 | ret = -ENODEV; | ||
69 | atomic_dec(&g->usage_count); | ||
70 | goto fail; | ||
71 | } | ||
72 | |||
73 | dev = g->dev; | ||
74 | |||
75 | if (pm_runtime_enabled(dev)) { | ||
76 | ret = pm_runtime_get_sync(dev); | ||
77 | if (ret < 0) { | ||
78 | pm_runtime_put_noidle(dev); | ||
79 | atomic_dec(&g->usage_count); | ||
80 | goto fail; | ||
81 | } | ||
82 | } else { | ||
83 | if (!g->power_on) { | ||
84 | ret = gk20a_gpu_is_virtual(dev) ? | ||
85 | vgpu_pm_finalize_poweron(dev) | ||
86 | : gk20a_pm_finalize_poweron(dev); | ||
87 | if (ret) { | ||
88 | atomic_dec(&g->usage_count); | ||
89 | goto fail; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | gk20a_scale_notify_busy(dev); | ||
95 | |||
96 | fail: | ||
97 | up_read(&g->busy_lock); | ||
98 | |||
99 | return ret < 0 ? ret : 0; | ||
100 | } | ||
101 | |||
102 | void gk20a_idle_nosuspend(struct device *dev) | ||
103 | { | ||
104 | pm_runtime_put_noidle(dev); | ||
105 | } | ||
106 | |||
107 | void gk20a_idle(struct gk20a *g) | ||
108 | { | ||
109 | struct device *dev; | ||
110 | |||
111 | atomic_dec(&g->usage_count); | ||
112 | down_read(&g->busy_lock); | ||
113 | |||
114 | dev = g->dev; | ||
115 | |||
116 | if (!(dev && gk20a_can_busy(g))) | ||
117 | goto fail; | ||
118 | |||
119 | if (pm_runtime_enabled(dev)) { | ||
120 | #ifdef CONFIG_PM | ||
121 | if (atomic_read(&g->dev->power.usage_count) == 1) | ||
122 | gk20a_scale_notify_idle(dev); | ||
123 | #endif | ||
124 | |||
125 | pm_runtime_mark_last_busy(dev); | ||
126 | pm_runtime_put_sync_autosuspend(dev); | ||
127 | |||
128 | } else { | ||
129 | gk20a_scale_notify_idle(dev); | ||
130 | } | ||
131 | fail: | ||
132 | up_read(&g->busy_lock); | ||
133 | } | ||
134 | |||
135 | int gk20a_pm_finalize_poweron(struct device *dev) | ||
136 | { | ||
137 | struct gk20a *g = get_gk20a(dev); | ||
138 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
139 | int err, nice_value; | ||
140 | |||
141 | gk20a_dbg_fn(""); | ||
142 | |||
143 | if (g->power_on) | ||
144 | return 0; | ||
145 | |||
146 | trace_gk20a_finalize_poweron(dev_name(dev)); | ||
147 | |||
148 | /* Increment platform power refcount */ | ||
149 | if (platform->busy) { | ||
150 | err = platform->busy(dev); | ||
151 | if (err < 0) { | ||
152 | nvgpu_err(g, "failed to poweron platform dependency"); | ||
153 | return err; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | err = gk20a_restore_registers(g); | ||
158 | if (err) | ||
159 | return err; | ||
160 | |||
161 | nice_value = task_nice(current); | ||
162 | set_user_nice(current, -20); | ||
163 | |||
164 | err = gk20a_finalize_poweron(g); | ||
165 | set_user_nice(current, nice_value); | ||
166 | if (err) | ||
167 | goto done; | ||
168 | |||
169 | trace_gk20a_finalize_poweron_done(dev_name(dev)); | ||
170 | |||
171 | enable_irq(g->irq_stall); | ||
172 | if (g->irq_stall != g->irq_nonstall) | ||
173 | enable_irq(g->irq_nonstall); | ||
174 | g->irqs_enabled = 1; | ||
175 | |||
176 | gk20a_scale_resume(g->dev); | ||
177 | |||
178 | if (platform->has_cde) | ||
179 | gk20a_init_cde_support(g); | ||
180 | |||
181 | done: | ||
182 | if (err) | ||
183 | g->power_on = false; | ||
184 | |||
185 | return err; | ||
186 | } | ||
187 | |||
188 | static int gk20a_pm_prepare_poweroff(struct device *dev) | ||
189 | { | ||
190 | struct gk20a *g = get_gk20a(dev); | ||
191 | int ret = 0; | ||
192 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
193 | |||
194 | gk20a_dbg_fn(""); | ||
195 | |||
196 | nvgpu_mutex_acquire(&g->poweroff_lock); | ||
197 | |||
198 | if (!g->power_on) | ||
199 | goto done; | ||
200 | |||
201 | gk20a_scale_suspend(dev); | ||
202 | |||
203 | ret = gk20a_prepare_poweroff(g); | ||
204 | if (ret) | ||
205 | goto error; | ||
206 | |||
207 | /* | ||
208 | * After this point, gk20a interrupts should not get | ||
209 | * serviced. | ||
210 | */ | ||
211 | disable_irq(g->irq_stall); | ||
212 | if (g->irq_stall != g->irq_nonstall) | ||
213 | disable_irq(g->irq_nonstall); | ||
214 | |||
215 | /* | ||
216 | * is_fmodel needs to be in gk20a struct for deferred teardown | ||
217 | */ | ||
218 | g->is_fmodel = platform->is_fmodel; | ||
219 | |||
220 | /* Decrement platform power refcount */ | ||
221 | if (platform->idle) | ||
222 | platform->idle(dev); | ||
223 | |||
224 | /* Stop CPU from accessing the GPU registers. */ | ||
225 | gk20a_lockout_registers(g); | ||
226 | |||
227 | nvgpu_mutex_release(&g->poweroff_lock); | ||
228 | return 0; | ||
229 | |||
230 | error: | ||
231 | gk20a_scale_resume(dev); | ||
232 | done: | ||
233 | nvgpu_mutex_release(&g->poweroff_lock); | ||
234 | |||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | static struct of_device_id tegra_gk20a_of_match[] = { | ||
239 | #ifdef CONFIG_TEGRA_GK20A | ||
240 | { .compatible = "nvidia,tegra124-gk20a", | ||
241 | .data = &gk20a_tegra_platform }, | ||
242 | { .compatible = "nvidia,tegra210-gm20b", | ||
243 | .data = &gm20b_tegra_platform }, | ||
244 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | ||
245 | { .compatible = "nvidia,tegra186-gp10b", | ||
246 | .data = &gp10b_tegra_platform }, | ||
247 | #endif | ||
248 | #ifdef CONFIG_TEGRA_19x_GPU | ||
249 | { .compatible = TEGRA_19x_GPU_COMPAT_TEGRA, | ||
250 | .data = &t19x_gpu_tegra_platform }, | ||
251 | #endif | ||
252 | #ifdef CONFIG_TEGRA_GR_VIRTUALIZATION | ||
253 | { .compatible = "nvidia,tegra124-gk20a-vgpu", | ||
254 | .data = &vgpu_tegra_platform }, | ||
255 | #endif | ||
256 | #else | ||
257 | { .compatible = "nvidia,tegra124-gk20a", | ||
258 | .data = &gk20a_generic_platform }, | ||
259 | { .compatible = "nvidia,tegra210-gm20b", | ||
260 | .data = &gk20a_generic_platform }, | ||
261 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | ||
262 | { .compatible = TEGRA_18x_GPU_COMPAT_TEGRA, | ||
263 | .data = &gk20a_generic_platform }, | ||
264 | #endif | ||
265 | |||
266 | #endif | ||
267 | { .compatible = "nvidia,generic-gk20a", | ||
268 | .data = &gk20a_generic_platform }, | ||
269 | { .compatible = "nvidia,generic-gm20b", | ||
270 | .data = &gk20a_generic_platform }, | ||
271 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | ||
272 | { .compatible = "nvidia,generic-gp10b", | ||
273 | .data = &gk20a_generic_platform }, | ||
274 | #endif | ||
275 | { }, | ||
276 | }; | ||
277 | |||
278 | #ifdef CONFIG_PM | ||
279 | /** | ||
280 | * __gk20a_do_idle() - force the GPU to idle and railgate | ||
281 | * | ||
282 | * In success, this call MUST be balanced by caller with __gk20a_do_unidle() | ||
283 | * | ||
284 | * Acquires two locks : &g->busy_lock and &platform->railgate_lock | ||
285 | * In success, we hold these locks and return | ||
286 | * In failure, we release these locks and return | ||
287 | */ | ||
288 | int __gk20a_do_idle(struct device *dev, bool force_reset) | ||
289 | { | ||
290 | struct gk20a *g = get_gk20a(dev); | ||
291 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
292 | struct nvgpu_timeout timeout; | ||
293 | int ref_cnt; | ||
294 | int target_ref_cnt = 0; | ||
295 | bool is_railgated; | ||
296 | int err = 0; | ||
297 | |||
298 | /* acquire busy lock to block other busy() calls */ | ||
299 | down_write(&g->busy_lock); | ||
300 | |||
301 | /* acquire railgate lock to prevent unrailgate in midst of do_idle() */ | ||
302 | nvgpu_mutex_acquire(&platform->railgate_lock); | ||
303 | |||
304 | /* check if it is already railgated ? */ | ||
305 | if (platform->is_railgated(dev)) | ||
306 | return 0; | ||
307 | |||
308 | /* | ||
309 | * release railgate_lock, prevent suspend by incrementing usage counter, | ||
310 | * re-acquire railgate_lock | ||
311 | */ | ||
312 | nvgpu_mutex_release(&platform->railgate_lock); | ||
313 | pm_runtime_get_sync(dev); | ||
314 | |||
315 | /* | ||
316 | * One refcount taken in this API | ||
317 | * If User disables rail gating, we take one more | ||
318 | * extra refcount | ||
319 | */ | ||
320 | if (platform->user_railgate_disabled) | ||
321 | target_ref_cnt = 2; | ||
322 | else | ||
323 | target_ref_cnt = 1; | ||
324 | nvgpu_mutex_acquire(&platform->railgate_lock); | ||
325 | |||
326 | nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS, | ||
327 | NVGPU_TIMER_CPU_TIMER); | ||
328 | |||
329 | /* check and wait until GPU is idle (with a timeout) */ | ||
330 | do { | ||
331 | nvgpu_msleep(1); | ||
332 | ref_cnt = atomic_read(&dev->power.usage_count); | ||
333 | } while (ref_cnt != target_ref_cnt && !nvgpu_timeout_expired(&timeout)); | ||
334 | |||
335 | if (ref_cnt != target_ref_cnt) { | ||
336 | nvgpu_err(g, "failed to idle - refcount %d != 1", | ||
337 | ref_cnt); | ||
338 | goto fail_drop_usage_count; | ||
339 | } | ||
340 | |||
341 | /* check if global force_reset flag is set */ | ||
342 | force_reset |= platform->force_reset_in_do_idle; | ||
343 | |||
344 | nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS, | ||
345 | NVGPU_TIMER_CPU_TIMER); | ||
346 | |||
347 | if (platform->can_railgate && !force_reset) { | ||
348 | /* | ||
349 | * Case 1 : GPU railgate is supported | ||
350 | * | ||
351 | * if GPU is now idle, we will have only one ref count, | ||
352 | * drop this ref which will rail gate the GPU | ||
353 | */ | ||
354 | pm_runtime_put_sync(dev); | ||
355 | |||
356 | /* add sufficient delay to allow GPU to rail gate */ | ||
357 | nvgpu_msleep(platform->railgate_delay); | ||
358 | |||
359 | /* check in loop if GPU is railgated or not */ | ||
360 | do { | ||
361 | nvgpu_msleep(1); | ||
362 | is_railgated = platform->is_railgated(dev); | ||
363 | } while (!is_railgated && !nvgpu_timeout_expired(&timeout)); | ||
364 | |||
365 | if (is_railgated) { | ||
366 | return 0; | ||
367 | } else { | ||
368 | nvgpu_err(g, "failed to idle in timeout"); | ||
369 | goto fail_timeout; | ||
370 | } | ||
371 | } else { | ||
372 | /* | ||
373 | * Case 2 : GPU railgate is not supported or we explicitly | ||
374 | * do not want to depend on runtime PM | ||
375 | * | ||
376 | * if GPU is now idle, call prepare_poweroff() to save the | ||
377 | * state and then do explicit railgate | ||
378 | * | ||
379 | * __gk20a_do_unidle() needs to unrailgate, call | ||
380 | * finalize_poweron(), and then call pm_runtime_put_sync() | ||
381 | * to balance the GPU usage counter | ||
382 | */ | ||
383 | |||
384 | /* Save the GPU state */ | ||
385 | err = gk20a_pm_prepare_poweroff(dev); | ||
386 | if (err) | ||
387 | goto fail_drop_usage_count; | ||
388 | |||
389 | /* railgate GPU */ | ||
390 | platform->railgate(dev); | ||
391 | |||
392 | nvgpu_udelay(10); | ||
393 | |||
394 | g->forced_reset = true; | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | fail_drop_usage_count: | ||
399 | pm_runtime_put_noidle(dev); | ||
400 | fail_timeout: | ||
401 | nvgpu_mutex_release(&platform->railgate_lock); | ||
402 | up_write(&g->busy_lock); | ||
403 | return -EBUSY; | ||
404 | } | ||
405 | |||
406 | /** | ||
407 | * gk20a_do_idle() - wrap up for __gk20a_do_idle() to be called | ||
408 | * from outside of GPU driver | ||
409 | * | ||
410 | * In success, this call MUST be balanced by caller with gk20a_do_unidle() | ||
411 | */ | ||
412 | int gk20a_do_idle(void) | ||
413 | { | ||
414 | struct device_node *node = | ||
415 | of_find_matching_node(NULL, tegra_gk20a_of_match); | ||
416 | struct platform_device *pdev = of_find_device_by_node(node); | ||
417 | |||
418 | int ret = __gk20a_do_idle(&pdev->dev, true); | ||
419 | |||
420 | of_node_put(node); | ||
421 | |||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | /** | ||
426 | * __gk20a_do_unidle() - unblock all the tasks blocked by __gk20a_do_idle() | ||
427 | */ | ||
428 | int __gk20a_do_unidle(struct device *dev) | ||
429 | { | ||
430 | struct gk20a *g = get_gk20a(dev); | ||
431 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
432 | int err; | ||
433 | |||
434 | if (g->forced_reset) { | ||
435 | /* | ||
436 | * If we did a forced-reset/railgate | ||
437 | * then unrailgate the GPU here first | ||
438 | */ | ||
439 | platform->unrailgate(dev); | ||
440 | |||
441 | /* restore the GPU state */ | ||
442 | err = gk20a_pm_finalize_poweron(dev); | ||
443 | if (err) | ||
444 | return err; | ||
445 | |||
446 | /* balance GPU usage counter */ | ||
447 | pm_runtime_put_sync(dev); | ||
448 | |||
449 | g->forced_reset = false; | ||
450 | } | ||
451 | |||
452 | /* release the lock and open up all other busy() calls */ | ||
453 | nvgpu_mutex_release(&platform->railgate_lock); | ||
454 | up_write(&g->busy_lock); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | /** | ||
460 | * gk20a_do_unidle() - wrap up for __gk20a_do_unidle() | ||
461 | */ | ||
462 | int gk20a_do_unidle(void) | ||
463 | { | ||
464 | struct device_node *node = | ||
465 | of_find_matching_node(NULL, tegra_gk20a_of_match); | ||
466 | struct platform_device *pdev = of_find_device_by_node(node); | ||
467 | |||
468 | int ret = __gk20a_do_unidle(&pdev->dev); | ||
469 | |||
470 | of_node_put(node); | ||
471 | |||
472 | return ret; | ||
473 | } | ||
474 | #endif | ||
475 | |||
476 | static void __iomem *gk20a_ioremap_resource(struct platform_device *dev, int i, | ||
477 | struct resource **out) | ||
478 | { | ||
479 | struct resource *r = platform_get_resource(dev, IORESOURCE_MEM, i); | ||
480 | |||
481 | if (!r) | ||
482 | return NULL; | ||
483 | if (out) | ||
484 | *out = r; | ||
485 | return devm_ioremap_resource(&dev->dev, r); | ||
486 | } | ||
487 | |||
488 | static irqreturn_t gk20a_intr_isr_stall(int irq, void *dev_id) | ||
489 | { | ||
490 | struct gk20a *g = dev_id; | ||
491 | |||
492 | return g->ops.mc.isr_stall(g); | ||
493 | } | ||
494 | |||
495 | static irqreturn_t gk20a_intr_isr_nonstall(int irq, void *dev_id) | ||
496 | { | ||
497 | struct gk20a *g = dev_id; | ||
498 | |||
499 | return g->ops.mc.isr_nonstall(g); | ||
500 | } | ||
501 | |||
502 | static irqreturn_t gk20a_intr_thread_stall(int irq, void *dev_id) | ||
503 | { | ||
504 | struct gk20a *g = dev_id; | ||
505 | |||
506 | return g->ops.mc.isr_thread_stall(g); | ||
507 | } | ||
508 | |||
509 | void gk20a_remove_support(struct gk20a *g) | ||
510 | { | ||
511 | #ifdef CONFIG_TEGRA_COMMON | ||
512 | tegra_unregister_idle_unidle(); | ||
513 | #endif | ||
514 | nvgpu_kfree(g, g->dbg_regops_tmp_buf); | ||
515 | |||
516 | if (g->pmu.remove_support) | ||
517 | g->pmu.remove_support(&g->pmu); | ||
518 | |||
519 | if (g->gr.remove_support) | ||
520 | g->gr.remove_support(&g->gr); | ||
521 | |||
522 | if (g->mm.remove_ce_support) | ||
523 | g->mm.remove_ce_support(&g->mm); | ||
524 | |||
525 | if (g->fifo.remove_support) | ||
526 | g->fifo.remove_support(&g->fifo); | ||
527 | |||
528 | if (g->mm.remove_support) | ||
529 | g->mm.remove_support(&g->mm); | ||
530 | |||
531 | if (g->sim.remove_support) | ||
532 | g->sim.remove_support(&g->sim); | ||
533 | |||
534 | /* free mappings to registers, etc */ | ||
535 | |||
536 | if (g->regs) { | ||
537 | iounmap(g->regs); | ||
538 | g->regs = NULL; | ||
539 | } | ||
540 | if (g->bar1) { | ||
541 | iounmap(g->bar1); | ||
542 | g->bar1 = NULL; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | static int gk20a_init_support(struct platform_device *dev) | ||
547 | { | ||
548 | int err = 0; | ||
549 | struct gk20a *g = get_gk20a(&dev->dev); | ||
550 | |||
551 | #ifdef CONFIG_TEGRA_COMMON | ||
552 | tegra_register_idle_unidle(gk20a_do_idle, gk20a_do_unidle); | ||
553 | #endif | ||
554 | |||
555 | g->regs = gk20a_ioremap_resource(dev, GK20A_BAR0_IORESOURCE_MEM, | ||
556 | &g->reg_mem); | ||
557 | if (IS_ERR(g->regs)) { | ||
558 | nvgpu_err(g, "failed to remap gk20a registers"); | ||
559 | err = PTR_ERR(g->regs); | ||
560 | goto fail; | ||
561 | } | ||
562 | |||
563 | g->bar1 = gk20a_ioremap_resource(dev, GK20A_BAR1_IORESOURCE_MEM, | ||
564 | &g->bar1_mem); | ||
565 | if (IS_ERR(g->bar1)) { | ||
566 | nvgpu_err(g, "failed to remap gk20a bar1"); | ||
567 | err = PTR_ERR(g->bar1); | ||
568 | goto fail; | ||
569 | } | ||
570 | |||
571 | if (nvgpu_platform_is_simulation(g)) { | ||
572 | g->sim.g = g; | ||
573 | g->sim.regs = gk20a_ioremap_resource(dev, | ||
574 | GK20A_SIM_IORESOURCE_MEM, | ||
575 | &g->sim.reg_mem); | ||
576 | if (IS_ERR(g->sim.regs)) { | ||
577 | nvgpu_err(g, "failed to remap gk20a sim regs"); | ||
578 | err = PTR_ERR(g->sim.regs); | ||
579 | goto fail; | ||
580 | } | ||
581 | |||
582 | err = gk20a_init_sim_support(dev); | ||
583 | if (err) | ||
584 | goto fail; | ||
585 | } | ||
586 | |||
587 | return 0; | ||
588 | |||
589 | fail: | ||
590 | return err; | ||
591 | } | ||
592 | |||
593 | static int gk20a_pm_railgate(struct device *dev) | ||
594 | { | ||
595 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
596 | int ret = 0; | ||
597 | #ifdef CONFIG_DEBUG_FS | ||
598 | struct gk20a *g = get_gk20a(dev); | ||
599 | |||
600 | g->pstats.last_rail_gate_start = jiffies; | ||
601 | |||
602 | if (g->pstats.railgating_cycle_count >= 1) | ||
603 | g->pstats.total_rail_ungate_time_ms = | ||
604 | g->pstats.total_rail_ungate_time_ms + | ||
605 | jiffies_to_msecs(g->pstats.last_rail_gate_start - | ||
606 | g->pstats.last_rail_ungate_complete); | ||
607 | #endif | ||
608 | |||
609 | if (platform->railgate) | ||
610 | ret = platform->railgate(dev); | ||
611 | |||
612 | #ifdef CONFIG_DEBUG_FS | ||
613 | g->pstats.last_rail_gate_complete = jiffies; | ||
614 | #endif | ||
615 | |||
616 | return ret; | ||
617 | } | ||
618 | |||
619 | static int gk20a_pm_unrailgate(struct device *dev) | ||
620 | { | ||
621 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
622 | int ret = 0; | ||
623 | struct gk20a *g = get_gk20a(dev); | ||
624 | |||
625 | #ifdef CONFIG_DEBUG_FS | ||
626 | g->pstats.last_rail_ungate_start = jiffies; | ||
627 | if (g->pstats.railgating_cycle_count >= 1) | ||
628 | g->pstats.total_rail_gate_time_ms = | ||
629 | g->pstats.total_rail_gate_time_ms + | ||
630 | jiffies_to_msecs(g->pstats.last_rail_ungate_start - | ||
631 | g->pstats.last_rail_gate_complete); | ||
632 | |||
633 | g->pstats.railgating_cycle_count++; | ||
634 | #endif | ||
635 | |||
636 | trace_gk20a_pm_unrailgate(dev_name(dev)); | ||
637 | |||
638 | if (platform->unrailgate) { | ||
639 | nvgpu_mutex_acquire(&platform->railgate_lock); | ||
640 | ret = platform->unrailgate(dev); | ||
641 | nvgpu_mutex_release(&platform->railgate_lock); | ||
642 | } | ||
643 | |||
644 | #ifdef CONFIG_DEBUG_FS | ||
645 | g->pstats.last_rail_ungate_complete = jiffies; | ||
646 | #endif | ||
647 | |||
648 | return ret; | ||
649 | } | ||
650 | |||
651 | static void gk20a_pm_shutdown(struct platform_device *pdev) | ||
652 | { | ||
653 | struct gk20a_platform *platform = platform_get_drvdata(pdev); | ||
654 | struct gk20a *g = platform->g; | ||
655 | int err; | ||
656 | |||
657 | nvgpu_info(g, "shutting down"); | ||
658 | |||
659 | /* vgpu has nothing to clean up currently */ | ||
660 | if (gk20a_gpu_is_virtual(&pdev->dev)) | ||
661 | return; | ||
662 | |||
663 | gk20a_driver_start_unload(g); | ||
664 | |||
665 | /* If GPU is already railgated, | ||
666 | * just prevent more requests, and return */ | ||
667 | if (platform->is_railgated && platform->is_railgated(&pdev->dev)) { | ||
668 | __pm_runtime_disable(&pdev->dev, false); | ||
669 | nvgpu_info(g, "already railgated, shut down complete"); | ||
670 | return; | ||
671 | } | ||
672 | |||
673 | /* Prevent more requests by disabling Runtime PM */ | ||
674 | __pm_runtime_disable(&pdev->dev, false); | ||
675 | |||
676 | err = gk20a_wait_for_idle(&pdev->dev); | ||
677 | if (err) { | ||
678 | nvgpu_err(g, "failed to idle GPU, err=%d", err); | ||
679 | goto finish; | ||
680 | } | ||
681 | |||
682 | err = gk20a_fifo_disable_all_engine_activity(g, true); | ||
683 | if (err) { | ||
684 | nvgpu_err(g, "failed to disable engine activity, err=%d", | ||
685 | err); | ||
686 | goto finish; | ||
687 | } | ||
688 | |||
689 | err = gk20a_fifo_wait_engine_idle(g); | ||
690 | if (err) { | ||
691 | nvgpu_err(g, "failed to idle engines, err=%d", | ||
692 | err); | ||
693 | goto finish; | ||
694 | } | ||
695 | |||
696 | if (gk20a_gpu_is_virtual(&pdev->dev)) | ||
697 | err = vgpu_pm_prepare_poweroff(&pdev->dev); | ||
698 | else | ||
699 | err = gk20a_pm_prepare_poweroff(&pdev->dev); | ||
700 | if (err) { | ||
701 | nvgpu_err(g, "failed to prepare for poweroff, err=%d", | ||
702 | err); | ||
703 | goto finish; | ||
704 | } | ||
705 | |||
706 | err = gk20a_pm_railgate(&pdev->dev); | ||
707 | if (err) | ||
708 | nvgpu_err(g, "failed to railgate, err=%d", err); | ||
709 | |||
710 | finish: | ||
711 | nvgpu_info(g, "shut down complete"); | ||
712 | } | ||
713 | |||
714 | #ifdef CONFIG_PM | ||
715 | static int gk20a_pm_runtime_resume(struct device *dev) | ||
716 | { | ||
717 | int err = 0; | ||
718 | |||
719 | err = gk20a_pm_unrailgate(dev); | ||
720 | if (err) | ||
721 | goto fail; | ||
722 | |||
723 | err = gk20a_pm_finalize_poweron(dev); | ||
724 | if (err) | ||
725 | goto fail_poweron; | ||
726 | |||
727 | return 0; | ||
728 | |||
729 | fail_poweron: | ||
730 | gk20a_pm_railgate(dev); | ||
731 | fail: | ||
732 | return err; | ||
733 | } | ||
734 | |||
735 | static int gk20a_pm_runtime_suspend(struct device *dev) | ||
736 | { | ||
737 | int err = 0; | ||
738 | |||
739 | err = gk20a_pm_prepare_poweroff(dev); | ||
740 | if (err) | ||
741 | goto fail; | ||
742 | |||
743 | err = gk20a_pm_railgate(dev); | ||
744 | if (err) | ||
745 | goto fail_railgate; | ||
746 | |||
747 | return 0; | ||
748 | |||
749 | fail_railgate: | ||
750 | gk20a_pm_finalize_poweron(dev); | ||
751 | fail: | ||
752 | pm_runtime_mark_last_busy(dev); | ||
753 | return err; | ||
754 | } | ||
755 | |||
756 | static int gk20a_pm_suspend(struct device *dev) | ||
757 | { | ||
758 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
759 | struct gk20a *g = get_gk20a(dev); | ||
760 | int ret = 0; | ||
761 | |||
762 | if (platform->user_railgate_disabled) | ||
763 | gk20a_idle_nosuspend(dev); | ||
764 | |||
765 | if (atomic_read(&dev->power.usage_count) > 1) { | ||
766 | ret = -EBUSY; | ||
767 | goto fail; | ||
768 | } | ||
769 | |||
770 | if (!g->power_on) | ||
771 | return 0; | ||
772 | |||
773 | ret = gk20a_pm_runtime_suspend(dev); | ||
774 | if (ret) | ||
775 | goto fail; | ||
776 | |||
777 | if (platform->suspend) | ||
778 | platform->suspend(dev); | ||
779 | |||
780 | g->suspended = true; | ||
781 | |||
782 | return 0; | ||
783 | |||
784 | fail: | ||
785 | if (platform->user_railgate_disabled) | ||
786 | gk20a_busy_noresume(dev); | ||
787 | |||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | static int gk20a_pm_resume(struct device *dev) | ||
792 | { | ||
793 | struct gk20a *g = get_gk20a(dev); | ||
794 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
795 | int ret = 0; | ||
796 | |||
797 | if (platform->user_railgate_disabled) | ||
798 | gk20a_busy_noresume(dev); | ||
799 | |||
800 | if (!g->suspended) | ||
801 | return 0; | ||
802 | |||
803 | ret = gk20a_pm_runtime_resume(dev); | ||
804 | |||
805 | g->suspended = false; | ||
806 | |||
807 | return ret; | ||
808 | } | ||
809 | |||
810 | static const struct dev_pm_ops gk20a_pm_ops = { | ||
811 | .runtime_resume = gk20a_pm_runtime_resume, | ||
812 | .runtime_suspend = gk20a_pm_runtime_suspend, | ||
813 | .resume = gk20a_pm_resume, | ||
814 | .suspend = gk20a_pm_suspend, | ||
815 | }; | ||
816 | #endif | ||
817 | |||
818 | int gk20a_pm_init(struct device *dev) | ||
819 | { | ||
820 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
821 | int err = 0; | ||
822 | |||
823 | gk20a_dbg_fn(""); | ||
824 | |||
825 | /* Initialise pm runtime */ | ||
826 | if (platform->railgate_delay) { | ||
827 | pm_runtime_set_autosuspend_delay(dev, | ||
828 | platform->railgate_delay); | ||
829 | pm_runtime_use_autosuspend(dev); | ||
830 | } | ||
831 | |||
832 | if (platform->can_railgate) { | ||
833 | pm_runtime_enable(dev); | ||
834 | if (!pm_runtime_enabled(dev)) | ||
835 | gk20a_pm_unrailgate(dev); | ||
836 | else | ||
837 | gk20a_pm_railgate(dev); | ||
838 | } else { | ||
839 | __pm_runtime_disable(dev, false); | ||
840 | gk20a_pm_unrailgate(dev); | ||
841 | } | ||
842 | |||
843 | return err; | ||
844 | } | ||
845 | |||
846 | static inline void set_gk20a(struct platform_device *pdev, struct gk20a *gk20a) | ||
847 | { | ||
848 | gk20a_get_platform(&pdev->dev)->g = gk20a; | ||
849 | } | ||
850 | |||
851 | static int gk20a_probe(struct platform_device *dev) | ||
852 | { | ||
853 | struct gk20a *gk20a; | ||
854 | int err; | ||
855 | struct gk20a_platform *platform = NULL; | ||
856 | |||
857 | if (dev->dev.of_node) { | ||
858 | const struct of_device_id *match; | ||
859 | |||
860 | match = of_match_device(tegra_gk20a_of_match, &dev->dev); | ||
861 | if (match) | ||
862 | platform = (struct gk20a_platform *)match->data; | ||
863 | } else | ||
864 | platform = (struct gk20a_platform *)dev->dev.platform_data; | ||
865 | |||
866 | if (!platform) { | ||
867 | dev_err(&dev->dev, "no platform data\n"); | ||
868 | return -ENODATA; | ||
869 | } | ||
870 | |||
871 | gk20a_dbg_fn(""); | ||
872 | |||
873 | platform_set_drvdata(dev, platform); | ||
874 | |||
875 | if (gk20a_gpu_is_virtual(&dev->dev)) | ||
876 | return vgpu_probe(dev); | ||
877 | |||
878 | gk20a = kzalloc(sizeof(struct gk20a), GFP_KERNEL); | ||
879 | if (!gk20a) { | ||
880 | dev_err(&dev->dev, "couldn't allocate gk20a support"); | ||
881 | return -ENOMEM; | ||
882 | } | ||
883 | |||
884 | set_gk20a(dev, gk20a); | ||
885 | gk20a->dev = &dev->dev; | ||
886 | |||
887 | if (nvgpu_platform_is_simulation(gk20a)) | ||
888 | platform->is_fmodel = true; | ||
889 | |||
890 | nvgpu_kmem_init(gk20a); | ||
891 | |||
892 | gk20a->irq_stall = platform_get_irq(dev, 0); | ||
893 | gk20a->irq_nonstall = platform_get_irq(dev, 1); | ||
894 | if (gk20a->irq_stall < 0 || gk20a->irq_nonstall < 0) | ||
895 | return -ENXIO; | ||
896 | |||
897 | err = devm_request_threaded_irq(&dev->dev, | ||
898 | gk20a->irq_stall, | ||
899 | gk20a_intr_isr_stall, | ||
900 | gk20a_intr_thread_stall, | ||
901 | 0, "gk20a_stall", gk20a); | ||
902 | if (err) { | ||
903 | dev_err(&dev->dev, | ||
904 | "failed to request stall intr irq @ %d\n", | ||
905 | gk20a->irq_stall); | ||
906 | return err; | ||
907 | } | ||
908 | err = devm_request_irq(&dev->dev, | ||
909 | gk20a->irq_nonstall, | ||
910 | gk20a_intr_isr_nonstall, | ||
911 | 0, "gk20a_nonstall", gk20a); | ||
912 | if (err) { | ||
913 | dev_err(&dev->dev, | ||
914 | "failed to request non-stall intr irq @ %d\n", | ||
915 | gk20a->irq_nonstall); | ||
916 | return err; | ||
917 | } | ||
918 | disable_irq(gk20a->irq_stall); | ||
919 | if (gk20a->irq_stall != gk20a->irq_nonstall) | ||
920 | disable_irq(gk20a->irq_nonstall); | ||
921 | |||
922 | err = gk20a_init_support(dev); | ||
923 | if (err) | ||
924 | return err; | ||
925 | |||
926 | #ifdef CONFIG_RESET_CONTROLLER | ||
927 | platform->reset_control = devm_reset_control_get(&dev->dev, NULL); | ||
928 | if (IS_ERR(platform->reset_control)) | ||
929 | platform->reset_control = NULL; | ||
930 | #endif | ||
931 | |||
932 | err = nvgpu_probe(gk20a, "gpu.0", INTERFACE_NAME, &nvgpu_class); | ||
933 | if (err) | ||
934 | return err; | ||
935 | |||
936 | err = gk20a_pm_init(&dev->dev); | ||
937 | if (err) { | ||
938 | dev_err(&dev->dev, "pm init failed"); | ||
939 | return err; | ||
940 | } | ||
941 | |||
942 | gk20a->mm.has_physical_mode = !nvgpu_is_hypervisor_mode(gk20a); | ||
943 | |||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | static int __exit gk20a_remove(struct platform_device *pdev) | ||
948 | { | ||
949 | struct device *dev = &pdev->dev; | ||
950 | struct gk20a *g = get_gk20a(dev); | ||
951 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
952 | |||
953 | gk20a_dbg_fn(""); | ||
954 | |||
955 | if (gk20a_gpu_is_virtual(dev)) | ||
956 | return vgpu_remove(pdev); | ||
957 | |||
958 | if (platform->has_cde) | ||
959 | gk20a_cde_destroy(g); | ||
960 | |||
961 | gk20a_ctxsw_trace_cleanup(g); | ||
962 | |||
963 | gk20a_sched_ctrl_cleanup(g); | ||
964 | |||
965 | if (IS_ENABLED(CONFIG_GK20A_DEVFREQ)) | ||
966 | gk20a_scale_exit(dev); | ||
967 | |||
968 | if (g->remove_support) | ||
969 | g->remove_support(g); | ||
970 | |||
971 | gk20a_ce_destroy(g); | ||
972 | |||
973 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | ||
974 | nvgpu_clk_arb_cleanup_arbiter(g); | ||
975 | #endif | ||
976 | |||
977 | gk20a_user_deinit(dev, &nvgpu_class); | ||
978 | |||
979 | debugfs_remove_recursive(platform->debugfs); | ||
980 | debugfs_remove_recursive(platform->debugfs_alias); | ||
981 | |||
982 | gk20a_remove_sysfs(dev); | ||
983 | |||
984 | if (platform->secure_buffer.destroy) | ||
985 | platform->secure_buffer.destroy(dev, | ||
986 | &platform->secure_buffer); | ||
987 | |||
988 | if (pm_runtime_enabled(dev)) | ||
989 | pm_runtime_disable(dev); | ||
990 | |||
991 | if (platform->remove) | ||
992 | platform->remove(dev); | ||
993 | |||
994 | set_gk20a(pdev, NULL); | ||
995 | gk20a_put(g); | ||
996 | |||
997 | gk20a_dbg_fn("removed"); | ||
998 | |||
999 | return 0; | ||
1000 | } | ||
1001 | |||
1002 | static struct platform_driver gk20a_driver = { | ||
1003 | .probe = gk20a_probe, | ||
1004 | .remove = __exit_p(gk20a_remove), | ||
1005 | .shutdown = gk20a_pm_shutdown, | ||
1006 | .driver = { | ||
1007 | .owner = THIS_MODULE, | ||
1008 | .name = "gk20a", | ||
1009 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0) | ||
1010 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, | ||
1011 | #endif | ||
1012 | #ifdef CONFIG_OF | ||
1013 | .of_match_table = tegra_gk20a_of_match, | ||
1014 | #endif | ||
1015 | #ifdef CONFIG_PM | ||
1016 | .pm = &gk20a_pm_ops, | ||
1017 | #endif | ||
1018 | .suppress_bind_attrs = true, | ||
1019 | } | ||
1020 | }; | ||
1021 | |||
1022 | struct class nvgpu_class = { | ||
1023 | .owner = THIS_MODULE, | ||
1024 | .name = CLASS_NAME, | ||
1025 | }; | ||
1026 | |||
1027 | static int __init gk20a_init(void) | ||
1028 | { | ||
1029 | |||
1030 | int ret; | ||
1031 | |||
1032 | ret = class_register(&nvgpu_class); | ||
1033 | if (ret) | ||
1034 | return ret; | ||
1035 | |||
1036 | ret = nvgpu_pci_init(); | ||
1037 | if (ret) | ||
1038 | return ret; | ||
1039 | |||
1040 | return platform_driver_register(&gk20a_driver); | ||
1041 | } | ||
1042 | |||
1043 | static void __exit gk20a_exit(void) | ||
1044 | { | ||
1045 | nvgpu_pci_exit(); | ||
1046 | platform_driver_unregister(&gk20a_driver); | ||
1047 | class_unregister(&nvgpu_class); | ||
1048 | } | ||
1049 | |||
1050 | MODULE_LICENSE("GPL v2"); | ||
1051 | module_init(gk20a_init); | ||
1052 | module_exit(gk20a_exit); | ||
diff --git a/drivers/gpu/nvgpu/common/linux/module.h b/drivers/gpu/nvgpu/common/linux/module.h new file mode 100644 index 00000000..45fa2f5c --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/module.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011-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 | #ifndef __NVGPU_COMMON_LINUX_MODULE_H__ | ||
14 | #define __NVGPU_COMMON_LINUX_MODULE_H__ | ||
15 | |||
16 | struct gk20a; | ||
17 | struct device; | ||
18 | |||
19 | int gk20a_pm_finalize_poweron(struct device *dev); | ||
20 | void gk20a_remove_support(struct gk20a *g); | ||
21 | |||
22 | #endif | ||
diff --git a/drivers/gpu/nvgpu/common/linux/pci.c b/drivers/gpu/nvgpu/common/linux/pci.c new file mode 100644 index 00000000..f90b3a6e --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/pci.c | |||
@@ -0,0 +1,511 @@ | |||
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/pci.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/pm_runtime.h> | ||
20 | |||
21 | #include <nvgpu/nvgpu_common.h> | ||
22 | #include <nvgpu/kmem.h> | ||
23 | |||
24 | #include "gk20a/gk20a.h" | ||
25 | #include "gk20a/platform_gk20a.h" | ||
26 | #include "clk/clk.h" | ||
27 | #include "module.h" | ||
28 | |||
29 | #include "pci.h" | ||
30 | |||
31 | #define PCI_INTERFACE_NAME "card-%s%%s" | ||
32 | |||
33 | static int nvgpu_pci_tegra_probe(struct device *dev) | ||
34 | { | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static int nvgpu_pci_tegra_remove(struct device *dev) | ||
39 | { | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static bool nvgpu_pci_tegra_is_railgated(struct device *pdev) | ||
44 | { | ||
45 | return false; | ||
46 | } | ||
47 | |||
48 | static long nvgpu_pci_clk_round_rate(struct device *dev, unsigned long rate) | ||
49 | { | ||
50 | long ret = (long)rate; | ||
51 | |||
52 | if (rate == UINT_MAX) | ||
53 | ret = BOOT_GPC2CLK_MHZ * 1000000UL; | ||
54 | |||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | static struct gk20a_platform nvgpu_pci_device[] = { | ||
59 | { /* DEVICE=0x1c35 */ | ||
60 | /* ptimer src frequency in hz */ | ||
61 | .ptimer_src_freq = 31250000, | ||
62 | |||
63 | .probe = nvgpu_pci_tegra_probe, | ||
64 | .remove = nvgpu_pci_tegra_remove, | ||
65 | |||
66 | /* power management configuration */ | ||
67 | .railgate_delay = 500, | ||
68 | .can_railgate = false, | ||
69 | .can_elpg = true, | ||
70 | .enable_elpg = true, | ||
71 | .enable_elcg = false, | ||
72 | .enable_slcg = true, | ||
73 | .enable_blcg = true, | ||
74 | .enable_mscg = true, | ||
75 | .default_pri_timeout = 0x3ff, | ||
76 | |||
77 | .disable_aspm = true, | ||
78 | |||
79 | /* power management callbacks */ | ||
80 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
81 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
82 | |||
83 | .default_big_page_size = SZ_64K, | ||
84 | |||
85 | .ch_wdt_timeout_ms = 7000, | ||
86 | |||
87 | .vidmem_is_vidmem = true, | ||
88 | .vbios_min_version = 0x86063000, | ||
89 | .hardcode_sw_threshold = true, | ||
90 | .ina3221_dcb_index = 0, | ||
91 | .ina3221_i2c_address = 0x84, | ||
92 | }, | ||
93 | { /* DEVICE=0x1c36 */ | ||
94 | /* ptimer src frequency in hz */ | ||
95 | .ptimer_src_freq = 31250000, | ||
96 | |||
97 | .probe = nvgpu_pci_tegra_probe, | ||
98 | .remove = nvgpu_pci_tegra_remove, | ||
99 | |||
100 | /* power management configuration */ | ||
101 | .railgate_delay = 500, | ||
102 | .can_railgate = false, | ||
103 | .can_elpg = true, | ||
104 | .enable_elpg = true, | ||
105 | .enable_elcg = false, | ||
106 | .enable_slcg = true, | ||
107 | .enable_blcg = true, | ||
108 | .enable_mscg = true, | ||
109 | .default_pri_timeout = 0x3ff, | ||
110 | |||
111 | .disable_aspm = true, | ||
112 | |||
113 | /* power management callbacks */ | ||
114 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
115 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
116 | |||
117 | .default_big_page_size = SZ_64K, | ||
118 | |||
119 | .ch_wdt_timeout_ms = 7000, | ||
120 | |||
121 | .vidmem_is_vidmem = true, | ||
122 | .vbios_min_version = 0x86062d00, | ||
123 | .hardcode_sw_threshold = true, | ||
124 | .ina3221_dcb_index = 0, | ||
125 | .ina3221_i2c_address = 0x84, | ||
126 | }, | ||
127 | { /* DEVICE=0x1c37 */ | ||
128 | /* ptimer src frequency in hz */ | ||
129 | .ptimer_src_freq = 31250000, | ||
130 | |||
131 | .probe = nvgpu_pci_tegra_probe, | ||
132 | .remove = nvgpu_pci_tegra_remove, | ||
133 | |||
134 | /* power management configuration */ | ||
135 | .railgate_delay = 500, | ||
136 | .can_railgate = false, | ||
137 | .can_elpg = true, | ||
138 | .enable_elpg = true, | ||
139 | .enable_elcg = false, | ||
140 | .enable_slcg = true, | ||
141 | .enable_blcg = true, | ||
142 | .enable_mscg = true, | ||
143 | .default_pri_timeout = 0x3ff, | ||
144 | |||
145 | .disable_aspm = true, | ||
146 | |||
147 | /* power management callbacks */ | ||
148 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
149 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
150 | |||
151 | .default_big_page_size = SZ_64K, | ||
152 | |||
153 | .ch_wdt_timeout_ms = 7000, | ||
154 | |||
155 | .vidmem_is_vidmem = true, | ||
156 | .vbios_min_version = 0x86063000, | ||
157 | .hardcode_sw_threshold = true, | ||
158 | .ina3221_dcb_index = 0, | ||
159 | .ina3221_i2c_address = 0x84, | ||
160 | }, | ||
161 | { /* DEVICE=0x1c75 */ | ||
162 | /* ptimer src frequency in hz */ | ||
163 | .ptimer_src_freq = 31250000, | ||
164 | |||
165 | .probe = nvgpu_pci_tegra_probe, | ||
166 | .remove = nvgpu_pci_tegra_remove, | ||
167 | |||
168 | /* power management configuration */ | ||
169 | .railgate_delay = 500, | ||
170 | .can_railgate = false, | ||
171 | .can_elpg = true, | ||
172 | .enable_elpg = true, | ||
173 | .enable_elcg = false, | ||
174 | .enable_slcg = true, | ||
175 | .enable_blcg = true, | ||
176 | .enable_mscg = true, | ||
177 | .default_pri_timeout = 0x3ff, | ||
178 | |||
179 | .disable_aspm = true, | ||
180 | |||
181 | /* power management callbacks */ | ||
182 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
183 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
184 | |||
185 | .default_big_page_size = SZ_64K, | ||
186 | |||
187 | .ch_wdt_timeout_ms = 7000, | ||
188 | |||
189 | .vidmem_is_vidmem = true, | ||
190 | .vbios_min_version = 0x86064700, | ||
191 | .hardcode_sw_threshold = false, | ||
192 | .ina3221_dcb_index = 1, | ||
193 | .ina3221_i2c_address = 0x80, | ||
194 | } | ||
195 | }; | ||
196 | |||
197 | static struct pci_device_id nvgpu_pci_table[] = { | ||
198 | { | ||
199 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1c35), | ||
200 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
201 | .class_mask = 0xff << 16, | ||
202 | .driver_data = 0, | ||
203 | }, | ||
204 | { | ||
205 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1c36), | ||
206 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
207 | .class_mask = 0xff << 16, | ||
208 | .driver_data = 1, | ||
209 | }, | ||
210 | { | ||
211 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1c37), | ||
212 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
213 | .class_mask = 0xff << 16, | ||
214 | .driver_data = 2, | ||
215 | }, | ||
216 | { | ||
217 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1c75), | ||
218 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
219 | .class_mask = 0xff << 16, | ||
220 | .driver_data = 3, | ||
221 | }, | ||
222 | {} | ||
223 | }; | ||
224 | |||
225 | static irqreturn_t nvgpu_pci_isr(int irq, void *dev_id) | ||
226 | { | ||
227 | struct gk20a *g = dev_id; | ||
228 | irqreturn_t ret_stall; | ||
229 | irqreturn_t ret_nonstall; | ||
230 | |||
231 | ret_stall = g->ops.mc.isr_stall(g); | ||
232 | ret_nonstall = g->ops.mc.isr_nonstall(g); | ||
233 | |||
234 | #if defined(CONFIG_PCI_MSI) | ||
235 | /* Send MSI EOI */ | ||
236 | if (g->ops.xve.rearm_msi && g->msi_enabled) | ||
237 | g->ops.xve.rearm_msi(g); | ||
238 | #endif | ||
239 | |||
240 | return (ret_stall == IRQ_NONE) ? ret_nonstall : IRQ_WAKE_THREAD; | ||
241 | } | ||
242 | |||
243 | static irqreturn_t nvgpu_pci_intr_thread(int irq, void *dev_id) | ||
244 | { | ||
245 | struct gk20a *g = dev_id; | ||
246 | |||
247 | g->ops.mc.isr_thread_stall(g); | ||
248 | |||
249 | return IRQ_HANDLED; | ||
250 | } | ||
251 | |||
252 | static int nvgpu_pci_init_support(struct pci_dev *pdev) | ||
253 | { | ||
254 | int err = 0; | ||
255 | struct gk20a *g = get_gk20a(&pdev->dev); | ||
256 | |||
257 | g->regs = ioremap(pci_resource_start(pdev, 0), | ||
258 | pci_resource_len(pdev, 0)); | ||
259 | if (IS_ERR(g->regs)) { | ||
260 | nvgpu_err(g, "failed to remap gk20a registers"); | ||
261 | err = PTR_ERR(g->regs); | ||
262 | goto fail; | ||
263 | } | ||
264 | |||
265 | g->bar1 = ioremap(pci_resource_start(pdev, 1), | ||
266 | pci_resource_len(pdev, 1)); | ||
267 | if (IS_ERR(g->bar1)) { | ||
268 | nvgpu_err(g, "failed to remap gk20a bar1"); | ||
269 | err = PTR_ERR(g->bar1); | ||
270 | goto fail; | ||
271 | } | ||
272 | |||
273 | return 0; | ||
274 | |||
275 | fail: | ||
276 | return err; | ||
277 | } | ||
278 | |||
279 | static char *nvgpu_pci_devnode(struct device *dev, umode_t *mode) | ||
280 | { | ||
281 | if (mode) | ||
282 | *mode = S_IRUGO | S_IWUGO; | ||
283 | return kasprintf(GFP_KERNEL, "nvgpu-pci/%s", dev_name(dev)); | ||
284 | } | ||
285 | |||
286 | static struct class nvgpu_pci_class = { | ||
287 | .owner = THIS_MODULE, | ||
288 | .name = "nvidia-pci-gpu", | ||
289 | .devnode = nvgpu_pci_devnode, | ||
290 | }; | ||
291 | |||
292 | #ifdef CONFIG_PM | ||
293 | static int nvgpu_pci_pm_runtime_resume(struct device *dev) | ||
294 | { | ||
295 | return gk20a_pm_finalize_poweron(dev); | ||
296 | } | ||
297 | |||
298 | static int nvgpu_pci_pm_runtime_suspend(struct device *dev) | ||
299 | { | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static const struct dev_pm_ops nvgpu_pci_pm_ops = { | ||
304 | .runtime_resume = nvgpu_pci_pm_runtime_resume, | ||
305 | .runtime_suspend = nvgpu_pci_pm_runtime_suspend, | ||
306 | .resume = nvgpu_pci_pm_runtime_resume, | ||
307 | .suspend = nvgpu_pci_pm_runtime_suspend, | ||
308 | }; | ||
309 | #endif | ||
310 | |||
311 | static int nvgpu_pci_pm_init(struct device *dev) | ||
312 | { | ||
313 | #ifdef CONFIG_PM | ||
314 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
315 | |||
316 | if (!platform->can_railgate) { | ||
317 | pm_runtime_disable(dev); | ||
318 | } else { | ||
319 | if (platform->railgate_delay) | ||
320 | pm_runtime_set_autosuspend_delay(dev, | ||
321 | platform->railgate_delay); | ||
322 | |||
323 | /* | ||
324 | * Runtime PM for PCI devices is disabled by default, | ||
325 | * so we need to enable it first | ||
326 | */ | ||
327 | pm_runtime_use_autosuspend(dev); | ||
328 | pm_runtime_put_noidle(dev); | ||
329 | pm_runtime_allow(dev); | ||
330 | } | ||
331 | #endif | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int nvgpu_pci_probe(struct pci_dev *pdev, | ||
336 | const struct pci_device_id *pent) | ||
337 | { | ||
338 | struct gk20a_platform *platform = NULL; | ||
339 | struct gk20a *g; | ||
340 | int err; | ||
341 | char nodefmt[64]; | ||
342 | |||
343 | /* make sure driver_data is a sane index */ | ||
344 | if (pent->driver_data >= sizeof(nvgpu_pci_device) / | ||
345 | sizeof(nvgpu_pci_device[0])) { | ||
346 | return -EINVAL; | ||
347 | } | ||
348 | |||
349 | platform = &nvgpu_pci_device[pent->driver_data]; | ||
350 | pci_set_drvdata(pdev, platform); | ||
351 | |||
352 | g = kzalloc(sizeof(struct gk20a), GFP_KERNEL); | ||
353 | if (!g) { | ||
354 | nvgpu_err(g, "couldn't allocate gk20a support"); | ||
355 | return -ENOMEM; | ||
356 | } | ||
357 | |||
358 | platform->g = g; | ||
359 | g->dev = &pdev->dev; | ||
360 | |||
361 | nvgpu_kmem_init(g); | ||
362 | |||
363 | err = pci_enable_device(pdev); | ||
364 | if (err) | ||
365 | return err; | ||
366 | pci_set_master(pdev); | ||
367 | |||
368 | g->pci_vendor_id = pdev->vendor; | ||
369 | g->pci_device_id = pdev->device; | ||
370 | g->pci_subsystem_vendor_id = pdev->subsystem_vendor; | ||
371 | g->pci_subsystem_device_id = pdev->subsystem_device; | ||
372 | g->pci_class = (pdev->class >> 8) & 0xFFFFU; // we only want base/sub | ||
373 | g->pci_revision = pdev->revision; | ||
374 | |||
375 | #if defined(CONFIG_PCI_MSI) | ||
376 | err = pci_enable_msi(pdev); | ||
377 | if (err) { | ||
378 | nvgpu_err(g, | ||
379 | "MSI could not be enabled, falling back to legacy"); | ||
380 | g->msi_enabled = false; | ||
381 | } else | ||
382 | g->msi_enabled = true; | ||
383 | #endif | ||
384 | |||
385 | g->irq_stall = pdev->irq; | ||
386 | g->irq_nonstall = pdev->irq; | ||
387 | if (g->irq_stall < 0) | ||
388 | return -ENXIO; | ||
389 | |||
390 | err = devm_request_threaded_irq(&pdev->dev, | ||
391 | g->irq_stall, | ||
392 | nvgpu_pci_isr, | ||
393 | nvgpu_pci_intr_thread, | ||
394 | #if defined(CONFIG_PCI_MSI) | ||
395 | g->msi_enabled ? 0 : | ||
396 | #endif | ||
397 | IRQF_SHARED, "nvgpu", g); | ||
398 | if (err) { | ||
399 | nvgpu_err(g, | ||
400 | "failed to request irq @ %d", g->irq_stall); | ||
401 | return err; | ||
402 | } | ||
403 | disable_irq(g->irq_stall); | ||
404 | |||
405 | /* | ||
406 | * is_fmodel needs to be in gk20a struct for deferred teardown | ||
407 | */ | ||
408 | g->is_fmodel = platform->is_fmodel; | ||
409 | |||
410 | err = nvgpu_pci_init_support(pdev); | ||
411 | if (err) | ||
412 | return err; | ||
413 | |||
414 | if (strchr(dev_name(&pdev->dev), '%')) { | ||
415 | nvgpu_err(g, "illegal character in device name"); | ||
416 | return -EINVAL; | ||
417 | } | ||
418 | |||
419 | snprintf(nodefmt, sizeof(nodefmt), | ||
420 | PCI_INTERFACE_NAME, dev_name(&pdev->dev)); | ||
421 | |||
422 | err = nvgpu_probe(g, "gpu_pci", nodefmt, &nvgpu_pci_class); | ||
423 | if (err) | ||
424 | return err; | ||
425 | |||
426 | err = nvgpu_pci_pm_init(&pdev->dev); | ||
427 | if (err) { | ||
428 | nvgpu_err(g, "pm init failed"); | ||
429 | return err; | ||
430 | } | ||
431 | |||
432 | g->mm.has_physical_mode = false; | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static void nvgpu_pci_remove(struct pci_dev *pdev) | ||
438 | { | ||
439 | struct gk20a_platform *platform = gk20a_get_platform(&pdev->dev); | ||
440 | struct gk20a *g = get_gk20a(&pdev->dev); | ||
441 | |||
442 | gk20a_dbg(gpu_dbg_shutdown, "Removing nvgpu driver!\n"); | ||
443 | |||
444 | if (g->irqs_enabled) | ||
445 | disable_irq(g->irq_stall); | ||
446 | |||
447 | devm_free_irq(&pdev->dev, g->irq_stall, g); | ||
448 | |||
449 | #if defined(CONFIG_PCI_MSI) | ||
450 | if (g->msi_enabled) { | ||
451 | pci_disable_msi(pdev); | ||
452 | g->msi_enabled = false; | ||
453 | } | ||
454 | #endif | ||
455 | gk20a_dbg(gpu_dbg_shutdown, "IRQs disabled.\n"); | ||
456 | |||
457 | /* | ||
458 | * Wait for the driver to finish up all the IOCTLs it's working on | ||
459 | * before cleaning up the driver's data structures. | ||
460 | */ | ||
461 | gk20a_driver_start_unload(g); | ||
462 | gk20a_dbg(gpu_dbg_shutdown, "Driver idle.\n"); | ||
463 | |||
464 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | ||
465 | nvgpu_clk_arb_cleanup_arbiter(g); | ||
466 | #endif | ||
467 | |||
468 | gk20a_user_deinit(g->dev, &nvgpu_pci_class); | ||
469 | gk20a_dbg(gpu_dbg_shutdown, "User de-init done.\b"); | ||
470 | |||
471 | debugfs_remove_recursive(platform->debugfs); | ||
472 | debugfs_remove_recursive(platform->debugfs_alias); | ||
473 | |||
474 | gk20a_remove_sysfs(g->dev); | ||
475 | |||
476 | if (platform->remove) | ||
477 | platform->remove(g->dev); | ||
478 | gk20a_dbg(gpu_dbg_shutdown, "Platform remove done.\b"); | ||
479 | |||
480 | enable_irq(g->irq_stall); | ||
481 | |||
482 | gk20a_get_platform(&pdev->dev)->g = NULL; | ||
483 | gk20a_put(g); | ||
484 | } | ||
485 | |||
486 | static struct pci_driver nvgpu_pci_driver = { | ||
487 | .name = "nvgpu", | ||
488 | .id_table = nvgpu_pci_table, | ||
489 | .probe = nvgpu_pci_probe, | ||
490 | .remove = nvgpu_pci_remove, | ||
491 | #ifdef CONFIG_PM | ||
492 | .driver.pm = &nvgpu_pci_pm_ops, | ||
493 | #endif | ||
494 | }; | ||
495 | |||
496 | int __init nvgpu_pci_init(void) | ||
497 | { | ||
498 | int ret; | ||
499 | |||
500 | ret = class_register(&nvgpu_pci_class); | ||
501 | if (ret) | ||
502 | return ret; | ||
503 | |||
504 | return pci_register_driver(&nvgpu_pci_driver); | ||
505 | } | ||
506 | |||
507 | void __exit nvgpu_pci_exit(void) | ||
508 | { | ||
509 | pci_unregister_driver(&nvgpu_pci_driver); | ||
510 | class_unregister(&nvgpu_pci_class); | ||
511 | } | ||
diff --git a/drivers/gpu/nvgpu/common/linux/pci.h b/drivers/gpu/nvgpu/common/linux/pci.h new file mode 100644 index 00000000..cc6b77b1 --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/pci.h | |||
@@ -0,0 +1,27 @@ | |||
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 NVGPU_PCI_H | ||
17 | #define NVGPU_PCI_H | ||
18 | |||
19 | #ifdef CONFIG_GK20A_PCI | ||
20 | int nvgpu_pci_init(void); | ||
21 | void nvgpu_pci_exit(void); | ||
22 | #else | ||
23 | static inline int nvgpu_pci_init(void) { return 0; } | ||
24 | static inline void nvgpu_pci_exit(void) {} | ||
25 | #endif | ||
26 | |||
27 | #endif | ||