diff options
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/mii/rgephy.c | 26 | ||||
| -rw-r--r-- | sys/dev/re/if_re.c | 389 |
2 files changed, 270 insertions, 145 deletions
diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c index e8ccff4a74bcb..24196ff2b9696 100644 --- a/sys/dev/mii/rgephy.c +++ b/sys/dev/mii/rgephy.c @@ -139,7 +139,6 @@ rgephy_attach(device_t dev) #endif rgephy_mii_model = MII_MODEL(ma->mii_id2); - rgephy_reset(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; sc->mii_capabilities &= ~BMSR_ANEG; @@ -158,6 +157,7 @@ rgephy_attach(device_t dev) #undef ADD #undef PRINT + rgephy_reset(sc); MIIBUS_MEDIAINIT(sc->mii_dev); return(0); } @@ -347,12 +347,14 @@ rgephy_status(struct mii_softc *sc) } bmsr = PHY_READ(sc, RL_GMEDIASTAT); - if (bmsr & RL_GMEDIASTAT_10MBPS) - mii->mii_media_active |= IFM_10_T; - if (bmsr & RL_GMEDIASTAT_100MBPS) - mii->mii_media_active |= IFM_100_TX; if (bmsr & RL_GMEDIASTAT_1000MBPS) mii->mii_media_active |= IFM_1000_T; + else if (bmsr & RL_GMEDIASTAT_100MBPS) + mii->mii_media_active |= IFM_100_TX; + else if (bmsr & RL_GMEDIASTAT_10MBPS) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_NONE; if (bmsr & RL_GMEDIASTAT_FDX) mii->mii_media_active |= IFM_FDX; @@ -369,7 +371,8 @@ rgephy_mii_phy_auto(struct mii_softc *mii) PHY_WRITE(mii, RGEPHY_MII_ANAR, BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA); DELAY(1000); - PHY_WRITE(mii, RGEPHY_MII_1000CTL, RGEPHY_1000CTL_AFD); + PHY_WRITE(mii, RGEPHY_MII_1000CTL, + RGEPHY_1000CTL_AHD|RGEPHY_1000CTL_AFD); DELAY(1000); PHY_WRITE(mii, RGEPHY_MII_BMCR, RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); @@ -407,13 +410,20 @@ rgephy_loop(struct mii_softc *sc) /* * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of * existing revisions of the 8169S/8110S chips need to be tuned in - * order to reliably negotiate a 1000Mbps link. Later revs of the - * chips may not require this software tuning. + * order to reliably negotiate a 1000Mbps link. This is only needed + * for rev 0 and rev 1 of the PHY. Later versions work without + * any fixups. */ static void rgephy_load_dspcode(struct mii_softc *sc) { int val; + uint16_t id2; + + id2 = PHY_READ(sc, MII_PHYIDR2); + + if (MII_REV(id2) > 1) + return; PHY_WRITE(sc, 31, 0x0001); PHY_WRITE(sc, 21, 0x1000); diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index 339d70b246d41..ab8110567c0ba 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -34,7 +34,7 @@ __FBSDID("$FreeBSD$"); /* - * RealTek 8139C+/8169/8169S/8110S PCI NIC driver + * RealTek 8139C+/8169/8169S/8110S/8168/8111/8101E PCI NIC driver * * Written by Bill Paul <wpaul@windriver.com> * Senior Networking Software Engineer @@ -44,8 +44,8 @@ __FBSDID("$FreeBSD$"); /* * This driver is designed to support RealTek's next generation of * 10/100 and 10/100/1000 PCI ethernet controllers. There are currently - * four devices in this family: the RTL8139C+, the RTL8169, the RTL8169S - * and the RTL8110S. + * seven devices in this family: the RTL8139C+, the RTL8169, the RTL8169S, + * RTL8110S, the RTL8168, the RTL8111 and the RTL8101E. * * The 8139C+ is a 10/100 ethernet chip. It is backwards compatible * with the older 8139 family, however it also supports a special @@ -121,6 +121,9 @@ __FBSDID("$FreeBSD$"); #include <sys/module.h> #include <sys/kernel.h> #include <sys/socket.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/taskqueue.h> #include <net/if.h> #include <net/if_arp.h> @@ -167,14 +170,18 @@ static struct rl_type re_devs[] = { "D-Link DGE-528(T) Gigabit Ethernet Adapter" }, { RT_VENDORID, RT_DEVICEID_8139, RL_HWREV_8139CPLUS, "RealTek 8139C+ 10/100BaseTX" }, + { RT_VENDORID, RT_DEVICEID_8101E, RL_HWREV_8101E, + "RealTek 8101E PCIe 10/100baseTX" }, { RT_VENDORID, RT_DEVICEID_8168, RL_HWREV_8168, - "Realtek 8168B/8111B Gigabit Ethernet" }, + "RealTek 8168B/8111B PCIe Gigabit Ethernet" }, { RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8169, "RealTek 8169 Gigabit Ethernet" }, { RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8169S, "RealTek 8169S Single-chip Gigabit Ethernet" }, - { RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8169SB, - "RealTek 8169SB Single-chip Gigabit Ethernet" }, + { RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8169_8110SB, + "RealTek 8169SB/8110SB Single-chip Gigabit Ethernet" }, + { RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8169_8110SC, + "RealTek 8169SC/8110SC Single-chip Gigabit Ethernet" }, { RT_VENDORID, RT_DEVICEID_8169, RL_HWREV_8110S, "RealTek 8110S Single-chip Gigabit Ethernet" }, { COREGA_VENDORID, COREGA_DEVICEID_CGLAPCIGT, RL_HWREV_8169S, @@ -193,13 +200,16 @@ static struct rl_hwrev re_hwrevs[] = { { RL_HWREV_8139C, RL_8139, "C" }, { RL_HWREV_8139D, RL_8139, "8139D/8100B/8100C" }, { RL_HWREV_8139CPLUS, RL_8139CPLUS, "C+"}, + { RL_HWREV_8168, RL_8169, "8168"}, { RL_HWREV_8169, RL_8169, "8169"}, { RL_HWREV_8169S, RL_8169, "8169S"}, - { RL_HWREV_8169SB, RL_8169, "8169SB"}, { RL_HWREV_8110S, RL_8169, "8110S"}, + { RL_HWREV_8169_8110SB, RL_8169, "8169SB"}, + { RL_HWREV_8169_8110SC, RL_8169, "8169SC"}, { RL_HWREV_8100, RL_8139, "8100"}, { RL_HWREV_8101, RL_8139, "8101"}, - { RL_HWREV_8168, RL_8169, "8168/8111B"}, + { RL_HWREV_8100E, RL_8169, "8100E"}, + { RL_HWREV_8101E, RL_8169, "8101E"}, { 0, 0, NULL } }; @@ -220,7 +230,7 @@ static int re_tx_list_init (struct rl_softc *); static __inline void re_fixup_rx (struct mbuf *); #endif -static void re_rxeof (struct rl_softc *); +static int re_rxeof (struct rl_softc *); static void re_txeof (struct rl_softc *); #ifdef DEVICE_POLLING static void re_poll (struct ifnet *, enum poll_cmd, int); @@ -228,8 +238,9 @@ static void re_poll_locked (struct ifnet *, enum poll_cmd, int); #endif static void re_intr (void *); static void re_tick (void *); +static void re_tx_task (void *, int); +static void re_int_task (void *, int); static void re_start (struct ifnet *); -static void re_start_locked (struct ifnet *); static int re_ioctl (struct ifnet *, u_long, caddr_t); static void re_init (void *); static void re_init_locked (struct rl_softc *); @@ -243,7 +254,7 @@ static void re_ifmedia_sts (struct ifnet *, struct ifmediareq *); static void re_eeprom_putbyte (struct rl_softc *, int); static void re_eeprom_getword (struct rl_softc *, int, u_int16_t *); -static void re_read_eeprom (struct rl_softc *, caddr_t, int, int, int); +static void re_read_eeprom (struct rl_softc *, caddr_t, int, int); static int re_gmii_readreg (device_t, int, int); static int re_gmii_writereg (device_t, int, int, int); @@ -254,7 +265,9 @@ static void re_miibus_statchg (device_t); static void re_setmulti (struct rl_softc *); static void re_reset (struct rl_softc *); +#ifdef RE_DIAG static int re_diag (struct rl_softc *); +#endif #ifdef RE_USEIOSPACE #define RL_RES SYS_RES_IOPORT @@ -315,12 +328,13 @@ re_eeprom_putbyte(sc, addr) { register int d, i; - d = addr | sc->rl_eecmd_read; + d = addr | (RL_9346_READ << sc->rl_eewidth); /* * Feed in each bit and strobe the clock. */ - for (i = 0x400; i; i >>= 1) { + + for (i = 1 << (sc->rl_eewidth + 3); i; i >>= 1) { if (d & i) { EE_SET(RL_EE_DATAIN); } else { @@ -332,6 +346,8 @@ re_eeprom_putbyte(sc, addr) EE_CLR(RL_EE_CLK); DELAY(100); } + + return; } /* @@ -346,16 +362,11 @@ re_eeprom_getword(sc, addr, dest) register int i; u_int16_t word = 0; - /* Enter EEPROM access mode. */ - CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); - /* * Send address of word we want to read. */ re_eeprom_putbyte(sc, addr); - CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_PROGRAM|RL_EE_SEL); - /* * Start reading bits from EEPROM. */ @@ -368,34 +379,39 @@ re_eeprom_getword(sc, addr, dest) DELAY(100); } - /* Turn off EEPROM access mode. */ - CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); - *dest = word; + + return; } /* * Read a sequence of words from the EEPROM. */ static void -re_read_eeprom(sc, dest, off, cnt, swap) +re_read_eeprom(sc, dest, off, cnt) struct rl_softc *sc; caddr_t dest; int off; int cnt; - int swap; { int i; u_int16_t word = 0, *ptr; + CSR_SETBIT_1(sc, RL_EECMD, RL_EEMODE_PROGRAM); + + DELAY(100); + for (i = 0; i < cnt; i++) { + CSR_SETBIT_1(sc, RL_EECMD, RL_EE_SEL); re_eeprom_getword(sc, off + i, &word); + CSR_CLRBIT_1(sc, RL_EECMD, RL_EE_SEL); ptr = (u_int16_t *)(dest + (i * 2)); - if (swap) - *ptr = ntohs(word); - else - *ptr = word; + *ptr = le16toh(word); } + + CSR_CLRBIT_1(sc, RL_EECMD, RL_EEMODE_PROGRAM); + + return; } static int @@ -656,6 +672,8 @@ re_reset(sc) CSR_WRITE_1(sc, 0x82, 1); } +#ifdef RE_DIAG + /* * The following routine is designed to test for a defect on some * 32-bit 8169 cards. Some of these NICs have the REQ64# and ACK64# @@ -686,7 +704,7 @@ re_diag(sc) struct rl_desc *cur_rx; u_int16_t status; u_int32_t rxstat; - int total_len, i, error = 0; + int total_len, i, error = 0, phyaddr; u_int8_t dst[] = { 0x00, 'h', 'e', 'l', 'l', 'o' }; u_int8_t src[] = { 0x00, 'w', 'o', 'r', 'l', 'd' }; @@ -708,10 +726,25 @@ re_diag(sc) ifp->if_flags |= IFF_PROMISC; sc->rl_testmode = 1; + re_reset(sc); re_init_locked(sc); - re_stop(sc); + sc->rl_link = 1; + if (sc->rl_type == RL_8169) + phyaddr = 1; + else + phyaddr = 0; + + re_miibus_writereg(sc->rl_dev, phyaddr, MII_BMCR, BMCR_RESET); + for (i = 0; i < RL_TIMEOUT; i++) { + status = re_miibus_readreg(sc->rl_dev, phyaddr, MII_BMCR); + if (!(status & BMCR_RESET)) + break; + } + + re_miibus_writereg(sc->rl_dev, phyaddr, MII_BMCR, BMCR_LOOP); + CSR_WRITE_2(sc, RL_ISR, RL_INTRS); + DELAY(100000); - re_init_locked(sc); /* Put some data in the mbuf */ @@ -738,6 +771,7 @@ re_diag(sc) DELAY(100000); for (i = 0; i < RL_TIMEOUT; i++) { status = CSR_READ_2(sc, RL_ISR); + CSR_WRITE_2(sc, RL_ISR, status); if ((status & (RL_ISR_TIMEOUT_EXPIRED|RL_ISR_RX_OK)) == (RL_ISR_TIMEOUT_EXPIRED|RL_ISR_RX_OK)) break; @@ -802,6 +836,7 @@ done: /* Turn interface off, release resources */ sc->rl_testmode = 0; + sc->rl_link = 0; ifp->if_flags &= ~IFF_PROMISC; re_stop(sc); if (m0 != NULL) @@ -812,6 +847,8 @@ done: return (error); } +#endif + /* * Probe for a RealTek 8139C+/8169/8110 chip. Check the PCI vendor and device * IDs against our list and return a device name if we find a match. @@ -1087,9 +1124,12 @@ re_attach(dev) int error = 0, rid, i; sc = device_get_softc(dev); + sc->rl_dev = dev; mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); + mtx_init(&sc->rl_intlock, device_get_nameunit(dev), MTX_NETWORK_LOCK, + MTX_SPIN); callout_init_mtx(&sc->rl_stat_callout, &sc->rl_mtx, 0); /* @@ -1136,44 +1176,28 @@ re_attach(dev) hw_rev++; } - if (sc->rl_type == RL_8169) { + sc->rl_eewidth = 6; + re_read_eeprom(sc, (caddr_t)&re_did, 0, 1); + if (re_did != 0x8129) + sc->rl_eewidth = 8; - /* Set RX length mask */ + /* + * Get station address from the EEPROM. + */ + re_read_eeprom(sc, (caddr_t)as, RL_EE_EADDR, 3); + for (i = 0; i < 3; i++) { + eaddr[(i * 2) + 0] = as[i] & 0xff; + eaddr[(i * 2) + 1] = as[i] >> 8; + } + if (sc->rl_type == RL_8169) { + /* Set RX length mask */ sc->rl_rxlenmask = RL_RDESC_STAT_GFRAGLEN; - - /* Force station address autoload from the EEPROM */ - - CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_AUTOLOAD); - for (i = 0; i < RL_TIMEOUT; i++) { - if (!(CSR_READ_1(sc, RL_EECMD) & RL_EEMODE_AUTOLOAD)) - break; - DELAY(100); - } - if (i == RL_TIMEOUT) - device_printf(dev, "eeprom autoload timed out\n"); - - for (i = 0; i < ETHER_ADDR_LEN; i++) - eaddr[i] = CSR_READ_1(sc, RL_IDR0 + i); + sc->rl_txstart = RL_GTXSTART; } else { - /* Set RX length mask */ - sc->rl_rxlenmask = RL_RDESC_STAT_FRAGLEN; - - sc->rl_eecmd_read = RL_EECMD_READ_6BIT; - re_read_eeprom(sc, (caddr_t)&re_did, 0, 1, 0); - if (re_did != 0x8129) - sc->rl_eecmd_read = RL_EECMD_READ_8BIT; - - /* - * Get station address from the EEPROM. - */ - re_read_eeprom(sc, (caddr_t)as, RL_EE_EADDR, 3, 0); - for (i = 0; i < 3; i++) { - eaddr[(i * 2) + 0] = as[i] & 0xff; - eaddr[(i * 2) + 1] = as[i] >> 8; - } + sc->rl_txstart = RL_TXSTART; } /* @@ -1220,7 +1244,7 @@ re_attach(dev) ifp->if_ioctl = re_ioctl; ifp->if_capabilities = IFCAP_VLAN_MTU; ifp->if_start = re_start; - ifp->if_hwassist = /*RE_CSUM_FEATURES*/0; + ifp->if_hwassist = RE_CSUM_FEATURES; ifp->if_capabilities |= IFCAP_HWCSUM|IFCAP_VLAN_HWTAGGING; ifp->if_capenable = ifp->if_capabilities & ~IFCAP_HWCSUM; #ifdef DEVICE_POLLING @@ -1228,33 +1252,46 @@ re_attach(dev) #endif ifp->if_watchdog = re_watchdog; ifp->if_init = re_init; - IFQ_SET_MAXLEN(&ifp->if_snd, RL_IFQ_MAXLEN); + IFQ_SET_MAXLEN(&ifp->if_snd, RL_IFQ_MAXLEN); ifp->if_snd.ifq_drv_maxlen = RL_IFQ_MAXLEN; IFQ_SET_READY(&ifp->if_snd); + TASK_INIT(&sc->rl_txtask, 1, re_tx_task, ifp); + TASK_INIT(&sc->rl_inttask, 0, re_int_task, sc); + /* * Call MI attach routine. */ ether_ifattach(ifp, eaddr); - /* Perform hardware diagnostic. */ - error = re_diag(sc); +#ifdef RE_DIAG + /* + * Perform hardware diagnostic on the original RTL8169. + * Some 32-bit cards were incorrectly wired and would + * malfunction if plugged into a 64-bit slot. + */ - if (error) { - device_printf(dev, "attach aborted due to hardware diag failure\n"); - ether_ifdetach(ifp); - goto fail; + if (hwrev == RL_HWREV_8169) { + error = re_diag(sc); + if (error) { + device_printf(dev, + "attach aborted due to hardware diag failure\n"); + ether_ifdetach(ifp); + goto fail; + } } +#endif /* Hook interrupt last to avoid having to lock softc */ - error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET | INTR_MPSAFE, - re_intr, sc, &sc->rl_intrhand); + error = bus_setup_intr(dev, sc->rl_irq, INTR_TYPE_NET | INTR_MPSAFE | + INTR_FAST, re_intr, sc, &sc->rl_intrhand); if (error) { device_printf(dev, "couldn't set up irq\n"); ether_ifdetach(ifp); } fail: + if (error) re_detach(dev); @@ -1284,7 +1321,6 @@ re_detach(dev) if (ifp->if_capenable & IFCAP_POLLING) ether_poll_deregister(ifp); #endif - /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { RL_LOCK(sc); @@ -1377,6 +1413,7 @@ re_detach(dev) bus_dma_tag_destroy(sc->rl_parent_tag); mtx_destroy(&sc->rl_mtx); + mtx_destroy(&sc->rl_intlock); return (0); } @@ -1510,7 +1547,7 @@ re_rx_list_init(sc) * the reception of jumbo frames that have been fragmented * across multiple 2K mbuf cluster buffers. */ -static void +static int re_rxeof(sc) struct rl_softc *sc; { @@ -1519,6 +1556,7 @@ re_rxeof(sc) int i, total_len; struct rl_desc *cur_rx; u_int32_t rxstat, rxvlan; + int maxpkt = 16; RL_LOCK_ASSERT(sc); @@ -1531,7 +1569,7 @@ re_rxeof(sc) sc->rl_ldata.rl_rx_list_map, BUS_DMASYNC_POSTREAD); - while (!RL_OWN(&sc->rl_ldata.rl_rx_list[i])) { + while (!RL_OWN(&sc->rl_ldata.rl_rx_list[i]) && maxpkt) { cur_rx = &sc->rl_ldata.rl_rx_list[i]; m = sc->rl_ldata.rl_rx_mbuf[i]; total_len = RL_RXBYTES(cur_rx); @@ -1669,7 +1707,7 @@ re_rxeof(sc) m->m_pkthdr.csum_data = 0xffff; } } - + maxpkt--; if (rxvlan & RL_RDESC_VLANCTL_TAG) { VLAN_INPUT_TAG(ifp, m, ntohs((rxvlan & RL_RDESC_VLANCTL_DATA))); @@ -1688,6 +1726,11 @@ re_rxeof(sc) BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); sc->rl_ldata.rl_rx_prodidx = i; + + if (maxpkt) + return(EAGAIN); + + return(0); } static void @@ -1707,12 +1750,14 @@ re_txeof(sc) sc->rl_ldata.rl_tx_list_map, BUS_DMASYNC_POSTREAD); - while (idx != sc->rl_ldata.rl_tx_prodidx) { + while (sc->rl_ldata.rl_tx_free < RL_TX_DESC_CNT) { txstat = le32toh(sc->rl_ldata.rl_tx_list[idx].rl_cmdstat); if (txstat & RL_TDESC_CMD_OWN) break; + sc->rl_ldata.rl_tx_list[idx].rl_bufaddr_lo = 0; + /* * We only stash mbufs in the last descriptor * in a fragment chain, which also happens to @@ -1739,12 +1784,13 @@ re_txeof(sc) /* No changes made to the TX ring, so no flush needed */ - if (idx != sc->rl_ldata.rl_tx_considx) { + if (sc->rl_ldata.rl_tx_free) { sc->rl_ldata.rl_tx_considx = idx; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_timer = 0; } +#ifdef RE_TX_MODERATION /* * If not all descriptors have been released reaped yet, * reload the timer so that we will eventually get another @@ -1753,6 +1799,7 @@ re_txeof(sc) */ if (sc->rl_ldata.rl_tx_free != RL_TX_DESC_CNT) CSR_WRITE_4(sc, RL_TIMERCNT, 1); +#endif } static void @@ -1761,14 +1808,28 @@ re_tick(xsc) { struct rl_softc *sc; struct mii_data *mii; + struct ifnet *ifp; sc = xsc; + ifp = sc->rl_ifp; RL_LOCK_ASSERT(sc); mii = device_get_softc(sc->rl_miibus); mii_tick(mii); + if (sc->rl_link) { + if (!(mii->mii_media_status & IFM_ACTIVE)) + sc->rl_link = 0; + } else { + if (mii->mii_media_status & IFM_ACTIVE && + IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { + sc->rl_link = 1; + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + taskqueue_enqueue_fast(taskqueue_fast, + &sc->rl_txtask); + } + } callout_reset(&sc->rl_stat_callout, hz, re_tick, sc); } @@ -1797,7 +1858,7 @@ re_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) re_txeof(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - re_start_locked(ifp); + taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_txtask); if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */ u_int16_t status; @@ -1826,61 +1887,91 @@ re_intr(arg) { struct rl_softc *sc; struct ifnet *ifp; + uint16_t status; + + sc = arg; + ifp = sc->rl_ifp; + + mtx_lock_spin(&sc->rl_intlock); + status = CSR_READ_2(sc, RL_ISR); + if (status == 0xFFFF || (status & RL_INTRS_CPLUS) == 0) { + mtx_unlock_spin(&sc->rl_intlock); + return; + } + CSR_WRITE_2(sc, RL_IMR, 0); + mtx_unlock_spin(&sc->rl_intlock); + + taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_inttask); + + return; +} + +static void +re_int_task(arg, npending) + void *arg; + int npending; +{ + struct rl_softc *sc; + struct ifnet *ifp; u_int16_t status; + int rval = 0; sc = arg; + ifp = sc->rl_ifp; RL_LOCK(sc); - ifp = sc->rl_ifp; + status = CSR_READ_2(sc, RL_ISR); + CSR_WRITE_2(sc, RL_ISR, status); - if (sc->suspended || !(ifp->if_flags & IFF_UP)) - goto done_locked; + if (sc->suspended || !(ifp->if_flags & IFF_UP)) { + RL_UNLOCK(sc); + return; + } #ifdef DEVICE_POLLING - if (ifp->if_capenable & IFCAP_POLLING) - goto done_locked; + if (ifp->if_capenable & IFCAP_POLLING) { + RL_UNLOCK(sc); + return; + } #endif - for (;;) { + if (status & (RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_FIFO_OFLOW)) + rval = re_rxeof(sc); - status = CSR_READ_2(sc, RL_ISR); - /* If the card has gone away the read returns 0xffff. */ - if (status == 0xffff) - break; - if (status) - CSR_WRITE_2(sc, RL_ISR, status); +#ifdef RE_TX_MODERATION + if (status & (RL_ISR_TIMEOUT_EXPIRED| +#else + if (status & (RL_ISR_TX_OK| +#endif + RL_ISR_TX_ERR|RL_ISR_TX_DESC_UNAVAIL)) + re_txeof(sc); - if ((status & RL_INTRS_CPLUS) == 0) - break; + if (status & RL_ISR_SYSTEM_ERR) { + re_reset(sc); + re_init_locked(sc); + } - if (((status & RL_ISR_RX_OK) || - (status & RL_ISR_RX_ERR)) && - ifp->if_drv_flags & IFF_DRV_RUNNING) - re_rxeof(sc); + if (status & RL_ISR_LINKCHG) { + callout_stop(&sc->rl_stat_callout); + re_tick(sc); + } - if (((status & RL_ISR_TIMEOUT_EXPIRED) || - (status & RL_ISR_TX_ERR) || - (status & RL_ISR_TX_DESC_UNAVAIL)) && - ifp->if_drv_flags & IFF_DRV_RUNNING) - re_txeof(sc); + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_txtask); - if (status & RL_ISR_SYSTEM_ERR) { - re_reset(sc); - re_init_locked(sc); - } + RL_UNLOCK(sc); - if (status & RL_ISR_LINKCHG) { - callout_stop(&sc->rl_stat_callout); - re_tick(sc); - } + if ((CSR_READ_2(sc, RL_ISR) & RL_INTRS_CPLUS) || rval) { + taskqueue_enqueue_fast(taskqueue_fast, &sc->rl_inttask); + return; } - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - re_start_locked(ifp); + mtx_lock_spin(&sc->rl_intlock); + CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS); + mtx_unlock_spin(&sc->rl_intlock); -done_locked: - RL_UNLOCK(sc); + return; } static int @@ -1986,29 +2077,30 @@ re_encap(sc, m_head, idx) sc->rl_ldata.rl_tx_list[*idx].rl_cmdstat |= htole32(RL_TDESC_CMD_OWN); - RL_DESC_INC(arg.rl_idx); + RL_DESC_INC(arg.rl_idx); *idx = arg.rl_idx; return (0); } static void -re_start(ifp) - struct ifnet *ifp; +re_tx_task(arg, npending) + void *arg; + int npending; { - struct rl_softc *sc; + struct ifnet *ifp; - sc = ifp->if_softc; - RL_LOCK(sc); - re_start_locked(ifp); - RL_UNLOCK(sc); + ifp = arg; + re_start(ifp); + + return; } /* * Main transmit routine for C+ and gigE NICs. */ static void -re_start_locked(ifp) +re_start(ifp) struct ifnet *ifp; { struct rl_softc *sc; @@ -2017,7 +2109,12 @@ re_start_locked(ifp) sc = ifp->if_softc; - RL_LOCK_ASSERT(sc); + RL_LOCK(sc); + + if (!sc->rl_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) { + RL_UNLOCK(sc); + return; + } idx = sc->rl_ldata.rl_tx_prodidx; @@ -2041,8 +2138,14 @@ re_start_locked(ifp) queued++; } - if (queued == 0) + if (queued == 0) { +#ifdef RE_TX_MODERATION + if (sc->rl_ldata.rl_tx_free != RL_TX_DESC_CNT) + CSR_WRITE_4(sc, RL_TIMERCNT, 1); +#endif + RL_UNLOCK(sc); return; + } /* Flush the TX descriptors */ @@ -2057,11 +2160,9 @@ re_start_locked(ifp) * location on the 8169 gigE chip. I don't know why. */ - if (sc->rl_type == RL_8169) - CSR_WRITE_2(sc, RL_GTXSTART, RL_TXSTART_START); - else - CSR_WRITE_2(sc, RL_TXSTART, RL_TXSTART_START); + CSR_WRITE_2(sc, sc->rl_txstart, RL_TXSTART_START); +#ifdef RE_TX_MODERATION /* * Use the countdown timer for interrupt moderation. * 'TX done' interrupts are disabled. Instead, we reset the @@ -2071,11 +2172,17 @@ re_start_locked(ifp) * the timer count is reset to 0. */ CSR_WRITE_4(sc, RL_TIMERCNT, 1); +#endif /* * Set a timeout in case the chip goes out to lunch. */ + ifp->if_timer = 5; + + RL_UNLOCK(sc); + + return; } static void @@ -2099,7 +2206,7 @@ re_init_locked(sc) union { uint32_t align_dummy; u_char eaddr[ETHER_ADDR_LEN]; - } eaddr; + } eaddr; RL_LOCK_ASSERT(sc); @@ -2117,9 +2224,7 @@ re_init_locked(sc) */ CSR_WRITE_2(sc, RL_CPLUS_CMD, RL_CPLUSCMD_RXENB| RL_CPLUSCMD_TXENB|RL_CPLUSCMD_PCI_MRW| - RL_CPLUSCMD_VLANSTRIP| - (ifp->if_capenable & IFCAP_RXCSUM ? - RL_CPLUSCMD_RXCSUM_ENB : 0)); + RL_CPLUSCMD_VLANSTRIP|RL_CPLUSCMD_RXCSUM_ENB); /* * Init our MAC address. Even though the chipset @@ -2129,10 +2234,10 @@ re_init_locked(sc) /* Copy MAC address on stack to align. */ bcopy(IF_LLADDR(ifp), eaddr.eaddr, ETHER_ADDR_LEN); CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG); - CSR_WRITE_STREAM_4(sc, RL_IDR0, - *(u_int32_t *)(&eaddr.eaddr[0])); - CSR_WRITE_STREAM_4(sc, RL_IDR4, - *(u_int32_t *)(&eaddr.eaddr[4])); + CSR_WRITE_4(sc, RL_IDR0, + htole32(*(u_int32_t *)(&eaddr.eaddr[0]))); + CSR_WRITE_4(sc, RL_IDR4, + htole32(*(u_int32_t *)(&eaddr.eaddr[4]))); CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF); /* @@ -2193,13 +2298,17 @@ re_init_locked(sc) CSR_WRITE_2(sc, RL_IMR, 0); else /* otherwise ... */ #endif + /* * Enable interrupts. */ + mtx_lock_spin(&sc->rl_intlock); if (sc->rl_testmode) CSR_WRITE_2(sc, RL_IMR, 0); else CSR_WRITE_2(sc, RL_IMR, RL_INTRS_CPLUS); + CSR_WRITE_2(sc, RL_ISR, RL_INTRS_CPLUS); + mtx_unlock_spin(&sc->rl_intlock); /* Set initial TX threshold */ sc->rl_txthresh = RL_TX_THRESH_INIT; @@ -2226,6 +2335,7 @@ re_init_locked(sc) CSR_WRITE_1(sc, RL_EARLY_TX_THRESH, 16); +#ifdef RE_TX_MODERATION /* * Initialize the timer interrupt register so that * a timer interrupt will be generated once the timer @@ -2237,6 +2347,7 @@ re_init_locked(sc) CSR_WRITE_4(sc, RL_TIMERINT_8169, 0x800); else CSR_WRITE_4(sc, RL_TIMERINT, 0x400); +#endif /* * For 8169 gigE NICs, set the max allowed RX packet @@ -2255,6 +2366,9 @@ re_init_locked(sc) ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + sc->rl_link = 0; + callout_reset(&sc->rl_stat_callout, hz, re_tick, sc); } @@ -2427,6 +2541,7 @@ re_stop(sc) CSR_WRITE_1(sc, RL_COMMAND, 0x00); CSR_WRITE_2(sc, RL_IMR, 0x0000); + CSR_WRITE_2(sc, RL_ISR, 0xFFFF); if (sc->rl_head != NULL) { m_freem(sc->rl_head); |
