Module Name: src
Committed By: skrll
Date: Mon May 5 08:13:31 UTC 2014
Modified Files:
src/sys/arch/arm/broadcom: bcm2835_vcaudio.c
Log Message:
Improve locking and kcondvar usage.
The "interrupt" lock doesn't need to be a spin mutex as the vchi
completions we're synchronising with are done in thread context.
Don't share the interrupt lock for the msg_sync done synchronisation.
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/broadcom/bcm2835_vcaudio.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/broadcom/bcm2835_vcaudio.c
diff -u src/sys/arch/arm/broadcom/bcm2835_vcaudio.c:1.2 src/sys/arch/arm/broadcom/bcm2835_vcaudio.c:1.3
--- src/sys/arch/arm/broadcom/bcm2835_vcaudio.c:1.2 Sun Apr 14 15:11:52 2013
+++ src/sys/arch/arm/broadcom/bcm2835_vcaudio.c Mon May 5 08:13:31 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835_vcaudio.c,v 1.2 2013/04/14 15:11:52 skrll Exp $ */
+/* $NetBSD: bcm2835_vcaudio.c,v 1.3 2014/05/05 08:13:31 skrll Exp $ */
/*-
* Copyright (c) 2013 Jared D. McNeill <[email protected]>
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_vcaudio.c,v 1.2 2013/04/14 15:11:52 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_vcaudio.c,v 1.3 2014/05/05 08:13:31 skrll Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -78,7 +78,9 @@ struct vcaudio_softc {
kmutex_t sc_lock;
kmutex_t sc_intr_lock;
- kcondvar_t sc_cv;
+
+ kmutex_t sc_msglock;
+ kcondvar_t sc_msgcv;
struct audio_format sc_format;
struct audio_encoding_set *sc_encodings;
@@ -93,6 +95,7 @@ struct vcaudio_softc {
void *sc_pend;
int sc_pblksize;
+ bool sc_msgdone;
int sc_success;
VCHI_INSTANCE_T sc_instance;
@@ -180,8 +183,10 @@ vcaudio_attach(device_t parent, device_t
sc->sc_dev = self;
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
- mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
- cv_init(&sc->sc_cv, "vcaudiocv");
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_msglock, MUTEX_DEFAULT, IPL_NONE);
+ cv_init(&sc->sc_msgcv, "vcaudiocv");
+ sc->sc_success = -1;
error = workqueue_create(&sc->sc_wq, "vcaudiowq", vcaudio_worker,
sc, PRI_BIO, IPL_SCHED, WQ_MPSAFE);
if (error) {
@@ -330,15 +335,17 @@ vcaudio_service_callback(void *priv, con
switch (msg.type) {
case VC_AUDIO_MSG_TYPE_RESULT:
- mutex_enter(&sc->sc_intr_lock);
+ mutex_enter(&sc->sc_msglock);
sc->sc_success = msg.u.result.success;
- cv_broadcast(&sc->sc_cv);
- mutex_exit(&sc->sc_intr_lock);
+ sc->sc_msgdone = true;
+ cv_broadcast(&sc->sc_msgcv);
+ mutex_exit(&sc->sc_msglock);
break;
case VC_AUDIO_MSG_TYPE_COMPLETE:
intr = msg.u.complete.callback;
intrarg = msg.u.complete.cookie;
if (intr && intrarg) {
+ mutex_enter(&sc->sc_intr_lock);
if (msg.u.complete.count > 0 && msg.u.complete.count <= sc->sc_pblksize) {
sc->sc_pbytes += msg.u.complete.count;
} else {
@@ -348,11 +355,10 @@ vcaudio_service_callback(void *priv, con
}
if (sc->sc_pbytes >= sc->sc_pblksize) {
sc->sc_pbytes -= sc->sc_pblksize;
- mutex_enter(&sc->sc_intr_lock);
intr(intrarg);
- mutex_exit(&sc->sc_intr_lock);
workqueue_enqueue(sc->sc_wq, (struct work *)&sc->sc_work, NULL);
}
+ mutex_exit(&sc->sc_intr_lock);
}
break;
default:
@@ -373,10 +379,11 @@ vcaudio_worker(struct work *wk, void *pr
mutex_enter(&sc->sc_intr_lock);
intr = sc->sc_pint;
intrarg = sc->sc_pintarg;
- mutex_exit(&sc->sc_intr_lock);
- if (intr == NULL || intrarg == NULL)
+ if (intr == NULL || intrarg == NULL) {
+ mutex_exit(&sc->sc_intr_lock);
return;
+ }
vchi_service_use(sc->sc_service);
@@ -423,7 +430,6 @@ vcaudio_worker(struct work *wk, void *pr
VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
if (error) {
printf("%s: failed to write (%d)\n", __func__, error);
- mutex_exit(&sc->sc_intr_lock);
goto done;
}
} else {
@@ -442,7 +448,6 @@ vcaudio_worker(struct work *wk, void *pr
VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
if (error) {
printf("%s: failed to write (%d)\n", __func__, error);
- mutex_exit(&sc->sc_intr_lock);
goto done;
}
@@ -467,6 +472,7 @@ vcaudio_worker(struct work *wk, void *pr
sc->sc_ppos = 0;
done:
+ mutex_exit(&sc->sc_intr_lock);
vchi_service_release(sc->sc_service);
}
@@ -475,24 +481,27 @@ vcaudio_msg_sync(struct vcaudio_softc *s
{
int error = 0;
- mutex_enter(&sc->sc_intr_lock);
+ mutex_enter(&sc->sc_msglock);
+
sc->sc_success = -1;
+ sc->sc_msgdone = false;
+
error = vchi_msg_queue(sc->sc_service, msg, msglen,
VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
if (error) {
printf("%s: failed to queue message (%d)\n", __func__, error);
goto done;
}
- while (sc->sc_success == -1) {
- error = cv_wait_sig(&sc->sc_cv, &sc->sc_intr_lock);
+
+ while (!sc->sc_msgdone) {
+ error = cv_wait_sig(&sc->sc_msgcv, &sc->sc_msglock);
if (error)
break;
}
- if (sc->sc_success > 0)
+ if (sc->sc_success != 0)
error = EIO;
-
done:
- mutex_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_msglock);
return error;
}