diff options
author | jfv <jfv@FreeBSD.org> | 2009-06-24 17:41:29 +0000 |
---|---|---|
committer | jfv <jfv@FreeBSD.org> | 2009-06-24 17:41:29 +0000 |
commit | bd3587c757355e28ac6abbaf11703661599270bb (patch) | |
tree | 2ecc6e8fbc53f9378cbe7397d226334796447dd4 /sys/dev/e1000/if_em.c | |
parent | 7d778199caba58e2bf12662021294f3869f8f1dd (diff) | |
download | FreeBSD-src-bd3587c757355e28ac6abbaf11703661599270bb.zip FreeBSD-src-bd3587c757355e28ac6abbaf11703661599270bb.tar.gz |
Updates for both the em and igb drivers, add support
for multiqueue tx, shared code updates, new device
support, and some bug fixes.
Diffstat (limited to 'sys/dev/e1000/if_em.c')
-rw-r--r-- | sys/dev/e1000/if_em.c | 570 |
1 files changed, 231 insertions, 339 deletions
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index 3d1d362..43990b6 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -39,7 +39,9 @@ #include <sys/param.h> #include <sys/systm.h> +#if __FreeBSD_version >= 800000 #include <sys/buf_ring.h> +#endif #include <sys/bus.h> #include <sys/endian.h> #include <sys/kernel.h> @@ -52,10 +54,8 @@ #include <sys/sockio.h> #include <sys/sysctl.h> #include <sys/taskqueue.h> +#if __FreeBSD_version >= 700029 #include <sys/eventhandler.h> -#ifdef EM_TIMESYNC -#include <sys/ioccom.h> -#include <sys/time.h> #endif #include <machine/bus.h> #include <machine/resource.h> @@ -94,7 +94,7 @@ int em_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char em_driver_version[] = "6.9.9"; +char em_driver_version[] = "6.9.14"; /********************************************************************* @@ -178,6 +178,7 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, E1000_DEV_ID_82573E, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82573E_IAMT, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82573L, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82583V, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_80003ES2LAN_COPPER_SPT, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_80003ES2LAN_SERDES_SPT, @@ -204,6 +205,7 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, E1000_DEV_ID_ICH9_IFE_G, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH9_BM, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82574L, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82574LA, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH10_R_BM_LM, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH10_R_BM_LF, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH10_R_BM_V, PCI_ANY_ID, PCI_ANY_ID, 0}, @@ -232,6 +234,11 @@ static int em_suspend(device_t); static int em_resume(device_t); static void em_start(struct ifnet *); static void em_start_locked(struct ifnet *ifp); +#if __FreeBSD_version >= 800000 +static int em_mq_start(struct ifnet *, struct mbuf *); +static int em_mq_start_locked(struct ifnet *, struct mbuf *); +static void em_qflush(struct ifnet *); +#endif static int em_ioctl(struct ifnet *, u_long, caddr_t); static void em_watchdog(struct adapter *); static void em_init(void *); @@ -261,7 +268,7 @@ static void em_txeof(struct adapter *); static void em_tx_purge(struct adapter *); static int em_allocate_receive_structures(struct adapter *); static int em_allocate_transmit_structures(struct adapter *); -static int em_rxeof(struct adapter *, int, int *); +static int em_rxeof(struct adapter *, int); #ifndef __NO_STRICT_ALIGNMENT static int em_fixup_rx(struct adapter *); #endif @@ -279,8 +286,11 @@ static void em_set_multi(struct adapter *); static void em_print_hw_stats(struct adapter *); static void em_update_link_status(struct adapter *); static int em_get_buf(struct adapter *, int); +#if __FreeBSD_version >= 700029 static void em_register_vlan(void *, struct ifnet *, u16); static void em_unregister_vlan(void *, struct ifnet *, u16); +static void em_setup_vlan_hw_support(struct adapter *); +#endif static int em_xmit(struct adapter *, struct mbuf **); static void em_smartspeed(struct adapter *); static int em_82547_fifo_workaround(struct adapter *, int); @@ -307,12 +317,6 @@ static void em_get_hw_control(struct adapter *); static void em_release_hw_control(struct adapter *); static void em_enable_wakeup(device_t); -#ifdef EM_TIMESYNC -/* Precision Time sync support */ -static int em_tsync_init(struct adapter *); -static void em_tsync_disable(struct adapter *); -#endif - #ifdef EM_LEGACY_IRQ static void em_intr(void *); #else /* FAST IRQ */ @@ -404,6 +408,18 @@ static int em_rx_process_limit = 100; TUNABLE_INT("hw.em.rx_process_limit", &em_rx_process_limit); #endif +/* Flow control setting - default to FULL */ +static int em_fc_setting = e1000_fc_full; +TUNABLE_INT("hw.em.fc_setting", &em_fc_setting); + +/* +** Shadow VFTA table, this is needed because +** the real vlan filter table gets cleared during +** a soft reset and the driver needs to be able +** to repopulate it. +*/ +static u32 em_shadow_vfta[EM_VFTA_SIZE]; + /* Global used in WOL setup with multiport cards */ static int global_quad_port_a = 0; @@ -796,11 +812,13 @@ em_attach(device_t dev) else adapter->pcix_82544 = FALSE; +#if __FreeBSD_version >= 700029 /* Register for VLAN events */ adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, em_register_vlan, 0, EVENTHANDLER_PRI_FIRST); adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, em_unregister_vlan, 0, EVENTHANDLER_PRI_FIRST); +#endif /* Tell the stack that the interface is not active */ adapter->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); @@ -869,6 +887,7 @@ em_detach(device_t dev) em_release_manageability(adapter); if (((adapter->hw.mac.type == e1000_82573) || + (adapter->hw.mac.type == e1000_82583) || (adapter->hw.mac.type == e1000_ich8lan) || (adapter->hw.mac.type == e1000_ich10lan) || (adapter->hw.mac.type == e1000_ich9lan)) && @@ -884,11 +903,13 @@ em_detach(device_t dev) EM_TX_UNLOCK(adapter); EM_CORE_UNLOCK(adapter); +#if __FreeBSD_version >= 700029 /* Unregister VLAN events */ if (adapter->vlan_attach != NULL) EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); if (adapter->vlan_detach != NULL) EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); +#endif ether_ifdetach(adapter->ifp); callout_drain(&adapter->timer); @@ -898,7 +919,9 @@ em_detach(device_t dev) bus_generic_detach(dev); if_free(ifp); +#if __FreeBSD_version >= 800000 drbr_free(adapter->br, M_DEVBUF); +#endif em_free_transmit_structures(adapter); em_free_receive_structures(adapter); @@ -950,6 +973,7 @@ em_suspend(device_t dev) em_release_manageability(adapter); if (((adapter->hw.mac.type == e1000_82573) || + (adapter->hw.mac.type == e1000_82583) || (adapter->hw.mac.type == e1000_ich8lan) || (adapter->hw.mac.type == e1000_ich10lan) || (adapter->hw.mac.type == e1000_ich9lan)) && @@ -993,20 +1017,25 @@ em_resume(device_t dev) * the packet is requeued. **********************************************************************/ -#ifdef IFNET_BUF_RING +#if __FreeBSD_version >= 800000 static int -em_transmit_locked(struct ifnet *ifp, struct mbuf *m) +em_mq_start_locked(struct ifnet *ifp, struct mbuf *m) { struct adapter *adapter = ifp->if_softc; - int error; + struct mbuf *next; + int error = E1000_SUCCESS; EM_TX_LOCK_ASSERT(adapter); + /* To allow being called from a tasklet */ + if (m == NULL) + goto process; + if (((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) || (!adapter->link_active)) { error = drbr_enqueue(ifp, adapter->br, m); return (error); - } else if (ADAPTER_RING_EMPTY(adapter) && + } else if (drbr_empty(ifp, adapter->br) && (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) { if (em_xmit(adapter, &m)) { if (m && (error = drbr_enqueue(ifp, adapter->br, m)) != 0) @@ -1027,22 +1056,43 @@ em_transmit_locked(struct ifnet *ifp, struct mbuf *m) } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0) return (error); - if (!ADAPTER_RING_EMPTY(adapter)) - em_start_locked(ifp); +process: + if (drbr_empty(ifp, adapter->br)) + return(error); + /* Process the queue */ + while (TRUE) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + break; + next = drbr_dequeue(ifp, adapter->br); + if (next == NULL) + break; + if (em_xmit(adapter, &next)) + break; + ETHER_BPF_MTAP(ifp, next); + /* Set the watchdog */ + adapter->watchdog_timer = EM_TX_TIMEOUT; + } + + if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) + ifp->if_drv_flags |= IFF_DRV_OACTIVE; return (0); } - + +/* +** Multiqueue capable stack interface, this is not +** yet truely multiqueue, but that is coming... +*/ static int -em_transmit(struct ifnet *ifp, struct mbuf *m) +em_mq_start(struct ifnet *ifp, struct mbuf *m) { struct adapter *adapter = ifp->if_softc; int error = 0; - if(EM_TX_TRYLOCK(adapter)) { + if (EM_TX_TRYLOCK(adapter)) { if (ifp->if_drv_flags & IFF_DRV_RUNNING) - error = em_transmit_locked(ifp, m); + error = em_mq_start_locked(ifp, m); EM_TX_UNLOCK(adapter); } else error = drbr_enqueue(ifp, adapter->br, m); @@ -1062,7 +1112,7 @@ em_qflush(struct ifnet *ifp) if_qflush(ifp); EM_TX_UNLOCK(adapter); } -#endif +#endif /* FreeBSD_version */ static void em_start_locked(struct ifnet *ifp) @@ -1078,10 +1128,9 @@ em_start_locked(struct ifnet *ifp) if (!adapter->link_active) return; - while ((adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD) - && (!ADAPTER_RING_EMPTY(adapter))) { + while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { - m_head = em_dequeue(ifp, adapter->br); + IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; /* @@ -1091,10 +1140,8 @@ em_start_locked(struct ifnet *ifp) if (em_xmit(adapter, &m_head)) { if (m_head == NULL) break; -#ifndef IFNET_BUF_RING ifp->if_drv_flags |= IFF_DRV_OACTIVE; IFQ_DRV_PREPEND(&ifp->if_snd, m_head); -#endif break; } @@ -1104,9 +1151,10 @@ em_start_locked(struct ifnet *ifp) /* Set timeout in case hardware has problems transmitting. */ adapter->watchdog_timer = EM_TX_TIMEOUT; } - if ((adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD)) + if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) ifp->if_drv_flags |= IFF_DRV_OACTIVE; + return; } static void @@ -1195,6 +1243,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) break; /* Adapters that do not support jumbo frames */ case e1000_82542: + case e1000_82583: case e1000_ich8lan: max_frame_size = ETHER_MAX_LEN; break; @@ -1320,70 +1369,6 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) break; } -#ifdef EM_TIMESYNC - /* - ** IOCTL support for Precision Time (IEEE 1588) Support - */ - case EM_TIMESYNC_READTS: - { - u32 rx_ctl, tx_ctl; - struct em_tsync_read *tdata; - - tdata = (struct em_tsync_read *) ifr->ifr_data; - - IOCTL_DEBUGOUT("Reading Timestamp\n"); - - if (tdata->read_current_time) { - getnanotime(&tdata->system_time); - tdata->network_time = E1000_READ_REG(&adapter->hw, E1000_SYSTIML); - tdata->network_time |= - (u64)E1000_READ_REG(&adapter->hw, E1000_SYSTIMH ) << 32; - } - - rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL); - tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL); - - IOCTL_DEBUGOUT1("RX_CTL value = %u\n", rx_ctl); - IOCTL_DEBUGOUT1("TX_CTL value = %u\n", tx_ctl); - - if (rx_ctl & 0x1) { - IOCTL_DEBUGOUT("RX timestamp is valid\n"); - u32 tmp; - unsigned char *tmp_cp; - - tdata->rx_valid = 1; - tdata->rx_stamp = E1000_READ_REG(&adapter->hw, E1000_RXSTMPL); - tdata->rx_stamp |= (u64)E1000_READ_REG(&adapter->hw, - E1000_RXSTMPH) << 32; - - tmp = E1000_READ_REG(&adapter->hw, E1000_RXSATRL); - tmp_cp = (unsigned char *) &tmp; - tdata->srcid[0] = tmp_cp[0]; - tdata->srcid[1] = tmp_cp[1]; - tdata->srcid[2] = tmp_cp[2]; - tdata->srcid[3] = tmp_cp[3]; - tmp = E1000_READ_REG(&adapter->hw, E1000_RXSATRH); - tmp_cp = (unsigned char *) &tmp; - tdata->srcid[4] = tmp_cp[0]; - tdata->srcid[5] = tmp_cp[1]; - tdata->seqid = tmp >> 16; - tdata->seqid = htons(tdata->seqid); - } else - tdata->rx_valid = 0; - - if (tx_ctl & 0x1) { - IOCTL_DEBUGOUT("TX timestamp is valid\n"); - tdata->tx_valid = 1; - tdata->tx_stamp = E1000_READ_REG(&adapter->hw, E1000_TXSTMPL); - tdata->tx_stamp |= (u64) E1000_READ_REG(&adapter->hw, - E1000_TXSTMPH) << 32; - } else - tdata->tx_valid = 0; - - return (0); - } -#endif /* EM_TIMESYNC */ - default: error = ether_ioctl(ifp, command, data); break; @@ -1499,13 +1484,11 @@ em_init_locked(struct adapter *adapter) pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */ break; case e1000_82574: + case e1000_82583: pba = E1000_PBA_20K; /* 20K for Rx, 20K for Tx */ break; case e1000_ich9lan: case e1000_ich10lan: -#define E1000_PBA_10K 0x000A - pba = E1000_PBA_10K; - break; case e1000_ich8lan: pba = E1000_PBA_8K; break; @@ -1549,14 +1532,17 @@ em_init_locked(struct adapter *adapter) /* Setup VLAN support, basic and offload if available */ E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN); - if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) && - ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0)) { +#if __FreeBSD_version < 700029 + if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) { u32 ctrl; ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); ctrl |= E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); } - +#else + /* Use real VLAN Filter support */ + em_setup_vlan_hw_support(adapter); +#endif /* Set hardware offload abilities */ ifp->if_hwassist = 0; @@ -1625,13 +1611,6 @@ em_init_locked(struct adapter *adapter) #endif /* DEVICE_POLLING */ em_enable_intr(adapter); -#ifdef EM_TIMESYNC - /* Initializae IEEE 1588 Precision Time hardware */ - if ((adapter->hw.mac.type == e1000_82574) || - (adapter->hw.mac.type == e1000_ich10lan)) - em_tsync_init(adapter); -#endif - /* Don't reset the phy next time init gets called */ adapter->hw.phy.reset_disable = TRUE; } @@ -1656,17 +1635,13 @@ em_init(void *arg) static int em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { - struct adapter *adapter; - u32 reg_icr; - int rx_npkts; - - adapter = ifp->if_softc; - rx_npkts = 0; + struct adapter *adapter = ifp->if_softc; + u32 reg_icr, rx_done = 0; EM_CORE_LOCK(adapter); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { EM_CORE_UNLOCK(adapter); - return (rx_npkts); + return (rx_done); } if (cmd == POLL_AND_CHECK_STATUS) { @@ -1681,15 +1656,19 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) } EM_CORE_UNLOCK(adapter); - em_rxeof(adapter, count, &rx_npkts); + rx_done = em_rxeof(adapter, count); EM_TX_LOCK(adapter); em_txeof(adapter); - - if (!ADAPTER_RING_EMPTY(adapter)) +#if __FreeBSD_version >= 800000 + if (!drbr_empty(ifp, adapter->br)) + em_mq_start_locked(ifp, NULL); +#else + if (!IFQ_DRV_IS_EMPTY(&ifp->snd)) em_start_locked(ifp); +#endif EM_TX_UNLOCK(adapter); - return (rx_npkts); + return (rx_done); } #endif /* DEVICE_POLLING */ @@ -1713,6 +1692,8 @@ em_intr(void *arg) EM_CORE_LOCK(adapter); reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR); + if (reg_icr & E1000_ICR_RXO) + adapter->rx_overruns++; if ((reg_icr == 0xffffffff) || (reg_icr == 0)|| (adapter->hw.mac.type >= e1000_82571 && (reg_icr & E1000_ICR_INT_ASSERTED) == 0)) @@ -1721,12 +1702,6 @@ em_intr(void *arg) if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) goto out; - EM_TX_LOCK(adapter); - em_txeof(adapter); - em_rxeof(adapter, -1, NULL); - em_txeof(adapter); - EM_TX_UNLOCK(adapter); - if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { callout_stop(&adapter->timer); adapter->hw.mac.get_link_status = 1; @@ -1735,15 +1710,21 @@ em_intr(void *arg) em_tx_purge(adapter); callout_reset(&adapter->timer, hz, em_local_timer, adapter); + goto out; } - if (reg_icr & E1000_ICR_RXO) - adapter->rx_overruns++; + EM_TX_LOCK(adapter); + em_txeof(adapter); + em_rxeof(adapter, -1); + em_txeof(adapter); + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + em_start_locked(ifp); + EM_TX_UNLOCK(adapter); + out: EM_CORE_UNLOCK(adapter); - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !ADAPTER_RING_EMPTY(adapter)) - em_start(ifp); + return; } #else /* EM_FAST_IRQ, then fast interrupt routines only */ @@ -1776,13 +1757,18 @@ em_handle_rxtx(void *context, int pending) if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - if (em_rxeof(adapter, adapter->rx_process_limit, NULL) != 0) + if (em_rxeof(adapter, adapter->rx_process_limit) != 0) taskqueue_enqueue(adapter->tq, &adapter->rxtx_task); EM_TX_LOCK(adapter); em_txeof(adapter); - if (!ADAPTER_RING_EMPTY(adapter)) +#if __FreeBSD_version >= 800000 + if (!drbr_empty(ifp, adapter->br)) + em_mq_start_locked(ifp, NULL); +#else + if (!IFQ_DRV_IS_EMPTY(&ifp->snd)) em_start_locked(ifp); +#endif EM_TX_UNLOCK(adapter); } @@ -1887,7 +1873,7 @@ em_msix_rx(void *arg) ++adapter->rx_irq; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && - (em_rxeof(adapter, adapter->rx_process_limit, NULL) != 0)) + (em_rxeof(adapter, adapter->rx_process_limit) != 0)) taskqueue_enqueue(adapter->tq, &adapter->rx_task); /* Reenable this interrupt */ E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_RX); @@ -1925,7 +1911,7 @@ em_handle_rx(void *context, int pending) struct ifnet *ifp = adapter->ifp; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && - (em_rxeof(adapter, adapter->rx_process_limit, NULL) != 0)) + (em_rxeof(adapter, adapter->rx_process_limit) != 0)) taskqueue_enqueue(adapter->tq, &adapter->rx_task); } @@ -1939,10 +1925,14 @@ em_handle_tx(void *context, int pending) if (ifp->if_drv_flags & IFF_DRV_RUNNING) { if (!EM_TX_TRYLOCK(adapter)) return; - em_txeof(adapter); - if (!ADAPTER_RING_EMPTY(adapter)) +#if __FreeBSD_version >= 800000 + if (!drbr_empty(ifp, adapter->br)) + em_mq_start_locked(ifp, NULL); +#else + if (!IFQ_DRV_IS_EMPTY(&ifp->snd)) em_start_locked(ifp); +#endif EM_TX_UNLOCK(adapter); } } @@ -2201,14 +2191,7 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) tso_desc = TRUE; } else #endif -#ifndef EM_TIMESYNC - /* - ** Timesync needs to check the packet header - ** so call checksum code to do so, but don't - ** penalize the code if not defined. - */ if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) -#endif em_transmit_checksum_setup(adapter, m_head, &txd_upper, &txd_lower); @@ -2365,11 +2348,6 @@ em_xmit(struct adapter *adapter, struct mbuf **m_headp) m_head->m_pkthdr.len); } -#ifdef EM_TIMESYNC - if (ctxd->upper.data & E1000_TXD_EXTCMD_TSTAMP) { - HW_DEBUGOUT( "@@@ Timestamp bit is set in transmit descriptor\n" ); - } -#endif return (0); } @@ -2728,13 +2706,6 @@ em_stop(void *arg) /* Tell the stack that the interface is no longer active */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -#ifdef EM_TIMESYNC - /* Disable IEEE 1588 Time hardware */ - if ((adapter->hw.mac.type == e1000_82574) || - (adapter->hw.mac.type == e1000_ich10lan)) - em_tsync_disable(adapter); -#endif - e1000_reset_hw(&adapter->hw); if (adapter->hw.mac.type >= e1000_82544) E1000_WRITE_REG(&adapter->hw, E1000_WUC, 0); @@ -3121,6 +3092,7 @@ em_hardware_init(struct adapter *adapter) /* Get control from any management/hw control */ if (((adapter->hw.mac.type == e1000_82573) || + (adapter->hw.mac.type == e1000_82583) || (adapter->hw.mac.type == e1000_ich8lan) || (adapter->hw.mac.type == e1000_ich10lan) || (adapter->hw.mac.type == e1000_ich9lan)) && @@ -3169,7 +3141,13 @@ em_hardware_init(struct adapter *adapter) else adapter->hw.fc.pause_time = EM_FC_PAUSE_TIME; adapter->hw.fc.send_xon = TRUE; - adapter->hw.fc.requested_mode = e1000_fc_full; + + /* Set Flow control, use the tunable location if sane */ + if ((em_fc_setting >= 0) || (em_fc_setting < 4)) + adapter->hw.fc.requested_mode = em_fc_setting; + else + adapter->hw.fc.requested_mode = e1000_fc_none; + if (e1000_init_hw(&adapter->hw) < 0) { device_printf(dev, "Hardware Initialization Failed\n"); @@ -3211,10 +3189,11 @@ em_setup_interface(device_t dev, struct adapter *adapter) ifp->if_capabilities = ifp->if_capenable = 0; -#ifdef IFNET_BUF_RING - ifp->if_transmit = em_transmit; +#if __FreeBSD_version >= 800000 + /* Multiqueue tx functions */ + ifp->if_transmit = em_mq_start; ifp->if_qflush = em_qflush; - adapter->br = buf_ring_alloc(2048, M_DEVBUF, M_WAITOK, &adapter->tx_mtx); + adapter->br = buf_ring_alloc(4096, M_DEVBUF, M_WAITOK, &adapter->tx_mtx); #endif if (adapter->hw.mac.type >= e1000_82543) { int version_cap; @@ -3664,6 +3643,9 @@ em_free_transmit_structures(struct adapter *adapter) bus_dma_tag_destroy(adapter->txtag); adapter->txtag = NULL; } +#if __FreeBSD_version >= 800000 + buf_ring_free(adapter->br, M_DEVBUF); +#endif } /********************************************************************* @@ -3672,27 +3654,27 @@ em_free_transmit_structures(struct adapter *adapter) * packet of a particular protocol (TCP/UDP). This routine has been * enhanced to deal with inserted VLAN headers, and IPV6 (not complete) * + * Added back the old method of keeping the current context type + * and not setting if unnecessary, as this is reported to be a + * big performance win. -jfv **********************************************************************/ static void em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, u32 *txd_upper, u32 *txd_lower) { - struct e1000_context_desc *TXD; + struct e1000_context_desc *TXD = NULL; struct em_buffer *tx_buffer; struct ether_vlan_header *eh; struct ip *ip = NULL; struct ip6_hdr *ip6; - struct tcp_hdr *th; int curr_txd, ehdrlen; u32 cmd, hdr_len, ip_hlen; u16 etype; u8 ipproto; + cmd = hdr_len = ipproto = 0; - /* Setup checksum offload context. */ curr_txd = adapter->next_avail_tx_desc; - tx_buffer = &adapter->tx_buffer_area[curr_txd]; - TXD = (struct e1000_context_desc *) &adapter->tx_desc_base[curr_txd]; /* * Determine where frame payload starts. @@ -3724,6 +3706,8 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, * End offset for header checksum calculation. * Offset of place to put the checksum. */ + TXD = (struct e1000_context_desc *) + &adapter->tx_desc_base[curr_txd]; TXD->lower_setup.ip_fields.ipcss = ehdrlen; TXD->lower_setup.ip_fields.ipcse = htole16(ehdrlen + ip_hlen); @@ -3753,11 +3737,6 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, ipproto = ip6->ip6_nxt; break; -#ifdef EM_TIMESYNC - case ETHERTYPE_IEEE1588: - *txd_upper |= E1000_TXD_EXTCMD_TSTAMP; - break; -#endif default: *txd_upper = 0; *txd_lower = 0; @@ -3767,42 +3746,46 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, switch (ipproto) { case IPPROTO_TCP: if (mp->m_pkthdr.csum_flags & CSUM_TCP) { + *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + *txd_upper |= E1000_TXD_POPTS_TXSM << 8; + /* no need for context if already set */ + if (adapter->last_hw_offload == CSUM_TCP) + return; + adapter->last_hw_offload = CSUM_TCP; /* * Start offset for payload checksum calculation. * End offset for payload checksum calculation. * Offset of place to put the checksum. */ - th = (struct tcp_hdr *)(mp->m_data + hdr_len); + TXD = (struct e1000_context_desc *) + &adapter->tx_desc_base[curr_txd]; TXD->upper_setup.tcp_fields.tucss = hdr_len; TXD->upper_setup.tcp_fields.tucse = htole16(0); TXD->upper_setup.tcp_fields.tucso = hdr_len + offsetof(struct tcphdr, th_sum); cmd |= E1000_TXD_CMD_TCP; - *txd_upper |= E1000_TXD_POPTS_TXSM << 8; } break; case IPPROTO_UDP: { -#ifdef EM_TIMESYNC - void *hdr = (caddr_t) ip + ip_hlen; - struct udphdr *uh = (struct udphdr *)hdr; - - if (uh->uh_dport == htons(TSYNC_PORT)) { - *txd_upper |= E1000_TXD_EXTCMD_TSTAMP; - IOCTL_DEBUGOUT("@@@ Sending Event Packet\n"); - } -#endif if (mp->m_pkthdr.csum_flags & CSUM_UDP) { + *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + *txd_upper |= E1000_TXD_POPTS_TXSM << 8; + /* no need for context if already set */ + if (adapter->last_hw_offload == CSUM_UDP) + return; + adapter->last_hw_offload = CSUM_UDP; /* * Start offset for header checksum calculation. * End offset for header checksum calculation. * Offset of place to put the checksum. */ + TXD = (struct e1000_context_desc *) + &adapter->tx_desc_base[curr_txd]; TXD->upper_setup.tcp_fields.tucss = hdr_len; TXD->upper_setup.tcp_fields.tucse = htole16(0); TXD->upper_setup.tcp_fields.tucso = hdr_len + offsetof(struct udphdr, uh_sum); - *txd_upper |= E1000_TXD_POPTS_TXSM << 8; } /* Fall Thru */ } @@ -3810,20 +3793,10 @@ em_transmit_checksum_setup(struct adapter *adapter, struct mbuf *mp, break; } -#ifdef EM_TIMESYNC - /* - ** We might be here just for TIMESYNC - ** which means we don't need the context - ** descriptor. - */ - if (!mp->m_pkthdr.csum_flags & CSUM_OFFLOAD) - return; -#endif - *txd_lower = E1000_TXD_CMD_DEXT | /* Extended descr type */ - E1000_TXD_DTYP_D; /* Data descr */ TXD->tcp_seg_setup.data = htole32(0); TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | cmd); + tx_buffer = &adapter->tx_buffer_area[curr_txd]; tx_buffer->m_head = NULL; tx_buffer->next_eop = -1; @@ -4463,30 +4436,28 @@ em_free_receive_structures(struct adapter *adapter) * * We loop at most count times if count is > 0, or until done if * count < 0. - * + * + * For polling we also now return the number of cleaned packets *********************************************************************/ static int -em_rxeof(struct adapter *adapter, int count, int *rx_npktsp) +em_rxeof(struct adapter *adapter, int count) { struct ifnet *ifp = adapter->ifp;; struct mbuf *mp; u8 status, accept_frame = 0, eop = 0; u16 len, desc_len, prev_len_adj; - int i, rx_npkts; + u32 i, rx_sent = 0; struct e1000_rx_desc *current_desc; EM_RX_LOCK(adapter); i = adapter->next_rx_desc_to_check; - rx_npkts = 0; current_desc = &adapter->rx_desc_base[i]; bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, BUS_DMASYNC_POSTREAD); if (!((current_desc->status) & E1000_RXD_STAT_DD)) { EM_RX_UNLOCK(adapter); - if (rx_npktsp != NULL) - *rx_npktsp = rx_npkts; - return (0); + return (rx_sent); } while ((current_desc->status & E1000_RXD_STAT_DD) && @@ -4628,13 +4599,13 @@ discard: /* Advance our pointers to the next descriptor. */ if (++i == adapter->num_rx_desc) i = 0; + /* Call into the stack */ if (m != NULL) { adapter->next_rx_desc_to_check = i; - /* Unlock for call into stack */ EM_RX_UNLOCK(adapter); (*ifp->if_input)(ifp, m); EM_RX_LOCK(adapter); - rx_npkts++; + rx_sent++; i = adapter->next_rx_desc_to_check; } current_desc = &adapter->rx_desc_base[i]; @@ -4646,12 +4617,7 @@ discard: i = adapter->num_rx_desc - 1; E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i); EM_RX_UNLOCK(adapter); - if (rx_npktsp != NULL) - *rx_npktsp = rx_npkts; - if (!((current_desc->status) & E1000_RXD_STAT_DD)) - return (0); - - return (1); + return (rx_sent); } #ifndef __NO_STRICT_ALIGNMENT @@ -4743,6 +4709,7 @@ em_receive_checksum(struct adapter *adapter, } } +#if __FreeBSD_version >= 700029 /* * This routine is run via an vlan * config EVENT @@ -4751,28 +4718,17 @@ static void em_register_vlan(void *unused, struct ifnet *ifp, u16 vtag) { struct adapter *adapter = ifp->if_softc; - u32 ctrl, rctl, index, vfta; - - ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); - ctrl |= E1000_CTRL_VME; - E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); - - /* Setup for Hardware Filter */ - rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); - rctl |= E1000_RCTL_VFE; - rctl &= ~E1000_RCTL_CFIEN; - E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl); - - /* Make entry in the hardware filter table */ - index = ((vtag >> 5) & 0x7F); - vfta = E1000_READ_REG_ARRAY(&adapter->hw, E1000_VFTA, index); - vfta |= (1 << (vtag & 0x1F)); - E1000_WRITE_REG_ARRAY(&adapter->hw, E1000_VFTA, index, vfta); + u32 index, bit; - /* Update the frame size */ - E1000_WRITE_REG(&adapter->hw, E1000_RLPML, - adapter->max_frame_size + VLAN_TAG_SIZE); + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + return; + index = (vtag >> 5) & 0x7F; + bit = vtag & 0x1F; + em_shadow_vfta[index] |= (1 << bit); + ++adapter->num_vlans; + /* Re-init to load the changes */ + em_init(adapter); } /* @@ -4783,26 +4739,58 @@ static void em_unregister_vlan(void *unused, struct ifnet *ifp, u16 vtag) { struct adapter *adapter = ifp->if_softc; - u32 index, vfta; - - /* Remove entry in the hardware filter table */ - index = ((vtag >> 5) & 0x7F); - vfta = E1000_READ_REG_ARRAY(&adapter->hw, E1000_VFTA, index); - vfta &= ~(1 << (vtag & 0x1F)); - E1000_WRITE_REG_ARRAY(&adapter->hw, E1000_VFTA, index, vfta); - /* Have all vlans unregistered? */ - if (adapter->ifp->if_vlantrunk == NULL) { - u32 rctl; - /* Turn off the filter table */ - rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); - rctl &= ~E1000_RCTL_VFE; - rctl |= E1000_RCTL_CFIEN; - E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl); - /* Reset the frame size */ - E1000_WRITE_REG(&adapter->hw, E1000_RLPML, - adapter->max_frame_size); - } + u32 index, bit; + + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + return; + + index = (vtag >> 5) & 0x7F; + bit = vtag & 0x1F; + em_shadow_vfta[index] &= ~(1 << bit); + --adapter->num_vlans; + /* Re-init to load the changes */ + em_init(adapter); +} + +static void +em_setup_vlan_hw_support(struct adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 reg; + + /* + ** We get here thru init_locked, meaning + ** a soft reset, this has already cleared + ** the VFTA and other state, so if there + ** have been no vlan's registered do nothing. + */ + if (adapter->num_vlans == 0) + return; + + /* + ** A soft reset zero's out the VFTA, so + ** we need to repopulate it now. + */ + for (int i = 0; i < EM_VFTA_SIZE; i++) + if (em_shadow_vfta[i] != 0) + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, + i, em_shadow_vfta[i]); + + reg = E1000_READ_REG(hw, E1000_CTRL); + reg |= E1000_CTRL_VME; + E1000_WRITE_REG(hw, E1000_CTRL, reg); + + /* Enable the Filter Table */ + reg = E1000_READ_REG(hw, E1000_RCTL); + reg &= ~E1000_RCTL_CFIEN; + reg |= E1000_RCTL_VFE; + E1000_WRITE_REG(hw, E1000_RCTL, reg); + + /* Update the frame size */ + E1000_WRITE_REG(&adapter->hw, E1000_RLPML, + adapter->max_frame_size + VLAN_TAG_SIZE); } +#endif static void em_enable_intr(struct adapter *adapter) @@ -5392,100 +5380,4 @@ em_add_rx_process_limit(struct adapter *adapter, const char *name, } #endif -#ifdef EM_TIMESYNC -/* - * Initialize the Time Sync Feature - */ -static int -em_tsync_init(struct adapter *adapter) -{ - device_t dev = adapter->dev; - u32 tx_ctl, rx_ctl; - - - E1000_WRITE_REG(&adapter->hw, E1000_TIMINCA, (1<<24) | - 20833/PICOSECS_PER_TICK); - - adapter->last_stamp = E1000_READ_REG(&adapter->hw, E1000_SYSTIML); - adapter->last_stamp |= (u64)E1000_READ_REG(&adapter->hw, - E1000_SYSTIMH) << 32ULL; - - /* Enable the TX side */ - tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL); - tx_ctl |= 0x10; - E1000_WRITE_REG(&adapter->hw, E1000_TSYNCTXCTL, tx_ctl); - E1000_WRITE_FLUSH(&adapter->hw); - - tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL); - if ((tx_ctl & 0x10) == 0) { - device_printf(dev, "Failed to enable TX timestamping\n"); - return (ENXIO); - } - - /* Enable RX */ - rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL); - rx_ctl |= 0x10; /* Enable the feature */ - rx_ctl |= 0x0a; /* This value turns on Ver 1 and 2 */ - E1000_WRITE_REG(&adapter->hw, E1000_TSYNCRXCTL, rx_ctl); - - /* - * Ethertype Stamping (Ethertype = 0x88F7) - */ - E1000_WRITE_REG(&adapter->hw, E1000_RXMTRL, htonl(0x440088f7)); - - /* - * Source Port Queue Filter Setup: - * this is for UDP port filtering - */ - E1000_WRITE_REG(&adapter->hw, E1000_RXUDP, htons(TSYNC_PORT)); - /* Protocol = UDP, enable Timestamp, and filter on source/protocol */ - - E1000_WRITE_FLUSH(&adapter->hw); - - rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL); - if ((rx_ctl & 0x10) == 0) { - device_printf(dev, "Failed to enable RX timestamping\n"); - return (ENXIO); - } - device_printf(dev, "IEEE 1588 Precision Time Protocol enabled\n"); - - return (0); -} - -/* - * Disable the Time Sync Feature - */ -static void -em_tsync_disable(struct adapter *adapter) -{ - u32 tx_ctl, rx_ctl; - - tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL); - tx_ctl &= ~0x10; - E1000_WRITE_REG(&adapter->hw, E1000_TSYNCTXCTL, tx_ctl); - E1000_WRITE_FLUSH(&adapter->hw); - - /* Invalidate TX Timestamp */ - E1000_READ_REG(&adapter->hw, E1000_TXSTMPH); - - tx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCTXCTL); - if (tx_ctl & 0x10) - HW_DEBUGOUT("Failed to disable TX timestamping\n"); - - rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL); - rx_ctl &= ~0x10; - - E1000_WRITE_REG(&adapter->hw, E1000_TSYNCRXCTL, rx_ctl); - E1000_WRITE_FLUSH(&adapter->hw); - - /* Invalidate RX Timestamp */ - E1000_READ_REG(&adapter->hw, E1000_RXSATRH); - - rx_ctl = E1000_READ_REG(&adapter->hw, E1000_TSYNCRXCTL); - if (rx_ctl & 0x10) - HW_DEBUGOUT("Failed to disable RX timestamping\n"); - - return; -} -#endif /* EM_TIMESYNC */ |