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.