Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/external/bsd/drm2 drm: Rework attach/detach and deferred...



details:   https://anonhg.NetBSD.org/src/rev/f93cb7aa355f
branches:  trunk
changeset: 1028914:f93cb7aa355f
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sun Dec 19 12:28:12 2021 +0000

description:
drm: Rework attach/detach and deferred task logic.

- Reduce the number of states the softc can be in.
- Fix races between attach and other threads.

diffstat:

 sys/external/bsd/drm2/amdgpu/amdgpu_pci.c         |  150 +++++++++------------
 sys/external/bsd/drm2/i915drm/i915_pci_autoconf.c |  141 +++++++++----------
 sys/external/bsd/drm2/nouveau/nouveau_pci.c       |  151 +++++++++------------
 sys/external/bsd/drm2/radeon/radeon_pci.c         |  150 +++++++++------------
 4 files changed, 270 insertions(+), 322 deletions(-)

diffs (truncated from 992 to 300 lines):

diff -r 50b0a8d2ecfe -r f93cb7aa355f sys/external/bsd/drm2/amdgpu/amdgpu_pci.c
--- a/sys/external/bsd/drm2/amdgpu/amdgpu_pci.c Sun Dec 19 12:28:04 2021 +0000
+++ b/sys/external/bsd/drm2/amdgpu/amdgpu_pci.c Sun Dec 19 12:28:12 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: amdgpu_pci.c,v 1.9 2021/12/19 12:21:29 riastradh Exp $ */
+/*     $NetBSD: amdgpu_pci.c,v 1.10 2021/12/19 12:28:12 riastradh Exp $        */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,9 +30,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amdgpu_pci.c,v 1.9 2021/12/19 12:21:29 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amdgpu_pci.c,v 1.10 2021/12/19 12:28:12 riastradh Exp $");
 
 #include <sys/types.h>
+#include <sys/atomic.h>
 #include <sys/queue.h>
 #include <sys/systm.h>
 #include <sys/workqueue.h>
@@ -57,14 +58,9 @@
 struct amdgpu_softc {
        device_t                        sc_dev;
        struct pci_attach_args          sc_pa;
-       enum {
-               AMDGPU_TASK_ATTACH,
-               AMDGPU_TASK_WORKQUEUE,
-       }                               sc_task_state;
-       union {
-               struct workqueue                *workqueue;
-               struct amdgpu_task_head         attach;
-       }                               sc_task_u;
+       struct lwp                      *sc_task_thread;
+       struct amdgpu_task_head         sc_tasks;
+       struct workqueue                *sc_task_wq;
        struct drm_device               *sc_drm_dev;
        struct pci_dev                  sc_pci_dev;
        bool                            sc_pci_attached;
@@ -135,20 +131,30 @@
 {
        struct amdgpu_softc *const sc = device_private(self);
        const struct pci_attach_args *const pa = aux;
+       int error;
 
        pci_aprint_devinfo(pa, NULL);
 
-       if (!pmf_device_register(self, &amdgpu_do_suspend, &amdgpu_do_resume))
-               aprint_error_dev(self, "unable to establish power handler\n");
+       /* Initialize the Linux PCI device descriptor.  */
+       linux_pci_dev_init(&sc->sc_pci_dev, self, device_parent(self), pa, 0);
+
+       sc->sc_dev = self;
+       sc->sc_pa = *pa;
+       sc->sc_task_thread = NULL;
+       SIMPLEQ_INIT(&sc->sc_tasks);
+       error = workqueue_create(&sc->sc_task_wq, "amdgpufb",
+           &amdgpu_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_wq = NULL;
+               return;
+       }
 
        /*
-        * Trivial initialization first; the rest will come after we
-        * have mounted the root file system and can load firmware
-        * images.
+        * Defer the remainder of initialization until we have mounted
+        * the root file system and can load firmware images.
         */
-       sc->sc_dev = NULL;
-       sc->sc_pa = *pa;
-
        config_mountroot(self, &amdgpu_attach_real);
 }
 
@@ -164,11 +170,11 @@
        ok = amdgpu_pci_lookup(pa, &flags);
        KASSERT(ok);
 
-       sc->sc_task_state = AMDGPU_TASK_ATTACH;
-       SIMPLEQ_INIT(&sc->sc_task_u.attach);
-
-       /* Initialize the Linux PCI device descriptor.  */
-       linux_pci_dev_init(&sc->sc_pci_dev, self, device_parent(self), pa, 0);
+       /*
+        * Cause any tasks issued synchronously during attach to be
+        * processed at the end of this function.
+        */
+       sc->sc_task_thread = curlwp;
 
        sc->sc_drm_dev = drm_dev_alloc(amdgpu_drm_driver, self);
        if (IS_ERR(sc->sc_drm_dev)) {
@@ -190,29 +196,29 @@
        error = -drm_dev_register(sc->sc_drm_dev, flags);
        if (error) {
                aprint_error_dev(self, "unable to register drm: %d\n", error);
-               return;
+               goto out;
        }
        sc->sc_dev_registered = true;
 
-       while (!SIMPLEQ_EMPTY(&sc->sc_task_u.attach)) {
-               struct amdgpu_task *const task =
-                   SIMPLEQ_FIRST(&sc->sc_task_u.attach);
+       if (!pmf_device_register(self, &amdgpu_do_suspend, &amdgpu_do_resume))
+               aprint_error_dev(self, "unable to establish power handler\n");
 
-               SIMPLEQ_REMOVE_HEAD(&sc->sc_task_u.attach, rt_u.queue);
+       /*
+        * 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 amdgpu_task *const task = SIMPLEQ_FIRST(&sc->sc_tasks);
+
+               SIMPLEQ_REMOVE_HEAD(&sc->sc_tasks, rt_u.queue);
                (*task->rt_fn)(task);
        }
 
-       sc->sc_task_state = AMDGPU_TASK_WORKQUEUE;
-       error = workqueue_create(&sc->sc_task_u.workqueue, "amdgpufb",
-           &amdgpu_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;
-               goto out;
-       }
-
-out:   sc->sc_dev = self;
+out:   /* Cause any subesquent tasks to be processed by the workqueue.  */
+       atomic_store_relaxed(&sc->sc_task_thread, NULL);
 }
 
 static int
@@ -221,35 +227,29 @@
        struct amdgpu_softc *const sc = device_private(self);
        int error;
 
-       if (sc->sc_dev == NULL)
-               /* Not done attaching.  */
-               return EBUSY;
-
        /* XXX Check for in-use before tearing it all down...  */
        error = config_detach_children(self, flags);
        if (error)
                return error;
 
-       if (sc->sc_task_state == AMDGPU_TASK_ATTACH)
-               goto out0;
-       if (sc->sc_task_u.workqueue != NULL) {
-               workqueue_destroy(sc->sc_task_u.workqueue);
-               sc->sc_task_u.workqueue = NULL;
-       }
+       KASSERT(sc->sc_task_thread == NULL);
+       KASSERT(SIMPLEQ_EMPTY(&sc->sc_tasks));
 
-       if (sc->sc_drm_dev == NULL)
-               goto out1;
-       if (!sc->sc_pci_attached)
-               goto out2;
-       if (!sc->sc_dev_registered)
-               goto out3;
+       pmf_device_deregister(self);
+       if (sc->sc_dev_registered)
+               drm_dev_unregister(sc->sc_drm_dev);
+       if (sc->sc_pci_attached)
+               drm_pci_detach(sc->sc_drm_dev);
+       if (sc->sc_drm_dev) {
+               drm_dev_put(sc->sc_drm_dev);
+               sc->sc_drm_dev = NULL;
+       }
+       if (sc->sc_task_wq) {
+               workqueue_destroy(sc->sc_task_wq);
+               sc->sc_task_wq = NULL;
+       }
+       linux_pci_dev_destroy(&sc->sc_pci_dev);
 
-       drm_dev_unregister(sc->sc_drm_dev);
-out3:  drm_pci_detach(sc->sc_drm_dev);
-out2:  drm_dev_put(sc->sc_drm_dev);
-       sc->sc_drm_dev = NULL;
-out1:  linux_pci_dev_destroy(&sc->sc_pci_dev);
-out0:  pmf_device_deregister(self);
        return 0;
 }
 
@@ -260,9 +260,6 @@
        struct drm_device *const dev = sc->sc_drm_dev;
        int ret;
 
-       if (dev == NULL)
-               return true;
-
        ret = amdgpu_device_suspend(dev, /*fbcon*/true);
        if (ret)
                return false;
@@ -277,9 +274,6 @@
        struct drm_device *const dev = sc->sc_drm_dev;
        int ret;
 
-       if (dev == NULL)
-               return true;
-
        ret = amdgpu_device_resume(dev, /*fbcon*/true);
        if (ret)
                return false;
@@ -301,20 +295,10 @@
 {
        struct amdgpu_softc *const sc = device_private(self);
 
-       switch (sc->sc_task_state) {
-       case AMDGPU_TASK_ATTACH:
-               SIMPLEQ_INSERT_TAIL(&sc->sc_task_u.attach, task, rt_u.queue);
-               return 0;
-       case AMDGPU_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;
-       default:
-               panic("amdgpu in invalid task state: %d\n",
-                   (int)sc->sc_task_state);
-       }
+       if (atomic_load_relaxed(&sc->sc_task_thread) == curlwp)
+               SIMPLEQ_INSERT_TAIL(&sc->sc_tasks, task, rt_u.queue);
+       else
+               workqueue_enqueue(sc->sc_task_wq, &task->rt_u.work, NULL);
+
+       return 0;
 }
diff -r 50b0a8d2ecfe -r f93cb7aa355f sys/external/bsd/drm2/i915drm/i915_pci_autoconf.c
--- a/sys/external/bsd/drm2/i915drm/i915_pci_autoconf.c Sun Dec 19 12:28:04 2021 +0000
+++ b/sys/external/bsd/drm2/i915drm/i915_pci_autoconf.c Sun Dec 19 12:28:12 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: i915_pci_autoconf.c,v 1.9 2021/12/19 11:54:10 riastradh Exp $  */
+/*     $NetBSD: i915_pci_autoconf.c,v 1.10 2021/12/19 12:28:12 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,9 +30,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i915_pci_autoconf.c,v 1.9 2021/12/19 11:54:10 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i915_pci_autoconf.c,v 1.10 2021/12/19 12:28:12 riastradh Exp $");
 
 #include <sys/types.h>
+#include <sys/atomic.h>
 #include <sys/queue.h>
 #include <sys/systm.h>
 #include <sys/queue.h>
@@ -50,18 +51,11 @@
 struct i915drmkms_softc {
        device_t                        sc_dev;
        struct pci_attach_args          sc_pa;
-       enum {
-               I915DRMKMS_TASK_ATTACH,
-               I915DRMKMS_TASK_WORKQUEUE,
-       }                               sc_task_state;
-       union {
-               struct workqueue                *workqueue;
-               struct i915drmkms_task_head     attach;
-       }                               sc_task_u;
+       struct lwp                      *sc_task_thread;
+       struct i915drmkms_task_head     sc_tasks;
+       struct workqueue                *sc_task_wq;
        struct drm_device               *sc_drm_dev;
        struct pci_dev                  sc_pci_dev;
-       bool                            sc_pci_attached;
-       bool                            sc_dev_registered;
 };
 
 static const struct pci_device_id *
@@ -144,21 +138,30 @@
 {
        struct i915drmkms_softc *const sc = device_private(self);
        const struct pci_attach_args *const pa = aux;
+       int error;
 
        pci_aprint_devinfo(pa, NULL);
 
-       if (!pmf_device_register(self, &i915drmkms_suspend,
-               &i915drmkms_resume))
-               aprint_error_dev(self, "unable to establish power handler\n");
+       /* Initialize the Linux PCI device descriptor.  */
+       linux_pci_dev_init(&sc->sc_pci_dev, self, parent, pa, 0);
+
+       sc->sc_dev = self;
+       sc->sc_pa = *pa;
+       sc->sc_task_thread = NULL;



Home | Main Index | Thread Index | Old Index