Module Name: src Committed By: riastradh Date: Fri Jul 25 12:35:03 UTC 2014
Modified Files: src/sys/arch/amd64/conf: DRMKMS src/sys/arch/i386/conf: DRMKMS src/sys/external/bsd/drm2/radeon: files.radeon radeon_pci.c Added Files: src/sys/external/bsd/drm2/radeon: radeon_task.h radeondrmkmsfb.c radeondrmkmsfb.h Log Message: Hook up radeondrmkmsfb code. Builds, not testable yet. To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/sys/arch/amd64/conf/DRMKMS cvs rdiff -u -r1.3 -r1.4 src/sys/arch/i386/conf/DRMKMS cvs rdiff -u -r1.2 -r1.3 src/sys/external/bsd/drm2/radeon/files.radeon cvs rdiff -u -r1.1 -r1.2 src/sys/external/bsd/drm2/radeon/radeon_pci.c cvs rdiff -u -r0 -r1.1 src/sys/external/bsd/drm2/radeon/radeon_task.h \ src/sys/external/bsd/drm2/radeon/radeondrmkmsfb.c \ src/sys/external/bsd/drm2/radeon/radeondrmkmsfb.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/amd64/conf/DRMKMS diff -u src/sys/arch/amd64/conf/DRMKMS:1.5 src/sys/arch/amd64/conf/DRMKMS:1.6 --- src/sys/arch/amd64/conf/DRMKMS:1.5 Thu Jul 24 21:18:40 2014 +++ src/sys/arch/amd64/conf/DRMKMS Fri Jul 25 12:35:03 2014 @@ -2,11 +2,19 @@ include "arch/amd64/conf/NO_DRM" i915drmkms* at pci? dev ? function ? intelfb* at intelfbbus? + +radeondrmkms* at pci? dev ? function ? +radeondrmkmsfb* at radeonfbbus? + #nouveau* at pci? dev ? function ? -#radeondrmkms* at pci? dev ? function ? +#nouveaufb* at nouveaufbbus no options DIAGNOSTIC options DIAGNOSTIC # expensive kernel consistency check options DEBUG # expensive debugging checks/support options LOCKDEBUG # debug locks makeoptions DEBUG="-g" # compile full symbol table + +#options ACPIVERBOSE # verbose ACPI device autoconfig messages +options PCIVERBOSE # verbose PCI device autoconfig messages +options USBVERBOSE # verbose USB device autoconfig messages Index: src/sys/arch/i386/conf/DRMKMS diff -u src/sys/arch/i386/conf/DRMKMS:1.3 src/sys/arch/i386/conf/DRMKMS:1.4 --- src/sys/arch/i386/conf/DRMKMS:1.3 Fri Jul 25 11:51:21 2014 +++ src/sys/arch/i386/conf/DRMKMS Fri Jul 25 12:35:03 2014 @@ -3,6 +3,12 @@ include "arch/i386/conf/NO_DRM" i915drmkms* at pci? dev ? function ? intelfb* at intelfbbus? +radeondrmkms* at pci? dev ? function ? +radeondrmkmsfb* at radeonfbbus? + +#nouveau* at pci? dev ? function ? +#nouveaufb* at nouveaufbbus + no options DIAGNOSTIC options DIAGNOSTIC # expensive kernel consistency check options DEBUG # expensive debugging checks/support Index: src/sys/external/bsd/drm2/radeon/files.radeon diff -u src/sys/external/bsd/drm2/radeon/files.radeon:1.2 src/sys/external/bsd/drm2/radeon/files.radeon:1.3 --- src/sys/external/bsd/drm2/radeon/files.radeon:1.2 Thu Jul 17 14:05:12 2014 +++ src/sys/external/bsd/drm2/radeon/files.radeon Fri Jul 25 12:35:03 2014 @@ -1,10 +1,16 @@ -# $NetBSD: files.radeon,v 1.2 2014/07/17 14:05:12 riastradh Exp $ +# $NetBSD: files.radeon,v 1.3 2014/07/25 12:35:03 riastradh Exp $ -device radeondrmkms: drmkms, drmkms_pci, drmkms_ttm, genfb, wsemuldisplaydev +define radeonfbbus { } +device radeondrmkms: drmkms, drmkms_pci, drmkms_ttm, radeonfbbus attach radeondrmkms at pci +# XXX Rename this to radeonfb when the legacy radeonfb(4) is gone. +device radeondrmkmsfb: radeonfbbus, genfb, wsemuldisplaydev +attach radeondrmkmsfb at radeonfbbus + makeoptions radeondrmkms CPPFLAGS+="-I$S/external/bsd/drm2/dist/drm/radeon" makeoptions radeondrmkms CPPFLAGS+="-I$S/external/bsd/drm2/include/radeon" +makeoptions radeondrmkms CPPFLAGS+="-I$S/external/bsd/drm2/radeon" makeoptions radeondrmkms "CWARNFLAGS.atombios_encoders.c"+="-Wno-missing-prototypes" makeoptions radeondrmkms "CWARNFLAGS.atombios_i2c.c"+="-Wno-missing-prototypes" @@ -154,3 +160,5 @@ file external/bsd/drm2/dist/drm/radeon/v file external/bsd/drm2/radeon/radeon_module.c radeondrmkms file external/bsd/drm2/radeon/radeon_pci.c radeondrmkms + +file external/bsd/drm2/radeon/radeondrmkmsfb.c radeondrmkmsfb Index: src/sys/external/bsd/drm2/radeon/radeon_pci.c diff -u src/sys/external/bsd/drm2/radeon/radeon_pci.c:1.1 src/sys/external/bsd/drm2/radeon/radeon_pci.c:1.2 --- src/sys/external/bsd/drm2/radeon/radeon_pci.c:1.1 Wed Jul 16 20:59:58 2014 +++ src/sys/external/bsd/drm2/radeon/radeon_pci.c Fri Jul 25 12:35:03 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: radeon_pci.c,v 1.1 2014/07/16 20:59:58 riastradh Exp $ */ +/* $NetBSD: radeon_pci.c,v 1.2 2014/07/25 12:35:03 riastradh Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: radeon_pci.c,v 1.1 2014/07/16 20:59:58 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: radeon_pci.c,v 1.2 2014/07/25 12:35:03 riastradh Exp $"); #ifdef _KERNEL_OPT #include "vga.h" @@ -65,25 +65,31 @@ __KERNEL_RCSID(0, "$NetBSD: radeon_pci.c #include <radeon.h> #include "radeon_drv.h" +#include "radeon_task.h" -struct radeon_genfb_work; -SIMPLEQ_HEAD(radeon_genfb_work_head, radeon_genfb_work); +SIMPLEQ_HEAD(radeon_task_head, radeon_task); struct radeon_softc { device_t sc_dev; - struct workqueue *sc_genfb_wq; - struct radeon_genfb_work_head sc_genfb_work; + enum { + RADEON_TASK_ATTACH, + RADEON_TASK_WORKQUEUE, + } sc_task_state; + union { + struct workqueue *workqueue; + struct radeon_task_head attach; + } sc_task_u; struct drm_device *sc_drm_dev; struct pci_dev sc_pci_dev; }; -struct radeon_genfb_work { - struct drm_fb_helper *rgw_fb_helper; - union { - SIMPLEQ_ENTRY(radeon_genfb_work) queue; - struct work work; - } rgw_u; -}; +struct radeon_device * +radeon_device_private(device_t self) +{ + struct radeon_softc *const sc = device_private(self); + + return sc->sc_drm_dev->dev_private; +} static bool radeon_pci_lookup(const struct pci_attach_args *, unsigned long *); @@ -92,12 +98,7 @@ static int radeon_match(device_t, cfdata static void radeon_attach(device_t, device_t, void *); static int radeon_detach(device_t, int); -static void radeon_genfb_defer_set_config(struct drm_fb_helper *); -static void radeon_genfb_set_config_work(struct work *, void *); -static void radeon_genfb_set_config(struct radeon_genfb_work *); -static int radeon_genfb_ioctl(void *, void *, unsigned long, void *, - int, struct lwp *); -static paddr_t radeon_genfb_mmap(void *, void *, off_t, int); +static void radeon_task_work(struct work *, void *); CFATTACH_DECL_NEW(radeondrmkms, sizeof(struct radeon_softc), radeon_match, radeon_attach, radeon_detach, NULL); @@ -162,7 +163,8 @@ radeon_attach(device_t parent, device_t pci_aprint_devinfo(pa, NULL); - SIMPLEQ_INIT(&sc->sc_genfb_work); + sc->sc_task_state = RADEON_TASK_ATTACH; + SIMPLEQ_INIT(&sc->sc_task_u.attach); /* XXX errno Linux->NetBSD */ error = -drm_pci_attach(self, pa, &sc->sc_pci_dev, radeon_drm_driver, @@ -172,20 +174,21 @@ radeon_attach(device_t parent, device_t return; } - while (!SIMPLEQ_EMPTY(&sc->sc_genfb_work)) { - struct radeon_genfb_work *const work = - SIMPLEQ_FIRST(&sc->sc_genfb_work); + while (!SIMPLEQ_EMPTY(&sc->sc_task_u.attach)) { + struct radeon_task *const task = + SIMPLEQ_FIRST(&sc->sc_task_u.attach); - SIMPLEQ_REMOVE_HEAD(&sc->sc_genfb_work, rgw_u.queue); - radeon_genfb_set_config(work); + SIMPLEQ_REMOVE_HEAD(&sc->sc_task_u.attach, rt_u.queue); + (*task->rt_fn)(task); } - error = workqueue_create(&sc->sc_genfb_wq, "radeonfb", - &radeon_genfb_set_config_work, NULL, PRI_NONE, IPL_NONE, - WQ_MPSAFE); + sc->sc_task_state = RADEON_TASK_WORKQUEUE; + error = workqueue_create(&sc->sc_task_u.workqueue, "radeonfb", + &radeon_task_work, NULL, PRI_NONE, IPL_NONE, WQ_MPSAFE); if (error) { aprint_error_dev(self, "unable to create workqueue: %d\n", error); + sc->sc_task_u.workqueue = NULL; return; } } @@ -201,228 +204,53 @@ radeon_detach(device_t self, int flags) if (error) return error; - if (sc->sc_genfb_wq == NULL) + if (sc->sc_task_state == RADEON_TASK_ATTACH) return 0; - workqueue_destroy(sc->sc_genfb_wq); + if (sc->sc_task_u.workqueue != NULL) { + workqueue_destroy(sc->sc_task_u.workqueue); + sc->sc_task_u.workqueue = NULL; + } if (sc->sc_drm_dev == NULL) return 0; /* XXX errno Linux->NetBSD */ error = -drm_pci_detach(sc->sc_drm_dev, flags); if (error) + /* XXX Kinda too late to fail now... */ return error; + sc->sc_drm_dev = NULL; return 0; } -int -radeon_genfb_attach(struct drm_device *dev, struct drm_fb_helper *helper, - const struct drm_fb_helper_surface_size *sizes, struct radeon_bo *rbo) -{ - struct radeon_softc *const sc = container_of(dev->pdev, - struct radeon_softc, sc_pci_dev); - static const struct genfb_ops zero_genfb_ops; - struct genfb_ops genfb_ops = zero_genfb_ops; - const prop_dictionary_t dict = device_properties(sc->sc_dev); - enum { CONS_VGA, CONS_GENFB, CONS_NONE } what_was_cons; - int ret; - -#if NVGA > 0 - if (vga_is_console(dev->pdev->pd_pa.pa_iot, -1) || - vga_is_console(dev->pdev->pd_pa.pa_iot, -1)) { - what_was_cons = CONS_VGA; - prop_dictionary_set_bool(dict, "is_console", true); - /* - * There is a window from here until genfb attaches in - * which kernel messages will go into a black hole, - * until genfb replays the console. Whattakludge. - * - * wsdisplay_cndetach must come first, to clear cn_tab, - * so that nothing will use it; then vga_cndetach - * unmaps the bus space that it would have used. - */ - wsdisplay_cndetach(); - vga_cndetach(); - } else -#endif - if (genfb_is_console() && genfb_is_enabled()) { - what_was_cons = CONS_GENFB; - prop_dictionary_set_bool(dict, "is_console", true); - } else { - what_was_cons = CONS_NONE; - prop_dictionary_set_bool(dict, "is_console", false); - } - - /* XXX Ugh... Pass these parameters some other way! */ - prop_dictionary_set_uint32(dict, "width", sizes->fb_width); - prop_dictionary_set_uint32(dict, "height", sizes->fb_height); - prop_dictionary_set_uint8(dict, "depth", sizes->surface_bpp); - prop_dictionary_set_uint16(dict, "linebytes", - roundup2((sizes->fb_width * howmany(sizes->surface_bpp, 8)), 64)); - prop_dictionary_set_uint32(dict, "address", 0); /* XXX >32-bit */ - CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t)); - prop_dictionary_set_uint64(dict, "virtual_address", - (uint64_t)(uintptr_t)rbo->kptr); - - helper->genfb.sc_dev = sc->sc_dev; - genfb_init(&helper->genfb); - genfb_ops.genfb_ioctl = radeon_genfb_ioctl; - genfb_ops.genfb_mmap = radeon_genfb_mmap; - - /* XXX errno NetBSD->Linux */ - ret = -genfb_attach(&helper->genfb, &genfb_ops); - if (ret) { - DRM_ERROR("failed to attach genfb: %d\n", ret); - switch (what_was_cons) { /* XXX Restore console... */ - case CONS_VGA: break; - case CONS_GENFB: break; - case CONS_NONE: break; - default: break; - } - return ret; - } - - radeon_genfb_defer_set_config(helper); - - return 0; -} - -static void -radeon_genfb_defer_set_config(struct drm_fb_helper *helper) -{ - struct drm_device *const dev = helper->dev; - struct radeon_softc *const sc = container_of(dev->pdev, - struct radeon_softc, sc_pci_dev); - struct radeon_genfb_work *work; - - /* Really shouldn't sleep here... */ - work = kmem_alloc(sizeof(*work), KM_SLEEP); - work->rgw_fb_helper = helper; - - if (sc->sc_genfb_wq == NULL) /* during attachment */ - SIMPLEQ_INSERT_TAIL(&sc->sc_genfb_work, work, rgw_u.queue); - else - workqueue_enqueue(sc->sc_genfb_wq, &work->rgw_u.work, NULL); -} - static void -radeon_genfb_set_config_work(struct work *work, void *cookie __unused) +radeon_task_work(struct work *work, void *cookie __unused) { + struct radeon_task *const task = container_of(work, struct radeon_task, + rt_u.work); - radeon_genfb_set_config(container_of(work, struct radeon_genfb_work, - rgw_u.work)); + (*task->rt_fn)(task); } -static void -radeon_genfb_set_config(struct radeon_genfb_work *work) +int +radeon_task_schedule(device_t self, struct radeon_task *task) { + struct radeon_softc *const sc = device_private(self); - drm_fb_helper_set_config(work->rgw_fb_helper); - kmem_free(work, sizeof(*work)); -} - -static int -radeon_genfb_ioctl(void *v, void *vs, unsigned long cmd, void *data, int flag, - struct lwp *l) -{ - struct genfb_softc *const genfb = v; - struct drm_fb_helper *const helper = container_of(genfb, - struct drm_fb_helper, genfb); - struct drm_device *const dev = helper->dev; - const struct pci_attach_args *const pa = &dev->pdev->pd_pa; - - switch (cmd) { - case WSDISPLAYIO_GTYPE: - *(unsigned int *)data = WSDISPLAY_TYPE_PCIVGA; + switch (sc->sc_task_state) { + case RADEON_TASK_ATTACH: + SIMPLEQ_INSERT_TAIL(&sc->sc_task_u.attach, task, rt_u.queue); + return 0; + case RADEON_TASK_WORKQUEUE: + if (sc->sc_task_u.workqueue == NULL) { + aprint_error_dev(self, "unable to schedule task\n"); + return EIO; + } + workqueue_enqueue(sc->sc_task_u.workqueue, &task->rt_u.work, + NULL); return 0; - - /* PCI config read/write passthrough. */ - case PCI_IOC_CFGREAD: - case PCI_IOC_CFGWRITE: - return pci_devioctl(pa->pa_pc, pa->pa_tag, cmd, data, flag, l); - - case WSDISPLAYIO_GET_BUSID: - return wsdisplayio_busid_pci(genfb->sc_dev, - pa->pa_pc, pa->pa_tag, data); - default: - return EPASSTHROUGH; - } -} - -static paddr_t -radeon_genfb_mmap(void *v, void *vs, off_t offset, int prot) -{ - struct genfb_softc *const genfb = v; - struct drm_fb_helper *const helper = container_of(genfb, - struct drm_fb_helper, genfb); - struct drm_framebuffer *const fb = helper->fb; - struct radeon_framebuffer *const rfb = container_of(fb, - struct radeon_framebuffer, base); - struct drm_gem_object *const gobj = rfb->obj; - struct radeon_bo *const rbo = gem_to_radeon_bo(gobj); - struct drm_device *const dev = helper->dev; - const struct pci_attach_args *const pa = &dev->pdev->pd_pa; - unsigned int i; - - if (offset < 0) - return -1; - - /* Treat low memory as the framebuffer itself. */ - if (offset < genfb->sc_fbsize) { - const unsigned num_pages __diagused = rbo->tbo.num_pages; - bus_addr_t addr; - int flags = 0; - - KASSERT(genfb->sc_fbsize == (num_pages << PAGE_SHIFT)); - KASSERT(num_pages == rbo->tbo.ttm->num_pages); - addr = page_to_phys(rbo->tbo.ttm->pages[offset >> PAGE_SHIFT]); - /* XXX CACHEABLE? PREFETCHABLE? WC? WB? */ - if (ISSET(rbo->tbo.mem.placement, TTM_PL_FLAG_CACHED)) - flags |= BUS_SPACE_MAP_PREFETCHABLE; - /* - * XXX Urk. We assume bus_space_mmap can cope with - * normal system RAM addresses. - */ - return bus_space_mmap(rbo->tbo.bdev->memt, addr, 0, prot, - flags); + panic("radeon in invalid task state: %d\n", + (int)sc->sc_task_state); } - - /* XXX Cargo-culted from genfb_pci. */ - if (kauth_authorize_machdep(kauth_cred_get(), - KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) { - aprint_normal_dev(dev->dev, "mmap at %"PRIxMAX" rejected\n", - (uintmax_t)offset); - return -1; - } - - for (i = 0; PCI_BAR(i) <= PCI_MAPREG_ROM; i++) { - pcireg_t type; - bus_addr_t addr; - bus_size_t size; - int flags; - - /* Interrogate the BAR. */ - if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, PCI_BAR(i), - &type)) - continue; - if (PCI_MAPREG_TYPE(type) != PCI_MAPREG_TYPE_MEM) - continue; - if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PCI_BAR(i), type, - &addr, &size, &flags)) - continue; - - /* Try to map it if it's in range. */ - if ((addr <= offset) && (offset < (addr + size))) - return bus_space_mmap(pa->pa_memt, addr, - (offset - addr), prot, flags); - - /* Skip a slot if this was a 64-bit BAR. */ - if ((PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) && - (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT)) - i += 1; - } - - /* Failure! */ - return -1; } Added files: Index: src/sys/external/bsd/drm2/radeon/radeon_task.h diff -u /dev/null src/sys/external/bsd/drm2/radeon/radeon_task.h:1.1 --- /dev/null Fri Jul 25 12:35:03 2014 +++ src/sys/external/bsd/drm2/radeon/radeon_task.h Fri Jul 25 12:35:03 2014 @@ -0,0 +1,55 @@ +/* $NetBSD: radeon_task.h,v 1.1 2014/07/25 12:35:03 riastradh Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Taylor R. Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RADEON_RADEON_TASK_H_ +#define _RADEON_RADEON_TASK_H_ + +#include <sys/queue.h> +#include <sys/workqueue.h> + +struct radeon_task { + union { + SIMPLEQ_ENTRY(radeon_task) queue; + struct work work; + } rt_u; + void (*rt_fn)(struct radeon_task *); +}; + +static inline void +radeon_task_init(struct radeon_task *task, void (*fn)(struct radeon_task *)) +{ + + task->rt_fn = fn; +} + +int radeon_task_schedule(device_t, struct radeon_task *); + +#endif /* _RADEON_RADEON_TASK_H_ */ Index: src/sys/external/bsd/drm2/radeon/radeondrmkmsfb.c diff -u /dev/null src/sys/external/bsd/drm2/radeon/radeondrmkmsfb.c:1.1 --- /dev/null Fri Jul 25 12:35:03 2014 +++ src/sys/external/bsd/drm2/radeon/radeondrmkmsfb.c Fri Jul 25 12:35:03 2014 @@ -0,0 +1,347 @@ +/* $NetBSD: radeondrmkmsfb.c,v 1.1 2014/07/25 12:35:03 riastradh Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Taylor R. Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: radeondrmkmsfb.c,v 1.1 2014/07/25 12:35:03 riastradh Exp $"); + +#ifdef _KERNEL_OPT +#include "vga.h" +#endif + +#include <sys/types.h> +#include <sys/device.h> + +#include <dev/pci/pciio.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <dev/pci/wsdisplay_pci.h> +#include <dev/wsfb/genfbvar.h> + +#if NVGA > 0 +/* + * XXX All we really need is vga_is_console from vgavar.h, but the + * header files are missing their own dependencies, so we need to + * explicitly drag in the other crap. + */ +#include <dev/ic/mc6845reg.h> +#include <dev/ic/pcdisplayvar.h> +#include <dev/ic/vgareg.h> +#include <dev/ic/vgavar.h> +#endif + +#include <drm/drmP.h> +#include <drm/drm_fb_helper.h> + +#include <radeon.h> +#include "radeon_drv.h" +#include "radeon_task.h" +#include "radeondrmkmsfb.h" + +struct radeonfb_softc { + /* XXX genfb requires the genfb_softc to be first. */ + struct genfb_softc sc_genfb; + device_t sc_dev; + struct radeonfb_attach_args sc_rfa; + struct radeon_task sc_setconfig_task; + bool sc_scheduled:1; + bool sc_attached:1; +}; + +static int radeonfb_match(device_t, cfdata_t, void *); +static void radeonfb_attach(device_t, device_t, void *); +static int radeonfb_detach(device_t, int); + +static void radeonfb_setconfig_task(struct radeon_task *); + +static int radeonfb_genfb_ioctl(void *, void *, unsigned long, void *, + int, struct lwp *); +static paddr_t radeonfb_genfb_mmap(void *, void *, off_t, int); +static int radeonfb_genfb_enable_polling(void *); +static int radeonfb_genfb_disable_polling(void *); + +CFATTACH_DECL_NEW(radeondrmkmsfb, sizeof(struct radeonfb_softc), + radeonfb_match, radeonfb_attach, radeonfb_detach, NULL); + +static int +radeonfb_match(device_t parent, cfdata_t match, void *aux) +{ + + return 1; +} + +static void +radeonfb_attach(device_t parent, device_t self, void *aux) +{ + struct radeonfb_softc *const sc = device_private(self); + const struct radeonfb_attach_args *const rfa = aux; + int error; + + sc->sc_dev = self; + sc->sc_rfa = *rfa; + sc->sc_scheduled = false; + sc->sc_attached = false; + + radeon_task_init(&sc->sc_setconfig_task, &radeonfb_setconfig_task); + error = radeon_task_schedule(parent, &sc->sc_setconfig_task); + if (error) { + aprint_error_dev(self, "failed to schedule mode set: %d\n", + error); + goto fail0; + } + sc->sc_scheduled = true; + + /* Success! */ + return; + +fail0: return; +} + +static int +radeonfb_detach(device_t self, int flags) +{ + struct radeonfb_softc *const sc = device_private(self); + + if (sc->sc_scheduled) + return EBUSY; + + if (sc->sc_attached) { + /* XXX genfb detach? Help? */ + sc->sc_attached = false; + } + + return 0; +} + +static void +radeonfb_setconfig_task(struct radeon_task *task) +{ + struct radeonfb_softc *const sc = container_of(task, + struct radeonfb_softc, sc_setconfig_task); + const prop_dictionary_t dict = device_properties(sc->sc_dev); + const struct radeonfb_attach_args *const rfa = &sc->sc_rfa; + const struct drm_fb_helper_surface_size *const sizes = + &rfa->rfa_fb_sizes; + enum { CONS_VGA, CONS_GENFB, CONS_NONE } what_was_cons; + static const struct genfb_ops zero_genfb_ops; + struct genfb_ops genfb_ops = zero_genfb_ops; + int error; + + KASSERT(sc->sc_scheduled); + + /* XXX Ugh... Pass these parameters some other way! */ + prop_dictionary_set_uint32(dict, "width", sizes->fb_width); + prop_dictionary_set_uint32(dict, "height", sizes->fb_height); + prop_dictionary_set_uint8(dict, "depth", sizes->surface_bpp); + prop_dictionary_set_uint16(dict, "linebytes", + roundup2((sizes->fb_width * howmany(sizes->surface_bpp, 8)), 64)); + prop_dictionary_set_uint32(dict, "address", 0); /* XXX >32-bit */ + CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t)); + prop_dictionary_set_uint64(dict, "virtual_address", + (uint64_t)(uintptr_t)rfa->rfa_fb_ptr); + + /* XXX Whattakludge! */ +#if NVGA > 0 + if (vga_is_console(rfa->rfa_fb_helper->dev->pdev->pd_pa.pa_iot, -1)) { + what_was_cons = CONS_VGA; + prop_dictionary_set_bool(dict, "is_console", true); + vga_cndetach(); + } else +#endif + if (genfb_is_console() && genfb_is_enabled()) { + what_was_cons = CONS_GENFB; + prop_dictionary_set_bool(dict, "is_console", true); + } else { + what_was_cons = CONS_NONE; + prop_dictionary_set_bool(dict, "is_console", false); + } + + sc->sc_genfb.sc_dev = sc->sc_dev; + genfb_init(&sc->sc_genfb); + genfb_ops.genfb_ioctl = radeonfb_genfb_ioctl; + genfb_ops.genfb_mmap = radeonfb_genfb_mmap; + genfb_ops.genfb_enable_polling = radeonfb_genfb_enable_polling; + genfb_ops.genfb_disable_polling = radeonfb_genfb_disable_polling; + + error = genfb_attach(&sc->sc_genfb, &genfb_ops); + if (error) { + aprint_error_dev(sc->sc_dev, "failed to attach genfb: %d\n", + error); + goto fail0; + } + sc->sc_attached = true; + + drm_fb_helper_set_config(sc->sc_rfa.rfa_fb_helper); + + /* Success! */ + sc->sc_scheduled = false; + return; + +fail0: /* XXX Restore console... */ + switch (what_was_cons) { + case CONS_VGA: + break; + case CONS_GENFB: + break; + case CONS_NONE: + break; + default: + break; + } +} + +static int +radeonfb_genfb_ioctl(void *v, void *vs, unsigned long cmd, void *data, int flag, + struct lwp *l) +{ + struct genfb_softc *const genfb = v; + struct radeonfb_softc *const sc = container_of(genfb, + struct radeonfb_softc, sc_genfb); + struct drm_device *const dev = sc->sc_rfa.rfa_fb_helper->dev; + const struct pci_attach_args *const pa = &dev->pdev->pd_pa; + + switch (cmd) { + case WSDISPLAYIO_GTYPE: + *(unsigned int *)data = WSDISPLAY_TYPE_PCIVGA; + return 0; + + /* PCI config read/write passthrough. */ + case PCI_IOC_CFGREAD: + case PCI_IOC_CFGWRITE: + return pci_devioctl(pa->pa_pc, pa->pa_tag, cmd, data, flag, l); + + case WSDISPLAYIO_GET_BUSID: + return wsdisplayio_busid_pci(dev->dev, pa->pa_pc, pa->pa_tag, + data); + + default: + return EPASSTHROUGH; + } +} + +static paddr_t +radeonfb_genfb_mmap(void *v, void *vs, off_t offset, int prot) +{ + struct genfb_softc *const genfb = v; + struct radeonfb_softc *const sc = container_of(genfb, + struct radeonfb_softc, sc_genfb); + struct drm_fb_helper *const helper = sc->sc_rfa.rfa_fb_helper; + struct drm_framebuffer *const fb = helper->fb; + struct radeon_framebuffer *const rfb = container_of(fb, + struct radeon_framebuffer, base); + struct drm_gem_object *const gobj = rfb->obj; + struct radeon_bo *const rbo = gem_to_radeon_bo(gobj); + struct drm_device *const dev = helper->dev; + const struct pci_attach_args *const pa = &dev->pdev->pd_pa; + unsigned int i; + + if (offset < 0) + return -1; + + /* Treat low memory as the framebuffer itself. */ + if (offset < genfb->sc_fbsize) { + const unsigned num_pages __diagused = rbo->tbo.num_pages; + bus_addr_t addr; + int flags = 0; + + KASSERT(genfb->sc_fbsize == (num_pages << PAGE_SHIFT)); + KASSERT(num_pages == rbo->tbo.ttm->num_pages); + addr = page_to_phys(rbo->tbo.ttm->pages[offset >> PAGE_SHIFT]); + /* XXX CACHEABLE/ PREFETCHABLE? WC? WB? */ + if (ISSET(rbo->tbo.mem.placement, TTM_PL_FLAG_CACHED)) + flags |= BUS_SPACE_MAP_PREFETCHABLE; + /* + * XXX Urk. We assume bus_space_mmap can cope with + * normal system RAM addresses. + */ + return bus_space_mmap(rbo->tbo.bdev->memt, addr, 0, prot, + flags); + } + + /* XXX Cargo-culted from genfb_pci. */ + if (kauth_authorize_machdep(kauth_cred_get(), + KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) { + aprint_normal_dev(dev->dev, "mmap at %"PRIxMAX" rejected\n", + (uintmax_t)offset); + return -1; + } + + for (i = 0; PCI_BAR(i) <= PCI_MAPREG_ROM; i++) { + pcireg_t type; + bus_addr_t addr; + bus_size_t size; + int flags; + + /* Interrogate the BAR. */ + if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, PCI_BAR(i), + &type)) + continue; + if (PCI_MAPREG_TYPE(type) != PCI_MAPREG_TYPE_MEM) + continue; + if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PCI_BAR(i), type, + &addr, &size, &flags)) + continue; + + /* Try to map it if it's in range. */ + if ((addr <= offset) && (offset < (addr + size))) + return bus_space_mmap(pa->pa_memt, addr, + (offset - addr), prot, flags); + + /* Skip a slot if this was a 64-bit BAR. */ + if ((PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) && + (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT)) + i += 1; + } + + /* Failure! */ + return -1; +} + +static int +radeonfb_genfb_enable_polling(void *cookie) +{ + struct genfb_softc *const genfb = cookie; + struct radeonfb_softc *const sc = container_of(genfb, + struct radeonfb_softc, sc_genfb); + + return drm_fb_helper_debug_enter_fb(sc->sc_rfa.rfa_fb_helper); +} + +static int +radeonfb_genfb_disable_polling(void *cookie) +{ + struct genfb_softc *const genfb = cookie; + struct radeonfb_softc *const sc = container_of(genfb, + struct radeonfb_softc, sc_genfb); + + return drm_fb_helper_debug_leave_fb(sc->sc_rfa.rfa_fb_helper); +} Index: src/sys/external/bsd/drm2/radeon/radeondrmkmsfb.h diff -u /dev/null src/sys/external/bsd/drm2/radeon/radeondrmkmsfb.h:1.1 --- /dev/null Fri Jul 25 12:35:03 2014 +++ src/sys/external/bsd/drm2/radeon/radeondrmkmsfb.h Fri Jul 25 12:35:03 2014 @@ -0,0 +1,44 @@ +/* $NetBSD: radeondrmkmsfb.h,v 1.1 2014/07/25 12:35:03 riastradh Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Taylor R. Campbell. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RADEON_RADEONDRMKMSFB_H_ +#define _RADEON_RADEONDRMKMSFB_H_ + +#include <drm/drmP.h> +#include <drm/drm_fb_helper.h> + +struct radeonfb_attach_args { + struct drm_fb_helper *rfa_fb_helper; + struct drm_fb_helper_surface_size rfa_fb_sizes; + void *rfa_fb_ptr; +}; + +#endif /* _RADEON_RADEONDRMKMS_H_ */