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);