1207673Sjoel/*- 2181643Skmacy * Copyright (c) 2004-2006 Kip Macy 3181643Skmacy * All rights reserved. 4181643Skmacy * 5207673Sjoel * Redistribution and use in source and binary forms, with or without 6207673Sjoel * modification, are permitted provided that the following conditions 7207673Sjoel * are met: 8207673Sjoel * 1. Redistributions of source code must retain the above copyright 9207673Sjoel * notice, this list of conditions and the following disclaimer. 10207673Sjoel * 2. Redistributions in binary form must reproduce the above copyright 11207673Sjoel * notice, this list of conditions and the following disclaimer in the 12207673Sjoel * documentation and/or other materials provided with the distribution. 13181643Skmacy * 14207673Sjoel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15207673Sjoel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16207673Sjoel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17207673Sjoel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18207673Sjoel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19207673Sjoel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20207673Sjoel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21207673Sjoel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22207673Sjoel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23207673Sjoel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24207673Sjoel * SUCH DAMAGE. 25181643Skmacy */ 26181643Skmacy 27181643Skmacy#include <sys/cdefs.h> 28181643Skmacy__FBSDID("$FreeBSD$"); 29181643Skmacy 30221130Sbz#include "opt_inet.h" 31259541Sglebius#include "opt_inet6.h" 32221130Sbz 33181643Skmacy#include <sys/param.h> 34181643Skmacy#include <sys/systm.h> 35181643Skmacy#include <sys/sockio.h> 36181643Skmacy#include <sys/mbuf.h> 37181643Skmacy#include <sys/malloc.h> 38185605Skmacy#include <sys/module.h> 39181643Skmacy#include <sys/kernel.h> 40181643Skmacy#include <sys/socket.h> 41189699Sdfr#include <sys/sysctl.h> 42181643Skmacy#include <sys/queue.h> 43193618Sadrian#include <sys/lock.h> 44181643Skmacy#include <sys/sx.h> 45181643Skmacy 46181643Skmacy#include <net/if.h> 47181643Skmacy#include <net/if_arp.h> 48181643Skmacy#include <net/ethernet.h> 49181643Skmacy#include <net/if_dl.h> 50181643Skmacy#include <net/if_media.h> 51181643Skmacy 52181643Skmacy#include <net/bpf.h> 53181643Skmacy 54181643Skmacy#include <net/if_types.h> 55181643Skmacy#include <net/if.h> 56181643Skmacy 57181643Skmacy#include <netinet/in_systm.h> 58181643Skmacy#include <netinet/in.h> 59181643Skmacy#include <netinet/ip.h> 60181643Skmacy#include <netinet/if_ether.h> 61189699Sdfr#if __FreeBSD_version >= 700000 62189699Sdfr#include <netinet/tcp.h> 63189699Sdfr#include <netinet/tcp_lro.h> 64189699Sdfr#endif 65181643Skmacy 66181643Skmacy#include <vm/vm.h> 67181643Skmacy#include <vm/pmap.h> 68181643Skmacy 69181643Skmacy#include <machine/clock.h> /* for DELAY */ 70181643Skmacy#include <machine/bus.h> 71181643Skmacy#include <machine/resource.h> 72181643Skmacy#include <machine/frame.h> 73181910Skmacy#include <machine/vmparam.h> 74181643Skmacy 75181643Skmacy#include <sys/bus.h> 76181643Skmacy#include <sys/rman.h> 77181643Skmacy 78181643Skmacy#include <machine/intr_machdep.h> 79181643Skmacy 80255040Sgibbs#include <xen/xen-os.h> 81186557Skmacy#include <xen/hypervisor.h> 82186557Skmacy#include <xen/xen_intr.h> 83181643Skmacy#include <xen/gnttab.h> 84181643Skmacy#include <xen/interface/memory.h> 85181643Skmacy#include <xen/interface/io/netif.h> 86185605Skmacy#include <xen/xenbus/xenbusvar.h> 87181643Skmacy 88255040Sgibbs#include <machine/xen/xenvar.h> 89255040Sgibbs 90189699Sdfr#include <dev/xen/netfront/mbufq.h> 91189699Sdfr 92185605Skmacy#include "xenbus_if.h" 93181643Skmacy 94225709Sgibbs/* Features supported by all backends. TSO and LRO can be negotiated */ 95225709Sgibbs#define XN_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) 96189699Sdfr 97181643Skmacy#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) 98181643Skmacy#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) 99181643Skmacy 100189699Sdfr#if __FreeBSD_version >= 700000 101189699Sdfr/* 102189699Sdfr * Should the driver do LRO on the RX end 103189699Sdfr * this can be toggled on the fly, but the 104189699Sdfr * interface must be reset (down/up) for it 105189699Sdfr * to take effect. 106189699Sdfr */ 107189699Sdfrstatic int xn_enable_lro = 1; 108189699SdfrTUNABLE_INT("hw.xn.enable_lro", &xn_enable_lro); 109189699Sdfr#else 110189699Sdfr 111189699Sdfr#define IFCAP_TSO4 0 112189699Sdfr#define CSUM_TSO 0 113189699Sdfr 114189699Sdfr#endif 115189699Sdfr 116181643Skmacy#ifdef CONFIG_XEN 117181643Skmacystatic int MODPARM_rx_copy = 0; 118181643Skmacymodule_param_named(rx_copy, MODPARM_rx_copy, bool, 0); 119181643SkmacyMODULE_PARM_DESC(rx_copy, "Copy packets from network card (rather than flip)"); 120181643Skmacystatic int MODPARM_rx_flip = 0; 121181643Skmacymodule_param_named(rx_flip, MODPARM_rx_flip, bool, 0); 122181643SkmacyMODULE_PARM_DESC(rx_flip, "Flip packets from network card (rather than copy)"); 123181643Skmacy#else 124181643Skmacystatic const int MODPARM_rx_copy = 1; 125181643Skmacystatic const int MODPARM_rx_flip = 0; 126181643Skmacy#endif 127181643Skmacy 128208901Sken/** 129208901Sken * \brief The maximum allowed data fragments in a single transmit 130208901Sken * request. 131208901Sken * 132208901Sken * This limit is imposed by the backend driver. We assume here that 133208901Sken * we are dealing with a Linux driver domain and have set our limit 134208901Sken * to mirror the Linux MAX_SKB_FRAGS constant. 135208901Sken */ 136208901Sken#define MAX_TX_REQ_FRAGS (65536 / PAGE_SIZE + 2) 137251297Sandre#define NF_TSO_MAXBURST ((IP_MAXPACKET / PAGE_SIZE) * MCLBYTES) 138208901Sken 139181643Skmacy#define RX_COPY_THRESHOLD 256 140181643Skmacy 141181643Skmacy#define net_ratelimit() 0 142181643Skmacy 143181643Skmacystruct netfront_info; 144181643Skmacystruct netfront_rx_info; 145181643Skmacy 146181643Skmacystatic void xn_txeof(struct netfront_info *); 147181643Skmacystatic void xn_rxeof(struct netfront_info *); 148181643Skmacystatic void network_alloc_rx_buffers(struct netfront_info *); 149181643Skmacy 150181643Skmacystatic void xn_tick_locked(struct netfront_info *); 151181643Skmacystatic void xn_tick(void *); 152181643Skmacy 153181643Skmacystatic void xn_intr(void *); 154208901Skenstatic inline int xn_count_frags(struct mbuf *m); 155208901Skenstatic int xn_assemble_tx_request(struct netfront_info *sc, 156208901Sken struct mbuf *m_head); 157181643Skmacystatic void xn_start_locked(struct ifnet *); 158181643Skmacystatic void xn_start(struct ifnet *); 159181643Skmacystatic int xn_ioctl(struct ifnet *, u_long, caddr_t); 160181643Skmacystatic void xn_ifinit_locked(struct netfront_info *); 161181643Skmacystatic void xn_ifinit(void *); 162181643Skmacystatic void xn_stop(struct netfront_info *); 163225709Sgibbsstatic void xn_query_features(struct netfront_info *np); 164225709Sgibbsstatic int xn_configure_features(struct netfront_info *np); 165181643Skmacy#ifdef notyet 166181643Skmacystatic void xn_watchdog(struct ifnet *); 167181643Skmacy#endif 168181643Skmacy 169181643Skmacy#ifdef notyet 170185605Skmacystatic void netfront_closing(device_t dev); 171181643Skmacy#endif 172181643Skmacystatic void netif_free(struct netfront_info *info); 173185605Skmacystatic int netfront_detach(device_t dev); 174181643Skmacy 175185605Skmacystatic int talk_to_backend(device_t dev, struct netfront_info *info); 176185605Skmacystatic int create_netdev(device_t dev); 177181643Skmacystatic void netif_disconnect_backend(struct netfront_info *info); 178185605Skmacystatic int setup_device(device_t dev, struct netfront_info *info); 179225707Sgibbsstatic void free_ring(int *ref, void *ring_ptr_ref); 180181643Skmacy 181199997Sgibbsstatic int xn_ifmedia_upd(struct ifnet *ifp); 182199997Sgibbsstatic void xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 183199997Sgibbs 184181643Skmacy/* Xenolinux helper functions */ 185185605Skmacyint network_connect(struct netfront_info *); 186181643Skmacy 187181643Skmacystatic void xn_free_rx_ring(struct netfront_info *); 188181643Skmacy 189181643Skmacystatic void xn_free_tx_ring(struct netfront_info *); 190181643Skmacy 191181643Skmacystatic int xennet_get_responses(struct netfront_info *np, 192208901Sken struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, 193208901Sken struct mbuf **list, int *pages_flipped_p); 194181643Skmacy 195181643Skmacy#define virt_to_mfn(x) (vtomach(x) >> PAGE_SHIFT) 196181643Skmacy 197181643Skmacy#define INVALID_P2M_ENTRY (~0UL) 198181643Skmacy 199181643Skmacy/* 200181643Skmacy * Mbuf pointers. We need these to keep track of the virtual addresses 201181643Skmacy * of our mbuf chains since we can only convert from virtual to physical, 202181643Skmacy * not the other way around. The size must track the free index arrays. 203181643Skmacy */ 204181643Skmacystruct xn_chain_data { 205208901Sken struct mbuf *xn_tx_chain[NET_TX_RING_SIZE+1]; 206208901Sken int xn_tx_chain_cnt; 207208901Sken struct mbuf *xn_rx_chain[NET_RX_RING_SIZE+1]; 208181643Skmacy}; 209181643Skmacy 210181643Skmacystruct net_device_stats 211181643Skmacy{ 212181643Skmacy u_long rx_packets; /* total packets received */ 213181643Skmacy u_long tx_packets; /* total packets transmitted */ 214181643Skmacy u_long rx_bytes; /* total bytes received */ 215181643Skmacy u_long tx_bytes; /* total bytes transmitted */ 216181643Skmacy u_long rx_errors; /* bad packets received */ 217181643Skmacy u_long tx_errors; /* packet transmit problems */ 218181643Skmacy u_long rx_dropped; /* no space in linux buffers */ 219181643Skmacy u_long tx_dropped; /* no space available in linux */ 220181643Skmacy u_long multicast; /* multicast packets received */ 221181643Skmacy u_long collisions; 222181643Skmacy 223181643Skmacy /* detailed rx_errors: */ 224181643Skmacy u_long rx_length_errors; 225181643Skmacy u_long rx_over_errors; /* receiver ring buff overflow */ 226181643Skmacy u_long rx_crc_errors; /* recved pkt with crc error */ 227181643Skmacy u_long rx_frame_errors; /* recv'd frame alignment error */ 228181643Skmacy u_long rx_fifo_errors; /* recv'r fifo overrun */ 229181643Skmacy u_long rx_missed_errors; /* receiver missed packet */ 230181643Skmacy 231181643Skmacy /* detailed tx_errors */ 232181643Skmacy u_long tx_aborted_errors; 233181643Skmacy u_long tx_carrier_errors; 234181643Skmacy u_long tx_fifo_errors; 235181643Skmacy u_long tx_heartbeat_errors; 236181643Skmacy u_long tx_window_errors; 237181643Skmacy 238181643Skmacy /* for cslip etc */ 239181643Skmacy u_long rx_compressed; 240181643Skmacy u_long tx_compressed; 241181643Skmacy}; 242181643Skmacy 243181643Skmacystruct netfront_info { 244181643Skmacy struct ifnet *xn_ifp; 245189699Sdfr#if __FreeBSD_version >= 700000 246189699Sdfr struct lro_ctrl xn_lro; 247189699Sdfr#endif 248181643Skmacy 249181643Skmacy struct net_device_stats stats; 250181643Skmacy u_int tx_full; 251181643Skmacy 252181643Skmacy netif_tx_front_ring_t tx; 253181643Skmacy netif_rx_front_ring_t rx; 254181643Skmacy 255181643Skmacy struct mtx tx_lock; 256181643Skmacy struct mtx rx_lock; 257204158Skmacy struct mtx sc_lock; 258181643Skmacy 259255040Sgibbs xen_intr_handle_t xen_intr_handle; 260181643Skmacy u_int copying_receiver; 261181643Skmacy u_int carrier; 262225709Sgibbs u_int maxfrags; 263181643Skmacy 264181643Skmacy /* Receive-ring batched refills. */ 265181643Skmacy#define RX_MIN_TARGET 32 266181643Skmacy#define RX_MAX_TARGET NET_RX_RING_SIZE 267199997Sgibbs int rx_min_target; 268199997Sgibbs int rx_max_target; 269199997Sgibbs int rx_target; 270181643Skmacy 271181643Skmacy grant_ref_t gref_tx_head; 272181643Skmacy grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1]; 273181643Skmacy grant_ref_t gref_rx_head; 274181643Skmacy grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1]; 275181643Skmacy 276199997Sgibbs device_t xbdev; 277199997Sgibbs int tx_ring_ref; 278199997Sgibbs int rx_ring_ref; 279199997Sgibbs uint8_t mac[ETHER_ADDR_LEN]; 280181643Skmacy struct xn_chain_data xn_cdata; /* mbufs */ 281199997Sgibbs struct mbuf_head xn_rx_batch; /* head of the batch queue */ 282181643Skmacy 283181643Skmacy int xn_if_flags; 284181643Skmacy struct callout xn_stat_ch; 285181643Skmacy 286199997Sgibbs u_long rx_pfn_array[NET_RX_RING_SIZE]; 287199997Sgibbs multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1]; 288199997Sgibbs mmu_update_t rx_mmu[NET_RX_RING_SIZE]; 289199997Sgibbs struct ifmedia sc_media; 290181643Skmacy}; 291181643Skmacy 292181643Skmacy#define rx_mbufs xn_cdata.xn_rx_chain 293181643Skmacy#define tx_mbufs xn_cdata.xn_tx_chain 294181643Skmacy 295181643Skmacy#define XN_LOCK_INIT(_sc, _name) \ 296181643Skmacy mtx_init(&(_sc)->tx_lock, #_name"_tx", "network transmit lock", MTX_DEF); \ 297181643Skmacy mtx_init(&(_sc)->rx_lock, #_name"_rx", "network receive lock", MTX_DEF); \ 298208901Sken mtx_init(&(_sc)->sc_lock, #_name"_sc", "netfront softc lock", MTX_DEF) 299181643Skmacy 300181643Skmacy#define XN_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_lock) 301181643Skmacy#define XN_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_lock) 302181643Skmacy 303181643Skmacy#define XN_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_lock) 304181643Skmacy#define XN_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_lock) 305181643Skmacy 306204158Skmacy#define XN_LOCK(_sc) mtx_lock(&(_sc)->sc_lock); 307204158Skmacy#define XN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock); 308181643Skmacy 309204158Skmacy#define XN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED); 310181643Skmacy#define XN_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_lock, MA_OWNED); 311181643Skmacy#define XN_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_lock, MA_OWNED); 312181643Skmacy#define XN_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_lock); \ 313181643Skmacy mtx_destroy(&(_sc)->tx_lock); \ 314204158Skmacy mtx_destroy(&(_sc)->sc_lock); 315181643Skmacy 316181643Skmacystruct netfront_rx_info { 317181643Skmacy struct netif_rx_response rx; 318181643Skmacy struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; 319181643Skmacy}; 320181643Skmacy 321181643Skmacy#define netfront_carrier_on(netif) ((netif)->carrier = 1) 322181643Skmacy#define netfront_carrier_off(netif) ((netif)->carrier = 0) 323181643Skmacy#define netfront_carrier_ok(netif) ((netif)->carrier) 324181643Skmacy 325181643Skmacy/* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ 326181643Skmacy 327181643Skmacystatic inline void 328208901Skenadd_id_to_freelist(struct mbuf **list, uintptr_t id) 329181643Skmacy{ 330208901Sken KASSERT(id != 0, 331208901Sken ("%s: the head item (0) must always be free.", __func__)); 332181643Skmacy list[id] = list[0]; 333208901Sken list[0] = (struct mbuf *)id; 334181643Skmacy} 335181643Skmacy 336181643Skmacystatic inline unsigned short 337181643Skmacyget_id_from_freelist(struct mbuf **list) 338181643Skmacy{ 339208901Sken uintptr_t id; 340208901Sken 341208901Sken id = (uintptr_t)list[0]; 342208901Sken KASSERT(id != 0, 343208901Sken ("%s: the head item (0) must always remain free.", __func__)); 344181643Skmacy list[0] = list[id]; 345181643Skmacy return (id); 346181643Skmacy} 347181643Skmacy 348181643Skmacystatic inline int 349181643Skmacyxennet_rxidx(RING_IDX idx) 350181643Skmacy{ 351181643Skmacy return idx & (NET_RX_RING_SIZE - 1); 352181643Skmacy} 353181643Skmacy 354181643Skmacystatic inline struct mbuf * 355208901Skenxennet_get_rx_mbuf(struct netfront_info *np, RING_IDX ri) 356181643Skmacy{ 357181643Skmacy int i = xennet_rxidx(ri); 358181643Skmacy struct mbuf *m; 359181643Skmacy 360181643Skmacy m = np->rx_mbufs[i]; 361181643Skmacy np->rx_mbufs[i] = NULL; 362181643Skmacy return (m); 363181643Skmacy} 364181643Skmacy 365181643Skmacystatic inline grant_ref_t 366181643Skmacyxennet_get_rx_ref(struct netfront_info *np, RING_IDX ri) 367181643Skmacy{ 368181643Skmacy int i = xennet_rxidx(ri); 369181643Skmacy grant_ref_t ref = np->grant_rx_ref[i]; 370214077Sgibbs KASSERT(ref != GRANT_REF_INVALID, ("Invalid grant reference!\n")); 371214077Sgibbs np->grant_rx_ref[i] = GRANT_REF_INVALID; 372181643Skmacy return ref; 373181643Skmacy} 374181643Skmacy 375181643Skmacy#define IPRINTK(fmt, args...) \ 376181643Skmacy printf("[XEN] " fmt, ##args) 377204158Skmacy#ifdef INVARIANTS 378181643Skmacy#define WPRINTK(fmt, args...) \ 379181643Skmacy printf("[XEN] " fmt, ##args) 380204158Skmacy#else 381204158Skmacy#define WPRINTK(fmt, args...) 382204158Skmacy#endif 383204158Skmacy#ifdef DEBUG 384181643Skmacy#define DPRINTK(fmt, args...) \ 385185605Skmacy printf("[XEN] %s: " fmt, __func__, ##args) 386189699Sdfr#else 387189699Sdfr#define DPRINTK(fmt, args...) 388189699Sdfr#endif 389181643Skmacy 390181643Skmacy/** 391181643Skmacy * Read the 'mac' node at the given device's node in the store, and parse that 392181643Skmacy * as colon-separated octets, placing result the given mac array. mac must be 393181643Skmacy * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). 394181643Skmacy * Return 0 on success, or errno on error. 395181643Skmacy */ 396181643Skmacystatic int 397185605Skmacyxen_net_read_mac(device_t dev, uint8_t mac[]) 398181643Skmacy{ 399186557Skmacy int error, i; 400186557Skmacy char *s, *e, *macstr; 401225708Sgibbs const char *path; 402186557Skmacy 403225708Sgibbs path = xenbus_get_node(dev); 404225708Sgibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 405225708Sgibbs if (error == ENOENT) { 406225708Sgibbs /* 407225708Sgibbs * Deal with missing mac XenStore nodes on devices with 408225708Sgibbs * HVM emulation (the 'ioemu' configuration attribute) 409225708Sgibbs * enabled. 410225708Sgibbs * 411225708Sgibbs * The HVM emulator may execute in a stub device model 412225708Sgibbs * domain which lacks the permission, only given to Dom0, 413225708Sgibbs * to update the guest's XenStore tree. For this reason, 414225708Sgibbs * the HVM emulator doesn't even attempt to write the 415225708Sgibbs * front-side mac node, even when operating in Dom0. 416225708Sgibbs * However, there should always be a mac listed in the 417225708Sgibbs * backend tree. Fallback to this version if our query 418225708Sgibbs * of the front side XenStore location doesn't find 419225708Sgibbs * anything. 420225708Sgibbs */ 421225708Sgibbs path = xenbus_get_otherend_path(dev); 422225708Sgibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 423225708Sgibbs } 424225708Sgibbs if (error != 0) { 425225708Sgibbs xenbus_dev_fatal(dev, error, "parsing %s/mac", path); 426186557Skmacy return (error); 427225708Sgibbs } 428186557Skmacy 429181643Skmacy s = macstr; 430181643Skmacy for (i = 0; i < ETHER_ADDR_LEN; i++) { 431181643Skmacy mac[i] = strtoul(s, &e, 16); 432181643Skmacy if (s == e || (e[0] != ':' && e[0] != 0)) { 433214077Sgibbs free(macstr, M_XENBUS); 434186557Skmacy return (ENOENT); 435181643Skmacy } 436181643Skmacy s = &e[1]; 437181643Skmacy } 438214077Sgibbs free(macstr, M_XENBUS); 439186557Skmacy return (0); 440181643Skmacy} 441181643Skmacy 442181643Skmacy/** 443181643Skmacy * Entry point to this code when a new device is created. Allocate the basic 444181643Skmacy * structures and the ring buffers for communication with the backend, and 445181643Skmacy * inform the backend of the appropriate details for those. Switch to 446181643Skmacy * Connected state. 447181643Skmacy */ 448181643Skmacystatic int 449185605Skmacynetfront_probe(device_t dev) 450181643Skmacy{ 451185605Skmacy 452185605Skmacy if (!strcmp(xenbus_get_type(dev), "vif")) { 453185605Skmacy device_set_desc(dev, "Virtual Network Interface"); 454185605Skmacy return (0); 455185605Skmacy } 456185605Skmacy 457185605Skmacy return (ENXIO); 458185605Skmacy} 459185605Skmacy 460185605Skmacystatic int 461185605Skmacynetfront_attach(device_t dev) 462185605Skmacy{ 463181643Skmacy int err; 464181643Skmacy 465185605Skmacy err = create_netdev(dev); 466181643Skmacy if (err) { 467181643Skmacy xenbus_dev_fatal(dev, err, "creating netdev"); 468225708Sgibbs return (err); 469181643Skmacy } 470181643Skmacy 471189699Sdfr#if __FreeBSD_version >= 700000 472189699Sdfr SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 473189699Sdfr SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 474189699Sdfr OID_AUTO, "enable_lro", CTLTYPE_INT|CTLFLAG_RW, 475189699Sdfr &xn_enable_lro, 0, "Large Receive Offload"); 476189699Sdfr#endif 477189699Sdfr 478225708Sgibbs return (0); 479181643Skmacy} 480181643Skmacy 481225707Sgibbsstatic int 482225707Sgibbsnetfront_suspend(device_t dev) 483225707Sgibbs{ 484225707Sgibbs struct netfront_info *info = device_get_softc(dev); 485181643Skmacy 486225707Sgibbs XN_RX_LOCK(info); 487225707Sgibbs XN_TX_LOCK(info); 488225707Sgibbs netfront_carrier_off(info); 489225707Sgibbs XN_TX_UNLOCK(info); 490225707Sgibbs XN_RX_UNLOCK(info); 491225707Sgibbs return (0); 492225707Sgibbs} 493225707Sgibbs 494181643Skmacy/** 495181643Skmacy * We are reconnecting to the backend, due to a suspend/resume, or a backend 496181643Skmacy * driver restart. We tear down our netif structure and recreate it, but 497181643Skmacy * leave the device-layer structures intact so that this is transparent to the 498181643Skmacy * rest of the kernel. 499181643Skmacy */ 500186557Skmacystatic int 501185605Skmacynetfront_resume(device_t dev) 502181643Skmacy{ 503185605Skmacy struct netfront_info *info = device_get_softc(dev); 504186557Skmacy 505181643Skmacy netif_disconnect_backend(info); 506181643Skmacy return (0); 507181643Skmacy} 508181643Skmacy 509181643Skmacy/* Common code used when first setting up, and when resuming. */ 510181643Skmacystatic int 511185605Skmacytalk_to_backend(device_t dev, struct netfront_info *info) 512181643Skmacy{ 513181643Skmacy const char *message; 514214077Sgibbs struct xs_transaction xst; 515185605Skmacy const char *node = xenbus_get_node(dev); 516181643Skmacy int err; 517181643Skmacy 518181643Skmacy err = xen_net_read_mac(dev, info->mac); 519181643Skmacy if (err) { 520185605Skmacy xenbus_dev_fatal(dev, err, "parsing %s/mac", node); 521181643Skmacy goto out; 522181643Skmacy } 523181643Skmacy 524181643Skmacy /* Create shared ring, alloc event channel. */ 525181643Skmacy err = setup_device(dev, info); 526181643Skmacy if (err) 527181643Skmacy goto out; 528181643Skmacy 529181643Skmacy again: 530214077Sgibbs err = xs_transaction_start(&xst); 531181643Skmacy if (err) { 532181643Skmacy xenbus_dev_fatal(dev, err, "starting transaction"); 533181643Skmacy goto destroy_ring; 534181643Skmacy } 535214077Sgibbs err = xs_printf(xst, node, "tx-ring-ref","%u", 536208901Sken info->tx_ring_ref); 537181643Skmacy if (err) { 538181643Skmacy message = "writing tx ring-ref"; 539181643Skmacy goto abort_transaction; 540181643Skmacy } 541214077Sgibbs err = xs_printf(xst, node, "rx-ring-ref","%u", 542208901Sken info->rx_ring_ref); 543181643Skmacy if (err) { 544181643Skmacy message = "writing rx ring-ref"; 545181643Skmacy goto abort_transaction; 546181643Skmacy } 547214077Sgibbs err = xs_printf(xst, node, 548255040Sgibbs "event-channel", "%u", 549255040Sgibbs xen_intr_port(info->xen_intr_handle)); 550181643Skmacy if (err) { 551181643Skmacy message = "writing event-channel"; 552181643Skmacy goto abort_transaction; 553181643Skmacy } 554214077Sgibbs err = xs_printf(xst, node, "request-rx-copy", "%u", 555208901Sken info->copying_receiver); 556181643Skmacy if (err) { 557181643Skmacy message = "writing request-rx-copy"; 558181643Skmacy goto abort_transaction; 559181643Skmacy } 560214077Sgibbs err = xs_printf(xst, node, "feature-rx-notify", "%d", 1); 561181643Skmacy if (err) { 562181643Skmacy message = "writing feature-rx-notify"; 563181643Skmacy goto abort_transaction; 564181643Skmacy } 565214077Sgibbs err = xs_printf(xst, node, "feature-sg", "%d", 1); 566181643Skmacy if (err) { 567181643Skmacy message = "writing feature-sg"; 568181643Skmacy goto abort_transaction; 569181643Skmacy } 570189699Sdfr#if __FreeBSD_version >= 700000 571214077Sgibbs err = xs_printf(xst, node, "feature-gso-tcpv4", "%d", 1); 572181643Skmacy if (err) { 573181643Skmacy message = "writing feature-gso-tcpv4"; 574181643Skmacy goto abort_transaction; 575181643Skmacy } 576181643Skmacy#endif 577181643Skmacy 578214077Sgibbs err = xs_transaction_end(xst, 0); 579181643Skmacy if (err) { 580181643Skmacy if (err == EAGAIN) 581181643Skmacy goto again; 582181643Skmacy xenbus_dev_fatal(dev, err, "completing transaction"); 583181643Skmacy goto destroy_ring; 584181643Skmacy } 585181643Skmacy 586181643Skmacy return 0; 587181643Skmacy 588181643Skmacy abort_transaction: 589214077Sgibbs xs_transaction_end(xst, 1); 590181643Skmacy xenbus_dev_fatal(dev, err, "%s", message); 591181643Skmacy destroy_ring: 592181643Skmacy netif_free(info); 593181643Skmacy out: 594181643Skmacy return err; 595181643Skmacy} 596181643Skmacy 597181643Skmacystatic int 598185605Skmacysetup_device(device_t dev, struct netfront_info *info) 599181643Skmacy{ 600181643Skmacy netif_tx_sring_t *txs; 601181643Skmacy netif_rx_sring_t *rxs; 602186557Skmacy int error; 603181643Skmacy struct ifnet *ifp; 604181643Skmacy 605181643Skmacy ifp = info->xn_ifp; 606181643Skmacy 607214077Sgibbs info->tx_ring_ref = GRANT_REF_INVALID; 608214077Sgibbs info->rx_ring_ref = GRANT_REF_INVALID; 609181643Skmacy info->rx.sring = NULL; 610181643Skmacy info->tx.sring = NULL; 611181643Skmacy 612181643Skmacy txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); 613181643Skmacy if (!txs) { 614186557Skmacy error = ENOMEM; 615186557Skmacy xenbus_dev_fatal(dev, error, "allocating tx ring page"); 616181643Skmacy goto fail; 617181643Skmacy } 618181643Skmacy SHARED_RING_INIT(txs); 619181643Skmacy FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE); 620186557Skmacy error = xenbus_grant_ring(dev, virt_to_mfn(txs), &info->tx_ring_ref); 621186557Skmacy if (error) 622181643Skmacy goto fail; 623181643Skmacy 624181643Skmacy rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); 625181643Skmacy if (!rxs) { 626186557Skmacy error = ENOMEM; 627186557Skmacy xenbus_dev_fatal(dev, error, "allocating rx ring page"); 628181643Skmacy goto fail; 629181643Skmacy } 630181643Skmacy SHARED_RING_INIT(rxs); 631181643Skmacy FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); 632181643Skmacy 633186557Skmacy error = xenbus_grant_ring(dev, virt_to_mfn(rxs), &info->rx_ring_ref); 634186557Skmacy if (error) 635181643Skmacy goto fail; 636181643Skmacy 637255040Sgibbs error = xen_intr_alloc_and_bind_local_port(dev, 638255040Sgibbs xenbus_get_otherend_id(dev), /*filter*/NULL, xn_intr, info, 639255040Sgibbs INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY, &info->xen_intr_handle); 640181643Skmacy 641186557Skmacy if (error) { 642186557Skmacy xenbus_dev_fatal(dev, error, 643255040Sgibbs "xen_intr_alloc_and_bind_local_port failed"); 644181643Skmacy goto fail; 645181643Skmacy } 646186557Skmacy 647186557Skmacy return (0); 648181643Skmacy 649181643Skmacy fail: 650181643Skmacy netif_free(info); 651186557Skmacy return (error); 652181643Skmacy} 653181643Skmacy 654221130Sbz#ifdef INET 655181643Skmacy/** 656189699Sdfr * If this interface has an ipv4 address, send an arp for it. This 657189699Sdfr * helps to get the network going again after migrating hosts. 658189699Sdfr */ 659189699Sdfrstatic void 660189699Sdfrnetfront_send_fake_arp(device_t dev, struct netfront_info *info) 661189699Sdfr{ 662189699Sdfr struct ifnet *ifp; 663189699Sdfr struct ifaddr *ifa; 664189699Sdfr 665189699Sdfr ifp = info->xn_ifp; 666189699Sdfr TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 667189699Sdfr if (ifa->ifa_addr->sa_family == AF_INET) { 668189699Sdfr arp_ifinit(ifp, ifa); 669189699Sdfr } 670189699Sdfr } 671189699Sdfr} 672221130Sbz#endif 673189699Sdfr 674189699Sdfr/** 675181643Skmacy * Callback received when the backend's state changes. 676181643Skmacy */ 677222975Sgibbsstatic void 678185605Skmacynetfront_backend_changed(device_t dev, XenbusState newstate) 679181643Skmacy{ 680185605Skmacy struct netfront_info *sc = device_get_softc(dev); 681181643Skmacy 682185605Skmacy DPRINTK("newstate=%d\n", newstate); 683185605Skmacy 684185605Skmacy switch (newstate) { 685181643Skmacy case XenbusStateInitialising: 686181643Skmacy case XenbusStateInitialised: 687181643Skmacy case XenbusStateConnected: 688181643Skmacy case XenbusStateUnknown: 689181643Skmacy case XenbusStateClosed: 690183375Skmacy case XenbusStateReconfigured: 691183375Skmacy case XenbusStateReconfiguring: 692185605Skmacy break; 693181643Skmacy case XenbusStateInitWait: 694185605Skmacy if (xenbus_get_state(dev) != XenbusStateInitialising) 695181643Skmacy break; 696185605Skmacy if (network_connect(sc) != 0) 697181643Skmacy break; 698185605Skmacy xenbus_set_state(dev, XenbusStateConnected); 699221130Sbz#ifdef INET 700189699Sdfr netfront_send_fake_arp(dev, sc); 701221130Sbz#endif 702185605Skmacy break; 703181643Skmacy case XenbusStateClosing: 704185605Skmacy xenbus_set_state(dev, XenbusStateClosed); 705181643Skmacy break; 706181643Skmacy } 707181643Skmacy} 708181643Skmacy 709181643Skmacystatic void 710181643Skmacyxn_free_rx_ring(struct netfront_info *sc) 711181643Skmacy{ 712181643Skmacy#if 0 713181643Skmacy int i; 714181643Skmacy 715181643Skmacy for (i = 0; i < NET_RX_RING_SIZE; i++) { 716208901Sken if (sc->xn_cdata.rx_mbufs[i] != NULL) { 717208901Sken m_freem(sc->rx_mbufs[i]); 718208901Sken sc->rx_mbufs[i] = NULL; 719181643Skmacy } 720181643Skmacy } 721181643Skmacy 722181643Skmacy sc->rx.rsp_cons = 0; 723181643Skmacy sc->xn_rx_if->req_prod = 0; 724181643Skmacy sc->xn_rx_if->event = sc->rx.rsp_cons ; 725181643Skmacy#endif 726181643Skmacy} 727181643Skmacy 728181643Skmacystatic void 729181643Skmacyxn_free_tx_ring(struct netfront_info *sc) 730181643Skmacy{ 731181643Skmacy#if 0 732181643Skmacy int i; 733181643Skmacy 734181643Skmacy for (i = 0; i < NET_TX_RING_SIZE; i++) { 735208901Sken if (sc->tx_mbufs[i] != NULL) { 736208901Sken m_freem(sc->tx_mbufs[i]); 737181643Skmacy sc->xn_cdata.xn_tx_chain[i] = NULL; 738181643Skmacy } 739181643Skmacy } 740181643Skmacy 741181643Skmacy return; 742181643Skmacy#endif 743181643Skmacy} 744181643Skmacy 745208901Sken/** 746208901Sken * \brief Verify that there is sufficient space in the Tx ring 747208901Sken * buffer for a maximally sized request to be enqueued. 748192869Sadrian * 749208901Sken * A transmit request requires a transmit descriptor for each packet 750208901Sken * fragment, plus up to 2 entries for "options" (e.g. TSO). 751192869Sadrian */ 752181643Skmacystatic inline int 753208901Skenxn_tx_slot_available(struct netfront_info *np) 754181643Skmacy{ 755208901Sken return (RING_FREE_REQUESTS(&np->tx) > (MAX_TX_REQ_FRAGS + 2)); 756181643Skmacy} 757208901Sken 758181643Skmacystatic void 759181643Skmacynetif_release_tx_bufs(struct netfront_info *np) 760181643Skmacy{ 761181643Skmacy int i; 762181643Skmacy 763181643Skmacy for (i = 1; i <= NET_TX_RING_SIZE; i++) { 764208901Sken struct mbuf *m; 765181643Skmacy 766208901Sken m = np->tx_mbufs[i]; 767208901Sken 768208901Sken /* 769208901Sken * We assume that no kernel addresses are 770208901Sken * less than NET_TX_RING_SIZE. Any entry 771208901Sken * in the table that is below this number 772208901Sken * must be an index from free-list tracking. 773208901Sken */ 774208901Sken if (((uintptr_t)m) <= NET_TX_RING_SIZE) 775181643Skmacy continue; 776225707Sgibbs gnttab_end_foreign_access_ref(np->grant_tx_ref[i]); 777181643Skmacy gnttab_release_grant_reference(&np->gref_tx_head, 778181643Skmacy np->grant_tx_ref[i]); 779214077Sgibbs np->grant_tx_ref[i] = GRANT_REF_INVALID; 780181643Skmacy add_id_to_freelist(np->tx_mbufs, i); 781192871Sadrian np->xn_cdata.xn_tx_chain_cnt--; 782192871Sadrian if (np->xn_cdata.xn_tx_chain_cnt < 0) { 783244991Smarius panic("%s: tx_chain_cnt must be >= 0", __func__); 784192871Sadrian } 785225707Sgibbs m_free(m); 786181643Skmacy } 787181643Skmacy} 788181643Skmacy 789181643Skmacystatic void 790181643Skmacynetwork_alloc_rx_buffers(struct netfront_info *sc) 791181643Skmacy{ 792185605Skmacy int otherend_id = xenbus_get_otherend_id(sc->xbdev); 793181643Skmacy unsigned short id; 794181643Skmacy struct mbuf *m_new; 795181643Skmacy int i, batch_target, notify; 796181643Skmacy RING_IDX req_prod; 797181643Skmacy struct xen_memory_reservation reservation; 798181643Skmacy grant_ref_t ref; 799181643Skmacy int nr_flips; 800181643Skmacy netif_rx_request_t *req; 801181643Skmacy vm_offset_t vaddr; 802181643Skmacy u_long pfn; 803181643Skmacy 804181643Skmacy req_prod = sc->rx.req_prod_pvt; 805181643Skmacy 806255040Sgibbs if (__predict_false(sc->carrier == 0)) 807181643Skmacy return; 808181643Skmacy 809181643Skmacy /* 810208901Sken * Allocate mbufs greedily, even though we batch updates to the 811181643Skmacy * receive ring. This creates a less bursty demand on the memory 812208901Sken * allocator, and so should reduce the chance of failed allocation 813181643Skmacy * requests both for ourself and for other kernel subsystems. 814208901Sken * 815208901Sken * Here we attempt to maintain rx_target buffers in flight, counting 816208901Sken * buffers that we have yet to process in the receive ring. 817181643Skmacy */ 818181643Skmacy batch_target = sc->rx_target - (req_prod - sc->rx.rsp_cons); 819181643Skmacy for (i = mbufq_len(&sc->xn_rx_batch); i < batch_target; i++) { 820243857Sglebius MGETHDR(m_new, M_NOWAIT, MT_DATA); 821208901Sken if (m_new == NULL) { 822208901Sken printf("%s: MGETHDR failed\n", __func__); 823181643Skmacy goto no_mbuf; 824208901Sken } 825181643Skmacy 826243857Sglebius m_cljget(m_new, M_NOWAIT, MJUMPAGESIZE); 827181643Skmacy if ((m_new->m_flags & M_EXT) == 0) { 828208901Sken printf("%s: m_cljget failed\n", __func__); 829181643Skmacy m_freem(m_new); 830181643Skmacy 831181643Skmacyno_mbuf: 832181643Skmacy if (i != 0) 833181643Skmacy goto refill; 834181643Skmacy /* 835181643Skmacy * XXX set timer 836181643Skmacy */ 837181643Skmacy break; 838181643Skmacy } 839181643Skmacy m_new->m_len = m_new->m_pkthdr.len = MJUMPAGESIZE; 840181643Skmacy 841181643Skmacy /* queue the mbufs allocated */ 842181643Skmacy mbufq_tail(&sc->xn_rx_batch, m_new); 843181643Skmacy } 844181643Skmacy 845208901Sken /* 846208901Sken * If we've allocated at least half of our target number of entries, 847208901Sken * submit them to the backend - we have enough to make the overhead 848208901Sken * of submission worthwhile. Otherwise wait for more mbufs and 849208901Sken * request entries to become available. 850208901Sken */ 851181643Skmacy if (i < (sc->rx_target/2)) { 852181643Skmacy if (req_prod >sc->rx.sring->req_prod) 853181643Skmacy goto push; 854181643Skmacy return; 855181643Skmacy } 856181643Skmacy 857208901Sken /* 858208901Sken * Double floating fill target if we risked having the backend 859208901Sken * run out of empty buffers for receive traffic. We define "running 860208901Sken * low" as having less than a fourth of our target buffers free 861208901Sken * at the time we refilled the queue. 862208901Sken */ 863208901Sken if ((req_prod - sc->rx.sring->rsp_prod) < (sc->rx_target / 4)) { 864208901Sken sc->rx_target *= 2; 865208901Sken if (sc->rx_target > sc->rx_max_target) 866208901Sken sc->rx_target = sc->rx_max_target; 867208901Sken } 868208901Sken 869181643Skmacyrefill: 870181643Skmacy for (nr_flips = i = 0; ; i++) { 871181643Skmacy if ((m_new = mbufq_dequeue(&sc->xn_rx_batch)) == NULL) 872181643Skmacy break; 873181643Skmacy 874181643Skmacy m_new->m_ext.ext_arg1 = (vm_paddr_t *)(uintptr_t)( 875181945Skmacy vtophys(m_new->m_ext.ext_buf) >> PAGE_SHIFT); 876181643Skmacy 877181643Skmacy id = xennet_rxidx(req_prod + i); 878181643Skmacy 879208901Sken KASSERT(sc->rx_mbufs[id] == NULL, ("non-NULL xm_rx_chain")); 880208901Sken sc->rx_mbufs[id] = m_new; 881181643Skmacy 882181643Skmacy ref = gnttab_claim_grant_reference(&sc->gref_rx_head); 883214077Sgibbs KASSERT(ref != GNTTAB_LIST_END, 884214077Sgibbs ("reserved grant references exhuasted")); 885181643Skmacy sc->grant_rx_ref[id] = ref; 886181643Skmacy 887181643Skmacy vaddr = mtod(m_new, vm_offset_t); 888181643Skmacy pfn = vtophys(vaddr) >> PAGE_SHIFT; 889181643Skmacy req = RING_GET_REQUEST(&sc->rx, req_prod + i); 890181643Skmacy 891181643Skmacy if (sc->copying_receiver == 0) { 892181643Skmacy gnttab_grant_foreign_transfer_ref(ref, 893185605Skmacy otherend_id, pfn); 894181643Skmacy sc->rx_pfn_array[nr_flips] = PFNTOMFN(pfn); 895181643Skmacy if (!xen_feature(XENFEAT_auto_translated_physmap)) { 896181643Skmacy /* Remove this page before passing 897181643Skmacy * back to Xen. 898181643Skmacy */ 899181643Skmacy set_phys_to_machine(pfn, INVALID_P2M_ENTRY); 900181643Skmacy MULTI_update_va_mapping(&sc->rx_mcl[i], 901181643Skmacy vaddr, 0, 0); 902181643Skmacy } 903181643Skmacy nr_flips++; 904181643Skmacy } else { 905181643Skmacy gnttab_grant_foreign_access_ref(ref, 906185605Skmacy otherend_id, 907181643Skmacy PFNTOMFN(pfn), 0); 908181643Skmacy } 909181643Skmacy req->id = id; 910181643Skmacy req->gref = ref; 911181643Skmacy 912181643Skmacy sc->rx_pfn_array[i] = 913181643Skmacy vtomach(mtod(m_new,vm_offset_t)) >> PAGE_SHIFT; 914181643Skmacy } 915181643Skmacy 916181643Skmacy KASSERT(i, ("no mbufs processed")); /* should have returned earlier */ 917181643Skmacy KASSERT(mbufq_len(&sc->xn_rx_batch) == 0, ("not all mbufs processed")); 918181643Skmacy /* 919181643Skmacy * We may have allocated buffers which have entries outstanding 920181643Skmacy * in the page * update queue -- make sure we flush those first! 921181643Skmacy */ 922181643Skmacy PT_UPDATES_FLUSH(); 923181643Skmacy if (nr_flips != 0) { 924181643Skmacy#ifdef notyet 925181643Skmacy /* Tell the ballon driver what is going on. */ 926181643Skmacy balloon_update_driver_allowance(i); 927181643Skmacy#endif 928183375Skmacy set_xen_guest_handle(reservation.extent_start, sc->rx_pfn_array); 929181643Skmacy reservation.nr_extents = i; 930181643Skmacy reservation.extent_order = 0; 931181643Skmacy reservation.address_bits = 0; 932181643Skmacy reservation.domid = DOMID_SELF; 933181643Skmacy 934181643Skmacy if (!xen_feature(XENFEAT_auto_translated_physmap)) { 935181643Skmacy /* After all PTEs have been zapped, flush the TLB. */ 936181643Skmacy sc->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] = 937181643Skmacy UVMF_TLB_FLUSH|UVMF_ALL; 938181643Skmacy 939181643Skmacy /* Give away a batch of pages. */ 940181643Skmacy sc->rx_mcl[i].op = __HYPERVISOR_memory_op; 941181643Skmacy sc->rx_mcl[i].args[0] = XENMEM_decrease_reservation; 942181643Skmacy sc->rx_mcl[i].args[1] = (u_long)&reservation; 943181643Skmacy /* Zap PTEs and give away pages in one big multicall. */ 944181643Skmacy (void)HYPERVISOR_multicall(sc->rx_mcl, i+1); 945181643Skmacy 946255040Sgibbs if (__predict_false(sc->rx_mcl[i].result != i || 947244991Smarius HYPERVISOR_memory_op(XENMEM_decrease_reservation, 948244991Smarius &reservation) != i)) 949244991Smarius panic("%s: unable to reduce memory " 950244991Smarius "reservation\n", __func__); 951181643Skmacy } 952181643Skmacy } else { 953181643Skmacy wmb(); 954181643Skmacy } 955181643Skmacy 956181643Skmacy /* Above is a suitable barrier to ensure backend will see requests. */ 957181643Skmacy sc->rx.req_prod_pvt = req_prod + i; 958181643Skmacypush: 959181643Skmacy RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->rx, notify); 960181643Skmacy if (notify) 961255040Sgibbs xen_intr_signal(sc->xen_intr_handle); 962181643Skmacy} 963181643Skmacy 964181643Skmacystatic void 965181643Skmacyxn_rxeof(struct netfront_info *np) 966181643Skmacy{ 967181643Skmacy struct ifnet *ifp; 968259541Sglebius#if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 969189699Sdfr struct lro_ctrl *lro = &np->xn_lro; 970189699Sdfr struct lro_entry *queued; 971189699Sdfr#endif 972181643Skmacy struct netfront_rx_info rinfo; 973181643Skmacy struct netif_rx_response *rx = &rinfo.rx; 974181643Skmacy struct netif_extra_info *extras = rinfo.extras; 975181643Skmacy RING_IDX i, rp; 976181643Skmacy multicall_entry_t *mcl; 977181643Skmacy struct mbuf *m; 978181945Skmacy struct mbuf_head rxq, errq; 979185473Sdfr int err, pages_flipped = 0, work_to_do; 980181643Skmacy 981185473Sdfr do { 982185473Sdfr XN_RX_LOCK_ASSERT(np); 983185473Sdfr if (!netfront_carrier_ok(np)) 984185473Sdfr return; 985181643Skmacy 986185473Sdfr mbufq_init(&errq); 987185473Sdfr mbufq_init(&rxq); 988181643Skmacy 989185473Sdfr ifp = np->xn_ifp; 990181643Skmacy 991185473Sdfr rp = np->rx.sring->rsp_prod; 992185473Sdfr rmb(); /* Ensure we see queued responses up to 'rp'. */ 993181643Skmacy 994185473Sdfr i = np->rx.rsp_cons; 995185473Sdfr while ((i != rp)) { 996185473Sdfr memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx)); 997185473Sdfr memset(extras, 0, sizeof(rinfo.extras)); 998181643Skmacy 999185473Sdfr m = NULL; 1000208901Sken err = xennet_get_responses(np, &rinfo, rp, &i, &m, 1001185473Sdfr &pages_flipped); 1002181643Skmacy 1003255040Sgibbs if (__predict_false(err)) { 1004181945Skmacy if (m) 1005185473Sdfr mbufq_tail(&errq, m); 1006185473Sdfr np->stats.rx_errors++; 1007185473Sdfr continue; 1008185473Sdfr } 1009181643Skmacy 1010185473Sdfr m->m_pkthdr.rcvif = ifp; 1011185473Sdfr if ( rx->flags & NETRXF_data_validated ) { 1012185473Sdfr /* Tell the stack the checksums are okay */ 1013185473Sdfr /* 1014185473Sdfr * XXX this isn't necessarily the case - need to add 1015185473Sdfr * check 1016185473Sdfr */ 1017181643Skmacy 1018185473Sdfr m->m_pkthdr.csum_flags |= 1019185473Sdfr (CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID 1020185473Sdfr | CSUM_PSEUDO_HDR); 1021185473Sdfr m->m_pkthdr.csum_data = 0xffff; 1022185473Sdfr } 1023181643Skmacy 1024185473Sdfr np->stats.rx_packets++; 1025185473Sdfr np->stats.rx_bytes += m->m_pkthdr.len; 1026181643Skmacy 1027185473Sdfr mbufq_tail(&rxq, m); 1028208901Sken np->rx.rsp_cons = i; 1029185473Sdfr } 1030181643Skmacy 1031185473Sdfr if (pages_flipped) { 1032185473Sdfr /* Some pages are no longer absent... */ 1033181643Skmacy#ifdef notyet 1034185473Sdfr balloon_update_driver_allowance(-pages_flipped); 1035181643Skmacy#endif 1036185473Sdfr /* Do all the remapping work, and M->P updates, in one big 1037185473Sdfr * hypercall. 1038185473Sdfr */ 1039185473Sdfr if (!!xen_feature(XENFEAT_auto_translated_physmap)) { 1040185473Sdfr mcl = np->rx_mcl + pages_flipped; 1041185473Sdfr mcl->op = __HYPERVISOR_mmu_update; 1042185473Sdfr mcl->args[0] = (u_long)np->rx_mmu; 1043185473Sdfr mcl->args[1] = pages_flipped; 1044185473Sdfr mcl->args[2] = 0; 1045185473Sdfr mcl->args[3] = DOMID_SELF; 1046185473Sdfr (void)HYPERVISOR_multicall(np->rx_mcl, 1047185473Sdfr pages_flipped + 1); 1048185473Sdfr } 1049181643Skmacy } 1050181643Skmacy 1051185473Sdfr while ((m = mbufq_dequeue(&errq))) 1052185473Sdfr m_freem(m); 1053181643Skmacy 1054185473Sdfr /* 1055185473Sdfr * Process all the mbufs after the remapping is complete. 1056185473Sdfr * Break the mbuf chain first though. 1057185473Sdfr */ 1058185473Sdfr while ((m = mbufq_dequeue(&rxq)) != NULL) { 1059185473Sdfr ifp->if_ipackets++; 1060181643Skmacy 1061185473Sdfr /* 1062185473Sdfr * Do we really need to drop the rx lock? 1063185473Sdfr */ 1064185473Sdfr XN_RX_UNLOCK(np); 1065259541Sglebius#if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 1066189699Sdfr /* Use LRO if possible */ 1067189699Sdfr if ((ifp->if_capenable & IFCAP_LRO) == 0 || 1068189699Sdfr lro->lro_cnt == 0 || tcp_lro_rx(lro, m, 0)) { 1069189699Sdfr /* 1070189699Sdfr * If LRO fails, pass up to the stack 1071189699Sdfr * directly. 1072189699Sdfr */ 1073189699Sdfr (*ifp->if_input)(ifp, m); 1074189699Sdfr } 1075189699Sdfr#else 1076185473Sdfr (*ifp->if_input)(ifp, m); 1077189699Sdfr#endif 1078185473Sdfr XN_RX_LOCK(np); 1079185473Sdfr } 1080181643Skmacy 1081185473Sdfr np->rx.rsp_cons = i; 1082181643Skmacy 1083259541Sglebius#if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 1084189699Sdfr /* 1085189699Sdfr * Flush any outstanding LRO work 1086189699Sdfr */ 1087189699Sdfr while (!SLIST_EMPTY(&lro->lro_active)) { 1088189699Sdfr queued = SLIST_FIRST(&lro->lro_active); 1089189699Sdfr SLIST_REMOVE_HEAD(&lro->lro_active, next); 1090189699Sdfr tcp_lro_flush(lro, queued); 1091189699Sdfr } 1092189699Sdfr#endif 1093189699Sdfr 1094181643Skmacy#if 0 1095185473Sdfr /* If we get a callback with very few responses, reduce fill target. */ 1096185473Sdfr /* NB. Note exponential increase, linear decrease. */ 1097185473Sdfr if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > 1098185473Sdfr ((3*np->rx_target) / 4)) && (--np->rx_target < np->rx_min_target)) 1099185473Sdfr np->rx_target = np->rx_min_target; 1100181643Skmacy#endif 1101181643Skmacy 1102185473Sdfr network_alloc_rx_buffers(np); 1103181643Skmacy 1104185473Sdfr RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, work_to_do); 1105185473Sdfr } while (work_to_do); 1106181643Skmacy} 1107181643Skmacy 1108181643Skmacystatic void 1109181643Skmacyxn_txeof(struct netfront_info *np) 1110181643Skmacy{ 1111181643Skmacy RING_IDX i, prod; 1112181643Skmacy unsigned short id; 1113181643Skmacy struct ifnet *ifp; 1114189699Sdfr netif_tx_response_t *txr; 1115181643Skmacy struct mbuf *m; 1116181643Skmacy 1117181643Skmacy XN_TX_LOCK_ASSERT(np); 1118181643Skmacy 1119181643Skmacy if (!netfront_carrier_ok(np)) 1120181643Skmacy return; 1121181643Skmacy 1122181643Skmacy ifp = np->xn_ifp; 1123181643Skmacy 1124181643Skmacy do { 1125181643Skmacy prod = np->tx.sring->rsp_prod; 1126181643Skmacy rmb(); /* Ensure we see responses up to 'rp'. */ 1127181643Skmacy 1128181643Skmacy for (i = np->tx.rsp_cons; i != prod; i++) { 1129189699Sdfr txr = RING_GET_RESPONSE(&np->tx, i); 1130189699Sdfr if (txr->status == NETIF_RSP_NULL) 1131189699Sdfr continue; 1132189699Sdfr 1133208901Sken if (txr->status != NETIF_RSP_OKAY) { 1134208901Sken printf("%s: WARNING: response is %d!\n", 1135208901Sken __func__, txr->status); 1136208901Sken } 1137189699Sdfr id = txr->id; 1138208901Sken m = np->tx_mbufs[id]; 1139192870Sadrian KASSERT(m != NULL, ("mbuf not found in xn_tx_chain")); 1140208901Sken KASSERT((uintptr_t)m > NET_TX_RING_SIZE, 1141208901Sken ("mbuf already on the free list, but we're " 1142208901Sken "trying to free it again!")); 1143192870Sadrian M_ASSERTVALID(m); 1144181643Skmacy 1145189699Sdfr /* 1146189699Sdfr * Increment packet count if this is the last 1147189699Sdfr * mbuf of the chain. 1148189699Sdfr */ 1149189699Sdfr if (!m->m_next) 1150189699Sdfr ifp->if_opackets++; 1151255040Sgibbs if (__predict_false(gnttab_query_foreign_access( 1152181643Skmacy np->grant_tx_ref[id]) != 0)) { 1153244991Smarius panic("%s: grant id %u still in use by the " 1154244991Smarius "backend", __func__, id); 1155181643Skmacy } 1156181643Skmacy gnttab_end_foreign_access_ref( 1157183375Skmacy np->grant_tx_ref[id]); 1158181643Skmacy gnttab_release_grant_reference( 1159181643Skmacy &np->gref_tx_head, np->grant_tx_ref[id]); 1160214077Sgibbs np->grant_tx_ref[id] = GRANT_REF_INVALID; 1161181643Skmacy 1162208901Sken np->tx_mbufs[id] = NULL; 1163208901Sken add_id_to_freelist(np->tx_mbufs, id); 1164192871Sadrian np->xn_cdata.xn_tx_chain_cnt--; 1165189699Sdfr m_free(m); 1166192894Sadrian /* Only mark the queue active if we've freed up at least one slot to try */ 1167192894Sadrian ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1168181643Skmacy } 1169181643Skmacy np->tx.rsp_cons = prod; 1170181643Skmacy 1171181643Skmacy /* 1172181643Skmacy * Set a new event, then check for race with update of 1173181643Skmacy * tx_cons. Note that it is essential to schedule a 1174181643Skmacy * callback, no matter how few buffers are pending. Even if 1175181643Skmacy * there is space in the transmit ring, higher layers may 1176181643Skmacy * be blocked because too much data is outstanding: in such 1177181643Skmacy * cases notification from Xen is likely to be the only kick 1178181643Skmacy * that we'll get. 1179181643Skmacy */ 1180181643Skmacy np->tx.sring->rsp_event = 1181181643Skmacy prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; 1182181643Skmacy 1183181643Skmacy mb(); 1184181643Skmacy } while (prod != np->tx.sring->rsp_prod); 1185181643Skmacy 1186181643Skmacy if (np->tx_full && 1187181643Skmacy ((np->tx.sring->req_prod - prod) < NET_TX_RING_SIZE)) { 1188181643Skmacy np->tx_full = 0; 1189181643Skmacy#if 0 1190181643Skmacy if (np->user_state == UST_OPEN) 1191181643Skmacy netif_wake_queue(dev); 1192181643Skmacy#endif 1193181643Skmacy } 1194181643Skmacy} 1195181643Skmacy 1196181643Skmacystatic void 1197181643Skmacyxn_intr(void *xsc) 1198181643Skmacy{ 1199181643Skmacy struct netfront_info *np = xsc; 1200181643Skmacy struct ifnet *ifp = np->xn_ifp; 1201181643Skmacy 1202181643Skmacy#if 0 1203181643Skmacy if (!(np->rx.rsp_cons != np->rx.sring->rsp_prod && 1204181643Skmacy likely(netfront_carrier_ok(np)) && 1205181643Skmacy ifp->if_drv_flags & IFF_DRV_RUNNING)) 1206181643Skmacy return; 1207181643Skmacy#endif 1208208901Sken if (RING_HAS_UNCONSUMED_RESPONSES(&np->tx)) { 1209181643Skmacy XN_TX_LOCK(np); 1210181643Skmacy xn_txeof(np); 1211181643Skmacy XN_TX_UNLOCK(np); 1212181643Skmacy } 1213181643Skmacy 1214181643Skmacy XN_RX_LOCK(np); 1215181643Skmacy xn_rxeof(np); 1216181643Skmacy XN_RX_UNLOCK(np); 1217181643Skmacy 1218181643Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1219181643Skmacy !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1220181643Skmacy xn_start(ifp); 1221181643Skmacy} 1222181643Skmacy 1223181643Skmacystatic void 1224181643Skmacyxennet_move_rx_slot(struct netfront_info *np, struct mbuf *m, 1225181643Skmacy grant_ref_t ref) 1226181643Skmacy{ 1227181643Skmacy int new = xennet_rxidx(np->rx.req_prod_pvt); 1228181643Skmacy 1229181643Skmacy KASSERT(np->rx_mbufs[new] == NULL, ("rx_mbufs != NULL")); 1230181643Skmacy np->rx_mbufs[new] = m; 1231181643Skmacy np->grant_rx_ref[new] = ref; 1232181643Skmacy RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new; 1233181643Skmacy RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref; 1234181643Skmacy np->rx.req_prod_pvt++; 1235181643Skmacy} 1236181643Skmacy 1237181643Skmacystatic int 1238181643Skmacyxennet_get_extras(struct netfront_info *np, 1239208901Sken struct netif_extra_info *extras, RING_IDX rp, RING_IDX *cons) 1240181643Skmacy{ 1241181643Skmacy struct netif_extra_info *extra; 1242181643Skmacy 1243181643Skmacy int err = 0; 1244181643Skmacy 1245181643Skmacy do { 1246181643Skmacy struct mbuf *m; 1247181643Skmacy grant_ref_t ref; 1248181643Skmacy 1249255040Sgibbs if (__predict_false(*cons + 1 == rp)) { 1250181643Skmacy#if 0 1251181643Skmacy if (net_ratelimit()) 1252181643Skmacy WPRINTK("Missing extra info\n"); 1253181643Skmacy#endif 1254208901Sken err = EINVAL; 1255181643Skmacy break; 1256181643Skmacy } 1257181643Skmacy 1258181643Skmacy extra = (struct netif_extra_info *) 1259208901Sken RING_GET_RESPONSE(&np->rx, ++(*cons)); 1260181643Skmacy 1261255040Sgibbs if (__predict_false(!extra->type || 1262181643Skmacy extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { 1263181643Skmacy#if 0 1264181643Skmacy if (net_ratelimit()) 1265181643Skmacy WPRINTK("Invalid extra type: %d\n", 1266181643Skmacy extra->type); 1267181643Skmacy#endif 1268208901Sken err = EINVAL; 1269181643Skmacy } else { 1270181643Skmacy memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); 1271181643Skmacy } 1272181643Skmacy 1273208901Sken m = xennet_get_rx_mbuf(np, *cons); 1274208901Sken ref = xennet_get_rx_ref(np, *cons); 1275181643Skmacy xennet_move_rx_slot(np, m, ref); 1276181643Skmacy } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); 1277181643Skmacy 1278181643Skmacy return err; 1279181643Skmacy} 1280181643Skmacy 1281181643Skmacystatic int 1282181643Skmacyxennet_get_responses(struct netfront_info *np, 1283208901Sken struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, 1284181945Skmacy struct mbuf **list, 1285181643Skmacy int *pages_flipped_p) 1286181643Skmacy{ 1287181643Skmacy int pages_flipped = *pages_flipped_p; 1288181643Skmacy struct mmu_update *mmu; 1289181643Skmacy struct multicall_entry *mcl; 1290181643Skmacy struct netif_rx_response *rx = &rinfo->rx; 1291181643Skmacy struct netif_extra_info *extras = rinfo->extras; 1292181945Skmacy struct mbuf *m, *m0, *m_prev; 1293208901Sken grant_ref_t ref = xennet_get_rx_ref(np, *cons); 1294208901Sken RING_IDX ref_cons = *cons; 1295181643Skmacy int frags = 1; 1296181643Skmacy int err = 0; 1297181643Skmacy u_long ret; 1298181643Skmacy 1299208901Sken m0 = m = m_prev = xennet_get_rx_mbuf(np, *cons); 1300181945Skmacy 1301181643Skmacy if (rx->flags & NETRXF_extra_info) { 1302208901Sken err = xennet_get_extras(np, extras, rp, cons); 1303181643Skmacy } 1304181643Skmacy 1305181945Skmacy if (m0 != NULL) { 1306208901Sken m0->m_pkthdr.len = 0; 1307208901Sken m0->m_next = NULL; 1308181945Skmacy } 1309244991Smarius 1310181643Skmacy for (;;) { 1311181643Skmacy u_long mfn; 1312181643Skmacy 1313181945Skmacy#if 0 1314204158Skmacy DPRINTK("rx->status=%hd rx->offset=%hu frags=%u\n", 1315181945Skmacy rx->status, rx->offset, frags); 1316181945Skmacy#endif 1317255040Sgibbs if (__predict_false(rx->status < 0 || 1318181643Skmacy rx->offset + rx->status > PAGE_SIZE)) { 1319208901Sken 1320181643Skmacy#if 0 1321181643Skmacy if (net_ratelimit()) 1322181643Skmacy WPRINTK("rx->offset: %x, size: %u\n", 1323181643Skmacy rx->offset, rx->status); 1324181643Skmacy#endif 1325181643Skmacy xennet_move_rx_slot(np, m, ref); 1326208901Sken if (m0 == m) 1327208901Sken m0 = NULL; 1328208901Sken m = NULL; 1329208901Sken err = EINVAL; 1330208901Sken goto next_skip_queue; 1331181643Skmacy } 1332181945Skmacy 1333181643Skmacy /* 1334181643Skmacy * This definitely indicates a bug, either in this driver or in 1335181643Skmacy * the backend driver. In future this should flag the bad 1336181643Skmacy * situation to the system controller to reboot the backed. 1337181643Skmacy */ 1338214077Sgibbs if (ref == GRANT_REF_INVALID) { 1339208901Sken 1340181643Skmacy#if 0 1341181643Skmacy if (net_ratelimit()) 1342181643Skmacy WPRINTK("Bad rx response id %d.\n", rx->id); 1343181643Skmacy#endif 1344214077Sgibbs printf("%s: Bad rx response id %d.\n", __func__,rx->id); 1345208901Sken err = EINVAL; 1346181643Skmacy goto next; 1347181643Skmacy } 1348181643Skmacy 1349181643Skmacy if (!np->copying_receiver) { 1350181643Skmacy /* Memory pressure, insufficient buffer 1351181643Skmacy * headroom, ... 1352181643Skmacy */ 1353181643Skmacy if (!(mfn = gnttab_end_foreign_transfer_ref(ref))) { 1354208901Sken WPRINTK("Unfulfilled rx req (id=%d, st=%d).\n", 1355208901Sken rx->id, rx->status); 1356181643Skmacy xennet_move_rx_slot(np, m, ref); 1357208901Sken err = ENOMEM; 1358181643Skmacy goto next; 1359181643Skmacy } 1360181643Skmacy 1361181643Skmacy if (!xen_feature( XENFEAT_auto_translated_physmap)) { 1362181643Skmacy /* Remap the page. */ 1363181643Skmacy void *vaddr = mtod(m, void *); 1364181643Skmacy uint32_t pfn; 1365181643Skmacy 1366181643Skmacy mcl = np->rx_mcl + pages_flipped; 1367181643Skmacy mmu = np->rx_mmu + pages_flipped; 1368181643Skmacy 1369181643Skmacy MULTI_update_va_mapping(mcl, (u_long)vaddr, 1370181916Skmacy (((vm_paddr_t)mfn) << PAGE_SHIFT) | PG_RW | 1371181643Skmacy PG_V | PG_M | PG_A, 0); 1372186557Skmacy pfn = (uintptr_t)m->m_ext.ext_arg1; 1373181643Skmacy mmu->ptr = ((vm_paddr_t)mfn << PAGE_SHIFT) | 1374181643Skmacy MMU_MACHPHYS_UPDATE; 1375181643Skmacy mmu->val = pfn; 1376181643Skmacy 1377181643Skmacy set_phys_to_machine(pfn, mfn); 1378181643Skmacy } 1379181643Skmacy pages_flipped++; 1380181643Skmacy } else { 1381183375Skmacy ret = gnttab_end_foreign_access_ref(ref); 1382181643Skmacy KASSERT(ret, ("ret != 0")); 1383181643Skmacy } 1384181643Skmacy 1385181643Skmacy gnttab_release_grant_reference(&np->gref_rx_head, ref); 1386181643Skmacy 1387181643Skmacynext: 1388192286Sadrian if (m == NULL) 1389192286Sadrian break; 1390192286Sadrian 1391192286Sadrian m->m_len = rx->status; 1392192286Sadrian m->m_data += rx->offset; 1393192286Sadrian m0->m_pkthdr.len += rx->status; 1394181945Skmacy 1395208901Skennext_skip_queue: 1396181643Skmacy if (!(rx->flags & NETRXF_more_data)) 1397181643Skmacy break; 1398181643Skmacy 1399208901Sken if (*cons + frags == rp) { 1400181643Skmacy if (net_ratelimit()) 1401181643Skmacy WPRINTK("Need more frags\n"); 1402208901Sken err = ENOENT; 1403208901Sken printf("%s: cons %u frags %u rp %u, not enough frags\n", 1404208901Sken __func__, *cons, frags, rp); 1405214077Sgibbs break; 1406181643Skmacy } 1407208901Sken /* 1408208901Sken * Note that m can be NULL, if rx->status < 0 or if 1409208901Sken * rx->offset + rx->status > PAGE_SIZE above. 1410208901Sken */ 1411181945Skmacy m_prev = m; 1412181945Skmacy 1413208901Sken rx = RING_GET_RESPONSE(&np->rx, *cons + frags); 1414208901Sken m = xennet_get_rx_mbuf(np, *cons + frags); 1415181945Skmacy 1416208901Sken /* 1417208901Sken * m_prev == NULL can happen if rx->status < 0 or if 1418208901Sken * rx->offset + * rx->status > PAGE_SIZE above. 1419208901Sken */ 1420208901Sken if (m_prev != NULL) 1421208901Sken m_prev->m_next = m; 1422208901Sken 1423208901Sken /* 1424208901Sken * m0 can be NULL if rx->status < 0 or if * rx->offset + 1425208901Sken * rx->status > PAGE_SIZE above. 1426208901Sken */ 1427208901Sken if (m0 == NULL) 1428208901Sken m0 = m; 1429181945Skmacy m->m_next = NULL; 1430208901Sken ref = xennet_get_rx_ref(np, *cons + frags); 1431208901Sken ref_cons = *cons + frags; 1432181643Skmacy frags++; 1433181643Skmacy } 1434181945Skmacy *list = m0; 1435208901Sken *cons += frags; 1436181643Skmacy *pages_flipped_p = pages_flipped; 1437181643Skmacy 1438218056Sgibbs return (err); 1439181643Skmacy} 1440181643Skmacy 1441181643Skmacystatic void 1442181643Skmacyxn_tick_locked(struct netfront_info *sc) 1443181643Skmacy{ 1444181643Skmacy XN_RX_LOCK_ASSERT(sc); 1445181643Skmacy callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); 1446181643Skmacy 1447181643Skmacy /* XXX placeholder for printing debug information */ 1448181643Skmacy} 1449181643Skmacy 1450181643Skmacystatic void 1451181643Skmacyxn_tick(void *xsc) 1452181643Skmacy{ 1453181643Skmacy struct netfront_info *sc; 1454181643Skmacy 1455181643Skmacy sc = xsc; 1456181643Skmacy XN_RX_LOCK(sc); 1457181643Skmacy xn_tick_locked(sc); 1458181643Skmacy XN_RX_UNLOCK(sc); 1459181643Skmacy} 1460208901Sken 1461208901Sken/** 1462208901Sken * \brief Count the number of fragments in an mbuf chain. 1463208901Sken * 1464208901Sken * Surprisingly, there isn't an M* macro for this. 1465208901Sken */ 1466208901Skenstatic inline int 1467208901Skenxn_count_frags(struct mbuf *m) 1468181643Skmacy{ 1469208901Sken int nfrags; 1470208901Sken 1471208901Sken for (nfrags = 0; m != NULL; m = m->m_next) 1472208901Sken nfrags++; 1473208901Sken 1474208901Sken return (nfrags); 1475208901Sken} 1476208901Sken 1477208901Sken/** 1478208901Sken * Given an mbuf chain, make sure we have enough room and then push 1479208901Sken * it onto the transmit ring. 1480208901Sken */ 1481208901Skenstatic int 1482208901Skenxn_assemble_tx_request(struct netfront_info *sc, struct mbuf *m_head) 1483208901Sken{ 1484208901Sken struct ifnet *ifp; 1485208901Sken struct mbuf *m; 1486208901Sken u_int nfrags; 1487208901Sken netif_extra_info_t *extra; 1488185605Skmacy int otherend_id; 1489181643Skmacy 1490208901Sken ifp = sc->xn_ifp; 1491181643Skmacy 1492208901Sken /** 1493208901Sken * Defragment the mbuf if necessary. 1494208901Sken */ 1495208901Sken nfrags = xn_count_frags(m_head); 1496181643Skmacy 1497208901Sken /* 1498208901Sken * Check to see whether this request is longer than netback 1499208901Sken * can handle, and try to defrag it. 1500208901Sken */ 1501208901Sken /** 1502208901Sken * It is a bit lame, but the netback driver in Linux can't 1503208901Sken * deal with nfrags > MAX_TX_REQ_FRAGS, which is a quirk of 1504208901Sken * the Linux network stack. 1505208901Sken */ 1506225709Sgibbs if (nfrags > sc->maxfrags) { 1507243857Sglebius m = m_defrag(m_head, M_NOWAIT); 1508208901Sken if (!m) { 1509208901Sken /* 1510208901Sken * Defrag failed, so free the mbuf and 1511208901Sken * therefore drop the packet. 1512208901Sken */ 1513208901Sken m_freem(m_head); 1514208901Sken return (EMSGSIZE); 1515189699Sdfr } 1516208901Sken m_head = m; 1517208901Sken } 1518189699Sdfr 1519208901Sken /* Determine how many fragments now exist */ 1520208901Sken nfrags = xn_count_frags(m_head); 1521192871Sadrian 1522208901Sken /* 1523208901Sken * Check to see whether the defragmented packet has too many 1524208901Sken * segments for the Linux netback driver. 1525208901Sken */ 1526208901Sken /** 1527208901Sken * The FreeBSD TCP stack, with TSO enabled, can produce a chain 1528208901Sken * of mbufs longer than Linux can handle. Make sure we don't 1529208901Sken * pass a too-long chain over to the other side by dropping the 1530208901Sken * packet. It doesn't look like there is currently a way to 1531208901Sken * tell the TCP stack to generate a shorter chain of packets. 1532208901Sken */ 1533208901Sken if (nfrags > MAX_TX_REQ_FRAGS) { 1534214077Sgibbs#ifdef DEBUG 1535214077Sgibbs printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback " 1536214077Sgibbs "won't be able to handle it, dropping\n", 1537214077Sgibbs __func__, nfrags, MAX_TX_REQ_FRAGS); 1538214077Sgibbs#endif 1539208901Sken m_freem(m_head); 1540208901Sken return (EMSGSIZE); 1541208901Sken } 1542192871Sadrian 1543208901Sken /* 1544208901Sken * This check should be redundant. We've already verified that we 1545208901Sken * have enough slots in the ring to handle a packet of maximum 1546208901Sken * size, and that our packet is less than the maximum size. Keep 1547208901Sken * it in here as an assert for now just to make certain that 1548208901Sken * xn_tx_chain_cnt is accurate. 1549208901Sken */ 1550208901Sken KASSERT((sc->xn_cdata.xn_tx_chain_cnt + nfrags) <= NET_TX_RING_SIZE, 1551208901Sken ("%s: xn_tx_chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE " 1552208901Sken "(%d)!", __func__, (int) sc->xn_cdata.xn_tx_chain_cnt, 1553208901Sken (int) nfrags, (int) NET_TX_RING_SIZE)); 1554192871Sadrian 1555208901Sken /* 1556208901Sken * Start packing the mbufs in this chain into 1557208901Sken * the fragment pointers. Stop when we run out 1558208901Sken * of fragments or hit the end of the mbuf chain. 1559208901Sken */ 1560208901Sken m = m_head; 1561208901Sken extra = NULL; 1562208901Sken otherend_id = xenbus_get_otherend_id(sc->xbdev); 1563208901Sken for (m = m_head; m; m = m->m_next) { 1564208901Sken netif_tx_request_t *tx; 1565208901Sken uintptr_t id; 1566208901Sken grant_ref_t ref; 1567208901Sken u_long mfn; /* XXX Wrong type? */ 1568192871Sadrian 1569208901Sken tx = RING_GET_REQUEST(&sc->tx, sc->tx.req_prod_pvt); 1570208901Sken id = get_id_from_freelist(sc->tx_mbufs); 1571208901Sken if (id == 0) 1572244991Smarius panic("%s: was allocated the freelist head!\n", 1573244991Smarius __func__); 1574208901Sken sc->xn_cdata.xn_tx_chain_cnt++; 1575208901Sken if (sc->xn_cdata.xn_tx_chain_cnt > NET_TX_RING_SIZE) 1576244991Smarius panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n", 1577244991Smarius __func__); 1578208901Sken sc->tx_mbufs[id] = m; 1579208901Sken tx->id = id; 1580208901Sken ref = gnttab_claim_grant_reference(&sc->gref_tx_head); 1581208901Sken KASSERT((short)ref >= 0, ("Negative ref")); 1582208901Sken mfn = virt_to_mfn(mtod(m, vm_offset_t)); 1583208901Sken gnttab_grant_foreign_access_ref(ref, otherend_id, 1584208901Sken mfn, GNTMAP_readonly); 1585208901Sken tx->gref = sc->grant_tx_ref[id] = ref; 1586208901Sken tx->offset = mtod(m, vm_offset_t) & (PAGE_SIZE - 1); 1587208901Sken tx->flags = 0; 1588208901Sken if (m == m_head) { 1589208901Sken /* 1590208901Sken * The first fragment has the entire packet 1591208901Sken * size, subsequent fragments have just the 1592208901Sken * fragment size. The backend works out the 1593208901Sken * true size of the first fragment by 1594208901Sken * subtracting the sizes of the other 1595208901Sken * fragments. 1596208901Sken */ 1597208901Sken tx->size = m->m_pkthdr.len; 1598189699Sdfr 1599208901Sken /* 1600208901Sken * The first fragment contains the checksum flags 1601208901Sken * and is optionally followed by extra data for 1602208901Sken * TSO etc. 1603208901Sken */ 1604208901Sken /** 1605208901Sken * CSUM_TSO requires checksum offloading. 1606208901Sken * Some versions of FreeBSD fail to 1607208901Sken * set CSUM_TCP in the CSUM_TSO case, 1608208901Sken * so we have to test for CSUM_TSO 1609208901Sken * explicitly. 1610208901Sken */ 1611208901Sken if (m->m_pkthdr.csum_flags 1612208901Sken & (CSUM_DELAY_DATA | CSUM_TSO)) { 1613208901Sken tx->flags |= (NETTXF_csum_blank 1614208901Sken | NETTXF_data_validated); 1615208901Sken } 1616189699Sdfr#if __FreeBSD_version >= 700000 1617208901Sken if (m->m_pkthdr.csum_flags & CSUM_TSO) { 1618208901Sken struct netif_extra_info *gso = 1619208901Sken (struct netif_extra_info *) 1620208901Sken RING_GET_REQUEST(&sc->tx, 1621208901Sken ++sc->tx.req_prod_pvt); 1622189699Sdfr 1623208901Sken tx->flags |= NETTXF_extra_info; 1624189699Sdfr 1625208901Sken gso->u.gso.size = m->m_pkthdr.tso_segsz; 1626208901Sken gso->u.gso.type = 1627208901Sken XEN_NETIF_GSO_TYPE_TCPV4; 1628208901Sken gso->u.gso.pad = 0; 1629208901Sken gso->u.gso.features = 0; 1630189699Sdfr 1631208901Sken gso->type = XEN_NETIF_EXTRA_TYPE_GSO; 1632208901Sken gso->flags = 0; 1633208901Sken } 1634181643Skmacy#endif 1635208901Sken } else { 1636208901Sken tx->size = m->m_len; 1637189699Sdfr } 1638208901Sken if (m->m_next) 1639208901Sken tx->flags |= NETTXF_more_data; 1640181643Skmacy 1641208901Sken sc->tx.req_prod_pvt++; 1642208901Sken } 1643208901Sken BPF_MTAP(ifp, m_head); 1644181643Skmacy 1645208901Sken sc->stats.tx_bytes += m_head->m_pkthdr.len; 1646208901Sken sc->stats.tx_packets++; 1647208901Sken 1648208901Sken return (0); 1649208901Sken} 1650208901Sken 1651208901Skenstatic void 1652208901Skenxn_start_locked(struct ifnet *ifp) 1653208901Sken{ 1654208901Sken struct netfront_info *sc; 1655208901Sken struct mbuf *m_head; 1656208901Sken int notify; 1657208901Sken 1658208901Sken sc = ifp->if_softc; 1659208901Sken 1660208901Sken if (!netfront_carrier_ok(sc)) 1661208901Sken return; 1662208901Sken 1663208901Sken /* 1664208901Sken * While we have enough transmit slots available for at least one 1665208901Sken * maximum-sized packet, pull mbufs off the queue and put them on 1666208901Sken * the transmit ring. 1667208901Sken */ 1668208901Sken while (xn_tx_slot_available(sc)) { 1669208901Sken IF_DEQUEUE(&ifp->if_snd, m_head); 1670208901Sken if (m_head == NULL) 1671208901Sken break; 1672208901Sken 1673208901Sken if (xn_assemble_tx_request(sc, m_head) != 0) 1674208901Sken break; 1675181643Skmacy } 1676181643Skmacy 1677181643Skmacy RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->tx, notify); 1678181643Skmacy if (notify) 1679255040Sgibbs xen_intr_signal(sc->xen_intr_handle); 1680181643Skmacy 1681181643Skmacy if (RING_FULL(&sc->tx)) { 1682181643Skmacy sc->tx_full = 1; 1683181643Skmacy#if 0 1684181643Skmacy netif_stop_queue(dev); 1685181643Skmacy#endif 1686181643Skmacy } 1687208901Sken} 1688181643Skmacy 1689181643Skmacystatic void 1690181643Skmacyxn_start(struct ifnet *ifp) 1691181643Skmacy{ 1692181643Skmacy struct netfront_info *sc; 1693181643Skmacy sc = ifp->if_softc; 1694181643Skmacy XN_TX_LOCK(sc); 1695181643Skmacy xn_start_locked(ifp); 1696181643Skmacy XN_TX_UNLOCK(sc); 1697181643Skmacy} 1698181643Skmacy 1699181643Skmacy/* equivalent of network_open() in Linux */ 1700181643Skmacystatic void 1701181643Skmacyxn_ifinit_locked(struct netfront_info *sc) 1702181643Skmacy{ 1703181643Skmacy struct ifnet *ifp; 1704181643Skmacy 1705181643Skmacy XN_LOCK_ASSERT(sc); 1706181643Skmacy 1707181643Skmacy ifp = sc->xn_ifp; 1708181643Skmacy 1709181643Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1710181643Skmacy return; 1711181643Skmacy 1712181643Skmacy xn_stop(sc); 1713181643Skmacy 1714181643Skmacy network_alloc_rx_buffers(sc); 1715181643Skmacy sc->rx.sring->rsp_event = sc->rx.rsp_cons + 1; 1716181643Skmacy 1717181643Skmacy ifp->if_drv_flags |= IFF_DRV_RUNNING; 1718181643Skmacy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1719199997Sgibbs if_link_state_change(ifp, LINK_STATE_UP); 1720181643Skmacy 1721181643Skmacy callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); 1722181643Skmacy} 1723181643Skmacy 1724181643Skmacystatic void 1725181643Skmacyxn_ifinit(void *xsc) 1726181643Skmacy{ 1727181643Skmacy struct netfront_info *sc = xsc; 1728181643Skmacy 1729181643Skmacy XN_LOCK(sc); 1730181643Skmacy xn_ifinit_locked(sc); 1731181643Skmacy XN_UNLOCK(sc); 1732181643Skmacy} 1733181643Skmacy 1734181643Skmacystatic int 1735181643Skmacyxn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1736181643Skmacy{ 1737181643Skmacy struct netfront_info *sc = ifp->if_softc; 1738181643Skmacy struct ifreq *ifr = (struct ifreq *) data; 1739221130Sbz#ifdef INET 1740181643Skmacy struct ifaddr *ifa = (struct ifaddr *)data; 1741221130Sbz#endif 1742181643Skmacy 1743181643Skmacy int mask, error = 0; 1744181643Skmacy switch(cmd) { 1745181643Skmacy case SIOCSIFADDR: 1746181643Skmacy case SIOCGIFADDR: 1747221130Sbz#ifdef INET 1748181643Skmacy XN_LOCK(sc); 1749181643Skmacy if (ifa->ifa_addr->sa_family == AF_INET) { 1750181643Skmacy ifp->if_flags |= IFF_UP; 1751181643Skmacy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1752181643Skmacy xn_ifinit_locked(sc); 1753181643Skmacy arp_ifinit(ifp, ifa); 1754189699Sdfr XN_UNLOCK(sc); 1755185473Sdfr } else { 1756189699Sdfr XN_UNLOCK(sc); 1757221130Sbz#endif 1758181643Skmacy error = ether_ioctl(ifp, cmd, data); 1759221130Sbz#ifdef INET 1760185473Sdfr } 1761221130Sbz#endif 1762181643Skmacy break; 1763181643Skmacy case SIOCSIFMTU: 1764181643Skmacy /* XXX can we alter the MTU on a VN ?*/ 1765181643Skmacy#ifdef notyet 1766181643Skmacy if (ifr->ifr_mtu > XN_JUMBO_MTU) 1767181643Skmacy error = EINVAL; 1768181643Skmacy else 1769181643Skmacy#endif 1770181643Skmacy { 1771181643Skmacy ifp->if_mtu = ifr->ifr_mtu; 1772181643Skmacy ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1773181643Skmacy xn_ifinit(sc); 1774181643Skmacy } 1775181643Skmacy break; 1776181643Skmacy case SIOCSIFFLAGS: 1777181643Skmacy XN_LOCK(sc); 1778181643Skmacy if (ifp->if_flags & IFF_UP) { 1779181643Skmacy /* 1780181643Skmacy * If only the state of the PROMISC flag changed, 1781181643Skmacy * then just use the 'set promisc mode' command 1782181643Skmacy * instead of reinitializing the entire NIC. Doing 1783181643Skmacy * a full re-init means reloading the firmware and 1784181643Skmacy * waiting for it to start up, which may take a 1785181643Skmacy * second or two. 1786181643Skmacy */ 1787181643Skmacy#ifdef notyet 1788181643Skmacy /* No promiscuous mode with Xen */ 1789181643Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1790181643Skmacy ifp->if_flags & IFF_PROMISC && 1791181643Skmacy !(sc->xn_if_flags & IFF_PROMISC)) { 1792181643Skmacy XN_SETBIT(sc, XN_RX_MODE, 1793181643Skmacy XN_RXMODE_RX_PROMISC); 1794181643Skmacy } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1795181643Skmacy !(ifp->if_flags & IFF_PROMISC) && 1796181643Skmacy sc->xn_if_flags & IFF_PROMISC) { 1797181643Skmacy XN_CLRBIT(sc, XN_RX_MODE, 1798181643Skmacy XN_RXMODE_RX_PROMISC); 1799181643Skmacy } else 1800181643Skmacy#endif 1801181643Skmacy xn_ifinit_locked(sc); 1802181643Skmacy } else { 1803181643Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1804181643Skmacy xn_stop(sc); 1805181643Skmacy } 1806181643Skmacy } 1807181643Skmacy sc->xn_if_flags = ifp->if_flags; 1808181643Skmacy XN_UNLOCK(sc); 1809181643Skmacy error = 0; 1810181643Skmacy break; 1811181643Skmacy case SIOCSIFCAP: 1812181643Skmacy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1813189699Sdfr if (mask & IFCAP_TXCSUM) { 1814189699Sdfr if (IFCAP_TXCSUM & ifp->if_capenable) { 1815189699Sdfr ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 1816189699Sdfr ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 1817189699Sdfr | CSUM_IP | CSUM_TSO); 1818189699Sdfr } else { 1819189699Sdfr ifp->if_capenable |= IFCAP_TXCSUM; 1820189699Sdfr ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP 1821189699Sdfr | CSUM_IP); 1822189699Sdfr } 1823181643Skmacy } 1824189699Sdfr if (mask & IFCAP_RXCSUM) { 1825189699Sdfr ifp->if_capenable ^= IFCAP_RXCSUM; 1826189699Sdfr } 1827189699Sdfr#if __FreeBSD_version >= 700000 1828189699Sdfr if (mask & IFCAP_TSO4) { 1829189699Sdfr if (IFCAP_TSO4 & ifp->if_capenable) { 1830189699Sdfr ifp->if_capenable &= ~IFCAP_TSO4; 1831189699Sdfr ifp->if_hwassist &= ~CSUM_TSO; 1832189699Sdfr } else if (IFCAP_TXCSUM & ifp->if_capenable) { 1833189699Sdfr ifp->if_capenable |= IFCAP_TSO4; 1834189699Sdfr ifp->if_hwassist |= CSUM_TSO; 1835189699Sdfr } else { 1836192927Sadrian IPRINTK("Xen requires tx checksum offload" 1837189699Sdfr " be enabled to use TSO\n"); 1838189699Sdfr error = EINVAL; 1839189699Sdfr } 1840189699Sdfr } 1841189699Sdfr if (mask & IFCAP_LRO) { 1842189699Sdfr ifp->if_capenable ^= IFCAP_LRO; 1843189699Sdfr 1844189699Sdfr } 1845189699Sdfr#endif 1846181643Skmacy error = 0; 1847181643Skmacy break; 1848181643Skmacy case SIOCADDMULTI: 1849181643Skmacy case SIOCDELMULTI: 1850181643Skmacy#ifdef notyet 1851181643Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1852181643Skmacy XN_LOCK(sc); 1853181643Skmacy xn_setmulti(sc); 1854181643Skmacy XN_UNLOCK(sc); 1855181643Skmacy error = 0; 1856181643Skmacy } 1857181643Skmacy#endif 1858181643Skmacy /* FALLTHROUGH */ 1859181643Skmacy case SIOCSIFMEDIA: 1860181643Skmacy case SIOCGIFMEDIA: 1861199997Sgibbs error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 1862181643Skmacy break; 1863181643Skmacy default: 1864181643Skmacy error = ether_ioctl(ifp, cmd, data); 1865181643Skmacy } 1866181643Skmacy 1867181643Skmacy return (error); 1868181643Skmacy} 1869181643Skmacy 1870181643Skmacystatic void 1871181643Skmacyxn_stop(struct netfront_info *sc) 1872181643Skmacy{ 1873181643Skmacy struct ifnet *ifp; 1874181643Skmacy 1875181643Skmacy XN_LOCK_ASSERT(sc); 1876181643Skmacy 1877181643Skmacy ifp = sc->xn_ifp; 1878181643Skmacy 1879181643Skmacy callout_stop(&sc->xn_stat_ch); 1880181643Skmacy 1881181643Skmacy xn_free_rx_ring(sc); 1882181643Skmacy xn_free_tx_ring(sc); 1883181643Skmacy 1884181643Skmacy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1885199997Sgibbs if_link_state_change(ifp, LINK_STATE_DOWN); 1886181643Skmacy} 1887181643Skmacy 1888181643Skmacy/* START of Xenolinux helper functions adapted to FreeBSD */ 1889185605Skmacyint 1890185605Skmacynetwork_connect(struct netfront_info *np) 1891181643Skmacy{ 1892186557Skmacy int i, requeue_idx, error; 1893181643Skmacy grant_ref_t ref; 1894181643Skmacy netif_rx_request_t *req; 1895181643Skmacy u_int feature_rx_copy, feature_rx_flip; 1896181643Skmacy 1897214077Sgibbs error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 1898186557Skmacy "feature-rx-copy", NULL, "%u", &feature_rx_copy); 1899186557Skmacy if (error) 1900181643Skmacy feature_rx_copy = 0; 1901214077Sgibbs error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 1902186557Skmacy "feature-rx-flip", NULL, "%u", &feature_rx_flip); 1903186557Skmacy if (error) 1904181643Skmacy feature_rx_flip = 1; 1905181643Skmacy 1906181643Skmacy /* 1907181643Skmacy * Copy packets on receive path if: 1908181643Skmacy * (a) This was requested by user, and the backend supports it; or 1909181643Skmacy * (b) Flipping was requested, but this is unsupported by the backend. 1910181643Skmacy */ 1911181643Skmacy np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) || 1912181643Skmacy (MODPARM_rx_flip && !feature_rx_flip)); 1913181643Skmacy 1914181643Skmacy /* Recovery procedure: */ 1915186557Skmacy error = talk_to_backend(np->xbdev, np); 1916186557Skmacy if (error) 1917186557Skmacy return (error); 1918181643Skmacy 1919181643Skmacy /* Step 1: Reinitialise variables. */ 1920225709Sgibbs xn_query_features(np); 1921225709Sgibbs xn_configure_features(np); 1922181643Skmacy netif_release_tx_bufs(np); 1923181643Skmacy 1924181643Skmacy /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ 1925181643Skmacy for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { 1926181643Skmacy struct mbuf *m; 1927186557Skmacy u_long pfn; 1928181643Skmacy 1929181643Skmacy if (np->rx_mbufs[i] == NULL) 1930181643Skmacy continue; 1931181643Skmacy 1932181643Skmacy m = np->rx_mbufs[requeue_idx] = xennet_get_rx_mbuf(np, i); 1933181643Skmacy ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i); 1934208901Sken 1935181643Skmacy req = RING_GET_REQUEST(&np->rx, requeue_idx); 1936186557Skmacy pfn = vtophys(mtod(m, vm_offset_t)) >> PAGE_SHIFT; 1937181643Skmacy 1938181643Skmacy if (!np->copying_receiver) { 1939181643Skmacy gnttab_grant_foreign_transfer_ref(ref, 1940185605Skmacy xenbus_get_otherend_id(np->xbdev), 1941186557Skmacy pfn); 1942181643Skmacy } else { 1943181643Skmacy gnttab_grant_foreign_access_ref(ref, 1944185605Skmacy xenbus_get_otherend_id(np->xbdev), 1945186557Skmacy PFNTOMFN(pfn), 0); 1946181643Skmacy } 1947181643Skmacy req->gref = ref; 1948181643Skmacy req->id = requeue_idx; 1949181643Skmacy 1950181643Skmacy requeue_idx++; 1951181643Skmacy } 1952181643Skmacy 1953181643Skmacy np->rx.req_prod_pvt = requeue_idx; 1954181643Skmacy 1955181643Skmacy /* Step 3: All public and private state should now be sane. Get 1956181643Skmacy * ready to start sending and receiving packets and give the driver 1957181643Skmacy * domain a kick because we've probably just requeued some 1958181643Skmacy * packets. 1959181643Skmacy */ 1960181643Skmacy netfront_carrier_on(np); 1961255040Sgibbs xen_intr_signal(np->xen_intr_handle); 1962181643Skmacy XN_TX_LOCK(np); 1963181643Skmacy xn_txeof(np); 1964181643Skmacy XN_TX_UNLOCK(np); 1965181643Skmacy network_alloc_rx_buffers(np); 1966181643Skmacy 1967181643Skmacy return (0); 1968181643Skmacy} 1969181643Skmacy 1970225709Sgibbsstatic void 1971225709Sgibbsxn_query_features(struct netfront_info *np) 1972225709Sgibbs{ 1973225709Sgibbs int val; 1974225709Sgibbs 1975225709Sgibbs device_printf(np->xbdev, "backend features:"); 1976225709Sgibbs 1977225709Sgibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 1978225709Sgibbs "feature-sg", NULL, "%d", &val) < 0) 1979225709Sgibbs val = 0; 1980225709Sgibbs 1981225709Sgibbs np->maxfrags = 1; 1982225709Sgibbs if (val) { 1983225709Sgibbs np->maxfrags = MAX_TX_REQ_FRAGS; 1984225709Sgibbs printf(" feature-sg"); 1985225709Sgibbs } 1986225709Sgibbs 1987225709Sgibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 1988225709Sgibbs "feature-gso-tcpv4", NULL, "%d", &val) < 0) 1989225709Sgibbs val = 0; 1990225709Sgibbs 1991225709Sgibbs np->xn_ifp->if_capabilities &= ~(IFCAP_TSO4|IFCAP_LRO); 1992225709Sgibbs if (val) { 1993225709Sgibbs np->xn_ifp->if_capabilities |= IFCAP_TSO4|IFCAP_LRO; 1994225709Sgibbs printf(" feature-gso-tcp4"); 1995225709Sgibbs } 1996225709Sgibbs 1997225709Sgibbs printf("\n"); 1998225709Sgibbs} 1999225709Sgibbs 2000225707Sgibbsstatic int 2001225709Sgibbsxn_configure_features(struct netfront_info *np) 2002225707Sgibbs{ 2003225707Sgibbs int err; 2004225707Sgibbs 2005225707Sgibbs err = 0; 2006259541Sglebius#if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 2007225709Sgibbs if ((np->xn_ifp->if_capenable & IFCAP_LRO) != 0) 2008225707Sgibbs tcp_lro_free(&np->xn_lro); 2009225709Sgibbs#endif 2010225709Sgibbs np->xn_ifp->if_capenable = 2011225709Sgibbs np->xn_ifp->if_capabilities & ~(IFCAP_LRO|IFCAP_TSO4); 2012225709Sgibbs np->xn_ifp->if_hwassist &= ~CSUM_TSO; 2013259541Sglebius#if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 2014225709Sgibbs if (xn_enable_lro && (np->xn_ifp->if_capabilities & IFCAP_LRO) != 0) { 2015225707Sgibbs err = tcp_lro_init(&np->xn_lro); 2016225707Sgibbs if (err) { 2017225707Sgibbs device_printf(np->xbdev, "LRO initialization failed\n"); 2018225707Sgibbs } else { 2019225707Sgibbs np->xn_lro.ifp = np->xn_ifp; 2020225709Sgibbs np->xn_ifp->if_capenable |= IFCAP_LRO; 2021225707Sgibbs } 2022225707Sgibbs } 2023225709Sgibbs if ((np->xn_ifp->if_capabilities & IFCAP_TSO4) != 0) { 2024225709Sgibbs np->xn_ifp->if_capenable |= IFCAP_TSO4; 2025225709Sgibbs np->xn_ifp->if_hwassist |= CSUM_TSO; 2026225709Sgibbs } 2027225707Sgibbs#endif 2028225707Sgibbs return (err); 2029225707Sgibbs} 2030225707Sgibbs 2031255040Sgibbs/** 2032255040Sgibbs * Create a network device. 2033255040Sgibbs * @param dev Newbus device representing this virtual NIC. 2034181643Skmacy */ 2035185605Skmacyint 2036185605Skmacycreate_netdev(device_t dev) 2037181643Skmacy{ 2038181643Skmacy int i; 2039181643Skmacy struct netfront_info *np; 2040181643Skmacy int err; 2041181643Skmacy struct ifnet *ifp; 2042181643Skmacy 2043185605Skmacy np = device_get_softc(dev); 2044181643Skmacy 2045181643Skmacy np->xbdev = dev; 2046181643Skmacy 2047181643Skmacy XN_LOCK_INIT(np, xennetif); 2048199997Sgibbs 2049199997Sgibbs ifmedia_init(&np->sc_media, 0, xn_ifmedia_upd, xn_ifmedia_sts); 2050199997Sgibbs ifmedia_add(&np->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 2051199997Sgibbs ifmedia_set(&np->sc_media, IFM_ETHER|IFM_MANUAL); 2052199997Sgibbs 2053181643Skmacy np->rx_target = RX_MIN_TARGET; 2054181643Skmacy np->rx_min_target = RX_MIN_TARGET; 2055181643Skmacy np->rx_max_target = RX_MAX_TARGET; 2056225709Sgibbs 2057181643Skmacy /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ 2058181643Skmacy for (i = 0; i <= NET_TX_RING_SIZE; i++) { 2059181643Skmacy np->tx_mbufs[i] = (void *) ((u_long) i+1); 2060214077Sgibbs np->grant_tx_ref[i] = GRANT_REF_INVALID; 2061181643Skmacy } 2062208901Sken np->tx_mbufs[NET_TX_RING_SIZE] = (void *)0; 2063208901Sken 2064181643Skmacy for (i = 0; i <= NET_RX_RING_SIZE; i++) { 2065208901Sken 2066181643Skmacy np->rx_mbufs[i] = NULL; 2067214077Sgibbs np->grant_rx_ref[i] = GRANT_REF_INVALID; 2068181643Skmacy } 2069181643Skmacy /* A grant for every tx ring slot */ 2070208901Sken if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, 2071208901Sken &np->gref_tx_head) != 0) { 2072204158Skmacy IPRINTK("#### netfront can't alloc tx grant refs\n"); 2073181643Skmacy err = ENOMEM; 2074181643Skmacy goto exit; 2075181643Skmacy } 2076181643Skmacy /* A grant for every rx ring slot */ 2077181643Skmacy if (gnttab_alloc_grant_references(RX_MAX_TARGET, 2078208901Sken &np->gref_rx_head) != 0) { 2079204158Skmacy WPRINTK("#### netfront can't alloc rx grant refs\n"); 2080181643Skmacy gnttab_free_grant_references(np->gref_tx_head); 2081181643Skmacy err = ENOMEM; 2082181643Skmacy goto exit; 2083181643Skmacy } 2084181643Skmacy 2085181643Skmacy err = xen_net_read_mac(dev, np->mac); 2086225708Sgibbs if (err) 2087181643Skmacy goto out; 2088181643Skmacy 2089181643Skmacy /* Set up ifnet structure */ 2090185605Skmacy ifp = np->xn_ifp = if_alloc(IFT_ETHER); 2091181643Skmacy ifp->if_softc = np; 2092185605Skmacy if_initname(ifp, "xn", device_get_unit(dev)); 2093186557Skmacy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2094181643Skmacy ifp->if_ioctl = xn_ioctl; 2095181643Skmacy ifp->if_output = ether_output; 2096181643Skmacy ifp->if_start = xn_start; 2097204158Skmacy#ifdef notyet 2098204158Skmacy ifp->if_watchdog = xn_watchdog; 2099204158Skmacy#endif 2100181643Skmacy ifp->if_init = xn_ifinit; 2101181643Skmacy ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1; 2102181643Skmacy 2103181643Skmacy ifp->if_hwassist = XN_CSUM_FEATURES; 2104181643Skmacy ifp->if_capabilities = IFCAP_HWCSUM; 2105251297Sandre ifp->if_hw_tsomax = NF_TSO_MAXBURST; 2106181643Skmacy 2107181643Skmacy ether_ifattach(ifp, np->mac); 2108181643Skmacy callout_init(&np->xn_stat_ch, CALLOUT_MPSAFE); 2109181643Skmacy netfront_carrier_off(np); 2110181643Skmacy 2111181643Skmacy return (0); 2112181643Skmacy 2113181643Skmacyexit: 2114181643Skmacy gnttab_free_grant_references(np->gref_tx_head); 2115181643Skmacyout: 2116225708Sgibbs return (err); 2117181643Skmacy} 2118181643Skmacy 2119181643Skmacy/** 2120181643Skmacy * Handle the change of state of the backend to Closing. We must delete our 2121181643Skmacy * device-layer structures now, to ensure that writes are flushed through to 2122181643Skmacy * the backend. Once is this done, we can switch to Closed in 2123181643Skmacy * acknowledgement. 2124181643Skmacy */ 2125181643Skmacy#if 0 2126199997Sgibbsstatic void 2127199997Sgibbsnetfront_closing(device_t dev) 2128181643Skmacy{ 2129181643Skmacy#if 0 2130181643Skmacy struct netfront_info *info = dev->dev_driver_data; 2131181643Skmacy 2132181643Skmacy DPRINTK("netfront_closing: %s removed\n", dev->nodename); 2133181643Skmacy 2134181643Skmacy close_netdev(info); 2135181643Skmacy#endif 2136181643Skmacy xenbus_switch_state(dev, XenbusStateClosed); 2137181643Skmacy} 2138181643Skmacy#endif 2139181643Skmacy 2140199997Sgibbsstatic int 2141199997Sgibbsnetfront_detach(device_t dev) 2142181643Skmacy{ 2143185605Skmacy struct netfront_info *info = device_get_softc(dev); 2144181643Skmacy 2145185605Skmacy DPRINTK("%s\n", xenbus_get_node(dev)); 2146181643Skmacy 2147181643Skmacy netif_free(info); 2148181643Skmacy 2149181643Skmacy return 0; 2150181643Skmacy} 2151181643Skmacy 2152199997Sgibbsstatic void 2153199997Sgibbsnetif_free(struct netfront_info *info) 2154181643Skmacy{ 2155250913Sgibbs XN_LOCK(info); 2156250913Sgibbs xn_stop(info); 2157250913Sgibbs XN_UNLOCK(info); 2158250913Sgibbs callout_drain(&info->xn_stat_ch); 2159181643Skmacy netif_disconnect_backend(info); 2160251176Sgibbs if (info->xn_ifp != NULL) { 2161251176Sgibbs ether_ifdetach(info->xn_ifp); 2162251176Sgibbs if_free(info->xn_ifp); 2163251176Sgibbs info->xn_ifp = NULL; 2164251176Sgibbs } 2165251729Sgibbs ifmedia_removeall(&info->sc_media); 2166181643Skmacy} 2167181643Skmacy 2168199997Sgibbsstatic void 2169199997Sgibbsnetif_disconnect_backend(struct netfront_info *info) 2170181643Skmacy{ 2171186557Skmacy XN_RX_LOCK(info); 2172186557Skmacy XN_TX_LOCK(info); 2173186557Skmacy netfront_carrier_off(info); 2174186557Skmacy XN_TX_UNLOCK(info); 2175186557Skmacy XN_RX_UNLOCK(info); 2176186557Skmacy 2177225707Sgibbs free_ring(&info->tx_ring_ref, &info->tx.sring); 2178225707Sgibbs free_ring(&info->rx_ring_ref, &info->rx.sring); 2179181643Skmacy 2180255040Sgibbs xen_intr_unbind(&info->xen_intr_handle); 2181181643Skmacy} 2182181643Skmacy 2183199997Sgibbsstatic void 2184225707Sgibbsfree_ring(int *ref, void *ring_ptr_ref) 2185181643Skmacy{ 2186225707Sgibbs void **ring_ptr_ptr = ring_ptr_ref; 2187225707Sgibbs 2188225707Sgibbs if (*ref != GRANT_REF_INVALID) { 2189225707Sgibbs /* This API frees the associated storage. */ 2190225707Sgibbs gnttab_end_foreign_access(*ref, *ring_ptr_ptr); 2191225707Sgibbs *ref = GRANT_REF_INVALID; 2192225707Sgibbs } 2193225707Sgibbs *ring_ptr_ptr = NULL; 2194181643Skmacy} 2195181643Skmacy 2196199997Sgibbsstatic int 2197199997Sgibbsxn_ifmedia_upd(struct ifnet *ifp) 2198199997Sgibbs{ 2199199997Sgibbs return (0); 2200199997Sgibbs} 2201199997Sgibbs 2202199997Sgibbsstatic void 2203199997Sgibbsxn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2204199997Sgibbs{ 2205199997Sgibbs ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE; 2206199997Sgibbs ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; 2207199997Sgibbs} 2208199997Sgibbs 2209181643Skmacy/* ** Driver registration ** */ 2210185605Skmacystatic device_method_t netfront_methods[] = { 2211185605Skmacy /* Device interface */ 2212185605Skmacy DEVMETHOD(device_probe, netfront_probe), 2213185605Skmacy DEVMETHOD(device_attach, netfront_attach), 2214185605Skmacy DEVMETHOD(device_detach, netfront_detach), 2215185605Skmacy DEVMETHOD(device_shutdown, bus_generic_shutdown), 2216225707Sgibbs DEVMETHOD(device_suspend, netfront_suspend), 2217185605Skmacy DEVMETHOD(device_resume, netfront_resume), 2218185605Skmacy 2219185605Skmacy /* Xenbus interface */ 2220214077Sgibbs DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed), 2221181643Skmacy 2222244991Smarius DEVMETHOD_END 2223185605Skmacy}; 2224181643Skmacy 2225185605Skmacystatic driver_t netfront_driver = { 2226185605Skmacy "xn", 2227185605Skmacy netfront_methods, 2228185605Skmacy sizeof(struct netfront_info), 2229185605Skmacy}; 2230185605Skmacydevclass_t netfront_devclass; 2231185605Skmacy 2232244991SmariusDRIVER_MODULE(xe, xenbusb_front, netfront_driver, netfront_devclass, NULL, 2233244991Smarius NULL); 2234