18e0ad55aSJoel Dahl /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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> 3189e0f4d2SKip Macy __FBSDID("$FreeBSD$"); 3289e0f4d2SKip Macy 33a0ae8f04SBjoern A. Zeeb #include "opt_inet.h" 34f909bbb4SGleb Smirnoff #include "opt_inet6.h" 35a0ae8f04SBjoern A. Zeeb 3689e0f4d2SKip Macy #include <sys/param.h> 3789e0f4d2SKip Macy #include <sys/sockio.h> 38c578b6acSGleb Smirnoff #include <sys/limits.h> 3989e0f4d2SKip Macy #include <sys/mbuf.h> 4089e0f4d2SKip Macy #include <sys/malloc.h> 4123dc5621SKip Macy #include <sys/module.h> 4289e0f4d2SKip Macy #include <sys/kernel.h> 4389e0f4d2SKip Macy #include <sys/socket.h> 4412678024SDoug Rabson #include <sys/sysctl.h> 4596375eacSRoger Pau Monné #include <sys/taskqueue.h> 4689e0f4d2SKip Macy 4789e0f4d2SKip Macy #include <net/if.h> 4877374386SGleb Smirnoff #include <net/if_var.h> 4989e0f4d2SKip Macy #include <net/if_arp.h> 5089e0f4d2SKip Macy #include <net/ethernet.h> 5189e0f4d2SKip Macy #include <net/if_media.h> 5289e0f4d2SKip Macy #include <net/bpf.h> 5389e0f4d2SKip Macy #include <net/if_types.h> 5489e0f4d2SKip Macy 5589e0f4d2SKip Macy #include <netinet/in.h> 5689e0f4d2SKip Macy #include <netinet/ip.h> 5789e0f4d2SKip Macy #include <netinet/if_ether.h> 5812678024SDoug Rabson #include <netinet/tcp.h> 5912678024SDoug Rabson #include <netinet/tcp_lro.h> 6089e0f4d2SKip Macy 6189e0f4d2SKip Macy #include <vm/vm.h> 6289e0f4d2SKip Macy #include <vm/pmap.h> 6389e0f4d2SKip Macy 6489e0f4d2SKip Macy #include <sys/bus.h> 6589e0f4d2SKip Macy 6676acc41fSJustin T. Gibbs #include <xen/xen-os.h> 673a6d1fcfSKip Macy #include <xen/hypervisor.h> 683a6d1fcfSKip Macy #include <xen/xen_intr.h> 6989e0f4d2SKip Macy #include <xen/gnttab.h> 7089e0f4d2SKip Macy #include <xen/interface/memory.h> 7189e0f4d2SKip Macy #include <xen/interface/io/netif.h> 7223dc5621SKip Macy #include <xen/xenbus/xenbusvar.h> 7389e0f4d2SKip Macy 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 *); 129931eeffaSKenneth D. Merry static inline int xn_count_frags(struct mbuf *m); 13096375eacSRoger Pau Monné static int xn_assemble_tx_request(struct netfront_txq *, struct mbuf *); 13189e0f4d2SKip Macy static int xn_ioctl(struct ifnet *, u_long, caddr_t); 13289e0f4d2SKip Macy static void xn_ifinit_locked(struct netfront_info *); 13389e0f4d2SKip Macy static void xn_ifinit(void *); 13489e0f4d2SKip Macy static void xn_stop(struct netfront_info *); 135578e4bf7SJustin T. Gibbs static void xn_query_features(struct netfront_info *np); 136578e4bf7SJustin T. Gibbs static int xn_configure_features(struct netfront_info *np); 13789e0f4d2SKip Macy static void netif_free(struct netfront_info *info); 13823dc5621SKip Macy static int netfront_detach(device_t dev); 13989e0f4d2SKip Macy 14096375eacSRoger Pau Monné static int xn_txq_mq_start_locked(struct netfront_txq *, struct mbuf *); 14196375eacSRoger Pau Monné static int xn_txq_mq_start(struct ifnet *, struct mbuf *); 14296375eacSRoger Pau Monné 14323dc5621SKip Macy static int talk_to_backend(device_t dev, struct netfront_info *info); 14423dc5621SKip Macy static int create_netdev(device_t dev); 14589e0f4d2SKip Macy static void netif_disconnect_backend(struct netfront_info *info); 14696375eacSRoger Pau Monné static int setup_device(device_t dev, struct netfront_info *info, 14796375eacSRoger Pau Monné unsigned long); 1480e509842SJustin T. Gibbs static int xn_ifmedia_upd(struct ifnet *ifp); 1490e509842SJustin T. Gibbs static void xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 1500e509842SJustin T. Gibbs 15165671253SRoger Pau Monné static int xn_connect(struct netfront_info *); 15265671253SRoger Pau Monné static void xn_kick_rings(struct netfront_info *); 15389e0f4d2SKip Macy 15496375eacSRoger Pau Monné static int xn_get_responses(struct netfront_rxq *, 15596375eacSRoger Pau Monné struct netfront_rx_info *, RING_IDX, RING_IDX *, 15696375eacSRoger Pau Monné struct mbuf **); 15789e0f4d2SKip Macy 1583c790178SJohn Baldwin #define virt_to_mfn(x) (vtophys(x) >> PAGE_SHIFT) 15989e0f4d2SKip Macy 16089e0f4d2SKip Macy #define INVALID_P2M_ENTRY (~0UL) 16196375eacSRoger Pau Monné #define XN_QUEUE_NAME_LEN 8 /* xn{t,r}x_%u, allow for two digits */ 16296375eacSRoger Pau Monné struct netfront_rxq { 16396375eacSRoger Pau Monné struct netfront_info *info; 16496375eacSRoger Pau Monné u_int id; 16596375eacSRoger Pau Monné char name[XN_QUEUE_NAME_LEN]; 16696375eacSRoger Pau Monné struct mtx lock; 16796375eacSRoger Pau Monné 16896375eacSRoger Pau Monné int ring_ref; 16996375eacSRoger Pau Monné netif_rx_front_ring_t ring; 17096375eacSRoger Pau Monné xen_intr_handle_t xen_intr_handle; 17196375eacSRoger Pau Monné 17296375eacSRoger Pau Monné grant_ref_t gref_head; 17336ea5721SOlivier Houchard grant_ref_t grant_ref[NET_RX_RING_SIZE + 1]; 17496375eacSRoger Pau Monné 17596375eacSRoger Pau Monné struct mbuf *mbufs[NET_RX_RING_SIZE + 1]; 17696375eacSRoger Pau Monné 17796375eacSRoger Pau Monné struct lro_ctrl lro; 17896375eacSRoger Pau Monné 1792568ee67SRoger Pau Monné struct callout rx_refill; 18096375eacSRoger Pau Monné }; 18196375eacSRoger Pau Monné 18296375eacSRoger Pau Monné struct netfront_txq { 18396375eacSRoger Pau Monné struct netfront_info *info; 18496375eacSRoger Pau Monné u_int id; 18596375eacSRoger Pau Monné char name[XN_QUEUE_NAME_LEN]; 18696375eacSRoger Pau Monné struct mtx lock; 18796375eacSRoger Pau Monné 18896375eacSRoger Pau Monné int ring_ref; 18996375eacSRoger Pau Monné netif_tx_front_ring_t ring; 19096375eacSRoger Pau Monné xen_intr_handle_t xen_intr_handle; 19196375eacSRoger Pau Monné 19296375eacSRoger Pau Monné grant_ref_t gref_head; 19396375eacSRoger Pau Monné grant_ref_t grant_ref[NET_TX_RING_SIZE + 1]; 19496375eacSRoger Pau Monné 19596375eacSRoger Pau Monné struct mbuf *mbufs[NET_TX_RING_SIZE + 1]; 19696375eacSRoger Pau Monné int mbufs_cnt; 19796375eacSRoger Pau Monné struct buf_ring *br; 19896375eacSRoger Pau Monné 19996375eacSRoger Pau Monné struct taskqueue *tq; 20096375eacSRoger Pau Monné struct task defrtask; 20196375eacSRoger Pau Monné 20296375eacSRoger Pau Monné bool full; 20396375eacSRoger Pau Monné }; 20496375eacSRoger Pau Monné 20589e0f4d2SKip Macy struct netfront_info { 20689e0f4d2SKip Macy struct ifnet *xn_ifp; 20789e0f4d2SKip Macy 208227ca257SKip Macy struct mtx sc_lock; 20989e0f4d2SKip Macy 21096375eacSRoger Pau Monné u_int num_queues; 21196375eacSRoger Pau Monné struct netfront_rxq *rxq; 21296375eacSRoger Pau Monné struct netfront_txq *txq; 21396375eacSRoger Pau Monné 21489e0f4d2SKip Macy u_int carrier; 215578e4bf7SJustin T. Gibbs u_int maxfrags; 21689e0f4d2SKip Macy 21723dc5621SKip Macy device_t xbdev; 21889e0f4d2SKip Macy uint8_t mac[ETHER_ADDR_LEN]; 21989e0f4d2SKip Macy 22089e0f4d2SKip Macy int xn_if_flags; 22189e0f4d2SKip Macy 2220e509842SJustin T. Gibbs struct ifmedia sc_media; 2236a8e9695SRoger Pau Monné 224c2d12e5eSRoger Pau Monné bool xn_reset; 22589e0f4d2SKip Macy }; 22689e0f4d2SKip Macy 22796375eacSRoger Pau Monné struct netfront_rx_info { 22896375eacSRoger Pau Monné struct netif_rx_response rx; 22996375eacSRoger Pau Monné struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; 23096375eacSRoger Pau Monné }; 23189e0f4d2SKip Macy 23296375eacSRoger Pau Monné #define XN_RX_LOCK(_q) mtx_lock(&(_q)->lock) 23396375eacSRoger Pau Monné #define XN_RX_UNLOCK(_q) mtx_unlock(&(_q)->lock) 23489e0f4d2SKip Macy 23596375eacSRoger Pau Monné #define XN_TX_LOCK(_q) mtx_lock(&(_q)->lock) 23696375eacSRoger Pau Monné #define XN_TX_TRYLOCK(_q) mtx_trylock(&(_q)->lock) 23796375eacSRoger Pau Monné #define XN_TX_UNLOCK(_q) mtx_unlock(&(_q)->lock) 23889e0f4d2SKip Macy 239227ca257SKip Macy #define XN_LOCK(_sc) mtx_lock(&(_sc)->sc_lock); 240227ca257SKip Macy #define XN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock); 24189e0f4d2SKip Macy 242227ca257SKip Macy #define XN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED); 24396375eacSRoger Pau Monné #define XN_RX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); 24496375eacSRoger Pau Monné #define XN_TX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); 24589e0f4d2SKip Macy 24689e0f4d2SKip Macy #define netfront_carrier_on(netif) ((netif)->carrier = 1) 24789e0f4d2SKip Macy #define netfront_carrier_off(netif) ((netif)->carrier = 0) 24889e0f4d2SKip Macy #define netfront_carrier_ok(netif) ((netif)->carrier) 24989e0f4d2SKip Macy 25089e0f4d2SKip Macy /* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ 25189e0f4d2SKip Macy 25289e0f4d2SKip Macy static inline void 253931eeffaSKenneth D. Merry add_id_to_freelist(struct mbuf **list, uintptr_t id) 25489e0f4d2SKip Macy { 25596375eacSRoger Pau Monné 256931eeffaSKenneth D. Merry KASSERT(id != 0, 257931eeffaSKenneth D. Merry ("%s: the head item (0) must always be free.", __func__)); 25889e0f4d2SKip Macy list[id] = list[0]; 259931eeffaSKenneth D. Merry list[0] = (struct mbuf *)id; 26089e0f4d2SKip Macy } 26189e0f4d2SKip Macy 26289e0f4d2SKip Macy static inline unsigned short 26389e0f4d2SKip Macy get_id_from_freelist(struct mbuf **list) 26489e0f4d2SKip Macy { 265931eeffaSKenneth D. Merry uintptr_t id; 266931eeffaSKenneth D. Merry 267931eeffaSKenneth D. Merry id = (uintptr_t)list[0]; 268931eeffaSKenneth D. Merry KASSERT(id != 0, 269931eeffaSKenneth D. Merry ("%s: the head item (0) must always remain free.", __func__)); 27089e0f4d2SKip Macy list[0] = list[id]; 27189e0f4d2SKip Macy return (id); 27289e0f4d2SKip Macy } 27389e0f4d2SKip Macy 27489e0f4d2SKip Macy static inline int 27596375eacSRoger Pau Monné xn_rxidx(RING_IDX idx) 27689e0f4d2SKip Macy { 27796375eacSRoger Pau Monné 27889e0f4d2SKip Macy return idx & (NET_RX_RING_SIZE - 1); 27989e0f4d2SKip Macy } 28089e0f4d2SKip Macy 28189e0f4d2SKip Macy static inline struct mbuf * 28296375eacSRoger Pau Monné xn_get_rx_mbuf(struct netfront_rxq *rxq, RING_IDX ri) 28389e0f4d2SKip Macy { 28496375eacSRoger Pau Monné int i; 28589e0f4d2SKip Macy struct mbuf *m; 28689e0f4d2SKip Macy 28796375eacSRoger Pau Monné i = xn_rxidx(ri); 28896375eacSRoger Pau Monné m = rxq->mbufs[i]; 28996375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 29089e0f4d2SKip Macy return (m); 29189e0f4d2SKip Macy } 29289e0f4d2SKip Macy 29389e0f4d2SKip Macy static inline grant_ref_t 29496375eacSRoger Pau Monné xn_get_rx_ref(struct netfront_rxq *rxq, RING_IDX ri) 29589e0f4d2SKip Macy { 29696375eacSRoger Pau Monné int i = xn_rxidx(ri); 29796375eacSRoger Pau Monné grant_ref_t ref = rxq->grant_ref[i]; 29896375eacSRoger Pau Monné 299ff662b5cSJustin T. Gibbs KASSERT(ref != GRANT_REF_INVALID, ("Invalid grant reference!\n")); 30096375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 30196375eacSRoger Pau Monné return (ref); 30289e0f4d2SKip Macy } 30389e0f4d2SKip Macy 30489e0f4d2SKip Macy #define IPRINTK(fmt, args...) \ 30589e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 306227ca257SKip Macy #ifdef INVARIANTS 30789e0f4d2SKip Macy #define WPRINTK(fmt, args...) \ 30889e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 309227ca257SKip Macy #else 310227ca257SKip Macy #define WPRINTK(fmt, args...) 311227ca257SKip Macy #endif 312227ca257SKip Macy #ifdef DEBUG 31389e0f4d2SKip Macy #define DPRINTK(fmt, args...) \ 31423dc5621SKip Macy printf("[XEN] %s: " fmt, __func__, ##args) 31512678024SDoug Rabson #else 31612678024SDoug Rabson #define DPRINTK(fmt, args...) 31712678024SDoug Rabson #endif 31889e0f4d2SKip Macy 31989e0f4d2SKip Macy /** 32089e0f4d2SKip Macy * Read the 'mac' node at the given device's node in the store, and parse that 32189e0f4d2SKip Macy * as colon-separated octets, placing result the given mac array. mac must be 32289e0f4d2SKip Macy * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). 32389e0f4d2SKip Macy * Return 0 on success, or errno on error. 32489e0f4d2SKip Macy */ 32589e0f4d2SKip Macy static int 32623dc5621SKip Macy xen_net_read_mac(device_t dev, uint8_t mac[]) 32789e0f4d2SKip Macy { 3283a6d1fcfSKip Macy int error, i; 3293a6d1fcfSKip Macy char *s, *e, *macstr; 330ffa06904SJustin T. Gibbs const char *path; 3313a6d1fcfSKip Macy 332ffa06904SJustin T. Gibbs path = xenbus_get_node(dev); 333ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 334ffa06904SJustin T. Gibbs if (error == ENOENT) { 335ffa06904SJustin T. Gibbs /* 336ffa06904SJustin T. Gibbs * Deal with missing mac XenStore nodes on devices with 337ffa06904SJustin T. Gibbs * HVM emulation (the 'ioemu' configuration attribute) 338ffa06904SJustin T. Gibbs * enabled. 339ffa06904SJustin T. Gibbs * 340ffa06904SJustin T. Gibbs * The HVM emulator may execute in a stub device model 341ffa06904SJustin T. Gibbs * domain which lacks the permission, only given to Dom0, 342ffa06904SJustin T. Gibbs * to update the guest's XenStore tree. For this reason, 343ffa06904SJustin T. Gibbs * the HVM emulator doesn't even attempt to write the 344ffa06904SJustin T. Gibbs * front-side mac node, even when operating in Dom0. 345ffa06904SJustin T. Gibbs * However, there should always be a mac listed in the 346ffa06904SJustin T. Gibbs * backend tree. Fallback to this version if our query 347ffa06904SJustin T. Gibbs * of the front side XenStore location doesn't find 348ffa06904SJustin T. Gibbs * anything. 349ffa06904SJustin T. Gibbs */ 350ffa06904SJustin T. Gibbs path = xenbus_get_otherend_path(dev); 351ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 352ffa06904SJustin T. Gibbs } 353ffa06904SJustin T. Gibbs if (error != 0) { 354ffa06904SJustin T. Gibbs xenbus_dev_fatal(dev, error, "parsing %s/mac", path); 3553a6d1fcfSKip Macy return (error); 356ffa06904SJustin T. Gibbs } 3573a6d1fcfSKip Macy 35889e0f4d2SKip Macy s = macstr; 35989e0f4d2SKip Macy for (i = 0; i < ETHER_ADDR_LEN; i++) { 36089e0f4d2SKip Macy mac[i] = strtoul(s, &e, 16); 36189e0f4d2SKip Macy if (s == e || (e[0] != ':' && e[0] != 0)) { 362ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 3633a6d1fcfSKip Macy return (ENOENT); 36489e0f4d2SKip Macy } 36589e0f4d2SKip Macy s = &e[1]; 36689e0f4d2SKip Macy } 367ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 3683a6d1fcfSKip Macy return (0); 36989e0f4d2SKip Macy } 37089e0f4d2SKip Macy 37189e0f4d2SKip Macy /** 37289e0f4d2SKip Macy * Entry point to this code when a new device is created. Allocate the basic 37389e0f4d2SKip Macy * structures and the ring buffers for communication with the backend, and 37489e0f4d2SKip Macy * inform the backend of the appropriate details for those. Switch to 37589e0f4d2SKip Macy * Connected state. 37689e0f4d2SKip Macy */ 37789e0f4d2SKip Macy static int 37823dc5621SKip Macy netfront_probe(device_t dev) 37923dc5621SKip Macy { 38023dc5621SKip Macy 3815f700083SJulien Grall if (xen_pv_nics_disabled()) 382f8f1bb83SRoger Pau Monné return (ENXIO); 383f8f1bb83SRoger Pau Monné 38423dc5621SKip Macy if (!strcmp(xenbus_get_type(dev), "vif")) { 38523dc5621SKip Macy device_set_desc(dev, "Virtual Network Interface"); 38623dc5621SKip Macy return (0); 38723dc5621SKip Macy } 38823dc5621SKip Macy 38923dc5621SKip Macy return (ENXIO); 39023dc5621SKip Macy } 39123dc5621SKip Macy 39223dc5621SKip Macy static int 39323dc5621SKip Macy netfront_attach(device_t dev) 39489e0f4d2SKip Macy { 39589e0f4d2SKip Macy int err; 39689e0f4d2SKip Macy 39723dc5621SKip Macy err = create_netdev(dev); 39896375eacSRoger Pau Monné if (err != 0) { 39989e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "creating netdev"); 400ffa06904SJustin T. Gibbs return (err); 40189e0f4d2SKip Macy } 40289e0f4d2SKip Macy 40312678024SDoug Rabson SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 40412678024SDoug Rabson SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 405f0188618SHans Petter Selasky OID_AUTO, "enable_lro", CTLFLAG_RW, 40612678024SDoug Rabson &xn_enable_lro, 0, "Large Receive Offload"); 40712678024SDoug Rabson 40896375eacSRoger Pau Monné SYSCTL_ADD_ULONG(device_get_sysctl_ctx(dev), 40996375eacSRoger Pau Monné SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 41096375eacSRoger Pau Monné OID_AUTO, "num_queues", CTLFLAG_RD, 41196375eacSRoger Pau Monné &xn_num_queues, "Number of pairs of queues"); 41296375eacSRoger Pau Monné 413ffa06904SJustin T. Gibbs return (0); 41489e0f4d2SKip Macy } 41589e0f4d2SKip Macy 416cf9c09e1SJustin T. Gibbs static int 417cf9c09e1SJustin T. Gibbs netfront_suspend(device_t dev) 418cf9c09e1SJustin T. Gibbs { 41996375eacSRoger Pau Monné struct netfront_info *np = device_get_softc(dev); 42096375eacSRoger Pau Monné u_int i; 421cf9c09e1SJustin T. Gibbs 42296375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 42396375eacSRoger Pau Monné XN_RX_LOCK(&np->rxq[i]); 42496375eacSRoger Pau Monné XN_TX_LOCK(&np->txq[i]); 42596375eacSRoger Pau Monné } 42696375eacSRoger Pau Monné netfront_carrier_off(np); 42796375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 42896375eacSRoger Pau Monné XN_RX_UNLOCK(&np->rxq[i]); 42996375eacSRoger Pau Monné XN_TX_UNLOCK(&np->txq[i]); 43096375eacSRoger Pau Monné } 431cf9c09e1SJustin T. Gibbs return (0); 432cf9c09e1SJustin T. Gibbs } 43389e0f4d2SKip Macy 43489e0f4d2SKip Macy /** 43589e0f4d2SKip Macy * We are reconnecting to the backend, due to a suspend/resume, or a backend 43689e0f4d2SKip Macy * driver restart. We tear down our netif structure and recreate it, but 43789e0f4d2SKip Macy * leave the device-layer structures intact so that this is transparent to the 43889e0f4d2SKip Macy * rest of the kernel. 43989e0f4d2SKip Macy */ 44089e0f4d2SKip Macy static int 44123dc5621SKip Macy netfront_resume(device_t dev) 44289e0f4d2SKip Macy { 44323dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 4448dee0e9bSRoger Pau Monné u_int i; 4458dee0e9bSRoger Pau Monné 4468dee0e9bSRoger Pau Monné if (xen_suspend_cancelled) { 4478dee0e9bSRoger Pau Monné for (i = 0; i < info->num_queues; i++) { 4488dee0e9bSRoger Pau Monné XN_RX_LOCK(&info->rxq[i]); 4498dee0e9bSRoger Pau Monné XN_TX_LOCK(&info->txq[i]); 4508dee0e9bSRoger Pau Monné } 4518dee0e9bSRoger Pau Monné netfront_carrier_on(info); 4528dee0e9bSRoger Pau Monné for (i = 0; i < info->num_queues; i++) { 4538dee0e9bSRoger Pau Monné XN_RX_UNLOCK(&info->rxq[i]); 4548dee0e9bSRoger Pau Monné XN_TX_UNLOCK(&info->txq[i]); 4558dee0e9bSRoger Pau Monné } 4568dee0e9bSRoger Pau Monné return (0); 4578dee0e9bSRoger Pau Monné } 45889e0f4d2SKip Macy 45989e0f4d2SKip Macy netif_disconnect_backend(info); 46089e0f4d2SKip Macy return (0); 46189e0f4d2SKip Macy } 46289e0f4d2SKip Macy 46396375eacSRoger Pau Monné static int 46496375eacSRoger Pau Monné write_queue_xenstore_keys(device_t dev, 46596375eacSRoger Pau Monné struct netfront_rxq *rxq, 46696375eacSRoger Pau Monné struct netfront_txq *txq, 46796375eacSRoger Pau Monné struct xs_transaction *xst, bool hierarchy) 46896375eacSRoger Pau Monné { 46996375eacSRoger Pau Monné int err; 47096375eacSRoger Pau Monné const char *message; 47196375eacSRoger Pau Monné const char *node = xenbus_get_node(dev); 47296375eacSRoger Pau Monné char *path; 47396375eacSRoger Pau Monné size_t path_size; 47496375eacSRoger Pau Monné 47596375eacSRoger Pau Monné KASSERT(rxq->id == txq->id, ("Mismatch between RX and TX queue ids")); 47696375eacSRoger Pau Monné /* Split event channel support is not yet there. */ 47796375eacSRoger Pau Monné KASSERT(rxq->xen_intr_handle == txq->xen_intr_handle, 47896375eacSRoger Pau Monné ("Split event channels are not supported")); 47996375eacSRoger Pau Monné 48096375eacSRoger Pau Monné if (hierarchy) { 48196375eacSRoger Pau Monné path_size = strlen(node) + 10; 48296375eacSRoger Pau Monné path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); 48396375eacSRoger Pau Monné snprintf(path, path_size, "%s/queue-%u", node, rxq->id); 48496375eacSRoger Pau Monné } else { 48596375eacSRoger Pau Monné path_size = strlen(node) + 1; 48696375eacSRoger Pau Monné path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); 48796375eacSRoger Pau Monné snprintf(path, path_size, "%s", node); 48896375eacSRoger Pau Monné } 48996375eacSRoger Pau Monné 49096375eacSRoger Pau Monné err = xs_printf(*xst, path, "tx-ring-ref","%u", txq->ring_ref); 49196375eacSRoger Pau Monné if (err != 0) { 49296375eacSRoger Pau Monné message = "writing tx ring-ref"; 49396375eacSRoger Pau Monné goto error; 49496375eacSRoger Pau Monné } 49596375eacSRoger Pau Monné err = xs_printf(*xst, path, "rx-ring-ref","%u", rxq->ring_ref); 49696375eacSRoger Pau Monné if (err != 0) { 49796375eacSRoger Pau Monné message = "writing rx ring-ref"; 49896375eacSRoger Pau Monné goto error; 49996375eacSRoger Pau Monné } 50096375eacSRoger Pau Monné err = xs_printf(*xst, path, "event-channel", "%u", 50196375eacSRoger Pau Monné xen_intr_port(rxq->xen_intr_handle)); 50296375eacSRoger Pau Monné if (err != 0) { 50396375eacSRoger Pau Monné message = "writing event-channel"; 50496375eacSRoger Pau Monné goto error; 50596375eacSRoger Pau Monné } 50696375eacSRoger Pau Monné 50796375eacSRoger Pau Monné free(path, M_DEVBUF); 50896375eacSRoger Pau Monné 50996375eacSRoger Pau Monné return (0); 51096375eacSRoger Pau Monné 51196375eacSRoger Pau Monné error: 51296375eacSRoger Pau Monné free(path, M_DEVBUF); 51396375eacSRoger Pau Monné xenbus_dev_fatal(dev, err, "%s", message); 51496375eacSRoger Pau Monné 51596375eacSRoger Pau Monné return (err); 51696375eacSRoger Pau Monné } 51796375eacSRoger Pau Monné 51889e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */ 51989e0f4d2SKip Macy static int 52023dc5621SKip Macy talk_to_backend(device_t dev, struct netfront_info *info) 52189e0f4d2SKip Macy { 52289e0f4d2SKip Macy const char *message; 523ff662b5cSJustin T. Gibbs struct xs_transaction xst; 52423dc5621SKip Macy const char *node = xenbus_get_node(dev); 52589e0f4d2SKip Macy int err; 52696375eacSRoger Pau Monné unsigned long num_queues, max_queues = 0; 52796375eacSRoger Pau Monné unsigned int i; 52889e0f4d2SKip Macy 52989e0f4d2SKip Macy err = xen_net_read_mac(dev, info->mac); 53096375eacSRoger Pau Monné if (err != 0) { 53123dc5621SKip Macy xenbus_dev_fatal(dev, err, "parsing %s/mac", node); 53289e0f4d2SKip Macy goto out; 53389e0f4d2SKip Macy } 53489e0f4d2SKip Macy 53596375eacSRoger Pau Monné err = xs_scanf(XST_NIL, xenbus_get_otherend_path(info->xbdev), 53696375eacSRoger Pau Monné "multi-queue-max-queues", NULL, "%lu", &max_queues); 53796375eacSRoger Pau Monné if (err != 0) 53896375eacSRoger Pau Monné max_queues = 1; 53996375eacSRoger Pau Monné num_queues = xn_num_queues; 54096375eacSRoger Pau Monné if (num_queues > max_queues) 54196375eacSRoger Pau Monné num_queues = max_queues; 54296375eacSRoger Pau Monné 54396375eacSRoger Pau Monné err = setup_device(dev, info, num_queues); 54496375eacSRoger Pau Monné if (err != 0) 54589e0f4d2SKip Macy goto out; 54689e0f4d2SKip Macy 54789e0f4d2SKip Macy again: 548ff662b5cSJustin T. Gibbs err = xs_transaction_start(&xst); 54996375eacSRoger Pau Monné if (err != 0) { 55089e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "starting transaction"); 55196375eacSRoger Pau Monné goto free; 55289e0f4d2SKip Macy } 55396375eacSRoger Pau Monné 55496375eacSRoger Pau Monné if (info->num_queues == 1) { 55596375eacSRoger Pau Monné err = write_queue_xenstore_keys(dev, &info->rxq[0], 55696375eacSRoger Pau Monné &info->txq[0], &xst, false); 55796375eacSRoger Pau Monné if (err != 0) 55896375eacSRoger Pau Monné goto abort_transaction_no_def_error; 55996375eacSRoger Pau Monné } else { 56096375eacSRoger Pau Monné err = xs_printf(xst, node, "multi-queue-num-queues", 56196375eacSRoger Pau Monné "%u", info->num_queues); 56296375eacSRoger Pau Monné if (err != 0) { 56396375eacSRoger Pau Monné message = "writing multi-queue-num-queues"; 56489e0f4d2SKip Macy goto abort_transaction; 56589e0f4d2SKip Macy } 56696375eacSRoger Pau Monné 56796375eacSRoger Pau Monné for (i = 0; i < info->num_queues; i++) { 56896375eacSRoger Pau Monné err = write_queue_xenstore_keys(dev, &info->rxq[i], 56996375eacSRoger Pau Monné &info->txq[i], &xst, true); 57096375eacSRoger Pau Monné if (err != 0) 57196375eacSRoger Pau Monné goto abort_transaction_no_def_error; 57289e0f4d2SKip Macy } 57389e0f4d2SKip Macy } 57496375eacSRoger Pau Monné 575d0f3a8b9SRoger Pau Monné err = xs_printf(xst, node, "request-rx-copy", "%u", 1); 57696375eacSRoger Pau Monné if (err != 0) { 57789e0f4d2SKip Macy message = "writing request-rx-copy"; 57889e0f4d2SKip Macy goto abort_transaction; 57989e0f4d2SKip Macy } 580ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-rx-notify", "%d", 1); 58196375eacSRoger Pau Monné if (err != 0) { 58289e0f4d2SKip Macy message = "writing feature-rx-notify"; 58389e0f4d2SKip Macy goto abort_transaction; 58489e0f4d2SKip Macy } 585ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-sg", "%d", 1); 58696375eacSRoger Pau Monné if (err != 0) { 58789e0f4d2SKip Macy message = "writing feature-sg"; 58889e0f4d2SKip Macy goto abort_transaction; 58989e0f4d2SKip Macy } 590c2d12e5eSRoger Pau Monné if ((info->xn_ifp->if_capenable & IFCAP_LRO) != 0) { 591ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-gso-tcpv4", "%d", 1); 59296375eacSRoger Pau Monné if (err != 0) { 59389e0f4d2SKip Macy message = "writing feature-gso-tcpv4"; 59489e0f4d2SKip Macy goto abort_transaction; 59589e0f4d2SKip Macy } 596c2d12e5eSRoger Pau Monné } 597c2d12e5eSRoger Pau Monné if ((info->xn_ifp->if_capenable & IFCAP_RXCSUM) == 0) { 598c2d12e5eSRoger Pau Monné err = xs_printf(xst, node, "feature-no-csum-offload", "%d", 1); 599c2d12e5eSRoger Pau Monné if (err != 0) { 600c2d12e5eSRoger Pau Monné message = "writing feature-no-csum-offload"; 601c2d12e5eSRoger Pau Monné goto abort_transaction; 602c2d12e5eSRoger Pau Monné } 603c2d12e5eSRoger Pau Monné } 60489e0f4d2SKip Macy 605ff662b5cSJustin T. Gibbs err = xs_transaction_end(xst, 0); 60696375eacSRoger Pau Monné if (err != 0) { 60789e0f4d2SKip Macy if (err == EAGAIN) 60889e0f4d2SKip Macy goto again; 60989e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "completing transaction"); 61096375eacSRoger Pau Monné goto free; 61189e0f4d2SKip Macy } 61289e0f4d2SKip Macy 61389e0f4d2SKip Macy return 0; 61489e0f4d2SKip Macy 61589e0f4d2SKip Macy abort_transaction: 61689e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "%s", message); 61796375eacSRoger Pau Monné abort_transaction_no_def_error: 61896375eacSRoger Pau Monné xs_transaction_end(xst, 1); 61996375eacSRoger Pau Monné free: 62089e0f4d2SKip Macy netif_free(info); 62189e0f4d2SKip Macy out: 62296375eacSRoger Pau Monné return (err); 62396375eacSRoger Pau Monné } 62496375eacSRoger Pau Monné 62596375eacSRoger Pau Monné static void 626da695b05SRoger Pau Monné xn_rxq_intr(struct netfront_rxq *rxq) 62796375eacSRoger Pau Monné { 62896375eacSRoger Pau Monné 62996375eacSRoger Pau Monné XN_RX_LOCK(rxq); 63096375eacSRoger Pau Monné xn_rxeof(rxq); 63196375eacSRoger Pau Monné XN_RX_UNLOCK(rxq); 63296375eacSRoger Pau Monné } 63396375eacSRoger Pau Monné 63496375eacSRoger Pau Monné static void 63596375eacSRoger Pau Monné xn_txq_start(struct netfront_txq *txq) 63696375eacSRoger Pau Monné { 63796375eacSRoger Pau Monné struct netfront_info *np = txq->info; 63896375eacSRoger Pau Monné struct ifnet *ifp = np->xn_ifp; 63996375eacSRoger Pau Monné 64096375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 64196375eacSRoger Pau Monné if (!drbr_empty(ifp, txq->br)) 64296375eacSRoger Pau Monné xn_txq_mq_start_locked(txq, NULL); 64396375eacSRoger Pau Monné } 64496375eacSRoger Pau Monné 64596375eacSRoger Pau Monné static void 646da695b05SRoger Pau Monné xn_txq_intr(struct netfront_txq *txq) 64796375eacSRoger Pau Monné { 64896375eacSRoger Pau Monné 64996375eacSRoger Pau Monné XN_TX_LOCK(txq); 65096375eacSRoger Pau Monné if (RING_HAS_UNCONSUMED_RESPONSES(&txq->ring)) 65196375eacSRoger Pau Monné xn_txeof(txq); 65296375eacSRoger Pau Monné xn_txq_start(txq); 65396375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 65496375eacSRoger Pau Monné } 65596375eacSRoger Pau Monné 65696375eacSRoger Pau Monné static void 65796375eacSRoger Pau Monné xn_txq_tq_deferred(void *xtxq, int pending) 65896375eacSRoger Pau Monné { 65996375eacSRoger Pau Monné struct netfront_txq *txq = xtxq; 66096375eacSRoger Pau Monné 66196375eacSRoger Pau Monné XN_TX_LOCK(txq); 66296375eacSRoger Pau Monné xn_txq_start(txq); 66396375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 66496375eacSRoger Pau Monné } 66596375eacSRoger Pau Monné 66696375eacSRoger Pau Monné static void 66796375eacSRoger Pau Monné disconnect_rxq(struct netfront_rxq *rxq) 66896375eacSRoger Pau Monné { 66996375eacSRoger Pau Monné 67096375eacSRoger Pau Monné xn_release_rx_bufs(rxq); 67196375eacSRoger Pau Monné gnttab_free_grant_references(rxq->gref_head); 672d039b070SRoger Pau Monné gnttab_end_foreign_access(rxq->ring_ref, NULL); 67396375eacSRoger Pau Monné /* 67496375eacSRoger Pau Monné * No split event channel support at the moment, handle will 67596375eacSRoger Pau Monné * be unbound in tx. So no need to call xen_intr_unbind here, 67696375eacSRoger Pau Monné * but we do want to reset the handler to 0. 67796375eacSRoger Pau Monné */ 67896375eacSRoger Pau Monné rxq->xen_intr_handle = 0; 67996375eacSRoger Pau Monné } 68096375eacSRoger Pau Monné 68196375eacSRoger Pau Monné static void 68296375eacSRoger Pau Monné destroy_rxq(struct netfront_rxq *rxq) 68396375eacSRoger Pau Monné { 68496375eacSRoger Pau Monné 6852568ee67SRoger Pau Monné callout_drain(&rxq->rx_refill); 68696375eacSRoger Pau Monné free(rxq->ring.sring, M_DEVBUF); 68796375eacSRoger Pau Monné } 68896375eacSRoger Pau Monné 68996375eacSRoger Pau Monné static void 69096375eacSRoger Pau Monné destroy_rxqs(struct netfront_info *np) 69196375eacSRoger Pau Monné { 69296375eacSRoger Pau Monné int i; 69396375eacSRoger Pau Monné 69496375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 69596375eacSRoger Pau Monné destroy_rxq(&np->rxq[i]); 69696375eacSRoger Pau Monné 69796375eacSRoger Pau Monné free(np->rxq, M_DEVBUF); 69896375eacSRoger Pau Monné np->rxq = NULL; 69989e0f4d2SKip Macy } 70089e0f4d2SKip Macy 70189e0f4d2SKip Macy static int 70296375eacSRoger Pau Monné setup_rxqs(device_t dev, struct netfront_info *info, 70396375eacSRoger Pau Monné unsigned long num_queues) 70489e0f4d2SKip Macy { 70596375eacSRoger Pau Monné int q, i; 7063a6d1fcfSKip Macy int error; 70796375eacSRoger Pau Monné netif_rx_sring_t *rxs; 70896375eacSRoger Pau Monné struct netfront_rxq *rxq; 70989e0f4d2SKip Macy 71096375eacSRoger Pau Monné info->rxq = malloc(sizeof(struct netfront_rxq) * num_queues, 71196375eacSRoger Pau Monné M_DEVBUF, M_WAITOK|M_ZERO); 71289e0f4d2SKip Macy 71396375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) { 71496375eacSRoger Pau Monné rxq = &info->rxq[q]; 71596375eacSRoger Pau Monné 71696375eacSRoger Pau Monné rxq->id = q; 71796375eacSRoger Pau Monné rxq->info = info; 71896375eacSRoger Pau Monné rxq->ring_ref = GRANT_REF_INVALID; 71996375eacSRoger Pau Monné rxq->ring.sring = NULL; 72096375eacSRoger Pau Monné snprintf(rxq->name, XN_QUEUE_NAME_LEN, "xnrx_%u", q); 72196375eacSRoger Pau Monné mtx_init(&rxq->lock, rxq->name, "netfront receive lock", 72296375eacSRoger Pau Monné MTX_DEF); 72396375eacSRoger Pau Monné 72496375eacSRoger Pau Monné for (i = 0; i <= NET_RX_RING_SIZE; i++) { 72596375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 72696375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 72796375eacSRoger Pau Monné } 72896375eacSRoger Pau Monné 72996375eacSRoger Pau Monné /* Start resources allocation */ 73096375eacSRoger Pau Monné 7312568ee67SRoger Pau Monné if (gnttab_alloc_grant_references(NET_RX_RING_SIZE, 73296375eacSRoger Pau Monné &rxq->gref_head) != 0) { 73396375eacSRoger Pau Monné device_printf(dev, "allocating rx gref"); 7343a6d1fcfSKip Macy error = ENOMEM; 73589e0f4d2SKip Macy goto fail; 73689e0f4d2SKip Macy } 73789e0f4d2SKip Macy 73896375eacSRoger Pau Monné rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, 73996375eacSRoger Pau Monné M_WAITOK|M_ZERO); 74089e0f4d2SKip Macy SHARED_RING_INIT(rxs); 74196375eacSRoger Pau Monné FRONT_RING_INIT(&rxq->ring, rxs, PAGE_SIZE); 74289e0f4d2SKip Macy 74396375eacSRoger Pau Monné error = xenbus_grant_ring(dev, virt_to_mfn(rxs), 74496375eacSRoger Pau Monné &rxq->ring_ref); 74596375eacSRoger Pau Monné if (error != 0) { 74696375eacSRoger Pau Monné device_printf(dev, "granting rx ring page"); 74796375eacSRoger Pau Monné goto fail_grant_ring; 74896375eacSRoger Pau Monné } 74989e0f4d2SKip Macy 7502568ee67SRoger Pau Monné callout_init(&rxq->rx_refill, 1); 75189e0f4d2SKip Macy } 75289e0f4d2SKip Macy 7533a6d1fcfSKip Macy return (0); 75489e0f4d2SKip Macy 75596375eacSRoger Pau Monné fail_grant_ring: 75696375eacSRoger Pau Monné gnttab_free_grant_references(rxq->gref_head); 75796375eacSRoger Pau Monné free(rxq->ring.sring, M_DEVBUF); 75889e0f4d2SKip Macy fail: 75996375eacSRoger Pau Monné for (; q >= 0; q--) { 76096375eacSRoger Pau Monné disconnect_rxq(&info->rxq[q]); 76196375eacSRoger Pau Monné destroy_rxq(&info->rxq[q]); 76296375eacSRoger Pau Monné } 76396375eacSRoger Pau Monné 76496375eacSRoger Pau Monné free(info->rxq, M_DEVBUF); 76596375eacSRoger Pau Monné return (error); 76696375eacSRoger Pau Monné } 76796375eacSRoger Pau Monné 76896375eacSRoger Pau Monné static void 76996375eacSRoger Pau Monné disconnect_txq(struct netfront_txq *txq) 77096375eacSRoger Pau Monné { 77196375eacSRoger Pau Monné 77296375eacSRoger Pau Monné xn_release_tx_bufs(txq); 77396375eacSRoger Pau Monné gnttab_free_grant_references(txq->gref_head); 774d039b070SRoger Pau Monné gnttab_end_foreign_access(txq->ring_ref, NULL); 77596375eacSRoger Pau Monné xen_intr_unbind(&txq->xen_intr_handle); 77696375eacSRoger Pau Monné } 77796375eacSRoger Pau Monné 77896375eacSRoger Pau Monné static void 77996375eacSRoger Pau Monné destroy_txq(struct netfront_txq *txq) 78096375eacSRoger Pau Monné { 78196375eacSRoger Pau Monné 78296375eacSRoger Pau Monné free(txq->ring.sring, M_DEVBUF); 78396375eacSRoger Pau Monné buf_ring_free(txq->br, M_DEVBUF); 78496375eacSRoger Pau Monné taskqueue_drain_all(txq->tq); 78596375eacSRoger Pau Monné taskqueue_free(txq->tq); 78696375eacSRoger Pau Monné } 78796375eacSRoger Pau Monné 78896375eacSRoger Pau Monné static void 78996375eacSRoger Pau Monné destroy_txqs(struct netfront_info *np) 79096375eacSRoger Pau Monné { 79196375eacSRoger Pau Monné int i; 79296375eacSRoger Pau Monné 79396375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 79496375eacSRoger Pau Monné destroy_txq(&np->txq[i]); 79596375eacSRoger Pau Monné 79696375eacSRoger Pau Monné free(np->txq, M_DEVBUF); 79796375eacSRoger Pau Monné np->txq = NULL; 79896375eacSRoger Pau Monné } 79996375eacSRoger Pau Monné 80096375eacSRoger Pau Monné static int 80196375eacSRoger Pau Monné setup_txqs(device_t dev, struct netfront_info *info, 80296375eacSRoger Pau Monné unsigned long num_queues) 80396375eacSRoger Pau Monné { 80496375eacSRoger Pau Monné int q, i; 80596375eacSRoger Pau Monné int error; 80696375eacSRoger Pau Monné netif_tx_sring_t *txs; 80796375eacSRoger Pau Monné struct netfront_txq *txq; 80896375eacSRoger Pau Monné 80996375eacSRoger Pau Monné info->txq = malloc(sizeof(struct netfront_txq) * num_queues, 81096375eacSRoger Pau Monné M_DEVBUF, M_WAITOK|M_ZERO); 81196375eacSRoger Pau Monné 81296375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) { 81396375eacSRoger Pau Monné txq = &info->txq[q]; 81496375eacSRoger Pau Monné 81596375eacSRoger Pau Monné txq->id = q; 81696375eacSRoger Pau Monné txq->info = info; 81796375eacSRoger Pau Monné 81896375eacSRoger Pau Monné txq->ring_ref = GRANT_REF_INVALID; 81996375eacSRoger Pau Monné txq->ring.sring = NULL; 82096375eacSRoger Pau Monné 82196375eacSRoger Pau Monné snprintf(txq->name, XN_QUEUE_NAME_LEN, "xntx_%u", q); 82296375eacSRoger Pau Monné 82396375eacSRoger Pau Monné mtx_init(&txq->lock, txq->name, "netfront transmit lock", 82496375eacSRoger Pau Monné MTX_DEF); 82596375eacSRoger Pau Monné 82696375eacSRoger Pau Monné for (i = 0; i <= NET_TX_RING_SIZE; i++) { 82796375eacSRoger Pau Monné txq->mbufs[i] = (void *) ((u_long) i+1); 82896375eacSRoger Pau Monné txq->grant_ref[i] = GRANT_REF_INVALID; 82996375eacSRoger Pau Monné } 83096375eacSRoger Pau Monné txq->mbufs[NET_TX_RING_SIZE] = (void *)0; 83196375eacSRoger Pau Monné 83296375eacSRoger Pau Monné /* Start resources allocation. */ 83396375eacSRoger Pau Monné 83496375eacSRoger Pau Monné if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, 83596375eacSRoger Pau Monné &txq->gref_head) != 0) { 83696375eacSRoger Pau Monné device_printf(dev, "failed to allocate tx grant refs\n"); 83796375eacSRoger Pau Monné error = ENOMEM; 83896375eacSRoger Pau Monné goto fail; 83996375eacSRoger Pau Monné } 84096375eacSRoger Pau Monné 84196375eacSRoger Pau Monné txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, 84296375eacSRoger Pau Monné M_WAITOK|M_ZERO); 84396375eacSRoger Pau Monné SHARED_RING_INIT(txs); 84496375eacSRoger Pau Monné FRONT_RING_INIT(&txq->ring, txs, PAGE_SIZE); 84596375eacSRoger Pau Monné 84696375eacSRoger Pau Monné error = xenbus_grant_ring(dev, virt_to_mfn(txs), 84796375eacSRoger Pau Monné &txq->ring_ref); 84896375eacSRoger Pau Monné if (error != 0) { 84996375eacSRoger Pau Monné device_printf(dev, "failed to grant tx ring\n"); 85096375eacSRoger Pau Monné goto fail_grant_ring; 85196375eacSRoger Pau Monné } 85296375eacSRoger Pau Monné 85396375eacSRoger Pau Monné txq->br = buf_ring_alloc(NET_TX_RING_SIZE, M_DEVBUF, 85496375eacSRoger Pau Monné M_WAITOK, &txq->lock); 85596375eacSRoger Pau Monné TASK_INIT(&txq->defrtask, 0, xn_txq_tq_deferred, txq); 85696375eacSRoger Pau Monné 857da695b05SRoger Pau Monné txq->tq = taskqueue_create(txq->name, M_WAITOK, 85896375eacSRoger Pau Monné taskqueue_thread_enqueue, &txq->tq); 85996375eacSRoger Pau Monné 86096375eacSRoger Pau Monné error = taskqueue_start_threads(&txq->tq, 1, PI_NET, 86196375eacSRoger Pau Monné "%s txq %d", device_get_nameunit(dev), txq->id); 86296375eacSRoger Pau Monné if (error != 0) { 86396375eacSRoger Pau Monné device_printf(dev, "failed to start tx taskq %d\n", 86496375eacSRoger Pau Monné txq->id); 86596375eacSRoger Pau Monné goto fail_start_thread; 86696375eacSRoger Pau Monné } 86796375eacSRoger Pau Monné 86896375eacSRoger Pau Monné error = xen_intr_alloc_and_bind_local_port(dev, 869da695b05SRoger Pau Monné xenbus_get_otherend_id(dev), /* filter */ NULL, xn_intr, 870da695b05SRoger Pau Monné &info->txq[q], INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY, 87196375eacSRoger Pau Monné &txq->xen_intr_handle); 87296375eacSRoger Pau Monné 87396375eacSRoger Pau Monné if (error != 0) { 87496375eacSRoger Pau Monné device_printf(dev, "xen_intr_alloc_and_bind_local_port failed\n"); 87596375eacSRoger Pau Monné goto fail_bind_port; 87696375eacSRoger Pau Monné } 87796375eacSRoger Pau Monné } 87896375eacSRoger Pau Monné 87996375eacSRoger Pau Monné return (0); 88096375eacSRoger Pau Monné 88196375eacSRoger Pau Monné fail_bind_port: 88296375eacSRoger Pau Monné taskqueue_drain_all(txq->tq); 88396375eacSRoger Pau Monné fail_start_thread: 88496375eacSRoger Pau Monné buf_ring_free(txq->br, M_DEVBUF); 88596375eacSRoger Pau Monné taskqueue_free(txq->tq); 886d039b070SRoger Pau Monné gnttab_end_foreign_access(txq->ring_ref, NULL); 88796375eacSRoger Pau Monné fail_grant_ring: 88896375eacSRoger Pau Monné gnttab_free_grant_references(txq->gref_head); 88996375eacSRoger Pau Monné free(txq->ring.sring, M_DEVBUF); 89096375eacSRoger Pau Monné fail: 89196375eacSRoger Pau Monné for (; q >= 0; q--) { 89296375eacSRoger Pau Monné disconnect_txq(&info->txq[q]); 89396375eacSRoger Pau Monné destroy_txq(&info->txq[q]); 89496375eacSRoger Pau Monné } 89596375eacSRoger Pau Monné 89696375eacSRoger Pau Monné free(info->txq, M_DEVBUF); 89796375eacSRoger Pau Monné return (error); 89896375eacSRoger Pau Monné } 89996375eacSRoger Pau Monné 90096375eacSRoger Pau Monné static int 90196375eacSRoger Pau Monné setup_device(device_t dev, struct netfront_info *info, 90296375eacSRoger Pau Monné unsigned long num_queues) 90396375eacSRoger Pau Monné { 90496375eacSRoger Pau Monné int error; 90596375eacSRoger Pau Monné int q; 90696375eacSRoger Pau Monné 90796375eacSRoger Pau Monné if (info->txq) 90896375eacSRoger Pau Monné destroy_txqs(info); 90996375eacSRoger Pau Monné 91096375eacSRoger Pau Monné if (info->rxq) 91196375eacSRoger Pau Monné destroy_rxqs(info); 91296375eacSRoger Pau Monné 91396375eacSRoger Pau Monné info->num_queues = 0; 91496375eacSRoger Pau Monné 91596375eacSRoger Pau Monné error = setup_rxqs(dev, info, num_queues); 91696375eacSRoger Pau Monné if (error != 0) 91796375eacSRoger Pau Monné goto out; 91896375eacSRoger Pau Monné error = setup_txqs(dev, info, num_queues); 91996375eacSRoger Pau Monné if (error != 0) 92096375eacSRoger Pau Monné goto out; 92196375eacSRoger Pau Monné 92296375eacSRoger Pau Monné info->num_queues = num_queues; 92396375eacSRoger Pau Monné 92496375eacSRoger Pau Monné /* No split event channel at the moment. */ 92596375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) 92696375eacSRoger Pau Monné info->rxq[q].xen_intr_handle = info->txq[q].xen_intr_handle; 92796375eacSRoger Pau Monné 92896375eacSRoger Pau Monné return (0); 92996375eacSRoger Pau Monné 93096375eacSRoger Pau Monné out: 93196375eacSRoger Pau Monné KASSERT(error != 0, ("Error path taken without providing an error code")); 9323a6d1fcfSKip Macy return (error); 93389e0f4d2SKip Macy } 93489e0f4d2SKip Macy 935a0ae8f04SBjoern A. Zeeb #ifdef INET 93689e0f4d2SKip Macy /** 93712678024SDoug Rabson * If this interface has an ipv4 address, send an arp for it. This 93812678024SDoug Rabson * helps to get the network going again after migrating hosts. 93912678024SDoug Rabson */ 94012678024SDoug Rabson static void 94112678024SDoug Rabson netfront_send_fake_arp(device_t dev, struct netfront_info *info) 94212678024SDoug Rabson { 94312678024SDoug Rabson struct ifnet *ifp; 94412678024SDoug Rabson struct ifaddr *ifa; 94512678024SDoug Rabson 94612678024SDoug Rabson ifp = info->xn_ifp; 947d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 94812678024SDoug Rabson if (ifa->ifa_addr->sa_family == AF_INET) { 94912678024SDoug Rabson arp_ifinit(ifp, ifa); 95012678024SDoug Rabson } 95112678024SDoug Rabson } 95212678024SDoug Rabson } 953a0ae8f04SBjoern A. Zeeb #endif 95412678024SDoug Rabson 95512678024SDoug Rabson /** 95689e0f4d2SKip Macy * Callback received when the backend's state changes. 95789e0f4d2SKip Macy */ 958283d6f72SJustin T. Gibbs static void 95923dc5621SKip Macy netfront_backend_changed(device_t dev, XenbusState newstate) 96089e0f4d2SKip Macy { 96123dc5621SKip Macy struct netfront_info *sc = device_get_softc(dev); 96289e0f4d2SKip Macy 96323dc5621SKip Macy DPRINTK("newstate=%d\n", newstate); 96489e0f4d2SKip Macy 965903eaa68SKristof Provost CURVNET_SET(sc->xn_ifp->if_vnet); 966903eaa68SKristof Provost 96723dc5621SKip Macy switch (newstate) { 96889e0f4d2SKip Macy case XenbusStateInitialising: 96989e0f4d2SKip Macy case XenbusStateInitialised: 97089e0f4d2SKip Macy case XenbusStateUnknown: 971920ba15bSKip Macy case XenbusStateReconfigured: 972920ba15bSKip Macy case XenbusStateReconfiguring: 97389e0f4d2SKip Macy break; 97489e0f4d2SKip Macy case XenbusStateInitWait: 97523dc5621SKip Macy if (xenbus_get_state(dev) != XenbusStateInitialising) 97689e0f4d2SKip Macy break; 97796375eacSRoger Pau Monné if (xn_connect(sc) != 0) 97889e0f4d2SKip Macy break; 97965671253SRoger Pau Monné /* Switch to connected state before kicking the rings. */ 98065671253SRoger Pau Monné xenbus_set_state(sc->xbdev, XenbusStateConnected); 98165671253SRoger Pau Monné xn_kick_rings(sc); 98223dc5621SKip Macy break; 98389e0f4d2SKip Macy case XenbusStateClosing: 98423dc5621SKip Macy xenbus_set_state(dev, XenbusStateClosed); 98589e0f4d2SKip Macy break; 986c2d12e5eSRoger Pau Monné case XenbusStateClosed: 987c2d12e5eSRoger Pau Monné if (sc->xn_reset) { 988c2d12e5eSRoger Pau Monné netif_disconnect_backend(sc); 989c2d12e5eSRoger Pau Monné xenbus_set_state(dev, XenbusStateInitialising); 990c2d12e5eSRoger Pau Monné sc->xn_reset = false; 991c2d12e5eSRoger Pau Monné } 992c2d12e5eSRoger Pau Monné break; 993dbf82bdeSRoger Pau Monné case XenbusStateConnected: 994dbf82bdeSRoger Pau Monné #ifdef INET 995dbf82bdeSRoger Pau Monné netfront_send_fake_arp(dev, sc); 996dbf82bdeSRoger Pau Monné #endif 997dbf82bdeSRoger Pau Monné break; 99889e0f4d2SKip Macy } 999903eaa68SKristof Provost 1000903eaa68SKristof Provost CURVNET_RESTORE(); 100189e0f4d2SKip Macy } 100289e0f4d2SKip Macy 1003931eeffaSKenneth D. Merry /** 1004931eeffaSKenneth D. Merry * \brief Verify that there is sufficient space in the Tx ring 1005931eeffaSKenneth D. Merry * buffer for a maximally sized request to be enqueued. 1006c099cafaSAdrian Chadd * 1007931eeffaSKenneth D. Merry * A transmit request requires a transmit descriptor for each packet 1008931eeffaSKenneth D. Merry * fragment, plus up to 2 entries for "options" (e.g. TSO). 1009c099cafaSAdrian Chadd */ 101089e0f4d2SKip Macy static inline int 101196375eacSRoger Pau Monné xn_tx_slot_available(struct netfront_txq *txq) 101289e0f4d2SKip Macy { 101396375eacSRoger Pau Monné 101496375eacSRoger Pau Monné return (RING_FREE_REQUESTS(&txq->ring) > (MAX_TX_REQ_FRAGS + 2)); 101589e0f4d2SKip Macy } 1016931eeffaSKenneth D. Merry 101789e0f4d2SKip Macy static void 101896375eacSRoger Pau Monné xn_release_tx_bufs(struct netfront_txq *txq) 101989e0f4d2SKip Macy { 102089e0f4d2SKip Macy int i; 102189e0f4d2SKip Macy 102289e0f4d2SKip Macy for (i = 1; i <= NET_TX_RING_SIZE; i++) { 1023931eeffaSKenneth D. Merry struct mbuf *m; 102489e0f4d2SKip Macy 102596375eacSRoger Pau Monné m = txq->mbufs[i]; 1026931eeffaSKenneth D. Merry 1027931eeffaSKenneth D. Merry /* 1028931eeffaSKenneth D. Merry * We assume that no kernel addresses are 1029931eeffaSKenneth D. Merry * less than NET_TX_RING_SIZE. Any entry 1030931eeffaSKenneth D. Merry * in the table that is below this number 1031931eeffaSKenneth D. Merry * must be an index from free-list tracking. 1032931eeffaSKenneth D. Merry */ 1033931eeffaSKenneth D. Merry if (((uintptr_t)m) <= NET_TX_RING_SIZE) 103489e0f4d2SKip Macy continue; 103596375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->grant_ref[i]); 103696375eacSRoger Pau Monné gnttab_release_grant_reference(&txq->gref_head, 103796375eacSRoger Pau Monné txq->grant_ref[i]); 103896375eacSRoger Pau Monné txq->grant_ref[i] = GRANT_REF_INVALID; 103996375eacSRoger Pau Monné add_id_to_freelist(txq->mbufs, i); 104096375eacSRoger Pau Monné txq->mbufs_cnt--; 104196375eacSRoger Pau Monné if (txq->mbufs_cnt < 0) { 10426f9767acSMarius Strobl panic("%s: tx_chain_cnt must be >= 0", __func__); 1043a4ec37f5SAdrian Chadd } 1044cf9c09e1SJustin T. Gibbs m_free(m); 104589e0f4d2SKip Macy } 104689e0f4d2SKip Macy } 104789e0f4d2SKip Macy 10482568ee67SRoger Pau Monné static struct mbuf * 10492568ee67SRoger Pau Monné xn_alloc_one_rx_buffer(struct netfront_rxq *rxq) 10502568ee67SRoger Pau Monné { 10512568ee67SRoger Pau Monné struct mbuf *m; 10522568ee67SRoger Pau Monné 10532568ee67SRoger Pau Monné m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 10542568ee67SRoger Pau Monné if (m == NULL) 10552568ee67SRoger Pau Monné return NULL; 10562568ee67SRoger Pau Monné m->m_len = m->m_pkthdr.len = MJUMPAGESIZE; 10572568ee67SRoger Pau Monné 10582568ee67SRoger Pau Monné return (m); 10592568ee67SRoger Pau Monné } 10602568ee67SRoger Pau Monné 106189e0f4d2SKip Macy static void 106296375eacSRoger Pau Monné xn_alloc_rx_buffers(struct netfront_rxq *rxq) 106389e0f4d2SKip Macy { 106489e0f4d2SKip Macy RING_IDX req_prod; 10652568ee67SRoger Pau Monné int notify; 10662568ee67SRoger Pau Monné 10672568ee67SRoger Pau Monné XN_RX_LOCK_ASSERT(rxq); 10682568ee67SRoger Pau Monné 10692568ee67SRoger Pau Monné if (__predict_false(rxq->info->carrier == 0)) 10702568ee67SRoger Pau Monné return; 10712568ee67SRoger Pau Monné 10722568ee67SRoger Pau Monné for (req_prod = rxq->ring.req_prod_pvt; 10732568ee67SRoger Pau Monné req_prod - rxq->ring.rsp_cons < NET_RX_RING_SIZE; 10742568ee67SRoger Pau Monné req_prod++) { 10752568ee67SRoger Pau Monné struct mbuf *m; 10762568ee67SRoger Pau Monné unsigned short id; 107789e0f4d2SKip Macy grant_ref_t ref; 10782568ee67SRoger Pau Monné struct netif_rx_request *req; 10792568ee67SRoger Pau Monné unsigned long pfn; 108089e0f4d2SKip Macy 10812568ee67SRoger Pau Monné m = xn_alloc_one_rx_buffer(rxq); 10822568ee67SRoger Pau Monné if (m == NULL) 108389e0f4d2SKip Macy break; 108489e0f4d2SKip Macy 10852568ee67SRoger Pau Monné id = xn_rxidx(req_prod); 108689e0f4d2SKip Macy 108796375eacSRoger Pau Monné KASSERT(rxq->mbufs[id] == NULL, ("non-NULL xn_rx_chain")); 10882568ee67SRoger Pau Monné rxq->mbufs[id] = m; 108989e0f4d2SKip Macy 109096375eacSRoger Pau Monné ref = gnttab_claim_grant_reference(&rxq->gref_head); 1091ff662b5cSJustin T. Gibbs KASSERT(ref != GNTTAB_LIST_END, 1092ff662b5cSJustin T. Gibbs ("reserved grant references exhuasted")); 109396375eacSRoger Pau Monné rxq->grant_ref[id] = ref; 109489e0f4d2SKip Macy 10952568ee67SRoger Pau Monné pfn = atop(vtophys(mtod(m, vm_offset_t))); 10962568ee67SRoger Pau Monné req = RING_GET_REQUEST(&rxq->ring, req_prod); 109789e0f4d2SKip Macy 10982568ee67SRoger Pau Monné gnttab_grant_foreign_access_ref(ref, 10992568ee67SRoger Pau Monné xenbus_get_otherend_id(rxq->info->xbdev), pfn, 0); 110089e0f4d2SKip Macy req->id = id; 110189e0f4d2SKip Macy req->gref = ref; 110289e0f4d2SKip Macy } 110389e0f4d2SKip Macy 11042568ee67SRoger Pau Monné rxq->ring.req_prod_pvt = req_prod; 110589e0f4d2SKip Macy 11062568ee67SRoger Pau Monné /* Not enough requests? Try again later. */ 11072568ee67SRoger Pau Monné if (req_prod - rxq->ring.rsp_cons < NET_RX_SLOTS_MIN) { 1108bf7b50dbSRoger Pau Monné callout_reset_curcpu(&rxq->rx_refill, hz/10, 1109bf7b50dbSRoger Pau Monné xn_alloc_rx_buffers_callout, rxq); 11102568ee67SRoger Pau Monné return; 11112568ee67SRoger Pau Monné } 11122568ee67SRoger Pau Monné 11132568ee67SRoger Pau Monné wmb(); /* barrier so backend seens requests */ 11142568ee67SRoger Pau Monné 111596375eacSRoger Pau Monné RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&rxq->ring, notify); 111689e0f4d2SKip Macy if (notify) 111796375eacSRoger Pau Monné xen_intr_signal(rxq->xen_intr_handle); 111889e0f4d2SKip Macy } 111989e0f4d2SKip Macy 11202568ee67SRoger Pau Monné static void xn_alloc_rx_buffers_callout(void *arg) 11212568ee67SRoger Pau Monné { 11222568ee67SRoger Pau Monné struct netfront_rxq *rxq; 11232568ee67SRoger Pau Monné 11242568ee67SRoger Pau Monné rxq = (struct netfront_rxq *)arg; 11252568ee67SRoger Pau Monné XN_RX_LOCK(rxq); 11262568ee67SRoger Pau Monné xn_alloc_rx_buffers(rxq); 11272568ee67SRoger Pau Monné XN_RX_UNLOCK(rxq); 11282568ee67SRoger Pau Monné } 11292568ee67SRoger Pau Monné 113089e0f4d2SKip Macy static void 113196375eacSRoger Pau Monné xn_release_rx_bufs(struct netfront_rxq *rxq) 113296375eacSRoger Pau Monné { 113396375eacSRoger Pau Monné int i, ref; 113496375eacSRoger Pau Monné struct mbuf *m; 113596375eacSRoger Pau Monné 113696375eacSRoger Pau Monné for (i = 0; i < NET_RX_RING_SIZE; i++) { 113796375eacSRoger Pau Monné m = rxq->mbufs[i]; 113896375eacSRoger Pau Monné 113996375eacSRoger Pau Monné if (m == NULL) 114096375eacSRoger Pau Monné continue; 114196375eacSRoger Pau Monné 114296375eacSRoger Pau Monné ref = rxq->grant_ref[i]; 114396375eacSRoger Pau Monné if (ref == GRANT_REF_INVALID) 114496375eacSRoger Pau Monné continue; 114596375eacSRoger Pau Monné 114696375eacSRoger Pau Monné gnttab_end_foreign_access_ref(ref); 114796375eacSRoger Pau Monné gnttab_release_grant_reference(&rxq->gref_head, ref); 114896375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 114996375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 115096375eacSRoger Pau Monné m_freem(m); 115196375eacSRoger Pau Monné } 115296375eacSRoger Pau Monné } 115396375eacSRoger Pau Monné 115496375eacSRoger Pau Monné static void 115596375eacSRoger Pau Monné xn_rxeof(struct netfront_rxq *rxq) 115689e0f4d2SKip Macy { 115789e0f4d2SKip Macy struct ifnet *ifp; 115896375eacSRoger Pau Monné struct netfront_info *np = rxq->info; 11593778878dSRoger Pau Monné #if (defined(INET) || defined(INET6)) 116096375eacSRoger Pau Monné struct lro_ctrl *lro = &rxq->lro; 11613778878dSRoger Pau Monné #endif 116289e0f4d2SKip Macy struct netfront_rx_info rinfo; 116389e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo.rx; 116489e0f4d2SKip Macy struct netif_extra_info *extras = rinfo.extras; 116589e0f4d2SKip Macy RING_IDX i, rp; 116689e0f4d2SKip Macy struct mbuf *m; 116796375eacSRoger Pau Monné struct mbufq mbufq_rxq, mbufq_errq; 1168d0f3a8b9SRoger Pau Monné int err, work_to_do; 116989e0f4d2SKip Macy 117096375eacSRoger Pau Monné XN_RX_LOCK_ASSERT(rxq); 1171bf319173SRoger Pau Monné 117289e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 117389e0f4d2SKip Macy return; 117489e0f4d2SKip Macy 1175c578b6acSGleb Smirnoff /* XXX: there should be some sane limit. */ 117696375eacSRoger Pau Monné mbufq_init(&mbufq_errq, INT_MAX); 117796375eacSRoger Pau Monné mbufq_init(&mbufq_rxq, INT_MAX); 117889e0f4d2SKip Macy 117989e0f4d2SKip Macy ifp = np->xn_ifp; 118089e0f4d2SKip Macy 1181bf319173SRoger Pau Monné do { 118296375eacSRoger Pau Monné rp = rxq->ring.sring->rsp_prod; 118389e0f4d2SKip Macy rmb(); /* Ensure we see queued responses up to 'rp'. */ 118489e0f4d2SKip Macy 118596375eacSRoger Pau Monné i = rxq->ring.rsp_cons; 118689e0f4d2SKip Macy while ((i != rp)) { 118796375eacSRoger Pau Monné memcpy(rx, RING_GET_RESPONSE(&rxq->ring, i), sizeof(*rx)); 118889e0f4d2SKip Macy memset(extras, 0, sizeof(rinfo.extras)); 118989e0f4d2SKip Macy 119083b92f6eSKip Macy m = NULL; 119196375eacSRoger Pau Monné err = xn_get_responses(rxq, &rinfo, rp, &i, &m); 119289e0f4d2SKip Macy 119376acc41fSJustin T. Gibbs if (__predict_false(err)) { 119483b92f6eSKip Macy if (m) 119596375eacSRoger Pau Monné (void )mbufq_enqueue(&mbufq_errq, m); 1196b2fd6999SRoger Pau Monné if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 119789e0f4d2SKip Macy continue; 119889e0f4d2SKip Macy } 119989e0f4d2SKip Macy 120089e0f4d2SKip Macy m->m_pkthdr.rcvif = ifp; 120189e0f4d2SKip Macy if (rx->flags & NETRXF_data_validated) { 120289e0f4d2SKip Macy /* 1203a81683c3SRoger Pau Monné * According to mbuf(9) the correct way to tell 1204a81683c3SRoger Pau Monné * the stack that the checksum of an inbound 1205a81683c3SRoger Pau Monné * packet is correct, without it actually being 1206a81683c3SRoger Pau Monné * present (because the underlying interface 1207a81683c3SRoger Pau Monné * doesn't provide it), is to set the 1208a81683c3SRoger Pau Monné * CSUM_DATA_VALID and CSUM_PSEUDO_HDR flags, 1209a81683c3SRoger Pau Monné * and the csum_data field to 0xffff. 121089e0f4d2SKip Macy */ 1211a81683c3SRoger Pau Monné m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID 121289e0f4d2SKip Macy | CSUM_PSEUDO_HDR); 121389e0f4d2SKip Macy m->m_pkthdr.csum_data = 0xffff; 121489e0f4d2SKip Macy } 1215d9a66b6dSRoger Pau Monné if ((rx->flags & NETRXF_extra_info) != 0 && 1216d9a66b6dSRoger Pau Monné (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type == 1217d9a66b6dSRoger Pau Monné XEN_NETIF_EXTRA_TYPE_GSO)) { 1218d9a66b6dSRoger Pau Monné m->m_pkthdr.tso_segsz = 1219d9a66b6dSRoger Pau Monné extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].u.gso.size; 1220d9a66b6dSRoger Pau Monné m->m_pkthdr.csum_flags |= CSUM_TSO; 1221d9a66b6dSRoger Pau Monné } 122289e0f4d2SKip Macy 122396375eacSRoger Pau Monné (void )mbufq_enqueue(&mbufq_rxq, m); 122489e0f4d2SKip Macy } 122589e0f4d2SKip Macy 1226bf319173SRoger Pau Monné rxq->ring.rsp_cons = i; 122789e0f4d2SKip Macy 1228bf319173SRoger Pau Monné xn_alloc_rx_buffers(rxq); 1229bf319173SRoger Pau Monné 1230bf319173SRoger Pau Monné RING_FINAL_CHECK_FOR_RESPONSES(&rxq->ring, work_to_do); 1231bf319173SRoger Pau Monné } while (work_to_do); 1232bf319173SRoger Pau Monné 1233bf319173SRoger Pau Monné mbufq_drain(&mbufq_errq); 123489e0f4d2SKip Macy /* 123589e0f4d2SKip Macy * Process all the mbufs after the remapping is complete. 123689e0f4d2SKip Macy * Break the mbuf chain first though. 123789e0f4d2SKip Macy */ 123896375eacSRoger Pau Monné while ((m = mbufq_dequeue(&mbufq_rxq)) != NULL) { 1239c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 124008c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 124112678024SDoug Rabson /* Use LRO if possible */ 124212678024SDoug Rabson if ((ifp->if_capenable & IFCAP_LRO) == 0 || 124312678024SDoug Rabson lro->lro_cnt == 0 || tcp_lro_rx(lro, m, 0)) { 124412678024SDoug Rabson /* 124512678024SDoug Rabson * If LRO fails, pass up to the stack 124612678024SDoug Rabson * directly. 124712678024SDoug Rabson */ 124889e0f4d2SKip Macy (*ifp->if_input)(ifp, m); 124912678024SDoug Rabson } 125012678024SDoug Rabson #else 125112678024SDoug Rabson (*ifp->if_input)(ifp, m); 125212678024SDoug Rabson #endif 125389e0f4d2SKip Macy } 125489e0f4d2SKip Macy 125508c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 125612678024SDoug Rabson /* 125712678024SDoug Rabson * Flush any outstanding LRO work 125812678024SDoug Rabson */ 12596dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro); 126012678024SDoug Rabson #endif 126189e0f4d2SKip Macy } 126289e0f4d2SKip Macy 126389e0f4d2SKip Macy static void 126496375eacSRoger Pau Monné xn_txeof(struct netfront_txq *txq) 126589e0f4d2SKip Macy { 126689e0f4d2SKip Macy RING_IDX i, prod; 126789e0f4d2SKip Macy unsigned short id; 126889e0f4d2SKip Macy struct ifnet *ifp; 126912678024SDoug Rabson netif_tx_response_t *txr; 127089e0f4d2SKip Macy struct mbuf *m; 127196375eacSRoger Pau Monné struct netfront_info *np = txq->info; 127289e0f4d2SKip Macy 127396375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 127489e0f4d2SKip Macy 127589e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 127689e0f4d2SKip Macy return; 127789e0f4d2SKip Macy 127889e0f4d2SKip Macy ifp = np->xn_ifp; 127989e0f4d2SKip Macy 128089e0f4d2SKip Macy do { 128196375eacSRoger Pau Monné prod = txq->ring.sring->rsp_prod; 128289e0f4d2SKip Macy rmb(); /* Ensure we see responses up to 'rp'. */ 128389e0f4d2SKip Macy 128496375eacSRoger Pau Monné for (i = txq->ring.rsp_cons; i != prod; i++) { 128596375eacSRoger Pau Monné txr = RING_GET_RESPONSE(&txq->ring, i); 128612678024SDoug Rabson if (txr->status == NETIF_RSP_NULL) 128712678024SDoug Rabson continue; 128812678024SDoug Rabson 1289931eeffaSKenneth D. Merry if (txr->status != NETIF_RSP_OKAY) { 1290931eeffaSKenneth D. Merry printf("%s: WARNING: response is %d!\n", 1291931eeffaSKenneth D. Merry __func__, txr->status); 1292931eeffaSKenneth D. Merry } 129312678024SDoug Rabson id = txr->id; 129496375eacSRoger Pau Monné m = txq->mbufs[id]; 129596375eacSRoger Pau Monné KASSERT(m != NULL, ("mbuf not found in chain")); 1296931eeffaSKenneth D. Merry KASSERT((uintptr_t)m > NET_TX_RING_SIZE, 1297931eeffaSKenneth D. Merry ("mbuf already on the free list, but we're " 1298931eeffaSKenneth D. Merry "trying to free it again!")); 12992d8fae98SAdrian Chadd M_ASSERTVALID(m); 130089e0f4d2SKip Macy 130176acc41fSJustin T. Gibbs if (__predict_false(gnttab_query_foreign_access( 130296375eacSRoger Pau Monné txq->grant_ref[id]) != 0)) { 13036f9767acSMarius Strobl panic("%s: grant id %u still in use by the " 13046f9767acSMarius Strobl "backend", __func__, id); 130589e0f4d2SKip Macy } 130696375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->grant_ref[id]); 130789e0f4d2SKip Macy gnttab_release_grant_reference( 130896375eacSRoger Pau Monné &txq->gref_head, txq->grant_ref[id]); 130996375eacSRoger Pau Monné txq->grant_ref[id] = GRANT_REF_INVALID; 131089e0f4d2SKip Macy 131196375eacSRoger Pau Monné txq->mbufs[id] = NULL; 131296375eacSRoger Pau Monné add_id_to_freelist(txq->mbufs, id); 131396375eacSRoger Pau Monné txq->mbufs_cnt--; 131412678024SDoug Rabson m_free(m); 131596375eacSRoger Pau Monné /* Only mark the txq active if we've freed up at least one slot to try */ 1316d76e4550SAdrian Chadd ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 131789e0f4d2SKip Macy } 131896375eacSRoger Pau Monné txq->ring.rsp_cons = prod; 131989e0f4d2SKip Macy 132089e0f4d2SKip Macy /* 132189e0f4d2SKip Macy * Set a new event, then check for race with update of 132289e0f4d2SKip Macy * tx_cons. Note that it is essential to schedule a 132389e0f4d2SKip Macy * callback, no matter how few buffers are pending. Even if 132489e0f4d2SKip Macy * there is space in the transmit ring, higher layers may 132589e0f4d2SKip Macy * be blocked because too much data is outstanding: in such 132689e0f4d2SKip Macy * cases notification from Xen is likely to be the only kick 132789e0f4d2SKip Macy * that we'll get. 132889e0f4d2SKip Macy */ 132996375eacSRoger Pau Monné txq->ring.sring->rsp_event = 133096375eacSRoger Pau Monné prod + ((txq->ring.sring->req_prod - prod) >> 1) + 1; 133189e0f4d2SKip Macy 133289e0f4d2SKip Macy mb(); 133396375eacSRoger Pau Monné } while (prod != txq->ring.sring->rsp_prod); 133489e0f4d2SKip Macy 133596375eacSRoger Pau Monné if (txq->full && 133696375eacSRoger Pau Monné ((txq->ring.sring->req_prod - prod) < NET_TX_RING_SIZE)) { 133796375eacSRoger Pau Monné txq->full = false; 1338da695b05SRoger Pau Monné xn_txq_start(txq); 133989e0f4d2SKip Macy } 134089e0f4d2SKip Macy } 134189e0f4d2SKip Macy 134289e0f4d2SKip Macy static void 134396375eacSRoger Pau Monné xn_intr(void *xsc) 134496375eacSRoger Pau Monné { 134596375eacSRoger Pau Monné struct netfront_txq *txq = xsc; 134696375eacSRoger Pau Monné struct netfront_info *np = txq->info; 134796375eacSRoger Pau Monné struct netfront_rxq *rxq = &np->rxq[txq->id]; 134896375eacSRoger Pau Monné 134996375eacSRoger Pau Monné /* kick both tx and rx */ 135096375eacSRoger Pau Monné xn_rxq_intr(rxq); 135196375eacSRoger Pau Monné xn_txq_intr(txq); 135296375eacSRoger Pau Monné } 135396375eacSRoger Pau Monné 135496375eacSRoger Pau Monné static void 135596375eacSRoger Pau Monné xn_move_rx_slot(struct netfront_rxq *rxq, struct mbuf *m, 135696375eacSRoger Pau Monné grant_ref_t ref) 135796375eacSRoger Pau Monné { 135896375eacSRoger Pau Monné int new = xn_rxidx(rxq->ring.req_prod_pvt); 135996375eacSRoger Pau Monné 136096375eacSRoger Pau Monné KASSERT(rxq->mbufs[new] == NULL, ("mbufs != NULL")); 136196375eacSRoger Pau Monné rxq->mbufs[new] = m; 136296375eacSRoger Pau Monné rxq->grant_ref[new] = ref; 136396375eacSRoger Pau Monné RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->id = new; 136496375eacSRoger Pau Monné RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->gref = ref; 136596375eacSRoger Pau Monné rxq->ring.req_prod_pvt++; 136696375eacSRoger Pau Monné } 136796375eacSRoger Pau Monné 136896375eacSRoger Pau Monné static int 136996375eacSRoger Pau Monné xn_get_extras(struct netfront_rxq *rxq, 1370931eeffaSKenneth D. Merry struct netif_extra_info *extras, RING_IDX rp, RING_IDX *cons) 137189e0f4d2SKip Macy { 137289e0f4d2SKip Macy struct netif_extra_info *extra; 137389e0f4d2SKip Macy 137489e0f4d2SKip Macy int err = 0; 137589e0f4d2SKip Macy 137689e0f4d2SKip Macy do { 137789e0f4d2SKip Macy struct mbuf *m; 137889e0f4d2SKip Macy grant_ref_t ref; 137989e0f4d2SKip Macy 138076acc41fSJustin T. Gibbs if (__predict_false(*cons + 1 == rp)) { 1381931eeffaSKenneth D. Merry err = EINVAL; 138289e0f4d2SKip Macy break; 138389e0f4d2SKip Macy } 138489e0f4d2SKip Macy 138589e0f4d2SKip Macy extra = (struct netif_extra_info *) 138696375eacSRoger Pau Monné RING_GET_RESPONSE(&rxq->ring, ++(*cons)); 138789e0f4d2SKip Macy 138876acc41fSJustin T. Gibbs if (__predict_false(!extra->type || 138989e0f4d2SKip Macy extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { 1390931eeffaSKenneth D. Merry err = EINVAL; 139189e0f4d2SKip Macy } else { 139289e0f4d2SKip Macy memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); 139389e0f4d2SKip Macy } 139489e0f4d2SKip Macy 139596375eacSRoger Pau Monné m = xn_get_rx_mbuf(rxq, *cons); 139696375eacSRoger Pau Monné ref = xn_get_rx_ref(rxq, *cons); 139796375eacSRoger Pau Monné xn_move_rx_slot(rxq, m, ref); 139889e0f4d2SKip Macy } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); 139989e0f4d2SKip Macy 140089e0f4d2SKip Macy return err; 140189e0f4d2SKip Macy } 140289e0f4d2SKip Macy 140389e0f4d2SKip Macy static int 140496375eacSRoger Pau Monné xn_get_responses(struct netfront_rxq *rxq, 1405931eeffaSKenneth D. Merry struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, 1406d0f3a8b9SRoger Pau Monné struct mbuf **list) 140789e0f4d2SKip Macy { 140889e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo->rx; 140989e0f4d2SKip Macy struct netif_extra_info *extras = rinfo->extras; 141083b92f6eSKip Macy struct mbuf *m, *m0, *m_prev; 141196375eacSRoger Pau Monné grant_ref_t ref = xn_get_rx_ref(rxq, *cons); 141289e0f4d2SKip Macy int frags = 1; 141389e0f4d2SKip Macy int err = 0; 1414*e7236a7dSMateusz Guzik u_long ret __diagused; 141589e0f4d2SKip Macy 141696375eacSRoger Pau Monné m0 = m = m_prev = xn_get_rx_mbuf(rxq, *cons); 141783b92f6eSKip Macy 141889e0f4d2SKip Macy if (rx->flags & NETRXF_extra_info) { 141996375eacSRoger Pau Monné err = xn_get_extras(rxq, extras, rp, cons); 142089e0f4d2SKip Macy } 142189e0f4d2SKip Macy 142283b92f6eSKip Macy if (m0 != NULL) { 142383b92f6eSKip Macy m0->m_pkthdr.len = 0; 142483b92f6eSKip Macy m0->m_next = NULL; 142583b92f6eSKip Macy } 142683b92f6eSKip Macy 142789e0f4d2SKip Macy for (;;) { 142883b92f6eSKip Macy #if 0 1429227ca257SKip Macy DPRINTK("rx->status=%hd rx->offset=%hu frags=%u\n", 143083b92f6eSKip Macy rx->status, rx->offset, frags); 143183b92f6eSKip Macy #endif 143276acc41fSJustin T. Gibbs if (__predict_false(rx->status < 0 || 143389e0f4d2SKip Macy rx->offset + rx->status > PAGE_SIZE)) { 143496375eacSRoger Pau Monné xn_move_rx_slot(rxq, m, ref); 1435931eeffaSKenneth D. Merry if (m0 == m) 1436931eeffaSKenneth D. Merry m0 = NULL; 1437931eeffaSKenneth D. Merry m = NULL; 1438931eeffaSKenneth D. Merry err = EINVAL; 1439931eeffaSKenneth D. Merry goto next_skip_queue; 144089e0f4d2SKip Macy } 144189e0f4d2SKip Macy 144289e0f4d2SKip Macy /* 144389e0f4d2SKip Macy * This definitely indicates a bug, either in this driver or in 144489e0f4d2SKip Macy * the backend driver. In future this should flag the bad 144589e0f4d2SKip Macy * situation to the system controller to reboot the backed. 144689e0f4d2SKip Macy */ 1447ff662b5cSJustin T. Gibbs if (ref == GRANT_REF_INVALID) { 1448ff662b5cSJustin T. Gibbs printf("%s: Bad rx response id %d.\n", __func__, rx->id); 1449931eeffaSKenneth D. Merry err = EINVAL; 145089e0f4d2SKip Macy goto next; 145189e0f4d2SKip Macy } 145289e0f4d2SKip Macy 1453920ba15bSKip Macy ret = gnttab_end_foreign_access_ref(ref); 1454d0f3a8b9SRoger Pau Monné KASSERT(ret, ("Unable to end access to grant references")); 145589e0f4d2SKip Macy 145696375eacSRoger Pau Monné gnttab_release_grant_reference(&rxq->gref_head, ref); 145789e0f4d2SKip Macy 145889e0f4d2SKip Macy next: 14593a539122SAdrian Chadd if (m == NULL) 14603a539122SAdrian Chadd break; 14613a539122SAdrian Chadd 146283b92f6eSKip Macy m->m_len = rx->status; 146383b92f6eSKip Macy m->m_data += rx->offset; 146483b92f6eSKip Macy m0->m_pkthdr.len += rx->status; 146583b92f6eSKip Macy 1466931eeffaSKenneth D. Merry next_skip_queue: 146789e0f4d2SKip Macy if (!(rx->flags & NETRXF_more_data)) 146889e0f4d2SKip Macy break; 146989e0f4d2SKip Macy 1470931eeffaSKenneth D. Merry if (*cons + frags == rp) { 147189e0f4d2SKip Macy if (net_ratelimit()) 147289e0f4d2SKip Macy WPRINTK("Need more frags\n"); 1473931eeffaSKenneth D. Merry err = ENOENT; 1474931eeffaSKenneth D. Merry printf("%s: cons %u frags %u rp %u, not enough frags\n", 1475931eeffaSKenneth D. Merry __func__, *cons, frags, rp); 147689e0f4d2SKip Macy break; 147789e0f4d2SKip Macy } 1478931eeffaSKenneth D. Merry /* 1479931eeffaSKenneth D. Merry * Note that m can be NULL, if rx->status < 0 or if 1480931eeffaSKenneth D. Merry * rx->offset + rx->status > PAGE_SIZE above. 1481931eeffaSKenneth D. Merry */ 148283b92f6eSKip Macy m_prev = m; 148389e0f4d2SKip Macy 148496375eacSRoger Pau Monné rx = RING_GET_RESPONSE(&rxq->ring, *cons + frags); 148596375eacSRoger Pau Monné m = xn_get_rx_mbuf(rxq, *cons + frags); 148683b92f6eSKip Macy 1487931eeffaSKenneth D. Merry /* 1488931eeffaSKenneth D. Merry * m_prev == NULL can happen if rx->status < 0 or if 1489931eeffaSKenneth D. Merry * rx->offset + * rx->status > PAGE_SIZE above. 1490931eeffaSKenneth D. Merry */ 1491931eeffaSKenneth D. Merry if (m_prev != NULL) 149283b92f6eSKip Macy m_prev->m_next = m; 1493931eeffaSKenneth D. Merry 1494931eeffaSKenneth D. Merry /* 1495931eeffaSKenneth D. Merry * m0 can be NULL if rx->status < 0 or if * rx->offset + 1496931eeffaSKenneth D. Merry * rx->status > PAGE_SIZE above. 1497931eeffaSKenneth D. Merry */ 1498931eeffaSKenneth D. Merry if (m0 == NULL) 1499931eeffaSKenneth D. Merry m0 = m; 150083b92f6eSKip Macy m->m_next = NULL; 150196375eacSRoger Pau Monné ref = xn_get_rx_ref(rxq, *cons + frags); 150289e0f4d2SKip Macy frags++; 150389e0f4d2SKip Macy } 150483b92f6eSKip Macy *list = m0; 1505931eeffaSKenneth D. Merry *cons += frags; 150689e0f4d2SKip Macy 15078577146eSJustin T. Gibbs return (err); 150889e0f4d2SKip Macy } 150989e0f4d2SKip Macy 1510931eeffaSKenneth D. Merry /** 1511931eeffaSKenneth D. Merry * \brief Count the number of fragments in an mbuf chain. 1512931eeffaSKenneth D. Merry * 1513931eeffaSKenneth D. Merry * Surprisingly, there isn't an M* macro for this. 1514c099cafaSAdrian Chadd */ 1515931eeffaSKenneth D. Merry static inline int 1516931eeffaSKenneth D. Merry xn_count_frags(struct mbuf *m) 1517931eeffaSKenneth D. Merry { 1518931eeffaSKenneth D. Merry int nfrags; 1519931eeffaSKenneth D. Merry 1520931eeffaSKenneth D. Merry for (nfrags = 0; m != NULL; m = m->m_next) 1521931eeffaSKenneth D. Merry nfrags++; 1522931eeffaSKenneth D. Merry 1523931eeffaSKenneth D. Merry return (nfrags); 152489e0f4d2SKip Macy } 152589e0f4d2SKip Macy 1526931eeffaSKenneth D. Merry /** 1527931eeffaSKenneth D. Merry * Given an mbuf chain, make sure we have enough room and then push 1528931eeffaSKenneth D. Merry * it onto the transmit ring. 1529931eeffaSKenneth D. Merry */ 1530931eeffaSKenneth D. Merry static int 153196375eacSRoger Pau Monné xn_assemble_tx_request(struct netfront_txq *txq, struct mbuf *m_head) 1532931eeffaSKenneth D. Merry { 1533931eeffaSKenneth D. Merry struct mbuf *m; 153496375eacSRoger Pau Monné struct netfront_info *np = txq->info; 153596375eacSRoger Pau Monné struct ifnet *ifp = np->xn_ifp; 1536931eeffaSKenneth D. Merry u_int nfrags; 1537931eeffaSKenneth D. Merry int otherend_id; 1538931eeffaSKenneth D. Merry 1539931eeffaSKenneth D. Merry /** 154012678024SDoug Rabson * Defragment the mbuf if necessary. 154112678024SDoug Rabson */ 1542931eeffaSKenneth D. Merry nfrags = xn_count_frags(m_head); 1543931eeffaSKenneth D. Merry 1544931eeffaSKenneth D. Merry /* 1545931eeffaSKenneth D. Merry * Check to see whether this request is longer than netback 1546931eeffaSKenneth D. Merry * can handle, and try to defrag it. 1547931eeffaSKenneth D. Merry */ 1548931eeffaSKenneth D. Merry /** 1549931eeffaSKenneth D. Merry * It is a bit lame, but the netback driver in Linux can't 1550931eeffaSKenneth D. Merry * deal with nfrags > MAX_TX_REQ_FRAGS, which is a quirk of 1551931eeffaSKenneth D. Merry * the Linux network stack. 1552931eeffaSKenneth D. Merry */ 155396375eacSRoger Pau Monné if (nfrags > np->maxfrags) { 1554c6499eccSGleb Smirnoff m = m_defrag(m_head, M_NOWAIT); 155512678024SDoug Rabson if (!m) { 1556931eeffaSKenneth D. Merry /* 1557931eeffaSKenneth D. Merry * Defrag failed, so free the mbuf and 1558931eeffaSKenneth D. Merry * therefore drop the packet. 1559931eeffaSKenneth D. Merry */ 156012678024SDoug Rabson m_freem(m_head); 1561931eeffaSKenneth D. Merry return (EMSGSIZE); 156212678024SDoug Rabson } 156312678024SDoug Rabson m_head = m; 156412678024SDoug Rabson } 156589e0f4d2SKip Macy 1566a4ec37f5SAdrian Chadd /* Determine how many fragments now exist */ 1567931eeffaSKenneth D. Merry nfrags = xn_count_frags(m_head); 1568a4ec37f5SAdrian Chadd 1569a4ec37f5SAdrian Chadd /* 1570931eeffaSKenneth D. Merry * Check to see whether the defragmented packet has too many 1571931eeffaSKenneth D. Merry * segments for the Linux netback driver. 1572a4ec37f5SAdrian Chadd */ 1573931eeffaSKenneth D. Merry /** 1574931eeffaSKenneth D. Merry * The FreeBSD TCP stack, with TSO enabled, can produce a chain 1575931eeffaSKenneth D. Merry * of mbufs longer than Linux can handle. Make sure we don't 1576931eeffaSKenneth D. Merry * pass a too-long chain over to the other side by dropping the 1577931eeffaSKenneth D. Merry * packet. It doesn't look like there is currently a way to 1578931eeffaSKenneth D. Merry * tell the TCP stack to generate a shorter chain of packets. 15793fb28bbbSAdrian Chadd */ 1580931eeffaSKenneth D. Merry if (nfrags > MAX_TX_REQ_FRAGS) { 1581ff662b5cSJustin T. Gibbs #ifdef DEBUG 1582ff662b5cSJustin T. Gibbs printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback " 1583ff662b5cSJustin T. Gibbs "won't be able to handle it, dropping\n", 1584ff662b5cSJustin T. Gibbs __func__, nfrags, MAX_TX_REQ_FRAGS); 1585ff662b5cSJustin T. Gibbs #endif 1586931eeffaSKenneth D. Merry m_freem(m_head); 1587931eeffaSKenneth D. Merry return (EMSGSIZE); 1588a4ec37f5SAdrian Chadd } 1589a4ec37f5SAdrian Chadd 15903fb28bbbSAdrian Chadd /* 1591931eeffaSKenneth D. Merry * This check should be redundant. We've already verified that we 1592931eeffaSKenneth D. Merry * have enough slots in the ring to handle a packet of maximum 1593931eeffaSKenneth D. Merry * size, and that our packet is less than the maximum size. Keep 1594931eeffaSKenneth D. Merry * it in here as an assert for now just to make certain that 159596375eacSRoger Pau Monné * chain_cnt is accurate. 15963fb28bbbSAdrian Chadd */ 159796375eacSRoger Pau Monné KASSERT((txq->mbufs_cnt + nfrags) <= NET_TX_RING_SIZE, 159896375eacSRoger Pau Monné ("%s: chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE " 159996375eacSRoger Pau Monné "(%d)!", __func__, (int) txq->mbufs_cnt, 1600931eeffaSKenneth D. Merry (int) nfrags, (int) NET_TX_RING_SIZE)); 1601a4ec37f5SAdrian Chadd 160289e0f4d2SKip Macy /* 160389e0f4d2SKip Macy * Start packing the mbufs in this chain into 160489e0f4d2SKip Macy * the fragment pointers. Stop when we run out 160589e0f4d2SKip Macy * of fragments or hit the end of the mbuf chain. 160689e0f4d2SKip Macy */ 160712678024SDoug Rabson m = m_head; 160896375eacSRoger Pau Monné otherend_id = xenbus_get_otherend_id(np->xbdev); 160912678024SDoug Rabson for (m = m_head; m; m = m->m_next) { 1610931eeffaSKenneth D. Merry netif_tx_request_t *tx; 1611931eeffaSKenneth D. Merry uintptr_t id; 1612931eeffaSKenneth D. Merry grant_ref_t ref; 1613931eeffaSKenneth D. Merry u_long mfn; /* XXX Wrong type? */ 1614931eeffaSKenneth D. Merry 161596375eacSRoger Pau Monné tx = RING_GET_REQUEST(&txq->ring, txq->ring.req_prod_pvt); 161696375eacSRoger Pau Monné id = get_id_from_freelist(txq->mbufs); 1617a4ec37f5SAdrian Chadd if (id == 0) 16186f9767acSMarius Strobl panic("%s: was allocated the freelist head!\n", 16196f9767acSMarius Strobl __func__); 162096375eacSRoger Pau Monné txq->mbufs_cnt++; 162196375eacSRoger Pau Monné if (txq->mbufs_cnt > NET_TX_RING_SIZE) 16226f9767acSMarius Strobl panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n", 16236f9767acSMarius Strobl __func__); 162496375eacSRoger Pau Monné txq->mbufs[id] = m; 162589e0f4d2SKip Macy tx->id = id; 162696375eacSRoger Pau Monné ref = gnttab_claim_grant_reference(&txq->gref_head); 162789e0f4d2SKip Macy KASSERT((short)ref >= 0, ("Negative ref")); 162812678024SDoug Rabson mfn = virt_to_mfn(mtod(m, vm_offset_t)); 162923dc5621SKip Macy gnttab_grant_foreign_access_ref(ref, otherend_id, 163089e0f4d2SKip Macy mfn, GNTMAP_readonly); 163196375eacSRoger Pau Monné tx->gref = txq->grant_ref[id] = ref; 163212678024SDoug Rabson tx->offset = mtod(m, vm_offset_t) & (PAGE_SIZE - 1); 163389e0f4d2SKip Macy tx->flags = 0; 163412678024SDoug Rabson if (m == m_head) { 163512678024SDoug Rabson /* 163612678024SDoug Rabson * The first fragment has the entire packet 163712678024SDoug Rabson * size, subsequent fragments have just the 163812678024SDoug Rabson * fragment size. The backend works out the 163912678024SDoug Rabson * true size of the first fragment by 164012678024SDoug Rabson * subtracting the sizes of the other 164112678024SDoug Rabson * fragments. 164212678024SDoug Rabson */ 164312678024SDoug Rabson tx->size = m->m_pkthdr.len; 164489e0f4d2SKip Macy 164512678024SDoug Rabson /* 1646931eeffaSKenneth D. Merry * The first fragment contains the checksum flags 1647931eeffaSKenneth D. Merry * and is optionally followed by extra data for 1648931eeffaSKenneth D. Merry * TSO etc. 1649931eeffaSKenneth D. Merry */ 1650931eeffaSKenneth D. Merry /** 1651931eeffaSKenneth D. Merry * CSUM_TSO requires checksum offloading. 1652931eeffaSKenneth D. Merry * Some versions of FreeBSD fail to 1653931eeffaSKenneth D. Merry * set CSUM_TCP in the CSUM_TSO case, 1654931eeffaSKenneth D. Merry * so we have to test for CSUM_TSO 1655931eeffaSKenneth D. Merry * explicitly. 165612678024SDoug Rabson */ 165712678024SDoug Rabson if (m->m_pkthdr.csum_flags 1658931eeffaSKenneth D. Merry & (CSUM_DELAY_DATA | CSUM_TSO)) { 165912678024SDoug Rabson tx->flags |= (NETTXF_csum_blank 166012678024SDoug Rabson | NETTXF_data_validated); 166112678024SDoug Rabson } 166212678024SDoug Rabson if (m->m_pkthdr.csum_flags & CSUM_TSO) { 166312678024SDoug Rabson struct netif_extra_info *gso = 166412678024SDoug Rabson (struct netif_extra_info *) 166596375eacSRoger Pau Monné RING_GET_REQUEST(&txq->ring, 166696375eacSRoger Pau Monné ++txq->ring.req_prod_pvt); 166789e0f4d2SKip Macy 166812678024SDoug Rabson tx->flags |= NETTXF_extra_info; 166989e0f4d2SKip Macy 167012678024SDoug Rabson gso->u.gso.size = m->m_pkthdr.tso_segsz; 167112678024SDoug Rabson gso->u.gso.type = 167212678024SDoug Rabson XEN_NETIF_GSO_TYPE_TCPV4; 167312678024SDoug Rabson gso->u.gso.pad = 0; 167412678024SDoug Rabson gso->u.gso.features = 0; 167512678024SDoug Rabson 167612678024SDoug Rabson gso->type = XEN_NETIF_EXTRA_TYPE_GSO; 167712678024SDoug Rabson gso->flags = 0; 167812678024SDoug Rabson } 167912678024SDoug Rabson } else { 168012678024SDoug Rabson tx->size = m->m_len; 168112678024SDoug Rabson } 1682931eeffaSKenneth D. Merry if (m->m_next) 168312678024SDoug Rabson tx->flags |= NETTXF_more_data; 168412678024SDoug Rabson 168596375eacSRoger Pau Monné txq->ring.req_prod_pvt++; 1686931eeffaSKenneth D. Merry } 168712678024SDoug Rabson BPF_MTAP(ifp, m_head); 168812678024SDoug Rabson 1689b2fd6999SRoger Pau Monné if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 1690b2fd6999SRoger Pau Monné if_inc_counter(ifp, IFCOUNTER_OBYTES, m_head->m_pkthdr.len); 1691b2fd6999SRoger Pau Monné if (m_head->m_flags & M_MCAST) 1692b2fd6999SRoger Pau Monné if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 169396375eacSRoger Pau Monné 1694b2fd6999SRoger Pau Monné xn_txeof(txq); 1695931eeffaSKenneth D. Merry 1696931eeffaSKenneth D. Merry return (0); 169789e0f4d2SKip Macy } 169889e0f4d2SKip Macy 169989e0f4d2SKip Macy /* equivalent of network_open() in Linux */ 170089e0f4d2SKip Macy static void 170196375eacSRoger Pau Monné xn_ifinit_locked(struct netfront_info *np) 170289e0f4d2SKip Macy { 170389e0f4d2SKip Macy struct ifnet *ifp; 170496375eacSRoger Pau Monné int i; 170596375eacSRoger Pau Monné struct netfront_rxq *rxq; 170689e0f4d2SKip Macy 170796375eacSRoger Pau Monné XN_LOCK_ASSERT(np); 170889e0f4d2SKip Macy 170996375eacSRoger Pau Monné ifp = np->xn_ifp; 171089e0f4d2SKip Macy 1711c21b47d8SRoger Pau Monné if (ifp->if_drv_flags & IFF_DRV_RUNNING || !netfront_carrier_ok(np)) 171289e0f4d2SKip Macy return; 171389e0f4d2SKip Macy 171496375eacSRoger Pau Monné xn_stop(np); 171589e0f4d2SKip Macy 171696375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 171796375eacSRoger Pau Monné rxq = &np->rxq[i]; 17182568ee67SRoger Pau Monné XN_RX_LOCK(rxq); 171996375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 172096375eacSRoger Pau Monné rxq->ring.sring->rsp_event = rxq->ring.rsp_cons + 1; 17212568ee67SRoger Pau Monné if (RING_HAS_UNCONSUMED_RESPONSES(&rxq->ring)) 1722da695b05SRoger Pau Monné xn_rxeof(rxq); 17232568ee67SRoger Pau Monné XN_RX_UNLOCK(rxq); 172496375eacSRoger Pau Monné } 172589e0f4d2SKip Macy 172689e0f4d2SKip Macy ifp->if_drv_flags |= IFF_DRV_RUNNING; 172789e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 17280e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_UP); 172989e0f4d2SKip Macy } 173089e0f4d2SKip Macy 173189e0f4d2SKip Macy static void 173289e0f4d2SKip Macy xn_ifinit(void *xsc) 173389e0f4d2SKip Macy { 173489e0f4d2SKip Macy struct netfront_info *sc = xsc; 173589e0f4d2SKip Macy 173689e0f4d2SKip Macy XN_LOCK(sc); 173789e0f4d2SKip Macy xn_ifinit_locked(sc); 173889e0f4d2SKip Macy XN_UNLOCK(sc); 173989e0f4d2SKip Macy } 174089e0f4d2SKip Macy 174189e0f4d2SKip Macy static int 174289e0f4d2SKip Macy xn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 174389e0f4d2SKip Macy { 174489e0f4d2SKip Macy struct netfront_info *sc = ifp->if_softc; 174589e0f4d2SKip Macy struct ifreq *ifr = (struct ifreq *) data; 1746c2d12e5eSRoger Pau Monné device_t dev; 1747a0ae8f04SBjoern A. Zeeb #ifdef INET 174889e0f4d2SKip Macy struct ifaddr *ifa = (struct ifaddr *)data; 1749a0ae8f04SBjoern A. Zeeb #endif 17503c9d5940SRoger Pau Monné int mask, error = 0, reinit; 1751c2d12e5eSRoger Pau Monné 1752c2d12e5eSRoger Pau Monné dev = sc->xbdev; 1753c2d12e5eSRoger Pau Monné 175489e0f4d2SKip Macy switch(cmd) { 175589e0f4d2SKip Macy case SIOCSIFADDR: 1756a0ae8f04SBjoern A. Zeeb #ifdef INET 175789e0f4d2SKip Macy XN_LOCK(sc); 175889e0f4d2SKip Macy if (ifa->ifa_addr->sa_family == AF_INET) { 175989e0f4d2SKip Macy ifp->if_flags |= IFF_UP; 176089e0f4d2SKip Macy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 176189e0f4d2SKip Macy xn_ifinit_locked(sc); 176289e0f4d2SKip Macy arp_ifinit(ifp, ifa); 176389e0f4d2SKip Macy XN_UNLOCK(sc); 176449906218SDoug Rabson } else { 176549906218SDoug Rabson XN_UNLOCK(sc); 1766a0ae8f04SBjoern A. Zeeb #endif 176749906218SDoug Rabson error = ether_ioctl(ifp, cmd, data); 1768a0ae8f04SBjoern A. Zeeb #ifdef INET 176949906218SDoug Rabson } 1770a0ae8f04SBjoern A. Zeeb #endif 177189e0f4d2SKip Macy break; 177289e0f4d2SKip Macy case SIOCSIFMTU: 1773c74415edSColin Percival if (ifp->if_mtu == ifr->ifr_mtu) 1774c74415edSColin Percival break; 1775c74415edSColin Percival 177689e0f4d2SKip Macy ifp->if_mtu = ifr->ifr_mtu; 177789e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 177889e0f4d2SKip Macy xn_ifinit(sc); 177989e0f4d2SKip Macy break; 178089e0f4d2SKip Macy case SIOCSIFFLAGS: 178189e0f4d2SKip Macy XN_LOCK(sc); 178289e0f4d2SKip Macy if (ifp->if_flags & IFF_UP) { 178389e0f4d2SKip Macy /* 178489e0f4d2SKip Macy * If only the state of the PROMISC flag changed, 178589e0f4d2SKip Macy * then just use the 'set promisc mode' command 178689e0f4d2SKip Macy * instead of reinitializing the entire NIC. Doing 178789e0f4d2SKip Macy * a full re-init means reloading the firmware and 178889e0f4d2SKip Macy * waiting for it to start up, which may take a 178989e0f4d2SKip Macy * second or two. 179089e0f4d2SKip Macy */ 179189e0f4d2SKip Macy xn_ifinit_locked(sc); 179289e0f4d2SKip Macy } else { 179389e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 179489e0f4d2SKip Macy xn_stop(sc); 179589e0f4d2SKip Macy } 179689e0f4d2SKip Macy } 179789e0f4d2SKip Macy sc->xn_if_flags = ifp->if_flags; 179889e0f4d2SKip Macy XN_UNLOCK(sc); 179989e0f4d2SKip Macy break; 180089e0f4d2SKip Macy case SIOCSIFCAP: 180189e0f4d2SKip Macy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 18023c9d5940SRoger Pau Monné reinit = 0; 18033c9d5940SRoger Pau Monné 180412678024SDoug Rabson if (mask & IFCAP_TXCSUM) { 18053c9d5940SRoger Pau Monné ifp->if_capenable ^= IFCAP_TXCSUM; 18063c9d5940SRoger Pau Monné ifp->if_hwassist ^= XN_CSUM_FEATURES; 180712678024SDoug Rabson } 180812678024SDoug Rabson if (mask & IFCAP_TSO4) { 18093c9d5940SRoger Pau Monné ifp->if_capenable ^= IFCAP_TSO4; 18103c9d5940SRoger Pau Monné ifp->if_hwassist ^= CSUM_TSO; 181112678024SDoug Rabson } 181212678024SDoug Rabson 18133c9d5940SRoger Pau Monné if (mask & (IFCAP_RXCSUM | IFCAP_LRO)) { 18143c9d5940SRoger Pau Monné /* These Rx features require us to renegotiate. */ 18153c9d5940SRoger Pau Monné reinit = 1; 18163c9d5940SRoger Pau Monné 18173c9d5940SRoger Pau Monné if (mask & IFCAP_RXCSUM) 18183c9d5940SRoger Pau Monné ifp->if_capenable ^= IFCAP_RXCSUM; 18193c9d5940SRoger Pau Monné if (mask & IFCAP_LRO) 18203c9d5940SRoger Pau Monné ifp->if_capenable ^= IFCAP_LRO; 182112678024SDoug Rabson } 18223c9d5940SRoger Pau Monné 18233c9d5940SRoger Pau Monné if (reinit == 0) 18243c9d5940SRoger Pau Monné break; 18253c9d5940SRoger Pau Monné 1826c2d12e5eSRoger Pau Monné /* 1827c2d12e5eSRoger Pau Monné * We must reset the interface so the backend picks up the 1828c2d12e5eSRoger Pau Monné * new features. 1829c2d12e5eSRoger Pau Monné */ 18303c9d5940SRoger Pau Monné device_printf(sc->xbdev, 18313c9d5940SRoger Pau Monné "performing interface reset due to feature change\n"); 1832c2d12e5eSRoger Pau Monné XN_LOCK(sc); 1833c2d12e5eSRoger Pau Monné netfront_carrier_off(sc); 1834c2d12e5eSRoger Pau Monné sc->xn_reset = true; 1835c2d12e5eSRoger Pau Monné /* 1836c2d12e5eSRoger Pau Monné * NB: the pending packet queue is not flushed, since 1837c2d12e5eSRoger Pau Monné * the interface should still support the old options. 1838c2d12e5eSRoger Pau Monné */ 1839c2d12e5eSRoger Pau Monné XN_UNLOCK(sc); 1840c2d12e5eSRoger Pau Monné /* 1841c2d12e5eSRoger Pau Monné * Delete the xenstore nodes that export features. 1842c2d12e5eSRoger Pau Monné * 1843c2d12e5eSRoger Pau Monné * NB: There's a xenbus state called 1844c2d12e5eSRoger Pau Monné * "XenbusStateReconfiguring", which is what we should set 1845c2d12e5eSRoger Pau Monné * here. Sadly none of the backends know how to handle it, 1846c2d12e5eSRoger Pau Monné * and simply disconnect from the frontend, so we will just 1847c2d12e5eSRoger Pau Monné * switch back to XenbusStateInitialising in order to force 1848c2d12e5eSRoger Pau Monné * a reconnection. 1849c2d12e5eSRoger Pau Monné */ 1850c2d12e5eSRoger Pau Monné xs_rm(XST_NIL, xenbus_get_node(dev), "feature-gso-tcpv4"); 1851c2d12e5eSRoger Pau Monné xs_rm(XST_NIL, xenbus_get_node(dev), "feature-no-csum-offload"); 1852c2d12e5eSRoger Pau Monné xenbus_set_state(dev, XenbusStateClosing); 18533c9d5940SRoger Pau Monné 18543c9d5940SRoger Pau Monné /* 18553c9d5940SRoger Pau Monné * Wait for the frontend to reconnect before returning 18563c9d5940SRoger Pau Monné * from the ioctl. 30s should be more than enough for any 18573c9d5940SRoger Pau Monné * sane backend to reconnect. 18583c9d5940SRoger Pau Monné */ 18593c9d5940SRoger Pau Monné error = tsleep(sc, 0, "xn_rst", 30*hz); 186089e0f4d2SKip Macy break; 186189e0f4d2SKip Macy case SIOCADDMULTI: 186289e0f4d2SKip Macy case SIOCDELMULTI: 1863ce8df48bSSimon J. Gerraty break; 186489e0f4d2SKip Macy case SIOCSIFMEDIA: 186589e0f4d2SKip Macy case SIOCGIFMEDIA: 18660e509842SJustin T. Gibbs error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 186789e0f4d2SKip Macy break; 186889e0f4d2SKip Macy default: 186989e0f4d2SKip Macy error = ether_ioctl(ifp, cmd, data); 187089e0f4d2SKip Macy } 187189e0f4d2SKip Macy 187289e0f4d2SKip Macy return (error); 187389e0f4d2SKip Macy } 187489e0f4d2SKip Macy 187589e0f4d2SKip Macy static void 187689e0f4d2SKip Macy xn_stop(struct netfront_info *sc) 187789e0f4d2SKip Macy { 187889e0f4d2SKip Macy struct ifnet *ifp; 187989e0f4d2SKip Macy 188089e0f4d2SKip Macy XN_LOCK_ASSERT(sc); 188189e0f4d2SKip Macy 188289e0f4d2SKip Macy ifp = sc->xn_ifp; 188389e0f4d2SKip Macy 188489e0f4d2SKip Macy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 18850e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_DOWN); 188689e0f4d2SKip Macy } 188789e0f4d2SKip Macy 188896375eacSRoger Pau Monné static void 188996375eacSRoger Pau Monné xn_rebuild_rx_bufs(struct netfront_rxq *rxq) 189089e0f4d2SKip Macy { 189196375eacSRoger Pau Monné int requeue_idx, i; 189289e0f4d2SKip Macy grant_ref_t ref; 189389e0f4d2SKip Macy netif_rx_request_t *req; 189489e0f4d2SKip Macy 189589e0f4d2SKip Macy for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { 189689e0f4d2SKip Macy struct mbuf *m; 18973a6d1fcfSKip Macy u_long pfn; 189889e0f4d2SKip Macy 189996375eacSRoger Pau Monné if (rxq->mbufs[i] == NULL) 190089e0f4d2SKip Macy continue; 190189e0f4d2SKip Macy 190296375eacSRoger Pau Monné m = rxq->mbufs[requeue_idx] = xn_get_rx_mbuf(rxq, i); 190396375eacSRoger Pau Monné ref = rxq->grant_ref[requeue_idx] = xn_get_rx_ref(rxq, i); 1904931eeffaSKenneth D. Merry 190596375eacSRoger Pau Monné req = RING_GET_REQUEST(&rxq->ring, requeue_idx); 19063a6d1fcfSKip Macy pfn = vtophys(mtod(m, vm_offset_t)) >> PAGE_SHIFT; 190789e0f4d2SKip Macy 190889e0f4d2SKip Macy gnttab_grant_foreign_access_ref(ref, 190996375eacSRoger Pau Monné xenbus_get_otherend_id(rxq->info->xbdev), 1910ed95805eSJohn Baldwin pfn, 0); 1911d0f3a8b9SRoger Pau Monné 191289e0f4d2SKip Macy req->gref = ref; 191389e0f4d2SKip Macy req->id = requeue_idx; 191489e0f4d2SKip Macy 191589e0f4d2SKip Macy requeue_idx++; 191689e0f4d2SKip Macy } 191789e0f4d2SKip Macy 191896375eacSRoger Pau Monné rxq->ring.req_prod_pvt = requeue_idx; 191996375eacSRoger Pau Monné } 192089e0f4d2SKip Macy 192196375eacSRoger Pau Monné /* START of Xenolinux helper functions adapted to FreeBSD */ 192265671253SRoger Pau Monné static int 192396375eacSRoger Pau Monné xn_connect(struct netfront_info *np) 192496375eacSRoger Pau Monné { 192596375eacSRoger Pau Monné int i, error; 192696375eacSRoger Pau Monné u_int feature_rx_copy; 192796375eacSRoger Pau Monné struct netfront_rxq *rxq; 192896375eacSRoger Pau Monné struct netfront_txq *txq; 192996375eacSRoger Pau Monné 193096375eacSRoger Pau Monné error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 193196375eacSRoger Pau Monné "feature-rx-copy", NULL, "%u", &feature_rx_copy); 193296375eacSRoger Pau Monné if (error != 0) 193396375eacSRoger Pau Monné feature_rx_copy = 0; 193496375eacSRoger Pau Monné 193596375eacSRoger Pau Monné /* We only support rx copy. */ 193696375eacSRoger Pau Monné if (!feature_rx_copy) 193796375eacSRoger Pau Monné return (EPROTONOSUPPORT); 193896375eacSRoger Pau Monné 193996375eacSRoger Pau Monné /* Recovery procedure: */ 194096375eacSRoger Pau Monné error = talk_to_backend(np->xbdev, np); 194196375eacSRoger Pau Monné if (error != 0) 194296375eacSRoger Pau Monné return (error); 194396375eacSRoger Pau Monné 194496375eacSRoger Pau Monné /* Step 1: Reinitialise variables. */ 194596375eacSRoger Pau Monné xn_query_features(np); 194696375eacSRoger Pau Monné xn_configure_features(np); 194796375eacSRoger Pau Monné 194896375eacSRoger Pau Monné /* Step 2: Release TX buffer */ 194996375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 195096375eacSRoger Pau Monné txq = &np->txq[i]; 195196375eacSRoger Pau Monné xn_release_tx_bufs(txq); 195296375eacSRoger Pau Monné } 195396375eacSRoger Pau Monné 195496375eacSRoger Pau Monné /* Step 3: Rebuild the RX buffer freelist and the RX ring itself. */ 195596375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 195696375eacSRoger Pau Monné rxq = &np->rxq[i]; 195796375eacSRoger Pau Monné xn_rebuild_rx_bufs(rxq); 195896375eacSRoger Pau Monné } 195996375eacSRoger Pau Monné 196096375eacSRoger Pau Monné /* Step 4: All public and private state should now be sane. Get 196189e0f4d2SKip Macy * ready to start sending and receiving packets and give the driver 196289e0f4d2SKip Macy * domain a kick because we've probably just requeued some 196389e0f4d2SKip Macy * packets. 196489e0f4d2SKip Macy */ 196589e0f4d2SKip Macy netfront_carrier_on(np); 19663c9d5940SRoger Pau Monné wakeup(np); 196765671253SRoger Pau Monné 196865671253SRoger Pau Monné return (0); 196965671253SRoger Pau Monné } 197065671253SRoger Pau Monné 197165671253SRoger Pau Monné static void 197265671253SRoger Pau Monné xn_kick_rings(struct netfront_info *np) 197365671253SRoger Pau Monné { 197465671253SRoger Pau Monné struct netfront_rxq *rxq; 197565671253SRoger Pau Monné struct netfront_txq *txq; 197665671253SRoger Pau Monné int i; 197765671253SRoger Pau Monné 197896375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 197996375eacSRoger Pau Monné txq = &np->txq[i]; 198065671253SRoger Pau Monné rxq = &np->rxq[i]; 198196375eacSRoger Pau Monné xen_intr_signal(txq->xen_intr_handle); 198296375eacSRoger Pau Monné XN_TX_LOCK(txq); 198396375eacSRoger Pau Monné xn_txeof(txq); 198496375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 19852568ee67SRoger Pau Monné XN_RX_LOCK(rxq); 198696375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 19872568ee67SRoger Pau Monné XN_RX_UNLOCK(rxq); 198896375eacSRoger Pau Monné } 198989e0f4d2SKip Macy } 199089e0f4d2SKip Macy 199189e0f4d2SKip Macy static void 1992578e4bf7SJustin T. Gibbs xn_query_features(struct netfront_info *np) 1993578e4bf7SJustin T. Gibbs { 1994578e4bf7SJustin T. Gibbs int val; 1995578e4bf7SJustin T. Gibbs 1996578e4bf7SJustin T. Gibbs device_printf(np->xbdev, "backend features:"); 1997578e4bf7SJustin T. Gibbs 1998578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 1999107cfbb7SRoger Pau Monné "feature-sg", NULL, "%d", &val) != 0) 2000578e4bf7SJustin T. Gibbs val = 0; 2001578e4bf7SJustin T. Gibbs 2002578e4bf7SJustin T. Gibbs np->maxfrags = 1; 2003578e4bf7SJustin T. Gibbs if (val) { 2004578e4bf7SJustin T. Gibbs np->maxfrags = MAX_TX_REQ_FRAGS; 2005578e4bf7SJustin T. Gibbs printf(" feature-sg"); 2006578e4bf7SJustin T. Gibbs } 2007578e4bf7SJustin T. Gibbs 2008578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 2009107cfbb7SRoger Pau Monné "feature-gso-tcpv4", NULL, "%d", &val) != 0) 2010578e4bf7SJustin T. Gibbs val = 0; 2011578e4bf7SJustin T. Gibbs 2012578e4bf7SJustin T. Gibbs np->xn_ifp->if_capabilities &= ~(IFCAP_TSO4|IFCAP_LRO); 2013578e4bf7SJustin T. Gibbs if (val) { 2014578e4bf7SJustin T. Gibbs np->xn_ifp->if_capabilities |= IFCAP_TSO4|IFCAP_LRO; 2015578e4bf7SJustin T. Gibbs printf(" feature-gso-tcp4"); 2016578e4bf7SJustin T. Gibbs } 2017578e4bf7SJustin T. Gibbs 2018c2d12e5eSRoger Pau Monné /* 2019c2d12e5eSRoger Pau Monné * HW CSUM offload is assumed to be available unless 2020c2d12e5eSRoger Pau Monné * feature-no-csum-offload is set in xenstore. 2021c2d12e5eSRoger Pau Monné */ 2022c2d12e5eSRoger Pau Monné if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 2023c2d12e5eSRoger Pau Monné "feature-no-csum-offload", NULL, "%d", &val) != 0) 2024c2d12e5eSRoger Pau Monné val = 0; 2025c2d12e5eSRoger Pau Monné 2026c2d12e5eSRoger Pau Monné np->xn_ifp->if_capabilities |= IFCAP_HWCSUM; 2027c2d12e5eSRoger Pau Monné if (val) { 2028c2d12e5eSRoger Pau Monné np->xn_ifp->if_capabilities &= ~(IFCAP_HWCSUM); 2029c2d12e5eSRoger Pau Monné printf(" feature-no-csum-offload"); 2030c2d12e5eSRoger Pau Monné } 2031c2d12e5eSRoger Pau Monné 2032578e4bf7SJustin T. Gibbs printf("\n"); 2033578e4bf7SJustin T. Gibbs } 2034578e4bf7SJustin T. Gibbs 2035cf9c09e1SJustin T. Gibbs static int 2036578e4bf7SJustin T. Gibbs xn_configure_features(struct netfront_info *np) 2037cf9c09e1SJustin T. Gibbs { 20386a8e9695SRoger Pau Monné int err, cap_enabled; 203996375eacSRoger Pau Monné #if (defined(INET) || defined(INET6)) 204096375eacSRoger Pau Monné int i; 204196375eacSRoger Pau Monné #endif 2042c2d12e5eSRoger Pau Monné struct ifnet *ifp; 2043cf9c09e1SJustin T. Gibbs 2044c2d12e5eSRoger Pau Monné ifp = np->xn_ifp; 2045cf9c09e1SJustin T. Gibbs err = 0; 20466a8e9695SRoger Pau Monné 2047c2d12e5eSRoger Pau Monné if ((ifp->if_capenable & ifp->if_capabilities) == ifp->if_capenable) { 20486a8e9695SRoger Pau Monné /* Current options are available, no need to do anything. */ 20496a8e9695SRoger Pau Monné return (0); 20506a8e9695SRoger Pau Monné } 20516a8e9695SRoger Pau Monné 20526a8e9695SRoger Pau Monné /* Try to preserve as many options as possible. */ 2053c2d12e5eSRoger Pau Monné cap_enabled = ifp->if_capenable; 2054c2d12e5eSRoger Pau Monné ifp->if_capenable = ifp->if_hwassist = 0; 20556a8e9695SRoger Pau Monné 205608c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 2057c2d12e5eSRoger Pau Monné if ((cap_enabled & IFCAP_LRO) != 0) 205896375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 205996375eacSRoger Pau Monné tcp_lro_free(&np->rxq[i].lro); 2060c2d12e5eSRoger Pau Monné if (xn_enable_lro && 2061c2d12e5eSRoger Pau Monné (ifp->if_capabilities & cap_enabled & IFCAP_LRO) != 0) { 2062c2d12e5eSRoger Pau Monné ifp->if_capenable |= IFCAP_LRO; 206396375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 206496375eacSRoger Pau Monné err = tcp_lro_init(&np->rxq[i].lro); 206596375eacSRoger Pau Monné if (err != 0) { 2066c2d12e5eSRoger Pau Monné device_printf(np->xbdev, 2067c2d12e5eSRoger Pau Monné "LRO initialization failed\n"); 2068c2d12e5eSRoger Pau Monné ifp->if_capenable &= ~IFCAP_LRO; 2069c2d12e5eSRoger Pau Monné break; 2070c2d12e5eSRoger Pau Monné } 2071c2d12e5eSRoger Pau Monné np->rxq[i].lro.ifp = ifp; 2072cf9c09e1SJustin T. Gibbs } 2073cf9c09e1SJustin T. Gibbs } 2074c2d12e5eSRoger Pau Monné if ((ifp->if_capabilities & cap_enabled & IFCAP_TSO4) != 0) { 2075c2d12e5eSRoger Pau Monné ifp->if_capenable |= IFCAP_TSO4; 2076c2d12e5eSRoger Pau Monné ifp->if_hwassist |= CSUM_TSO; 2077578e4bf7SJustin T. Gibbs } 2078cf9c09e1SJustin T. Gibbs #endif 2079c2d12e5eSRoger Pau Monné if ((ifp->if_capabilities & cap_enabled & IFCAP_TXCSUM) != 0) { 2080c2d12e5eSRoger Pau Monné ifp->if_capenable |= IFCAP_TXCSUM; 20813c9d5940SRoger Pau Monné ifp->if_hwassist |= XN_CSUM_FEATURES; 2082c2d12e5eSRoger Pau Monné } 2083c2d12e5eSRoger Pau Monné if ((ifp->if_capabilities & cap_enabled & IFCAP_RXCSUM) != 0) 2084c2d12e5eSRoger Pau Monné ifp->if_capenable |= IFCAP_RXCSUM; 2085c2d12e5eSRoger Pau Monné 2086cf9c09e1SJustin T. Gibbs return (err); 2087cf9c09e1SJustin T. Gibbs } 2088cf9c09e1SJustin T. Gibbs 208996375eacSRoger Pau Monné static int 209096375eacSRoger Pau Monné xn_txq_mq_start_locked(struct netfront_txq *txq, struct mbuf *m) 209196375eacSRoger Pau Monné { 209296375eacSRoger Pau Monné struct netfront_info *np; 209396375eacSRoger Pau Monné struct ifnet *ifp; 209496375eacSRoger Pau Monné struct buf_ring *br; 209596375eacSRoger Pau Monné int error, notify; 209696375eacSRoger Pau Monné 209796375eacSRoger Pau Monné np = txq->info; 209896375eacSRoger Pau Monné br = txq->br; 209996375eacSRoger Pau Monné ifp = np->xn_ifp; 210096375eacSRoger Pau Monné error = 0; 210196375eacSRoger Pau Monné 210296375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 210396375eacSRoger Pau Monné 210496375eacSRoger Pau Monné if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 210596375eacSRoger Pau Monné !netfront_carrier_ok(np)) { 210696375eacSRoger Pau Monné if (m != NULL) 210796375eacSRoger Pau Monné error = drbr_enqueue(ifp, br, m); 210896375eacSRoger Pau Monné return (error); 210996375eacSRoger Pau Monné } 211096375eacSRoger Pau Monné 211196375eacSRoger Pau Monné if (m != NULL) { 211296375eacSRoger Pau Monné error = drbr_enqueue(ifp, br, m); 211396375eacSRoger Pau Monné if (error != 0) 211496375eacSRoger Pau Monné return (error); 211596375eacSRoger Pau Monné } 211696375eacSRoger Pau Monné 211796375eacSRoger Pau Monné while ((m = drbr_peek(ifp, br)) != NULL) { 211896375eacSRoger Pau Monné if (!xn_tx_slot_available(txq)) { 211996375eacSRoger Pau Monné drbr_putback(ifp, br, m); 212096375eacSRoger Pau Monné break; 212196375eacSRoger Pau Monné } 212296375eacSRoger Pau Monné 212396375eacSRoger Pau Monné error = xn_assemble_tx_request(txq, m); 212496375eacSRoger Pau Monné /* xn_assemble_tx_request always consumes the mbuf*/ 212596375eacSRoger Pau Monné if (error != 0) { 212696375eacSRoger Pau Monné drbr_advance(ifp, br); 212796375eacSRoger Pau Monné break; 212896375eacSRoger Pau Monné } 212996375eacSRoger Pau Monné 213096375eacSRoger Pau Monné RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&txq->ring, notify); 213196375eacSRoger Pau Monné if (notify) 213296375eacSRoger Pau Monné xen_intr_signal(txq->xen_intr_handle); 213396375eacSRoger Pau Monné 213496375eacSRoger Pau Monné drbr_advance(ifp, br); 213596375eacSRoger Pau Monné } 213696375eacSRoger Pau Monné 213796375eacSRoger Pau Monné if (RING_FULL(&txq->ring)) 213896375eacSRoger Pau Monné txq->full = true; 213996375eacSRoger Pau Monné 214096375eacSRoger Pau Monné return (0); 214196375eacSRoger Pau Monné } 214296375eacSRoger Pau Monné 214396375eacSRoger Pau Monné static int 214496375eacSRoger Pau Monné xn_txq_mq_start(struct ifnet *ifp, struct mbuf *m) 214596375eacSRoger Pau Monné { 214696375eacSRoger Pau Monné struct netfront_info *np; 214796375eacSRoger Pau Monné struct netfront_txq *txq; 214896375eacSRoger Pau Monné int i, npairs, error; 214996375eacSRoger Pau Monné 215096375eacSRoger Pau Monné np = ifp->if_softc; 215196375eacSRoger Pau Monné npairs = np->num_queues; 215296375eacSRoger Pau Monné 2153339690b5SRoger Pau Monné if (!netfront_carrier_ok(np)) 2154339690b5SRoger Pau Monné return (ENOBUFS); 2155339690b5SRoger Pau Monné 2156c21b47d8SRoger Pau Monné KASSERT(npairs != 0, ("called with 0 available queues")); 2157c21b47d8SRoger Pau Monné 215896375eacSRoger Pau Monné /* check if flowid is set */ 215996375eacSRoger Pau Monné if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 216096375eacSRoger Pau Monné i = m->m_pkthdr.flowid % npairs; 216196375eacSRoger Pau Monné else 216296375eacSRoger Pau Monné i = curcpu % npairs; 216396375eacSRoger Pau Monné 216496375eacSRoger Pau Monné txq = &np->txq[i]; 216596375eacSRoger Pau Monné 216696375eacSRoger Pau Monné if (XN_TX_TRYLOCK(txq) != 0) { 216796375eacSRoger Pau Monné error = xn_txq_mq_start_locked(txq, m); 216896375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 216996375eacSRoger Pau Monné } else { 217096375eacSRoger Pau Monné error = drbr_enqueue(ifp, txq->br, m); 217196375eacSRoger Pau Monné taskqueue_enqueue(txq->tq, &txq->defrtask); 217296375eacSRoger Pau Monné } 217396375eacSRoger Pau Monné 217496375eacSRoger Pau Monné return (error); 217596375eacSRoger Pau Monné } 217696375eacSRoger Pau Monné 217796375eacSRoger Pau Monné static void 217896375eacSRoger Pau Monné xn_qflush(struct ifnet *ifp) 217996375eacSRoger Pau Monné { 218096375eacSRoger Pau Monné struct netfront_info *np; 218196375eacSRoger Pau Monné struct netfront_txq *txq; 218296375eacSRoger Pau Monné struct mbuf *m; 218396375eacSRoger Pau Monné int i; 218496375eacSRoger Pau Monné 218596375eacSRoger Pau Monné np = ifp->if_softc; 218696375eacSRoger Pau Monné 218796375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 218896375eacSRoger Pau Monné txq = &np->txq[i]; 218996375eacSRoger Pau Monné 219096375eacSRoger Pau Monné XN_TX_LOCK(txq); 219196375eacSRoger Pau Monné while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 219296375eacSRoger Pau Monné m_freem(m); 219396375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 219496375eacSRoger Pau Monné } 219596375eacSRoger Pau Monné 219696375eacSRoger Pau Monné if_qflush(ifp); 219796375eacSRoger Pau Monné } 219896375eacSRoger Pau Monné 219976acc41fSJustin T. Gibbs /** 220076acc41fSJustin T. Gibbs * Create a network device. 220176acc41fSJustin T. Gibbs * @param dev Newbus device representing this virtual NIC. 220289e0f4d2SKip Macy */ 220323dc5621SKip Macy int 220423dc5621SKip Macy create_netdev(device_t dev) 220589e0f4d2SKip Macy { 220689e0f4d2SKip Macy struct netfront_info *np; 220789e0f4d2SKip Macy int err; 220889e0f4d2SKip Macy struct ifnet *ifp; 220989e0f4d2SKip Macy 221023dc5621SKip Macy np = device_get_softc(dev); 221189e0f4d2SKip Macy 221289e0f4d2SKip Macy np->xbdev = dev; 221389e0f4d2SKip Macy 2214177e3f13SRoger Pau Monné mtx_init(&np->sc_lock, "xnsc", "netfront softc lock", MTX_DEF); 22150e509842SJustin T. Gibbs 22160e509842SJustin T. Gibbs ifmedia_init(&np->sc_media, 0, xn_ifmedia_upd, xn_ifmedia_sts); 22170e509842SJustin T. Gibbs ifmedia_add(&np->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 22180e509842SJustin T. Gibbs ifmedia_set(&np->sc_media, IFM_ETHER|IFM_MANUAL); 22190e509842SJustin T. Gibbs 222089e0f4d2SKip Macy err = xen_net_read_mac(dev, np->mac); 222196375eacSRoger Pau Monné if (err != 0) 22221a2928b7SRoger Pau Monné goto error; 222389e0f4d2SKip Macy 222489e0f4d2SKip Macy /* Set up ifnet structure */ 222523dc5621SKip Macy ifp = np->xn_ifp = if_alloc(IFT_ETHER); 222689e0f4d2SKip Macy ifp->if_softc = np; 222723dc5621SKip Macy if_initname(ifp, "xn", device_get_unit(dev)); 22283a6d1fcfSKip Macy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 222989e0f4d2SKip Macy ifp->if_ioctl = xn_ioctl; 223096375eacSRoger Pau Monné 223196375eacSRoger Pau Monné ifp->if_transmit = xn_txq_mq_start; 223296375eacSRoger Pau Monné ifp->if_qflush = xn_qflush; 223396375eacSRoger Pau Monné 223489e0f4d2SKip Macy ifp->if_init = xn_ifinit; 223589e0f4d2SKip Macy 223689e0f4d2SKip Macy ifp->if_hwassist = XN_CSUM_FEATURES; 2237c2d12e5eSRoger Pau Monné /* Enable all supported features at device creation. */ 2238c2d12e5eSRoger Pau Monné ifp->if_capenable = ifp->if_capabilities = 2239c2d12e5eSRoger Pau Monné IFCAP_HWCSUM|IFCAP_TSO4|IFCAP_LRO; 22409fd573c3SHans Petter Selasky ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 22419fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegcount = MAX_TX_REQ_FRAGS; 22429fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 224389e0f4d2SKip Macy 224489e0f4d2SKip Macy ether_ifattach(ifp, np->mac); 224589e0f4d2SKip Macy netfront_carrier_off(np); 224689e0f4d2SKip Macy 224789e0f4d2SKip Macy return (0); 224889e0f4d2SKip Macy 22491a2928b7SRoger Pau Monné error: 22501a2928b7SRoger Pau Monné KASSERT(err != 0, ("Error path with no error code specified")); 2251ffa06904SJustin T. Gibbs return (err); 225289e0f4d2SKip Macy } 225389e0f4d2SKip Macy 22540e509842SJustin T. Gibbs static int 22550e509842SJustin T. Gibbs netfront_detach(device_t dev) 225689e0f4d2SKip Macy { 225723dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 225889e0f4d2SKip Macy 225923dc5621SKip Macy DPRINTK("%s\n", xenbus_get_node(dev)); 226089e0f4d2SKip Macy 226189e0f4d2SKip Macy netif_free(info); 226289e0f4d2SKip Macy 226389e0f4d2SKip Macy return 0; 226489e0f4d2SKip Macy } 226589e0f4d2SKip Macy 22660e509842SJustin T. Gibbs static void 226796375eacSRoger Pau Monné netif_free(struct netfront_info *np) 226889e0f4d2SKip Macy { 226996375eacSRoger Pau Monné 227096375eacSRoger Pau Monné XN_LOCK(np); 227196375eacSRoger Pau Monné xn_stop(np); 227296375eacSRoger Pau Monné XN_UNLOCK(np); 227396375eacSRoger Pau Monné netif_disconnect_backend(np); 2274c21b47d8SRoger Pau Monné ether_ifdetach(np->xn_ifp); 227596375eacSRoger Pau Monné free(np->rxq, M_DEVBUF); 227696375eacSRoger Pau Monné free(np->txq, M_DEVBUF); 227796375eacSRoger Pau Monné if_free(np->xn_ifp); 227896375eacSRoger Pau Monné np->xn_ifp = NULL; 227996375eacSRoger Pau Monné ifmedia_removeall(&np->sc_media); 228089e0f4d2SKip Macy } 228189e0f4d2SKip Macy 22820e509842SJustin T. Gibbs static void 228396375eacSRoger Pau Monné netif_disconnect_backend(struct netfront_info *np) 228489e0f4d2SKip Macy { 228596375eacSRoger Pau Monné u_int i; 22863a6d1fcfSKip Macy 228796375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 228896375eacSRoger Pau Monné XN_RX_LOCK(&np->rxq[i]); 228996375eacSRoger Pau Monné XN_TX_LOCK(&np->txq[i]); 229096375eacSRoger Pau Monné } 229196375eacSRoger Pau Monné netfront_carrier_off(np); 229296375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 229396375eacSRoger Pau Monné XN_RX_UNLOCK(&np->rxq[i]); 229496375eacSRoger Pau Monné XN_TX_UNLOCK(&np->txq[i]); 229589e0f4d2SKip Macy } 229689e0f4d2SKip Macy 229796375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 229896375eacSRoger Pau Monné disconnect_rxq(&np->rxq[i]); 229996375eacSRoger Pau Monné disconnect_txq(&np->txq[i]); 2300cf9c09e1SJustin T. Gibbs } 230189e0f4d2SKip Macy } 230289e0f4d2SKip Macy 23030e509842SJustin T. Gibbs static int 23040e509842SJustin T. Gibbs xn_ifmedia_upd(struct ifnet *ifp) 23050e509842SJustin T. Gibbs { 230696375eacSRoger Pau Monné 23070e509842SJustin T. Gibbs return (0); 23080e509842SJustin T. Gibbs } 23090e509842SJustin T. Gibbs 23100e509842SJustin T. Gibbs static void 23110e509842SJustin T. Gibbs xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 23120e509842SJustin T. Gibbs { 231396375eacSRoger Pau Monné 23140e509842SJustin T. Gibbs ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE; 23150e509842SJustin T. Gibbs ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; 23160e509842SJustin T. Gibbs } 23170e509842SJustin T. Gibbs 231889e0f4d2SKip Macy /* ** Driver registration ** */ 231923dc5621SKip Macy static device_method_t netfront_methods[] = { 232023dc5621SKip Macy /* Device interface */ 232123dc5621SKip Macy DEVMETHOD(device_probe, netfront_probe), 232223dc5621SKip Macy DEVMETHOD(device_attach, netfront_attach), 232323dc5621SKip Macy DEVMETHOD(device_detach, netfront_detach), 232423dc5621SKip Macy DEVMETHOD(device_shutdown, bus_generic_shutdown), 2325cf9c09e1SJustin T. Gibbs DEVMETHOD(device_suspend, netfront_suspend), 232623dc5621SKip Macy DEVMETHOD(device_resume, netfront_resume), 232789e0f4d2SKip Macy 232823dc5621SKip Macy /* Xenbus interface */ 2329ff662b5cSJustin T. Gibbs DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed), 233089e0f4d2SKip Macy 23316f9767acSMarius Strobl DEVMETHOD_END 233289e0f4d2SKip Macy }; 233389e0f4d2SKip Macy 233423dc5621SKip Macy static driver_t netfront_driver = { 233523dc5621SKip Macy "xn", 233623dc5621SKip Macy netfront_methods, 233723dc5621SKip Macy sizeof(struct netfront_info), 233889e0f4d2SKip Macy }; 233923dc5621SKip Macy devclass_t netfront_devclass; 234089e0f4d2SKip Macy 23416f9767acSMarius Strobl DRIVER_MODULE(xe, xenbusb_front, netfront_driver, netfront_devclass, NULL, 23426f9767acSMarius Strobl NULL); 2343