summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/pci.c
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 /drivers/gpu/nvgpu/pci.c
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
Diffstat (limited to 'drivers/gpu/nvgpu/pci.c')
-rw-r--r--drivers/gpu/nvgpu/pci.c264
1 files changed, 264 insertions, 0 deletions
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}