Module Name: src Committed By: riastradh Date: Sun Dec 19 12:44:50 UTC 2021
Modified Files: src/sys/arch/arm/nvidia: tegra_drm.c tegra_drm.h tegra_fb.c Log Message: drm: Do the attach task dance for tegra drm. To generate a diff of this commit: cvs rdiff -u -r1.13 -r1.14 src/sys/arch/arm/nvidia/tegra_drm.c cvs rdiff -u -r1.10 -r1.11 src/sys/arch/arm/nvidia/tegra_drm.h cvs rdiff -u -r1.5 -r1.6 src/sys/arch/arm/nvidia/tegra_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/nvidia/tegra_drm.c diff -u src/sys/arch/arm/nvidia/tegra_drm.c:1.13 src/sys/arch/arm/nvidia/tegra_drm.c:1.14 --- src/sys/arch/arm/nvidia/tegra_drm.c:1.13 Sun Dec 19 12:44:14 2021 +++ src/sys/arch/arm/nvidia/tegra_drm.c Sun Dec 19 12:44:50 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: tegra_drm.c,v 1.13 2021/12/19 12:44:14 riastradh Exp $ */ +/* $NetBSD: tegra_drm.c,v 1.14 2021/12/19 12:44:50 riastradh Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tegra_drm.c,v 1.13 2021/12/19 12:44:14 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tegra_drm.c,v 1.14 2021/12/19 12:44:50 riastradh Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -55,6 +55,8 @@ static void tegra_drm_attach(device_t, d static int tegra_drm_load(struct drm_device *, unsigned long); static void tegra_drm_unload(struct drm_device *); +static void tegra_drm_task_work(struct work *, void *); + static struct drm_driver tegra_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM, .dev_priv_size = 0, @@ -123,6 +125,14 @@ tegra_drm_attach(device_t parent, device 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, "tegradrm", + &tegra_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"); aprint_normal("\n"); @@ -204,19 +214,43 @@ tegra_drm_attach(device_t parent, device sc->sc_ddev->dmat = sc->sc_ddev->bus_dmat; sc->sc_ddev->dmat_subregion_p = false; + /* + * 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) { drm_dev_put(sc->sc_ddev); + sc->sc_ddev = NULL; aprint_error_dev(self, "couldn't register DRM device: %d\n", error); - return; + goto out; } + sc->sc_dev_registered = true; aprint_normal_dev(self, "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); - return; + /* + * 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 tegra_drm_task *const task = + SIMPLEQ_FIRST(&sc->sc_tasks); + + SIMPLEQ_REMOVE_HEAD(&sc->sc_tasks, tdt_u.queue); + (*task->tdt_fn)(task); + } + +out: /* Cause any subesquent tasks to be processed by the workqueue. */ + atomic_store_relaxed(&sc->sc_task_thread, NULL); } static int @@ -246,3 +280,31 @@ tegra_drm_unload(struct drm_device *ddev drm_mode_config_cleanup(ddev); } + +static void +tegra_drm_task_work(struct work *work, void *cookie) +{ + struct tegra_drm_task *task = container_of(work, struct tegra_drm_task, + tdt_u.work); + + (*task->tdt_fn)(task); +} + +void +tegra_task_init(struct tegra_drm_task *task, + void (*fn)(struct tegra_drm_task *)) +{ + + task->tdt_fn = fn; +} + +void +tegra_task_schedule(device_t self, struct tegra_drm_task *task) +{ + struct tegra_drm_softc *sc = device_private(self); + + if (atomic_load_relaxed(&sc->sc_task_thread) == curlwp) + SIMPLEQ_INSERT_TAIL(&sc->sc_tasks, task, tdt_u.queue); + else + workqueue_enqueue(sc->sc_task_wq, &task->tdt_u.work, NULL); +} Index: src/sys/arch/arm/nvidia/tegra_drm.h diff -u src/sys/arch/arm/nvidia/tegra_drm.h:1.10 src/sys/arch/arm/nvidia/tegra_drm.h:1.11 --- src/sys/arch/arm/nvidia/tegra_drm.h:1.10 Sun Dec 19 12:44:14 2021 +++ src/sys/arch/arm/nvidia/tegra_drm.h Sun Dec 19 12:44:50 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: tegra_drm.h,v 1.10 2021/12/19 12:44:14 riastradh Exp $ */ +/* $NetBSD: tegra_drm.h,v 1.11 2021/12/19 12:44:50 riastradh Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -29,6 +29,8 @@ #ifndef _ARM_TEGRA_DRM_H #define _ARM_TEGRA_DRM_H +#include <sys/workqueue.h> + #include <drm/drm_encoder.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_cma_helper.h> @@ -54,6 +56,12 @@ struct tegra_drm_softc { int sc_phandle; + struct lwp *sc_task_thread; + SIMPLEQ_HEAD(, tegra_drm_task) sc_tasks; + struct workqueue *sc_task_wq; + + bool sc_dev_registered; + struct clk *sc_clk_host1x; struct fdtbus_reset *sc_rst_host1x; @@ -124,6 +132,14 @@ struct tegra_fbdev { struct drm_fb_helper helper; }; +struct tegra_drm_task { + union { + SIMPLEQ_ENTRY(tegra_drm_task) queue; + struct work work; + } tdt_u; + void (*tdt_fn)(struct tegra_drm_task *); +}; + #define HDMI_READ(enc, reg) \ bus_space_read_4((enc)->bst, (enc)->bsh, (reg)) #define HDMI_WRITE(enc, reg, val) \ @@ -155,4 +171,8 @@ void tegra_drm_disable_vblank(struct drm int tegra_drm_framebuffer_init(struct drm_device *, struct tegra_framebuffer *); +void tegra_task_init(struct tegra_drm_task *, + void (*)(struct tegra_drm_task *)); +void tegra_task_schedule(device_t, struct tegra_drm_task *); + #endif /* _ARM_TEGRA_DRM_H */ Index: src/sys/arch/arm/nvidia/tegra_fb.c diff -u src/sys/arch/arm/nvidia/tegra_fb.c:1.5 src/sys/arch/arm/nvidia/tegra_fb.c:1.6 --- src/sys/arch/arm/nvidia/tegra_fb.c:1.5 Sun Dec 19 12:44:14 2021 +++ src/sys/arch/arm/nvidia/tegra_fb.c Sun Dec 19 12:44:50 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: tegra_fb.c,v 1.5 2021/12/19 12:44:14 riastradh Exp $ */ +/* $NetBSD: tegra_fb.c,v 1.6 2021/12/19 12:44:50 riastradh Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tegra_fb.c,v 1.5 2021/12/19 12:44:14 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tegra_fb.c,v 1.6 2021/12/19 12:44:50 riastradh Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -42,6 +42,8 @@ __KERNEL_RCSID(0, "$NetBSD: tegra_fb.c,v static int tegra_fb_match(device_t, cfdata_t, void *); static void tegra_fb_attach(device_t, device_t, void *); +static void tegra_fb_init(struct tegra_drm_task *); + static bool tegra_fb_shutdown(device_t, int); struct tegra_fb_softc { @@ -50,6 +52,7 @@ struct tegra_fb_softc { struct tegra_drm_softc *sc_drm; struct tegra_drmfb_attach_args sc_tfa; struct tegra_framebuffer *sc_fb; + struct tegra_drm_task sc_attach_task; }; static paddr_t tegra_fb_mmapfb(struct drmfb_softc *, off_t, int); @@ -77,7 +80,6 @@ tegra_fb_attach(device_t parent, device_ struct tegra_fb_softc * const sc = device_private(self); struct tegra_drm_softc * const drmsc = device_private(parent); struct tegra_drmfb_attach_args * const tfa = aux; - int error; sc->sc_dev = self; sc->sc_drm = drmsc; @@ -87,6 +89,17 @@ tegra_fb_attach(device_t parent, device_ aprint_naive("\n"); aprint_normal("\n"); + tegra_task_init(&sc->sc_attach_task, &tegra_fb_init); + tegra_task_schedule(parent, &sc->sc_attach_task); +} + +static void +tegra_fb_init(struct tegra_drm_task *task) +{ + struct tegra_fb_softc *sc = container_of(task, struct tegra_fb_softc, + sc_attach_task); + device_t self = sc->sc_dev; + struct tegra_drmfb_attach_args * const tfa = &sc->sc_tfa; const struct drmfb_attach_args da = { .da_dev = self, .da_fb_helper = tfa->tfa_fb_helper, @@ -95,6 +108,7 @@ tegra_fb_attach(device_t parent, device_ .da_fb_linebytes = tfa->tfa_fb_linebytes, .da_params = &tegrafb_drmfb_params, }; + int error; error = drmfb_attach(&sc->sc_drmfb, &da); if (error) {