summaryrefslogtreecommitdiffstats
path: root/sys/pci/if_dc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/pci/if_dc.c')
-rw-r--r--sys/pci/if_dc.c118
1 files changed, 104 insertions, 14 deletions
diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c
index 5c330ff..5219671 100644
--- a/sys/pci/if_dc.c
+++ b/sys/pci/if_dc.c
@@ -229,6 +229,7 @@ static void dc_eeprom_getword_pnic
(struct dc_softc *, int, u_int16_t *);
static void dc_eeprom_getword_xircom
(struct dc_softc *, int, u_int16_t *);
+static void dc_eeprom_width (struct dc_softc *);
static void dc_read_eeprom (struct dc_softc *, caddr_t, int, int, int);
static void dc_mii_writebit (struct dc_softc *, int);
@@ -256,6 +257,7 @@ static void dc_reset (struct dc_softc *);
static int dc_list_rx_init (struct dc_softc *);
static int dc_list_tx_init (struct dc_softc *);
+static void dc_read_srom (struct dc_softc *, int);
static void dc_parse_21143_srom (struct dc_softc *);
static void dc_decode_leaf_sia (struct dc_softc *, struct dc_eblock_sia *);
static void dc_decode_leaf_mii (struct dc_softc *, struct dc_eblock_mii *);
@@ -330,6 +332,70 @@ dc_delay(sc)
CSR_READ_4(sc, DC_BUSCTL);
}
+void dc_eeprom_width(sc)
+ struct dc_softc *sc;
+{
+ int i;
+
+ /* Force EEPROM to idle state. */
+ dc_eeprom_idle(sc);
+
+ /* Enter EEPROM access mode. */
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+
+ for (i = 3; i--;) {
+ if (6 & (1 << i))
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN);
+ else
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ for (i = 1; i <= 12; i++) {
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ if (!(CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT)) {
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ break;
+ }
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
+
+ /* Turn off EEPROM access mode. */
+ dc_eeprom_idle(sc);
+
+ if (i < 4 || i > 12)
+ sc->dc_romwidth = 6;
+ else
+ sc->dc_romwidth = i;
+
+ /* Enter EEPROM access mode. */
+ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS);
+ dc_delay(sc);
+
+ /* Turn off EEPROM access mode. */
+ dc_eeprom_idle(sc);
+}
+
static void
dc_eeprom_idle(sc)
struct dc_softc *sc;
@@ -371,21 +437,24 @@ dc_eeprom_putbyte(sc, addr)
{
register int d, i;
- /*
- * The AN985 has a 93C66 EEPROM on it instead of
- * a 93C46. It uses a different bit sequence for
- * specifying the "read" opcode.
- */
- if (DC_IS_CENTAUR(sc) || DC_IS_CONEXANT(sc))
- d = addr | (DC_EECMD_READ << 2);
- else
- d = addr | DC_EECMD_READ;
+ d = DC_EECMD_READ >> 6;
+ for (i = 3; i--; ) {
+ if (d & (1 << i))
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN);
+ else
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN);
+ dc_delay(sc);
+ DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK);
+ dc_delay(sc);
+ }
/*
* Feed in each bit and strobe the clock.
*/
- for (i = 0x400; i; i >>= 1) {
- if (d & i) {
+ for (i = sc->dc_romwidth; i--;) {
+ if (addr & (1 << i)) {
SIO_SET(DC_SIO_EE_DATAIN);
} else {
SIO_CLR(DC_SIO_EE_DATAIN);
@@ -1767,6 +1836,17 @@ dc_decode_leaf_mii(sc, l)
return;
}
+void dc_read_srom(sc, bits)
+ struct dc_softc *sc;
+ int bits;
+{
+ int size;
+
+ size = 2 << bits;
+ sc->dc_srom = malloc(size, M_DEVBUF, M_NOWAIT);
+ dc_read_eeprom(sc, (caddr_t)sc->dc_srom, 0, (size / 2), 0);
+}
+
static void
dc_parse_21143_srom(sc)
struct dc_softc *sc;
@@ -1901,7 +1981,8 @@ dc_attach(dev)
sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR;
sc->dc_flags |= DC_REDUCED_MII_POLL;
/* Save EEPROM contents so we can parse them later. */
- dc_read_eeprom(sc, (caddr_t)&sc->dc_srom, 0, 512, 0);
+ dc_eeprom_width(sc);
+ dc_read_srom(sc, sc->dc_romwidth);
break;
case DC_DEVICEID_DM9100:
case DC_DEVICEID_DM9102:
@@ -1920,6 +2001,8 @@ dc_attach(dev)
sc->dc_flags |= DC_TX_USE_TX_INTR;
sc->dc_flags |= DC_TX_ADMTEK_WAR;
sc->dc_pmode = DC_PMODE_MII;
+ dc_eeprom_width(sc);
+ dc_read_srom(sc, sc->dc_romwidth);
break;
case DC_DEVICEID_AN985:
case DC_DEVICEID_FE2500:
@@ -1928,6 +2011,8 @@ dc_attach(dev)
sc->dc_flags |= DC_TX_USE_TX_INTR;
sc->dc_flags |= DC_TX_ADMTEK_WAR;
sc->dc_pmode = DC_PMODE_MII;
+ dc_eeprom_width(sc);
+ dc_read_srom(sc, sc->dc_romwidth);
break;
case DC_DEVICEID_98713:
case DC_DEVICEID_98713_CP:
@@ -1990,13 +2075,16 @@ dc_attach(dev)
* it to obtain a double word aligned buffer.
* The DC_TX_COALESCE flag is required.
*/
+ sc->dc_pmode = DC_PMODE_MII;
+ /* XXX Call the cardbus function to get nic from the CIS */
break;
case DC_DEVICEID_RS7112:
sc->dc_type = DC_TYPE_CONEXANT;
sc->dc_flags |= DC_TX_INTR_ALWAYS;
sc->dc_flags |= DC_REDUCED_MII_POLL;
sc->dc_pmode = DC_PMODE_MII;
- dc_read_eeprom(sc, (caddr_t)&sc->dc_srom, 0, 256, 0);
+ dc_eeprom_width(sc);
+ dc_read_srom(sc, sc->dc_romwidth);
break;
default:
printf("dc%d: unknown device: %x\n", sc->dc_unit,
@@ -2060,13 +2148,15 @@ dc_attach(dev)
break;
case DC_TYPE_AL981:
case DC_TYPE_AN985:
+ bcopy(&sc->dc_srom[DC_AL_EE_NODEADDR], (caddr_t)&eaddr,
+ ETHER_ADDR_LEN);
dc_read_eeprom(sc, (caddr_t)&eaddr, DC_AL_EE_NODEADDR, 3, 0);
break;
case DC_TYPE_CONEXANT:
bcopy(sc->dc_srom + DC_CONEXANT_EE_NODEADDR, &eaddr, 6);
break;
case DC_TYPE_XIRCOM:
- dc_read_eeprom(sc, (caddr_t)&eaddr, 3, 3, 0);
+
break;
default:
dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0);
OpenPOWER on IntegriCloud