summaryrefslogtreecommitdiffstats
path: root/sys/dev/dc
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2008-12-07 23:02:37 +0000
committermarius <marius@FreeBSD.org>2008-12-07 23:02:37 +0000
commitb5f6ffdd905393594ab1d9cc61a3ac47b95c2571 (patch)
tree5e8839c045e4e51e8717550cec6cb78699ace04c /sys/dev/dc
parent7bc367aaa495fcbd51501cdb4011912439354c8b (diff)
downloadFreeBSD-src-b5f6ffdd905393594ab1d9cc61a3ac47b95c2571.zip
FreeBSD-src-b5f6ffdd905393594ab1d9cc61a3ac47b95c2571.tar.gz
- 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.
Diffstat (limited to 'sys/dev/dc')
-rw-r--r--sys/dev/dc/if_dc.c80
-rw-r--r--sys/dev/dc/if_dcreg.h3
2 files changed, 47 insertions, 36 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c
index 979748d..be24cb0 100644
--- a/sys/dev/dc/if_dc.c
+++ b/sys/dev/dc/if_dc.c
@@ -607,15 +607,22 @@ dc_read_eeprom(struct dc_softc *sc, caddr_t dest, int off, int cnt, int be)
static void
dc_mii_writebit(struct dc_softc *sc, int bit)
{
-
- 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);
+ uint32_t reg;
+
+ 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 bit)
static int
dc_mii_readbit(struct dc_softc *sc)
{
-
- 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);
+ uint32_t reg;
+
+ 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_t bits, int cnt)
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, struct dc_mii_frame *frame)
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, struct dc_mii_frame *frame)
/*
* 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, struct dc_mii_frame *frame)
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);
diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h
index eb798dc..cce2c10 100644
--- a/sys/dev/dc/if_dcreg.h
+++ b/sys/dev/dc/if_dcreg.h
@@ -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
OpenPOWER on IntegriCloud