nouveau_pci.c revision 1.29 1 /* $NetBSD: nouveau_pci.c,v 1.29 2021/12/19 10:51:59 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: nouveau_pci.c,v 1.29 2021/12/19 10:51:59 riastradh Exp $");
34
35 #ifdef _KERNEL_OPT
36 #if defined(__arm__) || defined(__aarch64__)
37 #include "opt_fdt.h"
38 #endif
39 #endif
40
41 #include <sys/types.h>
42 #include <sys/device.h>
43 #include <sys/queue.h>
44 #include <sys/workqueue.h>
45 #include <sys/module.h>
46
47 #ifdef FDT
48 #include <dev/fdt/fdtvar.h>
49 #endif
50
51 #include <drm/drm_pci.h>
52
53 #include <core/device.h>
54 #include <core/pci.h>
55
56 #include "nouveau_drv.h"
57 #include "nouveau_pci.h"
58
59 struct drm_device;
60
61 MODULE(MODULE_CLASS_DRIVER, nouveau_pci, "nouveau,drmkms_pci");
62
63 SIMPLEQ_HEAD(nouveau_pci_task_head, nouveau_pci_task);
64
65 struct nouveau_pci_softc {
66 device_t sc_dev;
67 struct pci_attach_args sc_pa;
68 enum {
69 NOUVEAU_TASK_ATTACH,
70 NOUVEAU_TASK_WORKQUEUE,
71 } sc_task_state;
72 union {
73 struct workqueue *workqueue;
74 struct nouveau_pci_task_head attach;
75 } sc_task_u;
76 struct drm_device *sc_drm_dev;
77 struct pci_dev sc_pci_dev;
78 struct nvkm_device *sc_nv_dev;
79 };
80
81 static int nouveau_pci_match(device_t, cfdata_t, void *);
82 static void nouveau_pci_attach(device_t, device_t, void *);
83 static void nouveau_pci_attach_real(device_t);
84 static int nouveau_pci_detach(device_t, int);
85
86 static bool nouveau_pci_suspend(device_t, const pmf_qual_t *);
87 static bool nouveau_pci_resume(device_t, const pmf_qual_t *);
88
89 static void nouveau_pci_task_work(struct work *, void *);
90
91 CFATTACH_DECL_NEW(nouveau_pci, sizeof(struct nouveau_pci_softc),
92 nouveau_pci_match, nouveau_pci_attach, nouveau_pci_detach, NULL);
93
94 /* Kludge to get this from nouveau_drm.c. */
95 extern struct drm_driver *const nouveau_drm_driver_pci;
96
97 static int
98 nouveau_pci_match(device_t parent, cfdata_t match, void *aux)
99 {
100 const struct pci_attach_args *const pa = aux;
101 struct pci_dev pdev;
102 struct nvkm_device *device;
103 int ret;
104
105 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NVIDIA &&
106 PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NVIDIA_SGS)
107 return 0;
108
109 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
110 return 0;
111
112 /*
113 * NetBSD drm2 doesn't support Pascal, Volta or Turing based cards:
114 * 0x1580-0x15ff GP100
115 * 0x1b00-0x1b7f GP102
116 * 0x1b80-0x1bff GP104
117 * 0x1c00-0x1c7f GP106
118 * 0x1c80-0x1cff GP107
119 * 0x1d00-0x1d7f GP108
120 * 0x1d80-0x1dff GV100
121 * 0x1e00-0x1e7f TU102
122 * 0x1e80-0x1eff TU104
123 * 0x1f00-0x1f7f TU106
124 * 0x1f80-0x1fff TU117
125 * 0x2180-0x21ff TU116
126 *
127 * reduce this to >= 1580, so that new chipsets not explictly
128 * listed above will be picked up.
129 *
130 * XXX perhaps switch this to explicitly match known list.
131 */
132 if (PCI_PRODUCT(pa->pa_id) >= 0x1580)
133 return 0;
134
135 linux_pci_dev_init(&pdev, parent /* XXX bogus */, parent, pa, 0);
136 ret = nvkm_device_pci_new(&pdev, NULL, "error",
137 /* detect */ true, /* mmio */ false, /* subdev_mask */ 0, &device);
138 if (ret == 0) /* don't want to hang onto it */
139 nvkm_device_del(&device);
140 linux_pci_dev_destroy(&pdev);
141 if (ret) /* failure */
142 return 0;
143
144 return 6; /* XXX Beat genfb_pci... */
145 }
146
147 extern char *nouveau_config;
148 extern char *nouveau_debug;
149
150 static void
151 nouveau_pci_attach(device_t parent, device_t self, void *aux)
152 {
153 struct nouveau_pci_softc *const sc = device_private(self);
154 const struct pci_attach_args *const pa = aux;
155
156 pci_aprint_devinfo(pa, NULL);
157
158 if (!pmf_device_register(self, &nouveau_pci_suspend, &nouveau_pci_resume))
159 aprint_error_dev(self, "unable to establish power handler\n");
160
161 /*
162 * Trivial initialization first; the rest will come after we
163 * have mounted the root file system and can load firmware
164 * images.
165 */
166 sc->sc_dev = NULL;
167 sc->sc_pa = *pa;
168
169 #ifdef FDT
170 /*
171 * XXX Remove the simple framebuffer, assuming that this device
172 * will take over.
173 */
174 const char *fb_compatible[] = { "simple-framebuffer", NULL };
175 fdt_remove_bycompat(fb_compatible);
176 #endif
177
178 config_mountroot(self, &nouveau_pci_attach_real);
179 }
180
181 static void
182 nouveau_pci_attach_real(device_t self)
183 {
184 struct nouveau_pci_softc *const sc = device_private(self);
185 const struct pci_attach_args *const pa = &sc->sc_pa;
186 int error;
187
188 sc->sc_dev = self;
189 sc->sc_task_state = NOUVEAU_TASK_ATTACH;
190 SIMPLEQ_INIT(&sc->sc_task_u.attach);
191
192 /* Initialize the Linux PCI device descriptor. */
193 linux_pci_dev_init(&sc->sc_pci_dev, self, device_parent(self), pa, 0);
194
195 /* XXX errno Linux->NetBSD */
196 error = -nvkm_device_pci_new(&sc->sc_pci_dev,
197 nouveau_config, nouveau_debug,
198 /* detect */ true, /* mmio */ true, /* subdev_mask */ ~0ULL,
199 &sc->sc_nv_dev);
200 if (error) {
201 aprint_error_dev(self, "unable to create nouveau device: %d\n",
202 error);
203 return;
204 }
205
206 /* XXX errno Linux->NetBSD */
207 error = -drm_pci_attach(self, pa, &sc->sc_pci_dev,
208 nouveau_drm_driver_pci, 0, &sc->sc_drm_dev);
209 if (error) {
210 aprint_error_dev(self, "unable to attach drm: %d\n", error);
211 return;
212 }
213
214 while (!SIMPLEQ_EMPTY(&sc->sc_task_u.attach)) {
215 struct nouveau_pci_task *const task =
216 SIMPLEQ_FIRST(&sc->sc_task_u.attach);
217
218 SIMPLEQ_REMOVE_HEAD(&sc->sc_task_u.attach, nt_u.queue);
219 (*task->nt_fn)(task);
220 }
221
222 sc->sc_task_state = NOUVEAU_TASK_WORKQUEUE;
223 error = workqueue_create(&sc->sc_task_u.workqueue, "nouveau_pci",
224 &nouveau_pci_task_work, NULL, PRI_NONE, IPL_NONE, WQ_MPSAFE);
225 if (error) {
226 aprint_error_dev(self, "unable to create workqueue: %d\n",
227 error);
228 sc->sc_task_u.workqueue = NULL;
229 return;
230 }
231 }
232
233 static int
234 nouveau_pci_detach(device_t self, int flags)
235 {
236 struct nouveau_pci_softc *const sc = device_private(self);
237 int error;
238
239 if (sc->sc_dev == NULL)
240 /* Not done attaching. */
241 return EBUSY;
242
243 /* XXX Check for in-use before tearing it all down... */
244 error = config_detach_children(self, flags);
245 if (error)
246 return error;
247
248 if (sc->sc_task_state == NOUVEAU_TASK_ATTACH)
249 goto out0;
250 if (sc->sc_task_u.workqueue != NULL) {
251 workqueue_destroy(sc->sc_task_u.workqueue);
252 sc->sc_task_u.workqueue = NULL;
253 }
254
255 if (sc->sc_nv_dev == NULL)
256 goto out0;
257
258 if (sc->sc_drm_dev == NULL)
259 goto out1;
260 /* XXX errno Linux->NetBSD */
261 error = -drm_pci_detach(sc->sc_drm_dev, flags);
262 if (error)
263 /* XXX Kinda too late to fail now... */
264 return error;
265 sc->sc_drm_dev = NULL;
266
267 out1: nvkm_device_del(&sc->sc_nv_dev);
268 out0: linux_pci_dev_destroy(&sc->sc_pci_dev);
269 pmf_device_deregister(self);
270 return 0;
271 }
272
273 /*
274 * XXX Synchronize with nouveau_do_suspend in nouveau_drm.c.
275 */
276 static bool
277 nouveau_pci_suspend(device_t self, const pmf_qual_t *qual __unused)
278 {
279 struct nouveau_pci_softc *const sc = device_private(self);
280
281 return nouveau_pmops_suspend(sc->sc_drm_dev) == 0;
282 }
283
284 static bool
285 nouveau_pci_resume(device_t self, const pmf_qual_t *qual)
286 {
287 struct nouveau_pci_softc *const sc = device_private(self);
288
289 return nouveau_pmops_resume(sc->sc_drm_dev) == 0;
290 }
291
292 static void
293 nouveau_pci_task_work(struct work *work, void *cookie __unused)
294 {
295 struct nouveau_pci_task *const task = container_of(work,
296 struct nouveau_pci_task, nt_u.work);
297
298 (*task->nt_fn)(task);
299 }
300
301 int
302 nouveau_pci_task_schedule(device_t self, struct nouveau_pci_task *task)
303 {
304 struct nouveau_pci_softc *const sc = device_private(self);
305
306 switch (sc->sc_task_state) {
307 case NOUVEAU_TASK_ATTACH:
308 SIMPLEQ_INSERT_TAIL(&sc->sc_task_u.attach, task, nt_u.queue);
309 return 0;
310 case NOUVEAU_TASK_WORKQUEUE:
311 if (sc->sc_task_u.workqueue == NULL) {
312 aprint_error_dev(self, "unable to schedule task\n");
313 return EIO;
314 }
315 workqueue_enqueue(sc->sc_task_u.workqueue, &task->nt_u.work,
316 NULL);
317 return 0;
318 default:
319 panic("nouveau in invalid task state: %d\n",
320 (int)sc->sc_task_state);
321 }
322 }
323
324 extern struct drm_driver *const nouveau_drm_driver_stub; /* XXX */
325 extern struct drm_driver *const nouveau_drm_driver_pci; /* XXX */
326
327 static int
328 nouveau_pci_modcmd(modcmd_t cmd, void *arg __unused)
329 {
330
331 switch (cmd) {
332 case MODULE_CMD_INIT:
333 *nouveau_drm_driver_pci = *nouveau_drm_driver_stub;
334 nouveau_drm_driver_pci->set_busid = drm_pci_set_busid;
335 nouveau_drm_driver_pci->request_irq = drm_pci_request_irq;
336 nouveau_drm_driver_pci->free_irq = drm_pci_free_irq;
337 #if 0 /* XXX nouveau acpi */
338 nouveau_register_dsm_handler();
339 #endif
340 break;
341 case MODULE_CMD_FINI:
342 #if 0 /* XXX nouveau acpi */
343 nouveau_unregister_dsm_handler();
344 #endif
345 break;
346 default:
347 return ENOTTY;
348 }
349
350 return 0;
351 }
352