radeon_pci.c revision 1.1 1 /* $NetBSD: radeon_pci.c,v 1.1 2014/07/16 20:59:58 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2014 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: radeon_pci.c,v 1.1 2014/07/16 20:59:58 riastradh Exp $");
34
35 #ifdef _KERNEL_OPT
36 #include "vga.h"
37 #endif
38
39 #include <sys/types.h>
40 #include <sys/queue.h>
41 #include <sys/systm.h>
42 #include <sys/workqueue.h>
43
44 #include <dev/pci/pciio.h>
45 #include <dev/pci/pcireg.h>
46 #include <dev/pci/pcivar.h>
47
48 #include <dev/pci/wsdisplay_pci.h>
49 #include <dev/wsfb/genfbvar.h>
50
51 #if NVGA > 0
52 /*
53 * XXX All we really need is vga_is_console from vgavar.h, but the
54 * header files are missing their own dependencies, so we need to
55 * explicitly drag in the other crap.
56 */
57 #include <dev/ic/mc6845reg.h>
58 #include <dev/ic/pcdisplayvar.h>
59 #include <dev/ic/vgareg.h>
60 #include <dev/ic/vgavar.h>
61 #endif
62
63 #include <drm/drmP.h>
64 #include <drm/drm_fb_helper.h>
65
66 #include <radeon.h>
67 #include "radeon_drv.h"
68
69 struct radeon_genfb_work;
70 SIMPLEQ_HEAD(radeon_genfb_work_head, radeon_genfb_work);
71
72 struct radeon_softc {
73 device_t sc_dev;
74 struct workqueue *sc_genfb_wq;
75 struct radeon_genfb_work_head sc_genfb_work;
76 struct drm_device *sc_drm_dev;
77 struct pci_dev sc_pci_dev;
78 };
79
80 struct radeon_genfb_work {
81 struct drm_fb_helper *rgw_fb_helper;
82 union {
83 SIMPLEQ_ENTRY(radeon_genfb_work) queue;
84 struct work work;
85 } rgw_u;
86 };
87
88 static bool radeon_pci_lookup(const struct pci_attach_args *,
89 unsigned long *);
90
91 static int radeon_match(device_t, cfdata_t, void *);
92 static void radeon_attach(device_t, device_t, void *);
93 static int radeon_detach(device_t, int);
94
95 static void radeon_genfb_defer_set_config(struct drm_fb_helper *);
96 static void radeon_genfb_set_config_work(struct work *, void *);
97 static void radeon_genfb_set_config(struct radeon_genfb_work *);
98 static int radeon_genfb_ioctl(void *, void *, unsigned long, void *,
99 int, struct lwp *);
100 static paddr_t radeon_genfb_mmap(void *, void *, off_t, int);
101
102 CFATTACH_DECL_NEW(radeondrmkms, sizeof(struct radeon_softc),
103 radeon_match, radeon_attach, radeon_detach, NULL);
104
105 /* XXX Kludge to get these from radeon_drv.c. */
106 extern struct drm_driver *const radeon_drm_driver;
107 extern const struct pci_device_id *const radeon_device_ids;
108 extern const size_t radeon_n_device_ids;
109
110 static bool
111 radeon_pci_lookup(const struct pci_attach_args *pa, unsigned long *flags)
112 {
113 size_t i;
114
115 for (i = 0; i < radeon_n_device_ids; i++) {
116 if ((PCI_VENDOR(pa->pa_id) == radeon_device_ids[i].vendor) &&
117 (PCI_PRODUCT(pa->pa_id) == radeon_device_ids[i].device))
118 break;
119 }
120
121 /* Did we find it? */
122 if (i == radeon_n_device_ids)
123 return false;
124
125 if (flags)
126 *flags = radeon_device_ids[i].driver_data;
127 return true;
128 }
129
130 static int
131 radeon_match(device_t parent, cfdata_t match, void *aux)
132 {
133 extern int radeon_guarantee_initialized(void);
134 const struct pci_attach_args *const pa = aux;
135 int error;
136
137 error = radeon_guarantee_initialized();
138 if (error) {
139 aprint_error("radeon: failed to initialize: %d\n", error);
140 return 0;
141 }
142
143 if (!radeon_pci_lookup(pa, NULL))
144 return 0;
145
146 return 6; /* XXX Beat genfb_pci... */
147 }
148
149 static void
150 radeon_attach(device_t parent, device_t self, void *aux)
151 {
152 struct radeon_softc *const sc = device_private(self);
153 const struct pci_attach_args *const pa = aux;
154 bool ok __diagused;
155 unsigned long flags;
156 int error;
157
158 ok = radeon_pci_lookup(pa, &flags);
159 KASSERT(ok);
160
161 sc->sc_dev = self;
162
163 pci_aprint_devinfo(pa, NULL);
164
165 SIMPLEQ_INIT(&sc->sc_genfb_work);
166
167 /* XXX errno Linux->NetBSD */
168 error = -drm_pci_attach(self, pa, &sc->sc_pci_dev, radeon_drm_driver,
169 flags, &sc->sc_drm_dev);
170 if (error) {
171 aprint_error_dev(self, "unable to attach drm: %d\n", error);
172 return;
173 }
174
175 while (!SIMPLEQ_EMPTY(&sc->sc_genfb_work)) {
176 struct radeon_genfb_work *const work =
177 SIMPLEQ_FIRST(&sc->sc_genfb_work);
178
179 SIMPLEQ_REMOVE_HEAD(&sc->sc_genfb_work, rgw_u.queue);
180 radeon_genfb_set_config(work);
181 }
182
183 error = workqueue_create(&sc->sc_genfb_wq, "radeonfb",
184 &radeon_genfb_set_config_work, NULL, PRI_NONE, IPL_NONE,
185 WQ_MPSAFE);
186 if (error) {
187 aprint_error_dev(self, "unable to create workqueue: %d\n",
188 error);
189 return;
190 }
191 }
192
193 static int
194 radeon_detach(device_t self, int flags)
195 {
196 struct radeon_softc *const sc = device_private(self);
197 int error;
198
199 /* XXX Check for in-use before tearing it all down... */
200 error = config_detach_children(self, flags);
201 if (error)
202 return error;
203
204 if (sc->sc_genfb_wq == NULL)
205 return 0;
206 workqueue_destroy(sc->sc_genfb_wq);
207
208 if (sc->sc_drm_dev == NULL)
209 return 0;
210 /* XXX errno Linux->NetBSD */
211 error = -drm_pci_detach(sc->sc_drm_dev, flags);
212 if (error)
213 return error;
214
215 return 0;
216 }
217
218 int
219 radeon_genfb_attach(struct drm_device *dev, struct drm_fb_helper *helper,
220 const struct drm_fb_helper_surface_size *sizes, struct radeon_bo *rbo)
221 {
222 struct radeon_softc *const sc = container_of(dev->pdev,
223 struct radeon_softc, sc_pci_dev);
224 static const struct genfb_ops zero_genfb_ops;
225 struct genfb_ops genfb_ops = zero_genfb_ops;
226 const prop_dictionary_t dict = device_properties(sc->sc_dev);
227 enum { CONS_VGA, CONS_GENFB, CONS_NONE } what_was_cons;
228 int ret;
229
230 #if NVGA > 0
231 if (vga_is_console(dev->pdev->pd_pa.pa_iot, -1) ||
232 vga_is_console(dev->pdev->pd_pa.pa_iot, -1)) {
233 what_was_cons = CONS_VGA;
234 prop_dictionary_set_bool(dict, "is_console", true);
235 /*
236 * There is a window from here until genfb attaches in
237 * which kernel messages will go into a black hole,
238 * until genfb replays the console. Whattakludge.
239 *
240 * wsdisplay_cndetach must come first, to clear cn_tab,
241 * so that nothing will use it; then vga_cndetach
242 * unmaps the bus space that it would have used.
243 */
244 wsdisplay_cndetach();
245 vga_cndetach();
246 } else
247 #endif
248 if (genfb_is_console() && genfb_is_enabled()) {
249 what_was_cons = CONS_GENFB;
250 prop_dictionary_set_bool(dict, "is_console", true);
251 } else {
252 what_was_cons = CONS_NONE;
253 prop_dictionary_set_bool(dict, "is_console", false);
254 }
255
256 /* XXX Ugh... Pass these parameters some other way! */
257 prop_dictionary_set_uint32(dict, "width", sizes->fb_width);
258 prop_dictionary_set_uint32(dict, "height", sizes->fb_height);
259 prop_dictionary_set_uint8(dict, "depth", sizes->surface_bpp);
260 prop_dictionary_set_uint16(dict, "linebytes",
261 roundup2((sizes->fb_width * howmany(sizes->surface_bpp, 8)), 64));
262 prop_dictionary_set_uint32(dict, "address", 0); /* XXX >32-bit */
263 CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
264 prop_dictionary_set_uint64(dict, "virtual_address",
265 (uint64_t)(uintptr_t)rbo->kptr);
266
267 helper->genfb.sc_dev = sc->sc_dev;
268 genfb_init(&helper->genfb);
269 genfb_ops.genfb_ioctl = radeon_genfb_ioctl;
270 genfb_ops.genfb_mmap = radeon_genfb_mmap;
271
272 /* XXX errno NetBSD->Linux */
273 ret = -genfb_attach(&helper->genfb, &genfb_ops);
274 if (ret) {
275 DRM_ERROR("failed to attach genfb: %d\n", ret);
276 switch (what_was_cons) { /* XXX Restore console... */
277 case CONS_VGA: break;
278 case CONS_GENFB: break;
279 case CONS_NONE: break;
280 default: break;
281 }
282 return ret;
283 }
284
285 radeon_genfb_defer_set_config(helper);
286
287 return 0;
288 }
289
290 static void
291 radeon_genfb_defer_set_config(struct drm_fb_helper *helper)
292 {
293 struct drm_device *const dev = helper->dev;
294 struct radeon_softc *const sc = container_of(dev->pdev,
295 struct radeon_softc, sc_pci_dev);
296 struct radeon_genfb_work *work;
297
298 /* Really shouldn't sleep here... */
299 work = kmem_alloc(sizeof(*work), KM_SLEEP);
300 work->rgw_fb_helper = helper;
301
302 if (sc->sc_genfb_wq == NULL) /* during attachment */
303 SIMPLEQ_INSERT_TAIL(&sc->sc_genfb_work, work, rgw_u.queue);
304 else
305 workqueue_enqueue(sc->sc_genfb_wq, &work->rgw_u.work, NULL);
306 }
307
308 static void
309 radeon_genfb_set_config_work(struct work *work, void *cookie __unused)
310 {
311
312 radeon_genfb_set_config(container_of(work, struct radeon_genfb_work,
313 rgw_u.work));
314 }
315
316 static void
317 radeon_genfb_set_config(struct radeon_genfb_work *work)
318 {
319
320 drm_fb_helper_set_config(work->rgw_fb_helper);
321 kmem_free(work, sizeof(*work));
322 }
323
324 static int
325 radeon_genfb_ioctl(void *v, void *vs, unsigned long cmd, void *data, int flag,
326 struct lwp *l)
327 {
328 struct genfb_softc *const genfb = v;
329 struct drm_fb_helper *const helper = container_of(genfb,
330 struct drm_fb_helper, genfb);
331 struct drm_device *const dev = helper->dev;
332 const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
333
334 switch (cmd) {
335 case WSDISPLAYIO_GTYPE:
336 *(unsigned int *)data = WSDISPLAY_TYPE_PCIVGA;
337 return 0;
338
339 /* PCI config read/write passthrough. */
340 case PCI_IOC_CFGREAD:
341 case PCI_IOC_CFGWRITE:
342 return pci_devioctl(pa->pa_pc, pa->pa_tag, cmd, data, flag, l);
343
344 case WSDISPLAYIO_GET_BUSID:
345 return wsdisplayio_busid_pci(genfb->sc_dev,
346 pa->pa_pc, pa->pa_tag, data);
347
348 default:
349 return EPASSTHROUGH;
350 }
351 }
352
353 static paddr_t
354 radeon_genfb_mmap(void *v, void *vs, off_t offset, int prot)
355 {
356 struct genfb_softc *const genfb = v;
357 struct drm_fb_helper *const helper = container_of(genfb,
358 struct drm_fb_helper, genfb);
359 struct drm_framebuffer *const fb = helper->fb;
360 struct radeon_framebuffer *const rfb = container_of(fb,
361 struct radeon_framebuffer, base);
362 struct drm_gem_object *const gobj = rfb->obj;
363 struct radeon_bo *const rbo = gem_to_radeon_bo(gobj);
364 struct drm_device *const dev = helper->dev;
365 const struct pci_attach_args *const pa = &dev->pdev->pd_pa;
366 unsigned int i;
367
368 if (offset < 0)
369 return -1;
370
371 /* Treat low memory as the framebuffer itself. */
372 if (offset < genfb->sc_fbsize) {
373 const unsigned num_pages __diagused = rbo->tbo.num_pages;
374 bus_addr_t addr;
375 int flags = 0;
376
377 KASSERT(genfb->sc_fbsize == (num_pages << PAGE_SHIFT));
378 KASSERT(num_pages == rbo->tbo.ttm->num_pages);
379 addr = page_to_phys(rbo->tbo.ttm->pages[offset >> PAGE_SHIFT]);
380 /* XXX CACHEABLE? PREFETCHABLE? WC? WB? */
381 if (ISSET(rbo->tbo.mem.placement, TTM_PL_FLAG_CACHED))
382 flags |= BUS_SPACE_MAP_PREFETCHABLE;
383 /*
384 * XXX Urk. We assume bus_space_mmap can cope with
385 * normal system RAM addresses.
386 */
387 return bus_space_mmap(rbo->tbo.bdev->memt, addr, 0, prot,
388 flags);
389 }
390
391 /* XXX Cargo-culted from genfb_pci. */
392 if (kauth_authorize_machdep(kauth_cred_get(),
393 KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) {
394 aprint_normal_dev(dev->dev, "mmap at %"PRIxMAX" rejected\n",
395 (uintmax_t)offset);
396 return -1;
397 }
398
399 for (i = 0; PCI_BAR(i) <= PCI_MAPREG_ROM; i++) {
400 pcireg_t type;
401 bus_addr_t addr;
402 bus_size_t size;
403 int flags;
404
405 /* Interrogate the BAR. */
406 if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, PCI_BAR(i),
407 &type))
408 continue;
409 if (PCI_MAPREG_TYPE(type) != PCI_MAPREG_TYPE_MEM)
410 continue;
411 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PCI_BAR(i), type,
412 &addr, &size, &flags))
413 continue;
414
415 /* Try to map it if it's in range. */
416 if ((addr <= offset) && (offset < (addr + size)))
417 return bus_space_mmap(pa->pa_memt, addr,
418 (offset - addr), prot, flags);
419
420 /* Skip a slot if this was a 64-bit BAR. */
421 if ((PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) &&
422 (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT))
423 i += 1;
424 }
425
426 /* Failure! */
427 return -1;
428 }
429