Author: marius
Date: Mon Dec 15 21:37:40 2008
New Revision: 186138
URL: http://svn.freebsd.org/changeset/base/186138

Log:
  MFC: 185750
  
  - According to the corresponding Linux, NetBSD and OpenSolaris
    drivers, there should be a 1us delay after every write when
    bit-banging the MII. Also insert barriers in order to ensure
    the intended ordering. These changes hopefully will solve the
    bus wedging occasionally experienced with DM9102A since r182461.
  - Deobfuscate dc_mii_readreg() a bit.
  
  Approved by:  re (kib)

Modified:
  releng/7.1/sys/   (props changed)
  releng/7.1/sys/contrib/pf/   (props changed)
  releng/7.1/sys/dev/cxgb/   (props changed)
  releng/7.1/sys/dev/dc/if_dc.c
  releng/7.1/sys/dev/dc/if_dcreg.h

Modified: releng/7.1/sys/dev/dc/if_dc.c
==============================================================================
--- releng/7.1/sys/dev/dc/if_dc.c       Mon Dec 15 21:36:14 2008        
(r186137)
+++ releng/7.1/sys/dev/dc/if_dc.c       Mon Dec 15 21:37:40 2008        
(r186138)
@@ -607,15 +607,22 @@ dc_read_eeprom(struct dc_softc *sc, cadd
 static void
 dc_mii_writebit(struct dc_softc *sc, int bit)
 {
+       uint32_t reg;
 
-       if (bit)
-               CSR_WRITE_4(sc, DC_SIO,
-                   DC_SIO_ROMCTL_WRITE | DC_SIO_MII_DATAOUT);
-       else
-               CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE);
-
-       DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK);
-       DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+       reg = DC_SIO_ROMCTL_WRITE | (bit != 0 ? DC_SIO_MII_DATAOUT : 0);
+       CSR_WRITE_4(sc, DC_SIO, reg);
+       CSR_BARRIER_4(sc, DC_SIO,
+           BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+       DELAY(1);
+
+       CSR_WRITE_4(sc, DC_SIO, reg | DC_SIO_MII_CLK);
+       CSR_BARRIER_4(sc, DC_SIO,
+           BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+       DELAY(1);
+       CSR_WRITE_4(sc, DC_SIO, reg);
+       CSR_BARRIER_4(sc, DC_SIO,
+           BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+       DELAY(1);
 }
 
 /*
@@ -624,11 +631,22 @@ dc_mii_writebit(struct dc_softc *sc, int
 static int
 dc_mii_readbit(struct dc_softc *sc)
 {
+       uint32_t reg;
 
-       CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_READ | DC_SIO_MII_DIR);
-       CSR_READ_4(sc, DC_SIO);
-       DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK);
-       DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK);
+       reg = DC_SIO_ROMCTL_READ | DC_SIO_MII_DIR;
+       CSR_WRITE_4(sc, DC_SIO, reg);
+       CSR_BARRIER_4(sc, DC_SIO,
+           BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+       DELAY(1);
+       (void)CSR_READ_4(sc, DC_SIO);
+       CSR_WRITE_4(sc, DC_SIO, reg | DC_SIO_MII_CLK);
+       CSR_BARRIER_4(sc, DC_SIO,
+           BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+       DELAY(1);
+       CSR_WRITE_4(sc, DC_SIO, reg);
+       CSR_BARRIER_4(sc, DC_SIO,
+           BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+       DELAY(1);
        if (CSR_READ_4(sc, DC_SIO) & DC_SIO_MII_DATAIN)
                return (1);
 
@@ -644,6 +662,9 @@ dc_mii_sync(struct dc_softc *sc)
        int i;
 
        CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE);
+       CSR_BARRIER_4(sc, DC_SIO,
+           BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+       DELAY(1);
 
        for (i = 0; i < 32; i++)
                dc_mii_writebit(sc, 1);
@@ -667,15 +688,13 @@ dc_mii_send(struct dc_softc *sc, u_int32
 static int
 dc_mii_readreg(struct dc_softc *sc, struct dc_mii_frame *frame)
 {
-       int i, ack;
+       int i;
 
        /*
         * Set up frame for RX.
         */
        frame->mii_stdelim = DC_MII_STARTDELIM;
        frame->mii_opcode = DC_MII_READOP;
-       frame->mii_turnaround = 0;
-       frame->mii_data = 0;
 
        /*
         * Sync the PHYs.
@@ -690,38 +709,28 @@ dc_mii_readreg(struct dc_softc *sc, stru
        dc_mii_send(sc, frame->mii_phyaddr, 5);
        dc_mii_send(sc, frame->mii_regaddr, 5);
 
-#ifdef notdef
-       /* Idle bit */
-       dc_mii_writebit(sc, 1);
-       dc_mii_writebit(sc, 0);
-#endif
-
-       /* Check for ack. */
-       ack = dc_mii_readbit(sc);
-
        /*
-        * Now try reading data bits. If the ack failed, we still
+        * Now try reading data bits.  If the turnaround failed, we still
         * need to clock through 16 cycles to keep the PHY(s) in sync.
         */
-       if (ack) {
+       frame->mii_turnaround = dc_mii_readbit(sc);
+       if (frame->mii_turnaround != 0) {
                for (i = 0; i < 16; i++)
                        dc_mii_readbit(sc);
                goto fail;
        }
-
        for (i = 0x8000; i; i >>= 1) {
-               if (!ack) {
-                       if (dc_mii_readbit(sc))
-                               frame->mii_data |= i;
-               }
+               if (dc_mii_readbit(sc))
+                       frame->mii_data |= i;
        }
 
 fail:
 
+       /* Clock the idle bits. */
        dc_mii_writebit(sc, 0);
        dc_mii_writebit(sc, 0);
 
-       if (ack)
+       if (frame->mii_turnaround != 0)
                return (1);
        return (0);
 }
@@ -736,7 +745,6 @@ dc_mii_writereg(struct dc_softc *sc, str
        /*
         * Set up frame for TX.
         */
-
        frame->mii_stdelim = DC_MII_STARTDELIM;
        frame->mii_opcode = DC_MII_WRITEOP;
        frame->mii_turnaround = DC_MII_TURNAROUND;
@@ -753,7 +761,7 @@ dc_mii_writereg(struct dc_softc *sc, str
        dc_mii_send(sc, frame->mii_turnaround, 2);
        dc_mii_send(sc, frame->mii_data, 16);
 
-       /* Idle bit. */
+       /* Clock the idle bits. */
        dc_mii_writebit(sc, 0);
        dc_mii_writebit(sc, 0);
 

Modified: releng/7.1/sys/dev/dc/if_dcreg.h
==============================================================================
--- releng/7.1/sys/dev/dc/if_dcreg.h    Mon Dec 15 21:36:14 2008        
(r186137)
+++ releng/7.1/sys/dev/dc/if_dcreg.h    Mon Dec 15 21:37:40 2008        
(r186138)
@@ -791,6 +791,9 @@ struct dc_softc {
 #define CSR_READ_4(sc, reg)            \
        bus_space_read_4(sc->dc_btag, sc->dc_bhandle, reg)
 
+#define CSR_BARRIER_4(sc, reg, flags)          \
+       bus_space_barrier(sc->dc_btag, sc->dc_bhandle, reg, 4, flags)
+
 #define DC_TIMEOUT             1000
 #define ETHER_ALIGN            2
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to