18e0ad55aSJoel Dahl /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 489e0f4d2SKip Macy * Copyright (c) 2004-2006 Kip Macy 596375eacSRoger Pau Monné * Copyright (c) 2015 Wei Liu <wei.liu2@citrix.com> 689e0f4d2SKip Macy * All rights reserved. 789e0f4d2SKip Macy * 88e0ad55aSJoel Dahl * Redistribution and use in source and binary forms, with or without 98e0ad55aSJoel Dahl * modification, are permitted provided that the following conditions 108e0ad55aSJoel Dahl * are met: 118e0ad55aSJoel Dahl * 1. Redistributions of source code must retain the above copyright 128e0ad55aSJoel Dahl * notice, this list of conditions and the following disclaimer. 138e0ad55aSJoel Dahl * 2. Redistributions in binary form must reproduce the above copyright 148e0ad55aSJoel Dahl * notice, this list of conditions and the following disclaimer in the 158e0ad55aSJoel Dahl * documentation and/or other materials provided with the distribution. 1689e0f4d2SKip Macy * 178e0ad55aSJoel Dahl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 188e0ad55aSJoel Dahl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198e0ad55aSJoel Dahl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208e0ad55aSJoel Dahl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 218e0ad55aSJoel Dahl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228e0ad55aSJoel Dahl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238e0ad55aSJoel Dahl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248e0ad55aSJoel Dahl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258e0ad55aSJoel Dahl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268e0ad55aSJoel Dahl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278e0ad55aSJoel Dahl * SUCH DAMAGE. 2889e0f4d2SKip Macy */ 2989e0f4d2SKip Macy 3089e0f4d2SKip Macy #include <sys/cdefs.h> 31a0ae8f04SBjoern A. Zeeb #include "opt_inet.h" 32f909bbb4SGleb Smirnoff #include "opt_inet6.h" 33a0ae8f04SBjoern A. Zeeb 3489e0f4d2SKip Macy #include <sys/param.h> 3589e0f4d2SKip Macy #include <sys/sockio.h> 36c578b6acSGleb Smirnoff #include <sys/limits.h> 3789e0f4d2SKip Macy #include <sys/mbuf.h> 3889e0f4d2SKip Macy #include <sys/malloc.h> 3923dc5621SKip Macy #include <sys/module.h> 4089e0f4d2SKip Macy #include <sys/kernel.h> 4189e0f4d2SKip Macy #include <sys/socket.h> 4212678024SDoug Rabson #include <sys/sysctl.h> 4396375eacSRoger Pau Monné #include <sys/taskqueue.h> 4489e0f4d2SKip Macy 4589e0f4d2SKip Macy #include <net/if.h> 4677374386SGleb Smirnoff #include <net/if_var.h> 4789e0f4d2SKip Macy #include <net/if_arp.h> 4889e0f4d2SKip Macy #include <net/ethernet.h> 4989e0f4d2SKip Macy #include <net/if_media.h> 5089e0f4d2SKip Macy #include <net/bpf.h> 5189e0f4d2SKip Macy #include <net/if_types.h> 5289e0f4d2SKip Macy 5389e0f4d2SKip Macy #include <netinet/in.h> 5489e0f4d2SKip Macy #include <netinet/ip.h> 5589e0f4d2SKip Macy #include <netinet/if_ether.h> 5612678024SDoug Rabson #include <netinet/tcp.h> 5712678024SDoug Rabson #include <netinet/tcp_lro.h> 5889e0f4d2SKip Macy 5989e0f4d2SKip Macy #include <vm/vm.h> 6089e0f4d2SKip Macy #include <vm/pmap.h> 6189e0f4d2SKip Macy 6289e0f4d2SKip Macy #include <sys/bus.h> 6389e0f4d2SKip Macy 6476acc41fSJustin T. Gibbs #include <xen/xen-os.h> 653a6d1fcfSKip Macy #include <xen/hypervisor.h> 663a6d1fcfSKip Macy #include <xen/xen_intr.h> 6789e0f4d2SKip Macy #include <xen/gnttab.h> 68ad7dd514SElliott Mitchell #include <contrib/xen/memory.h> 69ad7dd514SElliott Mitchell #include <contrib/xen/io/netif.h> 7023dc5621SKip Macy #include <xen/xenbus/xenbusvar.h> 7189e0f4d2SKip Macy 72dabb3db7SRoger Pau Monné #include <machine/bus.h> 73dabb3db7SRoger Pau Monné 7423dc5621SKip Macy #include "xenbus_if.h" 7589e0f4d2SKip Macy 76578e4bf7SJustin T. Gibbs /* Features supported by all backends. TSO and LRO can be negotiated */ 77578e4bf7SJustin T. Gibbs #define XN_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) 7812678024SDoug Rabson 7998018db4SRyan Libby #define NET_TX_RING_SIZE __CONST_RING_SIZE(netif_tx, PAGE_SIZE) 8098018db4SRyan Libby #define NET_RX_RING_SIZE __CONST_RING_SIZE(netif_rx, PAGE_SIZE) 8189e0f4d2SKip Macy 822568ee67SRoger Pau Monné #define NET_RX_SLOTS_MIN (XEN_NETIF_NR_SLOTS_MIN + 1) 832568ee67SRoger Pau Monné 8412678024SDoug Rabson /* 8512678024SDoug Rabson * Should the driver do LRO on the RX end 8612678024SDoug Rabson * this can be toggled on the fly, but the 8712678024SDoug Rabson * interface must be reset (down/up) for it 8812678024SDoug Rabson * to take effect. 8912678024SDoug Rabson */ 9012678024SDoug Rabson static int xn_enable_lro = 1; 9112678024SDoug Rabson TUNABLE_INT("hw.xn.enable_lro", &xn_enable_lro); 9212678024SDoug Rabson 9396375eacSRoger Pau Monné /* 9496375eacSRoger Pau Monné * Number of pairs of queues. 9596375eacSRoger Pau Monné */ 9696375eacSRoger Pau Monné static unsigned long xn_num_queues = 4; 9796375eacSRoger Pau Monné TUNABLE_ULONG("hw.xn.num_queues", &xn_num_queues); 9896375eacSRoger Pau Monné 99931eeffaSKenneth D. Merry /** 100931eeffaSKenneth D. Merry * \brief The maximum allowed data fragments in a single transmit 101931eeffaSKenneth D. Merry * request. 102931eeffaSKenneth D. Merry * 103931eeffaSKenneth D. Merry * This limit is imposed by the backend driver. We assume here that 104931eeffaSKenneth D. Merry * we are dealing with a Linux driver domain and have set our limit 105931eeffaSKenneth D. Merry * to mirror the Linux MAX_SKB_FRAGS constant. 106931eeffaSKenneth D. Merry */ 107931eeffaSKenneth D. Merry #define MAX_TX_REQ_FRAGS (65536 / PAGE_SIZE + 2) 108931eeffaSKenneth D. Merry 10989e0f4d2SKip Macy #define RX_COPY_THRESHOLD 256 11089e0f4d2SKip Macy 11189e0f4d2SKip Macy #define net_ratelimit() 0 11289e0f4d2SKip Macy 11396375eacSRoger Pau Monné struct netfront_rxq; 11496375eacSRoger Pau Monné struct netfront_txq; 11589e0f4d2SKip Macy struct netfront_info; 11689e0f4d2SKip Macy struct netfront_rx_info; 11789e0f4d2SKip Macy 11896375eacSRoger Pau Monné static void xn_txeof(struct netfront_txq *); 11996375eacSRoger Pau Monné static void xn_rxeof(struct netfront_rxq *); 12096375eacSRoger Pau Monné static void xn_alloc_rx_buffers(struct netfront_rxq *); 1212568ee67SRoger Pau Monné static void xn_alloc_rx_buffers_callout(void *arg); 12289e0f4d2SKip Macy 12396375eacSRoger Pau Monné static void xn_release_rx_bufs(struct netfront_rxq *); 12496375eacSRoger Pau Monné static void xn_release_tx_bufs(struct netfront_txq *); 12589e0f4d2SKip Macy 126da695b05SRoger Pau Monné static void xn_rxq_intr(struct netfront_rxq *); 127da695b05SRoger Pau Monné static void xn_txq_intr(struct netfront_txq *); 128da695b05SRoger Pau Monné static void xn_intr(void *); 12996375eacSRoger Pau Monné static int xn_assemble_tx_request(struct netfront_txq *, struct mbuf *); 13002f3b17fSJustin Hibbits static int xn_ioctl(if_t, u_long, caddr_t); 13189e0f4d2SKip Macy static void xn_ifinit_locked(struct netfront_info *); 13289e0f4d2SKip Macy static void xn_ifinit(void *); 13389e0f4d2SKip Macy static void xn_stop(struct netfront_info *); 134578e4bf7SJustin T. Gibbs static void xn_query_features(struct netfront_info *np); 135578e4bf7SJustin T. Gibbs static int xn_configure_features(struct netfront_info *np); 13689e0f4d2SKip Macy static void netif_free(struct netfront_info *info); 13723dc5621SKip Macy static int netfront_detach(device_t dev); 13889e0f4d2SKip Macy 13996375eacSRoger Pau Monné static int xn_txq_mq_start_locked(struct netfront_txq *, struct mbuf *); 14002f3b17fSJustin Hibbits static int xn_txq_mq_start(if_t, struct mbuf *); 14196375eacSRoger Pau Monné 14223dc5621SKip Macy static int talk_to_backend(device_t dev, struct netfront_info *info); 14323dc5621SKip Macy static int create_netdev(device_t dev); 14489e0f4d2SKip Macy static void netif_disconnect_backend(struct netfront_info *info); 14596375eacSRoger Pau Monné static int setup_device(device_t dev, struct netfront_info *info, 14696375eacSRoger Pau Monné unsigned long); 14702f3b17fSJustin Hibbits static int xn_ifmedia_upd(if_t ifp); 14802f3b17fSJustin Hibbits static void xn_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr); 1490e509842SJustin T. Gibbs 15065671253SRoger Pau Monné static int xn_connect(struct netfront_info *); 15165671253SRoger Pau Monné static void xn_kick_rings(struct netfront_info *); 15289e0f4d2SKip Macy 15396375eacSRoger Pau Monné static int xn_get_responses(struct netfront_rxq *, 15496375eacSRoger Pau Monné struct netfront_rx_info *, RING_IDX, RING_IDX *, 15596375eacSRoger Pau Monné struct mbuf **); 15689e0f4d2SKip Macy 1573c790178SJohn Baldwin #define virt_to_mfn(x) (vtophys(x) >> PAGE_SHIFT) 15889e0f4d2SKip Macy 15989e0f4d2SKip Macy #define INVALID_P2M_ENTRY (~0UL) 16096375eacSRoger Pau Monné #define XN_QUEUE_NAME_LEN 8 /* xn{t,r}x_%u, allow for two digits */ 16196375eacSRoger Pau Monné struct netfront_rxq { 16296375eacSRoger Pau Monné struct netfront_info *info; 16396375eacSRoger Pau Monné u_int id; 16496375eacSRoger Pau Monné char name[XN_QUEUE_NAME_LEN]; 16596375eacSRoger Pau Monné struct mtx lock; 16696375eacSRoger Pau Monné 16796375eacSRoger Pau Monné int ring_ref; 16896375eacSRoger Pau Monné netif_rx_front_ring_t ring; 16996375eacSRoger Pau Monné xen_intr_handle_t xen_intr_handle; 17096375eacSRoger Pau Monné 17196375eacSRoger Pau Monné grant_ref_t gref_head; 17236ea5721SOlivier Houchard grant_ref_t grant_ref[NET_RX_RING_SIZE + 1]; 17396375eacSRoger Pau Monné 17496375eacSRoger Pau Monné struct mbuf *mbufs[NET_RX_RING_SIZE + 1]; 17596375eacSRoger Pau Monné 17696375eacSRoger Pau Monné struct lro_ctrl lro; 17796375eacSRoger Pau Monné 1782568ee67SRoger Pau Monné struct callout rx_refill; 17996375eacSRoger Pau Monné }; 18096375eacSRoger Pau Monné 18196375eacSRoger Pau Monné struct netfront_txq { 18296375eacSRoger Pau Monné struct netfront_info *info; 18396375eacSRoger Pau Monné u_int id; 18496375eacSRoger Pau Monné char name[XN_QUEUE_NAME_LEN]; 18596375eacSRoger Pau Monné struct mtx lock; 18696375eacSRoger Pau Monné 18796375eacSRoger Pau Monné int ring_ref; 18896375eacSRoger Pau Monné netif_tx_front_ring_t ring; 18996375eacSRoger Pau Monné xen_intr_handle_t xen_intr_handle; 19096375eacSRoger Pau Monné 19196375eacSRoger Pau Monné grant_ref_t gref_head; 19296375eacSRoger Pau Monné grant_ref_t grant_ref[NET_TX_RING_SIZE + 1]; 19396375eacSRoger Pau Monné 19496375eacSRoger Pau Monné struct mbuf *mbufs[NET_TX_RING_SIZE + 1]; 19596375eacSRoger Pau Monné int mbufs_cnt; 19696375eacSRoger Pau Monné struct buf_ring *br; 19796375eacSRoger Pau Monné 19896375eacSRoger Pau Monné struct taskqueue *tq; 19996375eacSRoger Pau Monné struct task defrtask; 20096375eacSRoger Pau Monné 201dabb3db7SRoger Pau Monné bus_dma_segment_t segs[MAX_TX_REQ_FRAGS]; 202dabb3db7SRoger Pau Monné struct mbuf_xennet { 203dabb3db7SRoger Pau Monné struct m_tag tag; 204dabb3db7SRoger Pau Monné bus_dma_tag_t dma_tag; 205dabb3db7SRoger Pau Monné bus_dmamap_t dma_map; 206dabb3db7SRoger Pau Monné struct netfront_txq *txq; 207dabb3db7SRoger Pau Monné SLIST_ENTRY(mbuf_xennet) next; 208dabb3db7SRoger Pau Monné u_int count; 209dabb3db7SRoger Pau Monné } xennet_tag[NET_TX_RING_SIZE + 1]; 210dabb3db7SRoger Pau Monné SLIST_HEAD(, mbuf_xennet) tags; 211dabb3db7SRoger Pau Monné 21296375eacSRoger Pau Monné bool full; 21396375eacSRoger Pau Monné }; 21496375eacSRoger Pau Monné 21589e0f4d2SKip Macy struct netfront_info { 21602f3b17fSJustin Hibbits if_t xn_ifp; 21789e0f4d2SKip Macy 218227ca257SKip Macy struct mtx sc_lock; 21989e0f4d2SKip Macy 22096375eacSRoger Pau Monné u_int num_queues; 22196375eacSRoger Pau Monné struct netfront_rxq *rxq; 22296375eacSRoger Pau Monné struct netfront_txq *txq; 22396375eacSRoger Pau Monné 22489e0f4d2SKip Macy u_int carrier; 225578e4bf7SJustin T. Gibbs u_int maxfrags; 22689e0f4d2SKip Macy 22723dc5621SKip Macy device_t xbdev; 22889e0f4d2SKip Macy uint8_t mac[ETHER_ADDR_LEN]; 22989e0f4d2SKip Macy 23089e0f4d2SKip Macy int xn_if_flags; 23189e0f4d2SKip Macy 2320e509842SJustin T. Gibbs struct ifmedia sc_media; 2336a8e9695SRoger Pau Monné 234dabb3db7SRoger Pau Monné bus_dma_tag_t dma_tag; 235dabb3db7SRoger Pau Monné 236c2d12e5eSRoger Pau Monné bool xn_reset; 23789e0f4d2SKip Macy }; 23889e0f4d2SKip Macy 23996375eacSRoger Pau Monné struct netfront_rx_info { 24096375eacSRoger Pau Monné struct netif_rx_response rx; 24196375eacSRoger Pau Monné struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; 24296375eacSRoger Pau Monné }; 24389e0f4d2SKip Macy 24496375eacSRoger Pau Monné #define XN_RX_LOCK(_q) mtx_lock(&(_q)->lock) 24596375eacSRoger Pau Monné #define XN_RX_UNLOCK(_q) mtx_unlock(&(_q)->lock) 24689e0f4d2SKip Macy 24796375eacSRoger Pau Monné #define XN_TX_LOCK(_q) mtx_lock(&(_q)->lock) 24896375eacSRoger Pau Monné #define XN_TX_TRYLOCK(_q) mtx_trylock(&(_q)->lock) 24996375eacSRoger Pau Monné #define XN_TX_UNLOCK(_q) mtx_unlock(&(_q)->lock) 25089e0f4d2SKip Macy 251227ca257SKip Macy #define XN_LOCK(_sc) mtx_lock(&(_sc)->sc_lock); 252227ca257SKip Macy #define XN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock); 25389e0f4d2SKip Macy 254227ca257SKip Macy #define XN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED); 25596375eacSRoger Pau Monné #define XN_RX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); 25696375eacSRoger Pau Monné #define XN_TX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); 25789e0f4d2SKip Macy 25889e0f4d2SKip Macy #define netfront_carrier_on(netif) ((netif)->carrier = 1) 25989e0f4d2SKip Macy #define netfront_carrier_off(netif) ((netif)->carrier = 0) 26089e0f4d2SKip Macy #define netfront_carrier_ok(netif) ((netif)->carrier) 26189e0f4d2SKip Macy 26289e0f4d2SKip Macy /* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ 26389e0f4d2SKip Macy 26489e0f4d2SKip Macy static inline void 265931eeffaSKenneth D. Merry add_id_to_freelist(struct mbuf **list, uintptr_t id) 26689e0f4d2SKip Macy { 26796375eacSRoger Pau Monné 268931eeffaSKenneth D. Merry KASSERT(id != 0, 269931eeffaSKenneth D. Merry ("%s: the head item (0) must always be free.", __func__)); 27089e0f4d2SKip Macy list[id] = list[0]; 271931eeffaSKenneth D. Merry list[0] = (struct mbuf *)id; 27289e0f4d2SKip Macy } 27389e0f4d2SKip Macy 27489e0f4d2SKip Macy static inline unsigned short 27589e0f4d2SKip Macy get_id_from_freelist(struct mbuf **list) 27689e0f4d2SKip Macy { 277931eeffaSKenneth D. Merry uintptr_t id; 278931eeffaSKenneth D. Merry 279931eeffaSKenneth D. Merry id = (uintptr_t)list[0]; 280931eeffaSKenneth D. Merry KASSERT(id != 0, 281931eeffaSKenneth D. Merry ("%s: the head item (0) must always remain free.", __func__)); 28289e0f4d2SKip Macy list[0] = list[id]; 28389e0f4d2SKip Macy return (id); 28489e0f4d2SKip Macy } 28589e0f4d2SKip Macy 28689e0f4d2SKip Macy static inline int 28796375eacSRoger Pau Monné xn_rxidx(RING_IDX idx) 28889e0f4d2SKip Macy { 28996375eacSRoger Pau Monné 29089e0f4d2SKip Macy return idx & (NET_RX_RING_SIZE - 1); 29189e0f4d2SKip Macy } 29289e0f4d2SKip Macy 29389e0f4d2SKip Macy static inline struct mbuf * 29496375eacSRoger Pau Monné xn_get_rx_mbuf(struct netfront_rxq *rxq, RING_IDX ri) 29589e0f4d2SKip Macy { 29696375eacSRoger Pau Monné int i; 29789e0f4d2SKip Macy struct mbuf *m; 29889e0f4d2SKip Macy 29996375eacSRoger Pau Monné i = xn_rxidx(ri); 30096375eacSRoger Pau Monné m = rxq->mbufs[i]; 30196375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 30289e0f4d2SKip Macy return (m); 30389e0f4d2SKip Macy } 30489e0f4d2SKip Macy 30589e0f4d2SKip Macy static inline grant_ref_t 30696375eacSRoger Pau Monné xn_get_rx_ref(struct netfront_rxq *rxq, RING_IDX ri) 30789e0f4d2SKip Macy { 30896375eacSRoger Pau Monné int i = xn_rxidx(ri); 30996375eacSRoger Pau Monné grant_ref_t ref = rxq->grant_ref[i]; 31096375eacSRoger Pau Monné 311ff662b5cSJustin T. Gibbs KASSERT(ref != GRANT_REF_INVALID, ("Invalid grant reference!\n")); 31296375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 31396375eacSRoger Pau Monné return (ref); 31489e0f4d2SKip Macy } 31589e0f4d2SKip Macy 316dabb3db7SRoger Pau Monné #define MTAG_COOKIE 1218492000 317dabb3db7SRoger Pau Monné #define MTAG_XENNET 0 318dabb3db7SRoger Pau Monné 319dabb3db7SRoger Pau Monné static void mbuf_grab(struct mbuf *m) 320dabb3db7SRoger Pau Monné { 321dabb3db7SRoger Pau Monné struct mbuf_xennet *ref; 322dabb3db7SRoger Pau Monné 323dabb3db7SRoger Pau Monné ref = (struct mbuf_xennet *)m_tag_locate(m, MTAG_COOKIE, 324dabb3db7SRoger Pau Monné MTAG_XENNET, NULL); 325dabb3db7SRoger Pau Monné KASSERT(ref != NULL, ("Cannot find refcount")); 326dabb3db7SRoger Pau Monné ref->count++; 327dabb3db7SRoger Pau Monné } 328dabb3db7SRoger Pau Monné 329dabb3db7SRoger Pau Monné static void mbuf_release(struct mbuf *m) 330dabb3db7SRoger Pau Monné { 331dabb3db7SRoger Pau Monné struct mbuf_xennet *ref; 332dabb3db7SRoger Pau Monné 333dabb3db7SRoger Pau Monné ref = (struct mbuf_xennet *)m_tag_locate(m, MTAG_COOKIE, 334dabb3db7SRoger Pau Monné MTAG_XENNET, NULL); 335dabb3db7SRoger Pau Monné KASSERT(ref != NULL, ("Cannot find refcount")); 336dabb3db7SRoger Pau Monné KASSERT(ref->count > 0, ("Invalid reference count")); 337dabb3db7SRoger Pau Monné 338*2e4781cbSMark Johnston if (--ref->count == 0) { 339*2e4781cbSMark Johnston /* 340*2e4781cbSMark Johnston * Explicitly free the tag while we hold the tx queue lock. 341*2e4781cbSMark Johnston * This ensures that the tag is deleted promptly in case 342*2e4781cbSMark Johnston * something else is holding extra references to the mbuf chain, 343*2e4781cbSMark Johnston * such as netmap. 344*2e4781cbSMark Johnston */ 345*2e4781cbSMark Johnston m_tag_delete(m, &ref->tag); 346dabb3db7SRoger Pau Monné m_freem(m); 347dabb3db7SRoger Pau Monné } 348*2e4781cbSMark Johnston } 349dabb3db7SRoger Pau Monné 350dabb3db7SRoger Pau Monné static void tag_free(struct m_tag *t) 351dabb3db7SRoger Pau Monné { 352dabb3db7SRoger Pau Monné struct mbuf_xennet *ref = (struct mbuf_xennet *)t; 353dabb3db7SRoger Pau Monné 354dabb3db7SRoger Pau Monné KASSERT(ref->count == 0, ("Free mbuf tag with pending refcnt")); 355dabb3db7SRoger Pau Monné bus_dmamap_sync(ref->dma_tag, ref->dma_map, BUS_DMASYNC_POSTWRITE); 356dabb3db7SRoger Pau Monné bus_dmamap_destroy(ref->dma_tag, ref->dma_map); 357dabb3db7SRoger Pau Monné SLIST_INSERT_HEAD(&ref->txq->tags, ref, next); 358dabb3db7SRoger Pau Monné } 359dabb3db7SRoger Pau Monné 36089e0f4d2SKip Macy #define IPRINTK(fmt, args...) \ 36189e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 362227ca257SKip Macy #ifdef INVARIANTS 36389e0f4d2SKip Macy #define WPRINTK(fmt, args...) \ 36489e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 365227ca257SKip Macy #else 366227ca257SKip Macy #define WPRINTK(fmt, args...) 367227ca257SKip Macy #endif 368227ca257SKip Macy #ifdef DEBUG 36989e0f4d2SKip Macy #define DPRINTK(fmt, args...) \ 37023dc5621SKip Macy printf("[XEN] %s: " fmt, __func__, ##args) 37112678024SDoug Rabson #else 37212678024SDoug Rabson #define DPRINTK(fmt, args...) 37312678024SDoug Rabson #endif 37489e0f4d2SKip Macy 37589e0f4d2SKip Macy /** 37689e0f4d2SKip Macy * Read the 'mac' node at the given device's node in the store, and parse that 37789e0f4d2SKip Macy * as colon-separated octets, placing result the given mac array. mac must be 37889e0f4d2SKip Macy * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). 37989e0f4d2SKip Macy * Return 0 on success, or errno on error. 38089e0f4d2SKip Macy */ 38189e0f4d2SKip Macy static int 38223dc5621SKip Macy xen_net_read_mac(device_t dev, uint8_t mac[]) 38389e0f4d2SKip Macy { 3843a6d1fcfSKip Macy int error, i; 3853a6d1fcfSKip Macy char *s, *e, *macstr; 386ffa06904SJustin T. Gibbs const char *path; 3873a6d1fcfSKip Macy 388ffa06904SJustin T. Gibbs path = xenbus_get_node(dev); 389ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 390ffa06904SJustin T. Gibbs if (error == ENOENT) { 391ffa06904SJustin T. Gibbs /* 392ffa06904SJustin T. Gibbs * Deal with missing mac XenStore nodes on devices with 393ffa06904SJustin T. Gibbs * HVM emulation (the 'ioemu' configuration attribute) 394ffa06904SJustin T. Gibbs * enabled. 395ffa06904SJustin T. Gibbs * 396ffa06904SJustin T. Gibbs * The HVM emulator may execute in a stub device model 397ffa06904SJustin T. Gibbs * domain which lacks the permission, only given to Dom0, 398ffa06904SJustin T. Gibbs * to update the guest's XenStore tree. For this reason, 399ffa06904SJustin T. Gibbs * the HVM emulator doesn't even attempt to write the 400ffa06904SJustin T. Gibbs * front-side mac node, even when operating in Dom0. 401ffa06904SJustin T. Gibbs * However, there should always be a mac listed in the 402ffa06904SJustin T. Gibbs * backend tree. Fallback to this version if our query 403ffa06904SJustin T. Gibbs * of the front side XenStore location doesn't find 404ffa06904SJustin T. Gibbs * anything. 405ffa06904SJustin T. Gibbs */ 406ffa06904SJustin T. Gibbs path = xenbus_get_otherend_path(dev); 407ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 408ffa06904SJustin T. Gibbs } 409ffa06904SJustin T. Gibbs if (error != 0) { 410ffa06904SJustin T. Gibbs xenbus_dev_fatal(dev, error, "parsing %s/mac", path); 4113a6d1fcfSKip Macy return (error); 412ffa06904SJustin T. Gibbs } 4133a6d1fcfSKip Macy 41489e0f4d2SKip Macy s = macstr; 41589e0f4d2SKip Macy for (i = 0; i < ETHER_ADDR_LEN; i++) { 41689e0f4d2SKip Macy mac[i] = strtoul(s, &e, 16); 41789e0f4d2SKip Macy if (s == e || (e[0] != ':' && e[0] != 0)) { 418ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 4193a6d1fcfSKip Macy return (ENOENT); 42089e0f4d2SKip Macy } 42189e0f4d2SKip Macy s = &e[1]; 42289e0f4d2SKip Macy } 423ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 4243a6d1fcfSKip Macy return (0); 42589e0f4d2SKip Macy } 42689e0f4d2SKip Macy 42789e0f4d2SKip Macy /** 42889e0f4d2SKip Macy * Entry point to this code when a new device is created. Allocate the basic 42989e0f4d2SKip Macy * structures and the ring buffers for communication with the backend, and 43089e0f4d2SKip Macy * inform the backend of the appropriate details for those. Switch to 43189e0f4d2SKip Macy * Connected state. 43289e0f4d2SKip Macy */ 43389e0f4d2SKip Macy static int 43423dc5621SKip Macy netfront_probe(device_t dev) 43523dc5621SKip Macy { 43623dc5621SKip Macy 4375f700083SJulien Grall if (xen_pv_nics_disabled()) 438f8f1bb83SRoger Pau Monné return (ENXIO); 439f8f1bb83SRoger Pau Monné 44023dc5621SKip Macy if (!strcmp(xenbus_get_type(dev), "vif")) { 44123dc5621SKip Macy device_set_desc(dev, "Virtual Network Interface"); 44223dc5621SKip Macy return (0); 44323dc5621SKip Macy } 44423dc5621SKip Macy 44523dc5621SKip Macy return (ENXIO); 44623dc5621SKip Macy } 44723dc5621SKip Macy 44823dc5621SKip Macy static int 44923dc5621SKip Macy netfront_attach(device_t dev) 45089e0f4d2SKip Macy { 45189e0f4d2SKip Macy int err; 45289e0f4d2SKip Macy 45323dc5621SKip Macy err = create_netdev(dev); 45496375eacSRoger Pau Monné if (err != 0) { 45589e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "creating netdev"); 456ffa06904SJustin T. Gibbs return (err); 45789e0f4d2SKip Macy } 45889e0f4d2SKip Macy 45912678024SDoug Rabson SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 46012678024SDoug Rabson SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 461f0188618SHans Petter Selasky OID_AUTO, "enable_lro", CTLFLAG_RW, 46212678024SDoug Rabson &xn_enable_lro, 0, "Large Receive Offload"); 46312678024SDoug Rabson 46496375eacSRoger Pau Monné SYSCTL_ADD_ULONG(device_get_sysctl_ctx(dev), 46596375eacSRoger Pau Monné SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 46696375eacSRoger Pau Monné OID_AUTO, "num_queues", CTLFLAG_RD, 46796375eacSRoger Pau Monné &xn_num_queues, "Number of pairs of queues"); 46896375eacSRoger Pau Monné 469ffa06904SJustin T. Gibbs return (0); 47089e0f4d2SKip Macy } 47189e0f4d2SKip Macy 472cf9c09e1SJustin T. Gibbs static int 473cf9c09e1SJustin T. Gibbs netfront_suspend(device_t dev) 474cf9c09e1SJustin T. Gibbs { 47596375eacSRoger Pau Monné struct netfront_info *np = device_get_softc(dev); 47696375eacSRoger Pau Monné u_int i; 477cf9c09e1SJustin T. Gibbs 47896375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 47996375eacSRoger Pau Monné XN_RX_LOCK(&np->rxq[i]); 48096375eacSRoger Pau Monné XN_TX_LOCK(&np->txq[i]); 48196375eacSRoger Pau Monné } 48296375eacSRoger Pau Monné netfront_carrier_off(np); 48396375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 48496375eacSRoger Pau Monné XN_RX_UNLOCK(&np->rxq[i]); 48596375eacSRoger Pau Monné XN_TX_UNLOCK(&np->txq[i]); 48696375eacSRoger Pau Monné } 487cf9c09e1SJustin T. Gibbs return (0); 488cf9c09e1SJustin T. Gibbs } 48989e0f4d2SKip Macy 49089e0f4d2SKip Macy /** 49189e0f4d2SKip Macy * We are reconnecting to the backend, due to a suspend/resume, or a backend 49289e0f4d2SKip Macy * driver restart. We tear down our netif structure and recreate it, but 49389e0f4d2SKip Macy * leave the device-layer structures intact so that this is transparent to the 49489e0f4d2SKip Macy * rest of the kernel. 49589e0f4d2SKip Macy */ 49689e0f4d2SKip Macy static int 49723dc5621SKip Macy netfront_resume(device_t dev) 49889e0f4d2SKip Macy { 49923dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 5008dee0e9bSRoger Pau Monné u_int i; 5018dee0e9bSRoger Pau Monné 5028dee0e9bSRoger Pau Monné if (xen_suspend_cancelled) { 5038dee0e9bSRoger Pau Monné for (i = 0; i < info->num_queues; i++) { 5048dee0e9bSRoger Pau Monné XN_RX_LOCK(&info->rxq[i]); 5058dee0e9bSRoger Pau Monné XN_TX_LOCK(&info->txq[i]); 5068dee0e9bSRoger Pau Monné } 5078dee0e9bSRoger Pau Monné netfront_carrier_on(info); 5088dee0e9bSRoger Pau Monné for (i = 0; i < info->num_queues; i++) { 5098dee0e9bSRoger Pau Monné XN_RX_UNLOCK(&info->rxq[i]); 5108dee0e9bSRoger Pau Monné XN_TX_UNLOCK(&info->txq[i]); 5118dee0e9bSRoger Pau Monné } 5128dee0e9bSRoger Pau Monné return (0); 5138dee0e9bSRoger Pau Monné } 51489e0f4d2SKip Macy 51589e0f4d2SKip Macy netif_disconnect_backend(info); 51689e0f4d2SKip Macy return (0); 51789e0f4d2SKip Macy } 51889e0f4d2SKip Macy 51996375eacSRoger Pau Monné static int 52096375eacSRoger Pau Monné write_queue_xenstore_keys(device_t dev, 52196375eacSRoger Pau Monné struct netfront_rxq *rxq, 52296375eacSRoger Pau Monné struct netfront_txq *txq, 52396375eacSRoger Pau Monné struct xs_transaction *xst, bool hierarchy) 52496375eacSRoger Pau Monné { 52596375eacSRoger Pau Monné int err; 52696375eacSRoger Pau Monné const char *message; 52796375eacSRoger Pau Monné const char *node = xenbus_get_node(dev); 52896375eacSRoger Pau Monné char *path; 52996375eacSRoger Pau Monné size_t path_size; 53096375eacSRoger Pau Monné 53196375eacSRoger Pau Monné KASSERT(rxq->id == txq->id, ("Mismatch between RX and TX queue ids")); 53296375eacSRoger Pau Monné /* Split event channel support is not yet there. */ 53396375eacSRoger Pau Monné KASSERT(rxq->xen_intr_handle == txq->xen_intr_handle, 53496375eacSRoger Pau Monné ("Split event channels are not supported")); 53596375eacSRoger Pau Monné 53696375eacSRoger Pau Monné if (hierarchy) { 53796375eacSRoger Pau Monné path_size = strlen(node) + 10; 53896375eacSRoger Pau Monné path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); 53996375eacSRoger Pau Monné snprintf(path, path_size, "%s/queue-%u", node, rxq->id); 54096375eacSRoger Pau Monné } else { 54196375eacSRoger Pau Monné path_size = strlen(node) + 1; 54296375eacSRoger Pau Monné path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); 54396375eacSRoger Pau Monné snprintf(path, path_size, "%s", node); 54496375eacSRoger Pau Monné } 54596375eacSRoger Pau Monné 54696375eacSRoger Pau Monné err = xs_printf(*xst, path, "tx-ring-ref","%u", txq->ring_ref); 54796375eacSRoger Pau Monné if (err != 0) { 54896375eacSRoger Pau Monné message = "writing tx ring-ref"; 54996375eacSRoger Pau Monné goto error; 55096375eacSRoger Pau Monné } 55196375eacSRoger Pau Monné err = xs_printf(*xst, path, "rx-ring-ref","%u", rxq->ring_ref); 55296375eacSRoger Pau Monné if (err != 0) { 55396375eacSRoger Pau Monné message = "writing rx ring-ref"; 55496375eacSRoger Pau Monné goto error; 55596375eacSRoger Pau Monné } 55696375eacSRoger Pau Monné err = xs_printf(*xst, path, "event-channel", "%u", 55796375eacSRoger Pau Monné xen_intr_port(rxq->xen_intr_handle)); 55896375eacSRoger Pau Monné if (err != 0) { 55996375eacSRoger Pau Monné message = "writing event-channel"; 56096375eacSRoger Pau Monné goto error; 56196375eacSRoger Pau Monné } 56296375eacSRoger Pau Monné 56396375eacSRoger Pau Monné free(path, M_DEVBUF); 56496375eacSRoger Pau Monné 56596375eacSRoger Pau Monné return (0); 56696375eacSRoger Pau Monné 56796375eacSRoger Pau Monné error: 56896375eacSRoger Pau Monné free(path, M_DEVBUF); 56996375eacSRoger Pau Monné xenbus_dev_fatal(dev, err, "%s", message); 57096375eacSRoger Pau Monné 57196375eacSRoger Pau Monné return (err); 57296375eacSRoger Pau Monné } 57396375eacSRoger Pau Monné 57489e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */ 57589e0f4d2SKip Macy static int 57623dc5621SKip Macy talk_to_backend(device_t dev, struct netfront_info *info) 57789e0f4d2SKip Macy { 57889e0f4d2SKip Macy const char *message; 579ff662b5cSJustin T. Gibbs struct xs_transaction xst; 58023dc5621SKip Macy const char *node = xenbus_get_node(dev); 58189e0f4d2SKip Macy int err; 58296375eacSRoger Pau Monné unsigned long num_queues, max_queues = 0; 58396375eacSRoger Pau Monné unsigned int i; 58489e0f4d2SKip Macy 58589e0f4d2SKip Macy err = xen_net_read_mac(dev, info->mac); 58696375eacSRoger Pau Monné if (err != 0) { 58723dc5621SKip Macy xenbus_dev_fatal(dev, err, "parsing %s/mac", node); 58889e0f4d2SKip Macy goto out; 58989e0f4d2SKip Macy } 59089e0f4d2SKip Macy 59196375eacSRoger Pau Monné err = xs_scanf(XST_NIL, xenbus_get_otherend_path(info->xbdev), 59296375eacSRoger Pau Monné "multi-queue-max-queues", NULL, "%lu", &max_queues); 59396375eacSRoger Pau Monné if (err != 0) 59496375eacSRoger Pau Monné max_queues = 1; 59596375eacSRoger Pau Monné num_queues = xn_num_queues; 59696375eacSRoger Pau Monné if (num_queues > max_queues) 59796375eacSRoger Pau Monné num_queues = max_queues; 59896375eacSRoger Pau Monné 59996375eacSRoger Pau Monné err = setup_device(dev, info, num_queues); 600318bbb6dSRoger Pau Monné if (err != 0) { 601318bbb6dSRoger Pau Monné xenbus_dev_fatal(dev, err, "setup device"); 60289e0f4d2SKip Macy goto out; 603318bbb6dSRoger Pau Monné } 60489e0f4d2SKip Macy 60589e0f4d2SKip Macy again: 606ff662b5cSJustin T. Gibbs err = xs_transaction_start(&xst); 60796375eacSRoger Pau Monné if (err != 0) { 60889e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "starting transaction"); 60996375eacSRoger Pau Monné goto free; 61089e0f4d2SKip Macy } 61196375eacSRoger Pau Monné 61296375eacSRoger Pau Monné if (info->num_queues == 1) { 61396375eacSRoger Pau Monné err = write_queue_xenstore_keys(dev, &info->rxq[0], 61496375eacSRoger Pau Monné &info->txq[0], &xst, false); 61596375eacSRoger Pau Monné if (err != 0) 61696375eacSRoger Pau Monné goto abort_transaction_no_def_error; 61796375eacSRoger Pau Monné } else { 61896375eacSRoger Pau Monné err = xs_printf(xst, node, "multi-queue-num-queues", 61996375eacSRoger Pau Monné "%u", info->num_queues); 62096375eacSRoger Pau Monné if (err != 0) { 62196375eacSRoger Pau Monné message = "writing multi-queue-num-queues"; 62289e0f4d2SKip Macy goto abort_transaction; 62389e0f4d2SKip Macy } 62496375eacSRoger Pau Monné 62596375eacSRoger Pau Monné for (i = 0; i < info->num_queues; i++) { 62696375eacSRoger Pau Monné err = write_queue_xenstore_keys(dev, &info->rxq[i], 62796375eacSRoger Pau Monné &info->txq[i], &xst, true); 62896375eacSRoger Pau Monné if (err != 0) 62996375eacSRoger Pau Monné goto abort_transaction_no_def_error; 63089e0f4d2SKip Macy } 63189e0f4d2SKip Macy } 63296375eacSRoger Pau Monné 633d0f3a8b9SRoger Pau Monné err = xs_printf(xst, node, "request-rx-copy", "%u", 1); 63496375eacSRoger Pau Monné if (err != 0) { 63589e0f4d2SKip Macy message = "writing request-rx-copy"; 63689e0f4d2SKip Macy goto abort_transaction; 63789e0f4d2SKip Macy } 638ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-rx-notify", "%d", 1); 63996375eacSRoger Pau Monné if (err != 0) { 64089e0f4d2SKip Macy message = "writing feature-rx-notify"; 64189e0f4d2SKip Macy goto abort_transaction; 64289e0f4d2SKip Macy } 643ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-sg", "%d", 1); 64496375eacSRoger Pau Monné if (err != 0) { 64589e0f4d2SKip Macy message = "writing feature-sg"; 64689e0f4d2SKip Macy goto abort_transaction; 64789e0f4d2SKip Macy } 64802f3b17fSJustin Hibbits if ((if_getcapenable(info->xn_ifp) & IFCAP_LRO) != 0) { 649ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-gso-tcpv4", "%d", 1); 65096375eacSRoger Pau Monné if (err != 0) { 65189e0f4d2SKip Macy message = "writing feature-gso-tcpv4"; 65289e0f4d2SKip Macy goto abort_transaction; 65389e0f4d2SKip Macy } 654c2d12e5eSRoger Pau Monné } 65502f3b17fSJustin Hibbits if ((if_getcapenable(info->xn_ifp) & IFCAP_RXCSUM) == 0) { 656c2d12e5eSRoger Pau Monné err = xs_printf(xst, node, "feature-no-csum-offload", "%d", 1); 657c2d12e5eSRoger Pau Monné if (err != 0) { 658c2d12e5eSRoger Pau Monné message = "writing feature-no-csum-offload"; 659c2d12e5eSRoger Pau Monné goto abort_transaction; 660c2d12e5eSRoger Pau Monné } 661c2d12e5eSRoger Pau Monné } 66289e0f4d2SKip Macy 663ff662b5cSJustin T. Gibbs err = xs_transaction_end(xst, 0); 66496375eacSRoger Pau Monné if (err != 0) { 66589e0f4d2SKip Macy if (err == EAGAIN) 66689e0f4d2SKip Macy goto again; 66789e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "completing transaction"); 66896375eacSRoger Pau Monné goto free; 66989e0f4d2SKip Macy } 67089e0f4d2SKip Macy 67189e0f4d2SKip Macy return 0; 67289e0f4d2SKip Macy 67389e0f4d2SKip Macy abort_transaction: 67489e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "%s", message); 67596375eacSRoger Pau Monné abort_transaction_no_def_error: 67696375eacSRoger Pau Monné xs_transaction_end(xst, 1); 67796375eacSRoger Pau Monné free: 67889e0f4d2SKip Macy netif_free(info); 67989e0f4d2SKip Macy out: 68096375eacSRoger Pau Monné return (err); 68196375eacSRoger Pau Monné } 68296375eacSRoger Pau Monné 68396375eacSRoger Pau Monné static void 684da695b05SRoger Pau Monné xn_rxq_intr(struct netfront_rxq *rxq) 68596375eacSRoger Pau Monné { 68696375eacSRoger Pau Monné 68796375eacSRoger Pau Monné XN_RX_LOCK(rxq); 68896375eacSRoger Pau Monné xn_rxeof(rxq); 68996375eacSRoger Pau Monné XN_RX_UNLOCK(rxq); 69096375eacSRoger Pau Monné } 69196375eacSRoger Pau Monné 69296375eacSRoger Pau Monné static void 69396375eacSRoger Pau Monné xn_txq_start(struct netfront_txq *txq) 69496375eacSRoger Pau Monné { 69596375eacSRoger Pau Monné struct netfront_info *np = txq->info; 69602f3b17fSJustin Hibbits if_t ifp = np->xn_ifp; 69796375eacSRoger Pau Monné 69896375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 69996375eacSRoger Pau Monné if (!drbr_empty(ifp, txq->br)) 70096375eacSRoger Pau Monné xn_txq_mq_start_locked(txq, NULL); 70196375eacSRoger Pau Monné } 70296375eacSRoger Pau Monné 70396375eacSRoger Pau Monné static void 704da695b05SRoger Pau Monné xn_txq_intr(struct netfront_txq *txq) 70596375eacSRoger Pau Monné { 70696375eacSRoger Pau Monné 70796375eacSRoger Pau Monné XN_TX_LOCK(txq); 70896375eacSRoger Pau Monné if (RING_HAS_UNCONSUMED_RESPONSES(&txq->ring)) 70996375eacSRoger Pau Monné xn_txeof(txq); 71096375eacSRoger Pau Monné xn_txq_start(txq); 71196375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 71296375eacSRoger Pau Monné } 71396375eacSRoger Pau Monné 71496375eacSRoger Pau Monné static void 71596375eacSRoger Pau Monné xn_txq_tq_deferred(void *xtxq, int pending) 71696375eacSRoger Pau Monné { 71796375eacSRoger Pau Monné struct netfront_txq *txq = xtxq; 71896375eacSRoger Pau Monné 71996375eacSRoger Pau Monné XN_TX_LOCK(txq); 72096375eacSRoger Pau Monné xn_txq_start(txq); 72196375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 72296375eacSRoger Pau Monné } 72396375eacSRoger Pau Monné 72496375eacSRoger Pau Monné static void 72596375eacSRoger Pau Monné disconnect_rxq(struct netfront_rxq *rxq) 72696375eacSRoger Pau Monné { 72796375eacSRoger Pau Monné 72896375eacSRoger Pau Monné xn_release_rx_bufs(rxq); 72996375eacSRoger Pau Monné gnttab_free_grant_references(rxq->gref_head); 730318bbb6dSRoger Pau Monné if (rxq->ring_ref != GRANT_REF_INVALID) { 731d039b070SRoger Pau Monné gnttab_end_foreign_access(rxq->ring_ref, NULL); 732318bbb6dSRoger Pau Monné rxq->ring_ref = GRANT_REF_INVALID; 733318bbb6dSRoger Pau Monné } 73496375eacSRoger Pau Monné /* 73596375eacSRoger Pau Monné * No split event channel support at the moment, handle will 73696375eacSRoger Pau Monné * be unbound in tx. So no need to call xen_intr_unbind here, 73796375eacSRoger Pau Monné * but we do want to reset the handler to 0. 73896375eacSRoger Pau Monné */ 73996375eacSRoger Pau Monné rxq->xen_intr_handle = 0; 74096375eacSRoger Pau Monné } 74196375eacSRoger Pau Monné 74296375eacSRoger Pau Monné static void 74396375eacSRoger Pau Monné destroy_rxq(struct netfront_rxq *rxq) 74496375eacSRoger Pau Monné { 74596375eacSRoger Pau Monné 7462568ee67SRoger Pau Monné callout_drain(&rxq->rx_refill); 74796375eacSRoger Pau Monné free(rxq->ring.sring, M_DEVBUF); 748318bbb6dSRoger Pau Monné rxq->ring.sring = NULL; 74996375eacSRoger Pau Monné } 75096375eacSRoger Pau Monné 75196375eacSRoger Pau Monné static void 75296375eacSRoger Pau Monné destroy_rxqs(struct netfront_info *np) 75396375eacSRoger Pau Monné { 75496375eacSRoger Pau Monné int i; 75596375eacSRoger Pau Monné 75696375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 75796375eacSRoger Pau Monné destroy_rxq(&np->rxq[i]); 75896375eacSRoger Pau Monné 75996375eacSRoger Pau Monné free(np->rxq, M_DEVBUF); 76096375eacSRoger Pau Monné np->rxq = NULL; 76189e0f4d2SKip Macy } 76289e0f4d2SKip Macy 76389e0f4d2SKip Macy static int 76496375eacSRoger Pau Monné setup_rxqs(device_t dev, struct netfront_info *info, 76596375eacSRoger Pau Monné unsigned long num_queues) 76689e0f4d2SKip Macy { 76796375eacSRoger Pau Monné int q, i; 7683a6d1fcfSKip Macy int error; 76996375eacSRoger Pau Monné netif_rx_sring_t *rxs; 77096375eacSRoger Pau Monné struct netfront_rxq *rxq; 77189e0f4d2SKip Macy 77296375eacSRoger Pau Monné info->rxq = malloc(sizeof(struct netfront_rxq) * num_queues, 77396375eacSRoger Pau Monné M_DEVBUF, M_WAITOK|M_ZERO); 77489e0f4d2SKip Macy 77596375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) { 77696375eacSRoger Pau Monné rxq = &info->rxq[q]; 77796375eacSRoger Pau Monné 77896375eacSRoger Pau Monné rxq->id = q; 77996375eacSRoger Pau Monné rxq->info = info; 780318bbb6dSRoger Pau Monné 781318bbb6dSRoger Pau Monné rxq->gref_head = GNTTAB_LIST_END; 78296375eacSRoger Pau Monné rxq->ring_ref = GRANT_REF_INVALID; 78396375eacSRoger Pau Monné rxq->ring.sring = NULL; 78496375eacSRoger Pau Monné snprintf(rxq->name, XN_QUEUE_NAME_LEN, "xnrx_%u", q); 78596375eacSRoger Pau Monné mtx_init(&rxq->lock, rxq->name, "netfront receive lock", 78696375eacSRoger Pau Monné MTX_DEF); 78796375eacSRoger Pau Monné 78896375eacSRoger Pau Monné for (i = 0; i <= NET_RX_RING_SIZE; i++) { 78996375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 79096375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 79196375eacSRoger Pau Monné } 79296375eacSRoger Pau Monné 79396375eacSRoger Pau Monné /* Start resources allocation */ 79496375eacSRoger Pau Monné 7952568ee67SRoger Pau Monné if (gnttab_alloc_grant_references(NET_RX_RING_SIZE, 79696375eacSRoger Pau Monné &rxq->gref_head) != 0) { 79796375eacSRoger Pau Monné device_printf(dev, "allocating rx gref"); 7983a6d1fcfSKip Macy error = ENOMEM; 79989e0f4d2SKip Macy goto fail; 80089e0f4d2SKip Macy } 80189e0f4d2SKip Macy 80296375eacSRoger Pau Monné rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, 80396375eacSRoger Pau Monné M_WAITOK|M_ZERO); 80489e0f4d2SKip Macy SHARED_RING_INIT(rxs); 80596375eacSRoger Pau Monné FRONT_RING_INIT(&rxq->ring, rxs, PAGE_SIZE); 80689e0f4d2SKip Macy 80796375eacSRoger Pau Monné error = xenbus_grant_ring(dev, virt_to_mfn(rxs), 80896375eacSRoger Pau Monné &rxq->ring_ref); 80996375eacSRoger Pau Monné if (error != 0) { 81096375eacSRoger Pau Monné device_printf(dev, "granting rx ring page"); 81196375eacSRoger Pau Monné goto fail_grant_ring; 81296375eacSRoger Pau Monné } 81389e0f4d2SKip Macy 8142568ee67SRoger Pau Monné callout_init(&rxq->rx_refill, 1); 81589e0f4d2SKip Macy } 81689e0f4d2SKip Macy 8173a6d1fcfSKip Macy return (0); 81889e0f4d2SKip Macy 81996375eacSRoger Pau Monné fail_grant_ring: 82096375eacSRoger Pau Monné gnttab_free_grant_references(rxq->gref_head); 82196375eacSRoger Pau Monné free(rxq->ring.sring, M_DEVBUF); 82289e0f4d2SKip Macy fail: 82396375eacSRoger Pau Monné for (; q >= 0; q--) { 82496375eacSRoger Pau Monné disconnect_rxq(&info->rxq[q]); 82596375eacSRoger Pau Monné destroy_rxq(&info->rxq[q]); 82696375eacSRoger Pau Monné } 82796375eacSRoger Pau Monné 82896375eacSRoger Pau Monné free(info->rxq, M_DEVBUF); 82996375eacSRoger Pau Monné return (error); 83096375eacSRoger Pau Monné } 83196375eacSRoger Pau Monné 83296375eacSRoger Pau Monné static void 83396375eacSRoger Pau Monné disconnect_txq(struct netfront_txq *txq) 83496375eacSRoger Pau Monné { 83596375eacSRoger Pau Monné 83696375eacSRoger Pau Monné xn_release_tx_bufs(txq); 83796375eacSRoger Pau Monné gnttab_free_grant_references(txq->gref_head); 838318bbb6dSRoger Pau Monné if (txq->ring_ref != GRANT_REF_INVALID) { 839d039b070SRoger Pau Monné gnttab_end_foreign_access(txq->ring_ref, NULL); 840318bbb6dSRoger Pau Monné txq->ring_ref = GRANT_REF_INVALID; 841318bbb6dSRoger Pau Monné } 84296375eacSRoger Pau Monné xen_intr_unbind(&txq->xen_intr_handle); 84396375eacSRoger Pau Monné } 84496375eacSRoger Pau Monné 84596375eacSRoger Pau Monné static void 84696375eacSRoger Pau Monné destroy_txq(struct netfront_txq *txq) 84796375eacSRoger Pau Monné { 848dabb3db7SRoger Pau Monné unsigned int i; 84996375eacSRoger Pau Monné 85096375eacSRoger Pau Monné free(txq->ring.sring, M_DEVBUF); 851318bbb6dSRoger Pau Monné txq->ring.sring = NULL; 85296375eacSRoger Pau Monné buf_ring_free(txq->br, M_DEVBUF); 853318bbb6dSRoger Pau Monné txq->br = NULL; 854318bbb6dSRoger Pau Monné if (txq->tq) { 85596375eacSRoger Pau Monné taskqueue_drain_all(txq->tq); 85696375eacSRoger Pau Monné taskqueue_free(txq->tq); 857318bbb6dSRoger Pau Monné txq->tq = NULL; 858318bbb6dSRoger Pau Monné } 859dabb3db7SRoger Pau Monné 860dabb3db7SRoger Pau Monné for (i = 0; i <= NET_TX_RING_SIZE; i++) { 861dabb3db7SRoger Pau Monné bus_dmamap_destroy(txq->info->dma_tag, 862dabb3db7SRoger Pau Monné txq->xennet_tag[i].dma_map); 863dabb3db7SRoger Pau Monné txq->xennet_tag[i].dma_map = NULL; 864dabb3db7SRoger Pau Monné } 86596375eacSRoger Pau Monné } 86696375eacSRoger Pau Monné 86796375eacSRoger Pau Monné static void 86896375eacSRoger Pau Monné destroy_txqs(struct netfront_info *np) 86996375eacSRoger Pau Monné { 87096375eacSRoger Pau Monné int i; 87196375eacSRoger Pau Monné 87296375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 87396375eacSRoger Pau Monné destroy_txq(&np->txq[i]); 87496375eacSRoger Pau Monné 87596375eacSRoger Pau Monné free(np->txq, M_DEVBUF); 87696375eacSRoger Pau Monné np->txq = NULL; 87796375eacSRoger Pau Monné } 87896375eacSRoger Pau Monné 87996375eacSRoger Pau Monné static int 88096375eacSRoger Pau Monné setup_txqs(device_t dev, struct netfront_info *info, 88196375eacSRoger Pau Monné unsigned long num_queues) 88296375eacSRoger Pau Monné { 88396375eacSRoger Pau Monné int q, i; 88496375eacSRoger Pau Monné int error; 88596375eacSRoger Pau Monné netif_tx_sring_t *txs; 88696375eacSRoger Pau Monné struct netfront_txq *txq; 88796375eacSRoger Pau Monné 88896375eacSRoger Pau Monné info->txq = malloc(sizeof(struct netfront_txq) * num_queues, 88996375eacSRoger Pau Monné M_DEVBUF, M_WAITOK|M_ZERO); 89096375eacSRoger Pau Monné 89196375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) { 89296375eacSRoger Pau Monné txq = &info->txq[q]; 89396375eacSRoger Pau Monné 89496375eacSRoger Pau Monné txq->id = q; 89596375eacSRoger Pau Monné txq->info = info; 89696375eacSRoger Pau Monné 897318bbb6dSRoger Pau Monné txq->gref_head = GNTTAB_LIST_END; 89896375eacSRoger Pau Monné txq->ring_ref = GRANT_REF_INVALID; 89996375eacSRoger Pau Monné txq->ring.sring = NULL; 90096375eacSRoger Pau Monné 90196375eacSRoger Pau Monné snprintf(txq->name, XN_QUEUE_NAME_LEN, "xntx_%u", q); 90296375eacSRoger Pau Monné 90396375eacSRoger Pau Monné mtx_init(&txq->lock, txq->name, "netfront transmit lock", 90496375eacSRoger Pau Monné MTX_DEF); 905dabb3db7SRoger Pau Monné SLIST_INIT(&txq->tags); 90696375eacSRoger Pau Monné 90796375eacSRoger Pau Monné for (i = 0; i <= NET_TX_RING_SIZE; i++) { 90896375eacSRoger Pau Monné txq->mbufs[i] = (void *) ((u_long) i+1); 90996375eacSRoger Pau Monné txq->grant_ref[i] = GRANT_REF_INVALID; 910dabb3db7SRoger Pau Monné txq->xennet_tag[i].txq = txq; 911dabb3db7SRoger Pau Monné txq->xennet_tag[i].dma_tag = info->dma_tag; 912dabb3db7SRoger Pau Monné error = bus_dmamap_create(info->dma_tag, 0, 913dabb3db7SRoger Pau Monné &txq->xennet_tag[i].dma_map); 914dabb3db7SRoger Pau Monné if (error != 0) { 915dabb3db7SRoger Pau Monné device_printf(dev, 916dabb3db7SRoger Pau Monné "failed to allocate dma map\n"); 917dabb3db7SRoger Pau Monné goto fail; 918dabb3db7SRoger Pau Monné } 919dabb3db7SRoger Pau Monné m_tag_setup(&txq->xennet_tag[i].tag, 920dabb3db7SRoger Pau Monné MTAG_COOKIE, MTAG_XENNET, 921dabb3db7SRoger Pau Monné sizeof(txq->xennet_tag[i]) - 922dabb3db7SRoger Pau Monné sizeof(txq->xennet_tag[i].tag)); 923dabb3db7SRoger Pau Monné txq->xennet_tag[i].tag.m_tag_free = &tag_free; 924dabb3db7SRoger Pau Monné SLIST_INSERT_HEAD(&txq->tags, &txq->xennet_tag[i], 925dabb3db7SRoger Pau Monné next); 92696375eacSRoger Pau Monné } 92796375eacSRoger Pau Monné txq->mbufs[NET_TX_RING_SIZE] = (void *)0; 92896375eacSRoger Pau Monné 92996375eacSRoger Pau Monné /* Start resources allocation. */ 93096375eacSRoger Pau Monné 93196375eacSRoger Pau Monné if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, 93296375eacSRoger Pau Monné &txq->gref_head) != 0) { 93396375eacSRoger Pau Monné device_printf(dev, "failed to allocate tx grant refs\n"); 93496375eacSRoger Pau Monné error = ENOMEM; 93596375eacSRoger Pau Monné goto fail; 93696375eacSRoger Pau Monné } 93796375eacSRoger Pau Monné 93896375eacSRoger Pau Monné txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, 93996375eacSRoger Pau Monné M_WAITOK|M_ZERO); 94096375eacSRoger Pau Monné SHARED_RING_INIT(txs); 94196375eacSRoger Pau Monné FRONT_RING_INIT(&txq->ring, txs, PAGE_SIZE); 94296375eacSRoger Pau Monné 94396375eacSRoger Pau Monné error = xenbus_grant_ring(dev, virt_to_mfn(txs), 94496375eacSRoger Pau Monné &txq->ring_ref); 94596375eacSRoger Pau Monné if (error != 0) { 94696375eacSRoger Pau Monné device_printf(dev, "failed to grant tx ring\n"); 94796375eacSRoger Pau Monné goto fail_grant_ring; 94896375eacSRoger Pau Monné } 94996375eacSRoger Pau Monné 95096375eacSRoger Pau Monné txq->br = buf_ring_alloc(NET_TX_RING_SIZE, M_DEVBUF, 95196375eacSRoger Pau Monné M_WAITOK, &txq->lock); 95296375eacSRoger Pau Monné TASK_INIT(&txq->defrtask, 0, xn_txq_tq_deferred, txq); 95396375eacSRoger Pau Monné 954da695b05SRoger Pau Monné txq->tq = taskqueue_create(txq->name, M_WAITOK, 95596375eacSRoger Pau Monné taskqueue_thread_enqueue, &txq->tq); 95696375eacSRoger Pau Monné 95796375eacSRoger Pau Monné error = taskqueue_start_threads(&txq->tq, 1, PI_NET, 95896375eacSRoger Pau Monné "%s txq %d", device_get_nameunit(dev), txq->id); 95996375eacSRoger Pau Monné if (error != 0) { 96096375eacSRoger Pau Monné device_printf(dev, "failed to start tx taskq %d\n", 96196375eacSRoger Pau Monné txq->id); 96296375eacSRoger Pau Monné goto fail_start_thread; 96396375eacSRoger Pau Monné } 96496375eacSRoger Pau Monné 96596375eacSRoger Pau Monné error = xen_intr_alloc_and_bind_local_port(dev, 966da695b05SRoger Pau Monné xenbus_get_otherend_id(dev), /* filter */ NULL, xn_intr, 967da695b05SRoger Pau Monné &info->txq[q], INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY, 96896375eacSRoger Pau Monné &txq->xen_intr_handle); 96996375eacSRoger Pau Monné 97096375eacSRoger Pau Monné if (error != 0) { 97196375eacSRoger Pau Monné device_printf(dev, "xen_intr_alloc_and_bind_local_port failed\n"); 97296375eacSRoger Pau Monné goto fail_bind_port; 97396375eacSRoger Pau Monné } 97496375eacSRoger Pau Monné } 97596375eacSRoger Pau Monné 97696375eacSRoger Pau Monné return (0); 97796375eacSRoger Pau Monné 97896375eacSRoger Pau Monné fail_bind_port: 97996375eacSRoger Pau Monné taskqueue_drain_all(txq->tq); 98096375eacSRoger Pau Monné fail_start_thread: 98196375eacSRoger Pau Monné buf_ring_free(txq->br, M_DEVBUF); 98296375eacSRoger Pau Monné taskqueue_free(txq->tq); 983d039b070SRoger Pau Monné gnttab_end_foreign_access(txq->ring_ref, NULL); 98496375eacSRoger Pau Monné fail_grant_ring: 98596375eacSRoger Pau Monné gnttab_free_grant_references(txq->gref_head); 98696375eacSRoger Pau Monné free(txq->ring.sring, M_DEVBUF); 98796375eacSRoger Pau Monné fail: 98896375eacSRoger Pau Monné for (; q >= 0; q--) { 98996375eacSRoger Pau Monné disconnect_txq(&info->txq[q]); 99096375eacSRoger Pau Monné destroy_txq(&info->txq[q]); 99196375eacSRoger Pau Monné } 99296375eacSRoger Pau Monné 99396375eacSRoger Pau Monné free(info->txq, M_DEVBUF); 99496375eacSRoger Pau Monné return (error); 99596375eacSRoger Pau Monné } 99696375eacSRoger Pau Monné 99796375eacSRoger Pau Monné static int 99896375eacSRoger Pau Monné setup_device(device_t dev, struct netfront_info *info, 99996375eacSRoger Pau Monné unsigned long num_queues) 100096375eacSRoger Pau Monné { 100196375eacSRoger Pau Monné int error; 100296375eacSRoger Pau Monné int q; 100396375eacSRoger Pau Monné 100496375eacSRoger Pau Monné if (info->txq) 100596375eacSRoger Pau Monné destroy_txqs(info); 100696375eacSRoger Pau Monné 100796375eacSRoger Pau Monné if (info->rxq) 100896375eacSRoger Pau Monné destroy_rxqs(info); 100996375eacSRoger Pau Monné 101096375eacSRoger Pau Monné info->num_queues = 0; 101196375eacSRoger Pau Monné 101296375eacSRoger Pau Monné error = setup_rxqs(dev, info, num_queues); 101396375eacSRoger Pau Monné if (error != 0) 101496375eacSRoger Pau Monné goto out; 101596375eacSRoger Pau Monné error = setup_txqs(dev, info, num_queues); 101696375eacSRoger Pau Monné if (error != 0) 101796375eacSRoger Pau Monné goto out; 101896375eacSRoger Pau Monné 101996375eacSRoger Pau Monné info->num_queues = num_queues; 102096375eacSRoger Pau Monné 102196375eacSRoger Pau Monné /* No split event channel at the moment. */ 102296375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) 102396375eacSRoger Pau Monné info->rxq[q].xen_intr_handle = info->txq[q].xen_intr_handle; 102496375eacSRoger Pau Monné 102596375eacSRoger Pau Monné return (0); 102696375eacSRoger Pau Monné 102796375eacSRoger Pau Monné out: 102896375eacSRoger Pau Monné KASSERT(error != 0, ("Error path taken without providing an error code")); 10293a6d1fcfSKip Macy return (error); 103089e0f4d2SKip Macy } 103189e0f4d2SKip Macy 1032a0ae8f04SBjoern A. Zeeb #ifdef INET 103302f3b17fSJustin Hibbits static u_int 103402f3b17fSJustin Hibbits netfront_addr_cb(void *arg, struct ifaddr *a, u_int count) 103502f3b17fSJustin Hibbits { 103602f3b17fSJustin Hibbits arp_ifinit((if_t)arg, a); 103702f3b17fSJustin Hibbits return (1); 103802f3b17fSJustin Hibbits } 103989e0f4d2SKip Macy /** 104012678024SDoug Rabson * If this interface has an ipv4 address, send an arp for it. This 104112678024SDoug Rabson * helps to get the network going again after migrating hosts. 104212678024SDoug Rabson */ 104312678024SDoug Rabson static void 104412678024SDoug Rabson netfront_send_fake_arp(device_t dev, struct netfront_info *info) 104512678024SDoug Rabson { 104602f3b17fSJustin Hibbits if_t ifp; 104712678024SDoug Rabson 104812678024SDoug Rabson ifp = info->xn_ifp; 104902f3b17fSJustin Hibbits if_foreach_addr_type(ifp, AF_INET, netfront_addr_cb, ifp); 105012678024SDoug Rabson } 1051a0ae8f04SBjoern A. Zeeb #endif 105212678024SDoug Rabson 105312678024SDoug Rabson /** 105489e0f4d2SKip Macy * Callback received when the backend's state changes. 105589e0f4d2SKip Macy */ 1056283d6f72SJustin T. Gibbs static void 105723dc5621SKip Macy netfront_backend_changed(device_t dev, XenbusState newstate) 105889e0f4d2SKip Macy { 105923dc5621SKip Macy struct netfront_info *sc = device_get_softc(dev); 106089e0f4d2SKip Macy 106123dc5621SKip Macy DPRINTK("newstate=%d\n", newstate); 106289e0f4d2SKip Macy 106302f3b17fSJustin Hibbits CURVNET_SET(if_getvnet(sc->xn_ifp)); 1064903eaa68SKristof Provost 106523dc5621SKip Macy switch (newstate) { 106689e0f4d2SKip Macy case XenbusStateInitialising: 106789e0f4d2SKip Macy case XenbusStateInitialised: 106889e0f4d2SKip Macy case XenbusStateUnknown: 1069920ba15bSKip Macy case XenbusStateReconfigured: 1070920ba15bSKip Macy case XenbusStateReconfiguring: 107189e0f4d2SKip Macy break; 107289e0f4d2SKip Macy case XenbusStateInitWait: 107323dc5621SKip Macy if (xenbus_get_state(dev) != XenbusStateInitialising) 107489e0f4d2SKip Macy break; 107596375eacSRoger Pau Monné if (xn_connect(sc) != 0) 107689e0f4d2SKip Macy break; 107765671253SRoger Pau Monné /* Switch to connected state before kicking the rings. */ 107865671253SRoger Pau Monné xenbus_set_state(sc->xbdev, XenbusStateConnected); 107965671253SRoger Pau Monné xn_kick_rings(sc); 108023dc5621SKip Macy break; 108189e0f4d2SKip Macy case XenbusStateClosing: 108223dc5621SKip Macy xenbus_set_state(dev, XenbusStateClosed); 108389e0f4d2SKip Macy break; 1084c2d12e5eSRoger Pau Monné case XenbusStateClosed: 1085c2d12e5eSRoger Pau Monné if (sc->xn_reset) { 1086c2d12e5eSRoger Pau Monné netif_disconnect_backend(sc); 1087c2d12e5eSRoger Pau Monné xenbus_set_state(dev, XenbusStateInitialising); 1088c2d12e5eSRoger Pau Monné sc->xn_reset = false; 1089c2d12e5eSRoger Pau Monné } 1090c2d12e5eSRoger Pau Monné break; 1091dbf82bdeSRoger Pau Monné case XenbusStateConnected: 1092dbf82bdeSRoger Pau Monné #ifdef INET 1093dbf82bdeSRoger Pau Monné netfront_send_fake_arp(dev, sc); 1094dbf82bdeSRoger Pau Monné #endif 1095dbf82bdeSRoger Pau Monné break; 109689e0f4d2SKip Macy } 1097903eaa68SKristof Provost 1098903eaa68SKristof Provost CURVNET_RESTORE(); 109989e0f4d2SKip Macy } 110089e0f4d2SKip Macy 1101931eeffaSKenneth D. Merry /** 1102931eeffaSKenneth D. Merry * \brief Verify that there is sufficient space in the Tx ring 1103931eeffaSKenneth D. Merry * buffer for a maximally sized request to be enqueued. 1104c099cafaSAdrian Chadd * 1105931eeffaSKenneth D. Merry * A transmit request requires a transmit descriptor for each packet 1106931eeffaSKenneth D. Merry * fragment, plus up to 2 entries for "options" (e.g. TSO). 1107c099cafaSAdrian Chadd */ 110889e0f4d2SKip Macy static inline int 110996375eacSRoger Pau Monné xn_tx_slot_available(struct netfront_txq *txq) 111089e0f4d2SKip Macy { 111196375eacSRoger Pau Monné 111296375eacSRoger Pau Monné return (RING_FREE_REQUESTS(&txq->ring) > (MAX_TX_REQ_FRAGS + 2)); 111389e0f4d2SKip Macy } 1114931eeffaSKenneth D. Merry 111589e0f4d2SKip Macy static void 111696375eacSRoger Pau Monné xn_release_tx_bufs(struct netfront_txq *txq) 111789e0f4d2SKip Macy { 111889e0f4d2SKip Macy int i; 111989e0f4d2SKip Macy 112089e0f4d2SKip Macy for (i = 1; i <= NET_TX_RING_SIZE; i++) { 1121931eeffaSKenneth D. Merry struct mbuf *m; 112289e0f4d2SKip Macy 112396375eacSRoger Pau Monné m = txq->mbufs[i]; 1124931eeffaSKenneth D. Merry 1125931eeffaSKenneth D. Merry /* 1126931eeffaSKenneth D. Merry * We assume that no kernel addresses are 1127931eeffaSKenneth D. Merry * less than NET_TX_RING_SIZE. Any entry 1128931eeffaSKenneth D. Merry * in the table that is below this number 1129931eeffaSKenneth D. Merry * must be an index from free-list tracking. 1130931eeffaSKenneth D. Merry */ 1131931eeffaSKenneth D. Merry if (((uintptr_t)m) <= NET_TX_RING_SIZE) 113289e0f4d2SKip Macy continue; 113396375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->grant_ref[i]); 113496375eacSRoger Pau Monné gnttab_release_grant_reference(&txq->gref_head, 113596375eacSRoger Pau Monné txq->grant_ref[i]); 113696375eacSRoger Pau Monné txq->grant_ref[i] = GRANT_REF_INVALID; 113796375eacSRoger Pau Monné add_id_to_freelist(txq->mbufs, i); 113896375eacSRoger Pau Monné txq->mbufs_cnt--; 113996375eacSRoger Pau Monné if (txq->mbufs_cnt < 0) { 11406f9767acSMarius Strobl panic("%s: tx_chain_cnt must be >= 0", __func__); 1141a4ec37f5SAdrian Chadd } 1142dabb3db7SRoger Pau Monné mbuf_release(m); 114389e0f4d2SKip Macy } 114489e0f4d2SKip Macy } 114589e0f4d2SKip Macy 11462568ee67SRoger Pau Monné static struct mbuf * 11472568ee67SRoger Pau Monné xn_alloc_one_rx_buffer(struct netfront_rxq *rxq) 11482568ee67SRoger Pau Monné { 11492568ee67SRoger Pau Monné struct mbuf *m; 11502568ee67SRoger Pau Monné 11512568ee67SRoger Pau Monné m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 11522568ee67SRoger Pau Monné if (m == NULL) 11532568ee67SRoger Pau Monné return NULL; 11542568ee67SRoger Pau Monné m->m_len = m->m_pkthdr.len = MJUMPAGESIZE; 11552568ee67SRoger Pau Monné 11562568ee67SRoger Pau Monné return (m); 11572568ee67SRoger Pau Monné } 11582568ee67SRoger Pau Monné 115989e0f4d2SKip Macy static void 116096375eacSRoger Pau Monné xn_alloc_rx_buffers(struct netfront_rxq *rxq) 116189e0f4d2SKip Macy { 116289e0f4d2SKip Macy RING_IDX req_prod; 11632568ee67SRoger Pau Monné int notify; 11642568ee67SRoger Pau Monné 11652568ee67SRoger Pau Monné XN_RX_LOCK_ASSERT(rxq); 11662568ee67SRoger Pau Monné 11672568ee67SRoger Pau Monné if (__predict_false(rxq->info->carrier == 0)) 11682568ee67SRoger Pau Monné return; 11692568ee67SRoger Pau Monné 11702568ee67SRoger Pau Monné for (req_prod = rxq->ring.req_prod_pvt; 11712568ee67SRoger Pau Monné req_prod - rxq->ring.rsp_cons < NET_RX_RING_SIZE; 11722568ee67SRoger Pau Monné req_prod++) { 11732568ee67SRoger Pau Monné struct mbuf *m; 11742568ee67SRoger Pau Monné unsigned short id; 117589e0f4d2SKip Macy grant_ref_t ref; 11762568ee67SRoger Pau Monné struct netif_rx_request *req; 11772568ee67SRoger Pau Monné unsigned long pfn; 117889e0f4d2SKip Macy 11792568ee67SRoger Pau Monné m = xn_alloc_one_rx_buffer(rxq); 11802568ee67SRoger Pau Monné if (m == NULL) 118189e0f4d2SKip Macy break; 118289e0f4d2SKip Macy 11832568ee67SRoger Pau Monné id = xn_rxidx(req_prod); 118489e0f4d2SKip Macy 118596375eacSRoger Pau Monné KASSERT(rxq->mbufs[id] == NULL, ("non-NULL xn_rx_chain")); 11862568ee67SRoger Pau Monné rxq->mbufs[id] = m; 118789e0f4d2SKip Macy 118896375eacSRoger Pau Monné ref = gnttab_claim_grant_reference(&rxq->gref_head); 1189ff662b5cSJustin T. Gibbs KASSERT(ref != GNTTAB_LIST_END, 1190ff662b5cSJustin T. Gibbs ("reserved grant references exhuasted")); 119196375eacSRoger Pau Monné rxq->grant_ref[id] = ref; 119289e0f4d2SKip Macy 11932568ee67SRoger Pau Monné pfn = atop(vtophys(mtod(m, vm_offset_t))); 11942568ee67SRoger Pau Monné req = RING_GET_REQUEST(&rxq->ring, req_prod); 119589e0f4d2SKip Macy 11962568ee67SRoger Pau Monné gnttab_grant_foreign_access_ref(ref, 11972568ee67SRoger Pau Monné xenbus_get_otherend_id(rxq->info->xbdev), pfn, 0); 119889e0f4d2SKip Macy req->id = id; 119989e0f4d2SKip Macy req->gref = ref; 120089e0f4d2SKip Macy } 120189e0f4d2SKip Macy 12022568ee67SRoger Pau Monné rxq->ring.req_prod_pvt = req_prod; 120389e0f4d2SKip Macy 12042568ee67SRoger Pau Monné /* Not enough requests? Try again later. */ 12052568ee67SRoger Pau Monné if (req_prod - rxq->ring.rsp_cons < NET_RX_SLOTS_MIN) { 1206bf7b50dbSRoger Pau Monné callout_reset_curcpu(&rxq->rx_refill, hz/10, 1207bf7b50dbSRoger Pau Monné xn_alloc_rx_buffers_callout, rxq); 12082568ee67SRoger Pau Monné return; 12092568ee67SRoger Pau Monné } 12102568ee67SRoger Pau Monné 12112568ee67SRoger Pau Monné wmb(); /* barrier so backend seens requests */ 12122568ee67SRoger Pau Monné 121396375eacSRoger Pau Monné RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&rxq->ring, notify); 121489e0f4d2SKip Macy if (notify) 121596375eacSRoger Pau Monné xen_intr_signal(rxq->xen_intr_handle); 121689e0f4d2SKip Macy } 121789e0f4d2SKip Macy 12182568ee67SRoger Pau Monné static void xn_alloc_rx_buffers_callout(void *arg) 12192568ee67SRoger Pau Monné { 12202568ee67SRoger Pau Monné struct netfront_rxq *rxq; 12212568ee67SRoger Pau Monné 12222568ee67SRoger Pau Monné rxq = (struct netfront_rxq *)arg; 12232568ee67SRoger Pau Monné XN_RX_LOCK(rxq); 12242568ee67SRoger Pau Monné xn_alloc_rx_buffers(rxq); 12252568ee67SRoger Pau Monné XN_RX_UNLOCK(rxq); 12262568ee67SRoger Pau Monné } 12272568ee67SRoger Pau Monné 122889e0f4d2SKip Macy static void 122996375eacSRoger Pau Monné xn_release_rx_bufs(struct netfront_rxq *rxq) 123096375eacSRoger Pau Monné { 123196375eacSRoger Pau Monné int i, ref; 123296375eacSRoger Pau Monné struct mbuf *m; 123396375eacSRoger Pau Monné 123496375eacSRoger Pau Monné for (i = 0; i < NET_RX_RING_SIZE; i++) { 123596375eacSRoger Pau Monné m = rxq->mbufs[i]; 123696375eacSRoger Pau Monné 123796375eacSRoger Pau Monné if (m == NULL) 123896375eacSRoger Pau Monné continue; 123996375eacSRoger Pau Monné 124096375eacSRoger Pau Monné ref = rxq->grant_ref[i]; 124196375eacSRoger Pau Monné if (ref == GRANT_REF_INVALID) 124296375eacSRoger Pau Monné continue; 124396375eacSRoger Pau Monné 124496375eacSRoger Pau Monné gnttab_end_foreign_access_ref(ref); 124596375eacSRoger Pau Monné gnttab_release_grant_reference(&rxq->gref_head, ref); 124696375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 124796375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 124896375eacSRoger Pau Monné m_freem(m); 124996375eacSRoger Pau Monné } 125096375eacSRoger Pau Monné } 125196375eacSRoger Pau Monné 125296375eacSRoger Pau Monné static void 125396375eacSRoger Pau Monné xn_rxeof(struct netfront_rxq *rxq) 125489e0f4d2SKip Macy { 125502f3b17fSJustin Hibbits if_t ifp; 125696375eacSRoger Pau Monné struct netfront_info *np = rxq->info; 12573778878dSRoger Pau Monné #if (defined(INET) || defined(INET6)) 125896375eacSRoger Pau Monné struct lro_ctrl *lro = &rxq->lro; 12593778878dSRoger Pau Monné #endif 126089e0f4d2SKip Macy struct netfront_rx_info rinfo; 126189e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo.rx; 126289e0f4d2SKip Macy struct netif_extra_info *extras = rinfo.extras; 126389e0f4d2SKip Macy RING_IDX i, rp; 126489e0f4d2SKip Macy struct mbuf *m; 126596375eacSRoger Pau Monné struct mbufq mbufq_rxq, mbufq_errq; 1266d0f3a8b9SRoger Pau Monné int err, work_to_do; 126789e0f4d2SKip Macy 126896375eacSRoger Pau Monné XN_RX_LOCK_ASSERT(rxq); 1269bf319173SRoger Pau Monné 127089e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 127189e0f4d2SKip Macy return; 127289e0f4d2SKip Macy 1273c578b6acSGleb Smirnoff /* XXX: there should be some sane limit. */ 127496375eacSRoger Pau Monné mbufq_init(&mbufq_errq, INT_MAX); 127596375eacSRoger Pau Monné mbufq_init(&mbufq_rxq, INT_MAX); 127689e0f4d2SKip Macy 127789e0f4d2SKip Macy ifp = np->xn_ifp; 127889e0f4d2SKip Macy 1279bf319173SRoger Pau Monné do { 128096375eacSRoger Pau Monné rp = rxq->ring.sring->rsp_prod; 128189e0f4d2SKip Macy rmb(); /* Ensure we see queued responses up to 'rp'. */ 128289e0f4d2SKip Macy 128396375eacSRoger Pau Monné i = rxq->ring.rsp_cons; 128489e0f4d2SKip Macy while ((i != rp)) { 128596375eacSRoger Pau Monné memcpy(rx, RING_GET_RESPONSE(&rxq->ring, i), sizeof(*rx)); 128689e0f4d2SKip Macy memset(extras, 0, sizeof(rinfo.extras)); 128789e0f4d2SKip Macy 128883b92f6eSKip Macy m = NULL; 128996375eacSRoger Pau Monné err = xn_get_responses(rxq, &rinfo, rp, &i, &m); 129089e0f4d2SKip Macy 129176acc41fSJustin T. Gibbs if (__predict_false(err)) { 129283b92f6eSKip Macy if (m) 129396375eacSRoger Pau Monné (void )mbufq_enqueue(&mbufq_errq, m); 1294b2fd6999SRoger Pau Monné if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 129589e0f4d2SKip Macy continue; 129689e0f4d2SKip Macy } 129789e0f4d2SKip Macy 129889e0f4d2SKip Macy m->m_pkthdr.rcvif = ifp; 129989e0f4d2SKip Macy if (rx->flags & NETRXF_data_validated) { 130089e0f4d2SKip Macy /* 1301a81683c3SRoger Pau Monné * According to mbuf(9) the correct way to tell 1302a81683c3SRoger Pau Monné * the stack that the checksum of an inbound 1303a81683c3SRoger Pau Monné * packet is correct, without it actually being 1304a81683c3SRoger Pau Monné * present (because the underlying interface 1305a81683c3SRoger Pau Monné * doesn't provide it), is to set the 1306a81683c3SRoger Pau Monné * CSUM_DATA_VALID and CSUM_PSEUDO_HDR flags, 1307a81683c3SRoger Pau Monné * and the csum_data field to 0xffff. 130889e0f4d2SKip Macy */ 1309a81683c3SRoger Pau Monné m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID 131089e0f4d2SKip Macy | CSUM_PSEUDO_HDR); 131189e0f4d2SKip Macy m->m_pkthdr.csum_data = 0xffff; 131289e0f4d2SKip Macy } 1313d9a66b6dSRoger Pau Monné if ((rx->flags & NETRXF_extra_info) != 0 && 1314d9a66b6dSRoger Pau Monné (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type == 1315d9a66b6dSRoger Pau Monné XEN_NETIF_EXTRA_TYPE_GSO)) { 1316d9a66b6dSRoger Pau Monné m->m_pkthdr.tso_segsz = 1317d9a66b6dSRoger Pau Monné extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].u.gso.size; 1318d9a66b6dSRoger Pau Monné m->m_pkthdr.csum_flags |= CSUM_TSO; 1319d9a66b6dSRoger Pau Monné } 132089e0f4d2SKip Macy 132196375eacSRoger Pau Monné (void )mbufq_enqueue(&mbufq_rxq, m); 132289e0f4d2SKip Macy } 132389e0f4d2SKip Macy 1324bf319173SRoger Pau Monné rxq->ring.rsp_cons = i; 132589e0f4d2SKip Macy 1326bf319173SRoger Pau Monné xn_alloc_rx_buffers(rxq); 1327bf319173SRoger Pau Monné 1328bf319173SRoger Pau Monné RING_FINAL_CHECK_FOR_RESPONSES(&rxq->ring, work_to_do); 1329bf319173SRoger Pau Monné } while (work_to_do); 1330bf319173SRoger Pau Monné 1331bf319173SRoger Pau Monné mbufq_drain(&mbufq_errq); 133289e0f4d2SKip Macy /* 133389e0f4d2SKip Macy * Process all the mbufs after the remapping is complete. 133489e0f4d2SKip Macy * Break the mbuf chain first though. 133589e0f4d2SKip Macy */ 133696375eacSRoger Pau Monné while ((m = mbufq_dequeue(&mbufq_rxq)) != NULL) { 1337c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 133808c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 133912678024SDoug Rabson /* Use LRO if possible */ 134002f3b17fSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_LRO) == 0 || 134112678024SDoug Rabson lro->lro_cnt == 0 || tcp_lro_rx(lro, m, 0)) { 134212678024SDoug Rabson /* 134312678024SDoug Rabson * If LRO fails, pass up to the stack 134412678024SDoug Rabson * directly. 134512678024SDoug Rabson */ 134602f3b17fSJustin Hibbits if_input(ifp, m); 134712678024SDoug Rabson } 134812678024SDoug Rabson #else 134902f3b17fSJustin Hibbits if_input(ifp, m); 135012678024SDoug Rabson #endif 135189e0f4d2SKip Macy } 135289e0f4d2SKip Macy 135308c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 135412678024SDoug Rabson /* 135512678024SDoug Rabson * Flush any outstanding LRO work 135612678024SDoug Rabson */ 13576dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro); 135812678024SDoug Rabson #endif 135989e0f4d2SKip Macy } 136089e0f4d2SKip Macy 136189e0f4d2SKip Macy static void 136296375eacSRoger Pau Monné xn_txeof(struct netfront_txq *txq) 136389e0f4d2SKip Macy { 136489e0f4d2SKip Macy RING_IDX i, prod; 136589e0f4d2SKip Macy unsigned short id; 136602f3b17fSJustin Hibbits if_t ifp; 136712678024SDoug Rabson netif_tx_response_t *txr; 136889e0f4d2SKip Macy struct mbuf *m; 136996375eacSRoger Pau Monné struct netfront_info *np = txq->info; 137089e0f4d2SKip Macy 137196375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 137289e0f4d2SKip Macy 137389e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 137489e0f4d2SKip Macy return; 137589e0f4d2SKip Macy 137689e0f4d2SKip Macy ifp = np->xn_ifp; 137789e0f4d2SKip Macy 137889e0f4d2SKip Macy do { 137996375eacSRoger Pau Monné prod = txq->ring.sring->rsp_prod; 138089e0f4d2SKip Macy rmb(); /* Ensure we see responses up to 'rp'. */ 138189e0f4d2SKip Macy 138296375eacSRoger Pau Monné for (i = txq->ring.rsp_cons; i != prod; i++) { 138396375eacSRoger Pau Monné txr = RING_GET_RESPONSE(&txq->ring, i); 138412678024SDoug Rabson if (txr->status == NETIF_RSP_NULL) 138512678024SDoug Rabson continue; 138612678024SDoug Rabson 1387931eeffaSKenneth D. Merry if (txr->status != NETIF_RSP_OKAY) { 1388931eeffaSKenneth D. Merry printf("%s: WARNING: response is %d!\n", 1389931eeffaSKenneth D. Merry __func__, txr->status); 1390931eeffaSKenneth D. Merry } 139112678024SDoug Rabson id = txr->id; 139296375eacSRoger Pau Monné m = txq->mbufs[id]; 139396375eacSRoger Pau Monné KASSERT(m != NULL, ("mbuf not found in chain")); 1394931eeffaSKenneth D. Merry KASSERT((uintptr_t)m > NET_TX_RING_SIZE, 1395931eeffaSKenneth D. Merry ("mbuf already on the free list, but we're " 1396931eeffaSKenneth D. Merry "trying to free it again!")); 13972d8fae98SAdrian Chadd M_ASSERTVALID(m); 139889e0f4d2SKip Macy 139976acc41fSJustin T. Gibbs if (__predict_false(gnttab_query_foreign_access( 140096375eacSRoger Pau Monné txq->grant_ref[id]) != 0)) { 14016f9767acSMarius Strobl panic("%s: grant id %u still in use by the " 14026f9767acSMarius Strobl "backend", __func__, id); 140389e0f4d2SKip Macy } 140496375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->grant_ref[id]); 140589e0f4d2SKip Macy gnttab_release_grant_reference( 140696375eacSRoger Pau Monné &txq->gref_head, txq->grant_ref[id]); 140796375eacSRoger Pau Monné txq->grant_ref[id] = GRANT_REF_INVALID; 140889e0f4d2SKip Macy 140996375eacSRoger Pau Monné txq->mbufs[id] = NULL; 141096375eacSRoger Pau Monné add_id_to_freelist(txq->mbufs, id); 141196375eacSRoger Pau Monné txq->mbufs_cnt--; 1412dabb3db7SRoger Pau Monné mbuf_release(m); 141396375eacSRoger Pau Monné /* Only mark the txq active if we've freed up at least one slot to try */ 141402f3b17fSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 141589e0f4d2SKip Macy } 141696375eacSRoger Pau Monné txq->ring.rsp_cons = prod; 141789e0f4d2SKip Macy 141889e0f4d2SKip Macy /* 141989e0f4d2SKip Macy * Set a new event, then check for race with update of 142089e0f4d2SKip Macy * tx_cons. Note that it is essential to schedule a 142189e0f4d2SKip Macy * callback, no matter how few buffers are pending. Even if 142289e0f4d2SKip Macy * there is space in the transmit ring, higher layers may 142389e0f4d2SKip Macy * be blocked because too much data is outstanding: in such 142489e0f4d2SKip Macy * cases notification from Xen is likely to be the only kick 142589e0f4d2SKip Macy * that we'll get. 142689e0f4d2SKip Macy */ 142796375eacSRoger Pau Monné txq->ring.sring->rsp_event = 142896375eacSRoger Pau Monné prod + ((txq->ring.sring->req_prod - prod) >> 1) + 1; 142989e0f4d2SKip Macy 143089e0f4d2SKip Macy mb(); 143196375eacSRoger Pau Monné } while (prod != txq->ring.sring->rsp_prod); 143289e0f4d2SKip Macy 143396375eacSRoger Pau Monné if (txq->full && 143496375eacSRoger Pau Monné ((txq->ring.sring->req_prod - prod) < NET_TX_RING_SIZE)) { 143596375eacSRoger Pau Monné txq->full = false; 1436da695b05SRoger Pau Monné xn_txq_start(txq); 143789e0f4d2SKip Macy } 143889e0f4d2SKip Macy } 143989e0f4d2SKip Macy 144089e0f4d2SKip Macy static void 144196375eacSRoger Pau Monné xn_intr(void *xsc) 144296375eacSRoger Pau Monné { 144396375eacSRoger Pau Monné struct netfront_txq *txq = xsc; 144496375eacSRoger Pau Monné struct netfront_info *np = txq->info; 144596375eacSRoger Pau Monné struct netfront_rxq *rxq = &np->rxq[txq->id]; 144696375eacSRoger Pau Monné 144796375eacSRoger Pau Monné /* kick both tx and rx */ 144896375eacSRoger Pau Monné xn_rxq_intr(rxq); 144996375eacSRoger Pau Monné xn_txq_intr(txq); 145096375eacSRoger Pau Monné } 145196375eacSRoger Pau Monné 145296375eacSRoger Pau Monné static void 145396375eacSRoger Pau Monné xn_move_rx_slot(struct netfront_rxq *rxq, struct mbuf *m, 145496375eacSRoger Pau Monné grant_ref_t ref) 145596375eacSRoger Pau Monné { 145696375eacSRoger Pau Monné int new = xn_rxidx(rxq->ring.req_prod_pvt); 145796375eacSRoger Pau Monné 145896375eacSRoger Pau Monné KASSERT(rxq->mbufs[new] == NULL, ("mbufs != NULL")); 145996375eacSRoger Pau Monné rxq->mbufs[new] = m; 146096375eacSRoger Pau Monné rxq->grant_ref[new] = ref; 146196375eacSRoger Pau Monné RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->id = new; 146296375eacSRoger Pau Monné RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->gref = ref; 146396375eacSRoger Pau Monné rxq->ring.req_prod_pvt++; 146496375eacSRoger Pau Monné } 146596375eacSRoger Pau Monné 146696375eacSRoger Pau Monné static int 146796375eacSRoger Pau Monné xn_get_extras(struct netfront_rxq *rxq, 1468931eeffaSKenneth D. Merry struct netif_extra_info *extras, RING_IDX rp, RING_IDX *cons) 146989e0f4d2SKip Macy { 147089e0f4d2SKip Macy struct netif_extra_info *extra; 147189e0f4d2SKip Macy 147289e0f4d2SKip Macy int err = 0; 147389e0f4d2SKip Macy 147489e0f4d2SKip Macy do { 147589e0f4d2SKip Macy struct mbuf *m; 147689e0f4d2SKip Macy grant_ref_t ref; 147789e0f4d2SKip Macy 147876acc41fSJustin T. Gibbs if (__predict_false(*cons + 1 == rp)) { 1479931eeffaSKenneth D. Merry err = EINVAL; 148089e0f4d2SKip Macy break; 148189e0f4d2SKip Macy } 148289e0f4d2SKip Macy 148389e0f4d2SKip Macy extra = (struct netif_extra_info *) 148496375eacSRoger Pau Monné RING_GET_RESPONSE(&rxq->ring, ++(*cons)); 148589e0f4d2SKip Macy 148676acc41fSJustin T. Gibbs if (__predict_false(!extra->type || 148789e0f4d2SKip Macy extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { 1488931eeffaSKenneth D. Merry err = EINVAL; 148989e0f4d2SKip Macy } else { 149089e0f4d2SKip Macy memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); 149189e0f4d2SKip Macy } 149289e0f4d2SKip Macy 149396375eacSRoger Pau Monné m = xn_get_rx_mbuf(rxq, *cons); 149496375eacSRoger Pau Monné ref = xn_get_rx_ref(rxq, *cons); 149596375eacSRoger Pau Monné xn_move_rx_slot(rxq, m, ref); 149689e0f4d2SKip Macy } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); 149789e0f4d2SKip Macy 149889e0f4d2SKip Macy return err; 149989e0f4d2SKip Macy } 150089e0f4d2SKip Macy 150189e0f4d2SKip Macy static int 150296375eacSRoger Pau Monné xn_get_responses(struct netfront_rxq *rxq, 1503931eeffaSKenneth D. Merry struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, 1504d0f3a8b9SRoger Pau Monné struct mbuf **list) 150589e0f4d2SKip Macy { 150689e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo->rx; 150789e0f4d2SKip Macy struct netif_extra_info *extras = rinfo->extras; 150883b92f6eSKip Macy struct mbuf *m, *m0, *m_prev; 150996375eacSRoger Pau Monné grant_ref_t ref = xn_get_rx_ref(rxq, *cons); 151089e0f4d2SKip Macy int frags = 1; 151189e0f4d2SKip Macy int err = 0; 1512e7236a7dSMateusz Guzik u_long ret __diagused; 151389e0f4d2SKip Macy 151496375eacSRoger Pau Monné m0 = m = m_prev = xn_get_rx_mbuf(rxq, *cons); 151583b92f6eSKip Macy 151689e0f4d2SKip Macy if (rx->flags & NETRXF_extra_info) { 151796375eacSRoger Pau Monné err = xn_get_extras(rxq, extras, rp, cons); 151889e0f4d2SKip Macy } 151989e0f4d2SKip Macy 152083b92f6eSKip Macy if (m0 != NULL) { 152183b92f6eSKip Macy m0->m_pkthdr.len = 0; 152283b92f6eSKip Macy m0->m_next = NULL; 152383b92f6eSKip Macy } 152483b92f6eSKip Macy 152589e0f4d2SKip Macy for (;;) { 152683b92f6eSKip Macy #if 0 1527227ca257SKip Macy DPRINTK("rx->status=%hd rx->offset=%hu frags=%u\n", 152883b92f6eSKip Macy rx->status, rx->offset, frags); 152983b92f6eSKip Macy #endif 153076acc41fSJustin T. Gibbs if (__predict_false(rx->status < 0 || 153189e0f4d2SKip Macy rx->offset + rx->status > PAGE_SIZE)) { 153296375eacSRoger Pau Monné xn_move_rx_slot(rxq, m, ref); 1533931eeffaSKenneth D. Merry if (m0 == m) 1534931eeffaSKenneth D. Merry m0 = NULL; 1535931eeffaSKenneth D. Merry m = NULL; 1536931eeffaSKenneth D. Merry err = EINVAL; 1537931eeffaSKenneth D. Merry goto next_skip_queue; 153889e0f4d2SKip Macy } 153989e0f4d2SKip Macy 154089e0f4d2SKip Macy /* 154189e0f4d2SKip Macy * This definitely indicates a bug, either in this driver or in 154289e0f4d2SKip Macy * the backend driver. In future this should flag the bad 154389e0f4d2SKip Macy * situation to the system controller to reboot the backed. 154489e0f4d2SKip Macy */ 1545ff662b5cSJustin T. Gibbs if (ref == GRANT_REF_INVALID) { 1546ff662b5cSJustin T. Gibbs printf("%s: Bad rx response id %d.\n", __func__, rx->id); 1547931eeffaSKenneth D. Merry err = EINVAL; 154889e0f4d2SKip Macy goto next; 154989e0f4d2SKip Macy } 155089e0f4d2SKip Macy 1551920ba15bSKip Macy ret = gnttab_end_foreign_access_ref(ref); 1552d0f3a8b9SRoger Pau Monné KASSERT(ret, ("Unable to end access to grant references")); 155389e0f4d2SKip Macy 155496375eacSRoger Pau Monné gnttab_release_grant_reference(&rxq->gref_head, ref); 155589e0f4d2SKip Macy 155689e0f4d2SKip Macy next: 15573a539122SAdrian Chadd if (m == NULL) 15583a539122SAdrian Chadd break; 15593a539122SAdrian Chadd 156083b92f6eSKip Macy m->m_len = rx->status; 156183b92f6eSKip Macy m->m_data += rx->offset; 156283b92f6eSKip Macy m0->m_pkthdr.len += rx->status; 156383b92f6eSKip Macy 1564931eeffaSKenneth D. Merry next_skip_queue: 156589e0f4d2SKip Macy if (!(rx->flags & NETRXF_more_data)) 156689e0f4d2SKip Macy break; 156789e0f4d2SKip Macy 1568931eeffaSKenneth D. Merry if (*cons + frags == rp) { 156989e0f4d2SKip Macy if (net_ratelimit()) 157089e0f4d2SKip Macy WPRINTK("Need more frags\n"); 1571931eeffaSKenneth D. Merry err = ENOENT; 1572931eeffaSKenneth D. Merry printf("%s: cons %u frags %u rp %u, not enough frags\n", 1573931eeffaSKenneth D. Merry __func__, *cons, frags, rp); 157489e0f4d2SKip Macy break; 157589e0f4d2SKip Macy } 1576931eeffaSKenneth D. Merry /* 1577931eeffaSKenneth D. Merry * Note that m can be NULL, if rx->status < 0 or if 1578931eeffaSKenneth D. Merry * rx->offset + rx->status > PAGE_SIZE above. 1579931eeffaSKenneth D. Merry */ 158083b92f6eSKip Macy m_prev = m; 158189e0f4d2SKip Macy 158296375eacSRoger Pau Monné rx = RING_GET_RESPONSE(&rxq->ring, *cons + frags); 158396375eacSRoger Pau Monné m = xn_get_rx_mbuf(rxq, *cons + frags); 158483b92f6eSKip Macy 1585931eeffaSKenneth D. Merry /* 1586931eeffaSKenneth D. Merry * m_prev == NULL can happen if rx->status < 0 or if 1587931eeffaSKenneth D. Merry * rx->offset + * rx->status > PAGE_SIZE above. 1588931eeffaSKenneth D. Merry */ 1589931eeffaSKenneth D. Merry if (m_prev != NULL) 159083b92f6eSKip Macy m_prev->m_next = m; 1591931eeffaSKenneth D. Merry 1592931eeffaSKenneth D. Merry /* 1593931eeffaSKenneth D. Merry * m0 can be NULL if rx->status < 0 or if * rx->offset + 1594931eeffaSKenneth D. Merry * rx->status > PAGE_SIZE above. 1595931eeffaSKenneth D. Merry */ 1596931eeffaSKenneth D. Merry if (m0 == NULL) 1597931eeffaSKenneth D. Merry m0 = m; 159883b92f6eSKip Macy m->m_next = NULL; 159996375eacSRoger Pau Monné ref = xn_get_rx_ref(rxq, *cons + frags); 160089e0f4d2SKip Macy frags++; 160189e0f4d2SKip Macy } 160283b92f6eSKip Macy *list = m0; 1603931eeffaSKenneth D. Merry *cons += frags; 160489e0f4d2SKip Macy 16058577146eSJustin T. Gibbs return (err); 160689e0f4d2SKip Macy } 160789e0f4d2SKip Macy 1608931eeffaSKenneth D. Merry /** 1609931eeffaSKenneth D. Merry * Given an mbuf chain, make sure we have enough room and then push 1610931eeffaSKenneth D. Merry * it onto the transmit ring. 1611931eeffaSKenneth D. Merry */ 1612931eeffaSKenneth D. Merry static int 161396375eacSRoger Pau Monné xn_assemble_tx_request(struct netfront_txq *txq, struct mbuf *m_head) 1614931eeffaSKenneth D. Merry { 161596375eacSRoger Pau Monné struct netfront_info *np = txq->info; 161602f3b17fSJustin Hibbits if_t ifp = np->xn_ifp; 1617dabb3db7SRoger Pau Monné int otherend_id, error, nfrags; 1618dabb3db7SRoger Pau Monné bus_dma_segment_t *segs = txq->segs; 1619dabb3db7SRoger Pau Monné struct mbuf_xennet *tag; 1620dabb3db7SRoger Pau Monné bus_dmamap_t map; 1621dabb3db7SRoger Pau Monné unsigned int i; 1622931eeffaSKenneth D. Merry 1623dabb3db7SRoger Pau Monné KASSERT(!SLIST_EMPTY(&txq->tags), ("no tags available")); 1624dabb3db7SRoger Pau Monné tag = SLIST_FIRST(&txq->tags); 1625dabb3db7SRoger Pau Monné SLIST_REMOVE_HEAD(&txq->tags, next); 1626dabb3db7SRoger Pau Monné KASSERT(tag->count == 0, ("tag already in-use")); 1627dabb3db7SRoger Pau Monné map = tag->dma_map; 1628dabb3db7SRoger Pau Monné error = bus_dmamap_load_mbuf_sg(np->dma_tag, map, m_head, segs, 1629dabb3db7SRoger Pau Monné &nfrags, 0); 1630dabb3db7SRoger Pau Monné if (error == EFBIG || nfrags > np->maxfrags) { 1631dabb3db7SRoger Pau Monné struct mbuf *m; 1632931eeffaSKenneth D. Merry 1633dabb3db7SRoger Pau Monné bus_dmamap_unload(np->dma_tag, map); 1634c6499eccSGleb Smirnoff m = m_defrag(m_head, M_NOWAIT); 163512678024SDoug Rabson if (!m) { 1636931eeffaSKenneth D. Merry /* 1637931eeffaSKenneth D. Merry * Defrag failed, so free the mbuf and 1638931eeffaSKenneth D. Merry * therefore drop the packet. 1639931eeffaSKenneth D. Merry */ 1640dabb3db7SRoger Pau Monné SLIST_INSERT_HEAD(&txq->tags, tag, next); 164112678024SDoug Rabson m_freem(m_head); 1642931eeffaSKenneth D. Merry return (EMSGSIZE); 164312678024SDoug Rabson } 164412678024SDoug Rabson m_head = m; 1645dabb3db7SRoger Pau Monné error = bus_dmamap_load_mbuf_sg(np->dma_tag, map, m_head, segs, 1646dabb3db7SRoger Pau Monné &nfrags, 0); 1647dabb3db7SRoger Pau Monné if (error != 0 || nfrags > np->maxfrags) { 1648dabb3db7SRoger Pau Monné bus_dmamap_unload(np->dma_tag, map); 1649dabb3db7SRoger Pau Monné SLIST_INSERT_HEAD(&txq->tags, tag, next); 1650dabb3db7SRoger Pau Monné m_freem(m_head); 1651dabb3db7SRoger Pau Monné return (error ?: EFBIG); 1652dabb3db7SRoger Pau Monné } 1653dabb3db7SRoger Pau Monné } else if (error != 0) { 1654dabb3db7SRoger Pau Monné SLIST_INSERT_HEAD(&txq->tags, tag, next); 1655dabb3db7SRoger Pau Monné m_freem(m_head); 1656dabb3db7SRoger Pau Monné return (error); 165712678024SDoug Rabson } 165889e0f4d2SKip Macy 1659931eeffaSKenneth D. Merry /** 1660931eeffaSKenneth D. Merry * The FreeBSD TCP stack, with TSO enabled, can produce a chain 1661931eeffaSKenneth D. Merry * of mbufs longer than Linux can handle. Make sure we don't 1662931eeffaSKenneth D. Merry * pass a too-long chain over to the other side by dropping the 1663931eeffaSKenneth D. Merry * packet. It doesn't look like there is currently a way to 1664931eeffaSKenneth D. Merry * tell the TCP stack to generate a shorter chain of packets. 16653fb28bbbSAdrian Chadd */ 1666931eeffaSKenneth D. Merry if (nfrags > MAX_TX_REQ_FRAGS) { 1667ff662b5cSJustin T. Gibbs #ifdef DEBUG 1668ff662b5cSJustin T. Gibbs printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback " 1669ff662b5cSJustin T. Gibbs "won't be able to handle it, dropping\n", 1670ff662b5cSJustin T. Gibbs __func__, nfrags, MAX_TX_REQ_FRAGS); 1671ff662b5cSJustin T. Gibbs #endif 1672dabb3db7SRoger Pau Monné SLIST_INSERT_HEAD(&txq->tags, tag, next); 1673dabb3db7SRoger Pau Monné bus_dmamap_unload(np->dma_tag, map); 1674931eeffaSKenneth D. Merry m_freem(m_head); 1675931eeffaSKenneth D. Merry return (EMSGSIZE); 1676a4ec37f5SAdrian Chadd } 1677a4ec37f5SAdrian Chadd 16783fb28bbbSAdrian Chadd /* 1679931eeffaSKenneth D. Merry * This check should be redundant. We've already verified that we 1680931eeffaSKenneth D. Merry * have enough slots in the ring to handle a packet of maximum 1681931eeffaSKenneth D. Merry * size, and that our packet is less than the maximum size. Keep 1682931eeffaSKenneth D. Merry * it in here as an assert for now just to make certain that 168396375eacSRoger Pau Monné * chain_cnt is accurate. 16843fb28bbbSAdrian Chadd */ 168596375eacSRoger Pau Monné KASSERT((txq->mbufs_cnt + nfrags) <= NET_TX_RING_SIZE, 168696375eacSRoger Pau Monné ("%s: chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE " 168796375eacSRoger Pau Monné "(%d)!", __func__, (int) txq->mbufs_cnt, 1688931eeffaSKenneth D. Merry (int) nfrags, (int) NET_TX_RING_SIZE)); 1689a4ec37f5SAdrian Chadd 169089e0f4d2SKip Macy /* 169189e0f4d2SKip Macy * Start packing the mbufs in this chain into 169289e0f4d2SKip Macy * the fragment pointers. Stop when we run out 169389e0f4d2SKip Macy * of fragments or hit the end of the mbuf chain. 169489e0f4d2SKip Macy */ 169596375eacSRoger Pau Monné otherend_id = xenbus_get_otherend_id(np->xbdev); 1696dabb3db7SRoger Pau Monné m_tag_prepend(m_head, &tag->tag); 1697dabb3db7SRoger Pau Monné for (i = 0; i < nfrags; i++) { 1698931eeffaSKenneth D. Merry netif_tx_request_t *tx; 1699931eeffaSKenneth D. Merry uintptr_t id; 1700931eeffaSKenneth D. Merry grant_ref_t ref; 1701931eeffaSKenneth D. Merry u_long mfn; /* XXX Wrong type? */ 1702931eeffaSKenneth D. Merry 170396375eacSRoger Pau Monné tx = RING_GET_REQUEST(&txq->ring, txq->ring.req_prod_pvt); 170496375eacSRoger Pau Monné id = get_id_from_freelist(txq->mbufs); 1705a4ec37f5SAdrian Chadd if (id == 0) 17066f9767acSMarius Strobl panic("%s: was allocated the freelist head!\n", 17076f9767acSMarius Strobl __func__); 170896375eacSRoger Pau Monné txq->mbufs_cnt++; 170996375eacSRoger Pau Monné if (txq->mbufs_cnt > NET_TX_RING_SIZE) 17106f9767acSMarius Strobl panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n", 17116f9767acSMarius Strobl __func__); 1712dabb3db7SRoger Pau Monné mbuf_grab(m_head); 1713dabb3db7SRoger Pau Monné txq->mbufs[id] = m_head; 171489e0f4d2SKip Macy tx->id = id; 171596375eacSRoger Pau Monné ref = gnttab_claim_grant_reference(&txq->gref_head); 171689e0f4d2SKip Macy KASSERT((short)ref >= 0, ("Negative ref")); 1717dabb3db7SRoger Pau Monné mfn = atop(segs[i].ds_addr); 171823dc5621SKip Macy gnttab_grant_foreign_access_ref(ref, otherend_id, 171989e0f4d2SKip Macy mfn, GNTMAP_readonly); 172096375eacSRoger Pau Monné tx->gref = txq->grant_ref[id] = ref; 1721dabb3db7SRoger Pau Monné tx->offset = segs[i].ds_addr & PAGE_MASK; 1722dabb3db7SRoger Pau Monné KASSERT(tx->offset + segs[i].ds_len <= PAGE_SIZE, 1723dabb3db7SRoger Pau Monné ("mbuf segment crosses a page boundary")); 172489e0f4d2SKip Macy tx->flags = 0; 1725dabb3db7SRoger Pau Monné if (i == 0) { 172612678024SDoug Rabson /* 172712678024SDoug Rabson * The first fragment has the entire packet 172812678024SDoug Rabson * size, subsequent fragments have just the 172912678024SDoug Rabson * fragment size. The backend works out the 173012678024SDoug Rabson * true size of the first fragment by 173112678024SDoug Rabson * subtracting the sizes of the other 173212678024SDoug Rabson * fragments. 173312678024SDoug Rabson */ 1734dabb3db7SRoger Pau Monné tx->size = m_head->m_pkthdr.len; 173589e0f4d2SKip Macy 173612678024SDoug Rabson /* 1737931eeffaSKenneth D. Merry * The first fragment contains the checksum flags 1738931eeffaSKenneth D. Merry * and is optionally followed by extra data for 1739931eeffaSKenneth D. Merry * TSO etc. 1740931eeffaSKenneth D. Merry */ 1741931eeffaSKenneth D. Merry /** 1742931eeffaSKenneth D. Merry * CSUM_TSO requires checksum offloading. 1743931eeffaSKenneth D. Merry * Some versions of FreeBSD fail to 1744931eeffaSKenneth D. Merry * set CSUM_TCP in the CSUM_TSO case, 1745931eeffaSKenneth D. Merry * so we have to test for CSUM_TSO 1746931eeffaSKenneth D. Merry * explicitly. 174712678024SDoug Rabson */ 1748dabb3db7SRoger Pau Monné if (m_head->m_pkthdr.csum_flags 1749931eeffaSKenneth D. Merry & (CSUM_DELAY_DATA | CSUM_TSO)) { 175012678024SDoug Rabson tx->flags |= (NETTXF_csum_blank 175112678024SDoug Rabson | NETTXF_data_validated); 175212678024SDoug Rabson } 1753dabb3db7SRoger Pau Monné if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { 175412678024SDoug Rabson struct netif_extra_info *gso = 175512678024SDoug Rabson (struct netif_extra_info *) 175696375eacSRoger Pau Monné RING_GET_REQUEST(&txq->ring, 175796375eacSRoger Pau Monné ++txq->ring.req_prod_pvt); 175889e0f4d2SKip Macy 175912678024SDoug Rabson tx->flags |= NETTXF_extra_info; 176089e0f4d2SKip Macy 1761dabb3db7SRoger Pau Monné gso->u.gso.size = m_head->m_pkthdr.tso_segsz; 176212678024SDoug Rabson gso->u.gso.type = 176312678024SDoug Rabson XEN_NETIF_GSO_TYPE_TCPV4; 176412678024SDoug Rabson gso->u.gso.pad = 0; 176512678024SDoug Rabson gso->u.gso.features = 0; 176612678024SDoug Rabson 176712678024SDoug Rabson gso->type = XEN_NETIF_EXTRA_TYPE_GSO; 176812678024SDoug Rabson gso->flags = 0; 176912678024SDoug Rabson } 177012678024SDoug Rabson } else { 1771dabb3db7SRoger Pau Monné tx->size = segs[i].ds_len; 177212678024SDoug Rabson } 1773dabb3db7SRoger Pau Monné if (i != nfrags - 1) 177412678024SDoug Rabson tx->flags |= NETTXF_more_data; 177512678024SDoug Rabson 177696375eacSRoger Pau Monné txq->ring.req_prod_pvt++; 1777931eeffaSKenneth D. Merry } 1778dabb3db7SRoger Pau Monné bus_dmamap_sync(np->dma_tag, map, BUS_DMASYNC_PREWRITE); 177912678024SDoug Rabson BPF_MTAP(ifp, m_head); 178012678024SDoug Rabson 1781b2fd6999SRoger Pau Monné if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 1782b2fd6999SRoger Pau Monné if_inc_counter(ifp, IFCOUNTER_OBYTES, m_head->m_pkthdr.len); 1783b2fd6999SRoger Pau Monné if (m_head->m_flags & M_MCAST) 1784b2fd6999SRoger Pau Monné if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 178596375eacSRoger Pau Monné 1786b2fd6999SRoger Pau Monné xn_txeof(txq); 1787931eeffaSKenneth D. Merry 1788931eeffaSKenneth D. Merry return (0); 178989e0f4d2SKip Macy } 179089e0f4d2SKip Macy 179189e0f4d2SKip Macy /* equivalent of network_open() in Linux */ 179289e0f4d2SKip Macy static void 179396375eacSRoger Pau Monné xn_ifinit_locked(struct netfront_info *np) 179489e0f4d2SKip Macy { 179502f3b17fSJustin Hibbits if_t ifp; 179696375eacSRoger Pau Monné int i; 179796375eacSRoger Pau Monné struct netfront_rxq *rxq; 179889e0f4d2SKip Macy 179996375eacSRoger Pau Monné XN_LOCK_ASSERT(np); 180089e0f4d2SKip Macy 180196375eacSRoger Pau Monné ifp = np->xn_ifp; 180289e0f4d2SKip Macy 180302f3b17fSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING || !netfront_carrier_ok(np)) 180489e0f4d2SKip Macy return; 180589e0f4d2SKip Macy 180696375eacSRoger Pau Monné xn_stop(np); 180789e0f4d2SKip Macy 180896375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 180996375eacSRoger Pau Monné rxq = &np->rxq[i]; 18102568ee67SRoger Pau Monné XN_RX_LOCK(rxq); 181196375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 181296375eacSRoger Pau Monné rxq->ring.sring->rsp_event = rxq->ring.rsp_cons + 1; 18132568ee67SRoger Pau Monné if (RING_HAS_UNCONSUMED_RESPONSES(&rxq->ring)) 1814da695b05SRoger Pau Monné xn_rxeof(rxq); 18152568ee67SRoger Pau Monné XN_RX_UNLOCK(rxq); 181696375eacSRoger Pau Monné } 181789e0f4d2SKip Macy 181802f3b17fSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 181902f3b17fSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 18200e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_UP); 182189e0f4d2SKip Macy } 182289e0f4d2SKip Macy 182389e0f4d2SKip Macy static void 182489e0f4d2SKip Macy xn_ifinit(void *xsc) 182589e0f4d2SKip Macy { 182689e0f4d2SKip Macy struct netfront_info *sc = xsc; 182789e0f4d2SKip Macy 182889e0f4d2SKip Macy XN_LOCK(sc); 182989e0f4d2SKip Macy xn_ifinit_locked(sc); 183089e0f4d2SKip Macy XN_UNLOCK(sc); 183189e0f4d2SKip Macy } 183289e0f4d2SKip Macy 183389e0f4d2SKip Macy static int 183402f3b17fSJustin Hibbits xn_ioctl(if_t ifp, u_long cmd, caddr_t data) 183589e0f4d2SKip Macy { 183602f3b17fSJustin Hibbits struct netfront_info *sc = if_getsoftc(ifp); 183789e0f4d2SKip Macy struct ifreq *ifr = (struct ifreq *) data; 1838c2d12e5eSRoger Pau Monné device_t dev; 1839a0ae8f04SBjoern A. Zeeb #ifdef INET 184089e0f4d2SKip Macy struct ifaddr *ifa = (struct ifaddr *)data; 1841a0ae8f04SBjoern A. Zeeb #endif 18423c9d5940SRoger Pau Monné int mask, error = 0, reinit; 1843c2d12e5eSRoger Pau Monné 1844c2d12e5eSRoger Pau Monné dev = sc->xbdev; 1845c2d12e5eSRoger Pau Monné 184689e0f4d2SKip Macy switch(cmd) { 184789e0f4d2SKip Macy case SIOCSIFADDR: 1848a0ae8f04SBjoern A. Zeeb #ifdef INET 184989e0f4d2SKip Macy XN_LOCK(sc); 185089e0f4d2SKip Macy if (ifa->ifa_addr->sa_family == AF_INET) { 185102f3b17fSJustin Hibbits if_setflagbits(ifp, IFF_UP, 0); 185202f3b17fSJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) 185389e0f4d2SKip Macy xn_ifinit_locked(sc); 185489e0f4d2SKip Macy arp_ifinit(ifp, ifa); 185589e0f4d2SKip Macy XN_UNLOCK(sc); 185649906218SDoug Rabson } else { 185749906218SDoug Rabson XN_UNLOCK(sc); 1858a0ae8f04SBjoern A. Zeeb #endif 185949906218SDoug Rabson error = ether_ioctl(ifp, cmd, data); 1860a0ae8f04SBjoern A. Zeeb #ifdef INET 186149906218SDoug Rabson } 1862a0ae8f04SBjoern A. Zeeb #endif 186389e0f4d2SKip Macy break; 186489e0f4d2SKip Macy case SIOCSIFMTU: 186502f3b17fSJustin Hibbits if (if_getmtu(ifp) == ifr->ifr_mtu) 1866c74415edSColin Percival break; 1867c74415edSColin Percival 186802f3b17fSJustin Hibbits if_setmtu(ifp, ifr->ifr_mtu); 186902f3b17fSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 187089e0f4d2SKip Macy xn_ifinit(sc); 187189e0f4d2SKip Macy break; 187289e0f4d2SKip Macy case SIOCSIFFLAGS: 187389e0f4d2SKip Macy XN_LOCK(sc); 187402f3b17fSJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 187589e0f4d2SKip Macy /* 187689e0f4d2SKip Macy * If only the state of the PROMISC flag changed, 187789e0f4d2SKip Macy * then just use the 'set promisc mode' command 187889e0f4d2SKip Macy * instead of reinitializing the entire NIC. Doing 187989e0f4d2SKip Macy * a full re-init means reloading the firmware and 188089e0f4d2SKip Macy * waiting for it to start up, which may take a 188189e0f4d2SKip Macy * second or two. 188289e0f4d2SKip Macy */ 188389e0f4d2SKip Macy xn_ifinit_locked(sc); 188489e0f4d2SKip Macy } else { 188502f3b17fSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 188689e0f4d2SKip Macy xn_stop(sc); 188789e0f4d2SKip Macy } 188889e0f4d2SKip Macy } 188902f3b17fSJustin Hibbits sc->xn_if_flags = if_getflags(ifp); 189089e0f4d2SKip Macy XN_UNLOCK(sc); 189189e0f4d2SKip Macy break; 189289e0f4d2SKip Macy case SIOCSIFCAP: 189302f3b17fSJustin Hibbits mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 18943c9d5940SRoger Pau Monné reinit = 0; 18953c9d5940SRoger Pau Monné 189612678024SDoug Rabson if (mask & IFCAP_TXCSUM) { 189702f3b17fSJustin Hibbits if_togglecapenable(ifp, IFCAP_TXCSUM); 189802f3b17fSJustin Hibbits if_togglehwassist(ifp, XN_CSUM_FEATURES); 189912678024SDoug Rabson } 190012678024SDoug Rabson if (mask & IFCAP_TSO4) { 190102f3b17fSJustin Hibbits if_togglecapenable(ifp, IFCAP_TSO4); 190202f3b17fSJustin Hibbits if_togglehwassist(ifp, CSUM_TSO); 190312678024SDoug Rabson } 190412678024SDoug Rabson 19053c9d5940SRoger Pau Monné if (mask & (IFCAP_RXCSUM | IFCAP_LRO)) { 19063c9d5940SRoger Pau Monné /* These Rx features require us to renegotiate. */ 19073c9d5940SRoger Pau Monné reinit = 1; 19083c9d5940SRoger Pau Monné 19093c9d5940SRoger Pau Monné if (mask & IFCAP_RXCSUM) 191002f3b17fSJustin Hibbits if_togglecapenable(ifp, IFCAP_RXCSUM); 19113c9d5940SRoger Pau Monné if (mask & IFCAP_LRO) 191202f3b17fSJustin Hibbits if_togglecapenable(ifp, IFCAP_LRO); 191312678024SDoug Rabson } 19143c9d5940SRoger Pau Monné 19153c9d5940SRoger Pau Monné if (reinit == 0) 19163c9d5940SRoger Pau Monné break; 19173c9d5940SRoger Pau Monné 1918c2d12e5eSRoger Pau Monné /* 1919c2d12e5eSRoger Pau Monné * We must reset the interface so the backend picks up the 1920c2d12e5eSRoger Pau Monné * new features. 1921c2d12e5eSRoger Pau Monné */ 19223c9d5940SRoger Pau Monné device_printf(sc->xbdev, 19233c9d5940SRoger Pau Monné "performing interface reset due to feature change\n"); 1924c2d12e5eSRoger Pau Monné XN_LOCK(sc); 1925c2d12e5eSRoger Pau Monné netfront_carrier_off(sc); 1926c2d12e5eSRoger Pau Monné sc->xn_reset = true; 1927c2d12e5eSRoger Pau Monné /* 1928c2d12e5eSRoger Pau Monné * NB: the pending packet queue is not flushed, since 1929c2d12e5eSRoger Pau Monné * the interface should still support the old options. 1930c2d12e5eSRoger Pau Monné */ 1931c2d12e5eSRoger Pau Monné XN_UNLOCK(sc); 1932c2d12e5eSRoger Pau Monné /* 1933c2d12e5eSRoger Pau Monné * Delete the xenstore nodes that export features. 1934c2d12e5eSRoger Pau Monné * 1935c2d12e5eSRoger Pau Monné * NB: There's a xenbus state called 1936c2d12e5eSRoger Pau Monné * "XenbusStateReconfiguring", which is what we should set 1937c2d12e5eSRoger Pau Monné * here. Sadly none of the backends know how to handle it, 1938c2d12e5eSRoger Pau Monné * and simply disconnect from the frontend, so we will just 1939c2d12e5eSRoger Pau Monné * switch back to XenbusStateInitialising in order to force 1940c2d12e5eSRoger Pau Monné * a reconnection. 1941c2d12e5eSRoger Pau Monné */ 1942c2d12e5eSRoger Pau Monné xs_rm(XST_NIL, xenbus_get_node(dev), "feature-gso-tcpv4"); 1943c2d12e5eSRoger Pau Monné xs_rm(XST_NIL, xenbus_get_node(dev), "feature-no-csum-offload"); 1944c2d12e5eSRoger Pau Monné xenbus_set_state(dev, XenbusStateClosing); 19453c9d5940SRoger Pau Monné 19463c9d5940SRoger Pau Monné /* 19473c9d5940SRoger Pau Monné * Wait for the frontend to reconnect before returning 19483c9d5940SRoger Pau Monné * from the ioctl. 30s should be more than enough for any 19493c9d5940SRoger Pau Monné * sane backend to reconnect. 19503c9d5940SRoger Pau Monné */ 19513c9d5940SRoger Pau Monné error = tsleep(sc, 0, "xn_rst", 30*hz); 195289e0f4d2SKip Macy break; 195389e0f4d2SKip Macy case SIOCADDMULTI: 195489e0f4d2SKip Macy case SIOCDELMULTI: 1955ce8df48bSSimon J. Gerraty break; 195689e0f4d2SKip Macy case SIOCSIFMEDIA: 195789e0f4d2SKip Macy case SIOCGIFMEDIA: 19580e509842SJustin T. Gibbs error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 195989e0f4d2SKip Macy break; 196089e0f4d2SKip Macy default: 196189e0f4d2SKip Macy error = ether_ioctl(ifp, cmd, data); 196289e0f4d2SKip Macy } 196389e0f4d2SKip Macy 196489e0f4d2SKip Macy return (error); 196589e0f4d2SKip Macy } 196689e0f4d2SKip Macy 196789e0f4d2SKip Macy static void 196889e0f4d2SKip Macy xn_stop(struct netfront_info *sc) 196989e0f4d2SKip Macy { 197002f3b17fSJustin Hibbits if_t ifp; 197189e0f4d2SKip Macy 197289e0f4d2SKip Macy XN_LOCK_ASSERT(sc); 197389e0f4d2SKip Macy 197489e0f4d2SKip Macy ifp = sc->xn_ifp; 197589e0f4d2SKip Macy 197602f3b17fSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 19770e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_DOWN); 197889e0f4d2SKip Macy } 197989e0f4d2SKip Macy 198096375eacSRoger Pau Monné static void 198196375eacSRoger Pau Monné xn_rebuild_rx_bufs(struct netfront_rxq *rxq) 198289e0f4d2SKip Macy { 198396375eacSRoger Pau Monné int requeue_idx, i; 198489e0f4d2SKip Macy grant_ref_t ref; 198589e0f4d2SKip Macy netif_rx_request_t *req; 198689e0f4d2SKip Macy 198789e0f4d2SKip Macy for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { 198889e0f4d2SKip Macy struct mbuf *m; 19893a6d1fcfSKip Macy u_long pfn; 199089e0f4d2SKip Macy 199196375eacSRoger Pau Monné if (rxq->mbufs[i] == NULL) 199289e0f4d2SKip Macy continue; 199389e0f4d2SKip Macy 199496375eacSRoger Pau Monné m = rxq->mbufs[requeue_idx] = xn_get_rx_mbuf(rxq, i); 199596375eacSRoger Pau Monné ref = rxq->grant_ref[requeue_idx] = xn_get_rx_ref(rxq, i); 1996931eeffaSKenneth D. Merry 199796375eacSRoger Pau Monné req = RING_GET_REQUEST(&rxq->ring, requeue_idx); 19983a6d1fcfSKip Macy pfn = vtophys(mtod(m, vm_offset_t)) >> PAGE_SHIFT; 199989e0f4d2SKip Macy 200089e0f4d2SKip Macy gnttab_grant_foreign_access_ref(ref, 200196375eacSRoger Pau Monné xenbus_get_otherend_id(rxq->info->xbdev), 2002ed95805eSJohn Baldwin pfn, 0); 2003d0f3a8b9SRoger Pau Monné 200489e0f4d2SKip Macy req->gref = ref; 200589e0f4d2SKip Macy req->id = requeue_idx; 200689e0f4d2SKip Macy 200789e0f4d2SKip Macy requeue_idx++; 200889e0f4d2SKip Macy } 200989e0f4d2SKip Macy 201096375eacSRoger Pau Monné rxq->ring.req_prod_pvt = requeue_idx; 201196375eacSRoger Pau Monné } 201289e0f4d2SKip Macy 201396375eacSRoger Pau Monné /* START of Xenolinux helper functions adapted to FreeBSD */ 201465671253SRoger Pau Monné static int 201596375eacSRoger Pau Monné xn_connect(struct netfront_info *np) 201696375eacSRoger Pau Monné { 201796375eacSRoger Pau Monné int i, error; 201896375eacSRoger Pau Monné u_int feature_rx_copy; 201996375eacSRoger Pau Monné struct netfront_rxq *rxq; 202096375eacSRoger Pau Monné struct netfront_txq *txq; 202196375eacSRoger Pau Monné 202296375eacSRoger Pau Monné error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 202396375eacSRoger Pau Monné "feature-rx-copy", NULL, "%u", &feature_rx_copy); 202496375eacSRoger Pau Monné if (error != 0) 202596375eacSRoger Pau Monné feature_rx_copy = 0; 202696375eacSRoger Pau Monné 202796375eacSRoger Pau Monné /* We only support rx copy. */ 202896375eacSRoger Pau Monné if (!feature_rx_copy) 202996375eacSRoger Pau Monné return (EPROTONOSUPPORT); 203096375eacSRoger Pau Monné 203196375eacSRoger Pau Monné /* Recovery procedure: */ 203296375eacSRoger Pau Monné error = talk_to_backend(np->xbdev, np); 203396375eacSRoger Pau Monné if (error != 0) 203496375eacSRoger Pau Monné return (error); 203596375eacSRoger Pau Monné 203696375eacSRoger Pau Monné /* Step 1: Reinitialise variables. */ 203796375eacSRoger Pau Monné xn_query_features(np); 203896375eacSRoger Pau Monné xn_configure_features(np); 203996375eacSRoger Pau Monné 204096375eacSRoger Pau Monné /* Step 2: Release TX buffer */ 204196375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 204296375eacSRoger Pau Monné txq = &np->txq[i]; 204396375eacSRoger Pau Monné xn_release_tx_bufs(txq); 204496375eacSRoger Pau Monné } 204596375eacSRoger Pau Monné 204696375eacSRoger Pau Monné /* Step 3: Rebuild the RX buffer freelist and the RX ring itself. */ 204796375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 204896375eacSRoger Pau Monné rxq = &np->rxq[i]; 204996375eacSRoger Pau Monné xn_rebuild_rx_bufs(rxq); 205096375eacSRoger Pau Monné } 205196375eacSRoger Pau Monné 205296375eacSRoger Pau Monné /* Step 4: All public and private state should now be sane. Get 205389e0f4d2SKip Macy * ready to start sending and receiving packets and give the driver 205489e0f4d2SKip Macy * domain a kick because we've probably just requeued some 205589e0f4d2SKip Macy * packets. 205689e0f4d2SKip Macy */ 205789e0f4d2SKip Macy netfront_carrier_on(np); 20583c9d5940SRoger Pau Monné wakeup(np); 205965671253SRoger Pau Monné 206065671253SRoger Pau Monné return (0); 206165671253SRoger Pau Monné } 206265671253SRoger Pau Monné 206365671253SRoger Pau Monné static void 206465671253SRoger Pau Monné xn_kick_rings(struct netfront_info *np) 206565671253SRoger Pau Monné { 206665671253SRoger Pau Monné struct netfront_rxq *rxq; 206765671253SRoger Pau Monné struct netfront_txq *txq; 206865671253SRoger Pau Monné int i; 206965671253SRoger Pau Monné 207096375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 207196375eacSRoger Pau Monné txq = &np->txq[i]; 207265671253SRoger Pau Monné rxq = &np->rxq[i]; 207396375eacSRoger Pau Monné xen_intr_signal(txq->xen_intr_handle); 207496375eacSRoger Pau Monné XN_TX_LOCK(txq); 207596375eacSRoger Pau Monné xn_txeof(txq); 207696375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 20772568ee67SRoger Pau Monné XN_RX_LOCK(rxq); 207896375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 20792568ee67SRoger Pau Monné XN_RX_UNLOCK(rxq); 208096375eacSRoger Pau Monné } 208189e0f4d2SKip Macy } 208289e0f4d2SKip Macy 208389e0f4d2SKip Macy static void 2084578e4bf7SJustin T. Gibbs xn_query_features(struct netfront_info *np) 2085578e4bf7SJustin T. Gibbs { 2086578e4bf7SJustin T. Gibbs int val; 2087578e4bf7SJustin T. Gibbs 2088578e4bf7SJustin T. Gibbs device_printf(np->xbdev, "backend features:"); 2089578e4bf7SJustin T. Gibbs 2090578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 2091107cfbb7SRoger Pau Monné "feature-sg", NULL, "%d", &val) != 0) 2092578e4bf7SJustin T. Gibbs val = 0; 2093578e4bf7SJustin T. Gibbs 2094578e4bf7SJustin T. Gibbs np->maxfrags = 1; 2095578e4bf7SJustin T. Gibbs if (val) { 2096578e4bf7SJustin T. Gibbs np->maxfrags = MAX_TX_REQ_FRAGS; 2097578e4bf7SJustin T. Gibbs printf(" feature-sg"); 2098578e4bf7SJustin T. Gibbs } 2099578e4bf7SJustin T. Gibbs 2100578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 2101107cfbb7SRoger Pau Monné "feature-gso-tcpv4", NULL, "%d", &val) != 0) 2102578e4bf7SJustin T. Gibbs val = 0; 2103578e4bf7SJustin T. Gibbs 210402f3b17fSJustin Hibbits if_setcapabilitiesbit(np->xn_ifp, 0, IFCAP_TSO4 | IFCAP_LRO); 2105578e4bf7SJustin T. Gibbs if (val) { 210602f3b17fSJustin Hibbits if_setcapabilitiesbit(np->xn_ifp, IFCAP_TSO4 | IFCAP_LRO, 0); 2107578e4bf7SJustin T. Gibbs printf(" feature-gso-tcp4"); 2108578e4bf7SJustin T. Gibbs } 2109578e4bf7SJustin T. Gibbs 2110c2d12e5eSRoger Pau Monné /* 2111c2d12e5eSRoger Pau Monné * HW CSUM offload is assumed to be available unless 2112c2d12e5eSRoger Pau Monné * feature-no-csum-offload is set in xenstore. 2113c2d12e5eSRoger Pau Monné */ 2114c2d12e5eSRoger Pau Monné if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 2115c2d12e5eSRoger Pau Monné "feature-no-csum-offload", NULL, "%d", &val) != 0) 2116c2d12e5eSRoger Pau Monné val = 0; 2117c2d12e5eSRoger Pau Monné 211802f3b17fSJustin Hibbits if_setcapabilitiesbit(np->xn_ifp, IFCAP_HWCSUM, 0); 2119c2d12e5eSRoger Pau Monné if (val) { 212002f3b17fSJustin Hibbits if_setcapabilitiesbit(np->xn_ifp, 0, IFCAP_HWCSUM); 2121c2d12e5eSRoger Pau Monné printf(" feature-no-csum-offload"); 2122c2d12e5eSRoger Pau Monné } 2123c2d12e5eSRoger Pau Monné 2124578e4bf7SJustin T. Gibbs printf("\n"); 2125578e4bf7SJustin T. Gibbs } 2126578e4bf7SJustin T. Gibbs 2127cf9c09e1SJustin T. Gibbs static int 2128578e4bf7SJustin T. Gibbs xn_configure_features(struct netfront_info *np) 2129cf9c09e1SJustin T. Gibbs { 21306a8e9695SRoger Pau Monné int err, cap_enabled; 213196375eacSRoger Pau Monné #if (defined(INET) || defined(INET6)) 213296375eacSRoger Pau Monné int i; 213396375eacSRoger Pau Monné #endif 213402f3b17fSJustin Hibbits if_t ifp; 2135cf9c09e1SJustin T. Gibbs 2136c2d12e5eSRoger Pau Monné ifp = np->xn_ifp; 2137cf9c09e1SJustin T. Gibbs err = 0; 21386a8e9695SRoger Pau Monné 213902f3b17fSJustin Hibbits if ((if_getcapenable(ifp) & if_getcapabilities(ifp)) == if_getcapenable(ifp)) { 21406a8e9695SRoger Pau Monné /* Current options are available, no need to do anything. */ 21416a8e9695SRoger Pau Monné return (0); 21426a8e9695SRoger Pau Monné } 21436a8e9695SRoger Pau Monné 21446a8e9695SRoger Pau Monné /* Try to preserve as many options as possible. */ 214502f3b17fSJustin Hibbits cap_enabled = if_getcapenable(ifp); 214602f3b17fSJustin Hibbits if_setcapenable(ifp, 0); 214702f3b17fSJustin Hibbits if_sethwassist(ifp, 0); 21486a8e9695SRoger Pau Monné 214908c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 2150c2d12e5eSRoger Pau Monné if ((cap_enabled & IFCAP_LRO) != 0) 215196375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 215296375eacSRoger Pau Monné tcp_lro_free(&np->rxq[i].lro); 2153c2d12e5eSRoger Pau Monné if (xn_enable_lro && 215402f3b17fSJustin Hibbits (if_getcapabilities(ifp) & cap_enabled & IFCAP_LRO) != 0) { 215502f3b17fSJustin Hibbits if_setcapenablebit(ifp, IFCAP_LRO, 0); 215696375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 215796375eacSRoger Pau Monné err = tcp_lro_init(&np->rxq[i].lro); 215896375eacSRoger Pau Monné if (err != 0) { 2159c2d12e5eSRoger Pau Monné device_printf(np->xbdev, 2160c2d12e5eSRoger Pau Monné "LRO initialization failed\n"); 216102f3b17fSJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_LRO); 2162c2d12e5eSRoger Pau Monné break; 2163c2d12e5eSRoger Pau Monné } 2164c2d12e5eSRoger Pau Monné np->rxq[i].lro.ifp = ifp; 2165cf9c09e1SJustin T. Gibbs } 2166cf9c09e1SJustin T. Gibbs } 216702f3b17fSJustin Hibbits if ((if_getcapabilities(ifp) & cap_enabled & IFCAP_TSO4) != 0) { 216802f3b17fSJustin Hibbits if_setcapenablebit(ifp, IFCAP_TSO4, 0); 216902f3b17fSJustin Hibbits if_sethwassistbits(ifp, CSUM_TSO, 0); 2170578e4bf7SJustin T. Gibbs } 2171cf9c09e1SJustin T. Gibbs #endif 217202f3b17fSJustin Hibbits if ((if_getcapabilities(ifp) & cap_enabled & IFCAP_TXCSUM) != 0) { 217302f3b17fSJustin Hibbits if_setcapenablebit(ifp, IFCAP_TXCSUM, 0); 217402f3b17fSJustin Hibbits if_sethwassistbits(ifp, XN_CSUM_FEATURES, 0); 2175c2d12e5eSRoger Pau Monné } 217602f3b17fSJustin Hibbits if ((if_getcapabilities(ifp) & cap_enabled & IFCAP_RXCSUM) != 0) 217702f3b17fSJustin Hibbits if_setcapenablebit(ifp, IFCAP_RXCSUM, 0); 2178c2d12e5eSRoger Pau Monné 2179cf9c09e1SJustin T. Gibbs return (err); 2180cf9c09e1SJustin T. Gibbs } 2181cf9c09e1SJustin T. Gibbs 218296375eacSRoger Pau Monné static int 218396375eacSRoger Pau Monné xn_txq_mq_start_locked(struct netfront_txq *txq, struct mbuf *m) 218496375eacSRoger Pau Monné { 218596375eacSRoger Pau Monné struct netfront_info *np; 218602f3b17fSJustin Hibbits if_t ifp; 218796375eacSRoger Pau Monné struct buf_ring *br; 218896375eacSRoger Pau Monné int error, notify; 218996375eacSRoger Pau Monné 219096375eacSRoger Pau Monné np = txq->info; 219196375eacSRoger Pau Monné br = txq->br; 219296375eacSRoger Pau Monné ifp = np->xn_ifp; 219396375eacSRoger Pau Monné error = 0; 219496375eacSRoger Pau Monné 219596375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 219696375eacSRoger Pau Monné 219702f3b17fSJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0 || 219896375eacSRoger Pau Monné !netfront_carrier_ok(np)) { 219996375eacSRoger Pau Monné if (m != NULL) 220096375eacSRoger Pau Monné error = drbr_enqueue(ifp, br, m); 220196375eacSRoger Pau Monné return (error); 220296375eacSRoger Pau Monné } 220396375eacSRoger Pau Monné 220496375eacSRoger Pau Monné if (m != NULL) { 220596375eacSRoger Pau Monné error = drbr_enqueue(ifp, br, m); 220696375eacSRoger Pau Monné if (error != 0) 220796375eacSRoger Pau Monné return (error); 220896375eacSRoger Pau Monné } 220996375eacSRoger Pau Monné 221096375eacSRoger Pau Monné while ((m = drbr_peek(ifp, br)) != NULL) { 221196375eacSRoger Pau Monné if (!xn_tx_slot_available(txq)) { 221296375eacSRoger Pau Monné drbr_putback(ifp, br, m); 221396375eacSRoger Pau Monné break; 221496375eacSRoger Pau Monné } 221596375eacSRoger Pau Monné 221696375eacSRoger Pau Monné error = xn_assemble_tx_request(txq, m); 221796375eacSRoger Pau Monné /* xn_assemble_tx_request always consumes the mbuf*/ 221896375eacSRoger Pau Monné if (error != 0) { 221996375eacSRoger Pau Monné drbr_advance(ifp, br); 222096375eacSRoger Pau Monné break; 222196375eacSRoger Pau Monné } 222296375eacSRoger Pau Monné 222396375eacSRoger Pau Monné RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&txq->ring, notify); 222496375eacSRoger Pau Monné if (notify) 222596375eacSRoger Pau Monné xen_intr_signal(txq->xen_intr_handle); 222696375eacSRoger Pau Monné 222796375eacSRoger Pau Monné drbr_advance(ifp, br); 222896375eacSRoger Pau Monné } 222996375eacSRoger Pau Monné 223096375eacSRoger Pau Monné if (RING_FULL(&txq->ring)) 223196375eacSRoger Pau Monné txq->full = true; 223296375eacSRoger Pau Monné 223396375eacSRoger Pau Monné return (0); 223496375eacSRoger Pau Monné } 223596375eacSRoger Pau Monné 223696375eacSRoger Pau Monné static int 223702f3b17fSJustin Hibbits xn_txq_mq_start(if_t ifp, struct mbuf *m) 223896375eacSRoger Pau Monné { 223996375eacSRoger Pau Monné struct netfront_info *np; 224096375eacSRoger Pau Monné struct netfront_txq *txq; 224196375eacSRoger Pau Monné int i, npairs, error; 224296375eacSRoger Pau Monné 224302f3b17fSJustin Hibbits np = if_getsoftc(ifp); 224496375eacSRoger Pau Monné npairs = np->num_queues; 224596375eacSRoger Pau Monné 2246339690b5SRoger Pau Monné if (!netfront_carrier_ok(np)) 2247339690b5SRoger Pau Monné return (ENOBUFS); 2248339690b5SRoger Pau Monné 2249c21b47d8SRoger Pau Monné KASSERT(npairs != 0, ("called with 0 available queues")); 2250c21b47d8SRoger Pau Monné 225196375eacSRoger Pau Monné /* check if flowid is set */ 225296375eacSRoger Pau Monné if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 225396375eacSRoger Pau Monné i = m->m_pkthdr.flowid % npairs; 225496375eacSRoger Pau Monné else 225596375eacSRoger Pau Monné i = curcpu % npairs; 225696375eacSRoger Pau Monné 225796375eacSRoger Pau Monné txq = &np->txq[i]; 225896375eacSRoger Pau Monné 225996375eacSRoger Pau Monné if (XN_TX_TRYLOCK(txq) != 0) { 226096375eacSRoger Pau Monné error = xn_txq_mq_start_locked(txq, m); 226196375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 226296375eacSRoger Pau Monné } else { 226396375eacSRoger Pau Monné error = drbr_enqueue(ifp, txq->br, m); 226496375eacSRoger Pau Monné taskqueue_enqueue(txq->tq, &txq->defrtask); 226596375eacSRoger Pau Monné } 226696375eacSRoger Pau Monné 226796375eacSRoger Pau Monné return (error); 226896375eacSRoger Pau Monné } 226996375eacSRoger Pau Monné 227096375eacSRoger Pau Monné static void 227102f3b17fSJustin Hibbits xn_qflush(if_t ifp) 227296375eacSRoger Pau Monné { 227396375eacSRoger Pau Monné struct netfront_info *np; 227496375eacSRoger Pau Monné struct netfront_txq *txq; 227596375eacSRoger Pau Monné struct mbuf *m; 227696375eacSRoger Pau Monné int i; 227796375eacSRoger Pau Monné 227802f3b17fSJustin Hibbits np = if_getsoftc(ifp); 227996375eacSRoger Pau Monné 228096375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 228196375eacSRoger Pau Monné txq = &np->txq[i]; 228296375eacSRoger Pau Monné 228396375eacSRoger Pau Monné XN_TX_LOCK(txq); 228496375eacSRoger Pau Monné while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 228596375eacSRoger Pau Monné m_freem(m); 228696375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 228796375eacSRoger Pau Monné } 228896375eacSRoger Pau Monné 228996375eacSRoger Pau Monné if_qflush(ifp); 229096375eacSRoger Pau Monné } 229196375eacSRoger Pau Monné 229276acc41fSJustin T. Gibbs /** 229376acc41fSJustin T. Gibbs * Create a network device. 229476acc41fSJustin T. Gibbs * @param dev Newbus device representing this virtual NIC. 229589e0f4d2SKip Macy */ 229623dc5621SKip Macy int 229723dc5621SKip Macy create_netdev(device_t dev) 229889e0f4d2SKip Macy { 229989e0f4d2SKip Macy struct netfront_info *np; 2300da4b0d6eSDoug Rabson int err, cap_enabled; 230102f3b17fSJustin Hibbits if_t ifp; 230289e0f4d2SKip Macy 230323dc5621SKip Macy np = device_get_softc(dev); 230489e0f4d2SKip Macy 230589e0f4d2SKip Macy np->xbdev = dev; 230689e0f4d2SKip Macy 2307177e3f13SRoger Pau Monné mtx_init(&np->sc_lock, "xnsc", "netfront softc lock", MTX_DEF); 23080e509842SJustin T. Gibbs 23090e509842SJustin T. Gibbs ifmedia_init(&np->sc_media, 0, xn_ifmedia_upd, xn_ifmedia_sts); 23100e509842SJustin T. Gibbs ifmedia_add(&np->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 23110e509842SJustin T. Gibbs ifmedia_set(&np->sc_media, IFM_ETHER|IFM_MANUAL); 23120e509842SJustin T. Gibbs 231389e0f4d2SKip Macy err = xen_net_read_mac(dev, np->mac); 231496375eacSRoger Pau Monné if (err != 0) 23151a2928b7SRoger Pau Monné goto error; 231689e0f4d2SKip Macy 231789e0f4d2SKip Macy /* Set up ifnet structure */ 231823dc5621SKip Macy ifp = np->xn_ifp = if_alloc(IFT_ETHER); 231902f3b17fSJustin Hibbits if_setsoftc(ifp, np); 232023dc5621SKip Macy if_initname(ifp, "xn", device_get_unit(dev)); 232102f3b17fSJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 232202f3b17fSJustin Hibbits if_setioctlfn(ifp, xn_ioctl); 232396375eacSRoger Pau Monné 232402f3b17fSJustin Hibbits if_settransmitfn(ifp, xn_txq_mq_start); 232502f3b17fSJustin Hibbits if_setqflushfn(ifp, xn_qflush); 232696375eacSRoger Pau Monné 232702f3b17fSJustin Hibbits if_setinitfn(ifp, xn_ifinit); 232889e0f4d2SKip Macy 232902f3b17fSJustin Hibbits if_sethwassist(ifp, XN_CSUM_FEATURES); 2330c2d12e5eSRoger Pau Monné /* Enable all supported features at device creation. */ 233102f3b17fSJustin Hibbits if_setcapabilities(ifp, IFCAP_HWCSUM|IFCAP_TSO4|IFCAP_LRO); 2332da4b0d6eSDoug Rabson cap_enabled = if_getcapabilities(ifp); 2333da4b0d6eSDoug Rabson if (!xn_enable_lro) { 2334da4b0d6eSDoug Rabson cap_enabled &= ~IFCAP_LRO; 2335da4b0d6eSDoug Rabson } 2336da4b0d6eSDoug Rabson if_setcapenable(ifp, cap_enabled); 233702f3b17fSJustin Hibbits 233802f3b17fSJustin Hibbits if_sethwtsomax(ifp, 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN)); 233902f3b17fSJustin Hibbits if_sethwtsomaxsegcount(ifp, MAX_TX_REQ_FRAGS); 234002f3b17fSJustin Hibbits if_sethwtsomaxsegsize(ifp, PAGE_SIZE); 234189e0f4d2SKip Macy 234289e0f4d2SKip Macy ether_ifattach(ifp, np->mac); 234389e0f4d2SKip Macy netfront_carrier_off(np); 234489e0f4d2SKip Macy 2345dabb3db7SRoger Pau Monné err = bus_dma_tag_create( 2346dabb3db7SRoger Pau Monné bus_get_dma_tag(dev), /* parent */ 2347dabb3db7SRoger Pau Monné 1, PAGE_SIZE, /* algnmnt, boundary */ 2348dabb3db7SRoger Pau Monné BUS_SPACE_MAXADDR, /* lowaddr */ 2349dabb3db7SRoger Pau Monné BUS_SPACE_MAXADDR, /* highaddr */ 2350dabb3db7SRoger Pau Monné NULL, NULL, /* filter, filterarg */ 2351dabb3db7SRoger Pau Monné PAGE_SIZE * MAX_TX_REQ_FRAGS, /* max request size */ 2352dabb3db7SRoger Pau Monné MAX_TX_REQ_FRAGS, /* max segments */ 2353dabb3db7SRoger Pau Monné PAGE_SIZE, /* maxsegsize */ 2354dabb3db7SRoger Pau Monné BUS_DMA_ALLOCNOW, /* flags */ 2355dabb3db7SRoger Pau Monné NULL, NULL, /* lockfunc, lockarg */ 2356dabb3db7SRoger Pau Monné &np->dma_tag); 2357dabb3db7SRoger Pau Monné 2358dabb3db7SRoger Pau Monné return (err); 235989e0f4d2SKip Macy 23601a2928b7SRoger Pau Monné error: 23611a2928b7SRoger Pau Monné KASSERT(err != 0, ("Error path with no error code specified")); 2362ffa06904SJustin T. Gibbs return (err); 236389e0f4d2SKip Macy } 236489e0f4d2SKip Macy 23650e509842SJustin T. Gibbs static int 23660e509842SJustin T. Gibbs netfront_detach(device_t dev) 236789e0f4d2SKip Macy { 236823dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 236989e0f4d2SKip Macy 237023dc5621SKip Macy DPRINTK("%s\n", xenbus_get_node(dev)); 237189e0f4d2SKip Macy 237289e0f4d2SKip Macy netif_free(info); 237389e0f4d2SKip Macy 237489e0f4d2SKip Macy return 0; 237589e0f4d2SKip Macy } 237689e0f4d2SKip Macy 23770e509842SJustin T. Gibbs static void 237896375eacSRoger Pau Monné netif_free(struct netfront_info *np) 237989e0f4d2SKip Macy { 238096375eacSRoger Pau Monné 238196375eacSRoger Pau Monné XN_LOCK(np); 238296375eacSRoger Pau Monné xn_stop(np); 238396375eacSRoger Pau Monné XN_UNLOCK(np); 238496375eacSRoger Pau Monné netif_disconnect_backend(np); 2385c21b47d8SRoger Pau Monné ether_ifdetach(np->xn_ifp); 238696375eacSRoger Pau Monné free(np->rxq, M_DEVBUF); 238796375eacSRoger Pau Monné free(np->txq, M_DEVBUF); 238896375eacSRoger Pau Monné if_free(np->xn_ifp); 238996375eacSRoger Pau Monné np->xn_ifp = NULL; 239096375eacSRoger Pau Monné ifmedia_removeall(&np->sc_media); 2391dabb3db7SRoger Pau Monné bus_dma_tag_destroy(np->dma_tag); 239289e0f4d2SKip Macy } 239389e0f4d2SKip Macy 23940e509842SJustin T. Gibbs static void 239596375eacSRoger Pau Monné netif_disconnect_backend(struct netfront_info *np) 239689e0f4d2SKip Macy { 239796375eacSRoger Pau Monné u_int i; 23983a6d1fcfSKip Macy 239996375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 240096375eacSRoger Pau Monné XN_RX_LOCK(&np->rxq[i]); 240196375eacSRoger Pau Monné XN_TX_LOCK(&np->txq[i]); 240296375eacSRoger Pau Monné } 240396375eacSRoger Pau Monné netfront_carrier_off(np); 240496375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 240596375eacSRoger Pau Monné XN_RX_UNLOCK(&np->rxq[i]); 240696375eacSRoger Pau Monné XN_TX_UNLOCK(&np->txq[i]); 240789e0f4d2SKip Macy } 240889e0f4d2SKip Macy 240996375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 241096375eacSRoger Pau Monné disconnect_rxq(&np->rxq[i]); 241196375eacSRoger Pau Monné disconnect_txq(&np->txq[i]); 2412cf9c09e1SJustin T. Gibbs } 241389e0f4d2SKip Macy } 241489e0f4d2SKip Macy 24150e509842SJustin T. Gibbs static int 241602f3b17fSJustin Hibbits xn_ifmedia_upd(if_t ifp) 24170e509842SJustin T. Gibbs { 241896375eacSRoger Pau Monné 24190e509842SJustin T. Gibbs return (0); 24200e509842SJustin T. Gibbs } 24210e509842SJustin T. Gibbs 24220e509842SJustin T. Gibbs static void 242302f3b17fSJustin Hibbits xn_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 24240e509842SJustin T. Gibbs { 242596375eacSRoger Pau Monné 24260e509842SJustin T. Gibbs ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE; 24270e509842SJustin T. Gibbs ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; 24280e509842SJustin T. Gibbs } 24290e509842SJustin T. Gibbs 243089e0f4d2SKip Macy /* ** Driver registration ** */ 243123dc5621SKip Macy static device_method_t netfront_methods[] = { 243223dc5621SKip Macy /* Device interface */ 243323dc5621SKip Macy DEVMETHOD(device_probe, netfront_probe), 243423dc5621SKip Macy DEVMETHOD(device_attach, netfront_attach), 243523dc5621SKip Macy DEVMETHOD(device_detach, netfront_detach), 243623dc5621SKip Macy DEVMETHOD(device_shutdown, bus_generic_shutdown), 2437cf9c09e1SJustin T. Gibbs DEVMETHOD(device_suspend, netfront_suspend), 243823dc5621SKip Macy DEVMETHOD(device_resume, netfront_resume), 243989e0f4d2SKip Macy 244023dc5621SKip Macy /* Xenbus interface */ 2441ff662b5cSJustin T. Gibbs DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed), 244289e0f4d2SKip Macy 24436f9767acSMarius Strobl DEVMETHOD_END 244489e0f4d2SKip Macy }; 244589e0f4d2SKip Macy 244623dc5621SKip Macy static driver_t netfront_driver = { 244723dc5621SKip Macy "xn", 244823dc5621SKip Macy netfront_methods, 244923dc5621SKip Macy sizeof(struct netfront_info), 245089e0f4d2SKip Macy }; 245189e0f4d2SKip Macy 2452f929eb1eSJohn Baldwin DRIVER_MODULE(xe, xenbusb_front, netfront_driver, NULL, NULL); 2453