summaryrefslogtreecommitdiffstats
path: root/sys/dev/dc
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2002-10-07 05:26:35 +0000
committerimp <imp@FreeBSD.org>2002-10-07 05:26:35 +0000
commit3c13760e8ac6448cd3a0e8467b5cab54ab1b3cc2 (patch)
tree75cbd504f8a21d6b9e302e35b1ae8d2d74ebad31 /sys/dev/dc
parenta9892a335e6fdaa4b8b3149312e4baa1eff74c86 (diff)
downloadFreeBSD-src-3c13760e8ac6448cd3a0e8467b5cab54ab1b3cc2.zip
FreeBSD-src-3c13760e8ac6448cd3a0e8467b5cab54ab1b3cc2.tar.gz
Dynamically configure the width of the srom. This code comes from
OpenBSD who got the code (or the idea) from the NetBSD tlp driver. This gets some cardbus dc cards working (either completely or nearly so). It also appears to get additional pci cards working, without breaking working ones. # Maybe some additional work is needed here. Also, the cardbus attachment # might need to match on the CIS rather than on the vendor/device so we have # a finer level of detail as to what the card is. Technically, the # vendor/device fields are undefined for CardBus (even though most cards are # using common silicon with pci models).
Diffstat (limited to 'sys/dev/dc')
-rw-r--r--sys/dev/dc/if_dc.c118
-rw-r--r--sys/dev/dc/if_dcreg.h3
2 files changed, 106 insertions, 15 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c
index 5c330ff..5219671 100644
--- a/sys/dev/dc/if_dc.c
+++ b/sys/dev/dc/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);
diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h
index 3be7658..432d9be 100644
--- a/sys/dev/dc/if_dcreg.h
+++ b/sys/dev/dc/if_dcreg.h
@@ -710,13 +710,14 @@ struct dc_softc {
u_int8_t dc_pmode;
u_int8_t dc_link;
u_int8_t dc_cachesize;
+ int dc_romwidth;
int dc_pnic_rx_bug_save;
unsigned char *dc_pnic_rx_buf;
int dc_if_flags;
int dc_if_media;
u_int32_t dc_flags;
u_int32_t dc_txthresh;
- u_int8_t dc_srom[1024];
+ u_int8_t *dc_srom;
struct dc_mediainfo *dc_mi;
struct dc_list_data *dc_ldata;
struct dc_chain_data dc_cdata;
OpenPOWER on IntegriCloud