18e0ad55aSJoel Dahl /*- 289e0f4d2SKip Macy * Copyright (c) 2004-2006 Kip Macy 396375eacSRoger Pau Monné * Copyright (c) 2015 Wei Liu <wei.liu2@citrix.com> 489e0f4d2SKip Macy * All rights reserved. 589e0f4d2SKip Macy * 68e0ad55aSJoel Dahl * Redistribution and use in source and binary forms, with or without 78e0ad55aSJoel Dahl * modification, are permitted provided that the following conditions 88e0ad55aSJoel Dahl * are met: 98e0ad55aSJoel Dahl * 1. Redistributions of source code must retain the above copyright 108e0ad55aSJoel Dahl * notice, this list of conditions and the following disclaimer. 118e0ad55aSJoel Dahl * 2. Redistributions in binary form must reproduce the above copyright 128e0ad55aSJoel Dahl * notice, this list of conditions and the following disclaimer in the 138e0ad55aSJoel Dahl * documentation and/or other materials provided with the distribution. 1489e0f4d2SKip Macy * 158e0ad55aSJoel Dahl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 168e0ad55aSJoel Dahl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 178e0ad55aSJoel Dahl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 188e0ad55aSJoel Dahl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 198e0ad55aSJoel Dahl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 208e0ad55aSJoel Dahl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 218e0ad55aSJoel Dahl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 228e0ad55aSJoel Dahl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 238e0ad55aSJoel Dahl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 248e0ad55aSJoel Dahl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 258e0ad55aSJoel Dahl * SUCH DAMAGE. 2689e0f4d2SKip Macy */ 2789e0f4d2SKip Macy 2889e0f4d2SKip Macy #include <sys/cdefs.h> 2989e0f4d2SKip Macy __FBSDID("$FreeBSD$"); 3089e0f4d2SKip Macy 31a0ae8f04SBjoern A. Zeeb #include "opt_inet.h" 32f909bbb4SGleb Smirnoff #include "opt_inet6.h" 33a0ae8f04SBjoern A. Zeeb 3489e0f4d2SKip Macy #include <sys/param.h> 3589e0f4d2SKip Macy #include <sys/sockio.h> 36c578b6acSGleb Smirnoff #include <sys/limits.h> 3789e0f4d2SKip Macy #include <sys/mbuf.h> 3889e0f4d2SKip Macy #include <sys/malloc.h> 3923dc5621SKip Macy #include <sys/module.h> 4089e0f4d2SKip Macy #include <sys/kernel.h> 4189e0f4d2SKip Macy #include <sys/socket.h> 4212678024SDoug Rabson #include <sys/sysctl.h> 4396375eacSRoger Pau Monné #include <sys/taskqueue.h> 4489e0f4d2SKip Macy 4589e0f4d2SKip Macy #include <net/if.h> 4677374386SGleb Smirnoff #include <net/if_var.h> 4789e0f4d2SKip Macy #include <net/if_arp.h> 4889e0f4d2SKip Macy #include <net/ethernet.h> 4989e0f4d2SKip Macy #include <net/if_media.h> 5089e0f4d2SKip Macy #include <net/bpf.h> 5189e0f4d2SKip Macy #include <net/if_types.h> 5289e0f4d2SKip Macy 5389e0f4d2SKip Macy #include <netinet/in.h> 5489e0f4d2SKip Macy #include <netinet/ip.h> 5589e0f4d2SKip Macy #include <netinet/if_ether.h> 5612678024SDoug Rabson #include <netinet/tcp.h> 5712678024SDoug Rabson #include <netinet/tcp_lro.h> 5889e0f4d2SKip Macy 5989e0f4d2SKip Macy #include <vm/vm.h> 6089e0f4d2SKip Macy #include <vm/pmap.h> 6189e0f4d2SKip Macy 6289e0f4d2SKip Macy #include <sys/bus.h> 6389e0f4d2SKip Macy 6476acc41fSJustin T. Gibbs #include <xen/xen-os.h> 653a6d1fcfSKip Macy #include <xen/hypervisor.h> 663a6d1fcfSKip Macy #include <xen/xen_intr.h> 6789e0f4d2SKip Macy #include <xen/gnttab.h> 6889e0f4d2SKip Macy #include <xen/interface/memory.h> 6989e0f4d2SKip Macy #include <xen/interface/io/netif.h> 7023dc5621SKip Macy #include <xen/xenbus/xenbusvar.h> 7189e0f4d2SKip Macy 7223dc5621SKip Macy #include "xenbus_if.h" 7389e0f4d2SKip Macy 74578e4bf7SJustin T. Gibbs /* Features supported by all backends. TSO and LRO can be negotiated */ 75578e4bf7SJustin T. Gibbs #define XN_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) 7612678024SDoug Rabson 7789e0f4d2SKip Macy #define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) 7889e0f4d2SKip Macy #define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) 7989e0f4d2SKip Macy 80*2568ee67SRoger Pau Monné #define NET_RX_SLOTS_MIN (XEN_NETIF_NR_SLOTS_MIN + 1) 81*2568ee67SRoger Pau Monné 8212678024SDoug Rabson /* 8312678024SDoug Rabson * Should the driver do LRO on the RX end 8412678024SDoug Rabson * this can be toggled on the fly, but the 8512678024SDoug Rabson * interface must be reset (down/up) for it 8612678024SDoug Rabson * to take effect. 8712678024SDoug Rabson */ 8812678024SDoug Rabson static int xn_enable_lro = 1; 8912678024SDoug Rabson TUNABLE_INT("hw.xn.enable_lro", &xn_enable_lro); 9012678024SDoug Rabson 9196375eacSRoger Pau Monné /* 9296375eacSRoger Pau Monné * Number of pairs of queues. 9396375eacSRoger Pau Monné */ 9496375eacSRoger Pau Monné static unsigned long xn_num_queues = 4; 9596375eacSRoger Pau Monné TUNABLE_ULONG("hw.xn.num_queues", &xn_num_queues); 9696375eacSRoger Pau Monné 97931eeffaSKenneth D. Merry /** 98931eeffaSKenneth D. Merry * \brief The maximum allowed data fragments in a single transmit 99931eeffaSKenneth D. Merry * request. 100931eeffaSKenneth D. Merry * 101931eeffaSKenneth D. Merry * This limit is imposed by the backend driver. We assume here that 102931eeffaSKenneth D. Merry * we are dealing with a Linux driver domain and have set our limit 103931eeffaSKenneth D. Merry * to mirror the Linux MAX_SKB_FRAGS constant. 104931eeffaSKenneth D. Merry */ 105931eeffaSKenneth D. Merry #define MAX_TX_REQ_FRAGS (65536 / PAGE_SIZE + 2) 106931eeffaSKenneth D. Merry 10789e0f4d2SKip Macy #define RX_COPY_THRESHOLD 256 10889e0f4d2SKip Macy 10989e0f4d2SKip Macy #define net_ratelimit() 0 11089e0f4d2SKip Macy 11196375eacSRoger Pau Monné struct netfront_rxq; 11296375eacSRoger Pau Monné struct netfront_txq; 11389e0f4d2SKip Macy struct netfront_info; 11489e0f4d2SKip Macy struct netfront_rx_info; 11589e0f4d2SKip Macy 11696375eacSRoger Pau Monné static void xn_txeof(struct netfront_txq *); 11796375eacSRoger Pau Monné static void xn_rxeof(struct netfront_rxq *); 11896375eacSRoger Pau Monné static void xn_alloc_rx_buffers(struct netfront_rxq *); 119*2568ee67SRoger Pau Monné static void xn_alloc_rx_buffers_callout(void *arg); 12089e0f4d2SKip Macy 12196375eacSRoger Pau Monné static void xn_release_rx_bufs(struct netfront_rxq *); 12296375eacSRoger Pau Monné static void xn_release_tx_bufs(struct netfront_txq *); 12389e0f4d2SKip Macy 12496375eacSRoger Pau Monné static void xn_rxq_intr(void *); 12596375eacSRoger Pau Monné static void xn_txq_intr(void *); 12696375eacSRoger Pau Monné static int xn_intr(void *); 127931eeffaSKenneth D. Merry static inline int xn_count_frags(struct mbuf *m); 12896375eacSRoger Pau Monné static int xn_assemble_tx_request(struct netfront_txq *, struct mbuf *); 12989e0f4d2SKip Macy static int xn_ioctl(struct ifnet *, u_long, caddr_t); 13089e0f4d2SKip Macy static void xn_ifinit_locked(struct netfront_info *); 13189e0f4d2SKip Macy static void xn_ifinit(void *); 13289e0f4d2SKip Macy static void xn_stop(struct netfront_info *); 133578e4bf7SJustin T. Gibbs static void xn_query_features(struct netfront_info *np); 134578e4bf7SJustin T. Gibbs static int xn_configure_features(struct netfront_info *np); 13589e0f4d2SKip Macy static void netif_free(struct netfront_info *info); 13623dc5621SKip Macy static int netfront_detach(device_t dev); 13789e0f4d2SKip Macy 13896375eacSRoger Pau Monné static int xn_txq_mq_start_locked(struct netfront_txq *, struct mbuf *); 13996375eacSRoger Pau Monné static int xn_txq_mq_start(struct ifnet *, struct mbuf *); 14096375eacSRoger Pau Monné 14123dc5621SKip Macy static int talk_to_backend(device_t dev, struct netfront_info *info); 14223dc5621SKip Macy static int create_netdev(device_t dev); 14389e0f4d2SKip Macy static void netif_disconnect_backend(struct netfront_info *info); 14496375eacSRoger Pau Monné static int setup_device(device_t dev, struct netfront_info *info, 14596375eacSRoger Pau Monné unsigned long); 1460e509842SJustin T. Gibbs static int xn_ifmedia_upd(struct ifnet *ifp); 1470e509842SJustin T. Gibbs static void xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 1480e509842SJustin T. Gibbs 14996375eacSRoger Pau Monné int xn_connect(struct netfront_info *); 15089e0f4d2SKip Macy 15196375eacSRoger Pau Monné static int xn_get_responses(struct netfront_rxq *, 15296375eacSRoger Pau Monné struct netfront_rx_info *, RING_IDX, RING_IDX *, 15396375eacSRoger Pau Monné struct mbuf **); 15489e0f4d2SKip Macy 1553c790178SJohn Baldwin #define virt_to_mfn(x) (vtophys(x) >> PAGE_SHIFT) 15689e0f4d2SKip Macy 15789e0f4d2SKip Macy #define INVALID_P2M_ENTRY (~0UL) 15889e0f4d2SKip Macy 15996375eacSRoger Pau Monné struct xn_rx_stats 16089e0f4d2SKip Macy { 16189e0f4d2SKip Macy u_long rx_packets; /* total packets received */ 16289e0f4d2SKip Macy u_long rx_bytes; /* total bytes received */ 16389e0f4d2SKip Macy u_long rx_errors; /* bad packets received */ 16496375eacSRoger Pau Monné }; 16596375eacSRoger Pau Monné 16696375eacSRoger Pau Monné struct xn_tx_stats 16796375eacSRoger Pau Monné { 16896375eacSRoger Pau Monné u_long tx_packets; /* total packets transmitted */ 16996375eacSRoger Pau Monné u_long tx_bytes; /* total bytes transmitted */ 17089e0f4d2SKip Macy u_long tx_errors; /* packet transmit problems */ 17189e0f4d2SKip Macy }; 17289e0f4d2SKip Macy 17396375eacSRoger Pau Monné #define XN_QUEUE_NAME_LEN 8 /* xn{t,r}x_%u, allow for two digits */ 17496375eacSRoger Pau Monné struct netfront_rxq { 17596375eacSRoger Pau Monné struct netfront_info *info; 17696375eacSRoger Pau Monné u_int id; 17796375eacSRoger Pau Monné char name[XN_QUEUE_NAME_LEN]; 17896375eacSRoger Pau Monné struct mtx lock; 17996375eacSRoger Pau Monné 18096375eacSRoger Pau Monné int ring_ref; 18196375eacSRoger Pau Monné netif_rx_front_ring_t ring; 18296375eacSRoger Pau Monné xen_intr_handle_t xen_intr_handle; 18396375eacSRoger Pau Monné 18496375eacSRoger Pau Monné grant_ref_t gref_head; 18596375eacSRoger Pau Monné grant_ref_t grant_ref[NET_TX_RING_SIZE + 1]; 18696375eacSRoger Pau Monné 18796375eacSRoger Pau Monné struct mbuf *mbufs[NET_RX_RING_SIZE + 1]; 18896375eacSRoger Pau Monné 18996375eacSRoger Pau Monné struct lro_ctrl lro; 19096375eacSRoger Pau Monné 19196375eacSRoger Pau Monné struct taskqueue *tq; 19296375eacSRoger Pau Monné struct task intrtask; 19396375eacSRoger Pau Monné 194*2568ee67SRoger Pau Monné struct callout rx_refill; 195*2568ee67SRoger Pau Monné 19696375eacSRoger Pau Monné struct xn_rx_stats stats; 19796375eacSRoger Pau Monné }; 19896375eacSRoger Pau Monné 19996375eacSRoger Pau Monné struct netfront_txq { 20096375eacSRoger Pau Monné struct netfront_info *info; 20196375eacSRoger Pau Monné u_int id; 20296375eacSRoger Pau Monné char name[XN_QUEUE_NAME_LEN]; 20396375eacSRoger Pau Monné struct mtx lock; 20496375eacSRoger Pau Monné 20596375eacSRoger Pau Monné int ring_ref; 20696375eacSRoger Pau Monné netif_tx_front_ring_t ring; 20796375eacSRoger Pau Monné xen_intr_handle_t xen_intr_handle; 20896375eacSRoger Pau Monné 20996375eacSRoger Pau Monné grant_ref_t gref_head; 21096375eacSRoger Pau Monné grant_ref_t grant_ref[NET_TX_RING_SIZE + 1]; 21196375eacSRoger Pau Monné 21296375eacSRoger Pau Monné struct mbuf *mbufs[NET_TX_RING_SIZE + 1]; 21396375eacSRoger Pau Monné int mbufs_cnt; 21496375eacSRoger Pau Monné struct buf_ring *br; 21596375eacSRoger Pau Monné 21696375eacSRoger Pau Monné struct taskqueue *tq; 21796375eacSRoger Pau Monné struct task intrtask; 21896375eacSRoger Pau Monné struct task defrtask; 21996375eacSRoger Pau Monné 22096375eacSRoger Pau Monné bool full; 22196375eacSRoger Pau Monné 22296375eacSRoger Pau Monné struct xn_tx_stats stats; 22396375eacSRoger Pau Monné }; 22496375eacSRoger Pau Monné 22589e0f4d2SKip Macy struct netfront_info { 22689e0f4d2SKip Macy struct ifnet *xn_ifp; 22789e0f4d2SKip Macy 228227ca257SKip Macy struct mtx sc_lock; 22989e0f4d2SKip Macy 23096375eacSRoger Pau Monné u_int num_queues; 23196375eacSRoger Pau Monné struct netfront_rxq *rxq; 23296375eacSRoger Pau Monné struct netfront_txq *txq; 23396375eacSRoger Pau Monné 23489e0f4d2SKip Macy u_int carrier; 235578e4bf7SJustin T. Gibbs u_int maxfrags; 23689e0f4d2SKip Macy 23723dc5621SKip Macy device_t xbdev; 23889e0f4d2SKip Macy uint8_t mac[ETHER_ADDR_LEN]; 23989e0f4d2SKip Macy 24089e0f4d2SKip Macy int xn_if_flags; 24189e0f4d2SKip Macy 2420e509842SJustin T. Gibbs struct ifmedia sc_media; 2436a8e9695SRoger Pau Monné 2446a8e9695SRoger Pau Monné bool xn_resume; 24589e0f4d2SKip Macy }; 24689e0f4d2SKip Macy 24796375eacSRoger Pau Monné struct netfront_rx_info { 24896375eacSRoger Pau Monné struct netif_rx_response rx; 24996375eacSRoger Pau Monné struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; 25096375eacSRoger Pau Monné }; 25189e0f4d2SKip Macy 25296375eacSRoger Pau Monné #define XN_RX_LOCK(_q) mtx_lock(&(_q)->lock) 25396375eacSRoger Pau Monné #define XN_RX_UNLOCK(_q) mtx_unlock(&(_q)->lock) 25489e0f4d2SKip Macy 25596375eacSRoger Pau Monné #define XN_TX_LOCK(_q) mtx_lock(&(_q)->lock) 25696375eacSRoger Pau Monné #define XN_TX_TRYLOCK(_q) mtx_trylock(&(_q)->lock) 25796375eacSRoger Pau Monné #define XN_TX_UNLOCK(_q) mtx_unlock(&(_q)->lock) 25889e0f4d2SKip Macy 259227ca257SKip Macy #define XN_LOCK(_sc) mtx_lock(&(_sc)->sc_lock); 260227ca257SKip Macy #define XN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock); 26189e0f4d2SKip Macy 262227ca257SKip Macy #define XN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED); 26396375eacSRoger Pau Monné #define XN_RX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); 26496375eacSRoger Pau Monné #define XN_TX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); 26589e0f4d2SKip Macy 26689e0f4d2SKip Macy #define netfront_carrier_on(netif) ((netif)->carrier = 1) 26789e0f4d2SKip Macy #define netfront_carrier_off(netif) ((netif)->carrier = 0) 26889e0f4d2SKip Macy #define netfront_carrier_ok(netif) ((netif)->carrier) 26989e0f4d2SKip Macy 27089e0f4d2SKip Macy /* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ 27189e0f4d2SKip Macy 27289e0f4d2SKip Macy static inline void 273931eeffaSKenneth D. Merry add_id_to_freelist(struct mbuf **list, uintptr_t id) 27489e0f4d2SKip Macy { 27596375eacSRoger Pau Monné 276931eeffaSKenneth D. Merry KASSERT(id != 0, 277931eeffaSKenneth D. Merry ("%s: the head item (0) must always be free.", __func__)); 27889e0f4d2SKip Macy list[id] = list[0]; 279931eeffaSKenneth D. Merry list[0] = (struct mbuf *)id; 28089e0f4d2SKip Macy } 28189e0f4d2SKip Macy 28289e0f4d2SKip Macy static inline unsigned short 28389e0f4d2SKip Macy get_id_from_freelist(struct mbuf **list) 28489e0f4d2SKip Macy { 285931eeffaSKenneth D. Merry uintptr_t id; 286931eeffaSKenneth D. Merry 287931eeffaSKenneth D. Merry id = (uintptr_t)list[0]; 288931eeffaSKenneth D. Merry KASSERT(id != 0, 289931eeffaSKenneth D. Merry ("%s: the head item (0) must always remain free.", __func__)); 29089e0f4d2SKip Macy list[0] = list[id]; 29189e0f4d2SKip Macy return (id); 29289e0f4d2SKip Macy } 29389e0f4d2SKip Macy 29489e0f4d2SKip Macy static inline int 29596375eacSRoger Pau Monné xn_rxidx(RING_IDX idx) 29689e0f4d2SKip Macy { 29796375eacSRoger Pau Monné 29889e0f4d2SKip Macy return idx & (NET_RX_RING_SIZE - 1); 29989e0f4d2SKip Macy } 30089e0f4d2SKip Macy 30189e0f4d2SKip Macy static inline struct mbuf * 30296375eacSRoger Pau Monné xn_get_rx_mbuf(struct netfront_rxq *rxq, RING_IDX ri) 30389e0f4d2SKip Macy { 30496375eacSRoger Pau Monné int i; 30589e0f4d2SKip Macy struct mbuf *m; 30689e0f4d2SKip Macy 30796375eacSRoger Pau Monné i = xn_rxidx(ri); 30896375eacSRoger Pau Monné m = rxq->mbufs[i]; 30996375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 31089e0f4d2SKip Macy return (m); 31189e0f4d2SKip Macy } 31289e0f4d2SKip Macy 31389e0f4d2SKip Macy static inline grant_ref_t 31496375eacSRoger Pau Monné xn_get_rx_ref(struct netfront_rxq *rxq, RING_IDX ri) 31589e0f4d2SKip Macy { 31696375eacSRoger Pau Monné int i = xn_rxidx(ri); 31796375eacSRoger Pau Monné grant_ref_t ref = rxq->grant_ref[i]; 31896375eacSRoger Pau Monné 319ff662b5cSJustin T. Gibbs KASSERT(ref != GRANT_REF_INVALID, ("Invalid grant reference!\n")); 32096375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 32196375eacSRoger Pau Monné return (ref); 32289e0f4d2SKip Macy } 32389e0f4d2SKip Macy 32489e0f4d2SKip Macy #define IPRINTK(fmt, args...) \ 32589e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 326227ca257SKip Macy #ifdef INVARIANTS 32789e0f4d2SKip Macy #define WPRINTK(fmt, args...) \ 32889e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 329227ca257SKip Macy #else 330227ca257SKip Macy #define WPRINTK(fmt, args...) 331227ca257SKip Macy #endif 332227ca257SKip Macy #ifdef DEBUG 33389e0f4d2SKip Macy #define DPRINTK(fmt, args...) \ 33423dc5621SKip Macy printf("[XEN] %s: " fmt, __func__, ##args) 33512678024SDoug Rabson #else 33612678024SDoug Rabson #define DPRINTK(fmt, args...) 33712678024SDoug Rabson #endif 33889e0f4d2SKip Macy 33989e0f4d2SKip Macy /** 34089e0f4d2SKip Macy * Read the 'mac' node at the given device's node in the store, and parse that 34189e0f4d2SKip Macy * as colon-separated octets, placing result the given mac array. mac must be 34289e0f4d2SKip Macy * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). 34389e0f4d2SKip Macy * Return 0 on success, or errno on error. 34489e0f4d2SKip Macy */ 34589e0f4d2SKip Macy static int 34623dc5621SKip Macy xen_net_read_mac(device_t dev, uint8_t mac[]) 34789e0f4d2SKip Macy { 3483a6d1fcfSKip Macy int error, i; 3493a6d1fcfSKip Macy char *s, *e, *macstr; 350ffa06904SJustin T. Gibbs const char *path; 3513a6d1fcfSKip Macy 352ffa06904SJustin T. Gibbs path = xenbus_get_node(dev); 353ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 354ffa06904SJustin T. Gibbs if (error == ENOENT) { 355ffa06904SJustin T. Gibbs /* 356ffa06904SJustin T. Gibbs * Deal with missing mac XenStore nodes on devices with 357ffa06904SJustin T. Gibbs * HVM emulation (the 'ioemu' configuration attribute) 358ffa06904SJustin T. Gibbs * enabled. 359ffa06904SJustin T. Gibbs * 360ffa06904SJustin T. Gibbs * The HVM emulator may execute in a stub device model 361ffa06904SJustin T. Gibbs * domain which lacks the permission, only given to Dom0, 362ffa06904SJustin T. Gibbs * to update the guest's XenStore tree. For this reason, 363ffa06904SJustin T. Gibbs * the HVM emulator doesn't even attempt to write the 364ffa06904SJustin T. Gibbs * front-side mac node, even when operating in Dom0. 365ffa06904SJustin T. Gibbs * However, there should always be a mac listed in the 366ffa06904SJustin T. Gibbs * backend tree. Fallback to this version if our query 367ffa06904SJustin T. Gibbs * of the front side XenStore location doesn't find 368ffa06904SJustin T. Gibbs * anything. 369ffa06904SJustin T. Gibbs */ 370ffa06904SJustin T. Gibbs path = xenbus_get_otherend_path(dev); 371ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 372ffa06904SJustin T. Gibbs } 373ffa06904SJustin T. Gibbs if (error != 0) { 374ffa06904SJustin T. Gibbs xenbus_dev_fatal(dev, error, "parsing %s/mac", path); 3753a6d1fcfSKip Macy return (error); 376ffa06904SJustin T. Gibbs } 3773a6d1fcfSKip Macy 37889e0f4d2SKip Macy s = macstr; 37989e0f4d2SKip Macy for (i = 0; i < ETHER_ADDR_LEN; i++) { 38089e0f4d2SKip Macy mac[i] = strtoul(s, &e, 16); 38189e0f4d2SKip Macy if (s == e || (e[0] != ':' && e[0] != 0)) { 382ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 3833a6d1fcfSKip Macy return (ENOENT); 38489e0f4d2SKip Macy } 38589e0f4d2SKip Macy s = &e[1]; 38689e0f4d2SKip Macy } 387ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 3883a6d1fcfSKip Macy return (0); 38989e0f4d2SKip Macy } 39089e0f4d2SKip Macy 39189e0f4d2SKip Macy /** 39289e0f4d2SKip Macy * Entry point to this code when a new device is created. Allocate the basic 39389e0f4d2SKip Macy * structures and the ring buffers for communication with the backend, and 39489e0f4d2SKip Macy * inform the backend of the appropriate details for those. Switch to 39589e0f4d2SKip Macy * Connected state. 39689e0f4d2SKip Macy */ 39789e0f4d2SKip Macy static int 39823dc5621SKip Macy netfront_probe(device_t dev) 39923dc5621SKip Macy { 40023dc5621SKip Macy 401f8f1bb83SRoger Pau Monné if (xen_hvm_domain() && xen_disable_pv_nics != 0) 402f8f1bb83SRoger Pau Monné return (ENXIO); 403f8f1bb83SRoger Pau Monné 40423dc5621SKip Macy if (!strcmp(xenbus_get_type(dev), "vif")) { 40523dc5621SKip Macy device_set_desc(dev, "Virtual Network Interface"); 40623dc5621SKip Macy return (0); 40723dc5621SKip Macy } 40823dc5621SKip Macy 40923dc5621SKip Macy return (ENXIO); 41023dc5621SKip Macy } 41123dc5621SKip Macy 41223dc5621SKip Macy static int 41323dc5621SKip Macy netfront_attach(device_t dev) 41489e0f4d2SKip Macy { 41589e0f4d2SKip Macy int err; 41689e0f4d2SKip Macy 41723dc5621SKip Macy err = create_netdev(dev); 41896375eacSRoger Pau Monné if (err != 0) { 41989e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "creating netdev"); 420ffa06904SJustin T. Gibbs return (err); 42189e0f4d2SKip Macy } 42289e0f4d2SKip Macy 42312678024SDoug Rabson SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 42412678024SDoug Rabson SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 425f0188618SHans Petter Selasky OID_AUTO, "enable_lro", CTLFLAG_RW, 42612678024SDoug Rabson &xn_enable_lro, 0, "Large Receive Offload"); 42712678024SDoug Rabson 42896375eacSRoger Pau Monné SYSCTL_ADD_ULONG(device_get_sysctl_ctx(dev), 42996375eacSRoger Pau Monné SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 43096375eacSRoger Pau Monné OID_AUTO, "num_queues", CTLFLAG_RD, 43196375eacSRoger Pau Monné &xn_num_queues, "Number of pairs of queues"); 43296375eacSRoger Pau Monné 433ffa06904SJustin T. Gibbs return (0); 43489e0f4d2SKip Macy } 43589e0f4d2SKip Macy 436cf9c09e1SJustin T. Gibbs static int 437cf9c09e1SJustin T. Gibbs netfront_suspend(device_t dev) 438cf9c09e1SJustin T. Gibbs { 43996375eacSRoger Pau Monné struct netfront_info *np = device_get_softc(dev); 44096375eacSRoger Pau Monné u_int i; 441cf9c09e1SJustin T. Gibbs 44296375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 44396375eacSRoger Pau Monné XN_RX_LOCK(&np->rxq[i]); 44496375eacSRoger Pau Monné XN_TX_LOCK(&np->txq[i]); 44596375eacSRoger Pau Monné } 44696375eacSRoger Pau Monné netfront_carrier_off(np); 44796375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 44896375eacSRoger Pau Monné XN_RX_UNLOCK(&np->rxq[i]); 44996375eacSRoger Pau Monné XN_TX_UNLOCK(&np->txq[i]); 45096375eacSRoger Pau Monné } 451cf9c09e1SJustin T. Gibbs return (0); 452cf9c09e1SJustin T. Gibbs } 45389e0f4d2SKip Macy 45489e0f4d2SKip Macy /** 45589e0f4d2SKip Macy * We are reconnecting to the backend, due to a suspend/resume, or a backend 45689e0f4d2SKip Macy * driver restart. We tear down our netif structure and recreate it, but 45789e0f4d2SKip Macy * leave the device-layer structures intact so that this is transparent to the 45889e0f4d2SKip Macy * rest of the kernel. 45989e0f4d2SKip Macy */ 46089e0f4d2SKip Macy static int 46123dc5621SKip Macy netfront_resume(device_t dev) 46289e0f4d2SKip Macy { 46323dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 46489e0f4d2SKip Macy 4656a8e9695SRoger Pau Monné info->xn_resume = true; 46689e0f4d2SKip Macy netif_disconnect_backend(info); 46789e0f4d2SKip Macy return (0); 46889e0f4d2SKip Macy } 46989e0f4d2SKip Macy 47096375eacSRoger Pau Monné static int 47196375eacSRoger Pau Monné write_queue_xenstore_keys(device_t dev, 47296375eacSRoger Pau Monné struct netfront_rxq *rxq, 47396375eacSRoger Pau Monné struct netfront_txq *txq, 47496375eacSRoger Pau Monné struct xs_transaction *xst, bool hierarchy) 47596375eacSRoger Pau Monné { 47696375eacSRoger Pau Monné int err; 47796375eacSRoger Pau Monné const char *message; 47896375eacSRoger Pau Monné const char *node = xenbus_get_node(dev); 47996375eacSRoger Pau Monné char *path; 48096375eacSRoger Pau Monné size_t path_size; 48196375eacSRoger Pau Monné 48296375eacSRoger Pau Monné KASSERT(rxq->id == txq->id, ("Mismatch between RX and TX queue ids")); 48396375eacSRoger Pau Monné /* Split event channel support is not yet there. */ 48496375eacSRoger Pau Monné KASSERT(rxq->xen_intr_handle == txq->xen_intr_handle, 48596375eacSRoger Pau Monné ("Split event channels are not supported")); 48696375eacSRoger Pau Monné 48796375eacSRoger Pau Monné if (hierarchy) { 48896375eacSRoger Pau Monné path_size = strlen(node) + 10; 48996375eacSRoger Pau Monné path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); 49096375eacSRoger Pau Monné snprintf(path, path_size, "%s/queue-%u", node, rxq->id); 49196375eacSRoger Pau Monné } else { 49296375eacSRoger Pau Monné path_size = strlen(node) + 1; 49396375eacSRoger Pau Monné path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); 49496375eacSRoger Pau Monné snprintf(path, path_size, "%s", node); 49596375eacSRoger Pau Monné } 49696375eacSRoger Pau Monné 49796375eacSRoger Pau Monné err = xs_printf(*xst, path, "tx-ring-ref","%u", txq->ring_ref); 49896375eacSRoger Pau Monné if (err != 0) { 49996375eacSRoger Pau Monné message = "writing tx ring-ref"; 50096375eacSRoger Pau Monné goto error; 50196375eacSRoger Pau Monné } 50296375eacSRoger Pau Monné err = xs_printf(*xst, path, "rx-ring-ref","%u", rxq->ring_ref); 50396375eacSRoger Pau Monné if (err != 0) { 50496375eacSRoger Pau Monné message = "writing rx ring-ref"; 50596375eacSRoger Pau Monné goto error; 50696375eacSRoger Pau Monné } 50796375eacSRoger Pau Monné err = xs_printf(*xst, path, "event-channel", "%u", 50896375eacSRoger Pau Monné xen_intr_port(rxq->xen_intr_handle)); 50996375eacSRoger Pau Monné if (err != 0) { 51096375eacSRoger Pau Monné message = "writing event-channel"; 51196375eacSRoger Pau Monné goto error; 51296375eacSRoger Pau Monné } 51396375eacSRoger Pau Monné 51496375eacSRoger Pau Monné free(path, M_DEVBUF); 51596375eacSRoger Pau Monné 51696375eacSRoger Pau Monné return (0); 51796375eacSRoger Pau Monné 51896375eacSRoger Pau Monné error: 51996375eacSRoger Pau Monné free(path, M_DEVBUF); 52096375eacSRoger Pau Monné xenbus_dev_fatal(dev, err, "%s", message); 52196375eacSRoger Pau Monné 52296375eacSRoger Pau Monné return (err); 52396375eacSRoger Pau Monné } 52496375eacSRoger Pau Monné 52589e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */ 52689e0f4d2SKip Macy static int 52723dc5621SKip Macy talk_to_backend(device_t dev, struct netfront_info *info) 52889e0f4d2SKip Macy { 52989e0f4d2SKip Macy const char *message; 530ff662b5cSJustin T. Gibbs struct xs_transaction xst; 53123dc5621SKip Macy const char *node = xenbus_get_node(dev); 53289e0f4d2SKip Macy int err; 53396375eacSRoger Pau Monné unsigned long num_queues, max_queues = 0; 53496375eacSRoger Pau Monné unsigned int i; 53589e0f4d2SKip Macy 53689e0f4d2SKip Macy err = xen_net_read_mac(dev, info->mac); 53796375eacSRoger Pau Monné if (err != 0) { 53823dc5621SKip Macy xenbus_dev_fatal(dev, err, "parsing %s/mac", node); 53989e0f4d2SKip Macy goto out; 54089e0f4d2SKip Macy } 54189e0f4d2SKip Macy 54296375eacSRoger Pau Monné err = xs_scanf(XST_NIL, xenbus_get_otherend_path(info->xbdev), 54396375eacSRoger Pau Monné "multi-queue-max-queues", NULL, "%lu", &max_queues); 54496375eacSRoger Pau Monné if (err != 0) 54596375eacSRoger Pau Monné max_queues = 1; 54696375eacSRoger Pau Monné num_queues = xn_num_queues; 54796375eacSRoger Pau Monné if (num_queues > max_queues) 54896375eacSRoger Pau Monné num_queues = max_queues; 54996375eacSRoger Pau Monné 55096375eacSRoger Pau Monné err = setup_device(dev, info, num_queues); 55196375eacSRoger Pau Monné if (err != 0) 55289e0f4d2SKip Macy goto out; 55389e0f4d2SKip Macy 55489e0f4d2SKip Macy again: 555ff662b5cSJustin T. Gibbs err = xs_transaction_start(&xst); 55696375eacSRoger Pau Monné if (err != 0) { 55789e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "starting transaction"); 55896375eacSRoger Pau Monné goto free; 55989e0f4d2SKip Macy } 56096375eacSRoger Pau Monné 56196375eacSRoger Pau Monné if (info->num_queues == 1) { 56296375eacSRoger Pau Monné err = write_queue_xenstore_keys(dev, &info->rxq[0], 56396375eacSRoger Pau Monné &info->txq[0], &xst, false); 56496375eacSRoger Pau Monné if (err != 0) 56596375eacSRoger Pau Monné goto abort_transaction_no_def_error; 56696375eacSRoger Pau Monné } else { 56796375eacSRoger Pau Monné err = xs_printf(xst, node, "multi-queue-num-queues", 56896375eacSRoger Pau Monné "%u", info->num_queues); 56996375eacSRoger Pau Monné if (err != 0) { 57096375eacSRoger Pau Monné message = "writing multi-queue-num-queues"; 57189e0f4d2SKip Macy goto abort_transaction; 57289e0f4d2SKip Macy } 57396375eacSRoger Pau Monné 57496375eacSRoger Pau Monné for (i = 0; i < info->num_queues; i++) { 57596375eacSRoger Pau Monné err = write_queue_xenstore_keys(dev, &info->rxq[i], 57696375eacSRoger Pau Monné &info->txq[i], &xst, true); 57796375eacSRoger Pau Monné if (err != 0) 57896375eacSRoger Pau Monné goto abort_transaction_no_def_error; 57989e0f4d2SKip Macy } 58089e0f4d2SKip Macy } 58196375eacSRoger Pau Monné 582d0f3a8b9SRoger Pau Monné err = xs_printf(xst, node, "request-rx-copy", "%u", 1); 58396375eacSRoger Pau Monné if (err != 0) { 58489e0f4d2SKip Macy message = "writing request-rx-copy"; 58589e0f4d2SKip Macy goto abort_transaction; 58689e0f4d2SKip Macy } 587ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-rx-notify", "%d", 1); 58896375eacSRoger Pau Monné if (err != 0) { 58989e0f4d2SKip Macy message = "writing feature-rx-notify"; 59089e0f4d2SKip Macy goto abort_transaction; 59189e0f4d2SKip Macy } 592ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-sg", "%d", 1); 59396375eacSRoger Pau Monné if (err != 0) { 59489e0f4d2SKip Macy message = "writing feature-sg"; 59589e0f4d2SKip Macy goto abort_transaction; 59689e0f4d2SKip Macy } 597ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-gso-tcpv4", "%d", 1); 59896375eacSRoger Pau Monné if (err != 0) { 59989e0f4d2SKip Macy message = "writing feature-gso-tcpv4"; 60089e0f4d2SKip Macy goto abort_transaction; 60189e0f4d2SKip Macy } 60289e0f4d2SKip Macy 603ff662b5cSJustin T. Gibbs err = xs_transaction_end(xst, 0); 60496375eacSRoger Pau Monné if (err != 0) { 60589e0f4d2SKip Macy if (err == EAGAIN) 60689e0f4d2SKip Macy goto again; 60789e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "completing transaction"); 60896375eacSRoger Pau Monné goto free; 60989e0f4d2SKip Macy } 61089e0f4d2SKip Macy 61189e0f4d2SKip Macy return 0; 61289e0f4d2SKip Macy 61389e0f4d2SKip Macy abort_transaction: 61489e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "%s", message); 61596375eacSRoger Pau Monné abort_transaction_no_def_error: 61696375eacSRoger Pau Monné xs_transaction_end(xst, 1); 61796375eacSRoger Pau Monné free: 61889e0f4d2SKip Macy netif_free(info); 61989e0f4d2SKip Macy out: 62096375eacSRoger Pau Monné return (err); 62196375eacSRoger Pau Monné } 62296375eacSRoger Pau Monné 62396375eacSRoger Pau Monné static void 62496375eacSRoger Pau Monné xn_rxq_tq_intr(void *xrxq, int pending) 62596375eacSRoger Pau Monné { 62696375eacSRoger Pau Monné struct netfront_rxq *rxq = xrxq; 62796375eacSRoger Pau Monné 62896375eacSRoger Pau Monné XN_RX_LOCK(rxq); 62996375eacSRoger Pau Monné xn_rxeof(rxq); 63096375eacSRoger Pau Monné XN_RX_UNLOCK(rxq); 63196375eacSRoger Pau Monné } 63296375eacSRoger Pau Monné 63396375eacSRoger Pau Monné static void 63496375eacSRoger Pau Monné xn_txq_start(struct netfront_txq *txq) 63596375eacSRoger Pau Monné { 63696375eacSRoger Pau Monné struct netfront_info *np = txq->info; 63796375eacSRoger Pau Monné struct ifnet *ifp = np->xn_ifp; 63896375eacSRoger Pau Monné 63996375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 64096375eacSRoger Pau Monné if (!drbr_empty(ifp, txq->br)) 64196375eacSRoger Pau Monné xn_txq_mq_start_locked(txq, NULL); 64296375eacSRoger Pau Monné } 64396375eacSRoger Pau Monné 64496375eacSRoger Pau Monné static void 64596375eacSRoger Pau Monné xn_txq_tq_intr(void *xtxq, int pending) 64696375eacSRoger Pau Monné { 64796375eacSRoger Pau Monné struct netfront_txq *txq = xtxq; 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); 67296375eacSRoger Pau Monné gnttab_end_foreign_access_ref(rxq->ring_ref); 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é 685*2568ee67SRoger Pau Monné callout_drain(&rxq->rx_refill); 68696375eacSRoger Pau Monné free(rxq->ring.sring, M_DEVBUF); 68796375eacSRoger Pau Monné taskqueue_drain_all(rxq->tq); 68896375eacSRoger Pau Monné taskqueue_free(rxq->tq); 68996375eacSRoger Pau Monné } 69096375eacSRoger Pau Monné 69196375eacSRoger Pau Monné static void 69296375eacSRoger Pau Monné destroy_rxqs(struct netfront_info *np) 69396375eacSRoger Pau Monné { 69496375eacSRoger Pau Monné int i; 69596375eacSRoger Pau Monné 69696375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 69796375eacSRoger Pau Monné destroy_rxq(&np->rxq[i]); 69896375eacSRoger Pau Monné 69996375eacSRoger Pau Monné free(np->rxq, M_DEVBUF); 70096375eacSRoger Pau Monné np->rxq = NULL; 70189e0f4d2SKip Macy } 70289e0f4d2SKip Macy 70389e0f4d2SKip Macy static int 70496375eacSRoger Pau Monné setup_rxqs(device_t dev, struct netfront_info *info, 70596375eacSRoger Pau Monné unsigned long num_queues) 70689e0f4d2SKip Macy { 70796375eacSRoger Pau Monné int q, i; 7083a6d1fcfSKip Macy int error; 70996375eacSRoger Pau Monné netif_rx_sring_t *rxs; 71096375eacSRoger Pau Monné struct netfront_rxq *rxq; 71189e0f4d2SKip Macy 71296375eacSRoger Pau Monné info->rxq = malloc(sizeof(struct netfront_rxq) * num_queues, 71396375eacSRoger Pau Monné M_DEVBUF, M_WAITOK|M_ZERO); 71489e0f4d2SKip Macy 71596375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) { 71696375eacSRoger Pau Monné rxq = &info->rxq[q]; 71796375eacSRoger Pau Monné 71896375eacSRoger Pau Monné rxq->id = q; 71996375eacSRoger Pau Monné rxq->info = info; 72096375eacSRoger Pau Monné rxq->ring_ref = GRANT_REF_INVALID; 72196375eacSRoger Pau Monné rxq->ring.sring = NULL; 72296375eacSRoger Pau Monné snprintf(rxq->name, XN_QUEUE_NAME_LEN, "xnrx_%u", q); 72396375eacSRoger Pau Monné mtx_init(&rxq->lock, rxq->name, "netfront receive lock", 72496375eacSRoger Pau Monné MTX_DEF); 72596375eacSRoger Pau Monné 72696375eacSRoger Pau Monné for (i = 0; i <= NET_RX_RING_SIZE; i++) { 72796375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 72896375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 72996375eacSRoger Pau Monné } 73096375eacSRoger Pau Monné 73196375eacSRoger Pau Monné /* Start resources allocation */ 73296375eacSRoger Pau Monné 733*2568ee67SRoger Pau Monné if (gnttab_alloc_grant_references(NET_RX_RING_SIZE, 73496375eacSRoger Pau Monné &rxq->gref_head) != 0) { 73596375eacSRoger Pau Monné device_printf(dev, "allocating rx gref"); 7363a6d1fcfSKip Macy error = ENOMEM; 73789e0f4d2SKip Macy goto fail; 73889e0f4d2SKip Macy } 73989e0f4d2SKip Macy 74096375eacSRoger Pau Monné rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, 74196375eacSRoger Pau Monné M_WAITOK|M_ZERO); 74289e0f4d2SKip Macy SHARED_RING_INIT(rxs); 74396375eacSRoger Pau Monné FRONT_RING_INIT(&rxq->ring, rxs, PAGE_SIZE); 74489e0f4d2SKip Macy 74596375eacSRoger Pau Monné error = xenbus_grant_ring(dev, virt_to_mfn(rxs), 74696375eacSRoger Pau Monné &rxq->ring_ref); 74796375eacSRoger Pau Monné if (error != 0) { 74896375eacSRoger Pau Monné device_printf(dev, "granting rx ring page"); 74996375eacSRoger Pau Monné goto fail_grant_ring; 75096375eacSRoger Pau Monné } 75189e0f4d2SKip Macy 75296375eacSRoger Pau Monné TASK_INIT(&rxq->intrtask, 0, xn_rxq_tq_intr, rxq); 75396375eacSRoger Pau Monné rxq->tq = taskqueue_create_fast(rxq->name, M_WAITOK, 75496375eacSRoger Pau Monné taskqueue_thread_enqueue, &rxq->tq); 75589e0f4d2SKip Macy 756*2568ee67SRoger Pau Monné callout_init(&rxq->rx_refill, 1); 757*2568ee67SRoger Pau Monné 75896375eacSRoger Pau Monné error = taskqueue_start_threads(&rxq->tq, 1, PI_NET, 75996375eacSRoger Pau Monné "%s rxq %d", device_get_nameunit(dev), rxq->id); 76096375eacSRoger Pau Monné if (error != 0) { 76196375eacSRoger Pau Monné device_printf(dev, "failed to start rx taskq %d\n", 76296375eacSRoger Pau Monné rxq->id); 76396375eacSRoger Pau Monné goto fail_start_thread; 76496375eacSRoger Pau Monné } 76589e0f4d2SKip Macy } 76689e0f4d2SKip Macy 7673a6d1fcfSKip Macy return (0); 76889e0f4d2SKip Macy 76996375eacSRoger Pau Monné fail_start_thread: 77096375eacSRoger Pau Monné gnttab_end_foreign_access_ref(rxq->ring_ref); 77196375eacSRoger Pau Monné taskqueue_drain_all(rxq->tq); 77296375eacSRoger Pau Monné taskqueue_free(rxq->tq); 77396375eacSRoger Pau Monné fail_grant_ring: 77496375eacSRoger Pau Monné gnttab_free_grant_references(rxq->gref_head); 77596375eacSRoger Pau Monné free(rxq->ring.sring, M_DEVBUF); 77689e0f4d2SKip Macy fail: 77796375eacSRoger Pau Monné for (; q >= 0; q--) { 77896375eacSRoger Pau Monné disconnect_rxq(&info->rxq[q]); 77996375eacSRoger Pau Monné destroy_rxq(&info->rxq[q]); 78096375eacSRoger Pau Monné } 78196375eacSRoger Pau Monné 78296375eacSRoger Pau Monné free(info->rxq, M_DEVBUF); 78396375eacSRoger Pau Monné return (error); 78496375eacSRoger Pau Monné } 78596375eacSRoger Pau Monné 78696375eacSRoger Pau Monné static void 78796375eacSRoger Pau Monné disconnect_txq(struct netfront_txq *txq) 78896375eacSRoger Pau Monné { 78996375eacSRoger Pau Monné 79096375eacSRoger Pau Monné xn_release_tx_bufs(txq); 79196375eacSRoger Pau Monné gnttab_free_grant_references(txq->gref_head); 79296375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->ring_ref); 79396375eacSRoger Pau Monné xen_intr_unbind(&txq->xen_intr_handle); 79496375eacSRoger Pau Monné } 79596375eacSRoger Pau Monné 79696375eacSRoger Pau Monné static void 79796375eacSRoger Pau Monné destroy_txq(struct netfront_txq *txq) 79896375eacSRoger Pau Monné { 79996375eacSRoger Pau Monné 80096375eacSRoger Pau Monné free(txq->ring.sring, M_DEVBUF); 80196375eacSRoger Pau Monné buf_ring_free(txq->br, M_DEVBUF); 80296375eacSRoger Pau Monné taskqueue_drain_all(txq->tq); 80396375eacSRoger Pau Monné taskqueue_free(txq->tq); 80496375eacSRoger Pau Monné } 80596375eacSRoger Pau Monné 80696375eacSRoger Pau Monné static void 80796375eacSRoger Pau Monné destroy_txqs(struct netfront_info *np) 80896375eacSRoger Pau Monné { 80996375eacSRoger Pau Monné int i; 81096375eacSRoger Pau Monné 81196375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 81296375eacSRoger Pau Monné destroy_txq(&np->txq[i]); 81396375eacSRoger Pau Monné 81496375eacSRoger Pau Monné free(np->txq, M_DEVBUF); 81596375eacSRoger Pau Monné np->txq = NULL; 81696375eacSRoger Pau Monné } 81796375eacSRoger Pau Monné 81896375eacSRoger Pau Monné static int 81996375eacSRoger Pau Monné setup_txqs(device_t dev, struct netfront_info *info, 82096375eacSRoger Pau Monné unsigned long num_queues) 82196375eacSRoger Pau Monné { 82296375eacSRoger Pau Monné int q, i; 82396375eacSRoger Pau Monné int error; 82496375eacSRoger Pau Monné netif_tx_sring_t *txs; 82596375eacSRoger Pau Monné struct netfront_txq *txq; 82696375eacSRoger Pau Monné 82796375eacSRoger Pau Monné info->txq = malloc(sizeof(struct netfront_txq) * num_queues, 82896375eacSRoger Pau Monné M_DEVBUF, M_WAITOK|M_ZERO); 82996375eacSRoger Pau Monné 83096375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) { 83196375eacSRoger Pau Monné txq = &info->txq[q]; 83296375eacSRoger Pau Monné 83396375eacSRoger Pau Monné txq->id = q; 83496375eacSRoger Pau Monné txq->info = info; 83596375eacSRoger Pau Monné 83696375eacSRoger Pau Monné txq->ring_ref = GRANT_REF_INVALID; 83796375eacSRoger Pau Monné txq->ring.sring = NULL; 83896375eacSRoger Pau Monné 83996375eacSRoger Pau Monné snprintf(txq->name, XN_QUEUE_NAME_LEN, "xntx_%u", q); 84096375eacSRoger Pau Monné 84196375eacSRoger Pau Monné mtx_init(&txq->lock, txq->name, "netfront transmit lock", 84296375eacSRoger Pau Monné MTX_DEF); 84396375eacSRoger Pau Monné 84496375eacSRoger Pau Monné for (i = 0; i <= NET_TX_RING_SIZE; i++) { 84596375eacSRoger Pau Monné txq->mbufs[i] = (void *) ((u_long) i+1); 84696375eacSRoger Pau Monné txq->grant_ref[i] = GRANT_REF_INVALID; 84796375eacSRoger Pau Monné } 84896375eacSRoger Pau Monné txq->mbufs[NET_TX_RING_SIZE] = (void *)0; 84996375eacSRoger Pau Monné 85096375eacSRoger Pau Monné /* Start resources allocation. */ 85196375eacSRoger Pau Monné 85296375eacSRoger Pau Monné if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, 85396375eacSRoger Pau Monné &txq->gref_head) != 0) { 85496375eacSRoger Pau Monné device_printf(dev, "failed to allocate tx grant refs\n"); 85596375eacSRoger Pau Monné error = ENOMEM; 85696375eacSRoger Pau Monné goto fail; 85796375eacSRoger Pau Monné } 85896375eacSRoger Pau Monné 85996375eacSRoger Pau Monné txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, 86096375eacSRoger Pau Monné M_WAITOK|M_ZERO); 86196375eacSRoger Pau Monné SHARED_RING_INIT(txs); 86296375eacSRoger Pau Monné FRONT_RING_INIT(&txq->ring, txs, PAGE_SIZE); 86396375eacSRoger Pau Monné 86496375eacSRoger Pau Monné error = xenbus_grant_ring(dev, virt_to_mfn(txs), 86596375eacSRoger Pau Monné &txq->ring_ref); 86696375eacSRoger Pau Monné if (error != 0) { 86796375eacSRoger Pau Monné device_printf(dev, "failed to grant tx ring\n"); 86896375eacSRoger Pau Monné goto fail_grant_ring; 86996375eacSRoger Pau Monné } 87096375eacSRoger Pau Monné 87196375eacSRoger Pau Monné txq->br = buf_ring_alloc(NET_TX_RING_SIZE, M_DEVBUF, 87296375eacSRoger Pau Monné M_WAITOK, &txq->lock); 87396375eacSRoger Pau Monné TASK_INIT(&txq->defrtask, 0, xn_txq_tq_deferred, txq); 87496375eacSRoger Pau Monné TASK_INIT(&txq->intrtask, 0, xn_txq_tq_intr, txq); 87596375eacSRoger Pau Monné 87696375eacSRoger Pau Monné txq->tq = taskqueue_create_fast(txq->name, M_WAITOK, 87796375eacSRoger Pau Monné taskqueue_thread_enqueue, &txq->tq); 87896375eacSRoger Pau Monné 87996375eacSRoger Pau Monné error = taskqueue_start_threads(&txq->tq, 1, PI_NET, 88096375eacSRoger Pau Monné "%s txq %d", device_get_nameunit(dev), txq->id); 88196375eacSRoger Pau Monné if (error != 0) { 88296375eacSRoger Pau Monné device_printf(dev, "failed to start tx taskq %d\n", 88396375eacSRoger Pau Monné txq->id); 88496375eacSRoger Pau Monné goto fail_start_thread; 88596375eacSRoger Pau Monné } 88696375eacSRoger Pau Monné 88796375eacSRoger Pau Monné error = xen_intr_alloc_and_bind_local_port(dev, 88896375eacSRoger Pau Monné xenbus_get_otherend_id(dev), xn_intr, /* handler */ NULL, 88996375eacSRoger Pau Monné &info->txq[q], 89096375eacSRoger Pau Monné INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY, 89196375eacSRoger Pau Monné &txq->xen_intr_handle); 89296375eacSRoger Pau Monné 89396375eacSRoger Pau Monné if (error != 0) { 89496375eacSRoger Pau Monné device_printf(dev, "xen_intr_alloc_and_bind_local_port failed\n"); 89596375eacSRoger Pau Monné goto fail_bind_port; 89696375eacSRoger Pau Monné } 89796375eacSRoger Pau Monné } 89896375eacSRoger Pau Monné 89996375eacSRoger Pau Monné return (0); 90096375eacSRoger Pau Monné 90196375eacSRoger Pau Monné fail_bind_port: 90296375eacSRoger Pau Monné taskqueue_drain_all(txq->tq); 90396375eacSRoger Pau Monné fail_start_thread: 90496375eacSRoger Pau Monné buf_ring_free(txq->br, M_DEVBUF); 90596375eacSRoger Pau Monné taskqueue_free(txq->tq); 906d4dae2b1SRoger Pau Monné gnttab_end_foreign_access_ref(txq->ring_ref); 90796375eacSRoger Pau Monné fail_grant_ring: 90896375eacSRoger Pau Monné gnttab_free_grant_references(txq->gref_head); 90996375eacSRoger Pau Monné free(txq->ring.sring, M_DEVBUF); 91096375eacSRoger Pau Monné fail: 91196375eacSRoger Pau Monné for (; q >= 0; q--) { 91296375eacSRoger Pau Monné disconnect_txq(&info->txq[q]); 91396375eacSRoger Pau Monné destroy_txq(&info->txq[q]); 91496375eacSRoger Pau Monné } 91596375eacSRoger Pau Monné 91696375eacSRoger Pau Monné free(info->txq, M_DEVBUF); 91796375eacSRoger Pau Monné return (error); 91896375eacSRoger Pau Monné } 91996375eacSRoger Pau Monné 92096375eacSRoger Pau Monné static int 92196375eacSRoger Pau Monné setup_device(device_t dev, struct netfront_info *info, 92296375eacSRoger Pau Monné unsigned long num_queues) 92396375eacSRoger Pau Monné { 92496375eacSRoger Pau Monné int error; 92596375eacSRoger Pau Monné int q; 92696375eacSRoger Pau Monné 92796375eacSRoger Pau Monné if (info->txq) 92896375eacSRoger Pau Monné destroy_txqs(info); 92996375eacSRoger Pau Monné 93096375eacSRoger Pau Monné if (info->rxq) 93196375eacSRoger Pau Monné destroy_rxqs(info); 93296375eacSRoger Pau Monné 93396375eacSRoger Pau Monné info->num_queues = 0; 93496375eacSRoger Pau Monné 93596375eacSRoger Pau Monné error = setup_rxqs(dev, info, num_queues); 93696375eacSRoger Pau Monné if (error != 0) 93796375eacSRoger Pau Monné goto out; 93896375eacSRoger Pau Monné error = setup_txqs(dev, info, num_queues); 93996375eacSRoger Pau Monné if (error != 0) 94096375eacSRoger Pau Monné goto out; 94196375eacSRoger Pau Monné 94296375eacSRoger Pau Monné info->num_queues = num_queues; 94396375eacSRoger Pau Monné 94496375eacSRoger Pau Monné /* No split event channel at the moment. */ 94596375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) 94696375eacSRoger Pau Monné info->rxq[q].xen_intr_handle = info->txq[q].xen_intr_handle; 94796375eacSRoger Pau Monné 94896375eacSRoger Pau Monné return (0); 94996375eacSRoger Pau Monné 95096375eacSRoger Pau Monné out: 95196375eacSRoger Pau Monné KASSERT(error != 0, ("Error path taken without providing an error code")); 9523a6d1fcfSKip Macy return (error); 95389e0f4d2SKip Macy } 95489e0f4d2SKip Macy 955a0ae8f04SBjoern A. Zeeb #ifdef INET 95689e0f4d2SKip Macy /** 95712678024SDoug Rabson * If this interface has an ipv4 address, send an arp for it. This 95812678024SDoug Rabson * helps to get the network going again after migrating hosts. 95912678024SDoug Rabson */ 96012678024SDoug Rabson static void 96112678024SDoug Rabson netfront_send_fake_arp(device_t dev, struct netfront_info *info) 96212678024SDoug Rabson { 96312678024SDoug Rabson struct ifnet *ifp; 96412678024SDoug Rabson struct ifaddr *ifa; 96512678024SDoug Rabson 96612678024SDoug Rabson ifp = info->xn_ifp; 96712678024SDoug Rabson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 96812678024SDoug Rabson if (ifa->ifa_addr->sa_family == AF_INET) { 96912678024SDoug Rabson arp_ifinit(ifp, ifa); 97012678024SDoug Rabson } 97112678024SDoug Rabson } 97212678024SDoug Rabson } 973a0ae8f04SBjoern A. Zeeb #endif 97412678024SDoug Rabson 97512678024SDoug Rabson /** 97689e0f4d2SKip Macy * Callback received when the backend's state changes. 97789e0f4d2SKip Macy */ 978283d6f72SJustin T. Gibbs static void 97923dc5621SKip Macy netfront_backend_changed(device_t dev, XenbusState newstate) 98089e0f4d2SKip Macy { 98123dc5621SKip Macy struct netfront_info *sc = device_get_softc(dev); 98289e0f4d2SKip Macy 98323dc5621SKip Macy DPRINTK("newstate=%d\n", newstate); 98489e0f4d2SKip Macy 98523dc5621SKip Macy switch (newstate) { 98689e0f4d2SKip Macy case XenbusStateInitialising: 98789e0f4d2SKip Macy case XenbusStateInitialised: 98889e0f4d2SKip Macy case XenbusStateUnknown: 98989e0f4d2SKip Macy case XenbusStateClosed: 990920ba15bSKip Macy case XenbusStateReconfigured: 991920ba15bSKip Macy case XenbusStateReconfiguring: 99289e0f4d2SKip Macy break; 99389e0f4d2SKip Macy case XenbusStateInitWait: 99423dc5621SKip Macy if (xenbus_get_state(dev) != XenbusStateInitialising) 99589e0f4d2SKip Macy break; 99696375eacSRoger Pau Monné if (xn_connect(sc) != 0) 99789e0f4d2SKip Macy break; 99823dc5621SKip Macy xenbus_set_state(dev, XenbusStateConnected); 99923dc5621SKip Macy break; 100089e0f4d2SKip Macy case XenbusStateClosing: 100123dc5621SKip Macy xenbus_set_state(dev, XenbusStateClosed); 100289e0f4d2SKip Macy break; 1003dbf82bdeSRoger Pau Monné case XenbusStateConnected: 1004dbf82bdeSRoger Pau Monné #ifdef INET 1005dbf82bdeSRoger Pau Monné netfront_send_fake_arp(dev, sc); 1006dbf82bdeSRoger Pau Monné #endif 1007dbf82bdeSRoger Pau Monné break; 100889e0f4d2SKip Macy } 100989e0f4d2SKip Macy } 101089e0f4d2SKip Macy 1011931eeffaSKenneth D. Merry /** 1012931eeffaSKenneth D. Merry * \brief Verify that there is sufficient space in the Tx ring 1013931eeffaSKenneth D. Merry * buffer for a maximally sized request to be enqueued. 1014c099cafaSAdrian Chadd * 1015931eeffaSKenneth D. Merry * A transmit request requires a transmit descriptor for each packet 1016931eeffaSKenneth D. Merry * fragment, plus up to 2 entries for "options" (e.g. TSO). 1017c099cafaSAdrian Chadd */ 101889e0f4d2SKip Macy static inline int 101996375eacSRoger Pau Monné xn_tx_slot_available(struct netfront_txq *txq) 102089e0f4d2SKip Macy { 102196375eacSRoger Pau Monné 102296375eacSRoger Pau Monné return (RING_FREE_REQUESTS(&txq->ring) > (MAX_TX_REQ_FRAGS + 2)); 102389e0f4d2SKip Macy } 1024931eeffaSKenneth D. Merry 102589e0f4d2SKip Macy static void 102696375eacSRoger Pau Monné xn_release_tx_bufs(struct netfront_txq *txq) 102789e0f4d2SKip Macy { 102889e0f4d2SKip Macy int i; 102989e0f4d2SKip Macy 103089e0f4d2SKip Macy for (i = 1; i <= NET_TX_RING_SIZE; i++) { 1031931eeffaSKenneth D. Merry struct mbuf *m; 103289e0f4d2SKip Macy 103396375eacSRoger Pau Monné m = txq->mbufs[i]; 1034931eeffaSKenneth D. Merry 1035931eeffaSKenneth D. Merry /* 1036931eeffaSKenneth D. Merry * We assume that no kernel addresses are 1037931eeffaSKenneth D. Merry * less than NET_TX_RING_SIZE. Any entry 1038931eeffaSKenneth D. Merry * in the table that is below this number 1039931eeffaSKenneth D. Merry * must be an index from free-list tracking. 1040931eeffaSKenneth D. Merry */ 1041931eeffaSKenneth D. Merry if (((uintptr_t)m) <= NET_TX_RING_SIZE) 104289e0f4d2SKip Macy continue; 104396375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->grant_ref[i]); 104496375eacSRoger Pau Monné gnttab_release_grant_reference(&txq->gref_head, 104596375eacSRoger Pau Monné txq->grant_ref[i]); 104696375eacSRoger Pau Monné txq->grant_ref[i] = GRANT_REF_INVALID; 104796375eacSRoger Pau Monné add_id_to_freelist(txq->mbufs, i); 104896375eacSRoger Pau Monné txq->mbufs_cnt--; 104996375eacSRoger Pau Monné if (txq->mbufs_cnt < 0) { 10506f9767acSMarius Strobl panic("%s: tx_chain_cnt must be >= 0", __func__); 1051a4ec37f5SAdrian Chadd } 1052cf9c09e1SJustin T. Gibbs m_free(m); 105389e0f4d2SKip Macy } 105489e0f4d2SKip Macy } 105589e0f4d2SKip Macy 1056*2568ee67SRoger Pau Monné static struct mbuf * 1057*2568ee67SRoger Pau Monné xn_alloc_one_rx_buffer(struct netfront_rxq *rxq) 1058*2568ee67SRoger Pau Monné { 1059*2568ee67SRoger Pau Monné struct mbuf *m; 1060*2568ee67SRoger Pau Monné 1061*2568ee67SRoger Pau Monné m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 1062*2568ee67SRoger Pau Monné if (m == NULL) 1063*2568ee67SRoger Pau Monné return NULL; 1064*2568ee67SRoger Pau Monné m->m_len = m->m_pkthdr.len = MJUMPAGESIZE; 1065*2568ee67SRoger Pau Monné 1066*2568ee67SRoger Pau Monné return (m); 1067*2568ee67SRoger Pau Monné } 1068*2568ee67SRoger Pau Monné 106989e0f4d2SKip Macy static void 107096375eacSRoger Pau Monné xn_alloc_rx_buffers(struct netfront_rxq *rxq) 107189e0f4d2SKip Macy { 107289e0f4d2SKip Macy RING_IDX req_prod; 1073*2568ee67SRoger Pau Monné int notify; 1074*2568ee67SRoger Pau Monné 1075*2568ee67SRoger Pau Monné XN_RX_LOCK_ASSERT(rxq); 1076*2568ee67SRoger Pau Monné 1077*2568ee67SRoger Pau Monné if (__predict_false(rxq->info->carrier == 0)) 1078*2568ee67SRoger Pau Monné return; 1079*2568ee67SRoger Pau Monné 1080*2568ee67SRoger Pau Monné for (req_prod = rxq->ring.req_prod_pvt; 1081*2568ee67SRoger Pau Monné req_prod - rxq->ring.rsp_cons < NET_RX_RING_SIZE; 1082*2568ee67SRoger Pau Monné req_prod++) { 1083*2568ee67SRoger Pau Monné struct mbuf *m; 1084*2568ee67SRoger Pau Monné unsigned short id; 108589e0f4d2SKip Macy grant_ref_t ref; 1086*2568ee67SRoger Pau Monné struct netif_rx_request *req; 1087*2568ee67SRoger Pau Monné unsigned long pfn; 108889e0f4d2SKip Macy 1089*2568ee67SRoger Pau Monné m = xn_alloc_one_rx_buffer(rxq); 1090*2568ee67SRoger Pau Monné if (m == NULL) 109189e0f4d2SKip Macy break; 109289e0f4d2SKip Macy 1093*2568ee67SRoger Pau Monné id = xn_rxidx(req_prod); 109489e0f4d2SKip Macy 109596375eacSRoger Pau Monné KASSERT(rxq->mbufs[id] == NULL, ("non-NULL xn_rx_chain")); 1096*2568ee67SRoger Pau Monné rxq->mbufs[id] = m; 109789e0f4d2SKip Macy 109896375eacSRoger Pau Monné ref = gnttab_claim_grant_reference(&rxq->gref_head); 1099ff662b5cSJustin T. Gibbs KASSERT(ref != GNTTAB_LIST_END, 1100ff662b5cSJustin T. Gibbs ("reserved grant references exhuasted")); 110196375eacSRoger Pau Monné rxq->grant_ref[id] = ref; 110289e0f4d2SKip Macy 1103*2568ee67SRoger Pau Monné pfn = atop(vtophys(mtod(m, vm_offset_t))); 1104*2568ee67SRoger Pau Monné req = RING_GET_REQUEST(&rxq->ring, req_prod); 110589e0f4d2SKip Macy 1106*2568ee67SRoger Pau Monné gnttab_grant_foreign_access_ref(ref, 1107*2568ee67SRoger Pau Monné xenbus_get_otherend_id(rxq->info->xbdev), pfn, 0); 110889e0f4d2SKip Macy req->id = id; 110989e0f4d2SKip Macy req->gref = ref; 111089e0f4d2SKip Macy } 111189e0f4d2SKip Macy 1112*2568ee67SRoger Pau Monné rxq->ring.req_prod_pvt = req_prod; 111389e0f4d2SKip Macy 1114*2568ee67SRoger Pau Monné /* Not enough requests? Try again later. */ 1115*2568ee67SRoger Pau Monné if (req_prod - rxq->ring.rsp_cons < NET_RX_SLOTS_MIN) { 1116*2568ee67SRoger Pau Monné callout_reset(&rxq->rx_refill, hz/10, xn_alloc_rx_buffers_callout, 1117*2568ee67SRoger Pau Monné rxq); 1118*2568ee67SRoger Pau Monné return; 1119*2568ee67SRoger Pau Monné } 1120*2568ee67SRoger Pau Monné 1121*2568ee67SRoger Pau Monné wmb(); /* barrier so backend seens requests */ 1122*2568ee67SRoger Pau Monné 112396375eacSRoger Pau Monné RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&rxq->ring, notify); 112489e0f4d2SKip Macy if (notify) 112596375eacSRoger Pau Monné xen_intr_signal(rxq->xen_intr_handle); 112689e0f4d2SKip Macy } 112789e0f4d2SKip Macy 1128*2568ee67SRoger Pau Monné static void xn_alloc_rx_buffers_callout(void *arg) 1129*2568ee67SRoger Pau Monné { 1130*2568ee67SRoger Pau Monné struct netfront_rxq *rxq; 1131*2568ee67SRoger Pau Monné 1132*2568ee67SRoger Pau Monné rxq = (struct netfront_rxq *)arg; 1133*2568ee67SRoger Pau Monné XN_RX_LOCK(rxq); 1134*2568ee67SRoger Pau Monné xn_alloc_rx_buffers(rxq); 1135*2568ee67SRoger Pau Monné XN_RX_UNLOCK(rxq); 1136*2568ee67SRoger Pau Monné } 1137*2568ee67SRoger Pau Monné 113889e0f4d2SKip Macy static void 113996375eacSRoger Pau Monné xn_release_rx_bufs(struct netfront_rxq *rxq) 114096375eacSRoger Pau Monné { 114196375eacSRoger Pau Monné int i, ref; 114296375eacSRoger Pau Monné struct mbuf *m; 114396375eacSRoger Pau Monné 114496375eacSRoger Pau Monné for (i = 0; i < NET_RX_RING_SIZE; i++) { 114596375eacSRoger Pau Monné m = rxq->mbufs[i]; 114696375eacSRoger Pau Monné 114796375eacSRoger Pau Monné if (m == NULL) 114896375eacSRoger Pau Monné continue; 114996375eacSRoger Pau Monné 115096375eacSRoger Pau Monné ref = rxq->grant_ref[i]; 115196375eacSRoger Pau Monné if (ref == GRANT_REF_INVALID) 115296375eacSRoger Pau Monné continue; 115396375eacSRoger Pau Monné 115496375eacSRoger Pau Monné gnttab_end_foreign_access_ref(ref); 115596375eacSRoger Pau Monné gnttab_release_grant_reference(&rxq->gref_head, ref); 115696375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 115796375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 115896375eacSRoger Pau Monné m_freem(m); 115996375eacSRoger Pau Monné } 116096375eacSRoger Pau Monné } 116196375eacSRoger Pau Monné 116296375eacSRoger Pau Monné static void 116396375eacSRoger Pau Monné xn_rxeof(struct netfront_rxq *rxq) 116489e0f4d2SKip Macy { 116589e0f4d2SKip Macy struct ifnet *ifp; 116696375eacSRoger Pau Monné struct netfront_info *np = rxq->info; 11673778878dSRoger Pau Monné #if (defined(INET) || defined(INET6)) 116896375eacSRoger Pau Monné struct lro_ctrl *lro = &rxq->lro; 11693778878dSRoger Pau Monné #endif 117089e0f4d2SKip Macy struct netfront_rx_info rinfo; 117189e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo.rx; 117289e0f4d2SKip Macy struct netif_extra_info *extras = rinfo.extras; 117389e0f4d2SKip Macy RING_IDX i, rp; 117489e0f4d2SKip Macy struct mbuf *m; 117596375eacSRoger Pau Monné struct mbufq mbufq_rxq, mbufq_errq; 1176d0f3a8b9SRoger Pau Monné int err, work_to_do; 117789e0f4d2SKip Macy 117849906218SDoug Rabson do { 117996375eacSRoger Pau Monné XN_RX_LOCK_ASSERT(rxq); 118089e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 118189e0f4d2SKip Macy return; 118289e0f4d2SKip Macy 1183c578b6acSGleb Smirnoff /* XXX: there should be some sane limit. */ 118496375eacSRoger Pau Monné mbufq_init(&mbufq_errq, INT_MAX); 118596375eacSRoger Pau Monné mbufq_init(&mbufq_rxq, INT_MAX); 118689e0f4d2SKip Macy 118789e0f4d2SKip Macy ifp = np->xn_ifp; 118889e0f4d2SKip Macy 118996375eacSRoger Pau Monné rp = rxq->ring.sring->rsp_prod; 119089e0f4d2SKip Macy rmb(); /* Ensure we see queued responses up to 'rp'. */ 119189e0f4d2SKip Macy 119296375eacSRoger Pau Monné i = rxq->ring.rsp_cons; 119389e0f4d2SKip Macy while ((i != rp)) { 119496375eacSRoger Pau Monné memcpy(rx, RING_GET_RESPONSE(&rxq->ring, i), sizeof(*rx)); 119589e0f4d2SKip Macy memset(extras, 0, sizeof(rinfo.extras)); 119689e0f4d2SKip Macy 119783b92f6eSKip Macy m = NULL; 119896375eacSRoger Pau Monné err = xn_get_responses(rxq, &rinfo, rp, &i, &m); 119989e0f4d2SKip Macy 120076acc41fSJustin T. Gibbs if (__predict_false(err)) { 120183b92f6eSKip Macy if (m) 120296375eacSRoger Pau Monné (void )mbufq_enqueue(&mbufq_errq, m); 120396375eacSRoger Pau Monné rxq->stats.rx_errors++; 120489e0f4d2SKip Macy continue; 120589e0f4d2SKip Macy } 120689e0f4d2SKip Macy 120789e0f4d2SKip Macy m->m_pkthdr.rcvif = ifp; 120889e0f4d2SKip Macy if ( rx->flags & NETRXF_data_validated ) { 120989e0f4d2SKip Macy /* Tell the stack the checksums are okay */ 121089e0f4d2SKip Macy /* 121189e0f4d2SKip Macy * XXX this isn't necessarily the case - need to add 121289e0f4d2SKip Macy * check 121389e0f4d2SKip Macy */ 121489e0f4d2SKip Macy 121589e0f4d2SKip Macy m->m_pkthdr.csum_flags |= 121689e0f4d2SKip Macy (CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID 121789e0f4d2SKip Macy | CSUM_PSEUDO_HDR); 121889e0f4d2SKip Macy m->m_pkthdr.csum_data = 0xffff; 121989e0f4d2SKip Macy } 1220d9a66b6dSRoger Pau Monné if ((rx->flags & NETRXF_extra_info) != 0 && 1221d9a66b6dSRoger Pau Monné (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type == 1222d9a66b6dSRoger Pau Monné XEN_NETIF_EXTRA_TYPE_GSO)) { 1223d9a66b6dSRoger Pau Monné m->m_pkthdr.tso_segsz = 1224d9a66b6dSRoger Pau Monné extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].u.gso.size; 1225d9a66b6dSRoger Pau Monné m->m_pkthdr.csum_flags |= CSUM_TSO; 1226d9a66b6dSRoger Pau Monné } 122789e0f4d2SKip Macy 122896375eacSRoger Pau Monné rxq->stats.rx_packets++; 122996375eacSRoger Pau Monné rxq->stats.rx_bytes += m->m_pkthdr.len; 123089e0f4d2SKip Macy 123196375eacSRoger Pau Monné (void )mbufq_enqueue(&mbufq_rxq, m); 123296375eacSRoger Pau Monné rxq->ring.rsp_cons = i; 123389e0f4d2SKip Macy } 123489e0f4d2SKip Macy 123596375eacSRoger Pau Monné mbufq_drain(&mbufq_errq); 123689e0f4d2SKip Macy 123789e0f4d2SKip Macy /* 123889e0f4d2SKip Macy * Process all the mbufs after the remapping is complete. 123989e0f4d2SKip Macy * Break the mbuf chain first though. 124089e0f4d2SKip Macy */ 124196375eacSRoger Pau Monné while ((m = mbufq_dequeue(&mbufq_rxq)) != NULL) { 1242c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 124389e0f4d2SKip Macy 124496375eacSRoger Pau Monné /* XXX: Do we really need to drop the rx lock? */ 124596375eacSRoger Pau Monné XN_RX_UNLOCK(rxq); 124608c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 124712678024SDoug Rabson /* Use LRO if possible */ 124812678024SDoug Rabson if ((ifp->if_capenable & IFCAP_LRO) == 0 || 124912678024SDoug Rabson lro->lro_cnt == 0 || tcp_lro_rx(lro, m, 0)) { 125012678024SDoug Rabson /* 125112678024SDoug Rabson * If LRO fails, pass up to the stack 125212678024SDoug Rabson * directly. 125312678024SDoug Rabson */ 125489e0f4d2SKip Macy (*ifp->if_input)(ifp, m); 125512678024SDoug Rabson } 125612678024SDoug Rabson #else 125712678024SDoug Rabson (*ifp->if_input)(ifp, m); 125812678024SDoug Rabson #endif 125996375eacSRoger Pau Monné 126096375eacSRoger Pau Monné XN_RX_LOCK(rxq); 126189e0f4d2SKip Macy } 126289e0f4d2SKip Macy 126396375eacSRoger Pau Monné rxq->ring.rsp_cons = i; 126489e0f4d2SKip Macy 126508c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 126612678024SDoug Rabson /* 126712678024SDoug Rabson * Flush any outstanding LRO work 126812678024SDoug Rabson */ 12696dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro); 127012678024SDoug Rabson #endif 127112678024SDoug Rabson 127296375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 127389e0f4d2SKip Macy 127496375eacSRoger Pau Monné RING_FINAL_CHECK_FOR_RESPONSES(&rxq->ring, work_to_do); 127549906218SDoug Rabson } while (work_to_do); 127689e0f4d2SKip Macy } 127789e0f4d2SKip Macy 127889e0f4d2SKip Macy static void 127996375eacSRoger Pau Monné xn_txeof(struct netfront_txq *txq) 128089e0f4d2SKip Macy { 128189e0f4d2SKip Macy RING_IDX i, prod; 128289e0f4d2SKip Macy unsigned short id; 128389e0f4d2SKip Macy struct ifnet *ifp; 128412678024SDoug Rabson netif_tx_response_t *txr; 128589e0f4d2SKip Macy struct mbuf *m; 128696375eacSRoger Pau Monné struct netfront_info *np = txq->info; 128789e0f4d2SKip Macy 128896375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 128989e0f4d2SKip Macy 129089e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 129189e0f4d2SKip Macy return; 129289e0f4d2SKip Macy 129389e0f4d2SKip Macy ifp = np->xn_ifp; 129489e0f4d2SKip Macy 129589e0f4d2SKip Macy do { 129696375eacSRoger Pau Monné prod = txq->ring.sring->rsp_prod; 129789e0f4d2SKip Macy rmb(); /* Ensure we see responses up to 'rp'. */ 129889e0f4d2SKip Macy 129996375eacSRoger Pau Monné for (i = txq->ring.rsp_cons; i != prod; i++) { 130096375eacSRoger Pau Monné txr = RING_GET_RESPONSE(&txq->ring, i); 130112678024SDoug Rabson if (txr->status == NETIF_RSP_NULL) 130212678024SDoug Rabson continue; 130312678024SDoug Rabson 1304931eeffaSKenneth D. Merry if (txr->status != NETIF_RSP_OKAY) { 1305931eeffaSKenneth D. Merry printf("%s: WARNING: response is %d!\n", 1306931eeffaSKenneth D. Merry __func__, txr->status); 1307931eeffaSKenneth D. Merry } 130812678024SDoug Rabson id = txr->id; 130996375eacSRoger Pau Monné m = txq->mbufs[id]; 131096375eacSRoger Pau Monné KASSERT(m != NULL, ("mbuf not found in chain")); 1311931eeffaSKenneth D. Merry KASSERT((uintptr_t)m > NET_TX_RING_SIZE, 1312931eeffaSKenneth D. Merry ("mbuf already on the free list, but we're " 1313931eeffaSKenneth D. Merry "trying to free it again!")); 13142d8fae98SAdrian Chadd M_ASSERTVALID(m); 131589e0f4d2SKip Macy 131612678024SDoug Rabson /* 131712678024SDoug Rabson * Increment packet count if this is the last 131812678024SDoug Rabson * mbuf of the chain. 131912678024SDoug Rabson */ 132012678024SDoug Rabson if (!m->m_next) 1321c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 132276acc41fSJustin T. Gibbs if (__predict_false(gnttab_query_foreign_access( 132396375eacSRoger Pau Monné txq->grant_ref[id]) != 0)) { 13246f9767acSMarius Strobl panic("%s: grant id %u still in use by the " 13256f9767acSMarius Strobl "backend", __func__, id); 132689e0f4d2SKip Macy } 132796375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->grant_ref[id]); 132889e0f4d2SKip Macy gnttab_release_grant_reference( 132996375eacSRoger Pau Monné &txq->gref_head, txq->grant_ref[id]); 133096375eacSRoger Pau Monné txq->grant_ref[id] = GRANT_REF_INVALID; 133189e0f4d2SKip Macy 133296375eacSRoger Pau Monné txq->mbufs[id] = NULL; 133396375eacSRoger Pau Monné add_id_to_freelist(txq->mbufs, id); 133496375eacSRoger Pau Monné txq->mbufs_cnt--; 133512678024SDoug Rabson m_free(m); 133696375eacSRoger Pau Monné /* Only mark the txq active if we've freed up at least one slot to try */ 1337d76e4550SAdrian Chadd ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 133889e0f4d2SKip Macy } 133996375eacSRoger Pau Monné txq->ring.rsp_cons = prod; 134089e0f4d2SKip Macy 134189e0f4d2SKip Macy /* 134289e0f4d2SKip Macy * Set a new event, then check for race with update of 134389e0f4d2SKip Macy * tx_cons. Note that it is essential to schedule a 134489e0f4d2SKip Macy * callback, no matter how few buffers are pending. Even if 134589e0f4d2SKip Macy * there is space in the transmit ring, higher layers may 134689e0f4d2SKip Macy * be blocked because too much data is outstanding: in such 134789e0f4d2SKip Macy * cases notification from Xen is likely to be the only kick 134889e0f4d2SKip Macy * that we'll get. 134989e0f4d2SKip Macy */ 135096375eacSRoger Pau Monné txq->ring.sring->rsp_event = 135196375eacSRoger Pau Monné prod + ((txq->ring.sring->req_prod - prod) >> 1) + 1; 135289e0f4d2SKip Macy 135389e0f4d2SKip Macy mb(); 135496375eacSRoger Pau Monné } while (prod != txq->ring.sring->rsp_prod); 135589e0f4d2SKip Macy 135696375eacSRoger Pau Monné if (txq->full && 135796375eacSRoger Pau Monné ((txq->ring.sring->req_prod - prod) < NET_TX_RING_SIZE)) { 135896375eacSRoger Pau Monné txq->full = false; 135996375eacSRoger Pau Monné taskqueue_enqueue(txq->tq, &txq->intrtask); 136089e0f4d2SKip Macy } 136189e0f4d2SKip Macy } 136289e0f4d2SKip Macy 136396375eacSRoger Pau Monné 136496375eacSRoger Pau Monné static void 136596375eacSRoger Pau Monné xn_rxq_intr(void *xrxq) 136696375eacSRoger Pau Monné { 136796375eacSRoger Pau Monné struct netfront_rxq *rxq = xrxq; 136896375eacSRoger Pau Monné 1369cbc4d2dbSJohn Baldwin taskqueue_enqueue(rxq->tq, &rxq->intrtask); 137096375eacSRoger Pau Monné } 137196375eacSRoger Pau Monné 137289e0f4d2SKip Macy static void 137396375eacSRoger Pau Monné xn_txq_intr(void *xtxq) 137489e0f4d2SKip Macy { 137596375eacSRoger Pau Monné struct netfront_txq *txq = xtxq; 137689e0f4d2SKip Macy 1377cbc4d2dbSJohn Baldwin taskqueue_enqueue(txq->tq, &txq->intrtask); 137889e0f4d2SKip Macy } 137989e0f4d2SKip Macy 138089e0f4d2SKip Macy static int 138196375eacSRoger Pau Monné xn_intr(void *xsc) 138296375eacSRoger Pau Monné { 138396375eacSRoger Pau Monné struct netfront_txq *txq = xsc; 138496375eacSRoger Pau Monné struct netfront_info *np = txq->info; 138596375eacSRoger Pau Monné struct netfront_rxq *rxq = &np->rxq[txq->id]; 138696375eacSRoger Pau Monné 138796375eacSRoger Pau Monné /* kick both tx and rx */ 138896375eacSRoger Pau Monné xn_rxq_intr(rxq); 138996375eacSRoger Pau Monné xn_txq_intr(txq); 139096375eacSRoger Pau Monné 139196375eacSRoger Pau Monné return (FILTER_HANDLED); 139296375eacSRoger Pau Monné } 139396375eacSRoger Pau Monné 139496375eacSRoger Pau Monné static void 139596375eacSRoger Pau Monné xn_move_rx_slot(struct netfront_rxq *rxq, struct mbuf *m, 139696375eacSRoger Pau Monné grant_ref_t ref) 139796375eacSRoger Pau Monné { 139896375eacSRoger Pau Monné int new = xn_rxidx(rxq->ring.req_prod_pvt); 139996375eacSRoger Pau Monné 140096375eacSRoger Pau Monné KASSERT(rxq->mbufs[new] == NULL, ("mbufs != NULL")); 140196375eacSRoger Pau Monné rxq->mbufs[new] = m; 140296375eacSRoger Pau Monné rxq->grant_ref[new] = ref; 140396375eacSRoger Pau Monné RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->id = new; 140496375eacSRoger Pau Monné RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->gref = ref; 140596375eacSRoger Pau Monné rxq->ring.req_prod_pvt++; 140696375eacSRoger Pau Monné } 140796375eacSRoger Pau Monné 140896375eacSRoger Pau Monné static int 140996375eacSRoger Pau Monné xn_get_extras(struct netfront_rxq *rxq, 1410931eeffaSKenneth D. Merry struct netif_extra_info *extras, RING_IDX rp, RING_IDX *cons) 141189e0f4d2SKip Macy { 141289e0f4d2SKip Macy struct netif_extra_info *extra; 141389e0f4d2SKip Macy 141489e0f4d2SKip Macy int err = 0; 141589e0f4d2SKip Macy 141689e0f4d2SKip Macy do { 141789e0f4d2SKip Macy struct mbuf *m; 141889e0f4d2SKip Macy grant_ref_t ref; 141989e0f4d2SKip Macy 142076acc41fSJustin T. Gibbs if (__predict_false(*cons + 1 == rp)) { 1421931eeffaSKenneth D. Merry err = EINVAL; 142289e0f4d2SKip Macy break; 142389e0f4d2SKip Macy } 142489e0f4d2SKip Macy 142589e0f4d2SKip Macy extra = (struct netif_extra_info *) 142696375eacSRoger Pau Monné RING_GET_RESPONSE(&rxq->ring, ++(*cons)); 142789e0f4d2SKip Macy 142876acc41fSJustin T. Gibbs if (__predict_false(!extra->type || 142989e0f4d2SKip Macy extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { 1430931eeffaSKenneth D. Merry err = EINVAL; 143189e0f4d2SKip Macy } else { 143289e0f4d2SKip Macy memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); 143389e0f4d2SKip Macy } 143489e0f4d2SKip Macy 143596375eacSRoger Pau Monné m = xn_get_rx_mbuf(rxq, *cons); 143696375eacSRoger Pau Monné ref = xn_get_rx_ref(rxq, *cons); 143796375eacSRoger Pau Monné xn_move_rx_slot(rxq, m, ref); 143889e0f4d2SKip Macy } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); 143989e0f4d2SKip Macy 144089e0f4d2SKip Macy return err; 144189e0f4d2SKip Macy } 144289e0f4d2SKip Macy 144389e0f4d2SKip Macy static int 144496375eacSRoger Pau Monné xn_get_responses(struct netfront_rxq *rxq, 1445931eeffaSKenneth D. Merry struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, 1446d0f3a8b9SRoger Pau Monné struct mbuf **list) 144789e0f4d2SKip Macy { 144889e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo->rx; 144989e0f4d2SKip Macy struct netif_extra_info *extras = rinfo->extras; 145083b92f6eSKip Macy struct mbuf *m, *m0, *m_prev; 145196375eacSRoger Pau Monné grant_ref_t ref = xn_get_rx_ref(rxq, *cons); 1452931eeffaSKenneth D. Merry RING_IDX ref_cons = *cons; 145389e0f4d2SKip Macy int frags = 1; 145489e0f4d2SKip Macy int err = 0; 145589e0f4d2SKip Macy u_long ret; 145689e0f4d2SKip Macy 145796375eacSRoger Pau Monné m0 = m = m_prev = xn_get_rx_mbuf(rxq, *cons); 145883b92f6eSKip Macy 145989e0f4d2SKip Macy if (rx->flags & NETRXF_extra_info) { 146096375eacSRoger Pau Monné err = xn_get_extras(rxq, extras, rp, cons); 146189e0f4d2SKip Macy } 146289e0f4d2SKip Macy 146383b92f6eSKip Macy if (m0 != NULL) { 146483b92f6eSKip Macy m0->m_pkthdr.len = 0; 146583b92f6eSKip Macy m0->m_next = NULL; 146683b92f6eSKip Macy } 146783b92f6eSKip Macy 146889e0f4d2SKip Macy for (;;) { 146983b92f6eSKip Macy #if 0 1470227ca257SKip Macy DPRINTK("rx->status=%hd rx->offset=%hu frags=%u\n", 147183b92f6eSKip Macy rx->status, rx->offset, frags); 147283b92f6eSKip Macy #endif 147376acc41fSJustin T. Gibbs if (__predict_false(rx->status < 0 || 147489e0f4d2SKip Macy rx->offset + rx->status > PAGE_SIZE)) { 1475931eeffaSKenneth D. Merry 147696375eacSRoger Pau Monné xn_move_rx_slot(rxq, m, ref); 1477931eeffaSKenneth D. Merry if (m0 == m) 1478931eeffaSKenneth D. Merry m0 = NULL; 1479931eeffaSKenneth D. Merry m = NULL; 1480931eeffaSKenneth D. Merry err = EINVAL; 1481931eeffaSKenneth D. Merry goto next_skip_queue; 148289e0f4d2SKip Macy } 148389e0f4d2SKip Macy 148489e0f4d2SKip Macy /* 148589e0f4d2SKip Macy * This definitely indicates a bug, either in this driver or in 148689e0f4d2SKip Macy * the backend driver. In future this should flag the bad 148789e0f4d2SKip Macy * situation to the system controller to reboot the backed. 148889e0f4d2SKip Macy */ 1489ff662b5cSJustin T. Gibbs if (ref == GRANT_REF_INVALID) { 1490ff662b5cSJustin T. Gibbs printf("%s: Bad rx response id %d.\n", __func__, rx->id); 1491931eeffaSKenneth D. Merry err = EINVAL; 149289e0f4d2SKip Macy goto next; 149389e0f4d2SKip Macy } 149489e0f4d2SKip Macy 1495920ba15bSKip Macy ret = gnttab_end_foreign_access_ref(ref); 1496d0f3a8b9SRoger Pau Monné KASSERT(ret, ("Unable to end access to grant references")); 149789e0f4d2SKip Macy 149896375eacSRoger Pau Monné gnttab_release_grant_reference(&rxq->gref_head, ref); 149989e0f4d2SKip Macy 150089e0f4d2SKip Macy next: 15013a539122SAdrian Chadd if (m == NULL) 15023a539122SAdrian Chadd break; 15033a539122SAdrian Chadd 150483b92f6eSKip Macy m->m_len = rx->status; 150583b92f6eSKip Macy m->m_data += rx->offset; 150683b92f6eSKip Macy m0->m_pkthdr.len += rx->status; 150783b92f6eSKip Macy 1508931eeffaSKenneth D. Merry next_skip_queue: 150989e0f4d2SKip Macy if (!(rx->flags & NETRXF_more_data)) 151089e0f4d2SKip Macy break; 151189e0f4d2SKip Macy 1512931eeffaSKenneth D. Merry if (*cons + frags == rp) { 151389e0f4d2SKip Macy if (net_ratelimit()) 151489e0f4d2SKip Macy WPRINTK("Need more frags\n"); 1515931eeffaSKenneth D. Merry err = ENOENT; 1516931eeffaSKenneth D. Merry printf("%s: cons %u frags %u rp %u, not enough frags\n", 1517931eeffaSKenneth D. Merry __func__, *cons, frags, rp); 151889e0f4d2SKip Macy break; 151989e0f4d2SKip Macy } 1520931eeffaSKenneth D. Merry /* 1521931eeffaSKenneth D. Merry * Note that m can be NULL, if rx->status < 0 or if 1522931eeffaSKenneth D. Merry * rx->offset + rx->status > PAGE_SIZE above. 1523931eeffaSKenneth D. Merry */ 152483b92f6eSKip Macy m_prev = m; 152589e0f4d2SKip Macy 152696375eacSRoger Pau Monné rx = RING_GET_RESPONSE(&rxq->ring, *cons + frags); 152796375eacSRoger Pau Monné m = xn_get_rx_mbuf(rxq, *cons + frags); 152883b92f6eSKip Macy 1529931eeffaSKenneth D. Merry /* 1530931eeffaSKenneth D. Merry * m_prev == NULL can happen if rx->status < 0 or if 1531931eeffaSKenneth D. Merry * rx->offset + * rx->status > PAGE_SIZE above. 1532931eeffaSKenneth D. Merry */ 1533931eeffaSKenneth D. Merry if (m_prev != NULL) 153483b92f6eSKip Macy m_prev->m_next = m; 1535931eeffaSKenneth D. Merry 1536931eeffaSKenneth D. Merry /* 1537931eeffaSKenneth D. Merry * m0 can be NULL if rx->status < 0 or if * rx->offset + 1538931eeffaSKenneth D. Merry * rx->status > PAGE_SIZE above. 1539931eeffaSKenneth D. Merry */ 1540931eeffaSKenneth D. Merry if (m0 == NULL) 1541931eeffaSKenneth D. Merry m0 = m; 154283b92f6eSKip Macy m->m_next = NULL; 154396375eacSRoger Pau Monné ref = xn_get_rx_ref(rxq, *cons + frags); 1544931eeffaSKenneth D. Merry ref_cons = *cons + frags; 154589e0f4d2SKip Macy frags++; 154689e0f4d2SKip Macy } 154783b92f6eSKip Macy *list = m0; 1548931eeffaSKenneth D. Merry *cons += frags; 154989e0f4d2SKip Macy 15508577146eSJustin T. Gibbs return (err); 155189e0f4d2SKip Macy } 155289e0f4d2SKip Macy 1553931eeffaSKenneth D. Merry /** 1554931eeffaSKenneth D. Merry * \brief Count the number of fragments in an mbuf chain. 1555931eeffaSKenneth D. Merry * 1556931eeffaSKenneth D. Merry * Surprisingly, there isn't an M* macro for this. 1557c099cafaSAdrian Chadd */ 1558931eeffaSKenneth D. Merry static inline int 1559931eeffaSKenneth D. Merry xn_count_frags(struct mbuf *m) 1560931eeffaSKenneth D. Merry { 1561931eeffaSKenneth D. Merry int nfrags; 1562931eeffaSKenneth D. Merry 1563931eeffaSKenneth D. Merry for (nfrags = 0; m != NULL; m = m->m_next) 1564931eeffaSKenneth D. Merry nfrags++; 1565931eeffaSKenneth D. Merry 1566931eeffaSKenneth D. Merry return (nfrags); 156789e0f4d2SKip Macy } 156889e0f4d2SKip Macy 1569931eeffaSKenneth D. Merry /** 1570931eeffaSKenneth D. Merry * Given an mbuf chain, make sure we have enough room and then push 1571931eeffaSKenneth D. Merry * it onto the transmit ring. 1572931eeffaSKenneth D. Merry */ 1573931eeffaSKenneth D. Merry static int 157496375eacSRoger Pau Monné xn_assemble_tx_request(struct netfront_txq *txq, struct mbuf *m_head) 1575931eeffaSKenneth D. Merry { 1576931eeffaSKenneth D. Merry struct mbuf *m; 157796375eacSRoger Pau Monné struct netfront_info *np = txq->info; 157896375eacSRoger Pau Monné struct ifnet *ifp = np->xn_ifp; 1579931eeffaSKenneth D. Merry u_int nfrags; 1580931eeffaSKenneth D. Merry int otherend_id; 1581931eeffaSKenneth D. Merry 1582931eeffaSKenneth D. Merry /** 158312678024SDoug Rabson * Defragment the mbuf if necessary. 158412678024SDoug Rabson */ 1585931eeffaSKenneth D. Merry nfrags = xn_count_frags(m_head); 1586931eeffaSKenneth D. Merry 1587931eeffaSKenneth D. Merry /* 1588931eeffaSKenneth D. Merry * Check to see whether this request is longer than netback 1589931eeffaSKenneth D. Merry * can handle, and try to defrag it. 1590931eeffaSKenneth D. Merry */ 1591931eeffaSKenneth D. Merry /** 1592931eeffaSKenneth D. Merry * It is a bit lame, but the netback driver in Linux can't 1593931eeffaSKenneth D. Merry * deal with nfrags > MAX_TX_REQ_FRAGS, which is a quirk of 1594931eeffaSKenneth D. Merry * the Linux network stack. 1595931eeffaSKenneth D. Merry */ 159696375eacSRoger Pau Monné if (nfrags > np->maxfrags) { 1597c6499eccSGleb Smirnoff m = m_defrag(m_head, M_NOWAIT); 159812678024SDoug Rabson if (!m) { 1599931eeffaSKenneth D. Merry /* 1600931eeffaSKenneth D. Merry * Defrag failed, so free the mbuf and 1601931eeffaSKenneth D. Merry * therefore drop the packet. 1602931eeffaSKenneth D. Merry */ 160312678024SDoug Rabson m_freem(m_head); 1604931eeffaSKenneth D. Merry return (EMSGSIZE); 160512678024SDoug Rabson } 160612678024SDoug Rabson m_head = m; 160712678024SDoug Rabson } 160889e0f4d2SKip Macy 1609a4ec37f5SAdrian Chadd /* Determine how many fragments now exist */ 1610931eeffaSKenneth D. Merry nfrags = xn_count_frags(m_head); 1611a4ec37f5SAdrian Chadd 1612a4ec37f5SAdrian Chadd /* 1613931eeffaSKenneth D. Merry * Check to see whether the defragmented packet has too many 1614931eeffaSKenneth D. Merry * segments for the Linux netback driver. 1615a4ec37f5SAdrian Chadd */ 1616931eeffaSKenneth D. Merry /** 1617931eeffaSKenneth D. Merry * The FreeBSD TCP stack, with TSO enabled, can produce a chain 1618931eeffaSKenneth D. Merry * of mbufs longer than Linux can handle. Make sure we don't 1619931eeffaSKenneth D. Merry * pass a too-long chain over to the other side by dropping the 1620931eeffaSKenneth D. Merry * packet. It doesn't look like there is currently a way to 1621931eeffaSKenneth D. Merry * tell the TCP stack to generate a shorter chain of packets. 16223fb28bbbSAdrian Chadd */ 1623931eeffaSKenneth D. Merry if (nfrags > MAX_TX_REQ_FRAGS) { 1624ff662b5cSJustin T. Gibbs #ifdef DEBUG 1625ff662b5cSJustin T. Gibbs printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback " 1626ff662b5cSJustin T. Gibbs "won't be able to handle it, dropping\n", 1627ff662b5cSJustin T. Gibbs __func__, nfrags, MAX_TX_REQ_FRAGS); 1628ff662b5cSJustin T. Gibbs #endif 1629931eeffaSKenneth D. Merry m_freem(m_head); 1630931eeffaSKenneth D. Merry return (EMSGSIZE); 1631a4ec37f5SAdrian Chadd } 1632a4ec37f5SAdrian Chadd 16333fb28bbbSAdrian Chadd /* 1634931eeffaSKenneth D. Merry * This check should be redundant. We've already verified that we 1635931eeffaSKenneth D. Merry * have enough slots in the ring to handle a packet of maximum 1636931eeffaSKenneth D. Merry * size, and that our packet is less than the maximum size. Keep 1637931eeffaSKenneth D. Merry * it in here as an assert for now just to make certain that 163896375eacSRoger Pau Monné * chain_cnt is accurate. 16393fb28bbbSAdrian Chadd */ 164096375eacSRoger Pau Monné KASSERT((txq->mbufs_cnt + nfrags) <= NET_TX_RING_SIZE, 164196375eacSRoger Pau Monné ("%s: chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE " 164296375eacSRoger Pau Monné "(%d)!", __func__, (int) txq->mbufs_cnt, 1643931eeffaSKenneth D. Merry (int) nfrags, (int) NET_TX_RING_SIZE)); 1644a4ec37f5SAdrian Chadd 164589e0f4d2SKip Macy /* 164689e0f4d2SKip Macy * Start packing the mbufs in this chain into 164789e0f4d2SKip Macy * the fragment pointers. Stop when we run out 164889e0f4d2SKip Macy * of fragments or hit the end of the mbuf chain. 164989e0f4d2SKip Macy */ 165012678024SDoug Rabson m = m_head; 165196375eacSRoger Pau Monné otherend_id = xenbus_get_otherend_id(np->xbdev); 165212678024SDoug Rabson for (m = m_head; m; m = m->m_next) { 1653931eeffaSKenneth D. Merry netif_tx_request_t *tx; 1654931eeffaSKenneth D. Merry uintptr_t id; 1655931eeffaSKenneth D. Merry grant_ref_t ref; 1656931eeffaSKenneth D. Merry u_long mfn; /* XXX Wrong type? */ 1657931eeffaSKenneth D. Merry 165896375eacSRoger Pau Monné tx = RING_GET_REQUEST(&txq->ring, txq->ring.req_prod_pvt); 165996375eacSRoger Pau Monné id = get_id_from_freelist(txq->mbufs); 1660a4ec37f5SAdrian Chadd if (id == 0) 16616f9767acSMarius Strobl panic("%s: was allocated the freelist head!\n", 16626f9767acSMarius Strobl __func__); 166396375eacSRoger Pau Monné txq->mbufs_cnt++; 166496375eacSRoger Pau Monné if (txq->mbufs_cnt > NET_TX_RING_SIZE) 16656f9767acSMarius Strobl panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n", 16666f9767acSMarius Strobl __func__); 166796375eacSRoger Pau Monné txq->mbufs[id] = m; 166889e0f4d2SKip Macy tx->id = id; 166996375eacSRoger Pau Monné ref = gnttab_claim_grant_reference(&txq->gref_head); 167089e0f4d2SKip Macy KASSERT((short)ref >= 0, ("Negative ref")); 167112678024SDoug Rabson mfn = virt_to_mfn(mtod(m, vm_offset_t)); 167223dc5621SKip Macy gnttab_grant_foreign_access_ref(ref, otherend_id, 167389e0f4d2SKip Macy mfn, GNTMAP_readonly); 167496375eacSRoger Pau Monné tx->gref = txq->grant_ref[id] = ref; 167512678024SDoug Rabson tx->offset = mtod(m, vm_offset_t) & (PAGE_SIZE - 1); 167689e0f4d2SKip Macy tx->flags = 0; 167712678024SDoug Rabson if (m == m_head) { 167812678024SDoug Rabson /* 167912678024SDoug Rabson * The first fragment has the entire packet 168012678024SDoug Rabson * size, subsequent fragments have just the 168112678024SDoug Rabson * fragment size. The backend works out the 168212678024SDoug Rabson * true size of the first fragment by 168312678024SDoug Rabson * subtracting the sizes of the other 168412678024SDoug Rabson * fragments. 168512678024SDoug Rabson */ 168612678024SDoug Rabson tx->size = m->m_pkthdr.len; 168789e0f4d2SKip Macy 168812678024SDoug Rabson /* 1689931eeffaSKenneth D. Merry * The first fragment contains the checksum flags 1690931eeffaSKenneth D. Merry * and is optionally followed by extra data for 1691931eeffaSKenneth D. Merry * TSO etc. 1692931eeffaSKenneth D. Merry */ 1693931eeffaSKenneth D. Merry /** 1694931eeffaSKenneth D. Merry * CSUM_TSO requires checksum offloading. 1695931eeffaSKenneth D. Merry * Some versions of FreeBSD fail to 1696931eeffaSKenneth D. Merry * set CSUM_TCP in the CSUM_TSO case, 1697931eeffaSKenneth D. Merry * so we have to test for CSUM_TSO 1698931eeffaSKenneth D. Merry * explicitly. 169912678024SDoug Rabson */ 170012678024SDoug Rabson if (m->m_pkthdr.csum_flags 1701931eeffaSKenneth D. Merry & (CSUM_DELAY_DATA | CSUM_TSO)) { 170212678024SDoug Rabson tx->flags |= (NETTXF_csum_blank 170312678024SDoug Rabson | NETTXF_data_validated); 170412678024SDoug Rabson } 170512678024SDoug Rabson if (m->m_pkthdr.csum_flags & CSUM_TSO) { 170612678024SDoug Rabson struct netif_extra_info *gso = 170712678024SDoug Rabson (struct netif_extra_info *) 170896375eacSRoger Pau Monné RING_GET_REQUEST(&txq->ring, 170996375eacSRoger Pau Monné ++txq->ring.req_prod_pvt); 171089e0f4d2SKip Macy 171112678024SDoug Rabson tx->flags |= NETTXF_extra_info; 171289e0f4d2SKip Macy 171312678024SDoug Rabson gso->u.gso.size = m->m_pkthdr.tso_segsz; 171412678024SDoug Rabson gso->u.gso.type = 171512678024SDoug Rabson XEN_NETIF_GSO_TYPE_TCPV4; 171612678024SDoug Rabson gso->u.gso.pad = 0; 171712678024SDoug Rabson gso->u.gso.features = 0; 171812678024SDoug Rabson 171912678024SDoug Rabson gso->type = XEN_NETIF_EXTRA_TYPE_GSO; 172012678024SDoug Rabson gso->flags = 0; 172112678024SDoug Rabson } 172212678024SDoug Rabson } else { 172312678024SDoug Rabson tx->size = m->m_len; 172412678024SDoug Rabson } 1725931eeffaSKenneth D. Merry if (m->m_next) 172612678024SDoug Rabson tx->flags |= NETTXF_more_data; 172712678024SDoug Rabson 172896375eacSRoger Pau Monné txq->ring.req_prod_pvt++; 1729931eeffaSKenneth D. Merry } 173012678024SDoug Rabson BPF_MTAP(ifp, m_head); 173112678024SDoug Rabson 173296375eacSRoger Pau Monné xn_txeof(txq); 173396375eacSRoger Pau Monné 173496375eacSRoger Pau Monné txq->stats.tx_bytes += m_head->m_pkthdr.len; 173596375eacSRoger Pau Monné txq->stats.tx_packets++; 1736931eeffaSKenneth D. Merry 1737931eeffaSKenneth D. Merry return (0); 173889e0f4d2SKip Macy } 173989e0f4d2SKip Macy 174089e0f4d2SKip Macy /* equivalent of network_open() in Linux */ 174189e0f4d2SKip Macy static void 174296375eacSRoger Pau Monné xn_ifinit_locked(struct netfront_info *np) 174389e0f4d2SKip Macy { 174489e0f4d2SKip Macy struct ifnet *ifp; 174596375eacSRoger Pau Monné int i; 174696375eacSRoger Pau Monné struct netfront_rxq *rxq; 174789e0f4d2SKip Macy 174896375eacSRoger Pau Monné XN_LOCK_ASSERT(np); 174989e0f4d2SKip Macy 175096375eacSRoger Pau Monné ifp = np->xn_ifp; 175189e0f4d2SKip Macy 175289e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) 175389e0f4d2SKip Macy return; 175489e0f4d2SKip Macy 175596375eacSRoger Pau Monné xn_stop(np); 175689e0f4d2SKip Macy 175796375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 175896375eacSRoger Pau Monné rxq = &np->rxq[i]; 1759*2568ee67SRoger Pau Monné XN_RX_LOCK(rxq); 176096375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 176196375eacSRoger Pau Monné rxq->ring.sring->rsp_event = rxq->ring.rsp_cons + 1; 1762*2568ee67SRoger Pau Monné if (RING_HAS_UNCONSUMED_RESPONSES(&rxq->ring)) 1763*2568ee67SRoger Pau Monné taskqueue_enqueue(rxq->tq, &rxq->intrtask); 1764*2568ee67SRoger Pau Monné XN_RX_UNLOCK(rxq); 176596375eacSRoger Pau Monné } 176689e0f4d2SKip Macy 176789e0f4d2SKip Macy ifp->if_drv_flags |= IFF_DRV_RUNNING; 176889e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 17690e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_UP); 177089e0f4d2SKip Macy } 177189e0f4d2SKip Macy 177289e0f4d2SKip Macy static void 177389e0f4d2SKip Macy xn_ifinit(void *xsc) 177489e0f4d2SKip Macy { 177589e0f4d2SKip Macy struct netfront_info *sc = xsc; 177689e0f4d2SKip Macy 177789e0f4d2SKip Macy XN_LOCK(sc); 177889e0f4d2SKip Macy xn_ifinit_locked(sc); 177989e0f4d2SKip Macy XN_UNLOCK(sc); 178089e0f4d2SKip Macy } 178189e0f4d2SKip Macy 178289e0f4d2SKip Macy static int 178389e0f4d2SKip Macy xn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 178489e0f4d2SKip Macy { 178589e0f4d2SKip Macy struct netfront_info *sc = ifp->if_softc; 178689e0f4d2SKip Macy struct ifreq *ifr = (struct ifreq *) data; 1787a0ae8f04SBjoern A. Zeeb #ifdef INET 178889e0f4d2SKip Macy struct ifaddr *ifa = (struct ifaddr *)data; 1789a0ae8f04SBjoern A. Zeeb #endif 179089e0f4d2SKip Macy 179189e0f4d2SKip Macy int mask, error = 0; 179289e0f4d2SKip Macy switch(cmd) { 179389e0f4d2SKip Macy case SIOCSIFADDR: 1794a0ae8f04SBjoern A. Zeeb #ifdef INET 179589e0f4d2SKip Macy XN_LOCK(sc); 179689e0f4d2SKip Macy if (ifa->ifa_addr->sa_family == AF_INET) { 179789e0f4d2SKip Macy ifp->if_flags |= IFF_UP; 179889e0f4d2SKip Macy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 179989e0f4d2SKip Macy xn_ifinit_locked(sc); 180089e0f4d2SKip Macy arp_ifinit(ifp, ifa); 180189e0f4d2SKip Macy XN_UNLOCK(sc); 180249906218SDoug Rabson } else { 180349906218SDoug Rabson XN_UNLOCK(sc); 1804a0ae8f04SBjoern A. Zeeb #endif 180549906218SDoug Rabson error = ether_ioctl(ifp, cmd, data); 1806a0ae8f04SBjoern A. Zeeb #ifdef INET 180749906218SDoug Rabson } 1808a0ae8f04SBjoern A. Zeeb #endif 180989e0f4d2SKip Macy break; 181089e0f4d2SKip Macy case SIOCSIFMTU: 181189e0f4d2SKip Macy ifp->if_mtu = ifr->ifr_mtu; 181289e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 181389e0f4d2SKip Macy xn_ifinit(sc); 181489e0f4d2SKip Macy break; 181589e0f4d2SKip Macy case SIOCSIFFLAGS: 181689e0f4d2SKip Macy XN_LOCK(sc); 181789e0f4d2SKip Macy if (ifp->if_flags & IFF_UP) { 181889e0f4d2SKip Macy /* 181989e0f4d2SKip Macy * If only the state of the PROMISC flag changed, 182089e0f4d2SKip Macy * then just use the 'set promisc mode' command 182189e0f4d2SKip Macy * instead of reinitializing the entire NIC. Doing 182289e0f4d2SKip Macy * a full re-init means reloading the firmware and 182389e0f4d2SKip Macy * waiting for it to start up, which may take a 182489e0f4d2SKip Macy * second or two. 182589e0f4d2SKip Macy */ 182689e0f4d2SKip Macy xn_ifinit_locked(sc); 182789e0f4d2SKip Macy } else { 182889e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 182989e0f4d2SKip Macy xn_stop(sc); 183089e0f4d2SKip Macy } 183189e0f4d2SKip Macy } 183289e0f4d2SKip Macy sc->xn_if_flags = ifp->if_flags; 183389e0f4d2SKip Macy XN_UNLOCK(sc); 183489e0f4d2SKip Macy break; 183589e0f4d2SKip Macy case SIOCSIFCAP: 183689e0f4d2SKip Macy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 183712678024SDoug Rabson if (mask & IFCAP_TXCSUM) { 183812678024SDoug Rabson if (IFCAP_TXCSUM & ifp->if_capenable) { 183912678024SDoug Rabson ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 184012678024SDoug Rabson ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 184112678024SDoug Rabson | CSUM_IP | CSUM_TSO); 184212678024SDoug Rabson } else { 184312678024SDoug Rabson ifp->if_capenable |= IFCAP_TXCSUM; 184412678024SDoug Rabson ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP 184512678024SDoug Rabson | CSUM_IP); 184689e0f4d2SKip Macy } 184712678024SDoug Rabson } 184812678024SDoug Rabson if (mask & IFCAP_RXCSUM) { 184912678024SDoug Rabson ifp->if_capenable ^= IFCAP_RXCSUM; 185012678024SDoug Rabson } 185112678024SDoug Rabson if (mask & IFCAP_TSO4) { 185212678024SDoug Rabson if (IFCAP_TSO4 & ifp->if_capenable) { 185312678024SDoug Rabson ifp->if_capenable &= ~IFCAP_TSO4; 185412678024SDoug Rabson ifp->if_hwassist &= ~CSUM_TSO; 185512678024SDoug Rabson } else if (IFCAP_TXCSUM & ifp->if_capenable) { 185612678024SDoug Rabson ifp->if_capenable |= IFCAP_TSO4; 185712678024SDoug Rabson ifp->if_hwassist |= CSUM_TSO; 185812678024SDoug Rabson } else { 18593552092bSAdrian Chadd IPRINTK("Xen requires tx checksum offload" 186012678024SDoug Rabson " be enabled to use TSO\n"); 186112678024SDoug Rabson error = EINVAL; 186212678024SDoug Rabson } 186312678024SDoug Rabson } 186412678024SDoug Rabson if (mask & IFCAP_LRO) { 186512678024SDoug Rabson ifp->if_capenable ^= IFCAP_LRO; 186612678024SDoug Rabson 186712678024SDoug Rabson } 186889e0f4d2SKip Macy break; 186989e0f4d2SKip Macy case SIOCADDMULTI: 187089e0f4d2SKip Macy case SIOCDELMULTI: 1871ce8df48bSSimon J. Gerraty break; 187289e0f4d2SKip Macy case SIOCSIFMEDIA: 187389e0f4d2SKip Macy case SIOCGIFMEDIA: 18740e509842SJustin T. Gibbs error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 187589e0f4d2SKip Macy break; 187689e0f4d2SKip Macy default: 187789e0f4d2SKip Macy error = ether_ioctl(ifp, cmd, data); 187889e0f4d2SKip Macy } 187989e0f4d2SKip Macy 188089e0f4d2SKip Macy return (error); 188189e0f4d2SKip Macy } 188289e0f4d2SKip Macy 188389e0f4d2SKip Macy static void 188489e0f4d2SKip Macy xn_stop(struct netfront_info *sc) 188589e0f4d2SKip Macy { 188689e0f4d2SKip Macy struct ifnet *ifp; 188789e0f4d2SKip Macy 188889e0f4d2SKip Macy XN_LOCK_ASSERT(sc); 188989e0f4d2SKip Macy 189089e0f4d2SKip Macy ifp = sc->xn_ifp; 189189e0f4d2SKip Macy 189289e0f4d2SKip Macy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 18930e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_DOWN); 189489e0f4d2SKip Macy } 189589e0f4d2SKip Macy 189696375eacSRoger Pau Monné static void 189796375eacSRoger Pau Monné xn_rebuild_rx_bufs(struct netfront_rxq *rxq) 189889e0f4d2SKip Macy { 189996375eacSRoger Pau Monné int requeue_idx, i; 190089e0f4d2SKip Macy grant_ref_t ref; 190189e0f4d2SKip Macy netif_rx_request_t *req; 190289e0f4d2SKip Macy 190389e0f4d2SKip Macy for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { 190489e0f4d2SKip Macy struct mbuf *m; 19053a6d1fcfSKip Macy u_long pfn; 190689e0f4d2SKip Macy 190796375eacSRoger Pau Monné if (rxq->mbufs[i] == NULL) 190889e0f4d2SKip Macy continue; 190989e0f4d2SKip Macy 191096375eacSRoger Pau Monné m = rxq->mbufs[requeue_idx] = xn_get_rx_mbuf(rxq, i); 191196375eacSRoger Pau Monné ref = rxq->grant_ref[requeue_idx] = xn_get_rx_ref(rxq, i); 1912931eeffaSKenneth D. Merry 191396375eacSRoger Pau Monné req = RING_GET_REQUEST(&rxq->ring, requeue_idx); 19143a6d1fcfSKip Macy pfn = vtophys(mtod(m, vm_offset_t)) >> PAGE_SHIFT; 191589e0f4d2SKip Macy 191689e0f4d2SKip Macy gnttab_grant_foreign_access_ref(ref, 191796375eacSRoger Pau Monné xenbus_get_otherend_id(rxq->info->xbdev), 1918ed95805eSJohn Baldwin pfn, 0); 1919d0f3a8b9SRoger Pau Monné 192089e0f4d2SKip Macy req->gref = ref; 192189e0f4d2SKip Macy req->id = requeue_idx; 192289e0f4d2SKip Macy 192389e0f4d2SKip Macy requeue_idx++; 192489e0f4d2SKip Macy } 192589e0f4d2SKip Macy 192696375eacSRoger Pau Monné rxq->ring.req_prod_pvt = requeue_idx; 192796375eacSRoger Pau Monné } 192889e0f4d2SKip Macy 192996375eacSRoger Pau Monné /* START of Xenolinux helper functions adapted to FreeBSD */ 193096375eacSRoger Pau Monné int 193196375eacSRoger Pau Monné xn_connect(struct netfront_info *np) 193296375eacSRoger Pau Monné { 193396375eacSRoger Pau Monné int i, error; 193496375eacSRoger Pau Monné u_int feature_rx_copy; 193596375eacSRoger Pau Monné struct netfront_rxq *rxq; 193696375eacSRoger Pau Monné struct netfront_txq *txq; 193796375eacSRoger Pau Monné 193896375eacSRoger Pau Monné error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 193996375eacSRoger Pau Monné "feature-rx-copy", NULL, "%u", &feature_rx_copy); 194096375eacSRoger Pau Monné if (error != 0) 194196375eacSRoger Pau Monné feature_rx_copy = 0; 194296375eacSRoger Pau Monné 194396375eacSRoger Pau Monné /* We only support rx copy. */ 194496375eacSRoger Pau Monné if (!feature_rx_copy) 194596375eacSRoger Pau Monné return (EPROTONOSUPPORT); 194696375eacSRoger Pau Monné 194796375eacSRoger Pau Monné /* Recovery procedure: */ 194896375eacSRoger Pau Monné error = talk_to_backend(np->xbdev, np); 194996375eacSRoger Pau Monné if (error != 0) 195096375eacSRoger Pau Monné return (error); 195196375eacSRoger Pau Monné 195296375eacSRoger Pau Monné /* Step 1: Reinitialise variables. */ 195396375eacSRoger Pau Monné xn_query_features(np); 195496375eacSRoger Pau Monné xn_configure_features(np); 195596375eacSRoger Pau Monné 195696375eacSRoger Pau Monné /* Step 2: Release TX buffer */ 195796375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 195896375eacSRoger Pau Monné txq = &np->txq[i]; 195996375eacSRoger Pau Monné xn_release_tx_bufs(txq); 196096375eacSRoger Pau Monné } 196196375eacSRoger Pau Monné 196296375eacSRoger Pau Monné /* Step 3: Rebuild the RX buffer freelist and the RX ring itself. */ 196396375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 196496375eacSRoger Pau Monné rxq = &np->rxq[i]; 196596375eacSRoger Pau Monné xn_rebuild_rx_bufs(rxq); 196696375eacSRoger Pau Monné } 196796375eacSRoger Pau Monné 196896375eacSRoger Pau Monné /* Step 4: All public and private state should now be sane. Get 196989e0f4d2SKip Macy * ready to start sending and receiving packets and give the driver 197089e0f4d2SKip Macy * domain a kick because we've probably just requeued some 197189e0f4d2SKip Macy * packets. 197289e0f4d2SKip Macy */ 197389e0f4d2SKip Macy netfront_carrier_on(np); 197496375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 197596375eacSRoger Pau Monné txq = &np->txq[i]; 197696375eacSRoger Pau Monné xen_intr_signal(txq->xen_intr_handle); 197796375eacSRoger Pau Monné XN_TX_LOCK(txq); 197896375eacSRoger Pau Monné xn_txeof(txq); 197996375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 1980*2568ee67SRoger Pau Monné XN_RX_LOCK(rxq); 198196375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 1982*2568ee67SRoger Pau Monné XN_RX_UNLOCK(rxq); 198396375eacSRoger Pau Monné } 198489e0f4d2SKip Macy 198589e0f4d2SKip Macy return (0); 198689e0f4d2SKip Macy } 198789e0f4d2SKip Macy 198889e0f4d2SKip Macy static void 1989578e4bf7SJustin T. Gibbs xn_query_features(struct netfront_info *np) 1990578e4bf7SJustin T. Gibbs { 1991578e4bf7SJustin T. Gibbs int val; 1992578e4bf7SJustin T. Gibbs 1993578e4bf7SJustin T. Gibbs device_printf(np->xbdev, "backend features:"); 1994578e4bf7SJustin T. Gibbs 1995578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 1996107cfbb7SRoger Pau Monné "feature-sg", NULL, "%d", &val) != 0) 1997578e4bf7SJustin T. Gibbs val = 0; 1998578e4bf7SJustin T. Gibbs 1999578e4bf7SJustin T. Gibbs np->maxfrags = 1; 2000578e4bf7SJustin T. Gibbs if (val) { 2001578e4bf7SJustin T. Gibbs np->maxfrags = MAX_TX_REQ_FRAGS; 2002578e4bf7SJustin T. Gibbs printf(" feature-sg"); 2003578e4bf7SJustin T. Gibbs } 2004578e4bf7SJustin T. Gibbs 2005578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 2006107cfbb7SRoger Pau Monné "feature-gso-tcpv4", NULL, "%d", &val) != 0) 2007578e4bf7SJustin T. Gibbs val = 0; 2008578e4bf7SJustin T. Gibbs 2009578e4bf7SJustin T. Gibbs np->xn_ifp->if_capabilities &= ~(IFCAP_TSO4|IFCAP_LRO); 2010578e4bf7SJustin T. Gibbs if (val) { 2011578e4bf7SJustin T. Gibbs np->xn_ifp->if_capabilities |= IFCAP_TSO4|IFCAP_LRO; 2012578e4bf7SJustin T. Gibbs printf(" feature-gso-tcp4"); 2013578e4bf7SJustin T. Gibbs } 2014578e4bf7SJustin T. Gibbs 2015578e4bf7SJustin T. Gibbs printf("\n"); 2016578e4bf7SJustin T. Gibbs } 2017578e4bf7SJustin T. Gibbs 2018cf9c09e1SJustin T. Gibbs static int 2019578e4bf7SJustin T. Gibbs xn_configure_features(struct netfront_info *np) 2020cf9c09e1SJustin T. Gibbs { 20216a8e9695SRoger Pau Monné int err, cap_enabled; 202296375eacSRoger Pau Monné #if (defined(INET) || defined(INET6)) 202396375eacSRoger Pau Monné int i; 202496375eacSRoger Pau Monné #endif 2025cf9c09e1SJustin T. Gibbs 2026cf9c09e1SJustin T. Gibbs err = 0; 20276a8e9695SRoger Pau Monné 20286a8e9695SRoger Pau Monné if (np->xn_resume && 20296a8e9695SRoger Pau Monné ((np->xn_ifp->if_capenable & np->xn_ifp->if_capabilities) 20306a8e9695SRoger Pau Monné == np->xn_ifp->if_capenable)) { 20316a8e9695SRoger Pau Monné /* Current options are available, no need to do anything. */ 20326a8e9695SRoger Pau Monné return (0); 20336a8e9695SRoger Pau Monné } 20346a8e9695SRoger Pau Monné 20356a8e9695SRoger Pau Monné /* Try to preserve as many options as possible. */ 20366a8e9695SRoger Pau Monné if (np->xn_resume) 20376a8e9695SRoger Pau Monné cap_enabled = np->xn_ifp->if_capenable; 20386a8e9695SRoger Pau Monné else 20396a8e9695SRoger Pau Monné cap_enabled = UINT_MAX; 20406a8e9695SRoger Pau Monné 204108c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 204296375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 204396375eacSRoger Pau Monné if ((np->xn_ifp->if_capenable & IFCAP_LRO) == 204496375eacSRoger Pau Monné (cap_enabled & IFCAP_LRO)) 204596375eacSRoger Pau Monné tcp_lro_free(&np->rxq[i].lro); 2046578e4bf7SJustin T. Gibbs #endif 2047578e4bf7SJustin T. Gibbs np->xn_ifp->if_capenable = 20486a8e9695SRoger Pau Monné np->xn_ifp->if_capabilities & ~(IFCAP_LRO|IFCAP_TSO4) & cap_enabled; 2049578e4bf7SJustin T. Gibbs np->xn_ifp->if_hwassist &= ~CSUM_TSO; 205008c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 205196375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 20526a8e9695SRoger Pau Monné if (xn_enable_lro && (np->xn_ifp->if_capabilities & IFCAP_LRO) == 20536a8e9695SRoger Pau Monné (cap_enabled & IFCAP_LRO)) { 205496375eacSRoger Pau Monné err = tcp_lro_init(&np->rxq[i].lro); 205596375eacSRoger Pau Monné if (err != 0) { 2056cf9c09e1SJustin T. Gibbs device_printf(np->xbdev, "LRO initialization failed\n"); 2057cf9c09e1SJustin T. Gibbs } else { 205896375eacSRoger Pau Monné np->rxq[i].lro.ifp = np->xn_ifp; 2059578e4bf7SJustin T. Gibbs np->xn_ifp->if_capenable |= IFCAP_LRO; 2060cf9c09e1SJustin T. Gibbs } 2061cf9c09e1SJustin T. Gibbs } 206296375eacSRoger Pau Monné } 20636a8e9695SRoger Pau Monné if ((np->xn_ifp->if_capabilities & IFCAP_TSO4) == 20646a8e9695SRoger Pau Monné (cap_enabled & IFCAP_TSO4)) { 2065578e4bf7SJustin T. Gibbs np->xn_ifp->if_capenable |= IFCAP_TSO4; 2066578e4bf7SJustin T. Gibbs np->xn_ifp->if_hwassist |= CSUM_TSO; 2067578e4bf7SJustin T. Gibbs } 2068cf9c09e1SJustin T. Gibbs #endif 2069cf9c09e1SJustin T. Gibbs return (err); 2070cf9c09e1SJustin T. Gibbs } 2071cf9c09e1SJustin T. Gibbs 207296375eacSRoger Pau Monné static int 207396375eacSRoger Pau Monné xn_txq_mq_start_locked(struct netfront_txq *txq, struct mbuf *m) 207496375eacSRoger Pau Monné { 207596375eacSRoger Pau Monné struct netfront_info *np; 207696375eacSRoger Pau Monné struct ifnet *ifp; 207796375eacSRoger Pau Monné struct buf_ring *br; 207896375eacSRoger Pau Monné int error, notify; 207996375eacSRoger Pau Monné 208096375eacSRoger Pau Monné np = txq->info; 208196375eacSRoger Pau Monné br = txq->br; 208296375eacSRoger Pau Monné ifp = np->xn_ifp; 208396375eacSRoger Pau Monné error = 0; 208496375eacSRoger Pau Monné 208596375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 208696375eacSRoger Pau Monné 208796375eacSRoger Pau Monné if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 208896375eacSRoger Pau Monné !netfront_carrier_ok(np)) { 208996375eacSRoger Pau Monné if (m != NULL) 209096375eacSRoger Pau Monné error = drbr_enqueue(ifp, br, m); 209196375eacSRoger Pau Monné return (error); 209296375eacSRoger Pau Monné } 209396375eacSRoger Pau Monné 209496375eacSRoger Pau Monné if (m != NULL) { 209596375eacSRoger Pau Monné error = drbr_enqueue(ifp, br, m); 209696375eacSRoger Pau Monné if (error != 0) 209796375eacSRoger Pau Monné return (error); 209896375eacSRoger Pau Monné } 209996375eacSRoger Pau Monné 210096375eacSRoger Pau Monné while ((m = drbr_peek(ifp, br)) != NULL) { 210196375eacSRoger Pau Monné if (!xn_tx_slot_available(txq)) { 210296375eacSRoger Pau Monné drbr_putback(ifp, br, m); 210396375eacSRoger Pau Monné break; 210496375eacSRoger Pau Monné } 210596375eacSRoger Pau Monné 210696375eacSRoger Pau Monné error = xn_assemble_tx_request(txq, m); 210796375eacSRoger Pau Monné /* xn_assemble_tx_request always consumes the mbuf*/ 210896375eacSRoger Pau Monné if (error != 0) { 210996375eacSRoger Pau Monné drbr_advance(ifp, br); 211096375eacSRoger Pau Monné break; 211196375eacSRoger Pau Monné } 211296375eacSRoger Pau Monné 211396375eacSRoger Pau Monné RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&txq->ring, notify); 211496375eacSRoger Pau Monné if (notify) 211596375eacSRoger Pau Monné xen_intr_signal(txq->xen_intr_handle); 211696375eacSRoger Pau Monné 211796375eacSRoger Pau Monné drbr_advance(ifp, br); 211896375eacSRoger Pau Monné } 211996375eacSRoger Pau Monné 212096375eacSRoger Pau Monné if (RING_FULL(&txq->ring)) 212196375eacSRoger Pau Monné txq->full = true; 212296375eacSRoger Pau Monné 212396375eacSRoger Pau Monné return (0); 212496375eacSRoger Pau Monné } 212596375eacSRoger Pau Monné 212696375eacSRoger Pau Monné static int 212796375eacSRoger Pau Monné xn_txq_mq_start(struct ifnet *ifp, struct mbuf *m) 212896375eacSRoger Pau Monné { 212996375eacSRoger Pau Monné struct netfront_info *np; 213096375eacSRoger Pau Monné struct netfront_txq *txq; 213196375eacSRoger Pau Monné int i, npairs, error; 213296375eacSRoger Pau Monné 213396375eacSRoger Pau Monné np = ifp->if_softc; 213496375eacSRoger Pau Monné npairs = np->num_queues; 213596375eacSRoger Pau Monné 213696375eacSRoger Pau Monné /* check if flowid is set */ 213796375eacSRoger Pau Monné if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 213896375eacSRoger Pau Monné i = m->m_pkthdr.flowid % npairs; 213996375eacSRoger Pau Monné else 214096375eacSRoger Pau Monné i = curcpu % npairs; 214196375eacSRoger Pau Monné 214296375eacSRoger Pau Monné txq = &np->txq[i]; 214396375eacSRoger Pau Monné 214496375eacSRoger Pau Monné if (XN_TX_TRYLOCK(txq) != 0) { 214596375eacSRoger Pau Monné error = xn_txq_mq_start_locked(txq, m); 214696375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 214796375eacSRoger Pau Monné } else { 214896375eacSRoger Pau Monné error = drbr_enqueue(ifp, txq->br, m); 214996375eacSRoger Pau Monné taskqueue_enqueue(txq->tq, &txq->defrtask); 215096375eacSRoger Pau Monné } 215196375eacSRoger Pau Monné 215296375eacSRoger Pau Monné return (error); 215396375eacSRoger Pau Monné } 215496375eacSRoger Pau Monné 215596375eacSRoger Pau Monné static void 215696375eacSRoger Pau Monné xn_qflush(struct ifnet *ifp) 215796375eacSRoger Pau Monné { 215896375eacSRoger Pau Monné struct netfront_info *np; 215996375eacSRoger Pau Monné struct netfront_txq *txq; 216096375eacSRoger Pau Monné struct mbuf *m; 216196375eacSRoger Pau Monné int i; 216296375eacSRoger Pau Monné 216396375eacSRoger Pau Monné np = ifp->if_softc; 216496375eacSRoger Pau Monné 216596375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 216696375eacSRoger Pau Monné txq = &np->txq[i]; 216796375eacSRoger Pau Monné 216896375eacSRoger Pau Monné XN_TX_LOCK(txq); 216996375eacSRoger Pau Monné while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 217096375eacSRoger Pau Monné m_freem(m); 217196375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 217296375eacSRoger Pau Monné } 217396375eacSRoger Pau Monné 217496375eacSRoger Pau Monné if_qflush(ifp); 217596375eacSRoger Pau Monné } 217696375eacSRoger Pau Monné 217776acc41fSJustin T. Gibbs /** 217876acc41fSJustin T. Gibbs * Create a network device. 217976acc41fSJustin T. Gibbs * @param dev Newbus device representing this virtual NIC. 218089e0f4d2SKip Macy */ 218123dc5621SKip Macy int 218223dc5621SKip Macy create_netdev(device_t dev) 218389e0f4d2SKip Macy { 218489e0f4d2SKip Macy struct netfront_info *np; 218589e0f4d2SKip Macy int err; 218689e0f4d2SKip Macy struct ifnet *ifp; 218789e0f4d2SKip Macy 218823dc5621SKip Macy np = device_get_softc(dev); 218989e0f4d2SKip Macy 219089e0f4d2SKip Macy np->xbdev = dev; 219189e0f4d2SKip Macy 2192177e3f13SRoger Pau Monné mtx_init(&np->sc_lock, "xnsc", "netfront softc lock", MTX_DEF); 21930e509842SJustin T. Gibbs 21940e509842SJustin T. Gibbs ifmedia_init(&np->sc_media, 0, xn_ifmedia_upd, xn_ifmedia_sts); 21950e509842SJustin T. Gibbs ifmedia_add(&np->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 21960e509842SJustin T. Gibbs ifmedia_set(&np->sc_media, IFM_ETHER|IFM_MANUAL); 21970e509842SJustin T. Gibbs 219889e0f4d2SKip Macy err = xen_net_read_mac(dev, np->mac); 219996375eacSRoger Pau Monné if (err != 0) 22001a2928b7SRoger Pau Monné goto error; 220189e0f4d2SKip Macy 220289e0f4d2SKip Macy /* Set up ifnet structure */ 220323dc5621SKip Macy ifp = np->xn_ifp = if_alloc(IFT_ETHER); 220489e0f4d2SKip Macy ifp->if_softc = np; 220523dc5621SKip Macy if_initname(ifp, "xn", device_get_unit(dev)); 22063a6d1fcfSKip Macy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 220789e0f4d2SKip Macy ifp->if_ioctl = xn_ioctl; 220896375eacSRoger Pau Monné 220996375eacSRoger Pau Monné ifp->if_transmit = xn_txq_mq_start; 221096375eacSRoger Pau Monné ifp->if_qflush = xn_qflush; 221196375eacSRoger Pau Monné 221289e0f4d2SKip Macy ifp->if_init = xn_ifinit; 221389e0f4d2SKip Macy 221489e0f4d2SKip Macy ifp->if_hwassist = XN_CSUM_FEATURES; 221589e0f4d2SKip Macy ifp->if_capabilities = IFCAP_HWCSUM; 22169fd573c3SHans Petter Selasky ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 22179fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegcount = MAX_TX_REQ_FRAGS; 22189fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 221989e0f4d2SKip Macy 222089e0f4d2SKip Macy ether_ifattach(ifp, np->mac); 222189e0f4d2SKip Macy netfront_carrier_off(np); 222289e0f4d2SKip Macy 222389e0f4d2SKip Macy return (0); 222489e0f4d2SKip Macy 22251a2928b7SRoger Pau Monné error: 22261a2928b7SRoger Pau Monné KASSERT(err != 0, ("Error path with no error code specified")); 2227ffa06904SJustin T. Gibbs return (err); 222889e0f4d2SKip Macy } 222989e0f4d2SKip Macy 22300e509842SJustin T. Gibbs static int 22310e509842SJustin T. Gibbs netfront_detach(device_t dev) 223289e0f4d2SKip Macy { 223323dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 223489e0f4d2SKip Macy 223523dc5621SKip Macy DPRINTK("%s\n", xenbus_get_node(dev)); 223689e0f4d2SKip Macy 223789e0f4d2SKip Macy netif_free(info); 223889e0f4d2SKip Macy 223989e0f4d2SKip Macy return 0; 224089e0f4d2SKip Macy } 224189e0f4d2SKip Macy 22420e509842SJustin T. Gibbs static void 224396375eacSRoger Pau Monné netif_free(struct netfront_info *np) 224489e0f4d2SKip Macy { 224596375eacSRoger Pau Monné 224696375eacSRoger Pau Monné XN_LOCK(np); 224796375eacSRoger Pau Monné xn_stop(np); 224896375eacSRoger Pau Monné XN_UNLOCK(np); 224996375eacSRoger Pau Monné netif_disconnect_backend(np); 225096375eacSRoger Pau Monné free(np->rxq, M_DEVBUF); 225196375eacSRoger Pau Monné free(np->txq, M_DEVBUF); 225296375eacSRoger Pau Monné ether_ifdetach(np->xn_ifp); 225396375eacSRoger Pau Monné if_free(np->xn_ifp); 225496375eacSRoger Pau Monné np->xn_ifp = NULL; 225596375eacSRoger Pau Monné ifmedia_removeall(&np->sc_media); 225689e0f4d2SKip Macy } 225789e0f4d2SKip Macy 22580e509842SJustin T. Gibbs static void 225996375eacSRoger Pau Monné netif_disconnect_backend(struct netfront_info *np) 226089e0f4d2SKip Macy { 226196375eacSRoger Pau Monné u_int i; 22623a6d1fcfSKip Macy 226396375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 226496375eacSRoger Pau Monné XN_RX_LOCK(&np->rxq[i]); 226596375eacSRoger Pau Monné XN_TX_LOCK(&np->txq[i]); 226696375eacSRoger Pau Monné } 226796375eacSRoger Pau Monné netfront_carrier_off(np); 226896375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 226996375eacSRoger Pau Monné XN_RX_UNLOCK(&np->rxq[i]); 227096375eacSRoger Pau Monné XN_TX_UNLOCK(&np->txq[i]); 227189e0f4d2SKip Macy } 227289e0f4d2SKip Macy 227396375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 227496375eacSRoger Pau Monné disconnect_rxq(&np->rxq[i]); 227596375eacSRoger Pau Monné disconnect_txq(&np->txq[i]); 2276cf9c09e1SJustin T. Gibbs } 227789e0f4d2SKip Macy } 227889e0f4d2SKip Macy 22790e509842SJustin T. Gibbs static int 22800e509842SJustin T. Gibbs xn_ifmedia_upd(struct ifnet *ifp) 22810e509842SJustin T. Gibbs { 228296375eacSRoger Pau Monné 22830e509842SJustin T. Gibbs return (0); 22840e509842SJustin T. Gibbs } 22850e509842SJustin T. Gibbs 22860e509842SJustin T. Gibbs static void 22870e509842SJustin T. Gibbs xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 22880e509842SJustin T. Gibbs { 228996375eacSRoger Pau Monné 22900e509842SJustin T. Gibbs ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE; 22910e509842SJustin T. Gibbs ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; 22920e509842SJustin T. Gibbs } 22930e509842SJustin T. Gibbs 229489e0f4d2SKip Macy /* ** Driver registration ** */ 229523dc5621SKip Macy static device_method_t netfront_methods[] = { 229623dc5621SKip Macy /* Device interface */ 229723dc5621SKip Macy DEVMETHOD(device_probe, netfront_probe), 229823dc5621SKip Macy DEVMETHOD(device_attach, netfront_attach), 229923dc5621SKip Macy DEVMETHOD(device_detach, netfront_detach), 230023dc5621SKip Macy DEVMETHOD(device_shutdown, bus_generic_shutdown), 2301cf9c09e1SJustin T. Gibbs DEVMETHOD(device_suspend, netfront_suspend), 230223dc5621SKip Macy DEVMETHOD(device_resume, netfront_resume), 230389e0f4d2SKip Macy 230423dc5621SKip Macy /* Xenbus interface */ 2305ff662b5cSJustin T. Gibbs DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed), 230689e0f4d2SKip Macy 23076f9767acSMarius Strobl DEVMETHOD_END 230889e0f4d2SKip Macy }; 230989e0f4d2SKip Macy 231023dc5621SKip Macy static driver_t netfront_driver = { 231123dc5621SKip Macy "xn", 231223dc5621SKip Macy netfront_methods, 231323dc5621SKip Macy sizeof(struct netfront_info), 231489e0f4d2SKip Macy }; 231523dc5621SKip Macy devclass_t netfront_devclass; 231689e0f4d2SKip Macy 23176f9767acSMarius Strobl DRIVER_MODULE(xe, xenbusb_front, netfront_driver, netfront_devclass, NULL, 23186f9767acSMarius Strobl NULL); 2319