Module Name:    src
Committed By:   riastradh
Date:           Fri Mar 18 23:35:48 UTC 2022

Modified Files:
        src/sys/arch/arm/sunxi: sun8i_crypto.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.27 src/sys/arch/arm/sunxi/sun8i_crypto.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/sunxi/sun8i_crypto.c
diff -u src/sys/arch/arm/sunxi/sun8i_crypto.c:1.26 src/sys/arch/arm/sunxi/sun8i_crypto.c:1.27
--- src/sys/arch/arm/sunxi/sun8i_crypto.c:1.26	Sat Aug  7 15:41:00 2021
+++ src/sys/arch/arm/sunxi/sun8i_crypto.c	Fri Mar 18 23:35:48 2022
@@ -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 @@ struct sun8i_crypto_softc {
 
 	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 @@ sun8i_crypto_attach(device_t parent, dev
 	    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 @@ out:	/* Done!  */
  *
  *	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 @@ sun8i_crypto_intr(void *cookie)
 	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 @@ sun8i_crypto_intr(void *cookie)
 	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 @@ static void
 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 @@ sun8i_crypto_worker(struct work *wk, voi
 	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,11 +1102,18 @@ sun8i_crypto_worker(struct work *wk, voi
 		 */
 		unblock |= sun8i_crypto_chan_done(sc, i, error);
 	}
-
-	/* 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
 	 * to issue new operations.  Asymmetric operations (which we
 	 * don't support, at the moment, but we could) and symmetric

Reply via email to