18e0ad55aSJoel Dahl /*- 289e0f4d2SKip Macy * Copyright (c) 2004-2006 Kip Macy 3*96375eacSRoger 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> 43*96375eacSRoger 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 8012678024SDoug Rabson /* 8112678024SDoug Rabson * Should the driver do LRO on the RX end 8212678024SDoug Rabson * this can be toggled on the fly, but the 8312678024SDoug Rabson * interface must be reset (down/up) for it 8412678024SDoug Rabson * to take effect. 8512678024SDoug Rabson */ 8612678024SDoug Rabson static int xn_enable_lro = 1; 8712678024SDoug Rabson TUNABLE_INT("hw.xn.enable_lro", &xn_enable_lro); 8812678024SDoug Rabson 89*96375eacSRoger Pau Monné /* 90*96375eacSRoger Pau Monné * Number of pairs of queues. 91*96375eacSRoger Pau Monné */ 92*96375eacSRoger Pau Monné static unsigned long xn_num_queues = 4; 93*96375eacSRoger Pau Monné TUNABLE_ULONG("hw.xn.num_queues", &xn_num_queues); 94*96375eacSRoger Pau Monné 95931eeffaSKenneth D. Merry /** 96931eeffaSKenneth D. Merry * \brief The maximum allowed data fragments in a single transmit 97931eeffaSKenneth D. Merry * request. 98931eeffaSKenneth D. Merry * 99931eeffaSKenneth D. Merry * This limit is imposed by the backend driver. We assume here that 100931eeffaSKenneth D. Merry * we are dealing with a Linux driver domain and have set our limit 101931eeffaSKenneth D. Merry * to mirror the Linux MAX_SKB_FRAGS constant. 102931eeffaSKenneth D. Merry */ 103931eeffaSKenneth D. Merry #define MAX_TX_REQ_FRAGS (65536 / PAGE_SIZE + 2) 104931eeffaSKenneth D. Merry 10589e0f4d2SKip Macy #define RX_COPY_THRESHOLD 256 10689e0f4d2SKip Macy 10789e0f4d2SKip Macy #define net_ratelimit() 0 10889e0f4d2SKip Macy 109*96375eacSRoger Pau Monné struct netfront_rxq; 110*96375eacSRoger Pau Monné struct netfront_txq; 11189e0f4d2SKip Macy struct netfront_info; 11289e0f4d2SKip Macy struct netfront_rx_info; 11389e0f4d2SKip Macy 114*96375eacSRoger Pau Monné static void xn_txeof(struct netfront_txq *); 115*96375eacSRoger Pau Monné static void xn_rxeof(struct netfront_rxq *); 116*96375eacSRoger Pau Monné static void xn_alloc_rx_buffers(struct netfront_rxq *); 11789e0f4d2SKip Macy 118*96375eacSRoger Pau Monné static void xn_release_rx_bufs(struct netfront_rxq *); 119*96375eacSRoger Pau Monné static void xn_release_tx_bufs(struct netfront_txq *); 12089e0f4d2SKip Macy 121*96375eacSRoger Pau Monné static void xn_rxq_intr(void *); 122*96375eacSRoger Pau Monné static void xn_txq_intr(void *); 123*96375eacSRoger Pau Monné static int xn_intr(void *); 124931eeffaSKenneth D. Merry static inline int xn_count_frags(struct mbuf *m); 125*96375eacSRoger Pau Monné static int xn_assemble_tx_request(struct netfront_txq *, struct mbuf *); 12689e0f4d2SKip Macy static int xn_ioctl(struct ifnet *, u_long, caddr_t); 12789e0f4d2SKip Macy static void xn_ifinit_locked(struct netfront_info *); 12889e0f4d2SKip Macy static void xn_ifinit(void *); 12989e0f4d2SKip Macy static void xn_stop(struct netfront_info *); 130578e4bf7SJustin T. Gibbs static void xn_query_features(struct netfront_info *np); 131578e4bf7SJustin T. Gibbs static int xn_configure_features(struct netfront_info *np); 13289e0f4d2SKip Macy static void netif_free(struct netfront_info *info); 13323dc5621SKip Macy static int netfront_detach(device_t dev); 13489e0f4d2SKip Macy 135*96375eacSRoger Pau Monné static int xn_txq_mq_start_locked(struct netfront_txq *, struct mbuf *); 136*96375eacSRoger Pau Monné static int xn_txq_mq_start(struct ifnet *, struct mbuf *); 137*96375eacSRoger Pau Monné 13823dc5621SKip Macy static int talk_to_backend(device_t dev, struct netfront_info *info); 13923dc5621SKip Macy static int create_netdev(device_t dev); 14089e0f4d2SKip Macy static void netif_disconnect_backend(struct netfront_info *info); 141*96375eacSRoger Pau Monné static int setup_device(device_t dev, struct netfront_info *info, 142*96375eacSRoger Pau Monné unsigned long); 1430e509842SJustin T. Gibbs static int xn_ifmedia_upd(struct ifnet *ifp); 1440e509842SJustin T. Gibbs static void xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 1450e509842SJustin T. Gibbs 146*96375eacSRoger Pau Monné int xn_connect(struct netfront_info *); 14789e0f4d2SKip Macy 148*96375eacSRoger Pau Monné static int xn_get_responses(struct netfront_rxq *, 149*96375eacSRoger Pau Monné struct netfront_rx_info *, RING_IDX, RING_IDX *, 150*96375eacSRoger Pau Monné struct mbuf **); 15189e0f4d2SKip Macy 1523c790178SJohn Baldwin #define virt_to_mfn(x) (vtophys(x) >> PAGE_SHIFT) 15389e0f4d2SKip Macy 15489e0f4d2SKip Macy #define INVALID_P2M_ENTRY (~0UL) 15589e0f4d2SKip Macy 156*96375eacSRoger Pau Monné struct xn_rx_stats 15789e0f4d2SKip Macy { 15889e0f4d2SKip Macy u_long rx_packets; /* total packets received */ 15989e0f4d2SKip Macy u_long rx_bytes; /* total bytes received */ 16089e0f4d2SKip Macy u_long rx_errors; /* bad packets received */ 161*96375eacSRoger Pau Monné }; 162*96375eacSRoger Pau Monné 163*96375eacSRoger Pau Monné struct xn_tx_stats 164*96375eacSRoger Pau Monné { 165*96375eacSRoger Pau Monné u_long tx_packets; /* total packets transmitted */ 166*96375eacSRoger Pau Monné u_long tx_bytes; /* total bytes transmitted */ 16789e0f4d2SKip Macy u_long tx_errors; /* packet transmit problems */ 16889e0f4d2SKip Macy }; 16989e0f4d2SKip Macy 170*96375eacSRoger Pau Monné #define XN_QUEUE_NAME_LEN 8 /* xn{t,r}x_%u, allow for two digits */ 171*96375eacSRoger Pau Monné struct netfront_rxq { 172*96375eacSRoger Pau Monné struct netfront_info *info; 173*96375eacSRoger Pau Monné u_int id; 174*96375eacSRoger Pau Monné char name[XN_QUEUE_NAME_LEN]; 175*96375eacSRoger Pau Monné struct mtx lock; 176*96375eacSRoger Pau Monné 177*96375eacSRoger Pau Monné int ring_ref; 178*96375eacSRoger Pau Monné netif_rx_front_ring_t ring; 179*96375eacSRoger Pau Monné xen_intr_handle_t xen_intr_handle; 180*96375eacSRoger Pau Monné 181*96375eacSRoger Pau Monné grant_ref_t gref_head; 182*96375eacSRoger Pau Monné grant_ref_t grant_ref[NET_TX_RING_SIZE + 1]; 183*96375eacSRoger Pau Monné 184*96375eacSRoger Pau Monné struct mbuf *mbufs[NET_RX_RING_SIZE + 1]; 185*96375eacSRoger Pau Monné struct mbufq batch; /* batch queue */ 186*96375eacSRoger Pau Monné int target; 187*96375eacSRoger Pau Monné 188*96375eacSRoger Pau Monné xen_pfn_t pfn_array[NET_RX_RING_SIZE]; 189*96375eacSRoger Pau Monné 190*96375eacSRoger Pau Monné struct lro_ctrl lro; 191*96375eacSRoger Pau Monné 192*96375eacSRoger Pau Monné struct taskqueue *tq; 193*96375eacSRoger Pau Monné struct task intrtask; 194*96375eacSRoger Pau Monné 195*96375eacSRoger Pau Monné struct xn_rx_stats stats; 196*96375eacSRoger Pau Monné }; 197*96375eacSRoger Pau Monné 198*96375eacSRoger Pau Monné struct netfront_txq { 199*96375eacSRoger Pau Monné struct netfront_info *info; 200*96375eacSRoger Pau Monné u_int id; 201*96375eacSRoger Pau Monné char name[XN_QUEUE_NAME_LEN]; 202*96375eacSRoger Pau Monné struct mtx lock; 203*96375eacSRoger Pau Monné 204*96375eacSRoger Pau Monné int ring_ref; 205*96375eacSRoger Pau Monné netif_tx_front_ring_t ring; 206*96375eacSRoger Pau Monné xen_intr_handle_t xen_intr_handle; 207*96375eacSRoger Pau Monné 208*96375eacSRoger Pau Monné grant_ref_t gref_head; 209*96375eacSRoger Pau Monné grant_ref_t grant_ref[NET_TX_RING_SIZE + 1]; 210*96375eacSRoger Pau Monné 211*96375eacSRoger Pau Monné struct mbuf *mbufs[NET_TX_RING_SIZE + 1]; 212*96375eacSRoger Pau Monné int mbufs_cnt; 213*96375eacSRoger Pau Monné struct buf_ring *br; 214*96375eacSRoger Pau Monné 215*96375eacSRoger Pau Monné struct taskqueue *tq; 216*96375eacSRoger Pau Monné struct task intrtask; 217*96375eacSRoger Pau Monné struct task defrtask; 218*96375eacSRoger Pau Monné 219*96375eacSRoger Pau Monné bool full; 220*96375eacSRoger Pau Monné 221*96375eacSRoger Pau Monné struct xn_tx_stats stats; 222*96375eacSRoger Pau Monné }; 223*96375eacSRoger Pau Monné 22489e0f4d2SKip Macy struct netfront_info { 22589e0f4d2SKip Macy struct ifnet *xn_ifp; 22689e0f4d2SKip Macy 227227ca257SKip Macy struct mtx sc_lock; 22889e0f4d2SKip Macy 229*96375eacSRoger Pau Monné u_int num_queues; 230*96375eacSRoger Pau Monné struct netfront_rxq *rxq; 231*96375eacSRoger Pau Monné struct netfront_txq *txq; 232*96375eacSRoger Pau Monné 23389e0f4d2SKip Macy u_int carrier; 234578e4bf7SJustin T. Gibbs u_int maxfrags; 23589e0f4d2SKip Macy 23689e0f4d2SKip Macy /* Receive-ring batched refills. */ 23789e0f4d2SKip Macy #define RX_MIN_TARGET 32 23889e0f4d2SKip Macy #define RX_MAX_TARGET NET_RX_RING_SIZE 2390e509842SJustin T. Gibbs int rx_min_target; 2400e509842SJustin T. Gibbs int rx_max_target; 24189e0f4d2SKip Macy 24223dc5621SKip Macy device_t xbdev; 24389e0f4d2SKip Macy uint8_t mac[ETHER_ADDR_LEN]; 24489e0f4d2SKip Macy 24589e0f4d2SKip Macy int xn_if_flags; 24689e0f4d2SKip Macy 2470e509842SJustin T. Gibbs struct ifmedia sc_media; 2486a8e9695SRoger Pau Monné 2496a8e9695SRoger Pau Monné bool xn_resume; 25089e0f4d2SKip Macy }; 25189e0f4d2SKip Macy 252*96375eacSRoger Pau Monné struct netfront_rx_info { 253*96375eacSRoger Pau Monné struct netif_rx_response rx; 254*96375eacSRoger Pau Monné struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; 255*96375eacSRoger Pau Monné }; 25689e0f4d2SKip Macy 257*96375eacSRoger Pau Monné #define XN_RX_LOCK(_q) mtx_lock(&(_q)->lock) 258*96375eacSRoger Pau Monné #define XN_RX_UNLOCK(_q) mtx_unlock(&(_q)->lock) 25989e0f4d2SKip Macy 260*96375eacSRoger Pau Monné #define XN_TX_LOCK(_q) mtx_lock(&(_q)->lock) 261*96375eacSRoger Pau Monné #define XN_TX_TRYLOCK(_q) mtx_trylock(&(_q)->lock) 262*96375eacSRoger Pau Monné #define XN_TX_UNLOCK(_q) mtx_unlock(&(_q)->lock) 26389e0f4d2SKip Macy 264227ca257SKip Macy #define XN_LOCK(_sc) mtx_lock(&(_sc)->sc_lock); 265227ca257SKip Macy #define XN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock); 26689e0f4d2SKip Macy 267227ca257SKip Macy #define XN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED); 268*96375eacSRoger Pau Monné #define XN_RX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); 269*96375eacSRoger Pau Monné #define XN_TX_LOCK_ASSERT(_q) mtx_assert(&(_q)->lock, MA_OWNED); 27089e0f4d2SKip Macy 27189e0f4d2SKip Macy #define netfront_carrier_on(netif) ((netif)->carrier = 1) 27289e0f4d2SKip Macy #define netfront_carrier_off(netif) ((netif)->carrier = 0) 27389e0f4d2SKip Macy #define netfront_carrier_ok(netif) ((netif)->carrier) 27489e0f4d2SKip Macy 27589e0f4d2SKip Macy /* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ 27689e0f4d2SKip Macy 27789e0f4d2SKip Macy static inline void 278931eeffaSKenneth D. Merry add_id_to_freelist(struct mbuf **list, uintptr_t id) 27989e0f4d2SKip Macy { 280*96375eacSRoger Pau Monné 281931eeffaSKenneth D. Merry KASSERT(id != 0, 282931eeffaSKenneth D. Merry ("%s: the head item (0) must always be free.", __func__)); 28389e0f4d2SKip Macy list[id] = list[0]; 284931eeffaSKenneth D. Merry list[0] = (struct mbuf *)id; 28589e0f4d2SKip Macy } 28689e0f4d2SKip Macy 28789e0f4d2SKip Macy static inline unsigned short 28889e0f4d2SKip Macy get_id_from_freelist(struct mbuf **list) 28989e0f4d2SKip Macy { 290931eeffaSKenneth D. Merry uintptr_t id; 291931eeffaSKenneth D. Merry 292931eeffaSKenneth D. Merry id = (uintptr_t)list[0]; 293931eeffaSKenneth D. Merry KASSERT(id != 0, 294931eeffaSKenneth D. Merry ("%s: the head item (0) must always remain free.", __func__)); 29589e0f4d2SKip Macy list[0] = list[id]; 29689e0f4d2SKip Macy return (id); 29789e0f4d2SKip Macy } 29889e0f4d2SKip Macy 29989e0f4d2SKip Macy static inline int 300*96375eacSRoger Pau Monné xn_rxidx(RING_IDX idx) 30189e0f4d2SKip Macy { 302*96375eacSRoger Pau Monné 30389e0f4d2SKip Macy return idx & (NET_RX_RING_SIZE - 1); 30489e0f4d2SKip Macy } 30589e0f4d2SKip Macy 30689e0f4d2SKip Macy static inline struct mbuf * 307*96375eacSRoger Pau Monné xn_get_rx_mbuf(struct netfront_rxq *rxq, RING_IDX ri) 30889e0f4d2SKip Macy { 309*96375eacSRoger Pau Monné int i; 31089e0f4d2SKip Macy struct mbuf *m; 31189e0f4d2SKip Macy 312*96375eacSRoger Pau Monné i = xn_rxidx(ri); 313*96375eacSRoger Pau Monné m = rxq->mbufs[i]; 314*96375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 31589e0f4d2SKip Macy return (m); 31689e0f4d2SKip Macy } 31789e0f4d2SKip Macy 31889e0f4d2SKip Macy static inline grant_ref_t 319*96375eacSRoger Pau Monné xn_get_rx_ref(struct netfront_rxq *rxq, RING_IDX ri) 32089e0f4d2SKip Macy { 321*96375eacSRoger Pau Monné int i = xn_rxidx(ri); 322*96375eacSRoger Pau Monné grant_ref_t ref = rxq->grant_ref[i]; 323*96375eacSRoger Pau Monné 324ff662b5cSJustin T. Gibbs KASSERT(ref != GRANT_REF_INVALID, ("Invalid grant reference!\n")); 325*96375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 326*96375eacSRoger Pau Monné return (ref); 32789e0f4d2SKip Macy } 32889e0f4d2SKip Macy 32989e0f4d2SKip Macy #define IPRINTK(fmt, args...) \ 33089e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 331227ca257SKip Macy #ifdef INVARIANTS 33289e0f4d2SKip Macy #define WPRINTK(fmt, args...) \ 33389e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 334227ca257SKip Macy #else 335227ca257SKip Macy #define WPRINTK(fmt, args...) 336227ca257SKip Macy #endif 337227ca257SKip Macy #ifdef DEBUG 33889e0f4d2SKip Macy #define DPRINTK(fmt, args...) \ 33923dc5621SKip Macy printf("[XEN] %s: " fmt, __func__, ##args) 34012678024SDoug Rabson #else 34112678024SDoug Rabson #define DPRINTK(fmt, args...) 34212678024SDoug Rabson #endif 34389e0f4d2SKip Macy 34489e0f4d2SKip Macy /** 34589e0f4d2SKip Macy * Read the 'mac' node at the given device's node in the store, and parse that 34689e0f4d2SKip Macy * as colon-separated octets, placing result the given mac array. mac must be 34789e0f4d2SKip Macy * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). 34889e0f4d2SKip Macy * Return 0 on success, or errno on error. 34989e0f4d2SKip Macy */ 35089e0f4d2SKip Macy static int 35123dc5621SKip Macy xen_net_read_mac(device_t dev, uint8_t mac[]) 35289e0f4d2SKip Macy { 3533a6d1fcfSKip Macy int error, i; 3543a6d1fcfSKip Macy char *s, *e, *macstr; 355ffa06904SJustin T. Gibbs const char *path; 3563a6d1fcfSKip Macy 357ffa06904SJustin T. Gibbs path = xenbus_get_node(dev); 358ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 359ffa06904SJustin T. Gibbs if (error == ENOENT) { 360ffa06904SJustin T. Gibbs /* 361ffa06904SJustin T. Gibbs * Deal with missing mac XenStore nodes on devices with 362ffa06904SJustin T. Gibbs * HVM emulation (the 'ioemu' configuration attribute) 363ffa06904SJustin T. Gibbs * enabled. 364ffa06904SJustin T. Gibbs * 365ffa06904SJustin T. Gibbs * The HVM emulator may execute in a stub device model 366ffa06904SJustin T. Gibbs * domain which lacks the permission, only given to Dom0, 367ffa06904SJustin T. Gibbs * to update the guest's XenStore tree. For this reason, 368ffa06904SJustin T. Gibbs * the HVM emulator doesn't even attempt to write the 369ffa06904SJustin T. Gibbs * front-side mac node, even when operating in Dom0. 370ffa06904SJustin T. Gibbs * However, there should always be a mac listed in the 371ffa06904SJustin T. Gibbs * backend tree. Fallback to this version if our query 372ffa06904SJustin T. Gibbs * of the front side XenStore location doesn't find 373ffa06904SJustin T. Gibbs * anything. 374ffa06904SJustin T. Gibbs */ 375ffa06904SJustin T. Gibbs path = xenbus_get_otherend_path(dev); 376ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 377ffa06904SJustin T. Gibbs } 378ffa06904SJustin T. Gibbs if (error != 0) { 379ffa06904SJustin T. Gibbs xenbus_dev_fatal(dev, error, "parsing %s/mac", path); 3803a6d1fcfSKip Macy return (error); 381ffa06904SJustin T. Gibbs } 3823a6d1fcfSKip Macy 38389e0f4d2SKip Macy s = macstr; 38489e0f4d2SKip Macy for (i = 0; i < ETHER_ADDR_LEN; i++) { 38589e0f4d2SKip Macy mac[i] = strtoul(s, &e, 16); 38689e0f4d2SKip Macy if (s == e || (e[0] != ':' && e[0] != 0)) { 387ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 3883a6d1fcfSKip Macy return (ENOENT); 38989e0f4d2SKip Macy } 39089e0f4d2SKip Macy s = &e[1]; 39189e0f4d2SKip Macy } 392ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 3933a6d1fcfSKip Macy return (0); 39489e0f4d2SKip Macy } 39589e0f4d2SKip Macy 39689e0f4d2SKip Macy /** 39789e0f4d2SKip Macy * Entry point to this code when a new device is created. Allocate the basic 39889e0f4d2SKip Macy * structures and the ring buffers for communication with the backend, and 39989e0f4d2SKip Macy * inform the backend of the appropriate details for those. Switch to 40089e0f4d2SKip Macy * Connected state. 40189e0f4d2SKip Macy */ 40289e0f4d2SKip Macy static int 40323dc5621SKip Macy netfront_probe(device_t dev) 40423dc5621SKip Macy { 40523dc5621SKip Macy 406f8f1bb83SRoger Pau Monné if (xen_hvm_domain() && xen_disable_pv_nics != 0) 407f8f1bb83SRoger Pau Monné return (ENXIO); 408f8f1bb83SRoger Pau Monné 40923dc5621SKip Macy if (!strcmp(xenbus_get_type(dev), "vif")) { 41023dc5621SKip Macy device_set_desc(dev, "Virtual Network Interface"); 41123dc5621SKip Macy return (0); 41223dc5621SKip Macy } 41323dc5621SKip Macy 41423dc5621SKip Macy return (ENXIO); 41523dc5621SKip Macy } 41623dc5621SKip Macy 41723dc5621SKip Macy static int 41823dc5621SKip Macy netfront_attach(device_t dev) 41989e0f4d2SKip Macy { 42089e0f4d2SKip Macy int err; 42189e0f4d2SKip Macy 42223dc5621SKip Macy err = create_netdev(dev); 423*96375eacSRoger Pau Monné if (err != 0) { 42489e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "creating netdev"); 425ffa06904SJustin T. Gibbs return (err); 42689e0f4d2SKip Macy } 42789e0f4d2SKip Macy 42812678024SDoug Rabson SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 42912678024SDoug Rabson SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 430f0188618SHans Petter Selasky OID_AUTO, "enable_lro", CTLFLAG_RW, 43112678024SDoug Rabson &xn_enable_lro, 0, "Large Receive Offload"); 43212678024SDoug Rabson 433*96375eacSRoger Pau Monné SYSCTL_ADD_ULONG(device_get_sysctl_ctx(dev), 434*96375eacSRoger Pau Monné SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 435*96375eacSRoger Pau Monné OID_AUTO, "num_queues", CTLFLAG_RD, 436*96375eacSRoger Pau Monné &xn_num_queues, "Number of pairs of queues"); 437*96375eacSRoger Pau Monné 438ffa06904SJustin T. Gibbs return (0); 43989e0f4d2SKip Macy } 44089e0f4d2SKip Macy 441cf9c09e1SJustin T. Gibbs static int 442cf9c09e1SJustin T. Gibbs netfront_suspend(device_t dev) 443cf9c09e1SJustin T. Gibbs { 444*96375eacSRoger Pau Monné struct netfront_info *np = device_get_softc(dev); 445*96375eacSRoger Pau Monné u_int i; 446cf9c09e1SJustin T. Gibbs 447*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 448*96375eacSRoger Pau Monné XN_RX_LOCK(&np->rxq[i]); 449*96375eacSRoger Pau Monné XN_TX_LOCK(&np->txq[i]); 450*96375eacSRoger Pau Monné } 451*96375eacSRoger Pau Monné netfront_carrier_off(np); 452*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 453*96375eacSRoger Pau Monné XN_RX_UNLOCK(&np->rxq[i]); 454*96375eacSRoger Pau Monné XN_TX_UNLOCK(&np->txq[i]); 455*96375eacSRoger Pau Monné } 456cf9c09e1SJustin T. Gibbs return (0); 457cf9c09e1SJustin T. Gibbs } 45889e0f4d2SKip Macy 45989e0f4d2SKip Macy /** 46089e0f4d2SKip Macy * We are reconnecting to the backend, due to a suspend/resume, or a backend 46189e0f4d2SKip Macy * driver restart. We tear down our netif structure and recreate it, but 46289e0f4d2SKip Macy * leave the device-layer structures intact so that this is transparent to the 46389e0f4d2SKip Macy * rest of the kernel. 46489e0f4d2SKip Macy */ 46589e0f4d2SKip Macy static int 46623dc5621SKip Macy netfront_resume(device_t dev) 46789e0f4d2SKip Macy { 46823dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 46989e0f4d2SKip Macy 4706a8e9695SRoger Pau Monné info->xn_resume = true; 47189e0f4d2SKip Macy netif_disconnect_backend(info); 47289e0f4d2SKip Macy return (0); 47389e0f4d2SKip Macy } 47489e0f4d2SKip Macy 475*96375eacSRoger Pau Monné static int 476*96375eacSRoger Pau Monné write_queue_xenstore_keys(device_t dev, 477*96375eacSRoger Pau Monné struct netfront_rxq *rxq, 478*96375eacSRoger Pau Monné struct netfront_txq *txq, 479*96375eacSRoger Pau Monné struct xs_transaction *xst, bool hierarchy) 480*96375eacSRoger Pau Monné { 481*96375eacSRoger Pau Monné int err; 482*96375eacSRoger Pau Monné const char *message; 483*96375eacSRoger Pau Monné const char *node = xenbus_get_node(dev); 484*96375eacSRoger Pau Monné char *path; 485*96375eacSRoger Pau Monné size_t path_size; 486*96375eacSRoger Pau Monné 487*96375eacSRoger Pau Monné KASSERT(rxq->id == txq->id, ("Mismatch between RX and TX queue ids")); 488*96375eacSRoger Pau Monné /* Split event channel support is not yet there. */ 489*96375eacSRoger Pau Monné KASSERT(rxq->xen_intr_handle == txq->xen_intr_handle, 490*96375eacSRoger Pau Monné ("Split event channels are not supported")); 491*96375eacSRoger Pau Monné 492*96375eacSRoger Pau Monné if (hierarchy) { 493*96375eacSRoger Pau Monné path_size = strlen(node) + 10; 494*96375eacSRoger Pau Monné path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); 495*96375eacSRoger Pau Monné snprintf(path, path_size, "%s/queue-%u", node, rxq->id); 496*96375eacSRoger Pau Monné } else { 497*96375eacSRoger Pau Monné path_size = strlen(node) + 1; 498*96375eacSRoger Pau Monné path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO); 499*96375eacSRoger Pau Monné snprintf(path, path_size, "%s", node); 500*96375eacSRoger Pau Monné } 501*96375eacSRoger Pau Monné 502*96375eacSRoger Pau Monné err = xs_printf(*xst, path, "tx-ring-ref","%u", txq->ring_ref); 503*96375eacSRoger Pau Monné if (err != 0) { 504*96375eacSRoger Pau Monné message = "writing tx ring-ref"; 505*96375eacSRoger Pau Monné goto error; 506*96375eacSRoger Pau Monné } 507*96375eacSRoger Pau Monné err = xs_printf(*xst, path, "rx-ring-ref","%u", rxq->ring_ref); 508*96375eacSRoger Pau Monné if (err != 0) { 509*96375eacSRoger Pau Monné message = "writing rx ring-ref"; 510*96375eacSRoger Pau Monné goto error; 511*96375eacSRoger Pau Monné } 512*96375eacSRoger Pau Monné err = xs_printf(*xst, path, "event-channel", "%u", 513*96375eacSRoger Pau Monné xen_intr_port(rxq->xen_intr_handle)); 514*96375eacSRoger Pau Monné if (err != 0) { 515*96375eacSRoger Pau Monné message = "writing event-channel"; 516*96375eacSRoger Pau Monné goto error; 517*96375eacSRoger Pau Monné } 518*96375eacSRoger Pau Monné 519*96375eacSRoger Pau Monné free(path, M_DEVBUF); 520*96375eacSRoger Pau Monné 521*96375eacSRoger Pau Monné return (0); 522*96375eacSRoger Pau Monné 523*96375eacSRoger Pau Monné error: 524*96375eacSRoger Pau Monné free(path, M_DEVBUF); 525*96375eacSRoger Pau Monné xenbus_dev_fatal(dev, err, "%s", message); 526*96375eacSRoger Pau Monné 527*96375eacSRoger Pau Monné return (err); 528*96375eacSRoger Pau Monné } 529*96375eacSRoger Pau Monné 53089e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */ 53189e0f4d2SKip Macy static int 53223dc5621SKip Macy talk_to_backend(device_t dev, struct netfront_info *info) 53389e0f4d2SKip Macy { 53489e0f4d2SKip Macy const char *message; 535ff662b5cSJustin T. Gibbs struct xs_transaction xst; 53623dc5621SKip Macy const char *node = xenbus_get_node(dev); 53789e0f4d2SKip Macy int err; 538*96375eacSRoger Pau Monné unsigned long num_queues, max_queues = 0; 539*96375eacSRoger Pau Monné unsigned int i; 54089e0f4d2SKip Macy 54189e0f4d2SKip Macy err = xen_net_read_mac(dev, info->mac); 542*96375eacSRoger Pau Monné if (err != 0) { 54323dc5621SKip Macy xenbus_dev_fatal(dev, err, "parsing %s/mac", node); 54489e0f4d2SKip Macy goto out; 54589e0f4d2SKip Macy } 54689e0f4d2SKip Macy 547*96375eacSRoger Pau Monné err = xs_scanf(XST_NIL, xenbus_get_otherend_path(info->xbdev), 548*96375eacSRoger Pau Monné "multi-queue-max-queues", NULL, "%lu", &max_queues); 549*96375eacSRoger Pau Monné if (err != 0) 550*96375eacSRoger Pau Monné max_queues = 1; 551*96375eacSRoger Pau Monné num_queues = xn_num_queues; 552*96375eacSRoger Pau Monné if (num_queues > max_queues) 553*96375eacSRoger Pau Monné num_queues = max_queues; 554*96375eacSRoger Pau Monné 555*96375eacSRoger Pau Monné err = setup_device(dev, info, num_queues); 556*96375eacSRoger Pau Monné if (err != 0) 55789e0f4d2SKip Macy goto out; 55889e0f4d2SKip Macy 55989e0f4d2SKip Macy again: 560ff662b5cSJustin T. Gibbs err = xs_transaction_start(&xst); 561*96375eacSRoger Pau Monné if (err != 0) { 56289e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "starting transaction"); 563*96375eacSRoger Pau Monné goto free; 56489e0f4d2SKip Macy } 565*96375eacSRoger Pau Monné 566*96375eacSRoger Pau Monné if (info->num_queues == 1) { 567*96375eacSRoger Pau Monné err = write_queue_xenstore_keys(dev, &info->rxq[0], 568*96375eacSRoger Pau Monné &info->txq[0], &xst, false); 569*96375eacSRoger Pau Monné if (err != 0) 570*96375eacSRoger Pau Monné goto abort_transaction_no_def_error; 571*96375eacSRoger Pau Monné } else { 572*96375eacSRoger Pau Monné err = xs_printf(xst, node, "multi-queue-num-queues", 573*96375eacSRoger Pau Monné "%u", info->num_queues); 574*96375eacSRoger Pau Monné if (err != 0) { 575*96375eacSRoger Pau Monné message = "writing multi-queue-num-queues"; 57689e0f4d2SKip Macy goto abort_transaction; 57789e0f4d2SKip Macy } 578*96375eacSRoger Pau Monné 579*96375eacSRoger Pau Monné for (i = 0; i < info->num_queues; i++) { 580*96375eacSRoger Pau Monné err = write_queue_xenstore_keys(dev, &info->rxq[i], 581*96375eacSRoger Pau Monné &info->txq[i], &xst, true); 582*96375eacSRoger Pau Monné if (err != 0) 583*96375eacSRoger Pau Monné goto abort_transaction_no_def_error; 58489e0f4d2SKip Macy } 58589e0f4d2SKip Macy } 586*96375eacSRoger Pau Monné 587d0f3a8b9SRoger Pau Monné err = xs_printf(xst, node, "request-rx-copy", "%u", 1); 588*96375eacSRoger Pau Monné if (err != 0) { 58989e0f4d2SKip Macy message = "writing request-rx-copy"; 59089e0f4d2SKip Macy goto abort_transaction; 59189e0f4d2SKip Macy } 592ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-rx-notify", "%d", 1); 593*96375eacSRoger Pau Monné if (err != 0) { 59489e0f4d2SKip Macy message = "writing feature-rx-notify"; 59589e0f4d2SKip Macy goto abort_transaction; 59689e0f4d2SKip Macy } 597ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-sg", "%d", 1); 598*96375eacSRoger Pau Monné if (err != 0) { 59989e0f4d2SKip Macy message = "writing feature-sg"; 60089e0f4d2SKip Macy goto abort_transaction; 60189e0f4d2SKip Macy } 602ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-gso-tcpv4", "%d", 1); 603*96375eacSRoger Pau Monné if (err != 0) { 60489e0f4d2SKip Macy message = "writing feature-gso-tcpv4"; 60589e0f4d2SKip Macy goto abort_transaction; 60689e0f4d2SKip Macy } 60789e0f4d2SKip Macy 608ff662b5cSJustin T. Gibbs err = xs_transaction_end(xst, 0); 609*96375eacSRoger Pau Monné if (err != 0) { 61089e0f4d2SKip Macy if (err == EAGAIN) 61189e0f4d2SKip Macy goto again; 61289e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "completing transaction"); 613*96375eacSRoger Pau Monné goto free; 61489e0f4d2SKip Macy } 61589e0f4d2SKip Macy 61689e0f4d2SKip Macy return 0; 61789e0f4d2SKip Macy 61889e0f4d2SKip Macy abort_transaction: 61989e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "%s", message); 620*96375eacSRoger Pau Monné abort_transaction_no_def_error: 621*96375eacSRoger Pau Monné xs_transaction_end(xst, 1); 622*96375eacSRoger Pau Monné free: 62389e0f4d2SKip Macy netif_free(info); 62489e0f4d2SKip Macy out: 625*96375eacSRoger Pau Monné return (err); 626*96375eacSRoger Pau Monné } 627*96375eacSRoger Pau Monné 628*96375eacSRoger Pau Monné static void 629*96375eacSRoger Pau Monné xn_rxq_tq_intr(void *xrxq, int pending) 630*96375eacSRoger Pau Monné { 631*96375eacSRoger Pau Monné struct netfront_rxq *rxq = xrxq; 632*96375eacSRoger Pau Monné 633*96375eacSRoger Pau Monné XN_RX_LOCK(rxq); 634*96375eacSRoger Pau Monné xn_rxeof(rxq); 635*96375eacSRoger Pau Monné XN_RX_UNLOCK(rxq); 636*96375eacSRoger Pau Monné } 637*96375eacSRoger Pau Monné 638*96375eacSRoger Pau Monné static void 639*96375eacSRoger Pau Monné xn_txq_start(struct netfront_txq *txq) 640*96375eacSRoger Pau Monné { 641*96375eacSRoger Pau Monné struct netfront_info *np = txq->info; 642*96375eacSRoger Pau Monné struct ifnet *ifp = np->xn_ifp; 643*96375eacSRoger Pau Monné 644*96375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 645*96375eacSRoger Pau Monné if (!drbr_empty(ifp, txq->br)) 646*96375eacSRoger Pau Monné xn_txq_mq_start_locked(txq, NULL); 647*96375eacSRoger Pau Monné } 648*96375eacSRoger Pau Monné 649*96375eacSRoger Pau Monné static void 650*96375eacSRoger Pau Monné xn_txq_tq_intr(void *xtxq, int pending) 651*96375eacSRoger Pau Monné { 652*96375eacSRoger Pau Monné struct netfront_txq *txq = xtxq; 653*96375eacSRoger Pau Monné 654*96375eacSRoger Pau Monné XN_TX_LOCK(txq); 655*96375eacSRoger Pau Monné if (RING_HAS_UNCONSUMED_RESPONSES(&txq->ring)) 656*96375eacSRoger Pau Monné xn_txeof(txq); 657*96375eacSRoger Pau Monné xn_txq_start(txq); 658*96375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 659*96375eacSRoger Pau Monné } 660*96375eacSRoger Pau Monné 661*96375eacSRoger Pau Monné static void 662*96375eacSRoger Pau Monné xn_txq_tq_deferred(void *xtxq, int pending) 663*96375eacSRoger Pau Monné { 664*96375eacSRoger Pau Monné struct netfront_txq *txq = xtxq; 665*96375eacSRoger Pau Monné 666*96375eacSRoger Pau Monné XN_TX_LOCK(txq); 667*96375eacSRoger Pau Monné xn_txq_start(txq); 668*96375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 669*96375eacSRoger Pau Monné } 670*96375eacSRoger Pau Monné 671*96375eacSRoger Pau Monné static void 672*96375eacSRoger Pau Monné disconnect_rxq(struct netfront_rxq *rxq) 673*96375eacSRoger Pau Monné { 674*96375eacSRoger Pau Monné 675*96375eacSRoger Pau Monné xn_release_rx_bufs(rxq); 676*96375eacSRoger Pau Monné gnttab_free_grant_references(rxq->gref_head); 677*96375eacSRoger Pau Monné gnttab_end_foreign_access_ref(rxq->ring_ref); 678*96375eacSRoger Pau Monné /* 679*96375eacSRoger Pau Monné * No split event channel support at the moment, handle will 680*96375eacSRoger Pau Monné * be unbound in tx. So no need to call xen_intr_unbind here, 681*96375eacSRoger Pau Monné * but we do want to reset the handler to 0. 682*96375eacSRoger Pau Monné */ 683*96375eacSRoger Pau Monné rxq->xen_intr_handle = 0; 684*96375eacSRoger Pau Monné } 685*96375eacSRoger Pau Monné 686*96375eacSRoger Pau Monné static void 687*96375eacSRoger Pau Monné destroy_rxq(struct netfront_rxq *rxq) 688*96375eacSRoger Pau Monné { 689*96375eacSRoger Pau Monné 690*96375eacSRoger Pau Monné free(rxq->ring.sring, M_DEVBUF); 691*96375eacSRoger Pau Monné taskqueue_drain_all(rxq->tq); 692*96375eacSRoger Pau Monné taskqueue_free(rxq->tq); 693*96375eacSRoger Pau Monné } 694*96375eacSRoger Pau Monné 695*96375eacSRoger Pau Monné static void 696*96375eacSRoger Pau Monné destroy_rxqs(struct netfront_info *np) 697*96375eacSRoger Pau Monné { 698*96375eacSRoger Pau Monné int i; 699*96375eacSRoger Pau Monné 700*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 701*96375eacSRoger Pau Monné destroy_rxq(&np->rxq[i]); 702*96375eacSRoger Pau Monné 703*96375eacSRoger Pau Monné free(np->rxq, M_DEVBUF); 704*96375eacSRoger Pau Monné np->rxq = NULL; 70589e0f4d2SKip Macy } 70689e0f4d2SKip Macy 70789e0f4d2SKip Macy static int 708*96375eacSRoger Pau Monné setup_rxqs(device_t dev, struct netfront_info *info, 709*96375eacSRoger Pau Monné unsigned long num_queues) 71089e0f4d2SKip Macy { 711*96375eacSRoger Pau Monné int q, i; 7123a6d1fcfSKip Macy int error; 713*96375eacSRoger Pau Monné netif_rx_sring_t *rxs; 714*96375eacSRoger Pau Monné struct netfront_rxq *rxq; 71589e0f4d2SKip Macy 716*96375eacSRoger Pau Monné info->rxq = malloc(sizeof(struct netfront_rxq) * num_queues, 717*96375eacSRoger Pau Monné M_DEVBUF, M_WAITOK|M_ZERO); 71889e0f4d2SKip Macy 719*96375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) { 720*96375eacSRoger Pau Monné rxq = &info->rxq[q]; 721*96375eacSRoger Pau Monné 722*96375eacSRoger Pau Monné rxq->id = q; 723*96375eacSRoger Pau Monné rxq->info = info; 724*96375eacSRoger Pau Monné rxq->target = RX_MIN_TARGET; 725*96375eacSRoger Pau Monné rxq->ring_ref = GRANT_REF_INVALID; 726*96375eacSRoger Pau Monné rxq->ring.sring = NULL; 727*96375eacSRoger Pau Monné snprintf(rxq->name, XN_QUEUE_NAME_LEN, "xnrx_%u", q); 728*96375eacSRoger Pau Monné mtx_init(&rxq->lock, rxq->name, "netfront receive lock", 729*96375eacSRoger Pau Monné MTX_DEF); 730*96375eacSRoger Pau Monné 731*96375eacSRoger Pau Monné for (i = 0; i <= NET_RX_RING_SIZE; i++) { 732*96375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 733*96375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 734*96375eacSRoger Pau Monné } 735*96375eacSRoger Pau Monné 736*96375eacSRoger Pau Monné mbufq_init(&rxq->batch, INT_MAX); 737*96375eacSRoger Pau Monné 738*96375eacSRoger Pau Monné /* Start resources allocation */ 739*96375eacSRoger Pau Monné 740*96375eacSRoger Pau Monné if (gnttab_alloc_grant_references(RX_MAX_TARGET, 741*96375eacSRoger Pau Monné &rxq->gref_head) != 0) { 742*96375eacSRoger Pau Monné device_printf(dev, "allocating rx gref"); 7433a6d1fcfSKip Macy error = ENOMEM; 74489e0f4d2SKip Macy goto fail; 74589e0f4d2SKip Macy } 74689e0f4d2SKip Macy 747*96375eacSRoger Pau Monné rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, 748*96375eacSRoger Pau Monné M_WAITOK|M_ZERO); 74989e0f4d2SKip Macy SHARED_RING_INIT(rxs); 750*96375eacSRoger Pau Monné FRONT_RING_INIT(&rxq->ring, rxs, PAGE_SIZE); 75189e0f4d2SKip Macy 752*96375eacSRoger Pau Monné error = xenbus_grant_ring(dev, virt_to_mfn(rxs), 753*96375eacSRoger Pau Monné &rxq->ring_ref); 754*96375eacSRoger Pau Monné if (error != 0) { 755*96375eacSRoger Pau Monné device_printf(dev, "granting rx ring page"); 756*96375eacSRoger Pau Monné goto fail_grant_ring; 757*96375eacSRoger Pau Monné } 75889e0f4d2SKip Macy 759*96375eacSRoger Pau Monné TASK_INIT(&rxq->intrtask, 0, xn_rxq_tq_intr, rxq); 760*96375eacSRoger Pau Monné rxq->tq = taskqueue_create_fast(rxq->name, M_WAITOK, 761*96375eacSRoger Pau Monné taskqueue_thread_enqueue, &rxq->tq); 76289e0f4d2SKip Macy 763*96375eacSRoger Pau Monné error = taskqueue_start_threads(&rxq->tq, 1, PI_NET, 764*96375eacSRoger Pau Monné "%s rxq %d", device_get_nameunit(dev), rxq->id); 765*96375eacSRoger Pau Monné if (error != 0) { 766*96375eacSRoger Pau Monné device_printf(dev, "failed to start rx taskq %d\n", 767*96375eacSRoger Pau Monné rxq->id); 768*96375eacSRoger Pau Monné goto fail_start_thread; 769*96375eacSRoger Pau Monné } 77089e0f4d2SKip Macy } 77189e0f4d2SKip Macy 7723a6d1fcfSKip Macy return (0); 77389e0f4d2SKip Macy 774*96375eacSRoger Pau Monné fail_start_thread: 775*96375eacSRoger Pau Monné gnttab_end_foreign_access_ref(rxq->ring_ref); 776*96375eacSRoger Pau Monné taskqueue_drain_all(rxq->tq); 777*96375eacSRoger Pau Monné taskqueue_free(rxq->tq); 778*96375eacSRoger Pau Monné fail_grant_ring: 779*96375eacSRoger Pau Monné gnttab_free_grant_references(rxq->gref_head); 780*96375eacSRoger Pau Monné free(rxq->ring.sring, M_DEVBUF); 78189e0f4d2SKip Macy fail: 782*96375eacSRoger Pau Monné for (; q >= 0; q--) { 783*96375eacSRoger Pau Monné disconnect_rxq(&info->rxq[q]); 784*96375eacSRoger Pau Monné destroy_rxq(&info->rxq[q]); 785*96375eacSRoger Pau Monné } 786*96375eacSRoger Pau Monné 787*96375eacSRoger Pau Monné free(info->rxq, M_DEVBUF); 788*96375eacSRoger Pau Monné return (error); 789*96375eacSRoger Pau Monné } 790*96375eacSRoger Pau Monné 791*96375eacSRoger Pau Monné static void 792*96375eacSRoger Pau Monné disconnect_txq(struct netfront_txq *txq) 793*96375eacSRoger Pau Monné { 794*96375eacSRoger Pau Monné 795*96375eacSRoger Pau Monné xn_release_tx_bufs(txq); 796*96375eacSRoger Pau Monné gnttab_free_grant_references(txq->gref_head); 797*96375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->ring_ref); 798*96375eacSRoger Pau Monné xen_intr_unbind(&txq->xen_intr_handle); 799*96375eacSRoger Pau Monné } 800*96375eacSRoger Pau Monné 801*96375eacSRoger Pau Monné static void 802*96375eacSRoger Pau Monné destroy_txq(struct netfront_txq *txq) 803*96375eacSRoger Pau Monné { 804*96375eacSRoger Pau Monné 805*96375eacSRoger Pau Monné free(txq->ring.sring, M_DEVBUF); 806*96375eacSRoger Pau Monné buf_ring_free(txq->br, M_DEVBUF); 807*96375eacSRoger Pau Monné taskqueue_drain_all(txq->tq); 808*96375eacSRoger Pau Monné taskqueue_free(txq->tq); 809*96375eacSRoger Pau Monné } 810*96375eacSRoger Pau Monné 811*96375eacSRoger Pau Monné static void 812*96375eacSRoger Pau Monné destroy_txqs(struct netfront_info *np) 813*96375eacSRoger Pau Monné { 814*96375eacSRoger Pau Monné int i; 815*96375eacSRoger Pau Monné 816*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 817*96375eacSRoger Pau Monné destroy_txq(&np->txq[i]); 818*96375eacSRoger Pau Monné 819*96375eacSRoger Pau Monné free(np->txq, M_DEVBUF); 820*96375eacSRoger Pau Monné np->txq = NULL; 821*96375eacSRoger Pau Monné } 822*96375eacSRoger Pau Monné 823*96375eacSRoger Pau Monné static int 824*96375eacSRoger Pau Monné setup_txqs(device_t dev, struct netfront_info *info, 825*96375eacSRoger Pau Monné unsigned long num_queues) 826*96375eacSRoger Pau Monné { 827*96375eacSRoger Pau Monné int q, i; 828*96375eacSRoger Pau Monné int error; 829*96375eacSRoger Pau Monné netif_tx_sring_t *txs; 830*96375eacSRoger Pau Monné struct netfront_txq *txq; 831*96375eacSRoger Pau Monné 832*96375eacSRoger Pau Monné info->txq = malloc(sizeof(struct netfront_txq) * num_queues, 833*96375eacSRoger Pau Monné M_DEVBUF, M_WAITOK|M_ZERO); 834*96375eacSRoger Pau Monné 835*96375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) { 836*96375eacSRoger Pau Monné txq = &info->txq[q]; 837*96375eacSRoger Pau Monné 838*96375eacSRoger Pau Monné txq->id = q; 839*96375eacSRoger Pau Monné txq->info = info; 840*96375eacSRoger Pau Monné 841*96375eacSRoger Pau Monné txq->ring_ref = GRANT_REF_INVALID; 842*96375eacSRoger Pau Monné txq->ring.sring = NULL; 843*96375eacSRoger Pau Monné 844*96375eacSRoger Pau Monné snprintf(txq->name, XN_QUEUE_NAME_LEN, "xntx_%u", q); 845*96375eacSRoger Pau Monné 846*96375eacSRoger Pau Monné mtx_init(&txq->lock, txq->name, "netfront transmit lock", 847*96375eacSRoger Pau Monné MTX_DEF); 848*96375eacSRoger Pau Monné 849*96375eacSRoger Pau Monné for (i = 0; i <= NET_TX_RING_SIZE; i++) { 850*96375eacSRoger Pau Monné txq->mbufs[i] = (void *) ((u_long) i+1); 851*96375eacSRoger Pau Monné txq->grant_ref[i] = GRANT_REF_INVALID; 852*96375eacSRoger Pau Monné } 853*96375eacSRoger Pau Monné txq->mbufs[NET_TX_RING_SIZE] = (void *)0; 854*96375eacSRoger Pau Monné 855*96375eacSRoger Pau Monné /* Start resources allocation. */ 856*96375eacSRoger Pau Monné 857*96375eacSRoger Pau Monné if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, 858*96375eacSRoger Pau Monné &txq->gref_head) != 0) { 859*96375eacSRoger Pau Monné device_printf(dev, "failed to allocate tx grant refs\n"); 860*96375eacSRoger Pau Monné error = ENOMEM; 861*96375eacSRoger Pau Monné goto fail; 862*96375eacSRoger Pau Monné } 863*96375eacSRoger Pau Monné 864*96375eacSRoger Pau Monné txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, 865*96375eacSRoger Pau Monné M_WAITOK|M_ZERO); 866*96375eacSRoger Pau Monné SHARED_RING_INIT(txs); 867*96375eacSRoger Pau Monné FRONT_RING_INIT(&txq->ring, txs, PAGE_SIZE); 868*96375eacSRoger Pau Monné 869*96375eacSRoger Pau Monné error = xenbus_grant_ring(dev, virt_to_mfn(txs), 870*96375eacSRoger Pau Monné &txq->ring_ref); 871*96375eacSRoger Pau Monné if (error != 0) { 872*96375eacSRoger Pau Monné device_printf(dev, "failed to grant tx ring\n"); 873*96375eacSRoger Pau Monné goto fail_grant_ring; 874*96375eacSRoger Pau Monné } 875*96375eacSRoger Pau Monné 876*96375eacSRoger Pau Monné txq->br = buf_ring_alloc(NET_TX_RING_SIZE, M_DEVBUF, 877*96375eacSRoger Pau Monné M_WAITOK, &txq->lock); 878*96375eacSRoger Pau Monné TASK_INIT(&txq->defrtask, 0, xn_txq_tq_deferred, txq); 879*96375eacSRoger Pau Monné TASK_INIT(&txq->intrtask, 0, xn_txq_tq_intr, txq); 880*96375eacSRoger Pau Monné 881*96375eacSRoger Pau Monné txq->tq = taskqueue_create_fast(txq->name, M_WAITOK, 882*96375eacSRoger Pau Monné taskqueue_thread_enqueue, &txq->tq); 883*96375eacSRoger Pau Monné 884*96375eacSRoger Pau Monné error = taskqueue_start_threads(&txq->tq, 1, PI_NET, 885*96375eacSRoger Pau Monné "%s txq %d", device_get_nameunit(dev), txq->id); 886*96375eacSRoger Pau Monné if (error != 0) { 887*96375eacSRoger Pau Monné device_printf(dev, "failed to start tx taskq %d\n", 888*96375eacSRoger Pau Monné txq->id); 889*96375eacSRoger Pau Monné goto fail_start_thread; 890*96375eacSRoger Pau Monné } 891*96375eacSRoger Pau Monné 892*96375eacSRoger Pau Monné error = xen_intr_alloc_and_bind_local_port(dev, 893*96375eacSRoger Pau Monné xenbus_get_otherend_id(dev), xn_intr, /* handler */ NULL, 894*96375eacSRoger Pau Monné &info->txq[q], 895*96375eacSRoger Pau Monné INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY, 896*96375eacSRoger Pau Monné &txq->xen_intr_handle); 897*96375eacSRoger Pau Monné 898*96375eacSRoger Pau Monné if (error != 0) { 899*96375eacSRoger Pau Monné device_printf(dev, "xen_intr_alloc_and_bind_local_port failed\n"); 900*96375eacSRoger Pau Monné goto fail_bind_port; 901*96375eacSRoger Pau Monné } 902*96375eacSRoger Pau Monné } 903*96375eacSRoger Pau Monné 904*96375eacSRoger Pau Monné return (0); 905*96375eacSRoger Pau Monné 906*96375eacSRoger Pau Monné fail_bind_port: 907*96375eacSRoger Pau Monné taskqueue_drain_all(txq->tq); 908*96375eacSRoger Pau Monné fail_start_thread: 909*96375eacSRoger Pau Monné gnttab_free_grant_references(txq->gref_head); 910*96375eacSRoger Pau Monné free(txq->ring.sring, M_DEVBUF); 911*96375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->ring_ref); 912*96375eacSRoger Pau Monné buf_ring_free(txq->br, M_DEVBUF); 913*96375eacSRoger Pau Monné taskqueue_free(txq->tq); 914*96375eacSRoger Pau Monné fail_grant_ring: 915*96375eacSRoger Pau Monné gnttab_free_grant_references(txq->gref_head); 916*96375eacSRoger Pau Monné free(txq->ring.sring, M_DEVBUF); 917*96375eacSRoger Pau Monné fail: 918*96375eacSRoger Pau Monné for (; q >= 0; q--) { 919*96375eacSRoger Pau Monné disconnect_txq(&info->txq[q]); 920*96375eacSRoger Pau Monné destroy_txq(&info->txq[q]); 921*96375eacSRoger Pau Monné } 922*96375eacSRoger Pau Monné 923*96375eacSRoger Pau Monné free(info->txq, M_DEVBUF); 924*96375eacSRoger Pau Monné return (error); 925*96375eacSRoger Pau Monné } 926*96375eacSRoger Pau Monné 927*96375eacSRoger Pau Monné static int 928*96375eacSRoger Pau Monné setup_device(device_t dev, struct netfront_info *info, 929*96375eacSRoger Pau Monné unsigned long num_queues) 930*96375eacSRoger Pau Monné { 931*96375eacSRoger Pau Monné int error; 932*96375eacSRoger Pau Monné int q; 933*96375eacSRoger Pau Monné 934*96375eacSRoger Pau Monné if (info->txq) 935*96375eacSRoger Pau Monné destroy_txqs(info); 936*96375eacSRoger Pau Monné 937*96375eacSRoger Pau Monné if (info->rxq) 938*96375eacSRoger Pau Monné destroy_rxqs(info); 939*96375eacSRoger Pau Monné 940*96375eacSRoger Pau Monné info->num_queues = 0; 941*96375eacSRoger Pau Monné 942*96375eacSRoger Pau Monné error = setup_rxqs(dev, info, num_queues); 943*96375eacSRoger Pau Monné if (error != 0) 944*96375eacSRoger Pau Monné goto out; 945*96375eacSRoger Pau Monné error = setup_txqs(dev, info, num_queues); 946*96375eacSRoger Pau Monné if (error != 0) 947*96375eacSRoger Pau Monné goto out; 948*96375eacSRoger Pau Monné 949*96375eacSRoger Pau Monné info->num_queues = num_queues; 950*96375eacSRoger Pau Monné 951*96375eacSRoger Pau Monné /* No split event channel at the moment. */ 952*96375eacSRoger Pau Monné for (q = 0; q < num_queues; q++) 953*96375eacSRoger Pau Monné info->rxq[q].xen_intr_handle = info->txq[q].xen_intr_handle; 954*96375eacSRoger Pau Monné 955*96375eacSRoger Pau Monné return (0); 956*96375eacSRoger Pau Monné 957*96375eacSRoger Pau Monné out: 958*96375eacSRoger Pau Monné KASSERT(error != 0, ("Error path taken without providing an error code")); 9593a6d1fcfSKip Macy return (error); 96089e0f4d2SKip Macy } 96189e0f4d2SKip Macy 962a0ae8f04SBjoern A. Zeeb #ifdef INET 96389e0f4d2SKip Macy /** 96412678024SDoug Rabson * If this interface has an ipv4 address, send an arp for it. This 96512678024SDoug Rabson * helps to get the network going again after migrating hosts. 96612678024SDoug Rabson */ 96712678024SDoug Rabson static void 96812678024SDoug Rabson netfront_send_fake_arp(device_t dev, struct netfront_info *info) 96912678024SDoug Rabson { 97012678024SDoug Rabson struct ifnet *ifp; 97112678024SDoug Rabson struct ifaddr *ifa; 97212678024SDoug Rabson 97312678024SDoug Rabson ifp = info->xn_ifp; 97412678024SDoug Rabson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 97512678024SDoug Rabson if (ifa->ifa_addr->sa_family == AF_INET) { 97612678024SDoug Rabson arp_ifinit(ifp, ifa); 97712678024SDoug Rabson } 97812678024SDoug Rabson } 97912678024SDoug Rabson } 980a0ae8f04SBjoern A. Zeeb #endif 98112678024SDoug Rabson 98212678024SDoug Rabson /** 98389e0f4d2SKip Macy * Callback received when the backend's state changes. 98489e0f4d2SKip Macy */ 985283d6f72SJustin T. Gibbs static void 98623dc5621SKip Macy netfront_backend_changed(device_t dev, XenbusState newstate) 98789e0f4d2SKip Macy { 98823dc5621SKip Macy struct netfront_info *sc = device_get_softc(dev); 98989e0f4d2SKip Macy 99023dc5621SKip Macy DPRINTK("newstate=%d\n", newstate); 99189e0f4d2SKip Macy 99223dc5621SKip Macy switch (newstate) { 99389e0f4d2SKip Macy case XenbusStateInitialising: 99489e0f4d2SKip Macy case XenbusStateInitialised: 99589e0f4d2SKip Macy case XenbusStateUnknown: 99689e0f4d2SKip Macy case XenbusStateClosed: 997920ba15bSKip Macy case XenbusStateReconfigured: 998920ba15bSKip Macy case XenbusStateReconfiguring: 99989e0f4d2SKip Macy break; 100089e0f4d2SKip Macy case XenbusStateInitWait: 100123dc5621SKip Macy if (xenbus_get_state(dev) != XenbusStateInitialising) 100289e0f4d2SKip Macy break; 1003*96375eacSRoger Pau Monné if (xn_connect(sc) != 0) 100489e0f4d2SKip Macy break; 100523dc5621SKip Macy xenbus_set_state(dev, XenbusStateConnected); 100623dc5621SKip Macy break; 100789e0f4d2SKip Macy case XenbusStateClosing: 100823dc5621SKip Macy xenbus_set_state(dev, XenbusStateClosed); 100989e0f4d2SKip Macy break; 1010dbf82bdeSRoger Pau Monné case XenbusStateConnected: 1011dbf82bdeSRoger Pau Monné #ifdef INET 1012dbf82bdeSRoger Pau Monné netfront_send_fake_arp(dev, sc); 1013dbf82bdeSRoger Pau Monné #endif 1014dbf82bdeSRoger Pau Monné break; 101589e0f4d2SKip Macy } 101689e0f4d2SKip Macy } 101789e0f4d2SKip Macy 1018931eeffaSKenneth D. Merry /** 1019931eeffaSKenneth D. Merry * \brief Verify that there is sufficient space in the Tx ring 1020931eeffaSKenneth D. Merry * buffer for a maximally sized request to be enqueued. 1021c099cafaSAdrian Chadd * 1022931eeffaSKenneth D. Merry * A transmit request requires a transmit descriptor for each packet 1023931eeffaSKenneth D. Merry * fragment, plus up to 2 entries for "options" (e.g. TSO). 1024c099cafaSAdrian Chadd */ 102589e0f4d2SKip Macy static inline int 1026*96375eacSRoger Pau Monné xn_tx_slot_available(struct netfront_txq *txq) 102789e0f4d2SKip Macy { 1028*96375eacSRoger Pau Monné 1029*96375eacSRoger Pau Monné return (RING_FREE_REQUESTS(&txq->ring) > (MAX_TX_REQ_FRAGS + 2)); 103089e0f4d2SKip Macy } 1031931eeffaSKenneth D. Merry 103289e0f4d2SKip Macy static void 1033*96375eacSRoger Pau Monné xn_release_tx_bufs(struct netfront_txq *txq) 103489e0f4d2SKip Macy { 103589e0f4d2SKip Macy int i; 103689e0f4d2SKip Macy 103789e0f4d2SKip Macy for (i = 1; i <= NET_TX_RING_SIZE; i++) { 1038931eeffaSKenneth D. Merry struct mbuf *m; 103989e0f4d2SKip Macy 1040*96375eacSRoger Pau Monné m = txq->mbufs[i]; 1041931eeffaSKenneth D. Merry 1042931eeffaSKenneth D. Merry /* 1043931eeffaSKenneth D. Merry * We assume that no kernel addresses are 1044931eeffaSKenneth D. Merry * less than NET_TX_RING_SIZE. Any entry 1045931eeffaSKenneth D. Merry * in the table that is below this number 1046931eeffaSKenneth D. Merry * must be an index from free-list tracking. 1047931eeffaSKenneth D. Merry */ 1048931eeffaSKenneth D. Merry if (((uintptr_t)m) <= NET_TX_RING_SIZE) 104989e0f4d2SKip Macy continue; 1050*96375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->grant_ref[i]); 1051*96375eacSRoger Pau Monné gnttab_release_grant_reference(&txq->gref_head, 1052*96375eacSRoger Pau Monné txq->grant_ref[i]); 1053*96375eacSRoger Pau Monné txq->grant_ref[i] = GRANT_REF_INVALID; 1054*96375eacSRoger Pau Monné add_id_to_freelist(txq->mbufs, i); 1055*96375eacSRoger Pau Monné txq->mbufs_cnt--; 1056*96375eacSRoger Pau Monné if (txq->mbufs_cnt < 0) { 10576f9767acSMarius Strobl panic("%s: tx_chain_cnt must be >= 0", __func__); 1058a4ec37f5SAdrian Chadd } 1059cf9c09e1SJustin T. Gibbs m_free(m); 106089e0f4d2SKip Macy } 106189e0f4d2SKip Macy } 106289e0f4d2SKip Macy 106389e0f4d2SKip Macy static void 1064*96375eacSRoger Pau Monné xn_alloc_rx_buffers(struct netfront_rxq *rxq) 106589e0f4d2SKip Macy { 1066*96375eacSRoger Pau Monné struct netfront_info *np = rxq->info; 1067*96375eacSRoger Pau Monné int otherend_id = xenbus_get_otherend_id(np->xbdev); 106889e0f4d2SKip Macy unsigned short id; 106989e0f4d2SKip Macy struct mbuf *m_new; 107089e0f4d2SKip Macy int i, batch_target, notify; 107189e0f4d2SKip Macy RING_IDX req_prod; 107289e0f4d2SKip Macy grant_ref_t ref; 107389e0f4d2SKip Macy netif_rx_request_t *req; 107489e0f4d2SKip Macy vm_offset_t vaddr; 107589e0f4d2SKip Macy u_long pfn; 107689e0f4d2SKip Macy 1077*96375eacSRoger Pau Monné req_prod = rxq->ring.req_prod_pvt; 107889e0f4d2SKip Macy 1079*96375eacSRoger Pau Monné if (__predict_false(np->carrier == 0)) 108089e0f4d2SKip Macy return; 108189e0f4d2SKip Macy 108289e0f4d2SKip Macy /* 1083931eeffaSKenneth D. Merry * Allocate mbufs greedily, even though we batch updates to the 108489e0f4d2SKip Macy * receive ring. This creates a less bursty demand on the memory 1085931eeffaSKenneth D. Merry * allocator, and so should reduce the chance of failed allocation 108689e0f4d2SKip Macy * requests both for ourself and for other kernel subsystems. 1087931eeffaSKenneth D. Merry * 1088931eeffaSKenneth D. Merry * Here we attempt to maintain rx_target buffers in flight, counting 1089931eeffaSKenneth D. Merry * buffers that we have yet to process in the receive ring. 109089e0f4d2SKip Macy */ 1091*96375eacSRoger Pau Monné batch_target = rxq->target - (req_prod - rxq->ring.rsp_cons); 1092*96375eacSRoger Pau Monné for (i = mbufq_len(&rxq->batch); i < batch_target; i++) { 1093c2d9c6f0SGleb Smirnoff m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 1094931eeffaSKenneth D. Merry if (m_new == NULL) { 109589e0f4d2SKip Macy if (i != 0) 109689e0f4d2SKip Macy goto refill; 1097*96375eacSRoger Pau Monné /* XXX set timer */ 109889e0f4d2SKip Macy break; 109989e0f4d2SKip Macy } 110089e0f4d2SKip Macy m_new->m_len = m_new->m_pkthdr.len = MJUMPAGESIZE; 110189e0f4d2SKip Macy 110289e0f4d2SKip Macy /* queue the mbufs allocated */ 1103*96375eacSRoger Pau Monné mbufq_enqueue(&rxq->batch, m_new); 110489e0f4d2SKip Macy } 110589e0f4d2SKip Macy 1106931eeffaSKenneth D. Merry /* 1107931eeffaSKenneth D. Merry * If we've allocated at least half of our target number of entries, 1108931eeffaSKenneth D. Merry * submit them to the backend - we have enough to make the overhead 1109931eeffaSKenneth D. Merry * of submission worthwhile. Otherwise wait for more mbufs and 1110931eeffaSKenneth D. Merry * request entries to become available. 1111931eeffaSKenneth D. Merry */ 1112*96375eacSRoger Pau Monné if (i < (rxq->target/2)) { 1113*96375eacSRoger Pau Monné if (req_prod > rxq->ring.sring->req_prod) 111489e0f4d2SKip Macy goto push; 111589e0f4d2SKip Macy return; 111689e0f4d2SKip Macy } 1117931eeffaSKenneth D. Merry 1118931eeffaSKenneth D. Merry /* 1119931eeffaSKenneth D. Merry * Double floating fill target if we risked having the backend 1120931eeffaSKenneth D. Merry * run out of empty buffers for receive traffic. We define "running 1121931eeffaSKenneth D. Merry * low" as having less than a fourth of our target buffers free 1122931eeffaSKenneth D. Merry * at the time we refilled the queue. 1123931eeffaSKenneth D. Merry */ 1124*96375eacSRoger Pau Monné if ((req_prod - rxq->ring.sring->rsp_prod) < (rxq->target / 4)) { 1125*96375eacSRoger Pau Monné rxq->target *= 2; 1126*96375eacSRoger Pau Monné if (rxq->target > np->rx_max_target) 1127*96375eacSRoger Pau Monné rxq->target = np->rx_max_target; 1128931eeffaSKenneth D. Merry } 112989e0f4d2SKip Macy 113089e0f4d2SKip Macy refill: 1131d0f3a8b9SRoger Pau Monné for (i = 0; ; i++) { 1132*96375eacSRoger Pau Monné if ((m_new = mbufq_dequeue(&rxq->batch)) == NULL) 113389e0f4d2SKip Macy break; 113489e0f4d2SKip Macy 113589e0f4d2SKip Macy m_new->m_ext.ext_arg1 = (vm_paddr_t *)(uintptr_t)( 113689e0f4d2SKip Macy vtophys(m_new->m_ext.ext_buf) >> PAGE_SHIFT); 113789e0f4d2SKip Macy 1138*96375eacSRoger Pau Monné id = xn_rxidx(req_prod + i); 113989e0f4d2SKip Macy 1140*96375eacSRoger Pau Monné KASSERT(rxq->mbufs[id] == NULL, ("non-NULL xn_rx_chain")); 1141*96375eacSRoger Pau Monné rxq->mbufs[id] = m_new; 114289e0f4d2SKip Macy 1143*96375eacSRoger Pau Monné ref = gnttab_claim_grant_reference(&rxq->gref_head); 1144ff662b5cSJustin T. Gibbs KASSERT(ref != GNTTAB_LIST_END, 1145ff662b5cSJustin T. Gibbs ("reserved grant references exhuasted")); 1146*96375eacSRoger Pau Monné rxq->grant_ref[id] = ref; 114789e0f4d2SKip Macy 114889e0f4d2SKip Macy vaddr = mtod(m_new, vm_offset_t); 114989e0f4d2SKip Macy pfn = vtophys(vaddr) >> PAGE_SHIFT; 1150*96375eacSRoger Pau Monné req = RING_GET_REQUEST(&rxq->ring, req_prod + i); 115189e0f4d2SKip Macy 1152d0f3a8b9SRoger Pau Monné gnttab_grant_foreign_access_ref(ref, otherend_id, pfn, 0); 115389e0f4d2SKip Macy req->id = id; 115489e0f4d2SKip Macy req->gref = ref; 115589e0f4d2SKip Macy 1156*96375eacSRoger Pau Monné rxq->pfn_array[i] = 11573c790178SJohn Baldwin vtophys(mtod(m_new,vm_offset_t)) >> PAGE_SHIFT; 115889e0f4d2SKip Macy } 115989e0f4d2SKip Macy 116089e0f4d2SKip Macy KASSERT(i, ("no mbufs processed")); /* should have returned earlier */ 1161*96375eacSRoger Pau Monné KASSERT(mbufq_len(&rxq->batch) == 0, ("not all mbufs processed")); 116289e0f4d2SKip Macy /* 116389e0f4d2SKip Macy * We may have allocated buffers which have entries outstanding 116489e0f4d2SKip Macy * in the page * update queue -- make sure we flush those first! 116589e0f4d2SKip Macy */ 116689e0f4d2SKip Macy wmb(); 116789e0f4d2SKip Macy 116889e0f4d2SKip Macy /* Above is a suitable barrier to ensure backend will see requests. */ 1169*96375eacSRoger Pau Monné rxq->ring.req_prod_pvt = req_prod + i; 117089e0f4d2SKip Macy push: 1171*96375eacSRoger Pau Monné RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&rxq->ring, notify); 117289e0f4d2SKip Macy if (notify) 1173*96375eacSRoger Pau Monné xen_intr_signal(rxq->xen_intr_handle); 117489e0f4d2SKip Macy } 117589e0f4d2SKip Macy 117689e0f4d2SKip Macy static void 1177*96375eacSRoger Pau Monné xn_release_rx_bufs(struct netfront_rxq *rxq) 1178*96375eacSRoger Pau Monné { 1179*96375eacSRoger Pau Monné int i, ref; 1180*96375eacSRoger Pau Monné struct mbuf *m; 1181*96375eacSRoger Pau Monné 1182*96375eacSRoger Pau Monné for (i = 0; i < NET_RX_RING_SIZE; i++) { 1183*96375eacSRoger Pau Monné m = rxq->mbufs[i]; 1184*96375eacSRoger Pau Monné 1185*96375eacSRoger Pau Monné if (m == NULL) 1186*96375eacSRoger Pau Monné continue; 1187*96375eacSRoger Pau Monné 1188*96375eacSRoger Pau Monné ref = rxq->grant_ref[i]; 1189*96375eacSRoger Pau Monné if (ref == GRANT_REF_INVALID) 1190*96375eacSRoger Pau Monné continue; 1191*96375eacSRoger Pau Monné 1192*96375eacSRoger Pau Monné gnttab_end_foreign_access_ref(ref); 1193*96375eacSRoger Pau Monné gnttab_release_grant_reference(&rxq->gref_head, ref); 1194*96375eacSRoger Pau Monné rxq->mbufs[i] = NULL; 1195*96375eacSRoger Pau Monné rxq->grant_ref[i] = GRANT_REF_INVALID; 1196*96375eacSRoger Pau Monné m_freem(m); 1197*96375eacSRoger Pau Monné } 1198*96375eacSRoger Pau Monné } 1199*96375eacSRoger Pau Monné 1200*96375eacSRoger Pau Monné static void 1201*96375eacSRoger Pau Monné xn_rxeof(struct netfront_rxq *rxq) 120289e0f4d2SKip Macy { 120389e0f4d2SKip Macy struct ifnet *ifp; 1204*96375eacSRoger Pau Monné struct netfront_info *np = rxq->info; 12053778878dSRoger Pau Monné #if (defined(INET) || defined(INET6)) 1206*96375eacSRoger Pau Monné struct lro_ctrl *lro = &rxq->lro; 120712678024SDoug Rabson struct lro_entry *queued; 12083778878dSRoger Pau Monné #endif 120989e0f4d2SKip Macy struct netfront_rx_info rinfo; 121089e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo.rx; 121189e0f4d2SKip Macy struct netif_extra_info *extras = rinfo.extras; 121289e0f4d2SKip Macy RING_IDX i, rp; 121389e0f4d2SKip Macy struct mbuf *m; 1214*96375eacSRoger Pau Monné struct mbufq mbufq_rxq, mbufq_errq; 1215d0f3a8b9SRoger Pau Monné int err, work_to_do; 121689e0f4d2SKip Macy 121749906218SDoug Rabson do { 1218*96375eacSRoger Pau Monné XN_RX_LOCK_ASSERT(rxq); 121989e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 122089e0f4d2SKip Macy return; 122189e0f4d2SKip Macy 1222c578b6acSGleb Smirnoff /* XXX: there should be some sane limit. */ 1223*96375eacSRoger Pau Monné mbufq_init(&mbufq_errq, INT_MAX); 1224*96375eacSRoger Pau Monné mbufq_init(&mbufq_rxq, INT_MAX); 122589e0f4d2SKip Macy 122689e0f4d2SKip Macy ifp = np->xn_ifp; 122789e0f4d2SKip Macy 1228*96375eacSRoger Pau Monné rp = rxq->ring.sring->rsp_prod; 122989e0f4d2SKip Macy rmb(); /* Ensure we see queued responses up to 'rp'. */ 123089e0f4d2SKip Macy 1231*96375eacSRoger Pau Monné i = rxq->ring.rsp_cons; 123289e0f4d2SKip Macy while ((i != rp)) { 1233*96375eacSRoger Pau Monné memcpy(rx, RING_GET_RESPONSE(&rxq->ring, i), sizeof(*rx)); 123489e0f4d2SKip Macy memset(extras, 0, sizeof(rinfo.extras)); 123589e0f4d2SKip Macy 123683b92f6eSKip Macy m = NULL; 1237*96375eacSRoger Pau Monné err = xn_get_responses(rxq, &rinfo, rp, &i, &m); 123889e0f4d2SKip Macy 123976acc41fSJustin T. Gibbs if (__predict_false(err)) { 124083b92f6eSKip Macy if (m) 1241*96375eacSRoger Pau Monné (void )mbufq_enqueue(&mbufq_errq, m); 1242*96375eacSRoger Pau Monné rxq->stats.rx_errors++; 124389e0f4d2SKip Macy continue; 124489e0f4d2SKip Macy } 124589e0f4d2SKip Macy 124689e0f4d2SKip Macy m->m_pkthdr.rcvif = ifp; 124789e0f4d2SKip Macy if ( rx->flags & NETRXF_data_validated ) { 124889e0f4d2SKip Macy /* Tell the stack the checksums are okay */ 124989e0f4d2SKip Macy /* 125089e0f4d2SKip Macy * XXX this isn't necessarily the case - need to add 125189e0f4d2SKip Macy * check 125289e0f4d2SKip Macy */ 125389e0f4d2SKip Macy 125489e0f4d2SKip Macy m->m_pkthdr.csum_flags |= 125589e0f4d2SKip Macy (CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID 125689e0f4d2SKip Macy | CSUM_PSEUDO_HDR); 125789e0f4d2SKip Macy m->m_pkthdr.csum_data = 0xffff; 125889e0f4d2SKip Macy } 125989e0f4d2SKip Macy 1260*96375eacSRoger Pau Monné rxq->stats.rx_packets++; 1261*96375eacSRoger Pau Monné rxq->stats.rx_bytes += m->m_pkthdr.len; 126289e0f4d2SKip Macy 1263*96375eacSRoger Pau Monné (void )mbufq_enqueue(&mbufq_rxq, m); 1264*96375eacSRoger Pau Monné rxq->ring.rsp_cons = i; 126589e0f4d2SKip Macy } 126689e0f4d2SKip Macy 1267*96375eacSRoger Pau Monné mbufq_drain(&mbufq_errq); 126889e0f4d2SKip Macy 126989e0f4d2SKip Macy /* 127089e0f4d2SKip Macy * Process all the mbufs after the remapping is complete. 127189e0f4d2SKip Macy * Break the mbuf chain first though. 127289e0f4d2SKip Macy */ 1273*96375eacSRoger Pau Monné while ((m = mbufq_dequeue(&mbufq_rxq)) != NULL) { 1274c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 127589e0f4d2SKip Macy 1276*96375eacSRoger Pau Monné /* XXX: Do we really need to drop the rx lock? */ 1277*96375eacSRoger Pau Monné XN_RX_UNLOCK(rxq); 127808c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 127912678024SDoug Rabson /* Use LRO if possible */ 128012678024SDoug Rabson if ((ifp->if_capenable & IFCAP_LRO) == 0 || 128112678024SDoug Rabson lro->lro_cnt == 0 || tcp_lro_rx(lro, m, 0)) { 128212678024SDoug Rabson /* 128312678024SDoug Rabson * If LRO fails, pass up to the stack 128412678024SDoug Rabson * directly. 128512678024SDoug Rabson */ 128689e0f4d2SKip Macy (*ifp->if_input)(ifp, m); 128712678024SDoug Rabson } 128812678024SDoug Rabson #else 128912678024SDoug Rabson (*ifp->if_input)(ifp, m); 129012678024SDoug Rabson #endif 1291*96375eacSRoger Pau Monné 1292*96375eacSRoger Pau Monné XN_RX_LOCK(rxq); 129389e0f4d2SKip Macy } 129489e0f4d2SKip Macy 1295*96375eacSRoger Pau Monné rxq->ring.rsp_cons = i; 129689e0f4d2SKip Macy 129708c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 129812678024SDoug Rabson /* 129912678024SDoug Rabson * Flush any outstanding LRO work 130012678024SDoug Rabson */ 130112678024SDoug Rabson while (!SLIST_EMPTY(&lro->lro_active)) { 130212678024SDoug Rabson queued = SLIST_FIRST(&lro->lro_active); 130312678024SDoug Rabson SLIST_REMOVE_HEAD(&lro->lro_active, next); 130412678024SDoug Rabson tcp_lro_flush(lro, queued); 130512678024SDoug Rabson } 130612678024SDoug Rabson #endif 130712678024SDoug Rabson 1308*96375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 130989e0f4d2SKip Macy 1310*96375eacSRoger Pau Monné RING_FINAL_CHECK_FOR_RESPONSES(&rxq->ring, work_to_do); 131149906218SDoug Rabson } while (work_to_do); 131289e0f4d2SKip Macy } 131389e0f4d2SKip Macy 131489e0f4d2SKip Macy static void 1315*96375eacSRoger Pau Monné xn_txeof(struct netfront_txq *txq) 131689e0f4d2SKip Macy { 131789e0f4d2SKip Macy RING_IDX i, prod; 131889e0f4d2SKip Macy unsigned short id; 131989e0f4d2SKip Macy struct ifnet *ifp; 132012678024SDoug Rabson netif_tx_response_t *txr; 132189e0f4d2SKip Macy struct mbuf *m; 1322*96375eacSRoger Pau Monné struct netfront_info *np = txq->info; 132389e0f4d2SKip Macy 1324*96375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 132589e0f4d2SKip Macy 132689e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 132789e0f4d2SKip Macy return; 132889e0f4d2SKip Macy 132989e0f4d2SKip Macy ifp = np->xn_ifp; 133089e0f4d2SKip Macy 133189e0f4d2SKip Macy do { 1332*96375eacSRoger Pau Monné prod = txq->ring.sring->rsp_prod; 133389e0f4d2SKip Macy rmb(); /* Ensure we see responses up to 'rp'. */ 133489e0f4d2SKip Macy 1335*96375eacSRoger Pau Monné for (i = txq->ring.rsp_cons; i != prod; i++) { 1336*96375eacSRoger Pau Monné txr = RING_GET_RESPONSE(&txq->ring, i); 133712678024SDoug Rabson if (txr->status == NETIF_RSP_NULL) 133812678024SDoug Rabson continue; 133912678024SDoug Rabson 1340931eeffaSKenneth D. Merry if (txr->status != NETIF_RSP_OKAY) { 1341931eeffaSKenneth D. Merry printf("%s: WARNING: response is %d!\n", 1342931eeffaSKenneth D. Merry __func__, txr->status); 1343931eeffaSKenneth D. Merry } 134412678024SDoug Rabson id = txr->id; 1345*96375eacSRoger Pau Monné m = txq->mbufs[id]; 1346*96375eacSRoger Pau Monné KASSERT(m != NULL, ("mbuf not found in chain")); 1347931eeffaSKenneth D. Merry KASSERT((uintptr_t)m > NET_TX_RING_SIZE, 1348931eeffaSKenneth D. Merry ("mbuf already on the free list, but we're " 1349931eeffaSKenneth D. Merry "trying to free it again!")); 13502d8fae98SAdrian Chadd M_ASSERTVALID(m); 135189e0f4d2SKip Macy 135212678024SDoug Rabson /* 135312678024SDoug Rabson * Increment packet count if this is the last 135412678024SDoug Rabson * mbuf of the chain. 135512678024SDoug Rabson */ 135612678024SDoug Rabson if (!m->m_next) 1357c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 135876acc41fSJustin T. Gibbs if (__predict_false(gnttab_query_foreign_access( 1359*96375eacSRoger Pau Monné txq->grant_ref[id]) != 0)) { 13606f9767acSMarius Strobl panic("%s: grant id %u still in use by the " 13616f9767acSMarius Strobl "backend", __func__, id); 136289e0f4d2SKip Macy } 1363*96375eacSRoger Pau Monné gnttab_end_foreign_access_ref(txq->grant_ref[id]); 136489e0f4d2SKip Macy gnttab_release_grant_reference( 1365*96375eacSRoger Pau Monné &txq->gref_head, txq->grant_ref[id]); 1366*96375eacSRoger Pau Monné txq->grant_ref[id] = GRANT_REF_INVALID; 136789e0f4d2SKip Macy 1368*96375eacSRoger Pau Monné txq->mbufs[id] = NULL; 1369*96375eacSRoger Pau Monné add_id_to_freelist(txq->mbufs, id); 1370*96375eacSRoger Pau Monné txq->mbufs_cnt--; 137112678024SDoug Rabson m_free(m); 1372*96375eacSRoger Pau Monné /* Only mark the txq active if we've freed up at least one slot to try */ 1373d76e4550SAdrian Chadd ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 137489e0f4d2SKip Macy } 1375*96375eacSRoger Pau Monné txq->ring.rsp_cons = prod; 137689e0f4d2SKip Macy 137789e0f4d2SKip Macy /* 137889e0f4d2SKip Macy * Set a new event, then check for race with update of 137989e0f4d2SKip Macy * tx_cons. Note that it is essential to schedule a 138089e0f4d2SKip Macy * callback, no matter how few buffers are pending. Even if 138189e0f4d2SKip Macy * there is space in the transmit ring, higher layers may 138289e0f4d2SKip Macy * be blocked because too much data is outstanding: in such 138389e0f4d2SKip Macy * cases notification from Xen is likely to be the only kick 138489e0f4d2SKip Macy * that we'll get. 138589e0f4d2SKip Macy */ 1386*96375eacSRoger Pau Monné txq->ring.sring->rsp_event = 1387*96375eacSRoger Pau Monné prod + ((txq->ring.sring->req_prod - prod) >> 1) + 1; 138889e0f4d2SKip Macy 138989e0f4d2SKip Macy mb(); 1390*96375eacSRoger Pau Monné } while (prod != txq->ring.sring->rsp_prod); 139189e0f4d2SKip Macy 1392*96375eacSRoger Pau Monné if (txq->full && 1393*96375eacSRoger Pau Monné ((txq->ring.sring->req_prod - prod) < NET_TX_RING_SIZE)) { 1394*96375eacSRoger Pau Monné txq->full = false; 1395*96375eacSRoger Pau Monné taskqueue_enqueue(txq->tq, &txq->intrtask); 139689e0f4d2SKip Macy } 139789e0f4d2SKip Macy } 139889e0f4d2SKip Macy 1399*96375eacSRoger Pau Monné 1400*96375eacSRoger Pau Monné static void 1401*96375eacSRoger Pau Monné xn_rxq_intr(void *xrxq) 1402*96375eacSRoger Pau Monné { 1403*96375eacSRoger Pau Monné struct netfront_rxq *rxq = xrxq; 1404*96375eacSRoger Pau Monné 1405*96375eacSRoger Pau Monné taskqueue_enqueue_fast(rxq->tq, &rxq->intrtask); 1406*96375eacSRoger Pau Monné } 1407*96375eacSRoger Pau Monné 140889e0f4d2SKip Macy static void 1409*96375eacSRoger Pau Monné xn_txq_intr(void *xtxq) 141089e0f4d2SKip Macy { 1411*96375eacSRoger Pau Monné struct netfront_txq *txq = xtxq; 141289e0f4d2SKip Macy 1413*96375eacSRoger Pau Monné taskqueue_enqueue_fast(txq->tq, &txq->intrtask); 141489e0f4d2SKip Macy } 141589e0f4d2SKip Macy 141689e0f4d2SKip Macy static int 1417*96375eacSRoger Pau Monné xn_intr(void *xsc) 1418*96375eacSRoger Pau Monné { 1419*96375eacSRoger Pau Monné struct netfront_txq *txq = xsc; 1420*96375eacSRoger Pau Monné struct netfront_info *np = txq->info; 1421*96375eacSRoger Pau Monné struct netfront_rxq *rxq = &np->rxq[txq->id]; 1422*96375eacSRoger Pau Monné 1423*96375eacSRoger Pau Monné /* kick both tx and rx */ 1424*96375eacSRoger Pau Monné xn_rxq_intr(rxq); 1425*96375eacSRoger Pau Monné xn_txq_intr(txq); 1426*96375eacSRoger Pau Monné 1427*96375eacSRoger Pau Monné return (FILTER_HANDLED); 1428*96375eacSRoger Pau Monné } 1429*96375eacSRoger Pau Monné 1430*96375eacSRoger Pau Monné static void 1431*96375eacSRoger Pau Monné xn_move_rx_slot(struct netfront_rxq *rxq, struct mbuf *m, 1432*96375eacSRoger Pau Monné grant_ref_t ref) 1433*96375eacSRoger Pau Monné { 1434*96375eacSRoger Pau Monné int new = xn_rxidx(rxq->ring.req_prod_pvt); 1435*96375eacSRoger Pau Monné 1436*96375eacSRoger Pau Monné KASSERT(rxq->mbufs[new] == NULL, ("mbufs != NULL")); 1437*96375eacSRoger Pau Monné rxq->mbufs[new] = m; 1438*96375eacSRoger Pau Monné rxq->grant_ref[new] = ref; 1439*96375eacSRoger Pau Monné RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->id = new; 1440*96375eacSRoger Pau Monné RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->gref = ref; 1441*96375eacSRoger Pau Monné rxq->ring.req_prod_pvt++; 1442*96375eacSRoger Pau Monné } 1443*96375eacSRoger Pau Monné 1444*96375eacSRoger Pau Monné static int 1445*96375eacSRoger Pau Monné xn_get_extras(struct netfront_rxq *rxq, 1446931eeffaSKenneth D. Merry struct netif_extra_info *extras, RING_IDX rp, RING_IDX *cons) 144789e0f4d2SKip Macy { 144889e0f4d2SKip Macy struct netif_extra_info *extra; 144989e0f4d2SKip Macy 145089e0f4d2SKip Macy int err = 0; 145189e0f4d2SKip Macy 145289e0f4d2SKip Macy do { 145389e0f4d2SKip Macy struct mbuf *m; 145489e0f4d2SKip Macy grant_ref_t ref; 145589e0f4d2SKip Macy 145676acc41fSJustin T. Gibbs if (__predict_false(*cons + 1 == rp)) { 1457931eeffaSKenneth D. Merry err = EINVAL; 145889e0f4d2SKip Macy break; 145989e0f4d2SKip Macy } 146089e0f4d2SKip Macy 146189e0f4d2SKip Macy extra = (struct netif_extra_info *) 1462*96375eacSRoger Pau Monné RING_GET_RESPONSE(&rxq->ring, ++(*cons)); 146389e0f4d2SKip Macy 146476acc41fSJustin T. Gibbs if (__predict_false(!extra->type || 146589e0f4d2SKip Macy extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { 1466931eeffaSKenneth D. Merry err = EINVAL; 146789e0f4d2SKip Macy } else { 146889e0f4d2SKip Macy memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); 146989e0f4d2SKip Macy } 147089e0f4d2SKip Macy 1471*96375eacSRoger Pau Monné m = xn_get_rx_mbuf(rxq, *cons); 1472*96375eacSRoger Pau Monné ref = xn_get_rx_ref(rxq, *cons); 1473*96375eacSRoger Pau Monné xn_move_rx_slot(rxq, m, ref); 147489e0f4d2SKip Macy } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); 147589e0f4d2SKip Macy 147689e0f4d2SKip Macy return err; 147789e0f4d2SKip Macy } 147889e0f4d2SKip Macy 147989e0f4d2SKip Macy static int 1480*96375eacSRoger Pau Monné xn_get_responses(struct netfront_rxq *rxq, 1481931eeffaSKenneth D. Merry struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, 1482d0f3a8b9SRoger Pau Monné struct mbuf **list) 148389e0f4d2SKip Macy { 148489e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo->rx; 148589e0f4d2SKip Macy struct netif_extra_info *extras = rinfo->extras; 148683b92f6eSKip Macy struct mbuf *m, *m0, *m_prev; 1487*96375eacSRoger Pau Monné grant_ref_t ref = xn_get_rx_ref(rxq, *cons); 1488931eeffaSKenneth D. Merry RING_IDX ref_cons = *cons; 148989e0f4d2SKip Macy int frags = 1; 149089e0f4d2SKip Macy int err = 0; 149189e0f4d2SKip Macy u_long ret; 149289e0f4d2SKip Macy 1493*96375eacSRoger Pau Monné m0 = m = m_prev = xn_get_rx_mbuf(rxq, *cons); 149483b92f6eSKip Macy 149589e0f4d2SKip Macy if (rx->flags & NETRXF_extra_info) { 1496*96375eacSRoger Pau Monné err = xn_get_extras(rxq, extras, rp, cons); 149789e0f4d2SKip Macy } 149889e0f4d2SKip Macy 149983b92f6eSKip Macy if (m0 != NULL) { 150083b92f6eSKip Macy m0->m_pkthdr.len = 0; 150183b92f6eSKip Macy m0->m_next = NULL; 150283b92f6eSKip Macy } 150383b92f6eSKip Macy 150489e0f4d2SKip Macy for (;;) { 150583b92f6eSKip Macy #if 0 1506227ca257SKip Macy DPRINTK("rx->status=%hd rx->offset=%hu frags=%u\n", 150783b92f6eSKip Macy rx->status, rx->offset, frags); 150883b92f6eSKip Macy #endif 150976acc41fSJustin T. Gibbs if (__predict_false(rx->status < 0 || 151089e0f4d2SKip Macy rx->offset + rx->status > PAGE_SIZE)) { 1511931eeffaSKenneth D. Merry 1512*96375eacSRoger Pau Monné xn_move_rx_slot(rxq, m, ref); 1513931eeffaSKenneth D. Merry if (m0 == m) 1514931eeffaSKenneth D. Merry m0 = NULL; 1515931eeffaSKenneth D. Merry m = NULL; 1516931eeffaSKenneth D. Merry err = EINVAL; 1517931eeffaSKenneth D. Merry goto next_skip_queue; 151889e0f4d2SKip Macy } 151989e0f4d2SKip Macy 152089e0f4d2SKip Macy /* 152189e0f4d2SKip Macy * This definitely indicates a bug, either in this driver or in 152289e0f4d2SKip Macy * the backend driver. In future this should flag the bad 152389e0f4d2SKip Macy * situation to the system controller to reboot the backed. 152489e0f4d2SKip Macy */ 1525ff662b5cSJustin T. Gibbs if (ref == GRANT_REF_INVALID) { 1526ff662b5cSJustin T. Gibbs printf("%s: Bad rx response id %d.\n", __func__, rx->id); 1527931eeffaSKenneth D. Merry err = EINVAL; 152889e0f4d2SKip Macy goto next; 152989e0f4d2SKip Macy } 153089e0f4d2SKip Macy 1531920ba15bSKip Macy ret = gnttab_end_foreign_access_ref(ref); 1532d0f3a8b9SRoger Pau Monné KASSERT(ret, ("Unable to end access to grant references")); 153389e0f4d2SKip Macy 1534*96375eacSRoger Pau Monné gnttab_release_grant_reference(&rxq->gref_head, ref); 153589e0f4d2SKip Macy 153689e0f4d2SKip Macy next: 15373a539122SAdrian Chadd if (m == NULL) 15383a539122SAdrian Chadd break; 15393a539122SAdrian Chadd 154083b92f6eSKip Macy m->m_len = rx->status; 154183b92f6eSKip Macy m->m_data += rx->offset; 154283b92f6eSKip Macy m0->m_pkthdr.len += rx->status; 154383b92f6eSKip Macy 1544931eeffaSKenneth D. Merry next_skip_queue: 154589e0f4d2SKip Macy if (!(rx->flags & NETRXF_more_data)) 154689e0f4d2SKip Macy break; 154789e0f4d2SKip Macy 1548931eeffaSKenneth D. Merry if (*cons + frags == rp) { 154989e0f4d2SKip Macy if (net_ratelimit()) 155089e0f4d2SKip Macy WPRINTK("Need more frags\n"); 1551931eeffaSKenneth D. Merry err = ENOENT; 1552931eeffaSKenneth D. Merry printf("%s: cons %u frags %u rp %u, not enough frags\n", 1553931eeffaSKenneth D. Merry __func__, *cons, frags, rp); 155489e0f4d2SKip Macy break; 155589e0f4d2SKip Macy } 1556931eeffaSKenneth D. Merry /* 1557931eeffaSKenneth D. Merry * Note that m can be NULL, if rx->status < 0 or if 1558931eeffaSKenneth D. Merry * rx->offset + rx->status > PAGE_SIZE above. 1559931eeffaSKenneth D. Merry */ 156083b92f6eSKip Macy m_prev = m; 156189e0f4d2SKip Macy 1562*96375eacSRoger Pau Monné rx = RING_GET_RESPONSE(&rxq->ring, *cons + frags); 1563*96375eacSRoger Pau Monné m = xn_get_rx_mbuf(rxq, *cons + frags); 156483b92f6eSKip Macy 1565931eeffaSKenneth D. Merry /* 1566931eeffaSKenneth D. Merry * m_prev == NULL can happen if rx->status < 0 or if 1567931eeffaSKenneth D. Merry * rx->offset + * rx->status > PAGE_SIZE above. 1568931eeffaSKenneth D. Merry */ 1569931eeffaSKenneth D. Merry if (m_prev != NULL) 157083b92f6eSKip Macy m_prev->m_next = m; 1571931eeffaSKenneth D. Merry 1572931eeffaSKenneth D. Merry /* 1573931eeffaSKenneth D. Merry * m0 can be NULL if rx->status < 0 or if * rx->offset + 1574931eeffaSKenneth D. Merry * rx->status > PAGE_SIZE above. 1575931eeffaSKenneth D. Merry */ 1576931eeffaSKenneth D. Merry if (m0 == NULL) 1577931eeffaSKenneth D. Merry m0 = m; 157883b92f6eSKip Macy m->m_next = NULL; 1579*96375eacSRoger Pau Monné ref = xn_get_rx_ref(rxq, *cons + frags); 1580931eeffaSKenneth D. Merry ref_cons = *cons + frags; 158189e0f4d2SKip Macy frags++; 158289e0f4d2SKip Macy } 158383b92f6eSKip Macy *list = m0; 1584931eeffaSKenneth D. Merry *cons += frags; 158589e0f4d2SKip Macy 15868577146eSJustin T. Gibbs return (err); 158789e0f4d2SKip Macy } 158889e0f4d2SKip Macy 1589931eeffaSKenneth D. Merry /** 1590931eeffaSKenneth D. Merry * \brief Count the number of fragments in an mbuf chain. 1591931eeffaSKenneth D. Merry * 1592931eeffaSKenneth D. Merry * Surprisingly, there isn't an M* macro for this. 1593c099cafaSAdrian Chadd */ 1594931eeffaSKenneth D. Merry static inline int 1595931eeffaSKenneth D. Merry xn_count_frags(struct mbuf *m) 1596931eeffaSKenneth D. Merry { 1597931eeffaSKenneth D. Merry int nfrags; 1598931eeffaSKenneth D. Merry 1599931eeffaSKenneth D. Merry for (nfrags = 0; m != NULL; m = m->m_next) 1600931eeffaSKenneth D. Merry nfrags++; 1601931eeffaSKenneth D. Merry 1602931eeffaSKenneth D. Merry return (nfrags); 160389e0f4d2SKip Macy } 160489e0f4d2SKip Macy 1605931eeffaSKenneth D. Merry /** 1606931eeffaSKenneth D. Merry * Given an mbuf chain, make sure we have enough room and then push 1607931eeffaSKenneth D. Merry * it onto the transmit ring. 1608931eeffaSKenneth D. Merry */ 1609931eeffaSKenneth D. Merry static int 1610*96375eacSRoger Pau Monné xn_assemble_tx_request(struct netfront_txq *txq, struct mbuf *m_head) 1611931eeffaSKenneth D. Merry { 1612931eeffaSKenneth D. Merry struct mbuf *m; 1613*96375eacSRoger Pau Monné struct netfront_info *np = txq->info; 1614*96375eacSRoger Pau Monné struct ifnet *ifp = np->xn_ifp; 1615931eeffaSKenneth D. Merry u_int nfrags; 1616931eeffaSKenneth D. Merry int otherend_id; 1617931eeffaSKenneth D. Merry 1618931eeffaSKenneth D. Merry /** 161912678024SDoug Rabson * Defragment the mbuf if necessary. 162012678024SDoug Rabson */ 1621931eeffaSKenneth D. Merry nfrags = xn_count_frags(m_head); 1622931eeffaSKenneth D. Merry 1623931eeffaSKenneth D. Merry /* 1624931eeffaSKenneth D. Merry * Check to see whether this request is longer than netback 1625931eeffaSKenneth D. Merry * can handle, and try to defrag it. 1626931eeffaSKenneth D. Merry */ 1627931eeffaSKenneth D. Merry /** 1628931eeffaSKenneth D. Merry * It is a bit lame, but the netback driver in Linux can't 1629931eeffaSKenneth D. Merry * deal with nfrags > MAX_TX_REQ_FRAGS, which is a quirk of 1630931eeffaSKenneth D. Merry * the Linux network stack. 1631931eeffaSKenneth D. Merry */ 1632*96375eacSRoger Pau Monné if (nfrags > np->maxfrags) { 1633c6499eccSGleb Smirnoff m = m_defrag(m_head, M_NOWAIT); 163412678024SDoug Rabson if (!m) { 1635931eeffaSKenneth D. Merry /* 1636931eeffaSKenneth D. Merry * Defrag failed, so free the mbuf and 1637931eeffaSKenneth D. Merry * therefore drop the packet. 1638931eeffaSKenneth D. Merry */ 163912678024SDoug Rabson m_freem(m_head); 1640931eeffaSKenneth D. Merry return (EMSGSIZE); 164112678024SDoug Rabson } 164212678024SDoug Rabson m_head = m; 164312678024SDoug Rabson } 164489e0f4d2SKip Macy 1645a4ec37f5SAdrian Chadd /* Determine how many fragments now exist */ 1646931eeffaSKenneth D. Merry nfrags = xn_count_frags(m_head); 1647a4ec37f5SAdrian Chadd 1648a4ec37f5SAdrian Chadd /* 1649931eeffaSKenneth D. Merry * Check to see whether the defragmented packet has too many 1650931eeffaSKenneth D. Merry * segments for the Linux netback driver. 1651a4ec37f5SAdrian Chadd */ 1652931eeffaSKenneth D. Merry /** 1653931eeffaSKenneth D. Merry * The FreeBSD TCP stack, with TSO enabled, can produce a chain 1654931eeffaSKenneth D. Merry * of mbufs longer than Linux can handle. Make sure we don't 1655931eeffaSKenneth D. Merry * pass a too-long chain over to the other side by dropping the 1656931eeffaSKenneth D. Merry * packet. It doesn't look like there is currently a way to 1657931eeffaSKenneth D. Merry * tell the TCP stack to generate a shorter chain of packets. 16583fb28bbbSAdrian Chadd */ 1659931eeffaSKenneth D. Merry if (nfrags > MAX_TX_REQ_FRAGS) { 1660ff662b5cSJustin T. Gibbs #ifdef DEBUG 1661ff662b5cSJustin T. Gibbs printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback " 1662ff662b5cSJustin T. Gibbs "won't be able to handle it, dropping\n", 1663ff662b5cSJustin T. Gibbs __func__, nfrags, MAX_TX_REQ_FRAGS); 1664ff662b5cSJustin T. Gibbs #endif 1665931eeffaSKenneth D. Merry m_freem(m_head); 1666931eeffaSKenneth D. Merry return (EMSGSIZE); 1667a4ec37f5SAdrian Chadd } 1668a4ec37f5SAdrian Chadd 16693fb28bbbSAdrian Chadd /* 1670931eeffaSKenneth D. Merry * This check should be redundant. We've already verified that we 1671931eeffaSKenneth D. Merry * have enough slots in the ring to handle a packet of maximum 1672931eeffaSKenneth D. Merry * size, and that our packet is less than the maximum size. Keep 1673931eeffaSKenneth D. Merry * it in here as an assert for now just to make certain that 1674*96375eacSRoger Pau Monné * chain_cnt is accurate. 16753fb28bbbSAdrian Chadd */ 1676*96375eacSRoger Pau Monné KASSERT((txq->mbufs_cnt + nfrags) <= NET_TX_RING_SIZE, 1677*96375eacSRoger Pau Monné ("%s: chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE " 1678*96375eacSRoger Pau Monné "(%d)!", __func__, (int) txq->mbufs_cnt, 1679931eeffaSKenneth D. Merry (int) nfrags, (int) NET_TX_RING_SIZE)); 1680a4ec37f5SAdrian Chadd 168189e0f4d2SKip Macy /* 168289e0f4d2SKip Macy * Start packing the mbufs in this chain into 168389e0f4d2SKip Macy * the fragment pointers. Stop when we run out 168489e0f4d2SKip Macy * of fragments or hit the end of the mbuf chain. 168589e0f4d2SKip Macy */ 168612678024SDoug Rabson m = m_head; 1687*96375eacSRoger Pau Monné otherend_id = xenbus_get_otherend_id(np->xbdev); 168812678024SDoug Rabson for (m = m_head; m; m = m->m_next) { 1689931eeffaSKenneth D. Merry netif_tx_request_t *tx; 1690931eeffaSKenneth D. Merry uintptr_t id; 1691931eeffaSKenneth D. Merry grant_ref_t ref; 1692931eeffaSKenneth D. Merry u_long mfn; /* XXX Wrong type? */ 1693931eeffaSKenneth D. Merry 1694*96375eacSRoger Pau Monné tx = RING_GET_REQUEST(&txq->ring, txq->ring.req_prod_pvt); 1695*96375eacSRoger Pau Monné id = get_id_from_freelist(txq->mbufs); 1696a4ec37f5SAdrian Chadd if (id == 0) 16976f9767acSMarius Strobl panic("%s: was allocated the freelist head!\n", 16986f9767acSMarius Strobl __func__); 1699*96375eacSRoger Pau Monné txq->mbufs_cnt++; 1700*96375eacSRoger Pau Monné if (txq->mbufs_cnt > NET_TX_RING_SIZE) 17016f9767acSMarius Strobl panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n", 17026f9767acSMarius Strobl __func__); 1703*96375eacSRoger Pau Monné txq->mbufs[id] = m; 170489e0f4d2SKip Macy tx->id = id; 1705*96375eacSRoger Pau Monné ref = gnttab_claim_grant_reference(&txq->gref_head); 170689e0f4d2SKip Macy KASSERT((short)ref >= 0, ("Negative ref")); 170712678024SDoug Rabson mfn = virt_to_mfn(mtod(m, vm_offset_t)); 170823dc5621SKip Macy gnttab_grant_foreign_access_ref(ref, otherend_id, 170989e0f4d2SKip Macy mfn, GNTMAP_readonly); 1710*96375eacSRoger Pau Monné tx->gref = txq->grant_ref[id] = ref; 171112678024SDoug Rabson tx->offset = mtod(m, vm_offset_t) & (PAGE_SIZE - 1); 171289e0f4d2SKip Macy tx->flags = 0; 171312678024SDoug Rabson if (m == m_head) { 171412678024SDoug Rabson /* 171512678024SDoug Rabson * The first fragment has the entire packet 171612678024SDoug Rabson * size, subsequent fragments have just the 171712678024SDoug Rabson * fragment size. The backend works out the 171812678024SDoug Rabson * true size of the first fragment by 171912678024SDoug Rabson * subtracting the sizes of the other 172012678024SDoug Rabson * fragments. 172112678024SDoug Rabson */ 172212678024SDoug Rabson tx->size = m->m_pkthdr.len; 172389e0f4d2SKip Macy 172412678024SDoug Rabson /* 1725931eeffaSKenneth D. Merry * The first fragment contains the checksum flags 1726931eeffaSKenneth D. Merry * and is optionally followed by extra data for 1727931eeffaSKenneth D. Merry * TSO etc. 1728931eeffaSKenneth D. Merry */ 1729931eeffaSKenneth D. Merry /** 1730931eeffaSKenneth D. Merry * CSUM_TSO requires checksum offloading. 1731931eeffaSKenneth D. Merry * Some versions of FreeBSD fail to 1732931eeffaSKenneth D. Merry * set CSUM_TCP in the CSUM_TSO case, 1733931eeffaSKenneth D. Merry * so we have to test for CSUM_TSO 1734931eeffaSKenneth D. Merry * explicitly. 173512678024SDoug Rabson */ 173612678024SDoug Rabson if (m->m_pkthdr.csum_flags 1737931eeffaSKenneth D. Merry & (CSUM_DELAY_DATA | CSUM_TSO)) { 173812678024SDoug Rabson tx->flags |= (NETTXF_csum_blank 173912678024SDoug Rabson | NETTXF_data_validated); 174012678024SDoug Rabson } 174112678024SDoug Rabson if (m->m_pkthdr.csum_flags & CSUM_TSO) { 174212678024SDoug Rabson struct netif_extra_info *gso = 174312678024SDoug Rabson (struct netif_extra_info *) 1744*96375eacSRoger Pau Monné RING_GET_REQUEST(&txq->ring, 1745*96375eacSRoger Pau Monné ++txq->ring.req_prod_pvt); 174689e0f4d2SKip Macy 174712678024SDoug Rabson tx->flags |= NETTXF_extra_info; 174889e0f4d2SKip Macy 174912678024SDoug Rabson gso->u.gso.size = m->m_pkthdr.tso_segsz; 175012678024SDoug Rabson gso->u.gso.type = 175112678024SDoug Rabson XEN_NETIF_GSO_TYPE_TCPV4; 175212678024SDoug Rabson gso->u.gso.pad = 0; 175312678024SDoug Rabson gso->u.gso.features = 0; 175412678024SDoug Rabson 175512678024SDoug Rabson gso->type = XEN_NETIF_EXTRA_TYPE_GSO; 175612678024SDoug Rabson gso->flags = 0; 175712678024SDoug Rabson } 175812678024SDoug Rabson } else { 175912678024SDoug Rabson tx->size = m->m_len; 176012678024SDoug Rabson } 1761931eeffaSKenneth D. Merry if (m->m_next) 176212678024SDoug Rabson tx->flags |= NETTXF_more_data; 176312678024SDoug Rabson 1764*96375eacSRoger Pau Monné txq->ring.req_prod_pvt++; 1765931eeffaSKenneth D. Merry } 176612678024SDoug Rabson BPF_MTAP(ifp, m_head); 176712678024SDoug Rabson 1768*96375eacSRoger Pau Monné xn_txeof(txq); 1769*96375eacSRoger Pau Monné 1770*96375eacSRoger Pau Monné txq->stats.tx_bytes += m_head->m_pkthdr.len; 1771*96375eacSRoger Pau Monné txq->stats.tx_packets++; 1772931eeffaSKenneth D. Merry 1773931eeffaSKenneth D. Merry return (0); 177489e0f4d2SKip Macy } 177589e0f4d2SKip Macy 177689e0f4d2SKip Macy /* equivalent of network_open() in Linux */ 177789e0f4d2SKip Macy static void 1778*96375eacSRoger Pau Monné xn_ifinit_locked(struct netfront_info *np) 177989e0f4d2SKip Macy { 178089e0f4d2SKip Macy struct ifnet *ifp; 1781*96375eacSRoger Pau Monné int i; 1782*96375eacSRoger Pau Monné struct netfront_rxq *rxq; 178389e0f4d2SKip Macy 1784*96375eacSRoger Pau Monné XN_LOCK_ASSERT(np); 178589e0f4d2SKip Macy 1786*96375eacSRoger Pau Monné ifp = np->xn_ifp; 178789e0f4d2SKip Macy 178889e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) 178989e0f4d2SKip Macy return; 179089e0f4d2SKip Macy 1791*96375eacSRoger Pau Monné xn_stop(np); 179289e0f4d2SKip Macy 1793*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 1794*96375eacSRoger Pau Monné rxq = &np->rxq[i]; 1795*96375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 1796*96375eacSRoger Pau Monné rxq->ring.sring->rsp_event = rxq->ring.rsp_cons + 1; 1797*96375eacSRoger Pau Monné } 179889e0f4d2SKip Macy 179989e0f4d2SKip Macy ifp->if_drv_flags |= IFF_DRV_RUNNING; 180089e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 18010e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_UP); 180289e0f4d2SKip Macy } 180389e0f4d2SKip Macy 180489e0f4d2SKip Macy static void 180589e0f4d2SKip Macy xn_ifinit(void *xsc) 180689e0f4d2SKip Macy { 180789e0f4d2SKip Macy struct netfront_info *sc = xsc; 180889e0f4d2SKip Macy 180989e0f4d2SKip Macy XN_LOCK(sc); 181089e0f4d2SKip Macy xn_ifinit_locked(sc); 181189e0f4d2SKip Macy XN_UNLOCK(sc); 181289e0f4d2SKip Macy } 181389e0f4d2SKip Macy 181489e0f4d2SKip Macy static int 181589e0f4d2SKip Macy xn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 181689e0f4d2SKip Macy { 181789e0f4d2SKip Macy struct netfront_info *sc = ifp->if_softc; 181889e0f4d2SKip Macy struct ifreq *ifr = (struct ifreq *) data; 1819a0ae8f04SBjoern A. Zeeb #ifdef INET 182089e0f4d2SKip Macy struct ifaddr *ifa = (struct ifaddr *)data; 1821a0ae8f04SBjoern A. Zeeb #endif 182289e0f4d2SKip Macy 182389e0f4d2SKip Macy int mask, error = 0; 182489e0f4d2SKip Macy switch(cmd) { 182589e0f4d2SKip Macy case SIOCSIFADDR: 1826a0ae8f04SBjoern A. Zeeb #ifdef INET 182789e0f4d2SKip Macy XN_LOCK(sc); 182889e0f4d2SKip Macy if (ifa->ifa_addr->sa_family == AF_INET) { 182989e0f4d2SKip Macy ifp->if_flags |= IFF_UP; 183089e0f4d2SKip Macy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 183189e0f4d2SKip Macy xn_ifinit_locked(sc); 183289e0f4d2SKip Macy arp_ifinit(ifp, ifa); 183389e0f4d2SKip Macy XN_UNLOCK(sc); 183449906218SDoug Rabson } else { 183549906218SDoug Rabson XN_UNLOCK(sc); 1836a0ae8f04SBjoern A. Zeeb #endif 183749906218SDoug Rabson error = ether_ioctl(ifp, cmd, data); 1838a0ae8f04SBjoern A. Zeeb #ifdef INET 183949906218SDoug Rabson } 1840a0ae8f04SBjoern A. Zeeb #endif 184189e0f4d2SKip Macy break; 184289e0f4d2SKip Macy case SIOCSIFMTU: 184389e0f4d2SKip Macy ifp->if_mtu = ifr->ifr_mtu; 184489e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 184589e0f4d2SKip Macy xn_ifinit(sc); 184689e0f4d2SKip Macy break; 184789e0f4d2SKip Macy case SIOCSIFFLAGS: 184889e0f4d2SKip Macy XN_LOCK(sc); 184989e0f4d2SKip Macy if (ifp->if_flags & IFF_UP) { 185089e0f4d2SKip Macy /* 185189e0f4d2SKip Macy * If only the state of the PROMISC flag changed, 185289e0f4d2SKip Macy * then just use the 'set promisc mode' command 185389e0f4d2SKip Macy * instead of reinitializing the entire NIC. Doing 185489e0f4d2SKip Macy * a full re-init means reloading the firmware and 185589e0f4d2SKip Macy * waiting for it to start up, which may take a 185689e0f4d2SKip Macy * second or two. 185789e0f4d2SKip Macy */ 185889e0f4d2SKip Macy xn_ifinit_locked(sc); 185989e0f4d2SKip Macy } else { 186089e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 186189e0f4d2SKip Macy xn_stop(sc); 186289e0f4d2SKip Macy } 186389e0f4d2SKip Macy } 186489e0f4d2SKip Macy sc->xn_if_flags = ifp->if_flags; 186589e0f4d2SKip Macy XN_UNLOCK(sc); 186689e0f4d2SKip Macy error = 0; 186789e0f4d2SKip Macy break; 186889e0f4d2SKip Macy case SIOCSIFCAP: 186989e0f4d2SKip Macy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 187012678024SDoug Rabson if (mask & IFCAP_TXCSUM) { 187112678024SDoug Rabson if (IFCAP_TXCSUM & ifp->if_capenable) { 187212678024SDoug Rabson ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 187312678024SDoug Rabson ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 187412678024SDoug Rabson | CSUM_IP | CSUM_TSO); 187512678024SDoug Rabson } else { 187612678024SDoug Rabson ifp->if_capenable |= IFCAP_TXCSUM; 187712678024SDoug Rabson ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP 187812678024SDoug Rabson | CSUM_IP); 187989e0f4d2SKip Macy } 188012678024SDoug Rabson } 188112678024SDoug Rabson if (mask & IFCAP_RXCSUM) { 188212678024SDoug Rabson ifp->if_capenable ^= IFCAP_RXCSUM; 188312678024SDoug Rabson } 188412678024SDoug Rabson if (mask & IFCAP_TSO4) { 188512678024SDoug Rabson if (IFCAP_TSO4 & ifp->if_capenable) { 188612678024SDoug Rabson ifp->if_capenable &= ~IFCAP_TSO4; 188712678024SDoug Rabson ifp->if_hwassist &= ~CSUM_TSO; 188812678024SDoug Rabson } else if (IFCAP_TXCSUM & ifp->if_capenable) { 188912678024SDoug Rabson ifp->if_capenable |= IFCAP_TSO4; 189012678024SDoug Rabson ifp->if_hwassist |= CSUM_TSO; 189112678024SDoug Rabson } else { 18923552092bSAdrian Chadd IPRINTK("Xen requires tx checksum offload" 189312678024SDoug Rabson " be enabled to use TSO\n"); 189412678024SDoug Rabson error = EINVAL; 189512678024SDoug Rabson } 189612678024SDoug Rabson } 189712678024SDoug Rabson if (mask & IFCAP_LRO) { 189812678024SDoug Rabson ifp->if_capenable ^= IFCAP_LRO; 189912678024SDoug Rabson 190012678024SDoug Rabson } 190189e0f4d2SKip Macy error = 0; 190289e0f4d2SKip Macy break; 190389e0f4d2SKip Macy case SIOCADDMULTI: 190489e0f4d2SKip Macy case SIOCDELMULTI: 1905ce8df48bSSimon J. Gerraty break; 190689e0f4d2SKip Macy case SIOCSIFMEDIA: 190789e0f4d2SKip Macy case SIOCGIFMEDIA: 19080e509842SJustin T. Gibbs error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 190989e0f4d2SKip Macy break; 191089e0f4d2SKip Macy default: 191189e0f4d2SKip Macy error = ether_ioctl(ifp, cmd, data); 191289e0f4d2SKip Macy } 191389e0f4d2SKip Macy 191489e0f4d2SKip Macy return (error); 191589e0f4d2SKip Macy } 191689e0f4d2SKip Macy 191789e0f4d2SKip Macy static void 191889e0f4d2SKip Macy xn_stop(struct netfront_info *sc) 191989e0f4d2SKip Macy { 192089e0f4d2SKip Macy struct ifnet *ifp; 192189e0f4d2SKip Macy 192289e0f4d2SKip Macy XN_LOCK_ASSERT(sc); 192389e0f4d2SKip Macy 192489e0f4d2SKip Macy ifp = sc->xn_ifp; 192589e0f4d2SKip Macy 192689e0f4d2SKip Macy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 19270e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_DOWN); 192889e0f4d2SKip Macy } 192989e0f4d2SKip Macy 1930*96375eacSRoger Pau Monné static void 1931*96375eacSRoger Pau Monné xn_rebuild_rx_bufs(struct netfront_rxq *rxq) 193289e0f4d2SKip Macy { 1933*96375eacSRoger Pau Monné int requeue_idx, i; 193489e0f4d2SKip Macy grant_ref_t ref; 193589e0f4d2SKip Macy netif_rx_request_t *req; 193689e0f4d2SKip Macy 193789e0f4d2SKip Macy for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { 193889e0f4d2SKip Macy struct mbuf *m; 19393a6d1fcfSKip Macy u_long pfn; 194089e0f4d2SKip Macy 1941*96375eacSRoger Pau Monné if (rxq->mbufs[i] == NULL) 194289e0f4d2SKip Macy continue; 194389e0f4d2SKip Macy 1944*96375eacSRoger Pau Monné m = rxq->mbufs[requeue_idx] = xn_get_rx_mbuf(rxq, i); 1945*96375eacSRoger Pau Monné ref = rxq->grant_ref[requeue_idx] = xn_get_rx_ref(rxq, i); 1946931eeffaSKenneth D. Merry 1947*96375eacSRoger Pau Monné req = RING_GET_REQUEST(&rxq->ring, requeue_idx); 19483a6d1fcfSKip Macy pfn = vtophys(mtod(m, vm_offset_t)) >> PAGE_SHIFT; 194989e0f4d2SKip Macy 195089e0f4d2SKip Macy gnttab_grant_foreign_access_ref(ref, 1951*96375eacSRoger Pau Monné xenbus_get_otherend_id(rxq->info->xbdev), 1952ed95805eSJohn Baldwin pfn, 0); 1953d0f3a8b9SRoger Pau Monné 195489e0f4d2SKip Macy req->gref = ref; 195589e0f4d2SKip Macy req->id = requeue_idx; 195689e0f4d2SKip Macy 195789e0f4d2SKip Macy requeue_idx++; 195889e0f4d2SKip Macy } 195989e0f4d2SKip Macy 1960*96375eacSRoger Pau Monné rxq->ring.req_prod_pvt = requeue_idx; 1961*96375eacSRoger Pau Monné } 196289e0f4d2SKip Macy 1963*96375eacSRoger Pau Monné /* START of Xenolinux helper functions adapted to FreeBSD */ 1964*96375eacSRoger Pau Monné int 1965*96375eacSRoger Pau Monné xn_connect(struct netfront_info *np) 1966*96375eacSRoger Pau Monné { 1967*96375eacSRoger Pau Monné int i, error; 1968*96375eacSRoger Pau Monné u_int feature_rx_copy; 1969*96375eacSRoger Pau Monné struct netfront_rxq *rxq; 1970*96375eacSRoger Pau Monné struct netfront_txq *txq; 1971*96375eacSRoger Pau Monné 1972*96375eacSRoger Pau Monné error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 1973*96375eacSRoger Pau Monné "feature-rx-copy", NULL, "%u", &feature_rx_copy); 1974*96375eacSRoger Pau Monné if (error != 0) 1975*96375eacSRoger Pau Monné feature_rx_copy = 0; 1976*96375eacSRoger Pau Monné 1977*96375eacSRoger Pau Monné /* We only support rx copy. */ 1978*96375eacSRoger Pau Monné if (!feature_rx_copy) 1979*96375eacSRoger Pau Monné return (EPROTONOSUPPORT); 1980*96375eacSRoger Pau Monné 1981*96375eacSRoger Pau Monné /* Recovery procedure: */ 1982*96375eacSRoger Pau Monné error = talk_to_backend(np->xbdev, np); 1983*96375eacSRoger Pau Monné if (error != 0) 1984*96375eacSRoger Pau Monné return (error); 1985*96375eacSRoger Pau Monné 1986*96375eacSRoger Pau Monné /* Step 1: Reinitialise variables. */ 1987*96375eacSRoger Pau Monné xn_query_features(np); 1988*96375eacSRoger Pau Monné xn_configure_features(np); 1989*96375eacSRoger Pau Monné 1990*96375eacSRoger Pau Monné /* Step 2: Release TX buffer */ 1991*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 1992*96375eacSRoger Pau Monné txq = &np->txq[i]; 1993*96375eacSRoger Pau Monné xn_release_tx_bufs(txq); 1994*96375eacSRoger Pau Monné } 1995*96375eacSRoger Pau Monné 1996*96375eacSRoger Pau Monné /* Step 3: Rebuild the RX buffer freelist and the RX ring itself. */ 1997*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 1998*96375eacSRoger Pau Monné rxq = &np->rxq[i]; 1999*96375eacSRoger Pau Monné xn_rebuild_rx_bufs(rxq); 2000*96375eacSRoger Pau Monné } 2001*96375eacSRoger Pau Monné 2002*96375eacSRoger Pau Monné /* Step 4: All public and private state should now be sane. Get 200389e0f4d2SKip Macy * ready to start sending and receiving packets and give the driver 200489e0f4d2SKip Macy * domain a kick because we've probably just requeued some 200589e0f4d2SKip Macy * packets. 200689e0f4d2SKip Macy */ 200789e0f4d2SKip Macy netfront_carrier_on(np); 2008*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 2009*96375eacSRoger Pau Monné txq = &np->txq[i]; 2010*96375eacSRoger Pau Monné xen_intr_signal(txq->xen_intr_handle); 2011*96375eacSRoger Pau Monné XN_TX_LOCK(txq); 2012*96375eacSRoger Pau Monné xn_txeof(txq); 2013*96375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 2014*96375eacSRoger Pau Monné xn_alloc_rx_buffers(rxq); 2015*96375eacSRoger Pau Monné } 201689e0f4d2SKip Macy 201789e0f4d2SKip Macy return (0); 201889e0f4d2SKip Macy } 201989e0f4d2SKip Macy 202089e0f4d2SKip Macy static void 2021578e4bf7SJustin T. Gibbs xn_query_features(struct netfront_info *np) 2022578e4bf7SJustin T. Gibbs { 2023578e4bf7SJustin T. Gibbs int val; 2024578e4bf7SJustin T. Gibbs 2025578e4bf7SJustin T. Gibbs device_printf(np->xbdev, "backend features:"); 2026578e4bf7SJustin T. Gibbs 2027578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 2028578e4bf7SJustin T. Gibbs "feature-sg", NULL, "%d", &val) < 0) 2029578e4bf7SJustin T. Gibbs val = 0; 2030578e4bf7SJustin T. Gibbs 2031578e4bf7SJustin T. Gibbs np->maxfrags = 1; 2032578e4bf7SJustin T. Gibbs if (val) { 2033578e4bf7SJustin T. Gibbs np->maxfrags = MAX_TX_REQ_FRAGS; 2034578e4bf7SJustin T. Gibbs printf(" feature-sg"); 2035578e4bf7SJustin T. Gibbs } 2036578e4bf7SJustin T. Gibbs 2037578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 2038578e4bf7SJustin T. Gibbs "feature-gso-tcpv4", NULL, "%d", &val) < 0) 2039578e4bf7SJustin T. Gibbs val = 0; 2040578e4bf7SJustin T. Gibbs 2041578e4bf7SJustin T. Gibbs np->xn_ifp->if_capabilities &= ~(IFCAP_TSO4|IFCAP_LRO); 2042578e4bf7SJustin T. Gibbs if (val) { 2043578e4bf7SJustin T. Gibbs np->xn_ifp->if_capabilities |= IFCAP_TSO4|IFCAP_LRO; 2044578e4bf7SJustin T. Gibbs printf(" feature-gso-tcp4"); 2045578e4bf7SJustin T. Gibbs } 2046578e4bf7SJustin T. Gibbs 2047578e4bf7SJustin T. Gibbs printf("\n"); 2048578e4bf7SJustin T. Gibbs } 2049578e4bf7SJustin T. Gibbs 2050cf9c09e1SJustin T. Gibbs static int 2051578e4bf7SJustin T. Gibbs xn_configure_features(struct netfront_info *np) 2052cf9c09e1SJustin T. Gibbs { 20536a8e9695SRoger Pau Monné int err, cap_enabled; 2054*96375eacSRoger Pau Monné #if (defined(INET) || defined(INET6)) 2055*96375eacSRoger Pau Monné int i; 2056*96375eacSRoger Pau Monné #endif 2057cf9c09e1SJustin T. Gibbs 2058cf9c09e1SJustin T. Gibbs err = 0; 20596a8e9695SRoger Pau Monné 20606a8e9695SRoger Pau Monné if (np->xn_resume && 20616a8e9695SRoger Pau Monné ((np->xn_ifp->if_capenable & np->xn_ifp->if_capabilities) 20626a8e9695SRoger Pau Monné == np->xn_ifp->if_capenable)) { 20636a8e9695SRoger Pau Monné /* Current options are available, no need to do anything. */ 20646a8e9695SRoger Pau Monné return (0); 20656a8e9695SRoger Pau Monné } 20666a8e9695SRoger Pau Monné 20676a8e9695SRoger Pau Monné /* Try to preserve as many options as possible. */ 20686a8e9695SRoger Pau Monné if (np->xn_resume) 20696a8e9695SRoger Pau Monné cap_enabled = np->xn_ifp->if_capenable; 20706a8e9695SRoger Pau Monné else 20716a8e9695SRoger Pau Monné cap_enabled = UINT_MAX; 20726a8e9695SRoger Pau Monné 207308c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 2074*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) 2075*96375eacSRoger Pau Monné if ((np->xn_ifp->if_capenable & IFCAP_LRO) == 2076*96375eacSRoger Pau Monné (cap_enabled & IFCAP_LRO)) 2077*96375eacSRoger Pau Monné tcp_lro_free(&np->rxq[i].lro); 2078578e4bf7SJustin T. Gibbs #endif 2079578e4bf7SJustin T. Gibbs np->xn_ifp->if_capenable = 20806a8e9695SRoger Pau Monné np->xn_ifp->if_capabilities & ~(IFCAP_LRO|IFCAP_TSO4) & cap_enabled; 2081578e4bf7SJustin T. Gibbs np->xn_ifp->if_hwassist &= ~CSUM_TSO; 208208c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6)) 2083*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 20846a8e9695SRoger Pau Monné if (xn_enable_lro && (np->xn_ifp->if_capabilities & IFCAP_LRO) == 20856a8e9695SRoger Pau Monné (cap_enabled & IFCAP_LRO)) { 2086*96375eacSRoger Pau Monné err = tcp_lro_init(&np->rxq[i].lro); 2087*96375eacSRoger Pau Monné if (err != 0) { 2088cf9c09e1SJustin T. Gibbs device_printf(np->xbdev, "LRO initialization failed\n"); 2089cf9c09e1SJustin T. Gibbs } else { 2090*96375eacSRoger Pau Monné np->rxq[i].lro.ifp = np->xn_ifp; 2091578e4bf7SJustin T. Gibbs np->xn_ifp->if_capenable |= IFCAP_LRO; 2092cf9c09e1SJustin T. Gibbs } 2093cf9c09e1SJustin T. Gibbs } 2094*96375eacSRoger Pau Monné } 20956a8e9695SRoger Pau Monné if ((np->xn_ifp->if_capabilities & IFCAP_TSO4) == 20966a8e9695SRoger Pau Monné (cap_enabled & IFCAP_TSO4)) { 2097578e4bf7SJustin T. Gibbs np->xn_ifp->if_capenable |= IFCAP_TSO4; 2098578e4bf7SJustin T. Gibbs np->xn_ifp->if_hwassist |= CSUM_TSO; 2099578e4bf7SJustin T. Gibbs } 2100cf9c09e1SJustin T. Gibbs #endif 2101cf9c09e1SJustin T. Gibbs return (err); 2102cf9c09e1SJustin T. Gibbs } 2103cf9c09e1SJustin T. Gibbs 2104*96375eacSRoger Pau Monné static int 2105*96375eacSRoger Pau Monné xn_txq_mq_start_locked(struct netfront_txq *txq, struct mbuf *m) 2106*96375eacSRoger Pau Monné { 2107*96375eacSRoger Pau Monné struct netfront_info *np; 2108*96375eacSRoger Pau Monné struct ifnet *ifp; 2109*96375eacSRoger Pau Monné struct buf_ring *br; 2110*96375eacSRoger Pau Monné int error, notify; 2111*96375eacSRoger Pau Monné 2112*96375eacSRoger Pau Monné np = txq->info; 2113*96375eacSRoger Pau Monné br = txq->br; 2114*96375eacSRoger Pau Monné ifp = np->xn_ifp; 2115*96375eacSRoger Pau Monné error = 0; 2116*96375eacSRoger Pau Monné 2117*96375eacSRoger Pau Monné XN_TX_LOCK_ASSERT(txq); 2118*96375eacSRoger Pau Monné 2119*96375eacSRoger Pau Monné if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 2120*96375eacSRoger Pau Monné !netfront_carrier_ok(np)) { 2121*96375eacSRoger Pau Monné if (m != NULL) 2122*96375eacSRoger Pau Monné error = drbr_enqueue(ifp, br, m); 2123*96375eacSRoger Pau Monné return (error); 2124*96375eacSRoger Pau Monné } 2125*96375eacSRoger Pau Monné 2126*96375eacSRoger Pau Monné if (m != NULL) { 2127*96375eacSRoger Pau Monné error = drbr_enqueue(ifp, br, m); 2128*96375eacSRoger Pau Monné if (error != 0) 2129*96375eacSRoger Pau Monné return (error); 2130*96375eacSRoger Pau Monné } 2131*96375eacSRoger Pau Monné 2132*96375eacSRoger Pau Monné while ((m = drbr_peek(ifp, br)) != NULL) { 2133*96375eacSRoger Pau Monné if (!xn_tx_slot_available(txq)) { 2134*96375eacSRoger Pau Monné drbr_putback(ifp, br, m); 2135*96375eacSRoger Pau Monné break; 2136*96375eacSRoger Pau Monné } 2137*96375eacSRoger Pau Monné 2138*96375eacSRoger Pau Monné error = xn_assemble_tx_request(txq, m); 2139*96375eacSRoger Pau Monné /* xn_assemble_tx_request always consumes the mbuf*/ 2140*96375eacSRoger Pau Monné if (error != 0) { 2141*96375eacSRoger Pau Monné drbr_advance(ifp, br); 2142*96375eacSRoger Pau Monné break; 2143*96375eacSRoger Pau Monné } 2144*96375eacSRoger Pau Monné 2145*96375eacSRoger Pau Monné RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&txq->ring, notify); 2146*96375eacSRoger Pau Monné if (notify) 2147*96375eacSRoger Pau Monné xen_intr_signal(txq->xen_intr_handle); 2148*96375eacSRoger Pau Monné 2149*96375eacSRoger Pau Monné drbr_advance(ifp, br); 2150*96375eacSRoger Pau Monné } 2151*96375eacSRoger Pau Monné 2152*96375eacSRoger Pau Monné if (RING_FULL(&txq->ring)) 2153*96375eacSRoger Pau Monné txq->full = true; 2154*96375eacSRoger Pau Monné 2155*96375eacSRoger Pau Monné return (0); 2156*96375eacSRoger Pau Monné } 2157*96375eacSRoger Pau Monné 2158*96375eacSRoger Pau Monné static int 2159*96375eacSRoger Pau Monné xn_txq_mq_start(struct ifnet *ifp, struct mbuf *m) 2160*96375eacSRoger Pau Monné { 2161*96375eacSRoger Pau Monné struct netfront_info *np; 2162*96375eacSRoger Pau Monné struct netfront_txq *txq; 2163*96375eacSRoger Pau Monné int i, npairs, error; 2164*96375eacSRoger Pau Monné 2165*96375eacSRoger Pau Monné np = ifp->if_softc; 2166*96375eacSRoger Pau Monné npairs = np->num_queues; 2167*96375eacSRoger Pau Monné 2168*96375eacSRoger Pau Monné /* check if flowid is set */ 2169*96375eacSRoger Pau Monné if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 2170*96375eacSRoger Pau Monné i = m->m_pkthdr.flowid % npairs; 2171*96375eacSRoger Pau Monné else 2172*96375eacSRoger Pau Monné i = curcpu % npairs; 2173*96375eacSRoger Pau Monné 2174*96375eacSRoger Pau Monné txq = &np->txq[i]; 2175*96375eacSRoger Pau Monné 2176*96375eacSRoger Pau Monné if (XN_TX_TRYLOCK(txq) != 0) { 2177*96375eacSRoger Pau Monné error = xn_txq_mq_start_locked(txq, m); 2178*96375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 2179*96375eacSRoger Pau Monné } else { 2180*96375eacSRoger Pau Monné error = drbr_enqueue(ifp, txq->br, m); 2181*96375eacSRoger Pau Monné taskqueue_enqueue(txq->tq, &txq->defrtask); 2182*96375eacSRoger Pau Monné } 2183*96375eacSRoger Pau Monné 2184*96375eacSRoger Pau Monné return (error); 2185*96375eacSRoger Pau Monné } 2186*96375eacSRoger Pau Monné 2187*96375eacSRoger Pau Monné static void 2188*96375eacSRoger Pau Monné xn_qflush(struct ifnet *ifp) 2189*96375eacSRoger Pau Monné { 2190*96375eacSRoger Pau Monné struct netfront_info *np; 2191*96375eacSRoger Pau Monné struct netfront_txq *txq; 2192*96375eacSRoger Pau Monné struct mbuf *m; 2193*96375eacSRoger Pau Monné int i; 2194*96375eacSRoger Pau Monné 2195*96375eacSRoger Pau Monné np = ifp->if_softc; 2196*96375eacSRoger Pau Monné 2197*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 2198*96375eacSRoger Pau Monné txq = &np->txq[i]; 2199*96375eacSRoger Pau Monné 2200*96375eacSRoger Pau Monné XN_TX_LOCK(txq); 2201*96375eacSRoger Pau Monné while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 2202*96375eacSRoger Pau Monné m_freem(m); 2203*96375eacSRoger Pau Monné XN_TX_UNLOCK(txq); 2204*96375eacSRoger Pau Monné } 2205*96375eacSRoger Pau Monné 2206*96375eacSRoger Pau Monné if_qflush(ifp); 2207*96375eacSRoger Pau Monné } 2208*96375eacSRoger Pau Monné 220976acc41fSJustin T. Gibbs /** 221076acc41fSJustin T. Gibbs * Create a network device. 221176acc41fSJustin T. Gibbs * @param dev Newbus device representing this virtual NIC. 221289e0f4d2SKip Macy */ 221323dc5621SKip Macy int 221423dc5621SKip Macy create_netdev(device_t dev) 221589e0f4d2SKip Macy { 221689e0f4d2SKip Macy struct netfront_info *np; 221789e0f4d2SKip Macy int err; 221889e0f4d2SKip Macy struct ifnet *ifp; 221989e0f4d2SKip Macy 222023dc5621SKip Macy np = device_get_softc(dev); 222189e0f4d2SKip Macy 222289e0f4d2SKip Macy np->xbdev = dev; 222389e0f4d2SKip Macy 2224177e3f13SRoger Pau Monné mtx_init(&np->sc_lock, "xnsc", "netfront softc lock", MTX_DEF); 22250e509842SJustin T. Gibbs 22260e509842SJustin T. Gibbs ifmedia_init(&np->sc_media, 0, xn_ifmedia_upd, xn_ifmedia_sts); 22270e509842SJustin T. Gibbs ifmedia_add(&np->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 22280e509842SJustin T. Gibbs ifmedia_set(&np->sc_media, IFM_ETHER|IFM_MANUAL); 22290e509842SJustin T. Gibbs 223089e0f4d2SKip Macy np->rx_min_target = RX_MIN_TARGET; 223189e0f4d2SKip Macy np->rx_max_target = RX_MAX_TARGET; 223289e0f4d2SKip Macy 223389e0f4d2SKip Macy err = xen_net_read_mac(dev, np->mac); 2234*96375eacSRoger Pau Monné if (err != 0) 22351a2928b7SRoger Pau Monné goto error; 223689e0f4d2SKip Macy 223789e0f4d2SKip Macy /* Set up ifnet structure */ 223823dc5621SKip Macy ifp = np->xn_ifp = if_alloc(IFT_ETHER); 223989e0f4d2SKip Macy ifp->if_softc = np; 224023dc5621SKip Macy if_initname(ifp, "xn", device_get_unit(dev)); 22413a6d1fcfSKip Macy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 224289e0f4d2SKip Macy ifp->if_ioctl = xn_ioctl; 2243*96375eacSRoger Pau Monné 2244*96375eacSRoger Pau Monné ifp->if_transmit = xn_txq_mq_start; 2245*96375eacSRoger Pau Monné ifp->if_qflush = xn_qflush; 2246*96375eacSRoger Pau Monné 224789e0f4d2SKip Macy ifp->if_init = xn_ifinit; 224889e0f4d2SKip Macy 224989e0f4d2SKip Macy ifp->if_hwassist = XN_CSUM_FEATURES; 225089e0f4d2SKip Macy ifp->if_capabilities = IFCAP_HWCSUM; 22519fd573c3SHans Petter Selasky ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 22529fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegcount = MAX_TX_REQ_FRAGS; 22539fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 225489e0f4d2SKip Macy 225589e0f4d2SKip Macy ether_ifattach(ifp, np->mac); 225689e0f4d2SKip Macy netfront_carrier_off(np); 225789e0f4d2SKip Macy 225889e0f4d2SKip Macy return (0); 225989e0f4d2SKip Macy 22601a2928b7SRoger Pau Monné error: 22611a2928b7SRoger Pau Monné KASSERT(err != 0, ("Error path with no error code specified")); 2262ffa06904SJustin T. Gibbs return (err); 226389e0f4d2SKip Macy } 226489e0f4d2SKip Macy 22650e509842SJustin T. Gibbs static int 22660e509842SJustin T. Gibbs netfront_detach(device_t dev) 226789e0f4d2SKip Macy { 226823dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 226989e0f4d2SKip Macy 227023dc5621SKip Macy DPRINTK("%s\n", xenbus_get_node(dev)); 227189e0f4d2SKip Macy 227289e0f4d2SKip Macy netif_free(info); 227389e0f4d2SKip Macy 227489e0f4d2SKip Macy return 0; 227589e0f4d2SKip Macy } 227689e0f4d2SKip Macy 22770e509842SJustin T. Gibbs static void 2278*96375eacSRoger Pau Monné netif_free(struct netfront_info *np) 227989e0f4d2SKip Macy { 2280*96375eacSRoger Pau Monné 2281*96375eacSRoger Pau Monné XN_LOCK(np); 2282*96375eacSRoger Pau Monné xn_stop(np); 2283*96375eacSRoger Pau Monné XN_UNLOCK(np); 2284*96375eacSRoger Pau Monné netif_disconnect_backend(np); 2285*96375eacSRoger Pau Monné free(np->rxq, M_DEVBUF); 2286*96375eacSRoger Pau Monné free(np->txq, M_DEVBUF); 2287*96375eacSRoger Pau Monné if (np->xn_ifp != NULL) { 2288*96375eacSRoger Pau Monné ether_ifdetach(np->xn_ifp); 2289*96375eacSRoger Pau Monné if_free(np->xn_ifp); 2290*96375eacSRoger Pau Monné np->xn_ifp = NULL; 2291e3242f9dSJustin T. Gibbs } 2292*96375eacSRoger Pau Monné ifmedia_removeall(&np->sc_media); 229389e0f4d2SKip Macy } 229489e0f4d2SKip Macy 22950e509842SJustin T. Gibbs static void 2296*96375eacSRoger Pau Monné netif_disconnect_backend(struct netfront_info *np) 229789e0f4d2SKip Macy { 2298*96375eacSRoger Pau Monné u_int i; 22993a6d1fcfSKip Macy 2300*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 2301*96375eacSRoger Pau Monné XN_RX_LOCK(&np->rxq[i]); 2302*96375eacSRoger Pau Monné XN_TX_LOCK(&np->txq[i]); 2303*96375eacSRoger Pau Monné } 2304*96375eacSRoger Pau Monné netfront_carrier_off(np); 2305*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 2306*96375eacSRoger Pau Monné XN_RX_UNLOCK(&np->rxq[i]); 2307*96375eacSRoger Pau Monné XN_TX_UNLOCK(&np->txq[i]); 230889e0f4d2SKip Macy } 230989e0f4d2SKip Macy 2310*96375eacSRoger Pau Monné for (i = 0; i < np->num_queues; i++) { 2311*96375eacSRoger Pau Monné disconnect_rxq(&np->rxq[i]); 2312*96375eacSRoger Pau Monné disconnect_txq(&np->txq[i]); 2313cf9c09e1SJustin T. Gibbs } 231489e0f4d2SKip Macy } 231589e0f4d2SKip Macy 23160e509842SJustin T. Gibbs static int 23170e509842SJustin T. Gibbs xn_ifmedia_upd(struct ifnet *ifp) 23180e509842SJustin T. Gibbs { 2319*96375eacSRoger Pau Monné 23200e509842SJustin T. Gibbs return (0); 23210e509842SJustin T. Gibbs } 23220e509842SJustin T. Gibbs 23230e509842SJustin T. Gibbs static void 23240e509842SJustin T. Gibbs xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 23250e509842SJustin T. Gibbs { 2326*96375eacSRoger Pau Monné 23270e509842SJustin T. Gibbs ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE; 23280e509842SJustin T. Gibbs ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; 23290e509842SJustin T. Gibbs } 23300e509842SJustin T. Gibbs 233189e0f4d2SKip Macy /* ** Driver registration ** */ 233223dc5621SKip Macy static device_method_t netfront_methods[] = { 233323dc5621SKip Macy /* Device interface */ 233423dc5621SKip Macy DEVMETHOD(device_probe, netfront_probe), 233523dc5621SKip Macy DEVMETHOD(device_attach, netfront_attach), 233623dc5621SKip Macy DEVMETHOD(device_detach, netfront_detach), 233723dc5621SKip Macy DEVMETHOD(device_shutdown, bus_generic_shutdown), 2338cf9c09e1SJustin T. Gibbs DEVMETHOD(device_suspend, netfront_suspend), 233923dc5621SKip Macy DEVMETHOD(device_resume, netfront_resume), 234089e0f4d2SKip Macy 234123dc5621SKip Macy /* Xenbus interface */ 2342ff662b5cSJustin T. Gibbs DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed), 234389e0f4d2SKip Macy 23446f9767acSMarius Strobl DEVMETHOD_END 234589e0f4d2SKip Macy }; 234689e0f4d2SKip Macy 234723dc5621SKip Macy static driver_t netfront_driver = { 234823dc5621SKip Macy "xn", 234923dc5621SKip Macy netfront_methods, 235023dc5621SKip Macy sizeof(struct netfront_info), 235189e0f4d2SKip Macy }; 235223dc5621SKip Macy devclass_t netfront_devclass; 235389e0f4d2SKip Macy 23546f9767acSMarius Strobl DRIVER_MODULE(xe, xenbusb_front, netfront_driver, netfront_devclass, NULL, 23556f9767acSMarius Strobl NULL); 2356