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 <m...@netbsd.org> Committer: Taylor R Campbell <riastr...@netbsd.org> 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 <jmcne...@invisible.ca> @@ -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 <jmcne...@invisible.ca> @@ -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 <jmcne...@invisible.ca> @@ -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,