mirror of
https://github.com/opnsense/src.git
synced 2026-06-08 16:22:46 -04:00
- 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(). Reviewed by: jfv MFC after: 1 week
This commit is contained in:
parent
beee0062b5
commit
1c2ed38455
2 changed files with 64 additions and 10 deletions
|
|
@ -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 mbuf *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);
|
||||
|
|
@ -960,6 +976,22 @@ igb_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m)
|
|||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -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 *adapter)
|
|||
{
|
||||
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 *adapter)
|
|||
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 *adapter)
|
|||
*/
|
||||
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 *adapter)
|
|||
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 adapter *adapter)
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue