Index: sys/arch/arm/broadcom/bcm2835_mbox.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/broadcom/bcm2835_mbox.c,v
retrieving revision 1.9
diff -u -r1.9 bcm2835_mbox.c
--- sys/arch/arm/broadcom/bcm2835_mbox.c	15 Oct 2014 06:57:27 -0000	1.9
+++ sys/arch/arm/broadcom/bcm2835_mbox.c	1 May 2015 13:15:24 -0000
@@ -54,18 +54,40 @@
 	bus_dma_tag_t sc_dmat;
 	void *sc_intrh;
 
-	kmutex_t sc_lock;
 	kmutex_t sc_intr_lock;
+	kmutex_t sc_lock[BCM2835_MBOX_NUMCHANNELS];
 	kcondvar_t sc_chan[BCM2835_MBOX_NUMCHANNELS];
 	uint32_t sc_mbox[BCM2835_MBOX_NUMCHANNELS];
 };
 
+static const char *channames[BCM2835_MBOX_NUMCHANNELS] = {
+	"mbxpower",
+	"mbxfbuf",
+	"mbxuart",
+	"mbxvchiq",
+	"mbxleds",
+	"mbxbutns",
+	"mbxtscrn",
+	"mbx7",
+	"mbxwvprop",
+	"mbxrvprop",
+	"mbx10",
+	"mbx11",
+	"mbx12",
+	"mbx13",
+	"mbx14",
+	"mbx15"
+};
+#define NCHANNAMES __arraycount(channames)
+
 static struct bcm2835mbox_softc *bcm2835mbox_sc;
 
 static int bcmmbox_match(device_t, cfdata_t, void *);
 static void bcmmbox_attach(device_t, device_t, void *);
 static int bcmmbox_intr1(struct bcm2835mbox_softc *, int);
 static int bcmmbox_intr(void *);
+static void bcmmbox_read1(struct bcm2835mbox_softc *, uint8_t, uint32_t *);
+static void bcmmbox_write1(struct bcm2835mbox_softc *, uint8_t, uint32_t);
 
 CFATTACH_DECL_NEW(bcmmbox, sizeof(struct bcm2835mbox_softc),
     bcmmbox_match, bcmmbox_attach, NULL, NULL);
@@ -96,10 +118,16 @@
 	sc->sc_dev = self;
 	sc->sc_iot = aaa->aaa_iot;
 	sc->sc_dmat = aaa->aaa_dmat;
-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
-	for (i = 0; i < BCM2835_MBOX_NUMCHANNELS; ++i)
-		cv_init(&sc->sc_chan[i], "bcmmbox");
+	for (i = 0; i < BCM2835_MBOX_NUMCHANNELS; ++i) {
+		const char *n;
+		if (i < NCHANNAMES)
+			n = channames[i];
+		else
+			n = "bcmmbox";
+		mutex_init(&sc->sc_lock[i], MUTEX_DEFAULT, IPL_NONE);
+		cv_init(&sc->sc_chan[i], n);
+	}
 
 	if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, BCM2835_MBOX_SIZE, 0,
 	    &sc->sc_ioh)) {
@@ -146,6 +174,9 @@
 		data = BCM2835_MBOX_DATA(mbox);
 		ret = 1;
 
+		bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, BCM2835_MBOX_SIZE,
+		    BUS_SPACE_BARRIER_READ);
+
 		if (BCM2835_MBOX_CHAN(sc->sc_mbox[chan]) != 0) {
 			aprint_error("bcmmbox_intr: chan %d overflow\n",chan);
 			continue;
@@ -157,6 +188,10 @@
 			cv_broadcast(&sc->sc_chan[chan]);
 	}
 
+	if (!ret)
+		printf("bcmmbox spurious interrupt\n");
+		
+
 	return ret;
 }
 
@@ -175,27 +210,46 @@
 	return ret;
 }
 
-void
-bcmmbox_read(uint8_t chan, uint32_t *data)
+static void
+bcmmbox_read1(struct bcm2835mbox_softc *sc, uint8_t chan, uint32_t *data)
 {
-	struct bcm2835mbox_softc *sc = bcm2835mbox_sc;
-
-	KASSERT(sc != NULL);
-
-	mutex_enter(&sc->sc_lock);
-
 	mutex_enter(&sc->sc_intr_lock);
 	while (BCM2835_MBOX_CHAN(sc->sc_mbox[chan]) == 0) {
 		if (cold)
 			bcmmbox_intr1(sc, 0);
-		else
-			cv_wait(&sc->sc_chan[chan], &sc->sc_intr_lock);
+		else {
+			int err;
+			err = cv_timedwait(&sc->sc_chan[chan], &sc->sc_intr_lock, hz);
+			if (err == EWOULDBLOCK) {
+				if (bcmmbox_intr1(sc, 0))
+					printf("bcmmbox missed interrupt\n");
+			}
+		}
 	}
 	*data = BCM2835_MBOX_DATA(sc->sc_mbox[chan]);
 	sc->sc_mbox[chan] = 0;
 	mutex_exit(&sc->sc_intr_lock);
+}
+
+static void
+bcmmbox_write1(struct bcm2835mbox_softc *sc, uint8_t chan, uint32_t data)
+{
+	bcm2835_mbox_write(sc->sc_iot, sc->sc_ioh, chan, data);
+}
+
+void
+bcmmbox_read(uint8_t chan, uint32_t *data)
+{
+	struct bcm2835mbox_softc *sc = bcm2835mbox_sc;
 
-	mutex_exit(&sc->sc_lock);
+	KASSERT(sc != NULL);
+	KASSERT(BCM2835_MBOX_CHAN(chan) == chan);
+
+	mutex_enter(&sc->sc_lock[chan]);
+
+	bcmmbox_read1(sc, chan, data);
+
+	mutex_exit(&sc->sc_lock[chan]);
 }
 
 void
@@ -207,11 +261,11 @@
 	KASSERT(BCM2835_MBOX_CHAN(chan) == chan);
 	KASSERT(BCM2835_MBOX_CHAN(data) == 0);
 
-	mutex_enter(&sc->sc_lock);
+	mutex_enter(&sc->sc_lock[chan]);
 
-	bcm2835_mbox_write(sc->sc_iot, sc->sc_ioh, chan, data);
+	bcmmbox_write1(sc, chan, data);
 
-	mutex_exit(&sc->sc_lock);
+	mutex_exit(&sc->sc_lock[chan]);
 }
 
 int
@@ -225,6 +279,7 @@
 	int error;
 
 	KASSERT(sc != NULL);
+	KASSERT(BCM2835_MBOX_CHAN(chan) == chan);
 
 	error = bus_dmamem_alloc(sc->sc_dmat, buflen, 16, 0, segs, 1,
 	    &nsegs, BUS_DMA_WAITOK);
@@ -245,13 +300,17 @@
 
 	memcpy(dma_buf, buf, buflen);
 
+	mutex_enter(&sc->sc_lock[chan]);
+
 	bus_dmamap_sync(sc->sc_dmat, map, 0, buflen,
 	     BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
-	bcmmbox_write(chan, map->dm_segs[0].ds_addr);
-	bcmmbox_read(chan, pres);
+	bcmmbox_write1(sc, chan, map->dm_segs[0].ds_addr);
+	bcmmbox_read1(sc, chan, pres);
 	bus_dmamap_sync(sc->sc_dmat, map, 0, buflen,
 	    BUS_DMASYNC_POSTWRITE|BUS_DMASYNC_POSTREAD);
 
+	mutex_exit(&sc->sc_lock[chan]);
+
 	memcpy(buf, dma_buf, buflen);
 
 	bus_dmamap_unload(sc->sc_dmat, map);
