Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/arm/sunxi sun8icrypto(4): Split out interrupt and t...



details:   https://anonhg.NetBSD.org/src/rev/23033dbb8813
branches:  trunk
changeset: 363959:23033dbb8813
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Fri Mar 18 23:35:48 2022 +0000

description:
sun8icrypto(4): Split out interrupt and thread locks.

No need to block interrupts while we're going through all the data
structures -- only need to block interrupts for the handoff from
interrupt handler to lower-priority logic.

diffstat:

 sys/arch/arm/sunxi/sun8i_crypto.c |  91 ++++++++++++++++++---------------------
 1 files changed, 42 insertions(+), 49 deletions(-)

diffs (196 lines):

diff -r 9c3e884a3d8f -r 23033dbb8813 sys/arch/arm/sunxi/sun8i_crypto.c
--- a/sys/arch/arm/sunxi/sun8i_crypto.c Fri Mar 18 23:35:37 2022 +0000
+++ b/sys/arch/arm/sunxi/sun8i_crypto.c Fri Mar 18 23:35:48 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sun8i_crypto.c,v 1.26 2021/08/07 15:41:00 riastradh Exp $      */
+/*     $NetBSD: sun8i_crypto.c,v 1.27 2022/03/18 23:35:48 riastradh Exp $      */
 
 /*-
  * Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -43,7 +43,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: sun8i_crypto.c,v 1.26 2021/08/07 15:41:00 riastradh Exp $");
+__KERNEL_RCSID(1, "$NetBSD: sun8i_crypto.c,v 1.27 2022/03/18 23:35:48 riastradh Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -111,18 +111,22 @@
 
        const struct sun8i_crypto_config *sc_cfg;
 
+       struct workqueue                *sc_wq;
+       void                            *sc_ih;
+
        kmutex_t                        sc_lock;
        struct sun8i_crypto_chan {
                struct sun8i_crypto_task        *cc_task;
                unsigned                        cc_starttime;
        }                               sc_chan[SUN8I_CRYPTO_NCHAN];
        struct callout                  sc_timeout;
-       struct workqueue                *sc_wq;
-       struct work                     sc_work;
-       void                            *sc_ih;
+
+       kmutex_t                        sc_intr_lock;
        uint32_t                        sc_done;
        uint32_t                        sc_esr;
+       struct work                     sc_work;
        bool                            sc_work_pending;
+
        struct sun8i_crypto_rng {
                struct sun8i_crypto_buf         cr_buf;
                struct sun8i_crypto_task        *cr_task;
@@ -381,7 +385,8 @@
            0, 0, 0, "sun8icry", NULL, IPL_VM,
            &sun8i_crypto_task_ctor, &sun8i_crypto_task_dtor, sc);
        sc->sc_cfg = of_compatible_lookup(phandle, compat_data)->data;
-       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
+       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+       mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
        callout_init(&sc->sc_timeout, CALLOUT_MPSAFE);
        callout_setfunc(&sc->sc_timeout, &sun8i_crypto_timeout, sc);
        if (workqueue_create(&sc->sc_wq, device_xname(self),
@@ -948,34 +953,16 @@
  *
  *     Timeout handler.  Schedules work in a thread to cancel all
  *     pending tasks that were started long enough ago we're bored of
- *     waiting for them, and reschedules another timeout unless the
- *     channels are all idle.
+ *     waiting for them.
  */
 static void
 sun8i_crypto_timeout(void *cookie)
 {
        struct sun8i_crypto_softc *sc = cookie;
-       unsigned i;
 
-       mutex_enter(&sc->sc_lock);
-
-       /* Check whether there are any tasks pending.  */
-       for (i = 0; i < SUN8I_CRYPTO_NCHAN; i++) {
-               if (sc->sc_chan[i].cc_task)
-                       break;
-       }
-       if (i == SUN8I_CRYPTO_NCHAN)
-               /* None pending, so nothing to do.  */
-               goto out;
-
-       /*
-        * Schedule the worker to check for timeouts, and schedule
-        * another timeout in case we need it.
-        */
+       mutex_enter(&sc->sc_intr_lock);
        sun8i_crypto_schedule_worker(sc);
-       callout_schedule(&sc->sc_timeout, SUN8I_CRYPTO_TIMEOUT);
-
-out:   mutex_exit(&sc->sc_lock);
+       mutex_exit(&sc->sc_intr_lock);
 }
 
 /*
@@ -991,7 +978,7 @@
        struct sun8i_crypto_softc *sc = cookie;
        uint32_t isr, esr;
 
-       mutex_enter(&sc->sc_lock);
+       mutex_enter(&sc->sc_intr_lock);
 
        /*
         * Get and acknowledge the interrupts and error status.
@@ -1014,7 +1001,7 @@
        sc->sc_done |= __SHIFTOUT(isr, SUN8I_CRYPTO_ISR_DONE);
        sc->sc_esr |= esr;
 
-       mutex_exit(&sc->sc_lock);
+       mutex_exit(&sc->sc_intr_lock);
 
        return __SHIFTOUT(isr, SUN8I_CRYPTO_ISR_DONE) != 0;
 }
@@ -1029,7 +1016,7 @@
 sun8i_crypto_schedule_worker(struct sun8i_crypto_softc *sc)
 {
 
-       KASSERT(mutex_owned(&sc->sc_lock));
+       KASSERT(mutex_owned(&sc->sc_intr_lock));
 
        /* Start the worker if necessary.  */
        if (!sc->sc_work_pending) {
@@ -1052,41 +1039,40 @@
        uint32_t done, esr, esr_chan;
        unsigned i, now;
        bool unblock = false;
+       bool schedtimeout = false;
        int error;
 
        /*
-        * Acquire the lock.  Note: We will be releasing and
-        * reacquiring it throughout the loop.
+        * Under the interrupt lock, acknowledge our work and claim the
+        * done mask and error status.
         */
-       mutex_enter(&sc->sc_lock);
-
-       /* Acknowledge the work.  */
+       mutex_enter(&sc->sc_intr_lock);
        KASSERT(sc->sc_work_pending);
        sc->sc_work_pending = false;
-
-       /*
-        * Claim the done mask and error status once; we will be
-        * releasing and reacquiring the lock for the callbacks, so
-        * they may change.
-        */
        done = sc->sc_done;
        esr = sc->sc_esr;
        sc->sc_done = 0;
        sc->sc_esr = 0;
+       mutex_exit(&sc->sc_intr_lock);
 
        /* Check the time to determine what's timed out.  */
        now = getticks();
 
-       /* Process the channels.  */
+       /* Under the lock, process the channels.  */
+       mutex_enter(&sc->sc_lock);
        for (i = 0; i < SUN8I_CRYPTO_NCHAN; i++) {
                /* Check whether the channel is done.  */
                if (!ISSET(done, SUN8I_CRYPTO_ISR_DONE_CHAN(i))) {
                        /* Nope.  Do we have a task to time out?  */
-                       if ((sc->sc_chan[i].cc_task != NULL) &&
-                           ((now - sc->sc_chan[i].cc_starttime) >=
-                               SUN8I_CRYPTO_TIMEOUT))
-                               unblock |= sun8i_crypto_chan_done(sc, i,
-                                   ETIMEDOUT);
+                       if (sc->sc_chan[i].cc_task != NULL) {
+                               if (now - sc->sc_chan[i].cc_starttime >=
+                                   SUN8I_CRYPTO_TIMEOUT) {
+                                       unblock |= sun8i_crypto_chan_done(sc,
+                                           i, ETIMEDOUT);
+                               } else {
+                                       schedtimeout = true;
+                               }
+                       }
                        continue;
                }
 
@@ -1116,9 +1102,16 @@
                 */
                unblock |= sun8i_crypto_chan_done(sc, i, error);
        }
+       mutex_exit(&sc->sc_lock);
 
-       /* All one; release the lock one last time.  */
-       mutex_exit(&sc->sc_lock);
+       /*
+        * If there are tasks still pending, make sure there's a
+        * timeout scheduled for them.  If the callout is already
+        * pending, it will take another pass through here to time some
+        * things out and schedule a new timeout.
+        */
+       if (schedtimeout && !callout_pending(&sc->sc_timeout))
+               callout_schedule(&sc->sc_timeout, SUN8I_CRYPTO_TIMEOUT);
 
        /*
         * If we cleared any channels, it is time to allow opencrypto



Home | Main Index | Thread Index | Old Index