Okay ... attached is a patch to fix this for em(4) (and lay the groundwork to
fix it for other drbr_* consumer as well). I have tested it in VirtualBox,
but don't have real hardware to check for non-ALTQ performance or other
regressions.
Test, comments and review appreciated.
--
Max
Index: sys/dev/e1000/if_em.c
===================================================================
--- sys/dev/e1000/if_em.c (revision 203362)
+++ sys/dev/e1000/if_em.c (working copy)
@@ -943,7 +943,7 @@
{
struct adapter *adapter = ifp->if_softc;
struct mbuf *next;
- int error = E1000_SUCCESS;
+ int ret, error = E1000_SUCCESS;
EM_TX_LOCK_ASSERT(adapter);
/* To allow being called from a tasklet */
@@ -955,28 +955,34 @@
|| (!adapter->link_active)) {
error = drbr_enqueue(ifp, adapter->br, m);
return (error);
- } else if (drbr_empty(ifp, adapter->br) &&
- (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) {
- if ((error = em_xmit(adapter, &m)) != 0) {
- if (m)
- error = drbr_enqueue(ifp, adapter->br, m);
+ }
+ ret = drbr_maybe_enqueue(ifp, adapter->br, m);
+ if (ret == 0) {
+ if (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD) {
+ if ((error = em_xmit(adapter, &m)) != 0) {
+ if (m)
+ error = drbr_enqueue(ifp, adapter->br,
+ m);
+ return (error);
+ } else {
+ /*
+ * We've bypassed the buf ring so we need to
+ * update ifp directly
+ */
+ drbr_stats_update(ifp, m->m_pkthdr.len,
+ m->m_flags);
+ /*
+ ** Send a copy of the frame to the BPF
+ ** listener and set the watchdog on.
+ */
+ ETHER_BPF_MTAP(ifp, m);
+ adapter->watchdog_check = TRUE;
+ }
+ } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
return (error);
- } else {
- /*
- * We've bypassed the buf ring so we need to update
- * ifp directly
- */
- drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags);
- /*
- ** Send a copy of the frame to the BPF
- ** listener and set the watchdog on.
- */
- ETHER_BPF_MTAP(ifp, m);
- adapter->watchdog_check = TRUE;
- }
- } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
- return (error);
-
+ } else if (ret < 0)
+ return (-ret);
+
process:
if (drbr_empty(ifp, adapter->br))
return(error);
@@ -989,7 +995,7 @@
break;
if ((error = em_xmit(adapter, &next)) != 0) {
if (next != NULL)
- error = drbr_enqueue(ifp, adapter->br, next);
+ error = drbr_requeue(ifp, adapter->br, next);
break;
}
drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
Index: sys/net/if_var.h
===================================================================
--- sys/net/if_var.h (revision 203362)
+++ sys/net/if_var.h (working copy)
@@ -597,18 +597,26 @@
return (error);
}
+static __inline int
+drbr_requeue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+#ifdef ALTQ
+ if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ return (0);
+ }
+#endif
+ return drbr_enqueue(ifp, br, m);
+}
+
static __inline void
drbr_flush(struct ifnet *ifp, struct buf_ring *br)
{
struct mbuf *m;
#ifdef ALTQ
- if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
- while (!IFQ_IS_EMPTY(&ifp->if_snd)) {
- IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
- m_freem(m);
- }
- }
+ if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd))
+ IFQ_DRV_PURGE(&ifp->if_snd);
#endif
while ((m = buf_ring_dequeue_sc(br)) != NULL)
m_freem(m);
@@ -642,11 +650,12 @@
{
struct mbuf *m;
#ifdef ALTQ
- /*
- * XXX need to evaluate / requeue
- */
if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m != NULL && func(m, arg) == 0) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ return (NULL);
+ }
return (m);
}
#endif
@@ -668,6 +677,24 @@
}
static __inline int
+drbr_maybe_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+ int error;
+
+#ifdef ALTQ
+ if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+ IFQ_ENQUEUE(&ifp->if_snd, m, error);
+ return error ? -error : 1;
+ }
+#endif
+ if (drbr_empty(ifp, br))
+ return 0;
+
+ error = drbr_enqueue(ifp, br, m);
+ return error ? -error : 1;
+}
+
+static __inline int
drbr_inuse(struct ifnet *ifp, struct buf_ring *br)
{
#ifdef ALTQ
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 7a2dbad..94ad229 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -1020,7 +1020,7 @@ em_mq_start_locked(struct ifnet *ifp, struct mbuf *m)
{
struct adapter *adapter = ifp->if_softc;
struct mbuf *next;
- int error = E1000_SUCCESS;
+ int ret, error = E1000_SUCCESS;
EM_TX_LOCK_ASSERT(adapter);
/* To allow being called from a tasklet */
@@ -1032,28 +1032,34 @@ em_mq_start_locked(struct ifnet *ifp, struct mbuf *m)
|| (!adapter->link_active)) {
error = drbr_enqueue(ifp, adapter->br, m);
return (error);
- } else if (drbr_empty(ifp, adapter->br) &&
- (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) {
- if ((error = em_xmit(adapter, &m)) != 0) {
- if (m != NULL)
- error = drbr_enqueue(ifp, adapter->br, m);
- return (error);
- } else {
- /*
- * We've bypassed the buf ring so we need to update
- * ifp directly
- */
- drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags);
- /*
- ** Send a copy of the frame to the BPF
- ** listener and set the watchdog on.
- */
- ETHER_BPF_MTAP(ifp, m);
- adapter->watchdog_timer = EM_TX_TIMEOUT;
- }
- } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
- return (error);
-
+ }
+ ret = drbr_maybe_enqueue(ifp, adapter->br, m);
+ if (ret == 0) {
+ if (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD) {
+ if ((error = em_xmit(adapter, &m)) != 0) {
+ if (m)
+ error = drbr_enqueue(ifp, adapter->br,
+ m);
+ return (error);
+ } else {
+ /*
+ * We've bypassed the buf ring so we need to
+ * update ifp directly
+ */
+ drbr_stats_update(ifp, m->m_pkthdr.len,
+ m->m_flags);
+ /*
+ ** Send a copy of the frame to the BPF
+ ** listener and set the watchdog on.
+ */
+ ETHER_BPF_MTAP(ifp, m);
+ adapter->watchdog_timer = EM_TX_TIMEOUT;
+ }
+ } else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
+ return (error);
+ } else if (ret < 0)
+ return (-ret);
+
process:
if (drbr_empty(ifp, adapter->br))
return(error);
@@ -1066,7 +1072,7 @@ process:
break;
if ((error = em_xmit(adapter, &next)) != 0) {
if (next != NULL)
- error = drbr_enqueue(ifp, adapter->br, next);
+ error = drbr_requeue(ifp, adapter->br, next);
break;
}
drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index eac7dbf..1d59402 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -595,18 +595,26 @@ drbr_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
return (error);
}
+static __inline int
+drbr_requeue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+#ifdef ALTQ
+ if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ return (0);
+ }
+#endif
+ return drbr_enqueue(ifp, br, m);
+}
+
static __inline void
drbr_flush(struct ifnet *ifp, struct buf_ring *br)
{
struct mbuf *m;
#ifdef ALTQ
- if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
- while (!IFQ_IS_EMPTY(&ifp->if_snd)) {
- IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
- m_freem(m);
- }
- }
+ if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd))
+ IFQ_DRV_PURGE(&ifp->if_snd);
#endif
while ((m = buf_ring_dequeue_sc(br)) != NULL)
m_freem(m);
@@ -640,11 +648,12 @@ drbr_dequeue_cond(struct ifnet *ifp, struct buf_ring *br,
{
struct mbuf *m;
#ifdef ALTQ
- /*
- * XXX need to evaluate / requeue
- */
if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m != NULL && func(m, arg) == 0) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ return (NULL);
+ }
return (m);
}
#endif
@@ -666,6 +675,24 @@ drbr_empty(struct ifnet *ifp, struct buf_ring *br)
}
static __inline int
+drbr_maybe_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+ int error;
+
+#ifdef ALTQ
+ if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+ IFQ_ENQUEUE(&ifp->if_snd, m, error);
+ return error ? -error : 1;
+ }
+#endif
+ if (drbr_empty(ifp, br))
+ return 0;
+
+ error = drbr_enqueue(ifp, br, m);
+ return error ? -error : 1;
+}
+
+static __inline int
drbr_inuse(struct ifnet *ifp, struct buf_ring *br)
{
#ifdef ALTQ
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-stable
To unsubscribe, send any mail to "[email protected]"