diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index fd602bf..60b9099 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -279,7 +279,7 @@ static void em_tso_setup(struct tx_ring *, struct mbuf *, int, struct ip *, static void em_set_promisc(struct adapter *); static void em_disable_promisc(struct adapter *); static void em_set_multi(struct adapter *); -static void em_update_link_status(struct adapter *); +static void em_update_link_status(struct adapter *, bool); static void em_refresh_mbufs(struct rx_ring *, int); static void em_register_vlan(void *, if_t, u16); static void em_unregister_vlan(void *, if_t, u16); @@ -306,6 +306,7 @@ static void em_enable_wakeup(device_t); static int em_enable_phy_wakeup(struct adapter *); static void em_led_func(void *, int); static void em_disable_aspm(struct adapter *); +static void em_reinit_task(void *, int); static int em_irq_fast(void *); @@ -524,6 +525,7 @@ em_attach(device_t dev) adapter->dev = adapter->osdep.dev = dev; hw = &adapter->hw; EM_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); + TASK_INIT(&adapter->reinit_task, 0, em_reinit_task, adapter); /* SYSCTL stuff */ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), @@ -778,7 +780,7 @@ em_attach(device_t dev) em_update_stats_counters(adapter); hw->mac.get_link_status = 1; - em_update_link_status(adapter); + em_update_link_status(adapter, false); /* Register for VLAN events */ adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, @@ -1382,7 +1384,7 @@ em_init_locked(struct adapter *adapter) /* Initialize the hardware */ em_reset(adapter); - em_update_link_status(adapter); + em_update_link_status(adapter, false); /* Setup VLAN support, basic and offload if available */ E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN); @@ -1392,7 +1394,7 @@ em_init_locked(struct adapter *adapter) if (if_getcapenable(ifp) & IFCAP_TXCSUM) if_sethwassistbits(ifp, CSUM_TCP | CSUM_UDP, 0); - if (if_getcapenable(ifp) & IFCAP_TSO4) + if ((if_getcapenable(ifp) & IFCAP_TSO4) && EM_CAN_TSO(adapter)) if_sethwassistbits(ifp, CSUM_TSO, 0); /* Configure for OS presence */ @@ -1509,7 +1511,7 @@ em_poll(if_t ifp, enum poll_cmd cmd, int count) if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { callout_stop(&adapter->timer); adapter->hw.mac.get_link_status = 1; - em_update_link_status(adapter); + em_update_link_status(adapter, true); callout_reset(&adapter->timer, hz, em_local_timer, adapter); } @@ -1752,7 +1754,7 @@ em_handle_link(void *context, int pending) EM_CORE_LOCK(adapter); callout_stop(&adapter->timer); - em_update_link_status(adapter); + em_update_link_status(adapter, true); callout_reset(&adapter->timer, hz, em_local_timer, adapter); E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_LINK | E1000_IMS_LSC); @@ -1790,7 +1792,7 @@ em_media_status(if_t ifp, struct ifmediareq *ifmr) INIT_DEBUGOUT("em_media_status: begin"); EM_CORE_LOCK(adapter); - em_update_link_status(adapter); + em_update_link_status(adapter, true); ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; @@ -2312,7 +2314,7 @@ em_local_timer(void *arg) EM_CORE_LOCK_ASSERT(adapter); - em_update_link_status(adapter); + em_update_link_status(adapter, true); em_update_stats_counters(adapter); /* Reset LAA into RAR[0] on 82571 */ @@ -2361,7 +2363,7 @@ hung: static void -em_update_link_status(struct adapter *adapter) +em_update_link_status(struct adapter *adapter, bool reset_tso) { struct e1000_hw *hw = &adapter->hw; if_t ifp = adapter->ifp; @@ -2401,16 +2403,20 @@ em_update_link_status(struct adapter *adapter) if (link_check && (adapter->link_active == 0)) { e1000_get_speed_and_duplex(hw, &adapter->link_speed, &adapter->link_duplex); - /* - ** There have proven to be problems with TSO when not - ** at full gigabit speed, so disable the assist automatically - ** when at lower speeds. -jfv - */ - if (adapter->link_speed != SPEED_1000) { - if_sethwassistbits(ifp, 0, CSUM_TSO); - if_setcapenablebit(ifp, 0, IFCAP_TSO4); - if_setcapabilitiesbit(ifp, 0, IFCAP_TSO4); - + if (!EM_CAN_TSO(adapter)) { + if (if_gethwassist(ifp) & CSUM_TSO) { + /* Disable TSO. */ + if_sethwassistbits(ifp, 0, CSUM_TSO); + if (reset_tso && + (if_getdrvflags(ifp) & IFF_DRV_RUNNING)) { + /* Drop all pending TSO packets. */ + taskqueue_enqueue(taskqueue_fast, + &adapter->reinit_task); + } + } + } else if (if_getcapenable(ifp) & IFCAP_TSO4) { + /* (Re-)enable TSO. */ + if_sethwassistbits(ifp, CSUM_TSO, 0); } /* Check if we must disable SPEED_MODE bit on PCI-E */ @@ -2544,6 +2550,20 @@ em_allocate_pci_resources(struct adapter *adapter) return (0); } +static void +em_reinit_task(void *arg, int pending __unused) +{ + struct adapter *adapter = arg; + if_t ifp = adapter->ifp; + + EM_CORE_LOCK(adapter); + if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { + em_stop(adapter); + em_init_locked(adapter); + } + EM_CORE_UNLOCK(adapter); +} + /********************************************************************* * * Setup the Legacy or MSI Interrupt handler diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h index 2a2bf2c..cb50732 100644 --- a/sys/dev/e1000/if_em.h +++ b/sys/dev/e1000/if_em.h @@ -420,6 +420,7 @@ struct adapter { /* Task for FAST handling */ struct task link_task; struct task que_task; + struct task reinit_task; struct taskqueue *tq; /* private task queue */ eventhandler_tag vlan_attach; @@ -486,6 +487,13 @@ struct adapter { struct e1000_hw_stats stats; }; +/* +** There have proven to be problems with TSO when not +** at full gigabit speed, so disable the assist automatically +** when at lower speeds. -jfv +*/ +#define EM_CAN_TSO(adapter) ((adapter)->link_speed == 1000) + /******************************************************************************** * vendor_info_array *