Module Name: src
Committed By: riastradh
Date: Sun Dec 19 12:28:27 UTC 2021
Modified Files:
src/sys/arch/arm/rockchip: rk_drm.c rk_drm.h rk_fb.c
Log Message:
rockchip/drm: use an explicit task queue to avoid config_defer pitfalls.
Author: phone <[email protected]>
Committer: Taylor R Campbell <[email protected]>
To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/arm/rockchip/rk_drm.c
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/rockchip/rk_drm.h
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/rockchip/rk_fb.c
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/arm/rockchip/rk_drm.c
diff -u src/sys/arch/arm/rockchip/rk_drm.c:1.11 src/sys/arch/arm/rockchip/rk_drm.c:1.12
--- src/sys/arch/arm/rockchip/rk_drm.c:1.11 Sun Dec 19 11:25:48 2021
+++ src/sys/arch/arm/rockchip/rk_drm.c Sun Dec 19 12:28:27 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_drm.c,v 1.11 2021/12/19 11:25:48 riastradh Exp $ */
+/* $NetBSD: rk_drm.c,v 1.12 2021/12/19 12:28:27 riastradh Exp $ */
/*-
* Copyright (c) 2019 Jared D. McNeill <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_drm.c,v 1.11 2021/12/19 11:25:48 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_drm.c,v 1.12 2021/12/19 12:28:27 riastradh Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -82,6 +82,8 @@ static void rk_drm_disable_vblank(struct
static int rk_drm_load(struct drm_device *, unsigned long);
static void rk_drm_unload(struct drm_device *);
+static void rk_drm_task_work(struct work *, void *);
+
static struct drm_driver rk_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM,
.dev_priv_size = 0,
@@ -131,6 +133,14 @@ rk_drm_attach(device_t parent, device_t
sc->sc_dmat = faa->faa_dmat;
sc->sc_bst = faa->faa_bst;
sc->sc_phandle = faa->faa_phandle;
+ sc->sc_task_thread = NULL;
+ SIMPLEQ_INIT(&sc->sc_tasks);
+ if (workqueue_create(&sc->sc_task_wq, "rkdrm",
+ &rk_drm_task_work, NULL, PRI_NONE, IPL_NONE, WQ_MPSAFE)) {
+ aprint_error_dev(self, "unable to create workqueue\n");
+ sc->sc_task_wq = NULL;
+ return;
+ }
aprint_naive("\n");
@@ -164,16 +174,40 @@ rk_drm_init(device_t dev)
struct drm_driver * const driver = &rk_drm_driver;
int error;
+ /*
+ * Cause any tasks issued synchronously during attach to be
+ * processed at the end of this function.
+ */
+ sc->sc_task_thread = curlwp;
+
error = -drm_dev_register(sc->sc_ddev, 0);
if (error) {
aprint_error_dev(dev, "couldn't register DRM device: %d\n",
error);
- return;
+ goto out;
}
+ sc->sc_dev_registered = true;
aprint_normal_dev(dev, "initialized %s %d.%d.%d %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, sc->sc_ddev->primary->index);
+
+ /*
+ * Process asynchronous tasks queued synchronously during
+ * attach. This will be for display detection to attach a
+ * framebuffer, so we have the opportunity for a console device
+ * to attach before autoconf has completed, in time for init(8)
+ * to find that console without panicking.
+ */
+ while (!SIMPLEQ_EMPTY(&sc->sc_tasks)) {
+ struct rk_drm_task *const task = SIMPLEQ_FIRST(&sc->sc_tasks);
+
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_tasks, rdt_u.queue);
+ (*task->rdt_fn)(task);
+ }
+
+out: /* Cause any subesquent tasks to be processed by the workqueue. */
+ atomic_store_relaxed(&sc->sc_task_thread, NULL);
}
static vmem_t *
@@ -484,3 +518,31 @@ rk_drm_port_device(struct fdt_device_por
return NULL;
}
+
+static void
+rk_drm_task_work(struct work *work, void *cookie)
+{
+ struct rk_drm_task *task = container_of(work, struct rk_drm_task,
+ rdt_u.work);
+
+ (*task->rdt_fn)(task);
+}
+
+void
+rk_task_init(struct rk_drm_task *task,
+ void (*fn)(struct rk_drm_task *))
+{
+
+ task->rdt_fn = fn;
+}
+
+void
+rk_task_schedule(device_t self, struct rk_drm_task *task)
+{
+ struct rk_drm_softc *sc = device_private(self);
+
+ if (atomic_load_relaxed(&sc->sc_task_thread) == curlwp)
+ SIMPLEQ_INSERT_TAIL(&sc->sc_tasks, task, rdt_u.queue);
+ else
+ workqueue_enqueue(sc->sc_task_wq, &task->rdt_u.work, NULL);
+}
Index: src/sys/arch/arm/rockchip/rk_drm.h
diff -u src/sys/arch/arm/rockchip/rk_drm.h:1.1 src/sys/arch/arm/rockchip/rk_drm.h:1.2
--- src/sys/arch/arm/rockchip/rk_drm.h:1.1 Sat Nov 9 23:30:14 2019
+++ src/sys/arch/arm/rockchip/rk_drm.h Sun Dec 19 12:28:27 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_drm.h,v 1.1 2019/11/09 23:30:14 jmcneill Exp $ */
+/* $NetBSD: rk_drm.h,v 1.2 2021/12/19 12:28:27 riastradh Exp $ */
/*-
* Copyright (c) 2019 Jared D. McNeill <[email protected]>
@@ -29,6 +29,7 @@
#ifndef _ARM_RK_DRM_H
#define _ARM_RK_DRM_H
+#include <sys/workqueue.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
@@ -62,6 +63,12 @@ struct rk_drm_softc {
int sc_phandle;
+ struct lwp *sc_task_thread;
+ SIMPLEQ_HEAD(, rk_drm_task) sc_tasks;
+ struct workqueue *sc_task_wq;
+
+ bool sc_dev_registered;
+
struct rk_drm_vblank sc_vbl[RK_DRM_MAX_CRTC];
};
@@ -90,10 +97,22 @@ struct rk_drmfb_attach_args {
uint32_t sfa_fb_linebytes;
};
+struct rk_drm_task {
+ union {
+ SIMPLEQ_ENTRY(rk_drm_task) queue;
+ struct work work;
+ } rdt_u;
+ void (*rdt_fn)(struct rk_drm_task *);
+};
+
#define rk_drm_private(ddev) (ddev)->dev_private
#define to_rk_drm_framebuffer(x) container_of(x, struct rk_drm_framebuffer, base)
int rk_drm_register_port(int, struct fdt_device_ports *);
struct drm_device *rk_drm_port_device(struct fdt_device_ports *);
+void rk_task_init(struct rk_drm_task *,
+ void (*)(struct rk_drm_task *));
+void rk_task_schedule(device_t, struct rk_drm_task *);
+
#endif /* _ARM_RK_DRM_H */
Index: src/sys/arch/arm/rockchip/rk_fb.c
diff -u src/sys/arch/arm/rockchip/rk_fb.c:1.4 src/sys/arch/arm/rockchip/rk_fb.c:1.5
--- src/sys/arch/arm/rockchip/rk_fb.c:1.4 Sun Dec 19 11:01:10 2021
+++ src/sys/arch/arm/rockchip/rk_fb.c Sun Dec 19 12:28:27 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: rk_fb.c,v 1.4 2021/12/19 11:01:10 riastradh Exp $ */
+/* $NetBSD: rk_fb.c,v 1.5 2021/12/19 12:28:27 riastradh Exp $ */
/*-
* Copyright (c) 2015-2019 Jared McNeill <[email protected]>
@@ -29,7 +29,7 @@
#include "opt_wsdisplay_compat.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rk_fb.c,v 1.4 2021/12/19 11:01:10 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rk_fb.c,v 1.5 2021/12/19 12:28:27 riastradh Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -45,6 +45,8 @@ __KERNEL_RCSID(0, "$NetBSD: rk_fb.c,v 1.
static int rk_fb_match(device_t, cfdata_t, void *);
static void rk_fb_attach(device_t, device_t, void *);
+static void rk_fb_init(struct rk_drm_task *);
+
static bool rk_fb_shutdown(device_t, int);
struct rk_fb_softc {
@@ -52,6 +54,7 @@ struct rk_fb_softc {
device_t sc_dev;
struct rk_drm_framebuffer *sc_fb;
struct rk_drmfb_attach_args sc_sfa;
+ struct rk_drm_task sc_attach_task;
};
static paddr_t rk_fb_mmapfb(struct drmfb_softc *, off_t, int);
@@ -77,7 +80,6 @@ rk_fb_attach(device_t parent, device_t s
{
struct rk_fb_softc * const sc = device_private(self);
struct rk_drmfb_attach_args * const sfa = aux;
- int error;
sc->sc_dev = self;
sc->sc_sfa = *sfa;
@@ -92,6 +94,19 @@ rk_fb_attach(device_t parent, device_t s
prop_dictionary_set_bool(dict, "is_console", is_console);
#endif
+ rk_task_init(&sc->sc_attach_task, &rk_fb_init);
+ rk_task_schedule(parent, &sc->sc_attach_task);
+}
+
+static void
+rk_fb_init(struct rk_drm_task *task)
+{
+ struct rk_fb_softc * const sc =
+ container_of(task, struct rk_fb_softc, sc_attach_task);
+ device_t self = sc->sc_dev;
+ struct rk_drmfb_attach_args * const sfa = &sc->sc_sfa;
+ int error;
+
const struct drmfb_attach_args da = {
.da_dev = self,
.da_fb_helper = sfa->sfa_fb_helper,