Author: ian
Date: Thu May  8 17:20:45 2014
New Revision: 265690
URL: http://svnweb.freebsd.org/changeset/base/265690

Log:
  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 <thomassk...@sbcglobal.net>

Modified:
  head/sys/arm/xilinx/zy7_devcfg.c

Modified: head/sys/arm/xilinx/zy7_devcfg.c
==============================================================================
--- head/sys/arm/xilinx/zy7_devcfg.c    Thu May  8 16:59:36 2014        
(r265689)
+++ head/sys/arm/xilinx/zy7_devcfg.c    Thu May  8 17:20:45 2014        
(r265690)
@@ -267,24 +267,35 @@ zy7_devcfg_reset_pl(struct zy7_devcfg_so
 
        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);
+       }
+       else {
+               /* Wait for positive edge interrupt. */
+               err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i1", hz);
+               if (err != 0)
+                       return (err);
        }
-
-       /* Reassert PROG_B. */
+       
+       /* 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_so
                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_so
        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, struc
 
                /* 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;
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to