MFC Rev. 1.80, 1.81 Dynamically configure the width of the srom. This code comes from OpenBSD who got the code (or the idea) from the NetBSD tlp driver. MFC Rev. 1.67 Fix Conexant chips which always reports carrier lost on full duplex mode. Index: if_dc.c =================================================================== RCS file: /home/ncvs/src/sys/pci/if_dc.c,v retrieving revision 1.9.2.38 diff -u -r1.9.2.38 if_dc.c --- if_dc.c 5 Feb 2003 22:10:04 -0000 1.9.2.38 +++ if_dc.c 7 Feb 2003 19:01:18 -0000 @@ -223,6 +223,7 @@ static void dc_eeprom_getword __P((struct dc_softc *, int, u_int16_t *)); static void dc_eeprom_getword_pnic __P((struct dc_softc *, int, u_int16_t *)); +static void dc_eeprom_width __P((struct dc_softc *)); static void dc_read_eeprom __P((struct dc_softc *, caddr_t, int, int, int)); @@ -250,6 +251,7 @@ static int dc_list_rx_init __P((struct dc_softc *)); static int dc_list_tx_init __P((struct dc_softc *)); +static void dc_read_srom __P((struct dc_softc *, int)); static void dc_parse_21143_srom __P((struct dc_softc *)); static void dc_decode_leaf_sia __P((struct dc_softc *, struct dc_eblock_sia *)); @@ -324,6 +326,70 @@ CSR_READ_4(sc, DC_BUSCTL); } +static 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; { @@ -363,21 +429,24 @@ { 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); @@ -1572,6 +1641,7 @@ m->dc_next = sc->dc_mi; sc->dc_mi = m; + free(sc->dc_srom, M_DEVBUF); sc->dc_pmode = DC_PMODE_SIA; @@ -1630,6 +1700,17 @@ return; } +static 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; { @@ -1753,13 +1834,17 @@ sc->dc_info = dc_devtype(dev); revision = pci_read_config(dev, DC_PCI_CFRV, 4) & 0x000000FF; + /* Get the eeprom width, but PNIC has no eeprom */ + if (sc->dc_info->dc_did != DC_DEVICEID_82C168) + dc_eeprom_width(sc); + switch(sc->dc_info->dc_did) { case DC_DEVICEID_21143: sc->dc_type = DC_TYPE_21143; 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_read_srom(sc, sc->dc_romwidth); break; case DC_DEVICEID_DM9009: case DC_DEVICEID_DM9100: @@ -1779,6 +1864,7 @@ sc->dc_flags |= DC_TX_USE_TX_INTR; sc->dc_flags |= DC_TX_ADMTEK_WAR; sc->dc_pmode = DC_PMODE_MII; + dc_read_srom(sc, sc->dc_romwidth); break; case DC_DEVICEID_AN985: case DC_DEVICEID_EN2242: @@ -1786,6 +1872,7 @@ sc->dc_flags |= DC_TX_USE_TX_INTR; sc->dc_flags |= DC_TX_ADMTEK_WAR; sc->dc_pmode = DC_PMODE_MII; + dc_read_srom(sc, sc->dc_romwidth); break; case DC_DEVICEID_98713: case DC_DEVICEID_98713_CP: @@ -1844,7 +1931,7 @@ 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_read_srom(sc, sc->dc_romwidth); break; default: printf("dc%d: unknown device: %x\n", sc->dc_unit, @@ -1908,6 +1995,8 @@ 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: @@ -2468,13 +2557,13 @@ * the list buffers. */ -static void dc_txeof(sc) +static void +dc_txeof(sc) struct dc_softc *sc; { struct dc_desc *cur_tx = NULL; struct ifnet *ifp; int idx; - u_int32_t errmask; ifp = &sc->arpcom.ac_if; @@ -2494,7 +2583,6 @@ if (!(cur_tx->dc_ctl & DC_TXCTL_LASTFRAG) || cur_tx->dc_ctl & DC_TXCTL_SETUP) { - sc->dc_cdata.dc_tx_cnt--; if (cur_tx->dc_ctl & DC_TXCTL_SETUP) { /* * Yes, the PNIC is so brain damaged @@ -2511,21 +2599,29 @@ } sc->dc_cdata.dc_tx_chain[idx] = NULL; } + sc->dc_cdata.dc_tx_cnt--; DC_INC(idx, DC_TX_LIST_CNT); continue; } - if (sc->dc_pmode == DC_PMODE_MII) { - errmask = DC_TXSTAT_ERRSUM| - DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST; + if (DC_IS_CONEXANT(sc)) { /* - * The Conexant chip always reports carrier lost - * in full duplex modes. + * For some reason Conexant chips like + * setting the CARRLOST flag even when + * the carrier is there. In CURRENT we + * have the same problem for Xircom + * cards ! */ - if (DC_IS_CONEXANT(sc) && (sc->dc_if_media & IFM_FDX)) { - errmask &= ~DC_TXSTAT_CARRLOST; - } - if ((txstat & 0xFFFF) & ~errmask) + if (/*sc->dc_type == DC_TYPE_21143 &&*/ + sc->dc_pmode == DC_PMODE_MII && + ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM| + DC_TXSTAT_NOCARRIER))) + txstat &= ~DC_TXSTAT_ERRSUM; + } else { + if (/*sc->dc_type == DC_TYPE_21143 &&*/ + sc->dc_pmode == DC_PMODE_MII && + ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM| + DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST))) txstat &= ~DC_TXSTAT_ERRSUM; } @@ -2553,11 +2649,13 @@ DC_INC(idx, DC_TX_LIST_CNT); } - if (idx != sc->dc_cdata.dc_tx_cons) { + if (idx != sc->dc_cdata.dc_tx_cons) { + /* some buffers have been freed */ sc->dc_cdata.dc_tx_cons = idx; - ifp->if_flags &= ~IFF_OACTIVE; - } - ifp->if_timer = (sc->dc_cdata.dc_tx_cnt == 0) ? 0 : 5; + ifp->if_flags &= ~IFF_OACTIVE; + } + ifp->if_timer = (sc->dc_cdata.dc_tx_cnt == 0) ? 0 : 5; + return; } Index: if_dcreg.h =================================================================== RCS file: /home/ncvs/src/sys/pci/if_dcreg.h,v retrieving revision 1.4.2.20 diff -u -r1.4.2.20 if_dcreg.h --- if_dcreg.h 5 Feb 2003 22:10:04 -0000 1.4.2.20 +++ if_dcreg.h 7 Feb 2003 19:01:18 -0000 @@ -688,13 +688,14 @@ 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;