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:
parent
0f14c360e4
commit
c8ade4200e
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user