diff options
author | mjacob <mjacob@cvs.openbsd.org> | 2000-07-06 06:19:09 +0000 |
---|---|---|
committer | mjacob <mjacob@cvs.openbsd.org> | 2000-07-06 06:19:09 +0000 |
commit | bc5d062a9c0ec8e606bf190319ea0317f2525ee0 (patch) | |
tree | e2dd110ec78b9dcf082d506cadefc1296e40579c /sys/dev/pci/if_wx.c | |
parent | e510074a97760fd6a6de9476c9ffdd5e37080a51 (diff) |
Port latest in from FreeBSD- finally have some of the link issues sorted
out so we should now be able to work with switches.
Diffstat (limited to 'sys/dev/pci/if_wx.c')
-rw-r--r-- | sys/dev/pci/if_wx.c | 153 |
1 files changed, 126 insertions, 27 deletions
diff --git a/sys/dev/pci/if_wx.c b/sys/dev/pci/if_wx.c index abe7c423a8b..5d1a50a70e1 100644 --- a/sys/dev/pci/if_wx.c +++ b/sys/dev/pci/if_wx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wx.c,v 1.3 2000/04/26 23:16:12 chris Exp $ */ +/* $OpenBSD: if_wx.c,v 1.4 2000/07/06 06:19:08 mjacob Exp $ */ /* * Copyright (c) 1999, Traakan Software @@ -75,6 +75,7 @@ static int wx_intr __P((void *)); static void wx_handle_link_intr __P((wx_softc_t *)); +static void wx_check_link __P((wx_softc_t *)); static void wx_handle_rxint __P((wx_softc_t *)); static void wx_gc __P((wx_softc_t *)); static void wx_start __P((struct ifnet *)); @@ -86,7 +87,7 @@ static void wx_hw_stop __P((wx_softc_t *)); static void wx_set_addr __P((wx_softc_t *, int, u_int8_t *)); static int wx_hw_initialize __P((wx_softc_t *)); static void wx_stop __P((wx_softc_t *)); -static void wx_watchdog __P((struct ifnet *)); +static void wx_txwatchdog __P((struct ifnet *)); static int wx_get_rbuf __P((wx_softc_t *, rxpkt_t *)); static void wx_rxdma_map __P((wx_softc_t *, rxpkt_t *, struct mbuf *)); @@ -99,7 +100,7 @@ static INLINE u_int16_t wx_read_eeprom_word __P((wx_softc_t *, int)); static void wx_read_eeprom __P((wx_softc_t *, u_int16_t *, int, int)); static int wx_attach_common __P((wx_softc_t *)); -static void wx_stats_update __P((void *)); +static void wx_watchdog __P((void *)); static INLINE void wx_mwi_whackon __P((wx_softc_t *)); static INLINE void wx_mwi_unwhack __P((wx_softc_t *)); @@ -255,7 +256,7 @@ wx_attach(parent, self, aux) ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = wx_ioctl; ifp->if_start = wx_start; - ifp->if_watchdog = wx_watchdog; + ifp->if_watchdog = wx_txwatchdog; /* * Attach the interface. @@ -650,7 +651,7 @@ wx_attach(device_t dev) ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = wx_ioctl; ifp->if_start = wx_start; - ifp->if_watchdog = wx_watchdog; + ifp->if_watchdog = wx_txwatchdog; if_attach(ifp); ifp->if_snd.ifq_maxlen = WX_MAX_TDESC - 1; ether_ifattach(ifp); @@ -784,23 +785,32 @@ wx_attach_common(sc) int ll = 0; /* - * First, reset the chip. + * First, check for revision support. + */ + if (sc->revision < 2) { + printf("%s: cannot support revision %d chips\n", + sc->wx_name, sc->revision); + return (ENXIO); + } + + /* + * Second, reset the chip. */ wx_hw_stop(sc); /* - * Second, validate our EEPROM. + * Third, validate our EEPROM. */ /* TBD */ /* - * Third, read eeprom for our MAC address and other things. + * Fourth, read eeprom for our MAC address and other things. */ wx_read_eeprom(sc, (u_int16_t *)sc->wx_enaddr, WX_EEPROM_MAC_OFF, 3); /* - * Fourth, establish some adapter parameters. + * Fifth, establish some adapter parameters. */ sc->wx_txint_delay = 128; ifmedia_init(&sc->wx_media, IFM_IMASK, wx_ifmedia_upd, wx_ifmedia_sts); @@ -811,7 +821,7 @@ wx_attach_common(sc) ll += 1; /* - * Fifth, establish a default device control register word. + * Sixth, establish a default device control register word. */ sc->wx_dcr = 0; if (sc->wx_cfg1 & WX_EEPROM_CTLR1_FD) @@ -831,7 +841,7 @@ wx_attach_common(sc) /* - * Sixth, allocate various sw structures... + * Seventh, allocate various sw structures... */ len = sizeof (rxpkt_t) * WX_MAX_RDESC; sc->rbase = (rxpkt_t *) WXMALLOC(len); @@ -850,7 +860,7 @@ wx_attach_common(sc) ll += 1; /* - * Seventh, allocate and dma map (platform dependent) descriptor rings. + * Eighth, allocate and dma map (platform dependent) descriptor rings. * They have to be aligned on a 4KB boundary. */ if (wx_dring_setup(sc) == 0) { @@ -1207,8 +1217,82 @@ static void wx_handle_link_intr(sc) wx_softc_t *sc; { + u_int32_t txcw, rxcw, dcr, dsr; + sc->wx_linkintr++; - printf("%s: link intr 0x%x\n", sc->wx_name, sc->wx_icr); + + dcr = READ_CSR(sc, WXREG_DCR); + txcw = READ_CSR(sc, WXREG_XMIT_CFGW); + rxcw = READ_CSR(sc, WXREG_RECV_CFGW); + dsr = READ_CSR(sc, WXREG_DSR); + + /* + * If we have LOS or are now receiving Ordered Sets and are not + * doing auto-negotiation, restore autonegotiation. + */ + + if (((dcr & WXDCR_SWDPIN1) || (rxcw & WXRXCW_C)) && + ((txcw & WXTXCW_ANE) == 0)) { + if (sc->wx_debug) { + printf("%s: /C/ ordered sets seen- enabling ANE\n", + sc->wx_name); + } + WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT); + sc->wx_dcr &= ~WXDCR_SLU; + WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); + sc->ane_failed = 0; + } + + if (sc->wx_icr & WXISR_LSC) { + if (READ_CSR(sc, WXREG_DSR) & WXDSR_LU) { + printf("%s: gigabit link now up\n", sc->wx_name); + sc->linkup = 1; + sc->wx_dcr |= (WXDCR_SWDPIO0|WXDCR_SWDPIN0); + } else { + printf("%s: gigabit link now down\n", sc->wx_name); + sc->linkup = 0; + sc->wx_dcr &= ~(WXDCR_SWDPIO0|WXDCR_SWDPIN0); + } + WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); + } else { + printf("%s: receive sequence error\n", sc->wx_name); + } +} + +static void +wx_check_link(sc) + wx_softc_t *sc; +{ + u_int32_t rxcw, dcr, dsr; + + rxcw = READ_CSR(sc, WXREG_RECV_CFGW); + dcr = READ_CSR(sc, WXREG_DCR); + dsr = READ_CSR(sc, WXREG_DSR); + + if ((dsr & WXDSR_LU) == 0 && (dcr & WXDCR_SWDPIN1) == 0 && + (rxcw & WXRXCW_C) == 0) { + if (sc->ane_failed == 0) { + sc->ane_failed = 1; + return; + } + if (sc->wx_debug) { + printf("%s: no /C/ ordered sets seen- disabling ANE\n", + sc->wx_name); + } + WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT & ~WXTXCW_ANE); + if (sc->revision == 2) + sc->wx_dcr &= ~WXDCR_TFCE; + sc->wx_dcr |= WXDCR_SLU; + WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); + } else if ((rxcw & WXRXCW_C) != 0 && (dcr & WXDCR_SLU) != 0) { + if (sc->wx_debug) { + printf("%s: /C/ ordered sets seen- enabling ANE\n", + sc->wx_name); + } + WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT); + sc->wx_dcr &= ~WXDCR_SLU; + WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); + } } static void @@ -1490,10 +1574,12 @@ wx_gc(sc) } /* - * Update packet in/out/collision statistics. + * Periodic timer to update packet in/out/collision statistics, + * and, more importantly, garbage collect completed transmissions + * and to handle link status changes. */ static void -wx_stats_update(arg) +wx_watchdog(arg) void *arg; { wx_softc_t *sc = arg; @@ -1501,12 +1587,13 @@ wx_stats_update(arg) s = splimp(); wx_gc(sc); + wx_check_link(sc); splx(s); /* * Schedule another timeout one second from now. */ - TIMEOUT(sc, wx_stats_update, sc, hz); + TIMEOUT(sc, wx_watchdog, sc, hz); } /* @@ -1591,6 +1678,13 @@ wx_hw_initialize(sc) for (i = 0; i < WX_MC_TAB_SIZE; i++) { WRITE_CSR(sc, WXREG_MTA + (sizeof (u_int32_t) * 4), 0); } + + /* + * Handle link control + */ + WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr | WXDCR_LRST); + DELAY(50 * 1000); + if (sc->wx_dcr & (WXDCR_RFCE|WXDCR_TFCE)) { WRITE_CSR(sc, WXREG_FCAL, FC_FRM_CONST_LO); WRITE_CSR(sc, WXREG_FCAH, FC_FRM_CONST_HI); @@ -1604,6 +1698,7 @@ wx_hw_initialize(sc) if (sc->revision == 2) { WRITE_CSR(sc, WXREG_FLOW_RCV_HI, 0); WRITE_CSR(sc, WXREG_FLOW_RCV_LO, 0); + sc->wx_dcr &= ~(WXDCR_RFCE|WXDCR_TFCE); } else { WRITE_CSR(sc, WXREG_FLOW_RCV_HI, WX_RCV_FLOW_HI_DFLT); WRITE_CSR(sc, WXREG_FLOW_RCV_LO, WX_RCV_FLOW_LO_DFLT); @@ -1616,20 +1711,22 @@ wx_hw_initialize(sc) * The pin stuff is all FM from the Linux driver. */ if ((READ_CSR(sc, WXREG_DCR) & WXDCR_SWDPIN1) == 0) { - for (i = 0; i < 500; i++) { + for (i = 0; i < (WX_LINK_UP_TIMEOUT/10); i++) { DELAY(10 * 1000); if (READ_CSR(sc, WXREG_DSR) & WXDSR_LU) { sc->linkup = 1; break; } } + if (sc->linkup == 0) { + sc->ane_failed = 1; + wx_check_link(sc); + } + sc->ane_failed = 0; } else { - printf("%s: swdpio did not clear\n", sc->wx_name); - return (-1); - } - if (sc->linkup == 0) { - printf("%s: link never came up\n", sc->wx_name); - return (-1); + printf("%s: swdpio1 did not clear- check for reversed or " + "disconnected cable\n", sc->wx_name); + /* but return okay anyway */ } sc->wx_ienable = WXIENABLE_DEFAULT; return (0); @@ -1649,7 +1746,7 @@ wx_stop(sc) /* * Cancel stats updater. */ - UNTIMEOUT(wx_stats_update, sc, sc); + UNTIMEOUT(wx_watchdog, sc, sc); /* * Reset the chip @@ -1690,10 +1787,10 @@ wx_stop(sc) } /* - * Watchdog/transmission transmit timeout handler. + * Transmit Watchdog */ static void -wx_watchdog(ifp) +wx_txwatchdog(ifp) struct ifnet *ifp; { wx_softc_t *sc = SOFTC_IFP(ifp); @@ -1826,7 +1923,7 @@ wx_init(xsc) /* * Start stats updater. */ - TIMEOUT(sc, wx_stats_update, sc, hz); + TIMEOUT(sc, wx_watchdog, sc, hz); /* * And we're outta here... @@ -1895,6 +1992,7 @@ wx_ioctl(ifp, command, data) error = ether_ioctl(ifp, command, data); break; +#ifdef SIOCGIFMTU case SIOCSIFMTU: if (ifr->ifr_mtu > WX_MAXMTU || ifr->ifr_mtu < ETHERMIN) { error = EINVAL; @@ -1903,6 +2001,7 @@ wx_ioctl(ifp, command, data) error = wx_init(sc); } break; +#endif case SIOCSIFFLAGS: sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; |