Home | History | Annotate | Line # | Download | only in radeon
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