📄 if_wx.c
字号:
/* * Free all the receive buffers. */ for (rxp = sc->rbase; rxp && rxp < &sc->rbase[WX_MAX_RDESC]; rxp++) { if (rxp->dptr) { m_free(rxp->dptr); rxp->dptr = NULL; } } if (sc->rpending) { m_freem(sc->rpending); sc->rpending = NULL; } /* * And we're outta here... */ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); ifp->if_timer = 0;}/* * Transmit Watchdog */static voidwx_txwatchdog(struct ifnet *ifp){ wx_softc_t *sc = SOFTC_IFP(ifp); printf("%s: device timeout\n", sc->wx_name); ifp->if_oerrors++; if (wx_init(sc)) { printf("%s: could not re-init device\n", sc->wx_name); sc->wx_needreinit = 1; }}static intwx_init(void *xsc){ struct ifmedia *ifm; wx_softc_t *sc = xsc; struct ifnet *ifp = &sc->wx_if; rxpkt_t *rxpkt; wxrd_t *rd; size_t len; int i, bflags; DPRINTF(sc, ("%s: wx_init\n", sc->wx_name)); WX_LOCK(sc); /* * Cancel any pending I/O by resetting things. * wx_stop will free any allocated mbufs. */ wx_stop(sc); /* * Reset the hardware. All network addresses loaded here, but * neither the receiver nor the transmitter are enabled. */ if (wx_hw_initialize(sc)) { DPRINTF(sc, ("%s: wx_hw_initialize failed\n", sc->wx_name)); WX_UNLOCK(sc); return (EIO); } /* * Set up the receive ring stuff. */ len = sizeof (wxrd_t) * WX_MAX_RDESC; bzero(sc->rdescriptors, len); for (rxpkt = sc->rbase, i = 0; rxpkt != NULL && i < WX_MAX_RDESC; i += RXINCR, rxpkt++) { rd = &sc->rdescriptors[i]; if (wx_get_rbuf(sc, rxpkt)) { break; } rd->address.lowpart = htole32(rxpkt->dma_addr + WX_RX_OFFSET_VALUE); } if (i != WX_MAX_RDESC) { printf("%s: could not set up rbufs\n", sc->wx_name); wx_stop(sc); WX_UNLOCK(sc); return (ENOMEM); } CACHESYNC(&sc->rdescriptors[0], sizeof (wxrd_t) * WX_MAX_RDESC, SYNC_W); CACHESYNC(&sc->rdescriptors[0], sizeof (wxrd_t) * WX_MAX_RDESC, SYNC_R); /* * Set up transmit parameters and enable the transmitter. */ sc->tnxtfree = sc->tactive = 0; sc->tbsyf = sc->tbsyl = NULL; CACHESYNC(&sc->tdescriptors[0], sizeof (wxtd_t) * WX_MAX_TDESC, SYNC_W); CACHESYNC(&sc->tdescriptors[0], sizeof (wxtd_t) * WX_MAX_TDESC, SYNC_R); WRITE_CSR(sc, WXREG_TCTL, 0); DELAY(5 * 1000); if (IS_WISEMAN(sc)) { WRITE_CSR(sc, WXREG_TDBA_LO, vtophys((vm_offset_t)&sc->tdescriptors[0])); WRITE_CSR(sc, WXREG_TDBA_HI, 0); WRITE_CSR(sc, WXREG_TDLEN, WX_MAX_TDESC * sizeof (wxtd_t)); WRITE_CSR(sc, WXREG_TDH, 0); WRITE_CSR(sc, WXREG_TDT, 0); WRITE_CSR(sc, WXREG_TQSA_HI, 0); WRITE_CSR(sc, WXREG_TQSA_LO, 0); WRITE_CSR(sc, WXREG_TIPG, WX_WISEMAN_TIPG_DFLT); WRITE_CSR(sc, WXREG_TIDV, 5000); } else { WRITE_CSR(sc, WXREG_TDBA_LO_LIVENGOOD, vtophys((vm_offset_t)&sc->tdescriptors[0])); WRITE_CSR(sc, WXREG_TDBA_HI_LIVENGOOD, 0); WRITE_CSR(sc, WXREG_TDLEN_LIVENGOOD, WX_MAX_TDESC * sizeof (wxtd_t)); WRITE_CSR(sc, WXREG_TDH_LIVENGOOD, 0); WRITE_CSR(sc, WXREG_TDT_LIVENGOOD, 0); WRITE_CSR(sc, WXREG_TQSA_HI, 0); WRITE_CSR(sc, WXREG_TQSA_LO, 0); WRITE_CSR(sc, WXREG_TIPG, WX_LIVENGOOD_TIPG_DFLT); WRITE_CSR(sc, WXREG_TIDV_LIVENGOOD, 5000); } WRITE_CSR(sc, WXREG_TCTL, (WXTCTL_CT(WX_COLLISION_THRESHOLD) | WXTCTL_COLD(WX_FDX_COLLISION_DX) | WXTCTL_EN)); /* * Set up receive parameters and enable the receiver. */ sc->rnxt = 0; WRITE_CSR(sc, WXREG_RCTL, 0); DELAY(5 * 1000); if (IS_WISEMAN(sc)) { WRITE_CSR(sc, WXREG_RDTR0, WXRDTR_FPD); WRITE_CSR(sc, WXREG_RDBA0_LO, vtophys((vm_offset_t)&sc->rdescriptors[0])); WRITE_CSR(sc, WXREG_RDBA0_HI, 0); WRITE_CSR(sc, WXREG_RDLEN0, WX_MAX_RDESC * sizeof (wxrd_t)); WRITE_CSR(sc, WXREG_RDH0, 0); WRITE_CSR(sc, WXREG_RDT0, (WX_MAX_RDESC - RXINCR)); } else { /* * The delay should yield ~10us receive interrupt delay */ WRITE_CSR(sc, WXREG_RDTR0_LIVENGOOD, WXRDTR_FPD | 0x40); WRITE_CSR(sc, WXREG_RDBA0_LO_LIVENGOOD, vtophys((vm_offset_t)&sc->rdescriptors[0])); WRITE_CSR(sc, WXREG_RDBA0_HI_LIVENGOOD, 0); WRITE_CSR(sc, WXREG_RDLEN0_LIVENGOOD, WX_MAX_RDESC * sizeof (wxrd_t)); WRITE_CSR(sc, WXREG_RDH0_LIVENGOOD, 0); WRITE_CSR(sc, WXREG_RDT0_LIVENGOOD, (WX_MAX_RDESC - RXINCR)); } WRITE_CSR(sc, WXREG_RDTR1, 0); WRITE_CSR(sc, WXREG_RDBA1_LO, 0); WRITE_CSR(sc, WXREG_RDBA1_HI, 0); WRITE_CSR(sc, WXREG_RDLEN1, 0); WRITE_CSR(sc, WXREG_RDH1, 0); WRITE_CSR(sc, WXREG_RDT1, 0); if (ifp->if_mtu > ETHERMTU) { bflags = WXRCTL_EN | WXRCTL_LPE | WXRCTL_2KRBUF; } else { bflags = WXRCTL_EN | WXRCTL_2KRBUF; } WRITE_CSR(sc, WXREG_RCTL, bflags | ((ifp->if_flags & IFF_BROADCAST) ? WXRCTL_BAM : 0) | ((ifp->if_flags & IFF_PROMISC) ? WXRCTL_UPE : 0) | ((sc->all_mcasts) ? WXRCTL_MPE : 0)); /* * Enable Interrupts */ WX_ENABLE_INT(sc); if (sc->wx_mii) { mii_mediachg(WX_MII_FROM_SOFTC(sc)); } else { ifm = &sc->wx_media; i = ifm->ifm_media; ifm->ifm_media = ifm->ifm_cur->ifm_media; wx_ifmedia_upd(ifp); ifm->ifm_media = i; } /* * Mark that we're up and running... */ ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; /* * Start stats updater. */ TIMEOUT(sc, wx_watchdog, sc, hz); WX_UNLOCK(sc); /* * And we're outta here... */ return (0);}/* * Get a receive buffer for our use (and dma map the data area). * * The Wiseman chip can have buffers be 256, 512, 1024 or 2048 bytes in size. * The LIVENGOOD chip can go higher (up to 16K), but what's the point as * we aren't doing non-MCLGET memory management. * * It wants them aligned on 256 byte boundaries, but can actually cope * with an offset in the first 255 bytes of the head of a receive frame. * * We'll allocate a MCLBYTE sized cluster but *not* adjust the data pointer * by any alignment value. Instead, we'll tell the chip to offset by any * alignment and we'll catch the alignment on the backend at interrupt time. */static voidwx_rxdma_map(wx_softc_t *sc, rxpkt_t *rxpkt, struct mbuf *mb){ rxpkt->dptr = mb; rxpkt->dma_addr = vtophys(mtod(mb, vm_offset_t)); CACHESYNC(mtod(mb, vm_offset_t), MCLBYTES, SYNC_R); CACHESYNC(rxpkt, sizeof(rxpkt_t), SYNC_W);}static intwx_get_rbuf(wx_softc_t *sc, rxpkt_t *rxpkt){ struct mbuf *mb; MGETHDR(mb, M_DONTWAIT, MT_DATA); if (mb == NULL) { rxpkt->dptr = NULL; return (-1); } MCLGET(mb, M_DONTWAIT); if ((mb->m_flags & M_EXT) == 0) { m_freem(mb); rxpkt->dptr = NULL; return (-1); } wx_rxdma_map(sc, rxpkt, mb); return (0);}static intwx_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data){ wx_softc_t *sc = SOFTC_IFP(ifp); struct ifreq *ifr = (struct ifreq *) data; int error = 0; WX_LOCK(sc); switch (command) { case SIOCSIFADDR: case SIOCGIFADDR: error = ether_ioctl(ifp, command, data); break;#ifndef PMON case SIOCSIFMTU: if (ifr->ifr_mtu > WX_MAXMTU || ifr->ifr_mtu < ETHERMIN) { error = EINVAL; } else if (ifp->if_mtu != ifr->ifr_mtu) { ifp->if_mtu = ifr->ifr_mtu; error = wx_init(sc); } break;#endif case SIOCSIFFLAGS: sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; /* * If interface is marked up and not running, then start it. * If it is marked down and running, stop it. * If it's up then re-initialize it. This is so flags * such as IFF_PROMISC are handled. */ if (ifp->if_flags & IFF_UP) { if ((ifp->if_flags & IFF_RUNNING) == 0) { error = wx_init(sc); } } else { if (ifp->if_flags & IFF_RUNNING) { wx_stop(sc); } } break; case SIOCADDMULTI: case SIOCDELMULTI: sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; error = wx_mc_setup(sc); break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: DPRINTF(sc, ("%s: ioctl SIOC[GS]IFMEDIA: command=%#lx\n", sc->wx_name, command)); if (sc->wx_mii) { mii_data_t *mii = WX_MII_FROM_SOFTC(sc); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); } else { error = ifmedia_ioctl(ifp, ifr, &sc->wx_media, command); } break; default: error = EINVAL; } WX_UNLOCK(sc); return (error);}static intwx_ifmedia_upd(struct ifnet *ifp){ struct wx_softc *sc = SOFTC_IFP(ifp); struct ifmedia *ifm; DPRINTF(sc, ("%s: ifmedia_upd\n", sc->wx_name)); if (sc->wx_mii) { mii_mediachg(WX_MII_FROM_SOFTC(sc)); return 0; } ifm = &sc->wx_media; if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) { return (EINVAL); } return (0);}static voidwx_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr){ u_int32_t dsr; struct wx_softc *sc = SOFTC_IFP(ifp); DPRINTF(sc, ("%s: ifmedia_sts: ", sc->wx_name)); if (sc->wx_mii) { mii_data_t *mii = WX_MII_FROM_SOFTC(sc); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; DPRINTF(sc, ("active=%#x status=%#x\n", ifmr->ifm_active, ifmr->ifm_status)); return; } DPRINTF(sc, ("\n")); ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; if (sc->linkup == 0) return; ifmr->ifm_status |= IFM_ACTIVE; dsr = READ_CSR(sc, WXREG_DSR); if (IS_LIVENGOOD(sc)) { if (dsr & WXDSR_1000BT) { if (IS_LIVENGOOD_CU(sc)) { ifmr->ifm_status |= IFM_1000_TX; } else { ifmr->ifm_status |= IFM_1000_SX; } } else if (dsr & WXDSR_100BT) { ifmr->ifm_status |= IFM_100_FX; /* ?? */ } else { ifmr->ifm_status |= IFM_10_T; /* ?? */ } } else { ifmr->ifm_status |= IFM_1000_SX; } if (dsr & WXDSR_FD) { ifmr->ifm_active |= IFM_FDX; }}#define RAISE_CLOCK(sc, dcr) \ WRITE_CSR(sc, WXREG_DCR, (dcr) | WXPHY_MDC), DELAY(2)#define LOWER_CLOCK(sc, dcr) \ WRITE_CSR(sc, WXREG_DCR, (dcr) & ~WXPHY_MDC), DELAY(2)static u_int32_twx_mii_shift_in(wx_softc_t *sc){ u_int32_t dcr, i; u_int32_t data = 0; dcr = READ_CSR(sc, WXREG_DCR); dcr &= ~(WXPHY_MDIO_DIR | WXPHY_MDIO); WRITE_CSR(sc, WXREG_DCR, dcr); RAISE_CLOCK(sc, dcr); LOWER_CLOCK(sc, dcr); for (i = 0; i < 16; i++) { data <<= 1; RAISE_CLOCK(sc, dcr); dcr = READ_CSR(sc, WXREG_DCR); if (dcr & WXPHY_MDIO) data |= 1; LOWER_CLOCK(sc, dcr); } RAISE_CLOCK(sc, dcr); LOWER_CLOCK(sc, dcr); return (data);}static voidwx_mii_shift_out(wx_softc_t *sc, u_int32_t data, u_int32_t count){ u_int32_t dcr, mask; dcr = READ_CSR(sc, WXREG_DCR); dcr |= WXPHY_MDIO_DIR | WXPHY_MDC_DIR; for (mask = (1 << (count - 1)); mask; mask >>= 1) { if (data & mask) dcr |= WXPHY_MDIO; else dcr &= ~WXPHY_MDIO; WRITE_CSR(sc, WXREG_DCR, dcr); DELAY(2); RAISE_CLOCK(sc, dcr); LOWER_CLOCK(sc, dcr); }}static intwx_miibus_readreg(void *arg, int phy, int reg){ wx_softc_t *sc = WX_SOFTC_FROM_MII_ARG(arg); unsigned int data = 0; if (!IS_LIVENGOOD_CU(sc)) { return 0; } wx_mii_shift_out(sc, WXPHYC_PREAMBLE, WXPHYC_PREAMBLE_LEN); wx_mii_shift_out(sc, reg | (phy << 5) | (WXPHYC_READ << 10) | (WXPHYC_SOF << 12), 14); data = wx_mii_shift_in(sc); return (data & WXMDIC_DATA_MASK);}static intwx_miibus_writereg(void *arg, int phy, int reg, int data){ wx_softc_t *sc = WX_SOFTC_FROM_MII_ARG(arg); if (!IS_LIVENGOOD_CU(sc)) { return 0; } wx_mii_shift_out(sc, WXPHYC_PREAMBLE, WXPHYC_PREAMBLE_LEN); wx_mii_shift_out(sc, (u_int32_t)data | (WXPHYC_TURNAROUND << 16) | (reg << 18) | (phy << 23) | (WXPHYC_WRITE << 28) | (WXPHYC_SOF << 30), 32); return (0);}static voidwx_miibus_statchg(void *arg){ wx_softc_t *sc = WX_SOFTC_FROM_MII_ARG(arg); mii_data_t *mii = WX_MII_FROM_SOFTC(sc); u_int32_t dcr, tctl; if (mii == NULL) return; dcr = sc->wx_dcr; tctl = READ_CSR(sc, WXREG_TCTL); DPRINTF(sc, ("%s: statchg dcr=%#x tctl=%#x", sc->wx_name, dcr, tctl)); dcr |= WXDCR_FRCSPD | WXDCR_FRCDPX | WXDCR_SLU; dcr &= ~(WXDCR_SPEED_MASK | WXDCR_ASDE /* | WXDCR_ILOS */); if (mii->mii_media_status & IFM_ACTIVE) { if (IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE) { DPRINTF(sc, (" link-down\n")); sc->linkup = 0; return; } sc->linkup = 1; } if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_TX) { DPRINTF(sc, (" 1000TX")); dcr |= WXDCR_1000BT; } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { DPRINTF(sc, (" 100TX")); dcr |= WXDCR_100BT; } else /* assume IFM_10_TX */ { DPRINTF(sc, (" 10TX")); dcr |= WXDCR_10BT; } if (mii->mii_media_active & IFM_FDX) { DPRINTF(sc, ("-FD")); tctl = WXTCTL_CT(WX_COLLISION_THRESHOLD) | WXTCTL_COLD(WX_FDX_COLLISION_DX) | WXTCTL_EN; dcr |= WXDCR_FD; } else { DPRINTF(sc, ("-HD")); tctl = WXTCTL_CT(WX_COLLISION_THRESHOLD) | WXTCTL_COLD(WX_HDX_COLLISION_DX) | WXTCTL_EN; dcr &= ~WXDCR_FD; } /* FLAG0==rx-flow-control FLAG1==tx-flow-control */ if (mii->mii_media_active & IFM_FLAG0) { dcr |= WXDCR_RFCE; } else { dcr &= ~WXDCR_RFCE; } if (mii->mii_media_active & IFM_FLAG1) { dcr |= WXDCR_TFCE; } else { dcr &= ~WXDCR_TFCE; } if (dcr & (WXDCR_RFCE|WXDCR_TFCE)) { WRITE_CSR(sc, WXREG_FCAL, FC_FRM_CONST_LO); WRITE_CSR(sc, WXREG_FCAH, FC_FRM_CONST_HI); WRITE_CSR(sc, WXREG_FCT, FC_TYP_CONST); } else { WRITE_CSR(sc, WXREG_FCAL, 0); WRITE_CSR(sc, WXREG_FCAH, 0); WRITE_CSR(sc, WXREG_FCT, 0); } DPRINTF(sc, (" dcr=%#x tctl=%#x\n", dcr, tctl)); WRITE_CSR(sc, WXREG_TCTL, tctl); sc->wx_dcr = dcr; WRITE_CSR(sc, WXREG_DCR, dcr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -