diff options
author | Nathan Binkert <nate@cvs.openbsd.org> | 2002-09-21 15:29:47 +0000 |
---|---|---|
committer | Nathan Binkert <nate@cvs.openbsd.org> | 2002-09-21 15:29:47 +0000 |
commit | 67390f52b421601097f154a2505e097bff37a52f (patch) | |
tree | 1a0fc6a71ff6db9abfa68cc1bc924cd117ae2e65 /sys/dev/pci/if_nge.c | |
parent | 2fb72a2dd548dc78a9e8dacc02cfd4f1652dae51 (diff) |
Add support for TBI mode in fiber based cards (heavily inspired by FreeBSD)
Clean up debugging printfs
Remove some old debugging code that shouldn't be there.
More changes from FreeBSD:
- ignore alignment problem on x86 platforms and don't copy.
- increase receive list to 128 to match transmit
- change a bit in the interrupt handling
Diffstat (limited to 'sys/dev/pci/if_nge.c')
-rw-r--r-- | sys/dev/pci/if_nge.c | 550 |
1 files changed, 393 insertions, 157 deletions
diff --git a/sys/dev/pci/if_nge.c b/sys/dev/pci/if_nge.c index 41f21ae0744..8007ba0c3c2 100644 --- a/sys/dev/pci/if_nge.c +++ b/sys/dev/pci/if_nge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_nge.c,v 1.21 2002/09/21 15:05:49 nate Exp $ */ +/* $OpenBSD: if_nge.c,v 1.22 2002/09/21 15:29:46 nate Exp $ */ /* * Copyright (c) 2001 Wind River Systems * Copyright (c) 1997, 1998, 1999, 2000, 2001 @@ -31,7 +31,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/nge/if_nge.c,v 1.19 2001/07/25 00:19:55 brooks Exp $ + * $FreeBSD: if_nge.c,v 1.35 2002/08/08 18:33:28 ambrisko Exp $ */ /* @@ -145,7 +145,6 @@ int nge_newbuf(struct nge_softc *, struct nge_desc *, struct mbuf *); int nge_encap(struct nge_softc *, struct mbuf *, u_int32_t *); void nge_rxeof(struct nge_softc *); -void nge_rxeoc(struct nge_softc *); void nge_txeof(struct nge_softc *); int nge_intr(void *); void nge_tick(void *); @@ -155,8 +154,10 @@ void nge_init(void *); void nge_stop(struct nge_softc *); void nge_watchdog(struct ifnet *); void nge_shutdown(void *); -int nge_ifmedia_upd(struct ifnet *); -void nge_ifmedia_sts(struct ifnet *, struct ifmediareq *); +int nge_ifmedia_mii_upd(struct ifnet *); +void nge_ifmedia_mii_sts(struct ifnet *, struct ifmediareq *); +int nge_ifmedia_tbi_upd(struct ifnet *); +void nge_ifmedia_tbi_sts(struct ifnet *, struct ifmediareq *); void nge_delay(struct nge_softc *); void nge_eeprom_idle(struct nge_softc *); @@ -538,6 +539,8 @@ nge_miibus_readreg(dev, phy, reg) struct nge_softc *sc = (struct nge_softc *)dev; struct nge_mii_frame frame; + DPRINTFN(9, ("%s: nge_miibus_readreg\n", sc->sc_dv.dv_xname)); + bzero((char *)&frame, sizeof(frame)); frame.mii_phyaddr = phy; @@ -556,6 +559,8 @@ nge_miibus_writereg(dev, phy, reg, data) struct nge_mii_frame frame; + DPRINTFN(9, ("%s: nge_miibus_writereg\n", sc->sc_dv.dv_xname)); + bzero((char *)&frame, sizeof(frame)); frame.mii_phyaddr = phy; @@ -570,36 +575,32 @@ nge_miibus_statchg(dev) { struct nge_softc *sc = (struct nge_softc *)dev; struct mii_data *mii = &sc->nge_mii; + u_int32_t txcfg, rxcfg; + + txcfg = CSR_READ_4(sc, NGE_TX_CFG); + rxcfg = CSR_READ_4(sc, NGE_RX_CFG); + + DPRINTFN(4, ("%s: nge_miibus_statchg txcfg=%#x, rxcfg=%#x\n", + sc->sc_dv.dv_xname, txcfg, rxcfg)); if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { - NGE_SETBIT(sc, NGE_TX_CFG, - (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); - NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); + txcfg |= (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR); + rxcfg |= (NGE_RXCFG_RX_FDX); } else { - NGE_CLRBIT(sc, NGE_TX_CFG, - (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); - NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); + txcfg &= ~(NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR); + rxcfg &= ~(NGE_RXCFG_RX_FDX); } - switch (IFM_SUBTYPE(sc->nge_mii.mii_media_active)) { - case IFM_1000_TX: /* Gigabit using GMII interface */ - NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); - NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_TBI_EN); - break; + txcfg |= NGE_TXCFG_AUTOPAD; + + CSR_WRITE_4(sc, NGE_TX_CFG, txcfg); + CSR_WRITE_4(sc, NGE_RX_CFG, rxcfg); - case IFM_1000_SX: /* Gigabit using TBI interface */ - case IFM_1000_CX: - case IFM_1000_LX: + /* If we have a 1000Mbps link, set the mode_1000 bit. */ + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_TX) + NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); + else NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); - NGE_SETBIT(sc, NGE_CFG, NGE_CFG_TBI_EN); - break; - - default: /* Default to MII interface */ - NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000| - NGE_CFG_TBI_EN); - break; - } - } u_int32_t @@ -658,7 +659,7 @@ nge_setmulti(sc) */ NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH); NGE_CLRBIT(sc, NGE_RXFILT_CTL, - NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH); + NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH); filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL); @@ -734,8 +735,6 @@ nge_probe(parent, match, aux) return (0); } -struct nge_softc *my_nge_softc; - /* * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. @@ -762,12 +761,11 @@ nge_attach(parent, self, aux) caddr_t kva; s = splimp(); - my_nge_softc = sc; /* * Handle power management nonsense. */ - DPRINTFN(5, ("Preparing for conf read\n")); + DPRINTFN(5, ("%s: preparing for conf read\n", sc->sc_dv.dv_xname)); command = pci_conf_read(pc, pa->pa_tag, NGE_PCI_CAPID) & 0x000000FF; if (command == 0x01) { command = pci_conf_read(pc, pa->pa_tag, NGE_PCI_PWRMGMTCTRL); @@ -797,7 +795,7 @@ nge_attach(parent, self, aux) /* * Map control/status registers. */ - DPRINTFN(5, ("Map control/status regs\n")); + DPRINTFN(5, ("%s: map control/status regs\n", sc->sc_dv.dv_xname)); command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); command |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE; @@ -814,12 +812,12 @@ nge_attach(parent, self, aux) /* * Map control/status registers. */ - DPRINTFN(5, ("pci_io_find\n")); + DPRINTFN(5, ("%s: pci_io_find\n", sc->sc_dv.dv_xname)); if (pci_io_find(pc, pa->pa_tag, NGE_PCI_LOIO, &iobase, &iosize)) { printf(": can't find i/o space\n"); goto fail; } - DPRINTFN(5, ("bus_space_map\n")); + DPRINTFN(5, ("%s: bus_space_map\n", sc->sc_dv.dv_xname)); if (bus_space_map(pa->pa_iot, iobase, iosize, 0, &sc->nge_bhandle)) { printf(": can't map i/o space\n"); goto fail; @@ -832,13 +830,13 @@ nge_attach(parent, self, aux) error = ENXIO; goto fail; } - DPRINTFN(5, ("pci_mem_find\n")); + DPRINTFN(5, ("%s: pci_mem_find\n", sc->sc_dv.dv_xname)); if (pci_mem_find(pc, pa->pa_tag, NGE_PCI_LOMEM, &iobase, &iosize, NULL)) { printf(": can't find mem space\n"); goto fail; } - DPRINTFN(5, ("bus_space_map\n")); + DPRINTFN(5, ("%s: bus_space_map\n", sc->sc_dv.dv_xname)); if (bus_space_map(pa->pa_memt, iobase, iosize, 0, &sc->nge_bhandle)) { printf(": can't map mem space\n"); goto fail; @@ -847,15 +845,18 @@ nge_attach(parent, self, aux) sc->nge_btag = pa->pa_memt; #endif - DPRINTFN(5, ("pci_intr_map\n")); + /* Disable all interrupts */ + CSR_WRITE_4(sc, NGE_IER, 0); + + DPRINTFN(5, ("%s: pci_intr_map\n", sc->sc_dv.dv_xname)); if (pci_intr_map(pa, &ih)) { printf(": couldn't map interrupt\n"); goto fail; } - DPRINTFN(5, ("pci_intr_string\n")); + DPRINTFN(5, ("%s: pci_intr_string\n", sc->sc_dv.dv_xname)); intrstr = pci_intr_string(pc, ih); - DPRINTFN(5, ("pci_intr_establish\n")); + DPRINTFN(5, ("%s: pci_intr_establish\n", sc->sc_dv.dv_xname)); sc->nge_intrhand = pci_intr_establish(pc, ih, IPL_NET, nge_intr, sc, sc->sc_dv.dv_xname); if (sc->nge_intrhand == NULL) { @@ -868,13 +869,13 @@ nge_attach(parent, self, aux) printf(": %s", intrstr); /* Reset the adapter. */ - DPRINTFN(5, ("nge_reset\n")); + DPRINTFN(5, ("%s: nge_reset\n", sc->sc_dv.dv_xname)); nge_reset(sc); /* * Get station address from the EEPROM. */ - DPRINTFN(5, ("nge_read_eeprom\n")); + DPRINTFN(5, ("%s: nge_read_eeprom\n", sc->sc_dv.dv_xname)); nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0); nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0); nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0); @@ -887,13 +888,13 @@ nge_attach(parent, self, aux) bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); sc->sc_dmatag = pa->pa_dmat; - DPRINTFN(5, ("bus_dmamem_alloc\n")); + DPRINTFN(5, ("%s: bus_dmamem_alloc\n", sc->sc_dv.dv_xname)); if (bus_dmamem_alloc(sc->sc_dmatag, sizeof(struct nge_list_data), PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) { printf("%s: can't alloc rx buffers\n", sc->sc_dv.dv_xname); goto fail; } - DPRINTFN(5, ("bus_dmamem_map\n")); + DPRINTFN(5, ("%s: bus_dmamem_map\n", sc->sc_dv.dv_xname)); if (bus_dmamem_map(sc->sc_dmatag, &seg, rseg, sizeof(struct nge_list_data), &kva, BUS_DMA_NOWAIT)) { @@ -902,7 +903,7 @@ nge_attach(parent, self, aux) bus_dmamem_free(sc->sc_dmatag, &seg, rseg); goto fail; } - DPRINTFN(5, ("bus_dmamem_create\n")); + DPRINTFN(5, ("%s: bus_dmamem_create\n", sc->sc_dv.dv_xname)); if (bus_dmamap_create(sc->sc_dmatag, sizeof(struct nge_list_data), 1, sizeof(struct nge_list_data), 0, BUS_DMA_NOWAIT, &dmamap)) { @@ -912,7 +913,7 @@ nge_attach(parent, self, aux) bus_dmamem_free(sc->sc_dmatag, &seg, rseg); goto fail; } - DPRINTFN(5, ("bus_dmamem_load\n")); + DPRINTFN(5, ("%s: bus_dmamem_load\n", sc->sc_dv.dv_xname)); if (bus_dmamap_load(sc->sc_dmatag, dmamap, kva, sizeof(struct nge_list_data), NULL, BUS_DMA_NOWAIT)) { @@ -923,12 +924,12 @@ nge_attach(parent, self, aux) goto fail; } - DPRINTFN(5, ("bzero\n")); + DPRINTFN(5, ("%s: bzero\n", sc->sc_dv.dv_xname)); sc->nge_ldata = (struct nge_list_data *)kva; bzero(sc->nge_ldata, sizeof(struct nge_list_data)); /* Try to allocate memory for jumbo buffers. */ - DPRINTFN(5, ("nge_alloc_jumbo_mem\n")); + DPRINTFN(5, ("%s: nge_alloc_jumbo_mem\n", sc->sc_dv.dv_xname)); if (nge_alloc_jumbo_mem(sc)) { printf("%s: jumbo buffer allocation failed\n", sc->sc_dv.dv_xname); @@ -951,39 +952,67 @@ nge_attach(parent, self, aux) #if NVLAN > 0 ifp->if_capabilities |= IFCAP_VLAN_MTU; #endif - DPRINTFN(5, ("bcopy\n")); + DPRINTFN(5, ("%s: bcopy\n", sc->sc_dv.dv_xname)); bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ); /* * Do MII setup. */ - DPRINTFN(5, ("mii setup\n")); - sc->nge_mii.mii_ifp = ifp; - sc->nge_mii.mii_readreg = nge_miibus_readreg; - sc->nge_mii.mii_writereg = nge_miibus_writereg; - sc->nge_mii.mii_statchg = nge_miibus_statchg; - ifmedia_init(&sc->nge_mii.mii_media, 0, nge_ifmedia_upd, - nge_ifmedia_sts); - mii_attach(&sc->sc_dv, &sc->nge_mii, 0xffffffff, MII_PHY_ANY, - MII_OFFSET_ANY, 0); - - if (LIST_FIRST(&sc->nge_mii.mii_phys) == NULL) { - printf("%s: no PHY found!\n", sc->sc_dv.dv_xname); - ifmedia_add(&sc->nge_mii.mii_media, IFM_ETHER|IFM_MANUAL, - 0, NULL); - ifmedia_set(&sc->nge_mii.mii_media, IFM_ETHER|IFM_MANUAL); + DPRINTFN(5, ("%s: mii setup\n", sc->sc_dv.dv_xname)); + if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) { + DPRINTFN(5, ("%s: TBI mode\n", sc->sc_dv.dv_xname)); + sc->nge_tbi = 1; + + ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_tbi_upd, + nge_ifmedia_tbi_sts); + + ifmedia_add(&sc->nge_ifmedia, IFM_ETHER|IFM_NONE, 0, NULL), + ifmedia_add(&sc->nge_ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL); + ifmedia_add(&sc->nge_ifmedia, IFM_ETHER|IFM_1000_SX|IFM_FDX, + 0, NULL); + ifmedia_add(&sc->nge_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); + + ifmedia_set(&sc->nge_ifmedia, IFM_ETHER|IFM_AUTO); + + CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) + | NGE_GPIO_GP4_OUT + | NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB + | NGE_GPIO_GP3_OUTENB | NGE_GPIO_GP4_OUTENB + | NGE_GPIO_GP5_OUTENB); + + NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); + } else { + sc->nge_mii.mii_ifp = ifp; + sc->nge_mii.mii_readreg = nge_miibus_readreg; + sc->nge_mii.mii_writereg = nge_miibus_writereg; + sc->nge_mii.mii_statchg = nge_miibus_statchg; + + ifmedia_init(&sc->nge_mii.mii_media, 0, nge_ifmedia_mii_upd, + nge_ifmedia_mii_sts); + mii_attach(&sc->sc_dv, &sc->nge_mii, 0xffffffff, MII_PHY_ANY, + MII_OFFSET_ANY, 0); + + if (LIST_FIRST(&sc->nge_mii.mii_phys) == NULL) { + + printf("%s: no PHY found!\n", sc->sc_dv.dv_xname); + ifmedia_add(&sc->nge_mii.mii_media, + IFM_ETHER|IFM_MANUAL, 0, NULL); + ifmedia_set(&sc->nge_mii.mii_media, + IFM_ETHER|IFM_MANUAL); + } + else + ifmedia_set(&sc->nge_mii.mii_media, + IFM_ETHER|IFM_AUTO); } - else - ifmedia_set(&sc->nge_mii.mii_media, IFM_ETHER|IFM_AUTO); /* * Call MI attach routine. */ - DPRINTFN(5, ("if_attach\n")); + DPRINTFN(5, ("%s: if_attach\n", sc->sc_dv.dv_xname)); if_attach(ifp); - DPRINTFN(5, ("ether_ifattach\n")); + DPRINTFN(5, ("%s: ether_ifattach\n", sc->sc_dv.dv_xname)); ether_ifattach(ifp); - DPRINTFN(5, ("timeout_set\n")); + DPRINTFN(5, ("%s: timeout_set\n", sc->sc_dv.dv_xname)); timeout_set(&sc->nge_timeout, nge_tick, sc); timeout_add(&sc->nge_timeout, hz); @@ -1113,7 +1142,8 @@ nge_newbuf(sc, c, m) c->nge_mbuf = m_new; c->nge_ptr = vtophys(mtod(m_new, caddr_t)); - DPRINTFN(7,("c->nge_ptr = 0x%08X\n", c->nge_ptr)); + DPRINTFN(7,("%s: c->nge_ptr=%#x\n", sc->sc_dv.dv_xname, + c->nge_ptr)); c->nge_ctl = m_new->m_len; c->nge_extsts = 0; @@ -1158,8 +1188,9 @@ nge_alloc_jumbo_mem(sc) return (ENOBUFS); } sc->nge_cdata.nge_jumbo_buf = (caddr_t)kva; - DPRINTFN(1,("nge_jumbo_buf = 0x%08X\n", sc->nge_cdata.nge_jumbo_buf)); - DPRINTFN(1,("NGE_MCLBYTES = 0x%08X\n", NGE_MCLBYTES)); + DPRINTFN(1,("%s: nge_jumbo_buf=%#x, NGE_MCLBYTES=%#x\n", + sc->sc_dv.dv_xname , sc->nge_cdata.nge_jumbo_buf, + NGE_MCLBYTES)); LIST_INIT(&sc->nge_jfree_listhead); LIST_INIT(&sc->nge_jinuse_listhead); @@ -1304,24 +1335,40 @@ nge_rxeof(sc) continue; } - /* * Ok. NatSemi really screwed up here. This is the * only gigE chip I know of with alignment constraints * on receive buffers. RX buffers must be 64-bit aligned. */ - m0 = m_devget(mtod(m, char *) - ETHER_ALIGN, - total_len + ETHER_ALIGN, 0, ifp, NULL); - nge_newbuf(sc, cur_rx, m); - if (m0 == NULL) { - printf("%s: no receive buffers " - "available -- packet dropped!\n", - sc->sc_dv.dv_xname); - ifp->if_ierrors++; - continue; +#ifdef __i386__ + /* + * By popular demand, ignore the alignment problems + * on the Intel x86 platform. The performance hit + * incurred due to unaligned accesses is much smaller + * than the hit produced by forcing buffer copies all + * the time, especially with jumbo frames. We still + * need to fix up the alignment everywhere else though. + */ + if (nge_newbuf(sc, cur_rx, NULL) == ENOBUFS) { +#endif + m0 = m_devget(mtod(m, char *), total_len, + ETHER_ALIGN, ifp, NULL); + nge_newbuf(sc, cur_rx, m); + if (m0 == NULL) { + printf("%s: no receive buffers " + "available -- packet dropped!\n", + sc->sc_dv.dv_xname); + ifp->if_ierrors++; + continue; + } + m_adj(m0, ETHER_ALIGN); + m = m0; +#ifdef __i386__ + } else { + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = total_len; } - m_adj(m0, ETHER_ALIGN); - m = m0; +#endif ifp->if_ipackets++; @@ -1371,18 +1418,6 @@ nge_rxeof(sc) sc->nge_cdata.nge_rx_prod = i; } -void -nge_rxeoc(sc) - struct nge_softc *sc; -{ - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - nge_rxeof(sc); - ifp->if_flags &= ~IFF_RUNNING; - nge_init(sc); -} - /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. @@ -1457,20 +1492,70 @@ nge_tick(xsc) s = splimp(); - mii_tick(mii); + DPRINTFN(10, ("%s: nge_tick: link=%d\n", sc->sc_dv.dv_xname, + sc->nge_link)); + + timeout_add(&sc->nge_timeout, hz); + if (sc->nge_link) { + splx(s); + return; + } + + if (sc->nge_tbi) { + if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) + == IFM_AUTO) { + u_int32_t bmsr, anlpar, txcfg, rxcfg; + + bmsr = CSR_READ_4(sc, NGE_TBI_BMSR); + DPRINTFN(2, ("%s: nge_tick: bmsr=%#x\n", + sc->sc_dv.dv_xname, bmsr)); - if (!sc->nge_link) { + if (!(bmsr & NGE_TBIBMSR_ANEG_DONE)) { + CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); + + splx(s); + return; + } + + anlpar = CSR_READ_4(sc, NGE_TBI_ANLPAR); + txcfg = CSR_READ_4(sc, NGE_TX_CFG); + rxcfg = CSR_READ_4(sc, NGE_RX_CFG); + + DPRINTFN(2, ("%s: nge_tick: anlpar=%#x, txcfg=%#x, " + "rxcfg=%#x\n", sc->sc_dv.dv_xname, anlpar, + txcfg, rxcfg)); + + if (anlpar == 0 || anlpar & NGE_TBIANAR_FDX) { + txcfg |= (NGE_TXCFG_IGN_HBEAT| + NGE_TXCFG_IGN_CARR); + rxcfg |= NGE_RXCFG_RX_FDX; + } else { + txcfg &= ~(NGE_TXCFG_IGN_HBEAT| + NGE_TXCFG_IGN_CARR); + rxcfg &= ~(NGE_RXCFG_RX_FDX); + } + txcfg |= NGE_TXCFG_AUTOPAD; + CSR_WRITE_4(sc, NGE_TX_CFG, txcfg); + CSR_WRITE_4(sc, NGE_RX_CFG, rxcfg); + } + + DPRINTF(("%s: gigabit link up\n", sc->sc_dv.dv_xname)); + sc->nge_link++; + if (!IFQ_IS_EMPTY(&ifp->if_snd)) + nge_start(ifp); + } else { + mii_tick(mii); mii_pollstat(mii); if (mii->mii_media_status & IFM_ACTIVE && IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { sc->nge_link++; if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_TX) - DPRINTFN("%s: gigabit link up\n", - sc->sc_dv.dv_xname); + DPRINTF(("%s: gigabit link up\n", + sc->sc_dv.dv_xname)); if (!IFQ_IS_EMPTY(&ifp->if_snd)) nge_start(ifp); - } else - timeout_add(&sc->nge_timeout, hz); + } + } splx(s); @@ -1497,6 +1582,11 @@ nge_intr(arg) /* Disable interrupts. */ CSR_WRITE_4(sc, NGE_IER, 0); + /* Data LED on for TBI mode */ + if(sc->nge_tbi) + CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) + | NGE_GPIO_GP3_OUT); + for (;;) { /* Reading the ISR register clears all interrupts. */ status = CSR_READ_4(sc, NGE_ISR); @@ -1513,13 +1603,15 @@ nge_intr(arg) nge_txeof(sc); if ((status & NGE_ISR_RX_DESC_OK) || + (status & NGE_ISR_RX_ERR) || + (status & NGE_ISR_RX_OFLOW) || + (status & NGE_ISR_RX_FIFO_OFLOW) || + (status & NGE_ISR_RX_IDLE) || (status & NGE_ISR_RX_OK)) nge_rxeof(sc); - if ((status & NGE_ISR_RX_ERR) || - (status & NGE_ISR_RX_OFLOW)) { - nge_rxeoc(sc); - } + if ((status & NGE_ISR_RX_IDLE)) + NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); if (status & NGE_ISR_SYSERR) { nge_reset(sc); @@ -1527,10 +1619,17 @@ nge_intr(arg) nge_init(sc); } - if (status & NGE_ISR_PHY_INTR) { +#if 0 + /* + * XXX: nge_tick() is not ready to be called this way + * it screws up the aneg timeout because mii_tick() is + * only to be called once per second. + */ + if (status & NGE_IMR_PHY_INTR) { sc->nge_link = 0; nge_tick(sc); } +#endif } /* Re-enable interrupts. */ @@ -1539,6 +1638,11 @@ nge_intr(arg) if (!IFQ_IS_EMPTY(&ifp->if_snd)) nge_start(ifp); + /* Data LED off for TBI mode */ + if(sc->nge_tbi) + CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) + & ~NGE_GPIO_GP3_OUT); + return claimed; } @@ -1579,7 +1683,8 @@ nge_encap(sc, m_head, txidx) f = &sc->nge_ldata->nge_tx_list[frag]; f->nge_ctl = NGE_CMDSTS_MORE | m->m_len; f->nge_ptr = vtophys(mtod(m, vm_offset_t)); - DPRINTFN(7,("f->nge_ptr = 0x%08X\n", f->nge_ptr)); + DPRINTFN(7,("%s: f->nge_ptr=%#x\n", + sc->sc_dv.dv_xname, f->nge_ptr)); if (cnt != 0) f->nge_ctl |= NGE_CMDSTS_OWN; cur = frag; @@ -1599,13 +1704,13 @@ nge_encap(sc, m_head, txidx) if (m_head->m_pkthdr.csum) { if (m_head->m_pkthdr.csum & M_IPV4_CSUM_OUT) sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= - NGE_TXEXTSTS_IPCSUM; + NGE_TXEXTSTS_IPCSUM; if (m_head->m_pkthdr.csum & M_TCPV4_CSUM_OUT) sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= - NGE_TXEXTSTS_TCPCSUM; + NGE_TXEXTSTS_TCPCSUM; if (m_head->m_pkthdr.csum & M_UDPV4_CSUM_OUT) sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= - NGE_TXEXTSTS_UDPCSUM; + NGE_TXEXTSTS_UDPCSUM; } #if NVLAN > 0 @@ -1686,16 +1791,15 @@ nge_start(ifp) ifp->if_timer = 5; } -int nge_loop = 0; - void nge_init(xsc) void *xsc; { struct nge_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; - struct mii_data *mii = &sc->nge_mii; - int s; + struct mii_data *mii; + u_int32_t txcfg, rxcfg; + int s, media; if (ifp->if_flags & IFF_RUNNING) return; @@ -1706,10 +1810,8 @@ nge_init(xsc) * Cancel pending I/O and free all RX/TX buffers. */ nge_stop(sc); - nge_reset(sc); - /* Turn the receive filter off */ - NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE); + mii = sc->nge_tbi ? NULL: &sc->nge_mii; /* Set MAC address */ CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0); @@ -1798,8 +1900,7 @@ nge_init(xsc) #endif /* Set TX configuration */ - CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG | - (nge_loop ? NGE_TXCFG_LOOPBK : 0)); + CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG); /* * Enable TX IPv4 checksumming on a per-packet basis. @@ -1817,16 +1918,32 @@ nge_init(xsc) #endif /* Set full/half duplex mode. */ - if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { - NGE_SETBIT(sc, NGE_TX_CFG, - (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); - NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); + if (sc->nge_tbi) + media = sc->nge_ifmedia.ifm_cur->ifm_media; + else + media = mii->mii_media_active; + + txcfg = CSR_READ_4(sc, NGE_TX_CFG); + rxcfg = CSR_READ_4(sc, NGE_RX_CFG); + + DPRINTFN(4, ("%s: nge_init txcfg=%#x, rxcfg=%#x\n", + sc->sc_dv.dv_xname, txcfg, rxcfg)); + + if ((media & IFM_GMASK) == IFM_FDX) { + txcfg |= (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR); + rxcfg |= (NGE_RXCFG_RX_FDX); } else { - NGE_CLRBIT(sc, NGE_TX_CFG, - (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); - NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); + txcfg &= ~(NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR); + rxcfg &= ~(NGE_RXCFG_RX_FDX); } + txcfg |= NGE_TXCFG_AUTOPAD; + + CSR_WRITE_4(sc, NGE_TX_CFG, txcfg); + CSR_WRITE_4(sc, NGE_RX_CFG, rxcfg); + + nge_tick(sc); + /* * Enable the delivery of PHY interrupts based on * link/speed/duplex status changes and enable return @@ -1836,7 +1953,16 @@ nge_init(xsc) NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD|NGE_CFG_PHYINTR_LNK| NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB); - DPRINTFN("NGE_CFG: 0x%08X\n", CSR_READ_4(sc, NGE_CFG)); + DPRINTFN(1, ("%s: nge_init: config=%#x\n", sc->sc_dv.dv_xname, + CSR_READ_4(sc, NGE_CFG))); + + /* + * Configure interrupt holdoff (moderation). We can + * have the chip delay interrupt delivery for a certain + * period. Units are in 100us, and the max setting + * is 25500us (0xFF x 100us). Default is a 100us holdoff. + */ + CSR_WRITE_4(sc, NGE_IHR, 0x01); /* * Enable interrupts. @@ -1848,7 +1974,10 @@ nge_init(xsc) NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); - nge_ifmedia_upd(ifp); + if (sc->nge_tbi) + nge_ifmedia_tbi_upd(ifp); + else + nge_ifmedia_mii_upd(ifp); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; @@ -1857,16 +1986,19 @@ nge_init(xsc) } /* - * Set media options. + * Set mii media options. */ int -nge_ifmedia_upd(ifp) +nge_ifmedia_mii_upd(ifp) struct ifnet *ifp; { struct nge_softc *sc = ifp->if_softc; - struct mii_data *mii = &sc->nge_mii; + struct mii_data *mii = &sc->nge_mii; + + DPRINTFN(2, ("%s: nge_ifmedia_mii_upd\n", sc->sc_dv.dv_xname)); sc->nge_link = 0; + if (mii->mii_instance) { struct mii_softc *miisc; for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; @@ -1879,21 +2011,127 @@ nge_ifmedia_upd(ifp) } /* - * Report current media status. + * Report current mii media status. */ void -nge_ifmedia_sts(ifp, ifmr) +nge_ifmedia_mii_sts(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr; { struct nge_softc *sc = ifp->if_softc; - struct mii_data *mii = &sc->nge_mii; + struct mii_data *mii = &sc->nge_mii; + + DPRINTFN(2, ("%s: nge_ifmedia_mii_sts\n", sc->sc_dv.dv_xname)); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; } +/* + * Set mii media options. + */ +int +nge_ifmedia_tbi_upd(ifp) + struct ifnet *ifp; +{ + struct nge_softc *sc = ifp->if_softc; + + DPRINTFN(2, ("%s: nge_ifmedia_tbi_upd\n", sc->sc_dv.dv_xname)); + + sc->nge_link = 0; + + if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) + == IFM_AUTO) { + u_int32_t anar, bmcr; + anar = CSR_READ_4(sc, NGE_TBI_ANAR); + anar |= (NGE_TBIANAR_HDX | NGE_TBIANAR_FDX); + CSR_WRITE_4(sc, NGE_TBI_ANAR, anar); + + bmcr = CSR_READ_4(sc, NGE_TBI_BMCR); + bmcr |= (NGE_TBIBMCR_ENABLE_ANEG|NGE_TBIBMCR_RESTART_ANEG); + CSR_WRITE_4(sc, NGE_TBI_BMCR, bmcr); + + bmcr &= ~(NGE_TBIBMCR_RESTART_ANEG); + CSR_WRITE_4(sc, NGE_TBI_BMCR, bmcr); + } else { + u_int32_t txcfg, rxcfg; + txcfg = CSR_READ_4(sc, NGE_TX_CFG); + rxcfg = CSR_READ_4(sc, NGE_RX_CFG); + + if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) + == IFM_FDX) { + txcfg |= NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR; + rxcfg |= NGE_RXCFG_RX_FDX; + } else { + txcfg &= ~(NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR); + rxcfg &= ~(NGE_RXCFG_RX_FDX); + } + + txcfg |= NGE_TXCFG_AUTOPAD; + CSR_WRITE_4(sc, NGE_TX_CFG, txcfg); + CSR_WRITE_4(sc, NGE_RX_CFG, rxcfg); + } + + NGE_CLRBIT(sc, NGE_GPIO, NGE_GPIO_GP3_OUT); + + return(0); +} + +/* + * Report current tbi media status. + */ +void +nge_ifmedia_tbi_sts(ifp, ifmr) + struct ifnet *ifp; + struct ifmediareq *ifmr; +{ + struct nge_softc *sc = ifp->if_softc; + u_int32_t bmcr; + + bmcr = CSR_READ_4(sc, NGE_TBI_BMCR); + + if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) == IFM_AUTO) { + u_int32_t bmsr = CSR_READ_4(sc, NGE_TBI_BMSR); + DPRINTFN(2, ("%s: nge_ifmedia_tbi_sts bmsr=%#x, bmcr=%#x\n", + sc->sc_dv.dv_xname, bmsr, bmcr)); + + if (!(bmsr & NGE_TBIBMSR_ANEG_DONE)) { + ifmr->ifm_active = IFM_ETHER|IFM_NONE; + ifmr->ifm_status = IFM_AVALID; + return; + } + } else { + DPRINTFN(2, ("%s: nge_ifmedia_tbi_sts bmcr=%#x\n", + sc->sc_dv.dv_xname, bmcr)); + } + + ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE; + ifmr->ifm_active = IFM_ETHER|IFM_1000_SX; + + if (bmcr & NGE_TBIBMCR_LOOPBACK) + ifmr->ifm_active |= IFM_LOOP; + + if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) == IFM_AUTO) { + u_int32_t anlpar = CSR_READ_4(sc, NGE_TBI_ANLPAR); + DPRINTFN(2, ("%s: nge_ifmedia_tbi_sts anlpar=%#x\n", + sc->sc_dv.dv_xname, anlpar)); + + ifmr->ifm_active |= IFM_AUTO; + if (anlpar & NGE_TBIANLPAR_FDX) { + ifmr->ifm_active |= IFM_FDX; + } else if (anlpar & NGE_TBIANLPAR_HDX) { + ifmr->ifm_active |= IFM_HDX; + } else + ifmr->ifm_active |= IFM_FDX; + + } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) == IFM_FDX) + ifmr->ifm_active |= IFM_FDX; + else + ifmr->ifm_active |= IFM_HDX; + +} + int nge_ioctl(ifp, command, data) struct ifnet *ifp; @@ -1920,9 +2158,9 @@ nge_ioctl(ifp, command, data) else { ifp->if_mtu = ifr->ifr_mtu; /* - * If requested MTU is larger than the - * size of the TX buffer, turn off TX - * checksumming. + * Workaround: if the MTU is larger than + * 8152 (TX FIFO size minus 64 minus 18), turn off + * TX checksum offloading. */ if (ifr->ifr_mtu >= 8152) ifp->if_capabilities &= ~(IFCAP_CSUM_IPv4 | @@ -1987,8 +2225,14 @@ nge_ioctl(ifp, command, data) break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: - mii = &sc->nge_mii; - error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); + if (sc->nge_tbi) { + error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia, + command); + } else { + mii = &sc->nge_mii; + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, + command); + } break; default: error = EINVAL; @@ -2030,12 +2274,15 @@ nge_stop(sc) { int i; struct ifnet *ifp; - struct ifmedia_entry *ifm; - struct mii_data *mii = &sc->nge_mii; - int mtmp, itmp; + struct mii_data *mii; ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; + if (sc->nge_tbi) { + mii = NULL; + } else { + mii = &sc->nge_mii; + } timeout_del(&sc->nge_timeout); CSR_WRITE_4(sc, NGE_IER, 0); @@ -2045,19 +2292,8 @@ nge_stop(sc) CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0); CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0); - /* - * Isolate/power down the PHY, but leave the media selection - * unchanged so that things will be put back to normal when - * we bring the interface back up. - */ - itmp = ifp->if_flags; - ifp->if_flags |= IFF_UP; - ifm = mii->mii_media.ifm_cur; - mtmp = ifm->ifm_media; - ifm->ifm_media = IFM_ETHER|IFM_NONE; - mii_mediachg(mii); - ifm->ifm_media = mtmp; - ifp->if_flags = itmp; + if (!sc->nge_tbi) + mii_down(mii); sc->nge_link = 0; |