diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2004-05-30 23:49:40 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2004-05-30 23:49:40 +0000 |
commit | e5a47b83f2d305b6217e3fee8f413502da00f21a (patch) | |
tree | bd4a88b55c47c0f2c282b3e0cf968fdef9bbcdef | |
parent | dc3f44f7515c3be73ec4b9ab60b0082704668fbc (diff) |
a bit of syncing with the FreeBSD driver, namely...
- disable TX hardware checksumming since its buggy and slow
- re-enable the hardware multicast filter setup on 3c905B/C's
- enable reception of VLAN sized frames on 3c90x's (pre B/C)
- remove all DELAY(1) calls around MII operations in the xl driver.
according to the MII specification, the delay produced by our
reads alone are sufficient for correct operation.
this reduces the time mii_tick takes from 10ms to ~1ms here. that's
still a lot, but much better than before
- report media status for bitrate PHYs
- change the method used to detect older boomerang chips
- fix an issue with reading PHY regs over the i2c bus
- fix mbuf leaks in an error (rare) code path
- reuse the TX descriptor if xl_encap() failed instead of just picking the next one
- fix bug with 3c90xB cards and newer. We weren't trying to
copy the mbuf chain into an mbuf cluster when there is
more than 63 mbufs in the chain. we were trying with older
cards though
- add some magic bits necessary to turn the transmitter on for some
(newer) 556B chips
local change...
- use ether_crc32_be() instead of hand-rolled xl_calchash()
tested on i386/3c900 by beck@, sparc64/3c905C by me, i386/3c905C by sturm@, naddy@ and a few others
ok deraadt@
-rw-r--r-- | sys/dev/ic/xl.c | 492 | ||||
-rw-r--r-- | sys/dev/ic/xlreg.h | 31 | ||||
-rw-r--r-- | sys/dev/pci/if_xl_pci.c | 9 |
3 files changed, 268 insertions, 264 deletions
diff --git a/sys/dev/ic/xl.c b/sys/dev/ic/xl.c index 0ba5754423c..c8253818f5e 100644 --- a/sys/dev/ic/xl.c +++ b/sys/dev/ic/xl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xl.c,v 1.51 2003/10/21 18:58:50 jmc Exp $ */ +/* $OpenBSD: xl.c,v 1.52 2004/05/30 23:49:39 brad Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -51,25 +51,23 @@ * 3Com 3c900B-FL 10Mbps/Fiber-optic * 3Com 3c905B-COMBO 10/100Mbps/RJ-45,AUI,BNC * 3Com 3c905B-TX 10/100Mbps/RJ-45 - * 3Com 3c900-FL/FX 10/100Mbps/Fiber-optic + * 3Com 3c905B-FL/FX 10/100Mbps/Fiber-optic * 3Com 3c905C-TX 10/100Mbps/RJ-45 (Tornado ASIC) - * 3Com 3c450-TX 10/100Mbps/RJ-45 (Tornado ASIC) - * 3Com 3c555 10/100Mbps/RJ-45 (MiniPCI, Hurricane ASIC) - * 3Com 3c556 10/100Mbps/RJ-45 (MiniPCI, Hurricane ASIC) - * 3Com 3c556B 10/100Mbps/RJ-45 (MiniPCI, Hurricane ASIC) * 3Com 3c980-TX 10/100Mbps server adapter (Hurricane ASIC) * 3Com 3c980C-TX 10/100Mbps server adapter (Tornado ASIC) - * 3Com 3C575TX 10/100Mbps LAN CardBus PC Card - * 3Com 3CCFE575BT 10/100Mbps LAN CardBus PC Card - * 3Com 3CCFE575CT 10/100Mbps LAN CardBus PC Card - * 3Com 3C3FE575CT 10/100Mbps LAN CardBus Type III PC Card - * 3Com 3CCFEM656 10/100Mbps LAN+56k Modem CardBus PC Card - * 3Com 3CCFEM656B 10/100Mbps LAN+56k Modem CardBus PC Card - * 3Com 3CCFEM656C 10/100Mbps LAN+56k Global Modem CardBus PC Card - * 3Com 3C3FEM656C 10/100Mbps LAN+56k Global Modem CardBus Type III PC Card * 3Com 3cSOHO100-TX 10/100Mbps/RJ-45 (Hurricane ASIC) + * 3Com 3c450-TX 10/100Mbps/RJ-45 (Tornado ASIC) + * 3Com 3c555 10/100Mbps/RJ-45 (MiniPCI, Laptop Hurricane) + * 3Com 3c556 10/100Mbps/RJ-45 (MiniPCI, Hurricane ASIC) + * 3Com 3c556B 10/100Mbps/RJ-45 (MiniPCI, Hurricane ASIC) + * 3Com 3c575TX 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC) + * 3Com 3c575B 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC) + * 3Com 3c575C 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC) + * 3Com 3cxfem656 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC) + * 3Com 3cxfem656b 10/100Mbps/RJ-45 (Cardbus, Hurricane ASIC) + * 3Com 3cxfem656c 10/100Mbps/RJ-45 (Cardbus, Tornado ASIC) * Dell Optiplex GX1 on-board 3c918 10/100Mbps/RJ-45 - * Dell on-board 3c920 10/100Mbps/RJ-45 + * Dell on-board 3c920 10/100Mbps/RJ-45 * Dell Precision on-board 3c905B 10/100Mbps/RJ-45 * Dell Latitude laptop docking station embedded 3c905-TX * @@ -84,7 +82,7 @@ * (3c59x) also supported a bus master mode, however for those chips * you could only DMA packets to/from a contiguous memory buffer. For * transmission this would mean copying the contents of the queued mbuf - * chain into a an mbuf cluster and then DMAing the cluster. This extra + * chain into an mbuf cluster and then DMAing the cluster. This extra * copy would sort of defeat the purpose of the bus master support for * any packet that doesn't fit into a single mbuf. * @@ -141,12 +139,20 @@ #include <dev/ic/xlreg.h> +/* + * TX Checksumming is disabled by default for two reasons: + * - TX Checksumming will occasionally produce corrupt packets + * - TX Checksumming seems to reduce performance + * + * Only 905B/C cards were reported to have this problem, it is possible + * that later chips _may_ be immune. + */ +#define XL905B_TXCSUM_BROKEN 1 + int xl_newbuf(struct xl_softc *, struct xl_chain_onefrag *); void xl_stats_update(void *); int xl_encap(struct xl_softc *, struct xl_chain *, struct mbuf * ); -int xl_encap_90xB(struct xl_softc *, struct xl_chain *, - struct mbuf * ); void xl_rxeof(struct xl_softc *); int xl_rx_resync(struct xl_softc *); void xl_txeof(struct xl_softc *); @@ -173,10 +179,9 @@ int xl_mii_writereg(struct xl_softc *, struct xl_mii_frame *); void xl_setcfg(struct xl_softc *); void xl_setmode(struct xl_softc *, int); -u_int8_t xl_calchash(caddr_t); void xl_setmulti(struct xl_softc *); void xl_setmulti_hash(struct xl_softc *); -void xl_reset(struct xl_softc *, int); +void xl_reset(struct xl_softc *); int xl_list_rx_init(struct xl_softc *); int xl_list_tx_init(struct xl_softc *); int xl_list_tx_init_90xB(struct xl_softc *); @@ -208,7 +213,7 @@ xl_power(why, arg) else { ifp = &sc->sc_arpcom.ac_if; if (ifp->if_flags & IFF_UP) { - xl_reset(sc, 1); + xl_reset(sc); xl_init(sc); } } @@ -223,7 +228,8 @@ xl_power(why, arg) * but it isn't called during normal operation so we can afford * to make it a function. */ -void xl_wait(sc) +void +xl_wait(sc) struct xl_softc *sc; { register int i; @@ -233,10 +239,8 @@ void xl_wait(sc) break; } -#ifdef DIAGNOSTIC if (i == XL_TIMEOUT) printf("%s: command never completed!\n", sc->sc_dev.dv_xname); -#endif return; } @@ -252,16 +256,17 @@ void xl_wait(sc) */ #define MII_SET(x) \ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \ - CSR_READ_2(sc, XL_W4_PHY_MGMT) | x) + CSR_READ_2(sc, XL_W4_PHY_MGMT) | (x)) #define MII_CLR(x) \ CSR_WRITE_2(sc, XL_W4_PHY_MGMT, \ - CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~x) + CSR_READ_2(sc, XL_W4_PHY_MGMT) & ~(x)) /* * Sync the PHYs by setting data bit and strobing the clock 32 times. */ -void xl_mii_sync(sc) +void +xl_mii_sync(sc) struct xl_softc *sc; { register int i; @@ -271,9 +276,11 @@ void xl_mii_sync(sc) for (i = 0; i < 32; i++) { MII_SET(XL_MII_CLK); - DELAY(1); + MII_SET(XL_MII_DATA); + MII_SET(XL_MII_DATA); MII_CLR(XL_MII_CLK); - DELAY(1); + MII_SET(XL_MII_DATA); + MII_SET(XL_MII_DATA); } return; @@ -282,7 +289,8 @@ void xl_mii_sync(sc) /* * Clock a series of bits through the MII. */ -void xl_mii_send(sc, bits, cnt) +void +xl_mii_send(sc, bits, cnt) struct xl_softc *sc; u_int32_t bits; int cnt; @@ -298,9 +306,7 @@ void xl_mii_send(sc, bits, cnt) } else { MII_CLR(XL_MII_DATA); } - DELAY(1); MII_CLR(XL_MII_CLK); - DELAY(1); MII_SET(XL_MII_CLK); } } @@ -308,7 +314,8 @@ void xl_mii_send(sc, bits, cnt) /* * Read an PHY register through the MII. */ -int xl_mii_readreg(sc, frame) +int +xl_mii_readreg(sc, frame) struct xl_softc *sc; struct xl_mii_frame *frame; @@ -349,19 +356,15 @@ int xl_mii_readreg(sc, frame) /* Idle bit */ MII_CLR((XL_MII_CLK|XL_MII_DATA)); - DELAY(1); MII_SET(XL_MII_CLK); - DELAY(1); /* Turn off xmit. */ MII_CLR(XL_MII_DIR); /* Check for ack */ MII_CLR(XL_MII_CLK); - DELAY(1); - MII_SET(XL_MII_CLK); - DELAY(1); ack = CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA; + MII_SET(XL_MII_CLK); /* * Now try reading data bits. If the ack failed, we still @@ -370,31 +373,24 @@ int xl_mii_readreg(sc, frame) if (ack) { for(i = 0; i < 16; i++) { MII_CLR(XL_MII_CLK); - DELAY(1); MII_SET(XL_MII_CLK); - DELAY(1); } goto fail; } for (i = 0x8000; i; i >>= 1) { MII_CLR(XL_MII_CLK); - DELAY(1); if (!ack) { if (CSR_READ_2(sc, XL_W4_PHY_MGMT) & XL_MII_DATA) frame->mii_data |= i; - DELAY(1); } MII_SET(XL_MII_CLK); - DELAY(1); } fail: MII_CLR(XL_MII_CLK); - DELAY(1); MII_SET(XL_MII_CLK); - DELAY(1); splx(s); @@ -406,7 +402,8 @@ fail: /* * Write to a PHY register through the MII. */ -int xl_mii_writereg(sc, frame) +int +xl_mii_writereg(sc, frame) struct xl_softc *sc; struct xl_mii_frame *frame; @@ -443,9 +440,7 @@ int xl_mii_writereg(sc, frame) /* Idle bit. */ MII_SET(XL_MII_CLK); - DELAY(1); MII_CLR(XL_MII_CLK); - DELAY(1); /* * Turn off xmit. @@ -495,6 +490,8 @@ xl_miibus_writereg(self, phy, reg, data) frame.mii_data = data; xl_mii_writereg(sc, &frame); + + return; } void @@ -505,6 +502,7 @@ xl_miibus_statchg(self) xl_setcfg(sc); + /* Set ASIC's duplex mode to match the PHY. */ XL_SEL_WIN(3); if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX) CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX); @@ -517,7 +515,8 @@ xl_miibus_statchg(self) * The EEPROM is slow: give it time to come ready after issuing * it a command. */ -int xl_eeprom_wait(sc) +int +xl_eeprom_wait(sc) struct xl_softc *sc; { int i; @@ -541,7 +540,8 @@ int xl_eeprom_wait(sc) * Read a sequence of words from the EEPROM. Note that ethernet address * data is stored in the EEPROM in network byte order. */ -int xl_read_eeprom(sc, dest, off, cnt, swap) +int +xl_read_eeprom(sc, dest, off, cnt, swap) struct xl_softc *sc; caddr_t dest; int off; @@ -586,49 +586,11 @@ int xl_read_eeprom(sc, dest, off, cnt, swap) } /* - * This routine is taken from the 3Com Etherlink XL manual, - * page 10-7. It calculates a CRC of the supplied multicast - * group address and returns the lower 8 bits, which are used - * as the multicast filter position. - * Note: the 3c905B currently only supports a 64-bit hash table, - * which means we really only need 6 bits, but the manual indicates - * that future chip revisions will have a 256-bit hash table, - * hence the routine is set up to calculate 8 bits of position - * info in case we need it some day. - * Note II, The Sequel: _CURRENT_ versions of the 3c905B have a - * 256 bit hash table. This means we have to use all 8 bits regardless. - * On older cards, the upper 2 bits will be ignored. Grrrr.... - */ -u_int8_t xl_calchash(addr) - caddr_t addr; -{ - u_int32_t crc, carry; - int i, j; - u_int8_t c; - - /* Compute CRC for the address value. */ - crc = 0xFFFFFFFF; /* initial value */ - - for (i = 0; i < 6; i++) { - c = *(addr + i); - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); - crc <<= 1; - c >>= 1; - if (carry) - crc = (crc ^ 0x04c11db6) | carry; - } - } - - /* return the filter bit position */ - return(crc & 0x000000FF); -} - -/* * NICs older than the 3c905B have only one multicast option, which * is to enable reception of all multicast frames. */ -void xl_setmulti(sc) +void +xl_setmulti(sc) struct xl_softc *sc; { struct ifnet *ifp; @@ -659,7 +621,8 @@ void xl_setmulti(sc) /* * 3c905B adapters have a hash filter that we can program. */ -void xl_setmulti_hash(sc) +void +xl_setmulti_hash(sc) struct xl_softc *sc; { struct ifnet *ifp; @@ -695,7 +658,8 @@ allmulti: ifp->if_flags |= IFF_ALLMULTI; goto allmulti; } - h = xl_calchash(enm->enm_addrlo); + h = (ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26) & + 0x000000FF; CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH|XL_HASH_SET|h); mcnt++; ETHER_NEXT_MULTI(step, enm); @@ -712,7 +676,8 @@ allmulti: } #ifdef notdef -void xl_testpacket(sc) +void +xl_testpacket(sc) struct xl_softc *sc; { struct mbuf *m; @@ -742,7 +707,8 @@ void xl_testpacket(sc) } #endif -void xl_setcfg(sc) +void +xl_setcfg(sc) struct xl_softc *sc; { u_int32_t icfg; @@ -751,16 +717,19 @@ void xl_setcfg(sc) icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG); icfg &= ~XL_ICFG_CONNECTOR_MASK; if (sc->xl_media & XL_MEDIAOPT_MII || - sc->xl_media & XL_MEDIAOPT_BT4) + sc->xl_media & XL_MEDIAOPT_BT4) icfg |= (XL_XCVR_MII << XL_ICFG_CONNECTOR_BITS); if (sc->xl_media & XL_MEDIAOPT_BTX) icfg |= (XL_XCVR_AUTO << XL_ICFG_CONNECTOR_BITS); CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP); + + return; } -void xl_setmode(sc, media) +void +xl_setmode(sc, media) struct xl_softc *sc; int media; { @@ -848,22 +817,30 @@ void xl_setmode(sc, media) CSR_WRITE_2(sc, XL_W4_MEDIA_STATUS, mediastat); DELAY(800); XL_SEL_WIN(7); + + return; } -void xl_reset(sc, hard) +void +xl_reset(sc) struct xl_softc *sc; - int hard; { register int i; XL_SEL_WIN(0); - if (hard || (sc->xl_flags & XL_FLAG_WEIRDRESET)) { - CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET | - ((sc->xl_flags & XL_FLAG_WEIRDRESET)?0xFF:0)); - } - else - CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET | 0x0010); - xl_wait(sc); + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET | + ((sc->xl_flags & XL_FLAG_WEIRDRESET) ? + XL_RESETOPT_DISADVFD:0)); + + /* + * If we're using memory mapped register mode, pause briefly + * after issuing the reset command before trying to access any + * other registers. With my 3c575C cardbus card, failing to do + * this results in the system locking up while trying to poll + * the command busy bit in the status register. + */ + if (sc->xl_flags & XL_FLAG_USE_MMIO) + DELAY(100000); for (i = 0; i < XL_TIMEOUT; i++) { DELAY(10); @@ -871,18 +848,29 @@ void xl_reset(sc, hard) break; } - DELAY(100000); + if (i == XL_TIMEOUT) + printf("xl%d: reset didn't complete\n", sc->sc_dev.dv_xname); - /* Reset TX and RX. */ + /* Note: the RX reset takes an absurd amount of time + * on newer versions of the Tornado chips such as those + * on the 3c905CX and newer 3c908C cards. We wait an + * extra amount of time so that xl_wait() doesn't complain + * and annoy the users. + */ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET); + DELAY(100000); xl_wait(sc); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_RESET); xl_wait(sc); - if (sc->xl_flags & XL_FLAG_WEIRDRESET) { + if (sc->xl_flags & XL_FLAG_INVERT_LED_PWR || + sc->xl_flags & XL_FLAG_INVERT_MII_PWR) { XL_SEL_WIN(2); CSR_WRITE_2(sc, XL_W2_RESET_OPTIONS, CSR_READ_2(sc, - XL_W2_RESET_OPTIONS) | 0x4010); + XL_W2_RESET_OPTIONS) + | ((sc->xl_flags & XL_FLAG_INVERT_LED_PWR)?XL_RESETOPT_INVERT_LED:0) + | ((sc->xl_flags & XL_FLAG_INVERT_MII_PWR)?XL_RESETOPT_INVERT_MII:0) + ); } /* Wait a little while for the chip to get its brains in order. */ @@ -902,7 +890,8 @@ void xl_reset(sc, hard) * will try to guess the media options values and warn the user of a * possible manufacturing defect with his adapter/system/whatever. */ -void xl_mediacheck(sc) +void +xl_mediacheck(sc) struct xl_softc *sc; { /* @@ -939,7 +928,8 @@ void xl_mediacheck(sc) xl_choose_xcvr(sc, 1); } -void xl_choose_xcvr(sc, verbose) +void +xl_choose_xcvr(sc, verbose) struct xl_softc *sc; int verbose; { @@ -985,6 +975,13 @@ void xl_choose_xcvr(sc, verbose) case TC_DEVICEID_HURRICANE_555: /* 3c555 */ case TC_DEVICEID_HURRICANE_556: /* 3c556 */ case TC_DEVICEID_HURRICANE_556B: /* 3c556B */ + case TC_DEVICEID_HURRICANE_575A: /* 3c575TX */ + case TC_DEVICEID_HURRICANE_575B: /* 3c575B */ + case TC_DEVICEID_HURRICANE_575C: /* 3c575C */ + case TC_DEVICEID_HURRICANE_656: /* 3c656 */ + case TC_DEVICEID_HURRICANE_656B: /* 3c656B */ + case TC_DEVICEID_TORNADO_656C: /* 3c656C */ + case TC_DEVICEID_TORNADO_10_100BT_920B: /* 3c920B-EMB */ sc->xl_media = XL_MEDIAOPT_MII; sc->xl_xcvr = XL_XCVR_MII; if (verbose) @@ -1016,15 +1013,6 @@ void xl_choose_xcvr(sc, verbose) printf("%s: guessing 10/100 plus BNC/AUI\n", sc->sc_dev.dv_xname); break; - case TC_DEVICEID_3C575_CARDBUS: - case TC_DEVICEID_3CCFE575BT_CARDBUS: - case TC_DEVICEID_3CCFE575CT_CARDBUS: - case TC_DEVICEID_3CCFEM656_CARDBUS: - case TC_DEVICEID_3CCFEM656B_CARDBUS: - case TC_DEVICEID_3CCFEM656C_CARDBUS: - sc->xl_media = XL_MEDIAOPT_MII; - sc->xl_xcvr = XL_XCVR_MII; - break; default: printf("%s: unknown device ID: %x -- " "defaulting to 10baseT\n", sc->sc_dev.dv_xname, devid); @@ -1038,7 +1026,8 @@ void xl_choose_xcvr(sc, verbose) /* * Initialize the transmit descriptors. */ -int xl_list_tx_init(sc) +int +xl_list_tx_init(sc) struct xl_softc *sc; { struct xl_chain_data *cd; @@ -1106,7 +1095,8 @@ xl_list_tx_init_90xB(sc) * we arrange the descriptors in a closed ring, so that the last descriptor * points back to the first. */ -int xl_list_rx_init(sc) +int +xl_list_rx_init(sc) struct xl_softc *sc; { struct xl_chain_data *cd; @@ -1143,7 +1133,8 @@ int xl_list_rx_init(sc) /* * Initialize an RX descriptor and attach an MBUF cluster. */ -int xl_newbuf(sc, c) +int +xl_newbuf(sc, c) struct xl_softc *sc; struct xl_chain_onefrag *c; { @@ -1199,7 +1190,8 @@ int xl_newbuf(sc, c) return(0); } -int xl_rx_resync(sc) +int +xl_rx_resync(sc) struct xl_softc *sc; { struct xl_chain_onefrag *pos; @@ -1219,18 +1211,19 @@ int xl_rx_resync(sc) } if (i == XL_RX_LIST_CNT) - return (0); + return(0); sc->xl_cdata.xl_rx_head = pos; - return (EAGAIN); + return(EAGAIN); } /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */ -void xl_rxeof(sc) +void +xl_rxeof(sc) struct xl_softc *sc; { struct mbuf *m; @@ -1247,6 +1240,7 @@ again: != 0) { cur_rx = sc->xl_cdata.xl_rx_head; sc->xl_cdata.xl_rx_head = cur_rx->xl_next; + total_len = rxstat & XL_RXSTAT_LENMASK; bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap, ((caddr_t)cur_rx->xl_ptr - sc->sc_listkva), @@ -1254,6 +1248,15 @@ again: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); /* + * Since we have told the chip to allow large frames, + * we need to trap giant frame errors in software. We allow + * a little more than the normal frame size to account for + * frames with VLAN tags. + */ + if (total_len > XL_MAX_FRAMELEN) + rxstat |= (XL_RXSTAT_UP_ERROR|XL_RXSTAT_OVERSIZE); + + /* * If an error occurs, update stats, clear the * status word and leave the mbuf cluster in place: * it should simply get re-used next time this descriptor @@ -1266,13 +1269,13 @@ again: } /* - * If there error bit was not set, the upload complete + * If the error bit was not set, the upload complete * bit should be set which means we have a valid packet. * If not, something truly strange has happened. */ if (!(rxstat & XL_RXSTAT_UP_CMPLT)) { printf("%s: bad receive status -- " - "packet dropped", sc->sc_dev.dv_xname); + "packet dropped\n", sc->sc_dev.dv_xname); ifp->if_ierrors++; cur_rx->xl_ptr->xl_status = htole32(0); continue; @@ -1280,8 +1283,6 @@ again: /* No errors; receive the packet. */ m = cur_rx->xl_mbuf; - total_len = letoh32(cur_rx->xl_ptr->xl_status) & - XL_RXSTAT_LENMASK; /* * Try to conjure up a new mbuf cluster. If that @@ -1360,7 +1361,8 @@ again: * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */ -void xl_txeof(sc) +void +xl_txeof(sc) struct xl_softc *sc; { struct xl_chain *cur_tx; @@ -1466,6 +1468,8 @@ xl_txeof_90xB(sc) if (cur_tx != NULL) ifp->if_flags &= ~IFF_OACTIVE; + + return; } /* @@ -1473,7 +1477,8 @@ xl_txeof_90xB(sc) * only get a 'TX complete' interrupt if there's a transmit error, * so this is really TX error handler. */ -void xl_txeoc(sc) +void +xl_txeoc(sc) struct xl_softc *sc; { u_int8_t txstat; @@ -1538,7 +1543,8 @@ void xl_txeoc(sc) return; } -int xl_intr(arg) +int +xl_intr(arg) void *arg; { struct xl_softc *sc; @@ -1549,7 +1555,7 @@ int xl_intr(arg) sc = arg; ifp = &sc->sc_arpcom.ac_if; - while ((status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS) { + while ((status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS && status != 0xFFFF) { claimed = 1; @@ -1583,7 +1589,7 @@ int xl_intr(arg) } if (status & XL_STAT_ADFAIL) { - xl_reset(sc, 0); + xl_reset(sc); xl_init(sc); } @@ -1600,7 +1606,8 @@ int xl_intr(arg) return (claimed); } -void xl_stats_update(xsc) +void +xl_stats_update(xsc) void *xsc; { struct xl_softc *sc; @@ -1640,7 +1647,7 @@ void xl_stats_update(xsc) XL_SEL_WIN(4); CSR_READ_1(sc, XL_W4_BADSSD); - if (mii != NULL) + if (mii != NULL && (!sc->xl_stats_no_timeout)) mii_tick(mii); XL_SEL_WIN(7); @@ -1655,7 +1662,8 @@ void xl_stats_update(xsc) * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data * pointers to the fragment pointers. */ -int xl_encap(sc, c, m_head) +int +xl_encap(sc, c, m_head) struct xl_softc *sc; struct xl_chain *c; struct mbuf *m_head; @@ -1700,11 +1708,13 @@ reload: MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) + m_freem(m_head); return(1); if (m_head->m_pkthdr.len > MHLEN) { MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { m_freem(m_new); + m_freem(m_head); return(1); } } @@ -1732,6 +1742,15 @@ reload: c->xl_ptr->xl_status = htole32(total_len); c->xl_ptr->xl_next = 0; +#ifndef XL905B_TXCSUM_BROKEN + if (m_head->m_pkthdr.csum & M_IPV4_CSUM_OUT) + c->xl_ptr->xl_status |= htole32(XL_TXSTAT_IPCKSUM); + if (m_head->m_pkthdr.csum & M_TCPV4_CSUM_OUT) + c->xl_ptr->xl_status |= htole32(XL_TXSTAT_TCPCKSUM); + if (m_head->m_pkthdr.csum & M_UDPV4_CSUM_OUT) + c->xl_ptr->xl_status |= htole32(XL_TXSTAT_UDPCKSUM); +#endif + bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap, offsetof(struct xl_list_data, xl_tx_list[0]), sizeof(struct xl_list) * XL_TX_LIST_CNT, @@ -1746,12 +1765,15 @@ reload: * copy of the pointers since the transmit list fragment pointers are * physical addresses. */ -void xl_start(ifp) +void +xl_start(ifp) struct ifnet *ifp; { struct xl_softc *sc; struct mbuf *m_head = NULL; struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx; + struct xl_chain *prev_tx; + int error; sc = ifp->if_softc; @@ -1776,13 +1798,18 @@ void xl_start(ifp) break; /* Pick a descriptor off the free list. */ + prev_tx = cur_tx; cur_tx = sc->xl_cdata.xl_tx_free; - sc->xl_cdata.xl_tx_free = cur_tx->xl_next; - - cur_tx->xl_next = NULL; /* Pack the data into the descriptor. */ - xl_encap(sc, cur_tx, m_head); + error = xl_encap(sc, cur_tx, m_head); + if (error) { + cur_tx = prev_tx; + continue; + } + + sc->xl_cdata.xl_tx_free = cur_tx->xl_next; + cur_tx->xl_next = NULL; /* Chain it together. */ if (prev != NULL) { @@ -1872,69 +1899,6 @@ void xl_start(ifp) return; } -int xl_encap_90xB(sc, c, m_head) - struct xl_softc *sc; - struct xl_chain *c; - struct mbuf *m_head; -{ - struct xl_frag *f = NULL; - struct xl_list *d; - int frag; - bus_dmamap_t map; - - /* - * Start packing the mbufs in this chain into - * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. - */ - map = sc->sc_tx_sparemap; - d = c->xl_ptr; - d->xl_status = htole32(0); - d->xl_next = 0; - - if (bus_dmamap_load_mbuf(sc->sc_dmat, map, - m_head, BUS_DMA_NOWAIT) != 0) - return (ENOBUFS); - - for (frag = 0; frag < map->dm_nsegs; frag++) { - if (frag == XL_MAXFRAGS) - break; - f = &d->xl_frag[frag]; - f->xl_addr = htole32(map->dm_segs[frag].ds_addr); - f->xl_len = htole32(map->dm_segs[frag].ds_len); - } - - bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, - BUS_DMASYNC_PREWRITE); - - /* sync the old map, and unload it (if necessary) */ - if (c->map->dm_nsegs != 0) { - bus_dmamap_sync(sc->sc_dmat, c->map, 0, c->map->dm_mapsize, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sc_dmat, c->map); - } - - c->xl_mbuf = m_head; - sc->sc_tx_sparemap = c->map; - c->map = map; - c->xl_ptr->xl_frag[frag - 1].xl_len |= htole32(XL_LAST_FRAG); - c->xl_ptr->xl_status = htole32(XL_TXSTAT_RND_DEFEAT); - - if (m_head->m_pkthdr.csum & M_IPV4_CSUM_OUT) - c->xl_ptr->xl_status |= htole32(XL_TXSTAT_IPCKSUM); - if (m_head->m_pkthdr.csum & M_TCPV4_CSUM_OUT) - c->xl_ptr->xl_status |= htole32(XL_TXSTAT_TCPCKSUM); - if (m_head->m_pkthdr.csum & M_UDPV4_CSUM_OUT) - c->xl_ptr->xl_status |= htole32(XL_TXSTAT_UDPCKSUM); - - bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap, - offsetof(struct xl_list_data, xl_tx_list[0]), - sizeof(struct xl_list) * XL_TX_LIST_CNT, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - - return(0); -} - void xl_start_90xB(ifp) struct ifnet *ifp; @@ -1942,7 +1906,8 @@ xl_start_90xB(ifp) struct xl_softc *sc; struct mbuf *m_head = NULL; struct xl_chain *prev = NULL, *cur_tx = NULL, *start_tx; - int idx; + struct xl_chain *prev_tx; + int error, idx; sc = ifp->if_softc; @@ -1963,10 +1928,15 @@ xl_start_90xB(ifp) if (m_head == NULL) break; + prev_tx = cur_tx; cur_tx = &sc->xl_cdata.xl_tx_chain[idx]; /* Pack the data into the descriptor. */ - xl_encap_90xB(sc, cur_tx, m_head); + error = xl_encap(sc, cur_tx, m_head); + if (error) { + cur_tx = prev_tx; + continue; + } /* Chain it together. */ if (prev != NULL) @@ -2011,7 +1981,8 @@ xl_start_90xB(ifp) ifp->if_timer = 5; } -void xl_init(xsc) +void +xl_init(xsc) void *xsc; { struct xl_softc *sc = xsc; @@ -2038,7 +2009,6 @@ void xl_init(xsc) xl_wait(sc); DELAY(10000); - /* Init our MAC address */ XL_SEL_WIN(2); for (i = 0; i < ETHER_ADDR_LEN; i++) { @@ -2127,11 +2097,7 @@ void xl_init(xsc) /* * Program the multicast filter, if necessary. */ -#if 0 if (sc->xl_type == XL_TYPE_905B) -#else - if (0) /* xl_setmulti_hash() does not work right */ -#endif xl_setmulti_hash(sc); else xl_setmulti(sc); @@ -2177,9 +2143,21 @@ void xl_init(xsc) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP); #if NVLAN > 0 - /* Set max packet size to handle VLAN frames, only on 3c905B */ + /* + * increase packet size to allow reception of 802.1q or ISL packets. + * For the 3c90x chip, set the 'allow large packets' bit in the MAC + * control register. For 3c90xB/C chips, use the RX packet size + * register. + */ + if (sc->xl_type == XL_TYPE_905B) - CSR_WRITE_2(sc, XL_W3_MAX_PKT_SIZE, 1514 + 4); + CSR_WRITE_2(sc, XL_W3_MAXPKTSIZE, XL_PACKET_SIZE); + else { + u_int8_t macctl; + macctl = CSR_READ_1(sc, XL_W3_MAC_CTRL); + macctl |= XL_MACCTRL_ALLOW_LARGE_PACK; + CSR_WRITE_1(sc, XL_W3_MAC_CTRL, macctl); + } #endif /* Clear out the stats counters. */ @@ -2231,7 +2209,8 @@ void xl_init(xsc) /* * Set media options. */ -int xl_ifmedia_upd(ifp) +int +xl_ifmedia_upd(ifp) struct ifnet *ifp; { struct xl_softc *sc; @@ -2253,7 +2232,7 @@ int xl_ifmedia_upd(ifp) case IFM_10_2: case IFM_10_5: xl_setmode(sc, ifm->ifm_media); - return (0); + return(0); break; default: break; @@ -2272,23 +2251,32 @@ int xl_ifmedia_upd(ifp) /* * Report current media status. */ -void xl_ifmedia_sts(ifp, ifmr) +void +xl_ifmedia_sts(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr; { struct xl_softc *sc; u_int32_t icfg; + u_int16_t status = 0; struct mii_data *mii = NULL; sc = ifp->if_softc; if (sc->xl_hasmii != 0) mii = &sc->sc_mii; + XL_SEL_WIN(4); + status = CSR_READ_2(sc, XL_W4_MEDIA_STATUS); + XL_SEL_WIN(3); icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG) & XL_ICFG_CONNECTOR_MASK; icfg >>= XL_ICFG_CONNECTOR_BITS; ifmr->ifm_active = IFM_ETHER; + ifmr->ifm_status = IFM_AVALID; + + if ((status & XL_MEDIASTAT_CARRIER) == 0) + ifmr->ifm_status |= IFM_ACTIVE; switch(icfg) { case XL_XCVR_10BT: @@ -2418,11 +2406,7 @@ xl_ioctl(ifp, command, data) * Multicast list has changed; set the hardware * filter accordingly. */ -#if 0 if (sc->xl_type == XL_TYPE_905B) -#else - if (0) /* xl_setmulti_hash() does not work right */ -#endif xl_setmulti_hash(sc); else xl_setmulti(sc); @@ -2450,7 +2434,8 @@ xl_ioctl(ifp, command, data) return(error); } -void xl_watchdog(ifp) +void +xl_watchdog(ifp) struct ifnet *ifp; { struct xl_softc *sc; @@ -2469,7 +2454,7 @@ void xl_watchdog(ifp) xl_txeoc(sc); xl_txeof(sc); xl_rxeof(sc); - xl_reset(sc, 0); + xl_reset(sc); xl_init(sc); if (!IFQ_IS_EMPTY(&ifp->if_snd)) @@ -2526,7 +2511,8 @@ xl_freetxrx(sc) * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ -void xl_stop(sc) +void +xl_stop(sc) struct xl_softc *sc; { struct ifnet *ifp; @@ -2572,12 +2558,13 @@ xl_attach(sc) struct xl_softc *sc; { u_int8_t enaddr[ETHER_ADDR_LEN]; + u_int16_t xcvr[2]; struct ifnet *ifp = &sc->sc_arpcom.ac_if; int i, media = IFM_ETHER|IFM_100_TX|IFM_FDX; struct ifmedia *ifm; i = splimp(); - xl_reset(sc, 1); + xl_reset(sc); splx(i); /* @@ -2644,7 +2631,7 @@ xl_attach(sc) return; } - printf(" address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr)); + printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr)); if (sc->xl_flags & (XL_FLAG_INVERT_LED_PWR|XL_FLAG_INVERT_MII_PWR)) { u_int16_t n; @@ -2665,9 +2652,15 @@ xl_attach(sc) * Figure out the card type. 3c905B adapters have the * 'supportsNoTxLength' bit set in the capabilities * word in the EEPROM. + * Note: my 3c575C cardbus card lies. It returns a value + * of 0x1578 for its capabilities word, which is somewhat + * nonsensical. Another way to distinguish a 3c90x chip + * from a 3c90xB/C chip is to check for the 'supportsLargePackets' + * bit. This will only be set for 3c90x boomerage chips. */ xl_read_eeprom(sc, (caddr_t)&sc->xl_caps, XL_EE_CAPS, 1, 0); - if (sc->xl_caps & XL_CAPS_NO_TXLENGTH) + if (sc->xl_caps & XL_CAPS_NO_TXLENGTH || + !(sc->xl_caps & XL_CAPS_LARGE_PKTS)) sc->xl_type = XL_TYPE_905B; else sc->xl_type = XL_TYPE_90X; @@ -2679,10 +2672,15 @@ xl_attach(sc) ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = xl_ioctl; ifp->if_output = ether_output; +#if NVLAN > 0 + ifp->if_capabilities |= IFCAP_VLAN_MTU; +#endif if (sc->xl_type == XL_TYPE_905B) { ifp->if_start = xl_start_90xB; - ifp->if_capabilities = IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4| +#ifndef XL905B_TXCSUM_BROKEN + ifp->if_capabilities |= IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4| IFCAP_CSUM_UDPv4; +#endif } else ifp->if_start = xl_start; ifp->if_watchdog = xl_watchdog; @@ -2691,35 +2689,16 @@ xl_attach(sc) IFQ_SET_READY(&ifp->if_snd); bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); -#if NVLAN > 0 - if (sc->xl_type == XL_TYPE_905B) - ifp->if_capabilities |= IFCAP_VLAN_MTU; - /* - * XXX - * Do other cards filter large packets or simply pass them through? - * Apparently only the 905B has the capability to set a larger size. - */ -#endif - XL_SEL_WIN(3); sc->xl_media = CSR_READ_2(sc, XL_W3_MEDIA_OPT); - xl_read_eeprom(sc, (char *)&sc->xl_xcvr, XL_EE_ICFG_0, 2, 0); + xl_read_eeprom(sc, (char *)&xcvr, XL_EE_ICFG_0, 2, 0); + sc->xl_xcvr = xcvr[0] | xcvr[1] << 16; sc->xl_xcvr &= XL_ICFG_CONNECTOR_MASK; sc->xl_xcvr >>= XL_ICFG_CONNECTOR_BITS; - DELAY(100000); - xl_mediacheck(sc); - if (sc->xl_flags & XL_FLAG_INVERT_MII_PWR) { - XL_SEL_WIN(2); - CSR_WRITE_2(sc, XL_W2_RESET_OPTIONS, XL_RESETOPT_INVMIIPWR | - CSR_READ_2(sc, XL_W2_RESET_OPTIONS)); - } - - DELAY(100000); - if (sc->xl_media & XL_MEDIAOPT_MII || sc->xl_media & XL_MEDIAOPT_BTX || sc->xl_media & XL_MEDIAOPT_BT4) { ifmedia_init(&sc->sc_mii.mii_media, 0, @@ -2757,7 +2736,7 @@ xl_attach(sc) if (sc->xl_xcvr == XL_XCVR_AUTO) { xl_choose_xcvr(sc, 0); i = splimp(); - xl_reset(sc, 0); + xl_reset(sc); splx(i); } @@ -2837,6 +2816,11 @@ xl_attach(sc) if (sc->xl_hasmii == 0) ifmedia_set(&sc->ifmedia, media); + if (sc->xl_flags & XL_FLAG_NO_XCVR_PWR) { + XL_SEL_WIN(0); + CSR_WRITE_2(sc, XL_W0_MFG_ID, XL_NO_XCVR_PWR_MAGICBITS); + } + /* * Call MI attach routines. */ @@ -2880,7 +2864,7 @@ xl_shutdown(v) { struct xl_softc *sc = (struct xl_softc *)v; - xl_reset(sc, 1); + xl_reset(sc); xl_stop(sc); } diff --git a/sys/dev/ic/xlreg.h b/sys/dev/ic/xlreg.h index dc6e0c3f333..3f4abcf6579 100644 --- a/sys/dev/ic/xlreg.h +++ b/sys/dev/ic/xlreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: xlreg.h,v 1.18 2004/05/19 12:11:34 brad Exp $ */ +/* $OpenBSD: xlreg.h,v 1.19 2004/05/30 23:49:39 brad Exp $ */ /* * Copyright (c) 1997, 1998 @@ -83,8 +83,10 @@ #define XL_CAPS_100MBPS 0x1000 #define XL_CAPS_PWRMGMT 0x2000 -#define XL_PACKET_SIZE 1536 - +#define XL_PACKET_SIZE 1540 + +#define XL_MAX_FRAMELEN (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) + /* * Register layouts. */ @@ -250,12 +252,15 @@ #define XL_RESETOPT_TESTPDTPDR 0x0800 #define XL_RESETOPT_TEST100TX 0x1000 #define XL_RESETOPT_TEST100RX 0x2000 -#define XL_RESETOPT_INVMIIPWR 0x4000 /* some 3c905Bs only */ + +#define XL_RESETOPT_INVERT_LED 0x0010 +#define XL_RESETOPT_INVERT_MII 0x4000 + /* * Window 3 (fifo management) */ #define XL_W3_INTERNAL_CFG 0x00 -#define XL_W3_MAX_PKT_SIZE 0x04 /* 3C905B only */ +#define XL_W3_MAXPKTSIZE 0x04 /* 3C905B only */ #define XL_W3_RESET_OPT 0x08 #define XL_W3_FREE_TX 0x0C #define XL_W3_FREE_RX 0x0A @@ -561,6 +566,11 @@ struct xl_mii_frame { #define XL_FLAG_8BITROM 0x0010 #define XL_FLAG_INVERT_LED_PWR 0x0020 #define XL_FLAG_INVERT_MII_PWR 0x0040 +#define XL_FLAG_NO_XCVR_PWR 0x0080 +#define XL_FLAG_USE_MMIO 0x0100 +#define XL_FLAG_NO_MMIO 0x0200 + +#define XL_NO_XCVR_PWR_MAGICBITS 0x0900 struct xl_softc { struct device sc_dev; /* generic device structure */ @@ -651,9 +661,16 @@ struct xl_stats { */ #define TC_DEVICEID_TORNADO_HOMECONNECT 0x4500 #define TC_DEVICEID_HURRICANE_555 0x5055 +#define TC_DEVICEID_HURRICANE_575A 0x5057 +#define TC_DEVICEID_HURRICANE_575B 0x5157 +#define TC_DEVICEID_HURRICANE_575C 0x5257 +#define TC_DEVICEID_HURRICANE_656 0x6560 +#define TC_DEVICEID_HURRICANE_656B 0x6562 +#define TC_DEVICEID_TORNADO_656C 0x6564 #define TC_DEVICEID_HURRICANE_556 0x6055 #define TC_DEVICEID_HURRICANE_556B 0x6056 -#define TC_DEVICEID_BOOMERANG_10BT 0x9000 +#define TC_DEVICEID_HURRICANE_SOHO100TX 0x7646 +#define TC_DEVICEID_BOOMERANG_10BT 0x9000 #define TC_DEVICEID_BOOMERANG_10BT_COMBO 0x9001 #define TC_DEVICEID_BOOMERANG_10_100BT 0x9050 #define TC_DEVICEID_BOOMERANG_100BT4 0x9051 @@ -666,9 +683,9 @@ struct xl_stats { #define TC_DEVICEID_CYCLONE_10_100_COMBO 0x9058 #define TC_DEVICEID_CYCLONE_10_100FX 0x905A #define TC_DEVICEID_TORNADO_10_100BT 0x9200 +#define TC_DEVICEID_TORNADO_10_100BT_920B 0x9201 #define TC_DEVICEID_HURRICANE_10_100BT_SERV 0x9800 #define TC_DEVICEID_TORNADO_10_100BT_SERV 0x9805 -#define TC_DEVICEID_HURRICANE_SOHO100TX 0x7646 /* * 3Com CardBus chip device IDs. diff --git a/sys/dev/pci/if_xl_pci.c b/sys/dev/pci/if_xl_pci.c index 94c1dc5276a..404f052cd5b 100644 --- a/sys/dev/pci/if_xl_pci.c +++ b/sys/dev/pci/if_xl_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_xl_pci.c,v 1.18 2004/01/09 21:32:24 brad Exp $ */ +/* $OpenBSD: if_xl_pci.c,v 1.19 2004/05/30 23:49:39 brad Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -148,7 +148,7 @@ xl_pci_attach(parent, self, aux) sc->xl_flags = 0; - /* set flags required for 3Com MiniPCI adapters */ + /* set required flags */ switch (PCI_PRODUCT(pa->pa_id)) { case TC_DEVICEID_HURRICANE_555: sc->xl_flags |= XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_8BITROM; @@ -164,9 +164,12 @@ xl_pci_attach(parent, self, aux) XL_FLAG_EEPROM_OFFSET_30 | XL_FLAG_WEIRDRESET; sc->xl_flags |= XL_FLAG_INVERT_LED_PWR|XL_FLAG_INVERT_MII_PWR; break; - case PCI_PRODUCT_3COM_3C9201: + case PCI_PRODUCT_3COM_3C9201: sc->xl_flags |= XL_FLAG_PHYOK; break; + case TC_DEVICEID_BOOMERANG_10_100BT: + sc->xl_flags |= XL_FLAG_NO_MMIO; + break; default: break; } |