summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-05-08 17:20:45 +0000
committerian <ian@FreeBSD.org>2014-05-08 17:20:45 +0000
commitc8ade4200e9e0edc9798f3f889bc6fe711d5650f (patch)
treebfcded5e4bbf132dfd45ec81cb9194ce734e9fd7
parent0f14c360e4d3c5f98d435a4e683df3f59a206d26 (diff)
downloadFreeBSD-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.c43
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;
OpenPOWER on IntegriCloud