diff options
author | ian <ian@FreeBSD.org> | 2014-05-08 17:20:45 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2014-05-08 17:20:45 +0000 |
commit | c8ade4200e9e0edc9798f3f889bc6fe711d5650f (patch) | |
tree | bfcded5e4bbf132dfd45ec81cb9194ce734e9fd7 | |
parent | 0f14c360e4d3c5f98d435a4e683df3f59a206d26 (diff) | |
download | FreeBSD-src-c8ade4200e9e0edc9798f3f889bc6fe711d5650f.zip FreeBSD-src-c8ade4200e9e0edc9798f3f889bc6fe711d5650f.tar.gz |
Use edge-triggered interrupts rather than polling loops to avoid missing
transitions of the INIT_B line. Also, release the mutex during uiomove().
Submitted by: Thomas Skibo <ThomasSkibo@sbcglobal.net>
-rw-r--r-- | sys/arm/xilinx/zy7_devcfg.c | 43 |
1 files changed, 28 insertions, 15 deletions
diff --git a/sys/arm/xilinx/zy7_devcfg.c b/sys/arm/xilinx/zy7_devcfg.c index ae96dd3..a8df6c7 100644 --- a/sys/arm/xilinx/zy7_devcfg.c +++ b/sys/arm/xilinx/zy7_devcfg.c @@ -267,24 +267,35 @@ zy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc) devcfg_ctl = RD4(sc, ZY7_DEVCFG_CTRL); + /* Clear sticky bits and set up INIT signal positive edge interrupt. */ + WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); + WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE); + /* Deassert PROG_B (active low). */ devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B; WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); - /* Wait for INIT_B deasserted (active low). */ - tries = 0; - while ((RD4(sc, ZY7_DEVCFG_STATUS) & - ZY7_DEVCFG_STATUS_PCFG_INIT) == 0) { - if (++tries >= 100) - return (EIO); - DELAY(5); + /* + * Wait for INIT to assert. If it is already asserted, we may not get + * an edge interrupt so cancel it and continue. + */ + if ((RD4(sc, ZY7_DEVCFG_STATUS) & + ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) { + /* Already asserted. Cancel interrupt. */ + WR4(sc, ZY7_DEVCFG_INT_MASK, ~0); } - - /* Reassert PROG_B. */ + else { + /* Wait for positive edge interrupt. */ + err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i1", hz); + if (err != 0) + return (err); + } + + /* Reassert PROG_B (active low). */ devcfg_ctl &= ~ZY7_DEVCFG_CTRL_PCFG_PROG_B; WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); - /* Wait for INIT_B asserted. */ + /* Wait for INIT deasserted. This happens almost instantly. */ tries = 0; while ((RD4(sc, ZY7_DEVCFG_STATUS) & ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) { @@ -293,7 +304,7 @@ zy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc) DELAY(5); } - /* Clear sticky bits and set up INIT_B positive edge interrupt. */ + /* Clear sticky bits and set up INIT positive edge interrupt. */ WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE); @@ -301,11 +312,11 @@ zy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc) devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B; WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); - /* Wait for INIT_B deasserted indicating FPGA internal initialization - * is complete. This takes much longer than the previous waits for - * INIT_B transition (on the order of 700us). + /* + * Wait for INIT asserted indicating FPGA internal initialization + * is complete. */ - err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7in", hz); + err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i2", hz); if (err != 0) return (err); @@ -404,7 +415,9 @@ zy7_devcfg_write(struct cdev *dev, struct uio *uio, int ioflag) /* uiomove the data from user buffer to our dma map. */ segsz = MIN(PAGE_SIZE, uio->uio_resid); + DEVCFG_SC_UNLOCK(sc); err = uiomove(dma_mem, segsz, uio); + DEVCFG_SC_LOCK(sc); if (err != 0) break; |