Module Name: src
Committed By: sborrill
Date: Fri Feb 24 17:45:29 UTC 2012
Modified Files:
src/sys/arch/xen/xen [netbsd-5]: if_xennet_xenbus.c
Log Message:
Pull up the following revisions(s) (requested by bouyer in ticket #1730):
sys/arch/xen/xen/if_xennet_xenbus.c: revision 1.59 via patch
Fix receive stall on the domU side when buffers stay a long time in the
network stack or socket buffers.
To generate a diff of this commit:
cvs rdiff -u -r1.29.2.6 -r1.29.2.7 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.29.2.6 src/sys/arch/xen/xen/if_xennet_xenbus.c:1.29.2.7
--- src/sys/arch/xen/xen/if_xennet_xenbus.c:1.29.2.6 Thu May 19 21:13:07 2011
+++ src/sys/arch/xen/xen/if_xennet_xenbus.c Fri Feb 24 17:45:29 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: if_xennet_xenbus.c,v 1.29.2.6 2011/05/19 21:13:07 bouyer Exp $ */
+/* $NetBSD: if_xennet_xenbus.c,v 1.29.2.7 2012/02/24 17:45:29 sborrill Exp $ */
/*
* Copyright (c) 2006 Manuel Bouyer.
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.29.2.6 2011/05/19 21:13:07 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.29.2.7 2012/02/24 17:45:29 sborrill Exp $");
#include "opt_xen.h"
#include "opt_nfs_boot.h"
@@ -130,7 +130,6 @@ int xennet_debug = 0xff;
#endif
#define GRANT_INVALID_REF -1 /* entry is free */
-#define GRANT_STACK_REF -2 /* entry owned by the network stack */
#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
@@ -192,6 +191,9 @@ struct xennet_xenbus_softc {
static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1];
static u_long xennet_pages[NET_RX_RING_SIZE];
+static pool_cache_t if_xennetrxbuf_cache;
+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 *);
static int xennet_xenbus_detach(device_t, int);
@@ -202,6 +204,7 @@ static void xennet_alloc_rx_buffer(struc
static void xennet_free_rx_buffer(struct xennet_xenbus_softc *);
static void xennet_tx_complete(struct xennet_xenbus_softc *);
static void xennet_rx_mbuf_free(struct mbuf *, void *, size_t, void *);
+static void xennet_rx_free_req(struct xennet_rxreq *);
static int xennet_handler(void *);
static int xennet_talk_to_backend(struct xennet_xenbus_softc *);
#ifdef XENNET_DEBUG_DUMP
@@ -278,6 +281,14 @@ xennet_xenbus_attach(device_t parent, de
sc->sc_xbusd = xa->xa_xbusd;
sc->sc_xbusd->xbusd_otherend_changed = xennet_backend_changed;
+ /* 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,
+ "xnfrx", NULL, IPL_VM, NULL, NULL, NULL);
+ if_xennetrxbuf_cache_inited = 1;
+ }
+
+
/* initialize free RX and RX request lists */
SLIST_INIT(&sc->sc_txreq_head);
for (i = 0; i < NET_TX_RING_SIZE; i++) {
@@ -291,13 +302,10 @@ xennet_xenbus_attach(device_t parent, de
struct xennet_rxreq *rxreq = &sc->sc_rxreqs[i];
rxreq->rxreq_id = i;
rxreq->rxreq_sc = sc;
- rxreq->rxreq_va = uvm_km_alloc(kernel_map,
- PAGE_SIZE, PAGE_SIZE, UVM_KMF_WIRED | UVM_KMF_ZERO);
+ rxreq->rxreq_va = (vaddr_t)pool_cache_get_paddr(
+ if_xennetrxbuf_cache, PR_WAITOK, &rxreq->rxreq_pa);
if (rxreq->rxreq_va == 0)
break;
- if (!pmap_extract(pmap_kernel(), rxreq->rxreq_va,
- &rxreq->rxreq_pa))
- panic("%s: no pa for mapped va ?", device_xname(self));
rxreq->rxreq_gntref = GRANT_INVALID_REF;
SLIST_INSERT_HEAD(&sc->sc_rxreq_head, rxreq, rxreq_next);
}
@@ -560,7 +568,7 @@ xennet_alloc_rx_buffer(struct xennet_xen
RING_IDX i;
struct xennet_rxreq *req;
struct xen_memory_reservation reservation;
- int s1, s2, otherend_id;
+ int s1, s2, otherend_id, notify;
paddr_t pfn;
otherend_id = sc->sc_xbusd->xbusd_otherend_id;
@@ -647,9 +655,10 @@ out_loop:
}
sc->sc_rx_ring.req_prod_pvt = req_prod + i;
- RING_PUSH_REQUESTS(&sc->sc_rx_ring);
-
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->sc_rx_ring, notify);
splx(s1);
+ if (notify)
+ hypervisor_notify_via_evtchn(sc->sc_evtchn);
return;
}
@@ -669,14 +678,6 @@ xennet_free_rx_buffer(struct xennet_xenb
for (i = 0; i < NET_RX_RING_SIZE; i++) {
struct xennet_rxreq *rxreq = &sc->sc_rxreqs[i];
- /*
- * if the buffer is in transit in the network stack, wait for
- * the network stack to free it.
- */
- while ((volatile grant_ref_t)rxreq->rxreq_gntref ==
- GRANT_STACK_REF)
- tsleep(xennet_xenbus_detach, PRIBIO, "xnet_free", hz/2);
-
if (rxreq->rxreq_gntref != GRANT_INVALID_REF) {
/*
* this req is still granted. Get back the page or
@@ -746,7 +747,20 @@ xennet_free_rx_buffer(struct xennet_xenb
static void
xennet_rx_mbuf_free(struct mbuf *m, void *buf, size_t size, void *arg)
{
- struct xennet_rxreq *req = arg;
+ int s = splnet();
+ KASSERT(buf == m->m_ext.ext_buf);
+ KASSERT(arg == NULL);
+ KASSERT(m != NULL);
+ vaddr_t va = (vaddr_t)(buf) & ~((vaddr_t)PAGE_MASK);
+ pool_cache_put_paddr(if_xennetrxbuf_cache,
+ (void *)va, m->m_ext.ext_paddr);
+ pool_cache_put(mb_cache, m);
+ splx(s);
+};
+
+static void
+xennet_rx_free_req(struct xennet_rxreq *req)
+{
struct xennet_xenbus_softc *sc = req->rxreq_sc;
int s = splnet();
@@ -755,17 +769,15 @@ xennet_rx_mbuf_free(struct mbuf *m, void
sc->sc_free_rxreql++;
req->rxreq_gntref = GRANT_INVALID_REF;
- if (sc->sc_free_rxreql >= SC_NLIVEREQ(sc) &&
+
+ if (sc->sc_free_rxreql >= (NET_RX_RING_SIZE * 4 / 5) &&
__predict_true(sc->sc_backend_status == BEST_CONNECTED)) {
xennet_alloc_rx_buffer(sc);
}
- if (m)
- pool_cache_put(mb_cache, m);
splx(s);
}
-
static void
xennet_tx_complete(struct xennet_xenbus_softc *sc)
{
@@ -879,8 +891,6 @@ again:
__func__, sc->sc_rx_feature);
}
- req->rxreq_gntref = GRANT_INVALID_REF;
-
pa = req->rxreq_pa;
va = req->rxreq_va;
@@ -912,8 +922,7 @@ again:
DPRINTFN(XEDB_EVENT,
("xennet_handler bad dest\n"));
/* packet not for us */
- xennet_rx_mbuf_free(NULL, (void *)va, PAGE_SIZE,
- req);
+ xennet_rx_free_req(req);
continue;
}
}
@@ -921,36 +930,28 @@ again:
if (__predict_false(m == NULL)) {
printf("xennet: rx no mbuf\n");
ifp->if_ierrors++;
- xennet_rx_mbuf_free(NULL, (void *)va, PAGE_SIZE, req);
+ xennet_rx_free_req(req);
continue;
}
MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner);
m->m_pkthdr.rcvif = ifp;
- if (__predict_true(sc->sc_rx_ring.req_prod_pvt !=
- sc->sc_rx_ring.sring->rsp_prod)) {
- m->m_len = m->m_pkthdr.len = rx->status;
- MEXTADD(m, pktp, rx->status,
- M_DEVBUF, xennet_rx_mbuf_free, req);
- m->m_flags |= M_EXT_RW; /* we own the buffer */
- req->rxreq_gntref = GRANT_STACK_REF;
- } else {
- /*
- * This was our last receive buffer, allocate
- * memory, copy data and push the receive
- * buffer back to the hypervisor.
- */
- m->m_len = min(MHLEN, rx->status);
- m->m_pkthdr.len = 0;
- m_copyback(m, 0, rx->status, pktp);
- xennet_rx_mbuf_free(NULL, (void *)va, PAGE_SIZE, req);
- if (m->m_pkthdr.len < rx->status) {
- /* out of memory, just drop packets */
- ifp->if_ierrors++;
- m_freem(m);
- continue;
- }
+ req->rxreq_va = (vaddr_t)pool_cache_get_paddr(
+ if_xennetrxbuf_cache, PR_NOWAIT, &req->rxreq_pa);
+ if (__predict_false(req->rxreq_va == 0)) {
+ printf("%s: rx no buf\n", ifp->if_xname);
+ ifp->if_ierrors++;
+ req->rxreq_va = va;
+ req->rxreq_pa = pa;
+ xennet_rx_free_req(req);
+ m_freem(m);
+ continue;
}
+ m->m_len = m->m_pkthdr.len = rx->status;
+ MEXTADD(m, pktp, rx->status,
+ M_DEVBUF, xennet_rx_mbuf_free, NULL);
+ m->m_flags |= M_EXT_RW; /* we own the buffer */
+ m->m_ext.ext_paddr = pa;
if ((rx->flags & NETRXF_csum_blank) != 0) {
xennet_checksum_fill(&m);
if (m == NULL) {
@@ -958,6 +959,8 @@ again:
continue;
}
}
+ /* free req may overwrite *rx, better doing it late */
+ xennet_rx_free_req(req);
#if NBPFILTER > 0
/*
* Pass packet to bpf if there is a listener.