summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2016-04-15 17:45:35 -0400
committerTerje Bergstrom <tbergstrom@nvidia.com>2016-04-27 11:10:54 -0400
commit6d888006aa7ed87b1589198369180e7e69f9f1d2 (patch)
treee4d324fd0022d99e3956dcfe166ca65981cac5d9
parentec62c649b5338e7608ea82546135e88f443b90a8 (diff)
gpu: nvgpu: Add PCIe device support
Add support for probing PCIe graphics cards. JIRA DNVGPU-7 Change-Id: Iad3d31a1dc0ca6575d8a9916857022cac9181948 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/1127684
-rw-r--r--drivers/gpu/nvgpu/Kconfig8
-rw-r--r--drivers/gpu/nvgpu/Makefile1
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.c12
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h4
-rw-r--r--drivers/gpu/nvgpu/pci.c264
-rw-r--r--drivers/gpu/nvgpu/pci.h27
6 files changed, 313 insertions, 3 deletions
diff --git a/drivers/gpu/nvgpu/Kconfig b/drivers/gpu/nvgpu/Kconfig
index 94173976..127bb3f7 100644
--- a/drivers/gpu/nvgpu/Kconfig
+++ b/drivers/gpu/nvgpu/Kconfig
@@ -91,3 +91,11 @@ config TEGRA_USE_NA_GPCPLL
91 Enable noise aware (NA) mode of GM20b GPCPLL. In this mode PLL output 91 Enable noise aware (NA) mode of GM20b GPCPLL. In this mode PLL output
92 frequency is automatically adjusted when GM20b voltage is fluctuating 92 frequency is automatically adjusted when GM20b voltage is fluctuating
93 because of transient PMIC or power distribution tree noise. 93 because of transient PMIC or power distribution tree noise.
94
95config GK20A_PCI
96 bool "Support PCIe NVIDIA GPUs on nvgpu"
97 depends on PCI && GK20A
98 default y if ARM64
99 default n
100 help
101 Enable support for GPUs on PCIe bus.
diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile
index 8cd5cc7c..57e32006 100644
--- a/drivers/gpu/nvgpu/Makefile
+++ b/drivers/gpu/nvgpu/Makefile
@@ -76,6 +76,7 @@ nvgpu-y := \
76 gm20b/therm_gm20b.o 76 gm20b/therm_gm20b.o
77nvgpu-$(CONFIG_TEGRA_GK20A) += gk20a/platform_gk20a_tegra.o 77nvgpu-$(CONFIG_TEGRA_GK20A) += gk20a/platform_gk20a_tegra.o
78nvgpu-$(CONFIG_SYNC) += gk20a/sync_gk20a.o 78nvgpu-$(CONFIG_SYNC) += gk20a/sync_gk20a.o
79nvgpu-$(CONFIG_GK20A_PCI) += pci.o
79 80
80nvgpu-$(CONFIG_TEGRA_GR_VIRTUALIZATION) += \ 81nvgpu-$(CONFIG_TEGRA_GR_VIRTUALIZATION) += \
81 gk20a/platform_vgpu_tegra.o \ 82 gk20a/platform_vgpu_tegra.o \
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c
index a865b078..7b0db89e 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.c
@@ -62,6 +62,7 @@
62#include "gk20a_allocator.h" 62#include "gk20a_allocator.h"
63#include "hal.h" 63#include "hal.h"
64#include "vgpu/vgpu.h" 64#include "vgpu/vgpu.h"
65#include "pci.h"
65 66
66#define CREATE_TRACE_POINTS 67#define CREATE_TRACE_POINTS
67#include <trace/events/gk20a.h> 68#include <trace/events/gk20a.h>
@@ -601,7 +602,7 @@ static irqreturn_t gk20a_intr_thread_nonstall(int irq, void *dev_id)
601 return g->ops.mc.isr_thread_nonstall(g); 602 return g->ops.mc.isr_thread_nonstall(g);
602} 603}
603 604
604static void gk20a_remove_support(struct device *dev) 605void gk20a_remove_support(struct device *dev)
605{ 606{
606 struct gk20a *g = get_gk20a(dev); 607 struct gk20a *g = get_gk20a(dev);
607 608
@@ -765,7 +766,7 @@ static int gk20a_detect_chip(struct gk20a *g)
765 return gpu_init_hal(g); 766 return gpu_init_hal(g);
766} 767}
767 768
768static int gk20a_pm_finalize_poweron(struct device *dev) 769int gk20a_pm_finalize_poweron(struct device *dev)
769{ 770{
770 struct gk20a *g = get_gk20a(dev); 771 struct gk20a *g = get_gk20a(dev);
771 struct gk20a_platform *platform = gk20a_get_platform(dev); 772 struct gk20a_platform *platform = gk20a_get_platform(dev);
@@ -1326,7 +1327,7 @@ static int gk20a_pm_initialise_domain(struct device *dev)
1326} 1327}
1327#endif 1328#endif
1328 1329
1329static int gk20a_pm_init(struct device *dev) 1330int gk20a_pm_init(struct device *dev)
1330{ 1331{
1331 struct gk20a_platform *platform = dev_get_drvdata(dev); 1332 struct gk20a_platform *platform = dev_get_drvdata(dev);
1332 int err = 0; 1333 int err = 0;
@@ -1764,11 +1765,16 @@ static int __init gk20a_init(void)
1764 if (ret) 1765 if (ret)
1765 return ret; 1766 return ret;
1766 1767
1768 ret = nvgpu_pci_init();
1769 if (ret)
1770 return ret;
1771
1767 return platform_driver_register(&gk20a_driver); 1772 return platform_driver_register(&gk20a_driver);
1768} 1773}
1769 1774
1770static void __exit gk20a_exit(void) 1775static void __exit gk20a_exit(void)
1771{ 1776{
1777 nvgpu_pci_exit();
1772 platform_driver_unregister(&gk20a_driver); 1778 platform_driver_unregister(&gk20a_driver);
1773 class_unregister(&nvgpu_class); 1779 class_unregister(&nvgpu_class);
1774} 1780}
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index 47adcc14..15f838d9 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -1070,4 +1070,8 @@ extern struct class nvgpu_class;
1070 1070
1071#define INTERFACE_NAME "nvhost%s-gpu" 1071#define INTERFACE_NAME "nvhost%s-gpu"
1072 1072
1073int gk20a_pm_init(struct device *dev);
1074int gk20a_pm_finalize_poweron(struct device *dev);
1075void gk20a_remove_support(struct device *dev);
1076
1073#endif /* GK20A_H */ 1077#endif /* GK20A_H */
diff --git a/drivers/gpu/nvgpu/pci.c b/drivers/gpu/nvgpu/pci.c
new file mode 100644
index 00000000..bc8cb510
--- /dev/null
+++ b/drivers/gpu/nvgpu/pci.c
@@ -0,0 +1,264 @@
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
17#include <linux/pci.h>
18#include <linux/interrupt.h>
19#include <linux/pm_runtime.h>
20#include "pci.h"
21#include "gk20a/gk20a.h"
22#include "gk20a/platform_gk20a.h"
23
24#define PCI_INTERFACE_NAME "nvgpu-pci%s"
25
26static int nvgpu_pci_tegra_probe(struct device *dev)
27{
28 return 0;
29}
30
31static int nvgpu_pci_tegra_remove(struct device *dev)
32{
33 return 0;
34}
35
36static bool nvgpu_pci_tegra_is_railgated(struct device *pdev)
37{
38 return false;
39}
40
41static int nvgpu_pci_busy(struct device *dev)
42{
43 struct gk20a *g = get_gk20a(dev);
44 int err = 0;
45
46 if (!g->power_on)
47 err = gk20a_pm_finalize_poweron(dev);
48
49 return err;
50}
51
52struct gk20a_platform nvgpu_pci_device = {
53 /* ptimer src frequency in hz */
54 .ptimer_src_freq = 31250000,
55
56 .probe = nvgpu_pci_tegra_probe,
57 .remove = nvgpu_pci_tegra_remove,
58 .busy = nvgpu_pci_busy,
59
60 /* power management callbacks */
61 .is_railgated = nvgpu_pci_tegra_is_railgated,
62
63 .default_big_page_size = SZ_64K,
64};
65
66static struct pci_device_id nvgpu_pci_table[] = {
67 {
68 PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
69 .class = PCI_BASE_CLASS_DISPLAY << 16,
70 .class_mask = 0xff << 16,
71 },
72 {}
73};
74
75static irqreturn_t nvgpu_pci_isr(int irq, void *dev_id)
76{
77 struct gk20a *g = dev_id;
78 irqreturn_t ret_stall;
79 irqreturn_t ret_nonstall;
80
81 ret_stall = g->ops.mc.isr_stall(g);
82 ret_nonstall = g->ops.mc.isr_nonstall(g);
83
84 return (ret_stall == IRQ_NONE && ret_nonstall == IRQ_NONE) ?
85 IRQ_NONE : IRQ_WAKE_THREAD;
86}
87
88static irqreturn_t nvgpu_pci_intr_thread(int irq, void *dev_id)
89{
90 struct gk20a *g = dev_id;
91
92 g->ops.mc.isr_thread_stall(g);
93 g->ops.mc.isr_thread_nonstall(g);
94
95 return IRQ_HANDLED;
96}
97
98static int nvgpu_pci_init_support(struct pci_dev *pdev)
99{
100 int err = 0;
101 struct gk20a *g = get_gk20a(&pdev->dev);
102
103 g->regs = ioremap(pci_resource_start(pdev, 0),
104 pci_resource_len(pdev, 0));
105 if (IS_ERR(g->regs)) {
106 gk20a_err(dev_from_gk20a(g), "failed to remap gk20a registers");
107 err = PTR_ERR(g->regs);
108 goto fail;
109 }
110
111 g->bar1 = ioremap(pci_resource_start(pdev, 1),
112 pci_resource_len(pdev, 1));
113 if (IS_ERR(g->bar1)) {
114 gk20a_err(dev_from_gk20a(g), "failed to remap gk20a bar1");
115 err = PTR_ERR(g->regs);
116 goto fail;
117 }
118
119 g->regs_saved = g->regs;
120 g->bar1_saved = g->bar1;
121
122 mutex_init(&g->dbg_sessions_lock);
123 mutex_init(&g->client_lock);
124 mutex_init(&g->ch_wdt_lock);
125 mutex_init(&g->poweroff_lock);
126
127 g->remove_support = gk20a_remove_support;
128 return 0;
129
130 fail:
131 gk20a_remove_support(&pdev->dev);
132 return err;
133}
134
135static int nvgpu_pci_probe(struct pci_dev *pdev,
136 const struct pci_device_id *pent)
137{
138 struct gk20a_platform *platform = &nvgpu_pci_device;
139 struct gk20a *g;
140 int err;
141
142 pci_set_drvdata(pdev, platform);
143
144 g = kzalloc(sizeof(struct gk20a), GFP_KERNEL);
145 if (!g) {
146 gk20a_err(&pdev->dev, "couldn't allocate gk20a support");
147 return -ENOMEM;
148 }
149
150 init_waitqueue_head(&g->sw_irq_stall_last_handled_wq);
151 init_waitqueue_head(&g->sw_irq_nonstall_last_handled_wq);
152
153 platform->g = g;
154 g->dev = &pdev->dev;
155
156 err = pci_enable_device(pdev);
157 if (err)
158 return err;
159 pci_set_master(pdev);
160
161 g->irq_stall = pdev->irq;
162 g->irq_nonstall = pdev->irq;
163 if (g->irq_stall < 0)
164 return -ENXIO;
165 err = devm_request_threaded_irq(&pdev->dev,
166 g->irq_stall,
167 nvgpu_pci_isr,
168 nvgpu_pci_intr_thread,
169 IRQF_SHARED, "nvgpu", g);
170 if (err) {
171 gk20a_err(&pdev->dev,
172 "failed to request irq @ %d", g->irq_stall);
173 return err;
174 }
175 disable_irq(g->irq_stall);
176
177 err = gk20a_user_init(&pdev->dev, PCI_INTERFACE_NAME);
178 if (err)
179 return err;
180
181 err = nvgpu_pci_init_support(pdev);
182 if (err)
183 return err;
184
185 init_rwsem(&g->busy_lock);
186 mutex_init(&platform->railgate_lock);
187
188 spin_lock_init(&g->mc_enable_lock);
189
190 gk20a_debug_init(&pdev->dev);
191
192 /* Initialize the platform interface. */
193 err = platform->probe(&pdev->dev);
194 if (err) {
195 gk20a_err(&pdev->dev, "platform probe failed");
196 return err;
197 }
198
199 /* Set DMA parameters to allow larger sgt lists */
200 pdev->dev.dma_parms = &g->dma_parms;
201 dma_set_max_seg_size(&pdev->dev, UINT_MAX);
202
203 g->gr_idle_timeout_default =
204 CONFIG_GK20A_DEFAULT_TIMEOUT;
205 if (tegra_platform_is_silicon())
206 g->timeouts_enabled = true;
207
208 g->runlist_interleave = true;
209
210 g->timeslice_low_priority_us = 1300;
211 g->timeslice_medium_priority_us = 2600;
212 g->timeslice_high_priority_us = 5200;
213
214 gk20a_create_sysfs(&pdev->dev);
215
216 g->mm.has_physical_mode = false;
217 g->mm.vidmem_is_vidmem = true;
218 g->mm.ltc_enabled = true;
219 g->mm.ltc_enabled_debug = true;
220 g->mm.bypass_smmu = platform->bypass_smmu;
221 g->mm.disable_bigpage = platform->disable_bigpage;
222
223 gk20a_init_gr(g);
224
225 return 0;
226}
227
228static void nvgpu_pci_remove(struct pci_dev *pdev)
229{
230 struct gk20a_platform *platform = gk20a_get_platform(&pdev->dev);
231 struct gk20a *g = get_gk20a(&pdev->dev);
232
233 if (g->remove_support)
234 g->remove_support(g->dev);
235
236 gk20a_user_deinit(g->dev);
237
238 debugfs_remove_recursive(platform->debugfs);
239 debugfs_remove_recursive(platform->debugfs_alias);
240
241 gk20a_remove_sysfs(g->dev);
242
243 if (platform->remove)
244 platform->remove(g->dev);
245
246 kfree(g);
247}
248
249static struct pci_driver nvgpu_pci_driver = {
250 .name = "nvgpu",
251 .id_table = nvgpu_pci_table,
252 .probe = nvgpu_pci_probe,
253 .remove = nvgpu_pci_remove,
254};
255
256int __init nvgpu_pci_init(void)
257{
258 return pci_register_driver(&nvgpu_pci_driver);
259}
260
261void __exit nvgpu_pci_exit(void)
262{
263 pci_unregister_driver(&nvgpu_pci_driver);
264}
diff --git a/drivers/gpu/nvgpu/pci.h b/drivers/gpu/nvgpu/pci.h
new file mode 100644
index 00000000..cc6b77b1
--- /dev/null
+++ b/drivers/gpu/nvgpu/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
20int nvgpu_pci_init(void);
21void nvgpu_pci_exit(void);
22#else
23static inline int nvgpu_pci_init(void) { return 0; }
24static inline void nvgpu_pci_exit(void) {}
25#endif
26
27#endif