📄 elnk.c
字号:
XL_SEL_WIN(1); sc->xl_stats.rxstatus = CSR_READ_2(sc, XL_W1_RX_STATUS ); sc->xl_stats.txstatus = CSR_READ_1(sc, XL_W1_TX_STATUS ); sc->xl_stats.smbstatus = CSR_READ_2(sc, 2 ); XL_SEL_WIN(3); sc->xl_stats.internalconfig = CSR_READ_4(sc, XL_W3_INTERNAL_CFG); sc->xl_stats.mac_control = CSR_READ_2(sc, XL_W3_MAC_CTRL); sc->xl_stats.txfree = CSR_READ_2(sc, XL_W3_FREE_TX ); /* Read all the stats registers. */ XL_SEL_WIN(6); sc->xl_stats.xl_carrier_lost += CSR_READ_1(sc, XL_W6_CARRIER_LOST); sc->xl_stats.xl_sqe_errs += CSR_READ_1(sc, XL_W6_SQE_ERRORS); sc->xl_stats.xl_tx_multi_collision += CSR_READ_1(sc, XL_W6_COL_MULTIPLE); sc->xl_stats.xl_tx_single_collision += CSR_READ_1(sc, XL_W6_COL_SINGLE); sc->xl_stats.xl_tx_late_collision += CSR_READ_1(sc, XL_W6_COL_LATE); sc->xl_stats.xl_rx_overrun += CSR_READ_1(sc, XL_W6_RX_OVERRUN); sc->xl_stats.xl_tx_deferred += CSR_READ_1(sc, XL_W6_DEFERRED); sc->xl_stats.xl_tx_frames_ok += CSR_READ_1(sc, XL_W6_TX_OK); sc->xl_stats.xl_rx_frames_ok += CSR_READ_1(sc, XL_W6_RX_OK); sc->xl_stats.xl_rx_bytes_ok += CSR_READ_2(sc, XL_W6_TX_BYTES_OK ); sc->xl_stats.xl_tx_bytes_ok += CSR_READ_2(sc, XL_W6_RX_BYTES_OK ); t1 = CSR_READ_1(sc, XL_W6_UPPER_FRAMES_OK); sc->xl_stats.xl_rx_frames_ok += ((t1 & 0x3) << 8); sc->xl_stats.xl_tx_frames_ok += (((t1 >> 4) & 0x3) << 8); ifp->if_ierrors += sc->xl_stats.xl_rx_overrun; ifp->if_collisions += sc->xl_stats.xl_tx_multi_collision + sc->xl_stats.xl_tx_single_collision + sc->xl_stats.xl_tx_late_collision; /* * Boomerang and cyclone chips have an extra stats counter * in window 4 (BadSSD). We have to read this too in order * to clear out all the stats registers and avoid a statsoflow * interrupt. */ XL_SEL_WIN(4); t1 = CSR_READ_1(sc, XL_W4_UPPERBYTESOK); sc->xl_stats.xl_rx_bytes_ok += ((t1 & 0xf) << 16); sc->xl_stats.xl_tx_bytes_ok += (((t1 >> 4) & 0xf) << 16); sc->xl_stats.xl_badssd += CSR_READ_1(sc, XL_W4_BADSSD); sc->xl_stats.mediastatus = CSR_READ_2(sc, XL_W4_MEDIA_STATUS ); sc->xl_stats.dmactl = CSR_READ_4(sc, XL_DMACTL ); XL_SEL_WIN(7); if (!sc->xl_stats_no_timeout) rtems_timer_fire_after( sc->stat_timer_id, sc->stats_update_ticks, xl_stats_update, (void *)sc ); return;}static voidxl_reset(sc) struct elnk_softc *sc;{ register int i; XL_SEL_WIN(0); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RESET | ((sc->xl_flags & XL_FLAG_WEIRDRESET) ? XL_RESETOPT_DISADVFD:0)); for (i = 0; i < XL_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_2(sc, XL_STATUS) & XL_STAT_CMDBUSY)) break; } if (i == XL_TIMEOUT) printk("etherlink : unit elnk%d reset didn't complete\n", sc->xl_unit); /* 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_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) | ((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. */ DELAY(100000); return;}static voidxl_stop(sc) struct elnk_softc *sc;{ struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; rtems_timer_cancel( sc->stat_timer_id ); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISABLE); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISCARD); xl_wait(sc); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_TX_DISABLE); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP); DELAY(800); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|XL_STAT_INTLATCH); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|0); CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0); return;}static voidxl_setcfg(sc) struct elnk_softc *sc;{ u_int32_t icfg; XL_SEL_WIN(3); 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) 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); XL_SEL_WIN(7); return;}static voidxl_setmode(sc, media) struct elnk_softc *sc; int media;{ u_int32_t icfg; u_int16_t mediastat; printk("etherlink : unit elnk%d selecting ", sc->xl_unit); XL_SEL_WIN(4); mediastat = CSR_READ_2(sc, XL_W4_MEDIA_STATUS); XL_SEL_WIN(3); icfg = CSR_READ_4(sc, XL_W3_INTERNAL_CFG); if (sc->xl_media & XL_MEDIAOPT_BT) { if (IFM_SUBTYPE(media) == IFM_10_T) { printk("10baseT transceiver, "); sc->xl_xcvr = XL_XCVR_10BT; icfg &= ~XL_ICFG_CONNECTOR_MASK; icfg |= (XL_XCVR_10BT << XL_ICFG_CONNECTOR_BITS); mediastat |= XL_MEDIASTAT_LINKBEAT| XL_MEDIASTAT_JABGUARD; mediastat &= ~XL_MEDIASTAT_SQEENB; } } if (sc->xl_media & XL_MEDIAOPT_BFX) { if (IFM_SUBTYPE(media) == IFM_100_FX) { printk("100baseFX port, "); sc->xl_xcvr = XL_XCVR_100BFX; icfg &= ~XL_ICFG_CONNECTOR_MASK; icfg |= (XL_XCVR_100BFX << XL_ICFG_CONNECTOR_BITS); mediastat |= XL_MEDIASTAT_LINKBEAT; mediastat &= ~XL_MEDIASTAT_SQEENB; } } if (sc->xl_media & (XL_MEDIAOPT_AUI|XL_MEDIAOPT_10FL)) { if (IFM_SUBTYPE(media) == IFM_10_5) { printk("AUI port, "); sc->xl_xcvr = XL_XCVR_AUI; icfg &= ~XL_ICFG_CONNECTOR_MASK; icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS); mediastat &= ~(XL_MEDIASTAT_LINKBEAT| XL_MEDIASTAT_JABGUARD); mediastat |= ~XL_MEDIASTAT_SQEENB; } if (IFM_SUBTYPE(media) == IFM_10_FL) { printk("10baseFL transceiver, "); sc->xl_xcvr = XL_XCVR_AUI; icfg &= ~XL_ICFG_CONNECTOR_MASK; icfg |= (XL_XCVR_AUI << XL_ICFG_CONNECTOR_BITS); mediastat &= ~(XL_MEDIASTAT_LINKBEAT| XL_MEDIASTAT_JABGUARD); mediastat |= ~XL_MEDIASTAT_SQEENB; } } if (sc->xl_media & XL_MEDIAOPT_BNC) { if (IFM_SUBTYPE(media) == IFM_10_2) { printk("BNC port, "); sc->xl_xcvr = XL_XCVR_COAX; icfg &= ~XL_ICFG_CONNECTOR_MASK; icfg |= (XL_XCVR_COAX << XL_ICFG_CONNECTOR_BITS); mediastat &= ~(XL_MEDIASTAT_LINKBEAT| XL_MEDIASTAT_JABGUARD| XL_MEDIASTAT_SQEENB); } } if ((media & IFM_GMASK) == IFM_FDX || IFM_SUBTYPE(media) == IFM_100_FX) { printk("full duplex\n"); XL_SEL_WIN(3); CSR_WRITE_1(sc, XL_W3_MAC_CTRL, XL_MACCTRL_DUPLEX); } else { printk("half duplex\n"); XL_SEL_WIN(3); CSR_WRITE_1(sc, XL_W3_MAC_CTRL, (CSR_READ_1(sc, XL_W3_MAC_CTRL) & ~XL_MACCTRL_DUPLEX)); } if (IFM_SUBTYPE(media) == IFM_10_2) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_START); else CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_COAX_STOP); CSR_WRITE_4(sc, XL_W3_INTERNAL_CFG, icfg); XL_SEL_WIN(4); CSR_WRITE_2(sc, XL_W4_MEDIA_STATUS, mediastat); DELAY(800); XL_SEL_WIN(7); return;}static voidxl_choose_xcvr(sc, verbose) struct elnk_softc *sc; int verbose;{ u_int16_t devid; /* * Read the device ID from the EEPROM. * This is what's loaded into the PCI device ID register, so it has * to be correct otherwise we wouldn't have gotten this far. */ xl_read_eeprom(sc, (caddr_t)&devid, XL_EE_PRODID, 1, 0); switch(devid) { case TC_DEVICEID_BOOMERANG_10BT: /* 3c900-TPO */ case TC_DEVICEID_KRAKATOA_10BT: /* 3c900B-TPO */ sc->xl_media = XL_MEDIAOPT_BT; sc->xl_xcvr = XL_XCVR_10BT; if (verbose) printk("etherlink : unit elnk%d guessing 10BaseT " "transceiver\n", sc->xl_unit); break; case TC_DEVICEID_BOOMERANG_10BT_COMBO: /* 3c900-COMBO */ case TC_DEVICEID_KRAKATOA_10BT_COMBO: /* 3c900B-COMBO */ sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI; sc->xl_xcvr = XL_XCVR_10BT; if (verbose) printk("etherlink : unit elnk%d guessing COMBO " "(AUI/BNC/TP)\n", sc->xl_unit); break; case TC_DEVICEID_KRAKATOA_10BT_TPC: /* 3c900B-TPC */ sc->xl_media = XL_MEDIAOPT_BT|XL_MEDIAOPT_BNC; sc->xl_xcvr = XL_XCVR_10BT; if (verbose) printk("etherlink : unit elnk%d guessing TPC (BNC/TP)\n", sc->xl_unit); break; case TC_DEVICEID_CYCLONE_10FL: /* 3c900B-FL */ sc->xl_media = XL_MEDIAOPT_10FL; sc->xl_xcvr = XL_XCVR_AUI; if (verbose) printk("etherlink : unit elnk%d guessing 10baseFL\n", sc->xl_unit); break; case TC_DEVICEID_BOOMERANG_10_100BT: /* 3c905-TX */ 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) printk("etherlink : unit elnk%d guessing MII\n", sc->xl_unit); break; case TC_DEVICEID_BOOMERANG_100BT4: /* 3c905-T4 */ case TC_DEVICEID_CYCLONE_10_100BT4: /* 3c905B-T4 */ sc->xl_media = XL_MEDIAOPT_BT4; sc->xl_xcvr = XL_XCVR_MII; if (verbose) printk("etherlink : unit elnk%d guessing 100BaseT4/MII\n", sc->xl_unit); break; case TC_DEVICEID_HURRICANE_10_100BT: /* 3c905B-TX */ case TC_DEVICEID_HURRICANE_10_100BT_SERV:/*3c980-TX */ case TC_DEVICEID_TORNADO_10_100BT_SERV: /* 3c980C-TX */ case TC_DEVICEID_HURRICANE_SOHO100TX: /* 3cSOHO100-TX */ case TC_DEVICEID_TORNADO_10_100BT: /* 3c905C-TX */ case TC_DEVICEID_TORNADO_HOMECONNECT: /* 3c450-TX */ sc->xl_media = XL_MEDIAOPT_BTX; sc->xl_xcvr = XL_XCVR_AUTO; if (verbose) printk("etherlink : unit elnk%d guessing 10/100 internal\n", sc->xl_unit); break; case TC_DEVICEID_CYCLONE_10_100_COMBO: /* 3c905B-COMBO */ sc->xl_media = XL_MEDIAOPT_BTX|XL_MEDIAOPT_BNC|XL_MEDIAOPT_AUI; sc->xl_xcvr = XL_XCVR_AUTO; if (verbose) printk("etherlink : unit elnk%d guessing 10/100 " "plus BNC/AUI\n", sc->xl_unit); break; default: printk("etherlink : unit elnk%d unknown device ID: %x -- " "defaulting to 10baseT\n", sc->xl_unit, devid); sc->xl_media = XL_MEDIAOPT_BT; break; } return;}/* * This routine is a kludge to work around possible hardware faults * or manufacturing defects that can cause the media options register * (or reset options register, as it's called for the first generation * 3c90x adapters) to return an incorrect result. I have encountered * one Dell Latitude laptop docking station with an integrated 3c905-TX * which doesn't have any of the 'mediaopt' bits set. This screws up * the attach routine pretty badly because it doesn't know what media * to look for. If we find ourselves in this predicament, this routine * will try to guess the media options values and warn the user of a * possible manufacturing defect with his adapter/system/whatever. */static voidxl_mediacheck(sc) struct elnk_softc *sc;{ xl_choose_xcvr(sc, 1); /* * If some of the media options bits are set, assume they are * correct. If not, try to figure it out down below. * XXX I should check for 10baseFL, but I don't have an adapter * to test with. */ if (sc->xl_media & (XL_MEDIAOPT_MASK & ~XL_MEDIAOPT_VCO)) { /* * Check the XCVR value. If it's not in the normal range * of values, we need to fake it up here. */ if (sc->xl_xcvr <= XL_XCVR_AUTO) return; else { printk("etherlink : unit elnk%d bogus xcvr value " "in EEPROM (%x)\n", sc->xl_unit, sc->xl_xcvr); printk("etherlink : unit elnk%d choosing new default based " "on card type\n", sc->xl_unit); } } else { if (sc->xl_type == XL_TYPE_905B && sc->xl_media & XL_MEDIAOPT_10FL) return; printk("etherlink : unit elnk%d WARNING: no media options bits set in " "the media options register!!\n", sc->xl_unit); printk("etherlink : unit elnk%d this could be a manufacturing defect in " "your adapter or system\n", sc->xl_unit); printk("etherlink : unit elnk%d attempting to guess media type; you " "should probably consult your vendor\n", sc->xl_unit); } return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -