Date: Wed, 29 Jun 2011 16:16:59 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r223675 - stable/8/sys/dev/e1000 Message-ID: <201106291616.p5TGGxOn004729@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jhb Date: Wed Jun 29 16:16:59 2011 New Revision: 223675 URL: http://svn.freebsd.org/changeset/base/223675 Log: MFC 223198: - Use a dedicated task to handle deferred transmits from the if_transmit method instead of reusing the existing per-queue interrupt task. Reusing the per-queue interrupt task could result in both an interrupt thread and the taskqueue thread trying to handle received packets on a single queue resulting in out-of-order packet processing. - Don't define igb_start() at all on 8.0 and where if_transmit is used. Replace last remaining call to igb_start() with a loop to kick off transmit on each queue instead. - Call ether_ifdetach() earlier in igb_detach(). - Drain tasks and free taskqueues during igb_detach(). Modified: stable/8/sys/dev/e1000/if_igb.c stable/8/sys/dev/e1000/if_igb.h Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) Modified: stable/8/sys/dev/e1000/if_igb.c ============================================================================== --- stable/8/sys/dev/e1000/if_igb.c Wed Jun 29 15:58:26 2011 (r223674) +++ stable/8/sys/dev/e1000/if_igb.c Wed Jun 29 16:16:59 2011 (r223675) @@ -170,13 +170,15 @@ static int igb_detach(device_t); static int igb_shutdown(device_t); static int igb_suspend(device_t); static int igb_resume(device_t); -static void igb_start(struct ifnet *); -static void igb_start_locked(struct tx_ring *, struct ifnet *ifp); #if __FreeBSD_version >= 800000 static int igb_mq_start(struct ifnet *, struct mbuf *); static int igb_mq_start_locked(struct ifnet *, struct tx_ring *, struct mbuf *); static void igb_qflush(struct ifnet *); +static void igb_deferred_mq_start(void *, int); +#else +static void igb_start(struct ifnet *); +static void igb_start_locked(struct tx_ring *, struct ifnet *ifp); #endif static int igb_ioctl(struct ifnet *, u_long, caddr_t); static void igb_init(void *); @@ -693,6 +695,8 @@ igb_detach(device_t dev) return (EBUSY); } + ether_ifdetach(adapter->ifp); + if (adapter->led_dev != NULL) led_destroy(adapter->led_dev); @@ -724,8 +728,6 @@ igb_detach(device_t dev) if (adapter->vlan_detach != NULL) EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); - ether_ifdetach(adapter->ifp); - callout_drain(&adapter->timer); igb_free_pci_resources(adapter); @@ -784,14 +786,27 @@ igb_resume(device_t dev) { struct adapter *adapter = device_get_softc(dev); struct ifnet *ifp = adapter->ifp; +#if __FreeBSD_version >= 800000 + struct tx_ring *txr = adapter->tx_rings; +#endif IGB_CORE_LOCK(adapter); igb_init_locked(adapter); igb_init_manageability(adapter); if ((ifp->if_flags & IFF_UP) && - (ifp->if_drv_flags & IFF_DRV_RUNNING)) + (ifp->if_drv_flags & IFF_DRV_RUNNING)) { +#if __FreeBSD_version < 800000 igb_start(ifp); +#else + for (int i = 0; i < adapter->num_queues; i++, txr++) { + IGB_TX_LOCK(txr); + if (!drbr_empty(ifp, txr->br)) + igb_mq_start_locked(ifp, txr, NULL); + IGB_TX_UNLOCK(txr); + } +#endif + } IGB_CORE_UNLOCK(adapter); @@ -799,6 +814,7 @@ igb_resume(device_t dev) } +#if __FreeBSD_version < 800000 /********************************************************************* * Transmit entry point * @@ -875,7 +891,7 @@ igb_start(struct ifnet *ifp) return; } -#if __FreeBSD_version >= 800000 +#else /* __FreeBSD_version >= 800000 */ /* ** Multiqueue Transmit driver ** @@ -900,7 +916,7 @@ igb_mq_start(struct ifnet *ifp, struct m IGB_TX_UNLOCK(txr); } else { err = drbr_enqueue(ifp, txr->br, m); - taskqueue_enqueue(que->tq, &que->que_task); + taskqueue_enqueue(que->tq, &txr->txq_task); } return (err); @@ -961,6 +977,22 @@ igb_mq_start_locked(struct ifnet *ifp, s } /* + * Called from a taskqueue to drain queued transmit packets. + */ +static void +igb_deferred_mq_start(void *arg, int pending) +{ + struct tx_ring *txr = arg; + struct adapter *adapter = txr->adapter; + struct ifnet *ifp = adapter->ifp; + + IGB_TX_LOCK(txr); + if (!drbr_empty(ifp, txr->br)) + igb_mq_start_locked(ifp, txr, NULL); + IGB_TX_UNLOCK(txr); +} + +/* ** Flush all ring buffers */ static void @@ -978,7 +1010,7 @@ igb_qflush(struct ifnet *ifp) } if_qflush(ifp); } -#endif /* __FreeBSD_version >= 800000 */ +#endif /* __FreeBSD_version < 800000 */ /********************************************************************* * Ioctl entry point @@ -2180,6 +2212,7 @@ igb_allocate_legacy(struct adapter *adap { device_t dev = adapter->dev; struct igb_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; int error, rid = 0; /* Turn off all interrupts */ @@ -2198,6 +2231,10 @@ igb_allocate_legacy(struct adapter *adap return (ENXIO); } +#if __FreeBSD_version >= 800000 + TASK_INIT(&txr->txq_task, 0, igb_deferred_mq_start, txr); +#endif + /* * Try allocating a fast interrupt and the associated deferred * processing contexts. @@ -2268,9 +2305,13 @@ igb_allocate_msix(struct adapter *adapte */ if (adapter->num_queues > 1) bus_bind_intr(dev, que->res, i); +#if __FreeBSD_version >= 800000 + TASK_INIT(&que->txr->txq_task, 0, igb_deferred_mq_start, + que->txr); +#endif /* Make tasklet for deferred handling */ TASK_INIT(&que->que_task, 0, igb_handle_que, que); - que->tq = taskqueue_create_fast("igb_que", M_NOWAIT, + que->tq = taskqueue_create("igb_que", M_NOWAIT, taskqueue_thread_enqueue, &que->tq); taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", device_get_nameunit(adapter->dev)); @@ -2477,13 +2518,24 @@ igb_free_pci_resources(struct adapter *a else (adapter->msix != 0) ? (rid = 1):(rid = 0); + que = adapter->queues; if (adapter->tag != NULL) { + taskqueue_drain(que->tq, &adapter->link_task); bus_teardown_intr(dev, adapter->res, adapter->tag); adapter->tag = NULL; } if (adapter->res != NULL) bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); + for (int i = 0; i < adapter->num_queues; i++, que++) { + if (que->tq != NULL) { +#if __FreeBSD_version >= 800000 + taskqueue_drain(que->tq, &que->txr->txq_task); +#endif + taskqueue_drain(que->tq, &que->que_task); + taskqueue_free(que->tq); + } + } mem: if (adapter->msix) pci_release_msi(dev); @@ -2744,10 +2796,11 @@ igb_setup_interface(device_t dev, struct ifp->if_softc = adapter; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = igb_ioctl; - ifp->if_start = igb_start; #if __FreeBSD_version >= 800000 ifp->if_transmit = igb_mq_start; ifp->if_qflush = igb_qflush; +#else + ifp->if_start = igb_start; #endif IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 1); ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 1; Modified: stable/8/sys/dev/e1000/if_igb.h ============================================================================== --- stable/8/sys/dev/e1000/if_igb.h Wed Jun 29 15:58:26 2011 (r223674) +++ stable/8/sys/dev/e1000/if_igb.h Wed Jun 29 16:16:59 2011 (r223675) @@ -297,6 +297,7 @@ struct tx_ring { struct buf_ring *br; #endif bus_dma_tag_t txtag; + struct task txq_task; u32 bytes; u32 packets;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106291616.p5TGGxOn004729>