diff options
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/pci.c')
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/pci.c | 619 |
1 files changed, 619 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/pci.c b/drivers/gpu/nvgpu/common/linux/pci.c new file mode 100644 index 00000000..296d0a7c --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/pci.c | |||
@@ -0,0 +1,619 @@ | |||
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 | #include <nvgpu/enabled.h> | ||
24 | |||
25 | #include "gk20a/gk20a.h" | ||
26 | #include "clk/clk.h" | ||
27 | #include "clk/clk_mclk.h" | ||
28 | #include "module.h" | ||
29 | #include "intr.h" | ||
30 | #include "sysfs.h" | ||
31 | #include "os_linux.h" | ||
32 | #include "platform_gk20a.h" | ||
33 | |||
34 | #include "pci.h" | ||
35 | #ifdef CONFIG_TEGRA_19x_GPU | ||
36 | #include <nvgpu/linux/pci_t19x.h> | ||
37 | #endif | ||
38 | |||
39 | #include "os_linux.h" | ||
40 | #include "driver_common.h" | ||
41 | |||
42 | #define PCI_INTERFACE_NAME "card-%s%%s" | ||
43 | |||
44 | static int nvgpu_pci_tegra_probe(struct device *dev) | ||
45 | { | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static int nvgpu_pci_tegra_remove(struct device *dev) | ||
50 | { | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static bool nvgpu_pci_tegra_is_railgated(struct device *pdev) | ||
55 | { | ||
56 | return false; | ||
57 | } | ||
58 | |||
59 | static long nvgpu_pci_clk_round_rate(struct device *dev, unsigned long rate) | ||
60 | { | ||
61 | long ret = (long)rate; | ||
62 | |||
63 | if (rate == UINT_MAX) | ||
64 | ret = BOOT_GPC2CLK_MHZ * 1000000UL; | ||
65 | |||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | static struct gk20a_platform nvgpu_pci_device[] = { | ||
70 | { /* DEVICE=0x1c35 */ | ||
71 | /* ptimer src frequency in hz */ | ||
72 | .ptimer_src_freq = 31250000, | ||
73 | |||
74 | .probe = nvgpu_pci_tegra_probe, | ||
75 | .remove = nvgpu_pci_tegra_remove, | ||
76 | |||
77 | /* power management configuration */ | ||
78 | .railgate_delay_init = 500, | ||
79 | .can_railgate_init = false, | ||
80 | .can_elpg_init = true, | ||
81 | .enable_elpg = true, | ||
82 | .enable_elcg = false, | ||
83 | .enable_slcg = true, | ||
84 | .enable_blcg = true, | ||
85 | .enable_mscg = true, | ||
86 | .can_slcg = true, | ||
87 | .can_blcg = true, | ||
88 | .can_elcg = true, | ||
89 | .default_pri_timeout = 0x3ff, | ||
90 | |||
91 | .disable_aspm = true, | ||
92 | |||
93 | /* power management callbacks */ | ||
94 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
95 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
96 | |||
97 | .ch_wdt_timeout_ms = 7000, | ||
98 | |||
99 | .honors_aperture = true, | ||
100 | .vbios_min_version = 0x86063000, | ||
101 | .hardcode_sw_threshold = true, | ||
102 | .ina3221_dcb_index = 0, | ||
103 | .ina3221_i2c_address = 0x84, | ||
104 | .ina3221_i2c_port = 0x2, | ||
105 | }, | ||
106 | { /* DEVICE=0x1c36 */ | ||
107 | /* ptimer src frequency in hz */ | ||
108 | .ptimer_src_freq = 31250000, | ||
109 | |||
110 | .probe = nvgpu_pci_tegra_probe, | ||
111 | .remove = nvgpu_pci_tegra_remove, | ||
112 | |||
113 | /* power management configuration */ | ||
114 | .railgate_delay_init = 500, | ||
115 | .can_railgate_init = false, | ||
116 | .can_elpg_init = true, | ||
117 | .enable_elpg = true, | ||
118 | .enable_elcg = false, | ||
119 | .enable_slcg = true, | ||
120 | .enable_blcg = true, | ||
121 | .enable_mscg = true, | ||
122 | .can_slcg = true, | ||
123 | .can_blcg = true, | ||
124 | .can_elcg = true, | ||
125 | .default_pri_timeout = 0x3ff, | ||
126 | |||
127 | .disable_aspm = true, | ||
128 | |||
129 | /* power management callbacks */ | ||
130 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
131 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
132 | |||
133 | .ch_wdt_timeout_ms = 7000, | ||
134 | |||
135 | .honors_aperture = true, | ||
136 | .vbios_min_version = 0x86062d00, | ||
137 | .hardcode_sw_threshold = true, | ||
138 | .ina3221_dcb_index = 0, | ||
139 | .ina3221_i2c_address = 0x84, | ||
140 | .ina3221_i2c_port = 0x2, | ||
141 | }, | ||
142 | { /* DEVICE=0x1c37 */ | ||
143 | /* ptimer src frequency in hz */ | ||
144 | .ptimer_src_freq = 31250000, | ||
145 | |||
146 | .probe = nvgpu_pci_tegra_probe, | ||
147 | .remove = nvgpu_pci_tegra_remove, | ||
148 | |||
149 | /* power management configuration */ | ||
150 | .railgate_delay_init = 500, | ||
151 | .can_railgate_init = false, | ||
152 | .can_elpg_init = true, | ||
153 | .enable_elpg = true, | ||
154 | .enable_elcg = false, | ||
155 | .enable_slcg = true, | ||
156 | .enable_blcg = true, | ||
157 | .enable_mscg = true, | ||
158 | .can_slcg = true, | ||
159 | .can_blcg = true, | ||
160 | .can_elcg = true, | ||
161 | .default_pri_timeout = 0x3ff, | ||
162 | |||
163 | .disable_aspm = true, | ||
164 | |||
165 | /* power management callbacks */ | ||
166 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
167 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
168 | |||
169 | .ch_wdt_timeout_ms = 7000, | ||
170 | |||
171 | .honors_aperture = true, | ||
172 | .vbios_min_version = 0x86063000, | ||
173 | .hardcode_sw_threshold = true, | ||
174 | .ina3221_dcb_index = 0, | ||
175 | .ina3221_i2c_address = 0x84, | ||
176 | .ina3221_i2c_port = 0x2, | ||
177 | }, | ||
178 | { /* DEVICE=0x1c75 */ | ||
179 | /* ptimer src frequency in hz */ | ||
180 | .ptimer_src_freq = 31250000, | ||
181 | |||
182 | .probe = nvgpu_pci_tegra_probe, | ||
183 | .remove = nvgpu_pci_tegra_remove, | ||
184 | |||
185 | /* power management configuration */ | ||
186 | .railgate_delay_init = 500, | ||
187 | .can_railgate_init = false, | ||
188 | .can_elpg_init = true, | ||
189 | .enable_elpg = true, | ||
190 | .enable_elcg = false, | ||
191 | .enable_slcg = true, | ||
192 | .enable_blcg = true, | ||
193 | .enable_mscg = true, | ||
194 | .can_slcg = true, | ||
195 | .can_blcg = true, | ||
196 | .can_elcg = true, | ||
197 | .default_pri_timeout = 0x3ff, | ||
198 | |||
199 | .disable_aspm = true, | ||
200 | |||
201 | /* power management callbacks */ | ||
202 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
203 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
204 | |||
205 | .ch_wdt_timeout_ms = 7000, | ||
206 | |||
207 | .honors_aperture = true, | ||
208 | .vbios_min_version = 0x86065300, | ||
209 | .hardcode_sw_threshold = false, | ||
210 | .ina3221_dcb_index = 1, | ||
211 | .ina3221_i2c_address = 0x80, | ||
212 | .ina3221_i2c_port = 0x1, | ||
213 | }, | ||
214 | { /* DEVICE=PG503 SKU 201 */ | ||
215 | /* ptimer src frequency in hz */ | ||
216 | .ptimer_src_freq = 31250000, | ||
217 | |||
218 | .probe = nvgpu_pci_tegra_probe, | ||
219 | .remove = nvgpu_pci_tegra_remove, | ||
220 | |||
221 | /* power management configuration */ | ||
222 | .railgate_delay_init = 500, | ||
223 | .can_railgate_init = false, | ||
224 | .can_elpg_init = false, | ||
225 | .enable_elpg = false, | ||
226 | .enable_elcg = false, | ||
227 | .enable_slcg = false, | ||
228 | .enable_blcg = false, | ||
229 | .enable_mscg = false, | ||
230 | .can_slcg = false, | ||
231 | .can_blcg = false, | ||
232 | .can_elcg = false, | ||
233 | .default_pri_timeout = 0x3ff, | ||
234 | |||
235 | .disable_aspm = true, | ||
236 | |||
237 | /* power management callbacks */ | ||
238 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
239 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
240 | |||
241 | .ch_wdt_timeout_ms = 7000, | ||
242 | |||
243 | .honors_aperture = true, | ||
244 | .vbios_min_version = 0x88001e00, | ||
245 | .hardcode_sw_threshold = false, | ||
246 | .run_preos = true, | ||
247 | .tsg_required = true, | ||
248 | }, | ||
249 | { /* DEVICE=PG503 SKU 200 ES */ | ||
250 | /* ptimer src frequency in hz */ | ||
251 | .ptimer_src_freq = 31250000, | ||
252 | |||
253 | .probe = nvgpu_pci_tegra_probe, | ||
254 | .remove = nvgpu_pci_tegra_remove, | ||
255 | |||
256 | /* power management configuration */ | ||
257 | .railgate_delay_init = 500, | ||
258 | .can_railgate_init = false, | ||
259 | .can_elpg_init = false, | ||
260 | .enable_elpg = false, | ||
261 | .enable_elcg = false, | ||
262 | .enable_slcg = false, | ||
263 | .enable_blcg = false, | ||
264 | .enable_mscg = false, | ||
265 | .can_slcg = false, | ||
266 | .can_blcg = false, | ||
267 | .can_elcg = false, | ||
268 | .default_pri_timeout = 0x3ff, | ||
269 | |||
270 | .disable_aspm = true, | ||
271 | |||
272 | /* power management callbacks */ | ||
273 | .is_railgated = nvgpu_pci_tegra_is_railgated, | ||
274 | .clk_round_rate = nvgpu_pci_clk_round_rate, | ||
275 | |||
276 | .ch_wdt_timeout_ms = 7000, | ||
277 | |||
278 | .honors_aperture = true, | ||
279 | .vbios_min_version = 0x88001e00, | ||
280 | .hardcode_sw_threshold = false, | ||
281 | .run_preos = true, | ||
282 | .tsg_required = true, | ||
283 | } | ||
284 | }; | ||
285 | |||
286 | static struct pci_device_id nvgpu_pci_table[] = { | ||
287 | { | ||
288 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1c35), | ||
289 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
290 | .class_mask = 0xff << 16, | ||
291 | .driver_data = 0, | ||
292 | }, | ||
293 | { | ||
294 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1c36), | ||
295 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
296 | .class_mask = 0xff << 16, | ||
297 | .driver_data = 1, | ||
298 | }, | ||
299 | { | ||
300 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1c37), | ||
301 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
302 | .class_mask = 0xff << 16, | ||
303 | .driver_data = 2, | ||
304 | }, | ||
305 | { | ||
306 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1c75), | ||
307 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
308 | .class_mask = 0xff << 16, | ||
309 | .driver_data = 3, | ||
310 | }, | ||
311 | { | ||
312 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1db1), | ||
313 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
314 | .class_mask = 0xff << 16, | ||
315 | .driver_data = 4, | ||
316 | }, | ||
317 | { | ||
318 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x1db0), | ||
319 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
320 | .class_mask = 0xff << 16, | ||
321 | .driver_data = 4, | ||
322 | }, | ||
323 | {} | ||
324 | }; | ||
325 | |||
326 | static irqreturn_t nvgpu_pci_isr(int irq, void *dev_id) | ||
327 | { | ||
328 | struct gk20a *g = dev_id; | ||
329 | irqreturn_t ret_stall; | ||
330 | irqreturn_t ret_nonstall; | ||
331 | |||
332 | ret_stall = nvgpu_intr_stall(g); | ||
333 | ret_nonstall = nvgpu_intr_nonstall(g); | ||
334 | |||
335 | #if defined(CONFIG_PCI_MSI) | ||
336 | /* Send MSI EOI */ | ||
337 | if (g->ops.xve.rearm_msi && g->msi_enabled) | ||
338 | g->ops.xve.rearm_msi(g); | ||
339 | #endif | ||
340 | |||
341 | return (ret_stall == IRQ_NONE) ? ret_nonstall : IRQ_WAKE_THREAD; | ||
342 | } | ||
343 | |||
344 | static irqreturn_t nvgpu_pci_intr_thread(int irq, void *dev_id) | ||
345 | { | ||
346 | struct gk20a *g = dev_id; | ||
347 | |||
348 | return nvgpu_intr_thread_stall(g); | ||
349 | } | ||
350 | |||
351 | static int nvgpu_pci_init_support(struct pci_dev *pdev) | ||
352 | { | ||
353 | int err = 0; | ||
354 | struct gk20a *g = get_gk20a(&pdev->dev); | ||
355 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
356 | |||
357 | l->regs = ioremap(pci_resource_start(pdev, 0), | ||
358 | pci_resource_len(pdev, 0)); | ||
359 | if (IS_ERR(l->regs)) { | ||
360 | nvgpu_err(g, "failed to remap gk20a registers"); | ||
361 | err = PTR_ERR(l->regs); | ||
362 | goto fail; | ||
363 | } | ||
364 | |||
365 | l->bar1 = ioremap(pci_resource_start(pdev, 1), | ||
366 | pci_resource_len(pdev, 1)); | ||
367 | if (IS_ERR(l->bar1)) { | ||
368 | nvgpu_err(g, "failed to remap gk20a bar1"); | ||
369 | err = PTR_ERR(l->bar1); | ||
370 | goto fail; | ||
371 | } | ||
372 | |||
373 | #ifdef CONFIG_TEGRA_19x_GPU | ||
374 | t19x_nvgpu_pci_init_support(l); | ||
375 | #endif | ||
376 | |||
377 | return 0; | ||
378 | |||
379 | fail: | ||
380 | return err; | ||
381 | } | ||
382 | |||
383 | static char *nvgpu_pci_devnode(struct device *dev, umode_t *mode) | ||
384 | { | ||
385 | if (mode) | ||
386 | *mode = S_IRUGO | S_IWUGO; | ||
387 | return kasprintf(GFP_KERNEL, "nvgpu-pci/%s", dev_name(dev)); | ||
388 | } | ||
389 | |||
390 | static struct class nvgpu_pci_class = { | ||
391 | .owner = THIS_MODULE, | ||
392 | .name = "nvidia-pci-gpu", | ||
393 | .devnode = nvgpu_pci_devnode, | ||
394 | }; | ||
395 | |||
396 | #ifdef CONFIG_PM | ||
397 | static int nvgpu_pci_pm_runtime_resume(struct device *dev) | ||
398 | { | ||
399 | return gk20a_pm_finalize_poweron(dev); | ||
400 | } | ||
401 | |||
402 | static int nvgpu_pci_pm_runtime_suspend(struct device *dev) | ||
403 | { | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static const struct dev_pm_ops nvgpu_pci_pm_ops = { | ||
408 | .runtime_resume = nvgpu_pci_pm_runtime_resume, | ||
409 | .runtime_suspend = nvgpu_pci_pm_runtime_suspend, | ||
410 | .resume = nvgpu_pci_pm_runtime_resume, | ||
411 | .suspend = nvgpu_pci_pm_runtime_suspend, | ||
412 | }; | ||
413 | #endif | ||
414 | |||
415 | static int nvgpu_pci_pm_init(struct device *dev) | ||
416 | { | ||
417 | #ifdef CONFIG_PM | ||
418 | struct gk20a *g = get_gk20a(dev); | ||
419 | |||
420 | if (!g->can_railgate) { | ||
421 | pm_runtime_disable(dev); | ||
422 | } else { | ||
423 | if (g->railgate_delay) | ||
424 | pm_runtime_set_autosuspend_delay(dev, | ||
425 | g->railgate_delay); | ||
426 | |||
427 | /* | ||
428 | * Runtime PM for PCI devices is disabled by default, | ||
429 | * so we need to enable it first | ||
430 | */ | ||
431 | pm_runtime_use_autosuspend(dev); | ||
432 | pm_runtime_put_noidle(dev); | ||
433 | pm_runtime_allow(dev); | ||
434 | } | ||
435 | #endif | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int nvgpu_pci_probe(struct pci_dev *pdev, | ||
440 | const struct pci_device_id *pent) | ||
441 | { | ||
442 | struct gk20a_platform *platform = NULL; | ||
443 | struct nvgpu_os_linux *l; | ||
444 | struct gk20a *g; | ||
445 | int err; | ||
446 | char nodefmt[64]; | ||
447 | |||
448 | /* make sure driver_data is a sane index */ | ||
449 | if (pent->driver_data >= sizeof(nvgpu_pci_device) / | ||
450 | sizeof(nvgpu_pci_device[0])) { | ||
451 | return -EINVAL; | ||
452 | } | ||
453 | |||
454 | l = kzalloc(sizeof(*l), GFP_KERNEL); | ||
455 | if (!l) { | ||
456 | dev_err(&pdev->dev, "couldn't allocate gk20a support"); | ||
457 | return -ENOMEM; | ||
458 | } | ||
459 | |||
460 | g = &l->g; | ||
461 | nvgpu_init_gk20a(g); | ||
462 | |||
463 | nvgpu_kmem_init(g); | ||
464 | |||
465 | /* Allocate memory to hold platform data*/ | ||
466 | platform = (struct gk20a_platform *)nvgpu_kzalloc( g, | ||
467 | sizeof(struct gk20a_platform)); | ||
468 | if (!platform) { | ||
469 | dev_err(&pdev->dev, "couldn't allocate platform data"); | ||
470 | return -ENOMEM; | ||
471 | } | ||
472 | |||
473 | /* copy detected device data to allocated platform space*/ | ||
474 | memcpy((void *)platform, (void *)&nvgpu_pci_device[pent->driver_data], | ||
475 | sizeof(struct gk20a_platform)); | ||
476 | |||
477 | pci_set_drvdata(pdev, platform); | ||
478 | |||
479 | err = nvgpu_init_enabled_flags(g); | ||
480 | if (err) { | ||
481 | kfree(g); | ||
482 | return err; | ||
483 | } | ||
484 | |||
485 | platform->g = g; | ||
486 | l->dev = &pdev->dev; | ||
487 | |||
488 | err = pci_enable_device(pdev); | ||
489 | if (err) | ||
490 | return err; | ||
491 | pci_set_master(pdev); | ||
492 | |||
493 | g->pci_vendor_id = pdev->vendor; | ||
494 | g->pci_device_id = pdev->device; | ||
495 | g->pci_subsystem_vendor_id = pdev->subsystem_vendor; | ||
496 | g->pci_subsystem_device_id = pdev->subsystem_device; | ||
497 | g->pci_class = (pdev->class >> 8) & 0xFFFFU; // we only want base/sub | ||
498 | g->pci_revision = pdev->revision; | ||
499 | |||
500 | #if defined(CONFIG_PCI_MSI) | ||
501 | err = pci_enable_msi(pdev); | ||
502 | if (err) { | ||
503 | nvgpu_err(g, | ||
504 | "MSI could not be enabled, falling back to legacy"); | ||
505 | g->msi_enabled = false; | ||
506 | } else | ||
507 | g->msi_enabled = true; | ||
508 | #endif | ||
509 | |||
510 | g->irq_stall = pdev->irq; | ||
511 | g->irq_nonstall = pdev->irq; | ||
512 | if (g->irq_stall < 0) | ||
513 | return -ENXIO; | ||
514 | |||
515 | err = devm_request_threaded_irq(&pdev->dev, | ||
516 | g->irq_stall, | ||
517 | nvgpu_pci_isr, | ||
518 | nvgpu_pci_intr_thread, | ||
519 | #if defined(CONFIG_PCI_MSI) | ||
520 | g->msi_enabled ? 0 : | ||
521 | #endif | ||
522 | IRQF_SHARED, "nvgpu", g); | ||
523 | if (err) { | ||
524 | nvgpu_err(g, | ||
525 | "failed to request irq @ %d", g->irq_stall); | ||
526 | return err; | ||
527 | } | ||
528 | disable_irq(g->irq_stall); | ||
529 | |||
530 | err = nvgpu_pci_init_support(pdev); | ||
531 | if (err) | ||
532 | return err; | ||
533 | |||
534 | if (strchr(dev_name(&pdev->dev), '%')) { | ||
535 | nvgpu_err(g, "illegal character in device name"); | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | |||
539 | snprintf(nodefmt, sizeof(nodefmt), | ||
540 | PCI_INTERFACE_NAME, dev_name(&pdev->dev)); | ||
541 | |||
542 | err = nvgpu_probe(g, "gpu_pci", nodefmt, &nvgpu_pci_class); | ||
543 | if (err) | ||
544 | return err; | ||
545 | |||
546 | err = nvgpu_pci_pm_init(&pdev->dev); | ||
547 | if (err) { | ||
548 | nvgpu_err(g, "pm init failed"); | ||
549 | return err; | ||
550 | } | ||
551 | |||
552 | g->mm.has_physical_mode = false; | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static void nvgpu_pci_remove(struct pci_dev *pdev) | ||
558 | { | ||
559 | struct gk20a *g = get_gk20a(&pdev->dev); | ||
560 | struct device *dev = dev_from_gk20a(g); | ||
561 | int err; | ||
562 | |||
563 | /* no support yet for unbind if DGPU is in VGPU mode */ | ||
564 | if (gk20a_gpu_is_virtual(dev)) | ||
565 | return; | ||
566 | |||
567 | gk20a_driver_start_unload(g); | ||
568 | err = nvgpu_quiesce(g); | ||
569 | /* TODO: handle failure to idle */ | ||
570 | WARN(err, "gpu failed to idle during driver removal"); | ||
571 | |||
572 | nvgpu_free_irq(g); | ||
573 | |||
574 | nvgpu_remove(dev, &nvgpu_pci_class); | ||
575 | |||
576 | #if defined(CONFIG_PCI_MSI) | ||
577 | if (g->msi_enabled) | ||
578 | pci_disable_msi(pdev); | ||
579 | else { | ||
580 | /* IRQ does not need to be enabled in MSI as the line is not | ||
581 | * shared | ||
582 | */ | ||
583 | enable_irq(g->irq_stall); | ||
584 | } | ||
585 | #endif | ||
586 | |||
587 | /* free allocated platform data space */ | ||
588 | nvgpu_kfree(g, gk20a_get_platform(&pdev->dev)); | ||
589 | |||
590 | gk20a_get_platform(&pdev->dev)->g = NULL; | ||
591 | gk20a_put(g); | ||
592 | } | ||
593 | |||
594 | static struct pci_driver nvgpu_pci_driver = { | ||
595 | .name = "nvgpu", | ||
596 | .id_table = nvgpu_pci_table, | ||
597 | .probe = nvgpu_pci_probe, | ||
598 | .remove = nvgpu_pci_remove, | ||
599 | #ifdef CONFIG_PM | ||
600 | .driver.pm = &nvgpu_pci_pm_ops, | ||
601 | #endif | ||
602 | }; | ||
603 | |||
604 | int __init nvgpu_pci_init(void) | ||
605 | { | ||
606 | int ret; | ||
607 | |||
608 | ret = class_register(&nvgpu_pci_class); | ||
609 | if (ret) | ||
610 | return ret; | ||
611 | |||
612 | return pci_register_driver(&nvgpu_pci_driver); | ||
613 | } | ||
614 | |||
615 | void __exit nvgpu_pci_exit(void) | ||
616 | { | ||
617 | pci_unregister_driver(&nvgpu_pci_driver); | ||
618 | class_unregister(&nvgpu_pci_class); | ||
619 | } | ||