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>
This commit is contained in:
ian 2014-05-08 17:20:45 +00:00
parent 0f14c360e4
commit c8ade4200e

View File

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