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_ */