diff options
-rw-r--r-- | sys/dev/usb/if_mos.c | 76 | ||||
-rw-r--r-- | sys/dev/usb/if_mosreg.h | 19 |
2 files changed, 69 insertions, 26 deletions
diff --git a/sys/dev/usb/if_mos.c b/sys/dev/usb/if_mos.c index 509141bc53d..4b0d7cf7cd0 100644 --- a/sys/dev/usb/if_mos.c +++ b/sys/dev/usb/if_mos.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mos.c,v 1.5 2008/11/12 23:42:40 sthen Exp $ */ +/* $OpenBSD: if_mos.c,v 1.6 2008/11/22 09:46:12 deraadt Exp $ */ /* * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net> @@ -221,7 +221,7 @@ mos_reg_read_1(struct mos_softc *sc, int reg) if (err) { DPRINTF(("mos_reg_read_1 error, reg: %d\n", reg)); - return (0); + return (-1); } return (val); @@ -249,7 +249,7 @@ mos_reg_read_2(struct mos_softc *sc, int reg) if (err) { DPRINTF(("mos_reg_read_2 error, reg: %d\n", reg)); - return(0); + return (-1); } return(UGETW(val)); @@ -277,7 +277,7 @@ mos_reg_write_1(struct mos_softc *sc, int reg, int aval) if (err) { DPRINTF(("mos_reg_write_1 error, reg: %d\n", reg)); - return(-1); + return (-1); } return(0); @@ -293,7 +293,7 @@ mos_reg_write_2(struct mos_softc *sc, int reg, int aval) USETW(val, aval); if (sc->mos_dying) - return(0); + return (0); req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = MOS_UR_WRITEREG; @@ -305,10 +305,10 @@ mos_reg_write_2(struct mos_softc *sc, int reg, int aval) if (err) { DPRINTF(("mos_reg_write_2 error, reg: %d\n", reg)); - return(-1); + return (-1); } - return(0); + return (0); } int @@ -330,10 +330,10 @@ mos_readmac(struct mos_softc *sc, u_char *mac) if (err) { DPRINTF(("mos_readmac error")); - return(-1); + return (-1); } - return(0); + return (0); } int @@ -355,10 +355,10 @@ mos_writemac(struct mos_softc *sc, u_char *mac) if (err) { DPRINTF(("mos_writemac error")); - return(-1); + return (-1); } - return(0); + return (0); } int @@ -460,7 +460,16 @@ mos_miibus_statchg(struct device *dev) struct mii_data *mii = GET_MII(sc); int val, err; + mos_lock_mii(sc); + + /* disable RX, TX prior to changing FDX, SPEEDSEL */ val = mos_reg_read_1(sc, MOS_CTL); + val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); + mos_reg_write_1(sc, MOS_CTL, val); + + /* reset register which counts dropped frames */ + mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0); + if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) val |= MOS_CTL_FDX_ENB; else @@ -475,7 +484,11 @@ mos_miibus_statchg(struct device *dev) break; } + /* re-enable TX, RX */ + val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); err = mos_reg_write_1(sc, MOS_CTL, val); + mos_unlock_mii(sc); + if (err) { printf("%s: media change failed\n", sc->mos_dev.dv_xname); return; @@ -572,6 +585,9 @@ mos_reset(struct mos_softc *sc) /* Disable RX, TX, promiscuous and allmulticast mode */ mos_reg_write_1(sc, MOS_CTL, ctl); + /* Reset frame drop counter register to zero */ + mos_reg_write_1(sc, MOS_FRAME_DROP_CNT, 0); + /* Wait a little while for the chip to get its brains in order. */ DELAY(1000); return; @@ -580,17 +596,15 @@ mos_reset(struct mos_softc *sc) void mos_chip_init(struct mos_softc *sc) { - uByte val; int i; /* * Rev.C devices have a pause threshold register which needs to be set * at startup. */ - val = mos_reg_read_1(sc, MOS_MAC0); - if (val) { + if (mos_reg_read_1(sc, MOS_PAUSE_TRHD) != -1) { for (i=0;i<MOS_PAUSE_REWRITES;i++) - mos_reg_write_1(sc, MOS_CTL, 0); + mos_reg_write_1(sc, MOS_PAUSE_TRHD, 0); } sc->mos_phyaddrs[0] = 1; sc->mos_phyaddrs[1] = 0xFF; @@ -654,8 +668,7 @@ mos_attach(struct device *parent, struct device *self, void *aux) id = usbd_get_interface_descriptor(sc->mos_iface); - sc->mos_bufsz = (sc->mos_udev->speed == USB_SPEED_HIGH) ? - MOS_MAX_BUFSZ : MOS_MIN_BUFSZ; + sc->mos_bufsz = MOS_BUFSZ; /* Find endpoints. */ for (i = 0; i < id->bNumEndpoints; i++) { @@ -923,6 +936,7 @@ mos_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) struct mos_softc *sc = c->mos_sc; struct ifnet *ifp = GET_IFP(sc); u_char *buf = c->mos_buf; + u_int8_t rxstat; u_int32_t total_len; u_int16_t pktlen = 0; struct mbuf *m; @@ -953,12 +967,26 @@ mos_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) if (total_len <= 1) goto done; - /* status byte at the end */ + /* evaluate status byte at the end */ pktlen = total_len - 1; + rxstat = buf[pktlen] & MOS_RXSTS_MASK; + + if (rxstat != MOS_RXSTS_VALID) { + DPRINTF(("%s: erroneous frame received: ", + sc->mos_dev.dv_xname)); + if (rxstat & MOS_RXSTS_SHORT_FRAME) + DPRINTF(("frame size less than 64 bytes\n")); + if (rxstat & MOS_RXSTS_LARGE_FRAME) + DPRINTF(("frame size larger than 1532 bytes\n")); + if (rxstat & MOS_RXSTS_CRC_ERROR) + DPRINTF(("CRC error\n")); + if (rxstat & MOS_RXSTS_ALIGN_ERROR) + DPRINTF(("alignment error\n")); + ifp->if_ierrors++; + goto done; + } - /* 0x20 seems to indicate that the packet is OK */ - if ( ( pktlen < sizeof(struct ether_header) ) - || ( buf[pktlen] != 0x20 ) ) { + if ( pktlen < sizeof(struct ether_header) ) { ifp->if_ierrors++; goto done; } @@ -1100,7 +1128,7 @@ mos_tick_task(void *xsc) sc->mos_dev.dv_xname, __func__)); sc->mos_link++; if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) - mos_start(ifp); + mos_start(ifp); } timeout_add_sec(&sc->mos_stat_ch, 1); @@ -1217,7 +1245,9 @@ mos_init(void *xsc) return; } - /* Set transmitter IPG values */ + /* Read and set transmitter IPG values */ + sc->mos_ipgs[0] = mos_reg_read_1(sc, MOS_IPG0); + sc->mos_ipgs[1] = mos_reg_read_1(sc, MOS_IPG1); mos_reg_write_1(sc, MOS_IPG0, sc->mos_ipgs[0]); mos_reg_write_1(sc, MOS_IPG1, sc->mos_ipgs[1]); diff --git a/sys/dev/usb/if_mosreg.h b/sys/dev/usb/if_mosreg.h index 1cdcb1b0653..5b873689420 100644 --- a/sys/dev/usb/if_mosreg.h +++ b/sys/dev/usb/if_mosreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mosreg.h,v 1.2 2008/11/02 23:50:48 jsg Exp $ */ +/* $OpenBSD: if_mosreg.h,v 1.3 2008/11/22 09:46:12 deraadt Exp $ */ /* * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net> @@ -69,6 +69,7 @@ #define MOS_MAC5 0x14 #define MOS_MAC MOS_MAC0 /* apparently only available on hardware rev. C */ +#define MOS_FRAME_DROP_CNT 0x15 #define MOS_PAUSE_TRHD 0x16 #define MOS_PHYCTL_PHYADDR 0x1f @@ -94,6 +95,18 @@ /* 0 = PHY controls speed/duplex mode, 1 = bridge controls speed/duplex mode */ #define MOS_CTL_BS_ENB 0x80 +#define MOS_RXSTS_SHORT_FRAME 0x01 +#define MOS_RXSTS_LENGTH_ERROR 0x02 +#define MOS_RXSTS_ALIGN_ERROR 0x04 +#define MOS_RXSTS_CRC_ERROR 0x08 +#define MOS_RXSTS_LARGE_FRAME 0x10 +#define MOS_RXSTS_VALID 0x20 +/* + * The EtherType field of an Ethernet frame can contain values other than + * the frame length, hence length errors are ignored. + */ +#define MOS_RXSTS_MASK 0x3d + #define MOS_PAUSE_TRHD_DEFAULT 0 #define MOS_PAUSE_REWRITES 3 @@ -102,8 +115,8 @@ #define MOS_RX_LIST_CNT 1 #define MOS_TX_LIST_CNT 1 -#define MOS_MIN_BUFSZ 2048 -#define MOS_MAX_BUFSZ 16384 +/* Maximum size of a fast ethernet frame plus one byte for the status */ +#define MOS_BUFSZ (ETHER_MAX_LEN+1) /* * USB endpoints. |