Module Name: src
Committed By: jdolecek
Date: Sun Apr 26 12:58:28 UTC 2020
Modified Files:
src/sys/arch/xen/xen: if_xennet_xenbus.c
Log Message:
support feature-sg
practical offshot of this xennet(4) now supports jumbo frames, it is
also necessary for eventual TSO support
always defrag short Tx packets before passing to backend - even
with feature-sg it's way faster to process the packet if it's
passed as single fragment
To generate a diff of this commit:
cvs rdiff -u -r1.118 -r1.119 src/sys/arch/xen/xen/if_xennet_xenbus.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/xen/xen/if_xennet_xenbus.c
diff -u src/sys/arch/xen/xen/if_xennet_xenbus.c:1.118 src/sys/arch/xen/xen/if_xennet_xenbus.c:1.119
--- src/sys/arch/xen/xen/if_xennet_xenbus.c:1.118 Sat Apr 25 15:26:18 2020
+++ src/sys/arch/xen/xen/if_xennet_xenbus.c Sun Apr 26 12:58:28 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: if_xennet_xenbus.c,v 1.118 2020/04/25 15:26:18 bouyer Exp $ */
+/* $NetBSD: if_xennet_xenbus.c,v 1.119 2020/04/26 12:58:28 jdolecek Exp $ */
/*
* Copyright (c) 2006 Manuel Bouyer.
@@ -81,7 +81,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.118 2020/04/25 15:26:18 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.119 2020/04/26 12:58:28 jdolecek Exp $");
#include "opt_xen.h"
#include "opt_nfs_boot.h"
@@ -186,19 +186,28 @@ struct xennet_xenbus_softc {
struct xennet_rxreq sc_rxreqs[NET_RX_RING_SIZE];
SLIST_HEAD(,xennet_txreq) sc_txreq_head; /* list of free TX requests */
SLIST_HEAD(,xennet_rxreq) sc_rxreq_head; /* list of free RX requests */
- int sc_free_rxreql; /* number of free receive request struct */
+ int sc_free_txreql; /* number of free transmit request structs */
+ int sc_free_rxreql; /* number of free receive request structs */
int sc_backend_status; /* our status with backend */
#define BEST_CLOSED 0
#define BEST_DISCONNECTED 1
#define BEST_CONNECTED 2
#define BEST_SUSPENDED 3
- bool sc_ipv6_csum; /* whether backend support IPv6 csum offload */
+ int sc_features;
+#define FEATURE_IPV6CSUM 0x01 /* IPv6 checksum offload */
+#define FEATURE_SG 0x02 /* scatter-gatter */
+#define FEATURE_BITS "\20\1IPV6-CSUM\2SG"
krndsource_t sc_rnd_source;
+ struct evcnt sc_cnt_tx_defrag;
+ struct evcnt sc_cnt_tx_queue_full;
+ struct evcnt sc_cnt_tx_drop;
+ struct evcnt sc_cnt_tx_frag;
+ struct evcnt sc_cnt_rx_frag;
};
static pool_cache_t if_xennetrxbuf_cache;
-static int if_xennetrxbuf_cache_inited=0;
+static int if_xennetrxbuf_cache_inited = 0;
static int xennet_xenbus_match(device_t, cfdata_t, void *);
static void xennet_xenbus_attach(device_t, device_t, void *);
@@ -256,6 +265,9 @@ xennet_xenbus_attach(device_t parent, de
unsigned long uval;
extern int ifqmaxlen; /* XXX */
char mac[32];
+ char buf[64];
+ bus_size_t maxsz;
+ int nsegs;
aprint_normal(": Xen Virtual Network Interface\n");
sc->sc_dev = self;
@@ -263,6 +275,18 @@ xennet_xenbus_attach(device_t parent, de
sc->sc_xbusd = xa->xa_xbusd;
sc->sc_xbusd->xbusd_otherend_changed = xennet_backend_changed;
+ /* read feature support flags */
+ err = xenbus_read_ul(NULL, sc->sc_xbusd->xbusd_otherend,
+ "feature-ipv6-csum-offload", &uval, 10);
+ if (!err && uval == 1)
+ sc->sc_features |= FEATURE_IPV6CSUM;
+ err = xenbus_read_ul(NULL, sc->sc_xbusd->xbusd_otherend,
+ "feature-sg", &uval, 10);
+ if (!err && uval == 1)
+ sc->sc_features |= FEATURE_SG;
+ snprintb(buf, sizeof(buf), FEATURE_BITS, sc->sc_features);
+ aprint_normal_dev(sc->sc_dev, "backend features %s\n", buf);
+
/* xenbus ensure 2 devices can't be probed at the same time */
if (if_xennetrxbuf_cache_inited == 0) {
if_xennetrxbuf_cache = pool_cache_init(PAGE_SIZE, 0, 0, 0,
@@ -271,13 +295,26 @@ xennet_xenbus_attach(device_t parent, de
}
/* initialize free RX and RX request lists */
+ if (sc->sc_features & FEATURE_SG) {
+ maxsz = ETHER_MAX_LEN_JUMBO;
+ /*
+ * Linux netback drops the packet if the request has more
+ * segments than XEN_NETIF_NR_SLOTS_MIN (== 18). With 2KB
+ * MCLBYTES this means maximum packet size 36KB, in reality
+ * less due to mbuf chain fragmentation.
+ */
+ nsegs = XEN_NETIF_NR_SLOTS_MIN;
+ } else {
+ maxsz = PAGE_SIZE;
+ nsegs = 1;
+ }
mutex_init(&sc->sc_tx_lock, MUTEX_DEFAULT, IPL_NET);
SLIST_INIT(&sc->sc_txreq_head);
for (i = 0; i < NET_TX_RING_SIZE; i++) {
struct xennet_txreq *txreq = &sc->sc_txreqs[i];
txreq->txreq_id = i;
- if (bus_dmamap_create(sc->sc_xbusd->xbusd_dmat, PAGE_SIZE, 1,
+ if (bus_dmamap_create(sc->sc_xbusd->xbusd_dmat, maxsz, nsegs,
PAGE_SIZE, PAGE_SIZE, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
&txreq->txreq_dmamap) != 0)
break;
@@ -285,13 +322,14 @@ xennet_xenbus_attach(device_t parent, de
SLIST_INSERT_HEAD(&sc->sc_txreq_head, &sc->sc_txreqs[i],
txreq_next);
}
+ sc->sc_free_txreql = i;
mutex_init(&sc->sc_rx_lock, MUTEX_DEFAULT, IPL_NET);
SLIST_INIT(&sc->sc_rxreq_head);
for (i = 0; i < NET_RX_RING_SIZE; i++) {
struct xennet_rxreq *rxreq = &sc->sc_rxreqs[i];
rxreq->rxreq_id = i;
- if (bus_dmamap_create(sc->sc_xbusd->xbusd_dmat, PAGE_SIZE, 1,
+ if (bus_dmamap_create(sc->sc_xbusd->xbusd_dmat, maxsz, nsegs,
PAGE_SIZE, PAGE_SIZE, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
&rxreq->rxreq_dmamap) != 0)
break;
@@ -323,14 +361,11 @@ xennet_xenbus_attach(device_t parent, de
aprint_normal_dev(self, "MAC address %s\n",
ether_sprintf(sc->sc_enaddr));
- /* read ipv6 csum support flag */
- err = xenbus_read_ul(NULL, sc->sc_xbusd->xbusd_otherend,
- "feature-ipv6-csum-offload", &uval, 10);
- sc->sc_ipv6_csum = (!err && uval == 1);
-
/* Initialize ifnet structure and attach interface */
strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
+ if (sc->sc_features & FEATURE_SG)
+ sc->sc_ethercom.ec_capabilities |= ETHERCAP_JUMBO_MTU;
ifp->if_softc = sc;
ifp->if_start = xennet_start;
ifp->if_ioctl = xennet_ioctl;
@@ -349,7 +384,7 @@ xennet_xenbus_attach(device_t parent, de
M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_IPv4 \
| M_CSUM_TCPv6 | M_CSUM_UDPv6 \
)
- if (sc->sc_ipv6_csum) {
+ if (sc->sc_features & FEATURE_IPV6CSUM) {
/*
* If backend supports IPv6 csum offloading, we can skip
* IPv6 csum for Tx packets. Rx packet validation can
@@ -359,6 +394,7 @@ xennet_xenbus_attach(device_t parent, de
IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_TCPv6_Tx;
}
+ IFQ_SET_MAXLEN(&ifp->if_snd, uimax(2 * NET_TX_RING_SIZE, IFQ_MAXLEN));
IFQ_SET_READY(&ifp->if_snd);
if_attach(ifp);
if_deferred_start_init(ifp, NULL);
@@ -387,6 +423,17 @@ xennet_xenbus_attach(device_t parent, de
rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dev),
RND_TYPE_NET, RND_FLAG_DEFAULT);
+ evcnt_attach_dynamic(&sc->sc_cnt_tx_defrag, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Tx packet defrag");
+ evcnt_attach_dynamic(&sc->sc_cnt_tx_frag, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Tx multi-segment packet");
+ evcnt_attach_dynamic(&sc->sc_cnt_tx_drop, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Tx packet dropped");
+ evcnt_attach_dynamic(&sc->sc_cnt_tx_queue_full, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Tx queue full");
+ evcnt_attach_dynamic(&sc->sc_cnt_rx_frag, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Rx multi-segment packet");
+
if (!pmf_device_register(self, xennet_xenbus_suspend,
xennet_xenbus_resume))
aprint_error_dev(self, "couldn't establish power handler\n");
@@ -441,6 +488,12 @@ xennet_xenbus_detach(device_t self, int
ether_ifdetach(ifp);
if_detach(ifp);
+ evcnt_detach(&sc->sc_cnt_tx_defrag);
+ evcnt_detach(&sc->sc_cnt_tx_frag);
+ evcnt_detach(&sc->sc_cnt_tx_drop);
+ evcnt_detach(&sc->sc_cnt_tx_queue_full);
+ evcnt_detach(&sc->sc_cnt_rx_frag);
+
/* Unhook the entropy source. */
rnd_detach_source(&sc->sc_rnd_source);
@@ -583,6 +636,12 @@ again:
goto abort_transaction;
}
error = xenbus_printf(xbt, sc->sc_xbusd->xbusd_path,
+ "feature-sg", "%u", 1);
+ if (error) {
+ errmsg = "writing feature-sg";
+ goto abort_transaction;
+ }
+ error = xenbus_printf(xbt, sc->sc_xbusd->xbusd_path,
"event-channel", "%u", sc->sc_evtchn);
if (error) {
errmsg = "writing event channel";
@@ -690,6 +749,7 @@ xennet_alloc_rx_buffer(struct xennet_xen
{
RING_IDX req_prod = sc->sc_rx_ring.req_prod_pvt;
RING_IDX i;
+ netif_rx_request_t *rxreq;
struct xennet_rxreq *req;
int otherend_id, notify;
struct mbuf *m;
@@ -751,11 +811,9 @@ xennet_alloc_rx_buffer(struct xennet_xen
req->rxreq_m = m;
- RING_GET_REQUEST(&sc->sc_rx_ring, req_prod + i)->id =
- req->rxreq_id;
-
- RING_GET_REQUEST(&sc->sc_rx_ring, req_prod + i)->gref =
- req->rxreq_gntref;
+ rxreq = RING_GET_REQUEST(&sc->sc_rx_ring, req_prod + i);
+ rxreq->id = req->rxreq_id;
+ rxreq->gref = req->rxreq_gntref;
SLIST_REMOVE_HEAD(&sc->sc_rxreq_head, rxreq_next);
sc->sc_free_rxreql--;
@@ -864,19 +922,25 @@ again:
KASSERT(req->txreq_id ==
RING_GET_RESPONSE(&sc->sc_tx_ring, i)->id);
KASSERT(xengnt_status(req->txreq_gntref) == 0);
- KASSERT(req->txreq_m != NULL);
-
- if (__predict_false(
- RING_GET_RESPONSE(&sc->sc_tx_ring, i)->status !=
- NETIF_RSP_OKAY))
- if_statinc(ifp, if_oerrors);
- else
- if_statinc(ifp, if_opackets);
xengnt_revoke_access(req->txreq_gntref);
- bus_dmamap_unload(sc->sc_xbusd->xbusd_dmat, req->txreq_dmamap);
- m_freem(req->txreq_m);
- req->txreq_m = NULL;
+ req->txreq_gntref = GRANT_INVALID_REF;
+
+ /* Cleanup/statistics if this is the master req of a chain */
+ if (req->txreq_m) {
+ if (__predict_false(
+ RING_GET_RESPONSE(&sc->sc_tx_ring, i)->status !=
+ NETIF_RSP_OKAY))
+ if_statinc(ifp, if_oerrors);
+ else
+ if_statinc(ifp, if_opackets);
+ bus_dmamap_unload(sc->sc_xbusd->xbusd_dmat,
+ req->txreq_dmamap);
+ m_freem(req->txreq_m);
+ req->txreq_m = NULL;
+ }
+
SLIST_INSERT_HEAD(&sc->sc_txreq_head, req, txreq_next);
+ sc->sc_free_txreql++;
}
sc->sc_tx_ring.rsp_cons = resp_prod;
@@ -901,7 +965,8 @@ xennet_handler(void *arg)
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
RING_IDX resp_prod, i;
struct xennet_rxreq *req;
- struct mbuf *m;
+ struct mbuf *m, *m0;
+ int rxflags, m0_rxflags;
int more_to_do;
if (sc->sc_backend_status != BEST_CONNECTED)
@@ -920,6 +985,7 @@ again:
resp_prod = sc->sc_rx_ring.sring->rsp_prod;
xen_rmb(); /* ensure we see replies up to resp_prod */
+ m0 = NULL;
for (i = sc->sc_rx_ring.rsp_cons; i != resp_prod; i++) {
netif_rx_response_t *rx = RING_GET_RESPONSE(&sc->sc_rx_ring, i);
req = &sc->sc_rxreqs[rx->id];
@@ -936,19 +1002,54 @@ again:
bus_dmamap_sync(sc->sc_xbusd->xbusd_dmat, req->rxreq_dmamap, 0,
m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
- MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner);
- m_set_rcvif(m, ifp);
+ if (m0 == NULL) {
+ MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner);
+ m_set_rcvif(m, ifp);
+ }
+
+ rxflags = rx->flags;
+
+ if (m0 || rxflags & NETRXF_more_data) {
+ /*
+ * On Rx, every fragment (even first one) contain
+ * just length of data in the fragment.
+ */
+ if (m0 == NULL) {
+ m0 = m;
+ m0_rxflags = rxflags;
+ } else {
+ m_cat(m0, m);
+ m0->m_pkthdr.len += m->m_len;
+ }
- if (rx->flags & NETRXF_csum_blank)
+ if (rxflags & NETRXF_more_data) {
+ /* Still more fragments to receive */
+ xennet_rx_free_req(sc, req);
+ continue;
+ }
+
+ sc->sc_cnt_rx_frag.ev_count++;
+ m = m0;
+ m0 = NULL;
+ rxflags = m0_rxflags;
+ }
+
+ if (rxflags & NETRXF_csum_blank)
xennet_checksum_fill(ifp, m);
- else if (rx->flags & NETRXF_data_validated)
+ else if (rxflags & NETRXF_data_validated)
m->m_pkthdr.csum_flags = XN_M_CSUM_SUPPORTED;
- /* free req may overwrite *rx, better doing it late */
+
+ /* We'are done with req */
xennet_rx_free_req(sc, req);
/* Pass the packet up. */
if_percpuq_enqueue(ifp->if_percpuq, m);
}
+ /* If the queued Rx fragments did not finish the packet, drop it */
+ if (m0) {
+ if_statinc(ifp, if_iqdrops);
+ m_freem(m0);
+ }
xen_rmb();
sc->sc_rx_ring.rsp_cons = i;
RING_FINAL_CHECK_FOR_RESPONSES(&sc->sc_rx_ring, more_to_do);
@@ -962,6 +1063,83 @@ again:
return 1;
}
+static bool
+xennet_submit_tx_request(struct xennet_xenbus_softc *sc, struct mbuf *m,
+ struct xennet_txreq *req0, int *req_prod)
+{
+ struct xennet_txreq *req = req0;
+ netif_tx_request_t *txreq;
+ int i, prod = *req_prod;
+ const bool multiseg = (req0->txreq_dmamap->dm_nsegs > 1);
+ const int lastseg = req0->txreq_dmamap->dm_nsegs - 1;
+ bus_dma_segment_t *ds;
+ SLIST_HEAD(, xennet_txreq) txchain;
+
+ KASSERT(mutex_owned(&sc->sc_tx_lock));
+ KASSERT(req0->txreq_dmamap->dm_nsegs > 0);
+
+ bus_dmamap_sync(sc->sc_xbusd->xbusd_dmat, req->txreq_dmamap, 0,
+ m->m_pkthdr.len, BUS_DMASYNC_POSTWRITE);
+ MCLAIM(m, &sc->sc_ethercom.ec_tx_mowner);
+ SLIST_INIT(&txchain);
+
+ for (i = 0; i < req0->txreq_dmamap->dm_nsegs; i++) {
+ KASSERT(req != NULL);
+
+ ds = &req0->txreq_dmamap->dm_segs[i];
+
+ if (__predict_false(xengnt_grant_access(
+ sc->sc_xbusd->xbusd_otherend_id,
+ trunc_page(ds->ds_addr),
+ GNTMAP_readonly, &req->txreq_gntref) != 0)) {
+ goto grant_fail;
+ }
+
+ KASSERT(SLIST_FIRST(&sc->sc_txreq_head) == req);
+ SLIST_REMOVE_HEAD(&sc->sc_txreq_head, txreq_next);
+ SLIST_INSERT_HEAD(&txchain, req, txreq_next);
+ sc->sc_free_txreql--;
+ req->txreq_m = (req == req0) ? m : NULL;
+
+ txreq = RING_GET_REQUEST(&sc->sc_tx_ring, prod + i);
+ txreq->id = req->txreq_id;
+ txreq->gref = req->txreq_gntref;
+ txreq->offset = ds->ds_addr & PAGE_MASK;
+ /* For Tx, first fragment has size always set to total size */
+ txreq->size = (i == 0) ? m->m_pkthdr.len : ds->ds_len;
+ txreq->flags = 0;
+ if ((m->m_pkthdr.csum_flags & XN_M_CSUM_SUPPORTED) != 0) {
+ txreq->flags |= NETTXF_csum_blank;
+ } else {
+ txreq->flags |= NETTXF_data_validated;
+ }
+ if (multiseg && i < lastseg)
+ txreq->flags |= NETTXF_more_data;
+
+ req = SLIST_FIRST(&sc->sc_txreq_head);
+ }
+
+ if (i > 1)
+ sc->sc_cnt_tx_frag.ev_count++;
+
+ /* All done */
+ *req_prod += i;
+ return true;
+
+grant_fail:
+ printf("%s: grant_access failed\n", device_xname(sc->sc_dev));
+ while (!SLIST_EMPTY(&txchain)) {
+ req = SLIST_FIRST(&txchain);
+ SLIST_REMOVE_HEAD(&txchain, txreq_next);
+ xengnt_revoke_access(req->txreq_gntref);
+ req->txreq_gntref = GRANT_INVALID_REF;
+ SLIST_INSERT_HEAD(&sc->sc_txreq_head, req, txreq_next);
+ sc->sc_free_txreql++;
+ }
+ req0->txreq_m = NULL;
+ return false;
+}
+
/*
* The output routine of a xennet interface. Prepares mbufs for TX,
* and notify backend when finished.
@@ -972,12 +1150,9 @@ xennet_start(struct ifnet *ifp)
{
struct xennet_xenbus_softc *sc = ifp->if_softc;
struct mbuf *m;
- netif_tx_request_t *txreq;
RING_IDX req_prod;
- paddr_t ma;
struct xennet_txreq *req;
int notify;
- int do_notify = 0;
mutex_enter(&sc->sc_tx_lock);
@@ -987,26 +1162,30 @@ xennet_start(struct ifnet *ifp)
req_prod = sc->sc_tx_ring.req_prod_pvt;
while (/*CONSTCOND*/1) {
- uint16_t txflags;
-
req = SLIST_FIRST(&sc->sc_txreq_head);
if (__predict_false(req == NULL)) {
+ if (!IFQ_IS_EMPTY(&ifp->if_snd))
+ sc->sc_cnt_tx_queue_full.ev_count++;
break;
}
IFQ_DEQUEUE(&ifp->if_snd, m);
if (m == NULL)
break;
- if ((m->m_pkthdr.csum_flags & XN_M_CSUM_SUPPORTED) != 0) {
- txflags = NETTXF_csum_blank;
- } else {
- txflags = NETTXF_data_validated;
- }
+ /*
+ * For short packets it's always way faster passing
+ * single defragmented packet, even with feature-sg.
+ * Try to defragment first if the result is likely to fit
+ * into a single mbuf.
+ */
+ if (m->m_pkthdr.len < MCLBYTES && m->m_next)
+ (void)m_defrag(m, M_DONTWAIT);
/* Try to load the mbuf as-is, if that fails defrag */
if (__predict_false(bus_dmamap_load_mbuf(
sc->sc_xbusd->xbusd_dmat,
req->txreq_dmamap, m, BUS_DMA_NOWAIT) != 0)) {
+ sc->sc_cnt_tx_defrag.ev_count++;
if (__predict_false(m_defrag(m, M_DONTWAIT) == NULL)) {
DPRINTF(("%s: defrag failed\n",
device_xname(sc->sc_dev)));
@@ -1025,28 +1204,16 @@ xennet_start(struct ifnet *ifp)
}
}
- KASSERT(req->txreq_dmamap->dm_nsegs == 1);
- ma = req->txreq_dmamap->dm_segs[0].ds_addr;
- KASSERT(((ma ^ (ma + m->m_pkthdr.len - 1)) & PTE_4KFRAME) == 0);
-
- if (__predict_false(xengnt_grant_access(
- sc->sc_xbusd->xbusd_otherend_id,
- trunc_page(ma),
- GNTMAP_readonly, &req->txreq_gntref) != 0)) {
+ if (req->txreq_dmamap->dm_nsegs > sc->sc_free_txreql) {
+ /* Not enough slots right now, postpone */
+ sc->sc_cnt_tx_queue_full.ev_count++;
+ sc->sc_cnt_tx_drop.ev_count++;
bus_dmamap_unload(sc->sc_xbusd->xbusd_dmat,
req->txreq_dmamap);
m_freem(m);
break;
}
- /* We are now committed to transmit the packet */
- bus_dmamap_sync(sc->sc_xbusd->xbusd_dmat, req->txreq_dmamap, 0,
- m->m_pkthdr.len, BUS_DMASYNC_POSTWRITE);
- MCLAIM(m, &sc->sc_ethercom.ec_tx_mowner);
-
- SLIST_REMOVE_HEAD(&sc->sc_txreq_head, txreq_next);
- req->txreq_m = m;
-
DPRINTFN(XEDB_MBUF, ("xennet_start id %d, "
"mbuf %p, buf %p/%p, size %d\n",
req->txreq_id, m, mtod(m, void *), (void *)ma,
@@ -1057,18 +1224,14 @@ xennet_start(struct ifnet *ifp)
req->txreq_id);
#endif
- txreq = RING_GET_REQUEST(&sc->sc_tx_ring, req_prod);
- txreq->id = req->txreq_id;
- txreq->gref = req->txreq_gntref;
- txreq->offset = ma & ~PTE_4KFRAME;
- txreq->size = m->m_pkthdr.len;
- txreq->flags = txflags;
-
- req_prod++;
- sc->sc_tx_ring.req_prod_pvt = req_prod;
- RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->sc_tx_ring, notify);
- if (notify)
- do_notify = 1;
+ if (!xennet_submit_tx_request(sc, m, req, &req_prod)) {
+ /* Grant failed, postpone */
+ sc->sc_cnt_tx_drop.ev_count++;
+ bus_dmamap_unload(sc->sc_xbusd->xbusd_dmat,
+ req->txreq_dmamap);
+ m_freem(m);
+ break;
+ }
/*
* Pass packet to bpf if there is a listener.
@@ -1076,7 +1239,9 @@ xennet_start(struct ifnet *ifp)
bpf_mtap(ifp, m, BPF_D_OUT);
}
- if (do_notify)
+ sc->sc_tx_ring.req_prod_pvt = req_prod;
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->sc_tx_ring, notify);
+ if (notify)
hypervisor_notify_via_evtchn(sc->sc_evtchn);
mutex_exit(&sc->sc_tx_lock);