18e0ad55aSJoel Dahl /*- 289e0f4d2SKip Macy * Copyright (c) 2004-2006 Kip Macy 389e0f4d2SKip Macy * All rights reserved. 489e0f4d2SKip Macy * 58e0ad55aSJoel Dahl * Redistribution and use in source and binary forms, with or without 68e0ad55aSJoel Dahl * modification, are permitted provided that the following conditions 78e0ad55aSJoel Dahl * are met: 88e0ad55aSJoel Dahl * 1. Redistributions of source code must retain the above copyright 98e0ad55aSJoel Dahl * notice, this list of conditions and the following disclaimer. 108e0ad55aSJoel Dahl * 2. Redistributions in binary form must reproduce the above copyright 118e0ad55aSJoel Dahl * notice, this list of conditions and the following disclaimer in the 128e0ad55aSJoel Dahl * documentation and/or other materials provided with the distribution. 1389e0f4d2SKip Macy * 148e0ad55aSJoel Dahl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158e0ad55aSJoel Dahl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168e0ad55aSJoel Dahl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178e0ad55aSJoel Dahl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188e0ad55aSJoel Dahl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198e0ad55aSJoel Dahl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208e0ad55aSJoel Dahl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218e0ad55aSJoel Dahl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228e0ad55aSJoel Dahl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238e0ad55aSJoel Dahl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248e0ad55aSJoel Dahl * SUCH DAMAGE. 2589e0f4d2SKip Macy */ 2689e0f4d2SKip Macy 2789e0f4d2SKip Macy #include <sys/cdefs.h> 2889e0f4d2SKip Macy __FBSDID("$FreeBSD$"); 2989e0f4d2SKip Macy 30a0ae8f04SBjoern A. Zeeb #include "opt_inet.h" 31f909bbb4SGleb Smirnoff #include "opt_inet6.h" 32a0ae8f04SBjoern A. Zeeb 3389e0f4d2SKip Macy #include <sys/param.h> 3489e0f4d2SKip Macy #include <sys/systm.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> 4389e0f4d2SKip Macy #include <sys/queue.h> 448cb07992SAdrian Chadd #include <sys/lock.h> 4589e0f4d2SKip Macy #include <sys/sx.h> 4689e0f4d2SKip Macy 4789e0f4d2SKip Macy #include <net/if.h> 4877374386SGleb Smirnoff #include <net/if_var.h> 4989e0f4d2SKip Macy #include <net/if_arp.h> 5089e0f4d2SKip Macy #include <net/ethernet.h> 5189e0f4d2SKip Macy #include <net/if_dl.h> 5289e0f4d2SKip Macy #include <net/if_media.h> 5389e0f4d2SKip Macy 5489e0f4d2SKip Macy #include <net/bpf.h> 5589e0f4d2SKip Macy 5689e0f4d2SKip Macy #include <net/if_types.h> 5789e0f4d2SKip Macy 5889e0f4d2SKip Macy #include <netinet/in_systm.h> 5989e0f4d2SKip Macy #include <netinet/in.h> 6089e0f4d2SKip Macy #include <netinet/ip.h> 6189e0f4d2SKip Macy #include <netinet/if_ether.h> 6212678024SDoug Rabson #if __FreeBSD_version >= 700000 6312678024SDoug Rabson #include <netinet/tcp.h> 6412678024SDoug Rabson #include <netinet/tcp_lro.h> 6512678024SDoug Rabson #endif 6689e0f4d2SKip Macy 6789e0f4d2SKip Macy #include <vm/vm.h> 6889e0f4d2SKip Macy #include <vm/pmap.h> 6989e0f4d2SKip Macy 7089e0f4d2SKip Macy #include <machine/clock.h> /* for DELAY */ 7189e0f4d2SKip Macy #include <machine/bus.h> 7289e0f4d2SKip Macy #include <machine/resource.h> 7389e0f4d2SKip Macy #include <machine/frame.h> 74980c7178SKip Macy #include <machine/vmparam.h> 7589e0f4d2SKip Macy 7689e0f4d2SKip Macy #include <sys/bus.h> 7789e0f4d2SKip Macy #include <sys/rman.h> 7889e0f4d2SKip Macy 7989e0f4d2SKip Macy #include <machine/intr_machdep.h> 8089e0f4d2SKip Macy 8176acc41fSJustin T. Gibbs #include <xen/xen-os.h> 823a6d1fcfSKip Macy #include <xen/hypervisor.h> 833a6d1fcfSKip Macy #include <xen/xen_intr.h> 8489e0f4d2SKip Macy #include <xen/gnttab.h> 8589e0f4d2SKip Macy #include <xen/interface/memory.h> 8689e0f4d2SKip Macy #include <xen/interface/io/netif.h> 8723dc5621SKip Macy #include <xen/xenbus/xenbusvar.h> 8889e0f4d2SKip Macy 8923dc5621SKip Macy #include "xenbus_if.h" 9089e0f4d2SKip Macy 91578e4bf7SJustin T. Gibbs /* Features supported by all backends. TSO and LRO can be negotiated */ 92578e4bf7SJustin T. Gibbs #define XN_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) 9312678024SDoug Rabson 9489e0f4d2SKip Macy #define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) 9589e0f4d2SKip Macy #define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) 9689e0f4d2SKip Macy 9712678024SDoug Rabson #if __FreeBSD_version >= 700000 9812678024SDoug Rabson /* 9912678024SDoug Rabson * Should the driver do LRO on the RX end 10012678024SDoug Rabson * this can be toggled on the fly, but the 10112678024SDoug Rabson * interface must be reset (down/up) for it 10212678024SDoug Rabson * to take effect. 10312678024SDoug Rabson */ 10412678024SDoug Rabson static int xn_enable_lro = 1; 10512678024SDoug Rabson TUNABLE_INT("hw.xn.enable_lro", &xn_enable_lro); 10612678024SDoug Rabson #else 10712678024SDoug Rabson 10812678024SDoug Rabson #define IFCAP_TSO4 0 10912678024SDoug Rabson #define CSUM_TSO 0 11012678024SDoug Rabson 11112678024SDoug Rabson #endif 11212678024SDoug Rabson 113931eeffaSKenneth D. Merry /** 114931eeffaSKenneth D. Merry * \brief The maximum allowed data fragments in a single transmit 115931eeffaSKenneth D. Merry * request. 116931eeffaSKenneth D. Merry * 117931eeffaSKenneth D. Merry * This limit is imposed by the backend driver. We assume here that 118931eeffaSKenneth D. Merry * we are dealing with a Linux driver domain and have set our limit 119931eeffaSKenneth D. Merry * to mirror the Linux MAX_SKB_FRAGS constant. 120931eeffaSKenneth D. Merry */ 121931eeffaSKenneth D. Merry #define MAX_TX_REQ_FRAGS (65536 / PAGE_SIZE + 2) 122931eeffaSKenneth D. Merry 12389e0f4d2SKip Macy #define RX_COPY_THRESHOLD 256 12489e0f4d2SKip Macy 12589e0f4d2SKip Macy #define net_ratelimit() 0 12689e0f4d2SKip Macy 12789e0f4d2SKip Macy struct netfront_info; 12889e0f4d2SKip Macy struct netfront_rx_info; 12989e0f4d2SKip Macy 13089e0f4d2SKip Macy static void xn_txeof(struct netfront_info *); 13189e0f4d2SKip Macy static void xn_rxeof(struct netfront_info *); 13289e0f4d2SKip Macy static void network_alloc_rx_buffers(struct netfront_info *); 13389e0f4d2SKip Macy 13489e0f4d2SKip Macy static void xn_tick_locked(struct netfront_info *); 13589e0f4d2SKip Macy static void xn_tick(void *); 13689e0f4d2SKip Macy 13789e0f4d2SKip Macy static void xn_intr(void *); 138931eeffaSKenneth D. Merry static inline int xn_count_frags(struct mbuf *m); 139931eeffaSKenneth D. Merry static int xn_assemble_tx_request(struct netfront_info *sc, 140931eeffaSKenneth D. Merry struct mbuf *m_head); 14189e0f4d2SKip Macy static void xn_start_locked(struct ifnet *); 14289e0f4d2SKip Macy static void xn_start(struct ifnet *); 14389e0f4d2SKip Macy static int xn_ioctl(struct ifnet *, u_long, caddr_t); 14489e0f4d2SKip Macy static void xn_ifinit_locked(struct netfront_info *); 14589e0f4d2SKip Macy static void xn_ifinit(void *); 14689e0f4d2SKip Macy static void xn_stop(struct netfront_info *); 147578e4bf7SJustin T. Gibbs static void xn_query_features(struct netfront_info *np); 148578e4bf7SJustin T. Gibbs static int xn_configure_features(struct netfront_info *np); 14989e0f4d2SKip Macy #ifdef notyet 15089e0f4d2SKip Macy static void xn_watchdog(struct ifnet *); 15189e0f4d2SKip Macy #endif 15289e0f4d2SKip Macy 15389e0f4d2SKip Macy #ifdef notyet 15423dc5621SKip Macy static void netfront_closing(device_t dev); 15589e0f4d2SKip Macy #endif 15689e0f4d2SKip Macy static void netif_free(struct netfront_info *info); 15723dc5621SKip Macy static int netfront_detach(device_t dev); 15889e0f4d2SKip Macy 15923dc5621SKip Macy static int talk_to_backend(device_t dev, struct netfront_info *info); 16023dc5621SKip Macy static int create_netdev(device_t dev); 16189e0f4d2SKip Macy static void netif_disconnect_backend(struct netfront_info *info); 16223dc5621SKip Macy static int setup_device(device_t dev, struct netfront_info *info); 163cf9c09e1SJustin T. Gibbs static void free_ring(int *ref, void *ring_ptr_ref); 16489e0f4d2SKip Macy 1650e509842SJustin T. Gibbs static int xn_ifmedia_upd(struct ifnet *ifp); 1660e509842SJustin T. Gibbs static void xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 1670e509842SJustin T. Gibbs 16889e0f4d2SKip Macy /* Xenolinux helper functions */ 16923dc5621SKip Macy int network_connect(struct netfront_info *); 17089e0f4d2SKip Macy 17189e0f4d2SKip Macy static void xn_free_rx_ring(struct netfront_info *); 17289e0f4d2SKip Macy 17389e0f4d2SKip Macy static void xn_free_tx_ring(struct netfront_info *); 17489e0f4d2SKip Macy 17589e0f4d2SKip Macy static int xennet_get_responses(struct netfront_info *np, 176931eeffaSKenneth D. Merry struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, 177d0f3a8b9SRoger Pau Monné struct mbuf **list); 17889e0f4d2SKip Macy 1793c790178SJohn Baldwin #define virt_to_mfn(x) (vtophys(x) >> PAGE_SHIFT) 18089e0f4d2SKip Macy 18189e0f4d2SKip Macy #define INVALID_P2M_ENTRY (~0UL) 18289e0f4d2SKip Macy 18389e0f4d2SKip Macy /* 18489e0f4d2SKip Macy * Mbuf pointers. We need these to keep track of the virtual addresses 18589e0f4d2SKip Macy * of our mbuf chains since we can only convert from virtual to physical, 18689e0f4d2SKip Macy * not the other way around. The size must track the free index arrays. 18789e0f4d2SKip Macy */ 18889e0f4d2SKip Macy struct xn_chain_data { 18989e0f4d2SKip Macy struct mbuf *xn_tx_chain[NET_TX_RING_SIZE+1]; 190a4ec37f5SAdrian Chadd int xn_tx_chain_cnt; 19189e0f4d2SKip Macy struct mbuf *xn_rx_chain[NET_RX_RING_SIZE+1]; 19289e0f4d2SKip Macy }; 19389e0f4d2SKip Macy 1949a7f9feaSRoger Pau Monné struct netfront_stats 19589e0f4d2SKip Macy { 19689e0f4d2SKip Macy u_long rx_packets; /* total packets received */ 19789e0f4d2SKip Macy u_long tx_packets; /* total packets transmitted */ 19889e0f4d2SKip Macy u_long rx_bytes; /* total bytes received */ 19989e0f4d2SKip Macy u_long tx_bytes; /* total bytes transmitted */ 20089e0f4d2SKip Macy u_long rx_errors; /* bad packets received */ 20189e0f4d2SKip Macy u_long tx_errors; /* packet transmit problems */ 20289e0f4d2SKip Macy }; 20389e0f4d2SKip Macy 20489e0f4d2SKip Macy struct netfront_info { 20589e0f4d2SKip Macy struct ifnet *xn_ifp; 20612678024SDoug Rabson #if __FreeBSD_version >= 700000 20712678024SDoug Rabson struct lro_ctrl xn_lro; 20812678024SDoug Rabson #endif 20989e0f4d2SKip Macy 2109a7f9feaSRoger Pau Monné struct netfront_stats stats; 21189e0f4d2SKip Macy u_int tx_full; 21289e0f4d2SKip Macy 21389e0f4d2SKip Macy netif_tx_front_ring_t tx; 21489e0f4d2SKip Macy netif_rx_front_ring_t rx; 21589e0f4d2SKip Macy 21689e0f4d2SKip Macy struct mtx tx_lock; 21789e0f4d2SKip Macy struct mtx rx_lock; 218227ca257SKip Macy struct mtx sc_lock; 21989e0f4d2SKip Macy 22076acc41fSJustin T. Gibbs xen_intr_handle_t xen_intr_handle; 22189e0f4d2SKip Macy u_int carrier; 222578e4bf7SJustin T. Gibbs u_int maxfrags; 22389e0f4d2SKip Macy 22489e0f4d2SKip Macy /* Receive-ring batched refills. */ 22589e0f4d2SKip Macy #define RX_MIN_TARGET 32 22689e0f4d2SKip Macy #define RX_MAX_TARGET NET_RX_RING_SIZE 2270e509842SJustin T. Gibbs int rx_min_target; 2280e509842SJustin T. Gibbs int rx_max_target; 2290e509842SJustin T. Gibbs int rx_target; 23089e0f4d2SKip Macy 23189e0f4d2SKip Macy grant_ref_t gref_tx_head; 23289e0f4d2SKip Macy grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1]; 23389e0f4d2SKip Macy grant_ref_t gref_rx_head; 23489e0f4d2SKip Macy grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1]; 23589e0f4d2SKip Macy 23623dc5621SKip Macy device_t xbdev; 23789e0f4d2SKip Macy int tx_ring_ref; 23889e0f4d2SKip Macy int rx_ring_ref; 23989e0f4d2SKip Macy uint8_t mac[ETHER_ADDR_LEN]; 24089e0f4d2SKip Macy struct xn_chain_data xn_cdata; /* mbufs */ 241c578b6acSGleb Smirnoff struct mbufq xn_rx_batch; /* batch queue */ 24289e0f4d2SKip Macy 24389e0f4d2SKip Macy int xn_if_flags; 24489e0f4d2SKip Macy struct callout xn_stat_ch; 24589e0f4d2SKip Macy 24689e0f4d2SKip Macy u_long rx_pfn_array[NET_RX_RING_SIZE]; 2470e509842SJustin T. Gibbs struct ifmedia sc_media; 2486a8e9695SRoger Pau Monné 2496a8e9695SRoger Pau Monné bool xn_resume; 25089e0f4d2SKip Macy }; 25189e0f4d2SKip Macy 25289e0f4d2SKip Macy #define rx_mbufs xn_cdata.xn_rx_chain 25389e0f4d2SKip Macy #define tx_mbufs xn_cdata.xn_tx_chain 25489e0f4d2SKip Macy 25589e0f4d2SKip Macy #define XN_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_lock) 25689e0f4d2SKip Macy #define XN_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_lock) 25789e0f4d2SKip Macy 25889e0f4d2SKip Macy #define XN_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_lock) 25989e0f4d2SKip Macy #define XN_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_lock) 26089e0f4d2SKip Macy 261227ca257SKip Macy #define XN_LOCK(_sc) mtx_lock(&(_sc)->sc_lock); 262227ca257SKip Macy #define XN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock); 26389e0f4d2SKip Macy 264227ca257SKip Macy #define XN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED); 26589e0f4d2SKip Macy #define XN_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_lock, MA_OWNED); 26689e0f4d2SKip Macy #define XN_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_lock, MA_OWNED); 26789e0f4d2SKip Macy 26889e0f4d2SKip Macy struct netfront_rx_info { 26989e0f4d2SKip Macy struct netif_rx_response rx; 27089e0f4d2SKip Macy struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; 27189e0f4d2SKip Macy }; 27289e0f4d2SKip Macy 27389e0f4d2SKip Macy #define netfront_carrier_on(netif) ((netif)->carrier = 1) 27489e0f4d2SKip Macy #define netfront_carrier_off(netif) ((netif)->carrier = 0) 27589e0f4d2SKip Macy #define netfront_carrier_ok(netif) ((netif)->carrier) 27689e0f4d2SKip Macy 27789e0f4d2SKip Macy /* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ 27889e0f4d2SKip Macy 27989e0f4d2SKip Macy static inline void 280931eeffaSKenneth D. Merry add_id_to_freelist(struct mbuf **list, uintptr_t id) 28189e0f4d2SKip Macy { 282931eeffaSKenneth D. Merry KASSERT(id != 0, 283931eeffaSKenneth D. Merry ("%s: the head item (0) must always be free.", __func__)); 28489e0f4d2SKip Macy list[id] = list[0]; 285931eeffaSKenneth D. Merry list[0] = (struct mbuf *)id; 28689e0f4d2SKip Macy } 28789e0f4d2SKip Macy 28889e0f4d2SKip Macy static inline unsigned short 28989e0f4d2SKip Macy get_id_from_freelist(struct mbuf **list) 29089e0f4d2SKip Macy { 291931eeffaSKenneth D. Merry uintptr_t id; 292931eeffaSKenneth D. Merry 293931eeffaSKenneth D. Merry id = (uintptr_t)list[0]; 294931eeffaSKenneth D. Merry KASSERT(id != 0, 295931eeffaSKenneth D. Merry ("%s: the head item (0) must always remain free.", __func__)); 29689e0f4d2SKip Macy list[0] = list[id]; 29789e0f4d2SKip Macy return (id); 29889e0f4d2SKip Macy } 29989e0f4d2SKip Macy 30089e0f4d2SKip Macy static inline int 30189e0f4d2SKip Macy xennet_rxidx(RING_IDX idx) 30289e0f4d2SKip Macy { 30389e0f4d2SKip Macy return idx & (NET_RX_RING_SIZE - 1); 30489e0f4d2SKip Macy } 30589e0f4d2SKip Macy 30689e0f4d2SKip Macy static inline struct mbuf * 307931eeffaSKenneth D. Merry xennet_get_rx_mbuf(struct netfront_info *np, RING_IDX ri) 30889e0f4d2SKip Macy { 30989e0f4d2SKip Macy int i = xennet_rxidx(ri); 31089e0f4d2SKip Macy struct mbuf *m; 31189e0f4d2SKip Macy 31289e0f4d2SKip Macy m = np->rx_mbufs[i]; 31389e0f4d2SKip Macy np->rx_mbufs[i] = NULL; 31489e0f4d2SKip Macy return (m); 31589e0f4d2SKip Macy } 31689e0f4d2SKip Macy 31789e0f4d2SKip Macy static inline grant_ref_t 31889e0f4d2SKip Macy xennet_get_rx_ref(struct netfront_info *np, RING_IDX ri) 31989e0f4d2SKip Macy { 32089e0f4d2SKip Macy int i = xennet_rxidx(ri); 32189e0f4d2SKip Macy grant_ref_t ref = np->grant_rx_ref[i]; 322ff662b5cSJustin T. Gibbs KASSERT(ref != GRANT_REF_INVALID, ("Invalid grant reference!\n")); 323ff662b5cSJustin T. Gibbs np->grant_rx_ref[i] = GRANT_REF_INVALID; 32489e0f4d2SKip Macy return ref; 32589e0f4d2SKip Macy } 32689e0f4d2SKip Macy 32789e0f4d2SKip Macy #define IPRINTK(fmt, args...) \ 32889e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 329227ca257SKip Macy #ifdef INVARIANTS 33089e0f4d2SKip Macy #define WPRINTK(fmt, args...) \ 33189e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 332227ca257SKip Macy #else 333227ca257SKip Macy #define WPRINTK(fmt, args...) 334227ca257SKip Macy #endif 335227ca257SKip Macy #ifdef DEBUG 33689e0f4d2SKip Macy #define DPRINTK(fmt, args...) \ 33723dc5621SKip Macy printf("[XEN] %s: " fmt, __func__, ##args) 33812678024SDoug Rabson #else 33912678024SDoug Rabson #define DPRINTK(fmt, args...) 34012678024SDoug Rabson #endif 34189e0f4d2SKip Macy 34289e0f4d2SKip Macy /** 34389e0f4d2SKip Macy * Read the 'mac' node at the given device's node in the store, and parse that 34489e0f4d2SKip Macy * as colon-separated octets, placing result the given mac array. mac must be 34589e0f4d2SKip Macy * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). 34689e0f4d2SKip Macy * Return 0 on success, or errno on error. 34789e0f4d2SKip Macy */ 34889e0f4d2SKip Macy static int 34923dc5621SKip Macy xen_net_read_mac(device_t dev, uint8_t mac[]) 35089e0f4d2SKip Macy { 3513a6d1fcfSKip Macy int error, i; 3523a6d1fcfSKip Macy char *s, *e, *macstr; 353ffa06904SJustin T. Gibbs const char *path; 3543a6d1fcfSKip Macy 355ffa06904SJustin T. Gibbs path = xenbus_get_node(dev); 356ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 357ffa06904SJustin T. Gibbs if (error == ENOENT) { 358ffa06904SJustin T. Gibbs /* 359ffa06904SJustin T. Gibbs * Deal with missing mac XenStore nodes on devices with 360ffa06904SJustin T. Gibbs * HVM emulation (the 'ioemu' configuration attribute) 361ffa06904SJustin T. Gibbs * enabled. 362ffa06904SJustin T. Gibbs * 363ffa06904SJustin T. Gibbs * The HVM emulator may execute in a stub device model 364ffa06904SJustin T. Gibbs * domain which lacks the permission, only given to Dom0, 365ffa06904SJustin T. Gibbs * to update the guest's XenStore tree. For this reason, 366ffa06904SJustin T. Gibbs * the HVM emulator doesn't even attempt to write the 367ffa06904SJustin T. Gibbs * front-side mac node, even when operating in Dom0. 368ffa06904SJustin T. Gibbs * However, there should always be a mac listed in the 369ffa06904SJustin T. Gibbs * backend tree. Fallback to this version if our query 370ffa06904SJustin T. Gibbs * of the front side XenStore location doesn't find 371ffa06904SJustin T. Gibbs * anything. 372ffa06904SJustin T. Gibbs */ 373ffa06904SJustin T. Gibbs path = xenbus_get_otherend_path(dev); 374ffa06904SJustin T. Gibbs error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr); 375ffa06904SJustin T. Gibbs } 376ffa06904SJustin T. Gibbs if (error != 0) { 377ffa06904SJustin T. Gibbs xenbus_dev_fatal(dev, error, "parsing %s/mac", path); 3783a6d1fcfSKip Macy return (error); 379ffa06904SJustin T. Gibbs } 3803a6d1fcfSKip Macy 38189e0f4d2SKip Macy s = macstr; 38289e0f4d2SKip Macy for (i = 0; i < ETHER_ADDR_LEN; i++) { 38389e0f4d2SKip Macy mac[i] = strtoul(s, &e, 16); 38489e0f4d2SKip Macy if (s == e || (e[0] != ':' && e[0] != 0)) { 385ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 3863a6d1fcfSKip Macy return (ENOENT); 38789e0f4d2SKip Macy } 38889e0f4d2SKip Macy s = &e[1]; 38989e0f4d2SKip Macy } 390ff662b5cSJustin T. Gibbs free(macstr, M_XENBUS); 3913a6d1fcfSKip Macy return (0); 39289e0f4d2SKip Macy } 39389e0f4d2SKip Macy 39489e0f4d2SKip Macy /** 39589e0f4d2SKip Macy * Entry point to this code when a new device is created. Allocate the basic 39689e0f4d2SKip Macy * structures and the ring buffers for communication with the backend, and 39789e0f4d2SKip Macy * inform the backend of the appropriate details for those. Switch to 39889e0f4d2SKip Macy * Connected state. 39989e0f4d2SKip Macy */ 40089e0f4d2SKip Macy static int 40123dc5621SKip Macy netfront_probe(device_t dev) 40223dc5621SKip Macy { 40323dc5621SKip Macy 404f8f1bb83SRoger Pau Monné if (xen_hvm_domain() && xen_disable_pv_nics != 0) 405f8f1bb83SRoger Pau Monné return (ENXIO); 406f8f1bb83SRoger Pau Monné 40723dc5621SKip Macy if (!strcmp(xenbus_get_type(dev), "vif")) { 40823dc5621SKip Macy device_set_desc(dev, "Virtual Network Interface"); 40923dc5621SKip Macy return (0); 41023dc5621SKip Macy } 41123dc5621SKip Macy 41223dc5621SKip Macy return (ENXIO); 41323dc5621SKip Macy } 41423dc5621SKip Macy 41523dc5621SKip Macy static int 41623dc5621SKip Macy netfront_attach(device_t dev) 41789e0f4d2SKip Macy { 41889e0f4d2SKip Macy int err; 41989e0f4d2SKip Macy 42023dc5621SKip Macy err = create_netdev(dev); 42189e0f4d2SKip Macy if (err) { 42289e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "creating netdev"); 423ffa06904SJustin T. Gibbs return (err); 42489e0f4d2SKip Macy } 42589e0f4d2SKip Macy 42612678024SDoug Rabson #if __FreeBSD_version >= 700000 42712678024SDoug Rabson SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), 42812678024SDoug Rabson SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 429f0188618SHans Petter Selasky OID_AUTO, "enable_lro", CTLFLAG_RW, 43012678024SDoug Rabson &xn_enable_lro, 0, "Large Receive Offload"); 43112678024SDoug Rabson #endif 43212678024SDoug Rabson 433ffa06904SJustin T. Gibbs return (0); 43489e0f4d2SKip Macy } 43589e0f4d2SKip Macy 436cf9c09e1SJustin T. Gibbs static int 437cf9c09e1SJustin T. Gibbs netfront_suspend(device_t dev) 438cf9c09e1SJustin T. Gibbs { 439cf9c09e1SJustin T. Gibbs struct netfront_info *info = device_get_softc(dev); 440cf9c09e1SJustin T. Gibbs 441cf9c09e1SJustin T. Gibbs XN_RX_LOCK(info); 442cf9c09e1SJustin T. Gibbs XN_TX_LOCK(info); 443cf9c09e1SJustin T. Gibbs netfront_carrier_off(info); 444cf9c09e1SJustin T. Gibbs XN_TX_UNLOCK(info); 445cf9c09e1SJustin T. Gibbs XN_RX_UNLOCK(info); 446cf9c09e1SJustin T. Gibbs return (0); 447cf9c09e1SJustin T. Gibbs } 44889e0f4d2SKip Macy 44989e0f4d2SKip Macy /** 45089e0f4d2SKip Macy * We are reconnecting to the backend, due to a suspend/resume, or a backend 45189e0f4d2SKip Macy * driver restart. We tear down our netif structure and recreate it, but 45289e0f4d2SKip Macy * leave the device-layer structures intact so that this is transparent to the 45389e0f4d2SKip Macy * rest of the kernel. 45489e0f4d2SKip Macy */ 45589e0f4d2SKip Macy static int 45623dc5621SKip Macy netfront_resume(device_t dev) 45789e0f4d2SKip Macy { 45823dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 45989e0f4d2SKip Macy 4606a8e9695SRoger Pau Monné info->xn_resume = true; 46189e0f4d2SKip Macy netif_disconnect_backend(info); 46289e0f4d2SKip Macy return (0); 46389e0f4d2SKip Macy } 46489e0f4d2SKip Macy 46589e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */ 46689e0f4d2SKip Macy static int 46723dc5621SKip Macy talk_to_backend(device_t dev, struct netfront_info *info) 46889e0f4d2SKip Macy { 46989e0f4d2SKip Macy const char *message; 470ff662b5cSJustin T. Gibbs struct xs_transaction xst; 47123dc5621SKip Macy const char *node = xenbus_get_node(dev); 47289e0f4d2SKip Macy int err; 47389e0f4d2SKip Macy 47489e0f4d2SKip Macy err = xen_net_read_mac(dev, info->mac); 47589e0f4d2SKip Macy if (err) { 47623dc5621SKip Macy xenbus_dev_fatal(dev, err, "parsing %s/mac", node); 47789e0f4d2SKip Macy goto out; 47889e0f4d2SKip Macy } 47989e0f4d2SKip Macy 48089e0f4d2SKip Macy /* Create shared ring, alloc event channel. */ 48189e0f4d2SKip Macy err = setup_device(dev, info); 48289e0f4d2SKip Macy if (err) 48389e0f4d2SKip Macy goto out; 48489e0f4d2SKip Macy 48589e0f4d2SKip Macy again: 486ff662b5cSJustin T. Gibbs err = xs_transaction_start(&xst); 48789e0f4d2SKip Macy if (err) { 48889e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "starting transaction"); 48989e0f4d2SKip Macy goto destroy_ring; 49089e0f4d2SKip Macy } 491ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "tx-ring-ref","%u", 49289e0f4d2SKip Macy info->tx_ring_ref); 49389e0f4d2SKip Macy if (err) { 49489e0f4d2SKip Macy message = "writing tx ring-ref"; 49589e0f4d2SKip Macy goto abort_transaction; 49689e0f4d2SKip Macy } 497ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "rx-ring-ref","%u", 49889e0f4d2SKip Macy info->rx_ring_ref); 49989e0f4d2SKip Macy if (err) { 50089e0f4d2SKip Macy message = "writing rx ring-ref"; 50189e0f4d2SKip Macy goto abort_transaction; 50289e0f4d2SKip Macy } 503ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, 50476acc41fSJustin T. Gibbs "event-channel", "%u", 50576acc41fSJustin T. Gibbs xen_intr_port(info->xen_intr_handle)); 50689e0f4d2SKip Macy if (err) { 50789e0f4d2SKip Macy message = "writing event-channel"; 50889e0f4d2SKip Macy goto abort_transaction; 50989e0f4d2SKip Macy } 510d0f3a8b9SRoger Pau Monné err = xs_printf(xst, node, "request-rx-copy", "%u", 1); 51189e0f4d2SKip Macy if (err) { 51289e0f4d2SKip Macy message = "writing request-rx-copy"; 51389e0f4d2SKip Macy goto abort_transaction; 51489e0f4d2SKip Macy } 515ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-rx-notify", "%d", 1); 51689e0f4d2SKip Macy if (err) { 51789e0f4d2SKip Macy message = "writing feature-rx-notify"; 51889e0f4d2SKip Macy goto abort_transaction; 51989e0f4d2SKip Macy } 520ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-sg", "%d", 1); 52189e0f4d2SKip Macy if (err) { 52289e0f4d2SKip Macy message = "writing feature-sg"; 52389e0f4d2SKip Macy goto abort_transaction; 52489e0f4d2SKip Macy } 52512678024SDoug Rabson #if __FreeBSD_version >= 700000 526ff662b5cSJustin T. Gibbs err = xs_printf(xst, node, "feature-gso-tcpv4", "%d", 1); 52789e0f4d2SKip Macy if (err) { 52889e0f4d2SKip Macy message = "writing feature-gso-tcpv4"; 52989e0f4d2SKip Macy goto abort_transaction; 53089e0f4d2SKip Macy } 53189e0f4d2SKip Macy #endif 53289e0f4d2SKip Macy 533ff662b5cSJustin T. Gibbs err = xs_transaction_end(xst, 0); 53489e0f4d2SKip Macy if (err) { 53589e0f4d2SKip Macy if (err == EAGAIN) 53689e0f4d2SKip Macy goto again; 53789e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "completing transaction"); 53889e0f4d2SKip Macy goto destroy_ring; 53989e0f4d2SKip Macy } 54089e0f4d2SKip Macy 54189e0f4d2SKip Macy return 0; 54289e0f4d2SKip Macy 54389e0f4d2SKip Macy abort_transaction: 544ff662b5cSJustin T. Gibbs xs_transaction_end(xst, 1); 54589e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "%s", message); 54689e0f4d2SKip Macy destroy_ring: 54789e0f4d2SKip Macy netif_free(info); 54889e0f4d2SKip Macy out: 54989e0f4d2SKip Macy return err; 55089e0f4d2SKip Macy } 55189e0f4d2SKip Macy 55289e0f4d2SKip Macy static int 55323dc5621SKip Macy setup_device(device_t dev, struct netfront_info *info) 55489e0f4d2SKip Macy { 55589e0f4d2SKip Macy netif_tx_sring_t *txs; 55689e0f4d2SKip Macy netif_rx_sring_t *rxs; 5573a6d1fcfSKip Macy int error; 55889e0f4d2SKip Macy 559ff662b5cSJustin T. Gibbs info->tx_ring_ref = GRANT_REF_INVALID; 560ff662b5cSJustin T. Gibbs info->rx_ring_ref = GRANT_REF_INVALID; 56189e0f4d2SKip Macy info->rx.sring = NULL; 56289e0f4d2SKip Macy info->tx.sring = NULL; 56389e0f4d2SKip Macy 56489e0f4d2SKip Macy txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); 56589e0f4d2SKip Macy if (!txs) { 5663a6d1fcfSKip Macy error = ENOMEM; 5673a6d1fcfSKip Macy xenbus_dev_fatal(dev, error, "allocating tx ring page"); 56889e0f4d2SKip Macy goto fail; 56989e0f4d2SKip Macy } 57089e0f4d2SKip Macy SHARED_RING_INIT(txs); 57189e0f4d2SKip Macy FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE); 5723a6d1fcfSKip Macy error = xenbus_grant_ring(dev, virt_to_mfn(txs), &info->tx_ring_ref); 5733a6d1fcfSKip Macy if (error) 57489e0f4d2SKip Macy goto fail; 57589e0f4d2SKip Macy 57689e0f4d2SKip Macy rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); 57789e0f4d2SKip Macy if (!rxs) { 5783a6d1fcfSKip Macy error = ENOMEM; 5793a6d1fcfSKip Macy xenbus_dev_fatal(dev, error, "allocating rx ring page"); 58089e0f4d2SKip Macy goto fail; 58189e0f4d2SKip Macy } 58289e0f4d2SKip Macy SHARED_RING_INIT(rxs); 58389e0f4d2SKip Macy FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); 58489e0f4d2SKip Macy 5853a6d1fcfSKip Macy error = xenbus_grant_ring(dev, virt_to_mfn(rxs), &info->rx_ring_ref); 5863a6d1fcfSKip Macy if (error) 58789e0f4d2SKip Macy goto fail; 58889e0f4d2SKip Macy 58976acc41fSJustin T. Gibbs error = xen_intr_alloc_and_bind_local_port(dev, 59076acc41fSJustin T. Gibbs xenbus_get_otherend_id(dev), /*filter*/NULL, xn_intr, info, 59176acc41fSJustin T. Gibbs INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY, &info->xen_intr_handle); 59289e0f4d2SKip Macy 5933a6d1fcfSKip Macy if (error) { 5943a6d1fcfSKip Macy xenbus_dev_fatal(dev, error, 59576acc41fSJustin T. Gibbs "xen_intr_alloc_and_bind_local_port failed"); 59689e0f4d2SKip Macy goto fail; 59789e0f4d2SKip Macy } 59889e0f4d2SKip Macy 5993a6d1fcfSKip Macy return (0); 60089e0f4d2SKip Macy 60189e0f4d2SKip Macy fail: 60289e0f4d2SKip Macy netif_free(info); 6033a6d1fcfSKip Macy return (error); 60489e0f4d2SKip Macy } 60589e0f4d2SKip Macy 606a0ae8f04SBjoern A. Zeeb #ifdef INET 60789e0f4d2SKip Macy /** 60812678024SDoug Rabson * If this interface has an ipv4 address, send an arp for it. This 60912678024SDoug Rabson * helps to get the network going again after migrating hosts. 61012678024SDoug Rabson */ 61112678024SDoug Rabson static void 61212678024SDoug Rabson netfront_send_fake_arp(device_t dev, struct netfront_info *info) 61312678024SDoug Rabson { 61412678024SDoug Rabson struct ifnet *ifp; 61512678024SDoug Rabson struct ifaddr *ifa; 61612678024SDoug Rabson 61712678024SDoug Rabson ifp = info->xn_ifp; 61812678024SDoug Rabson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 61912678024SDoug Rabson if (ifa->ifa_addr->sa_family == AF_INET) { 62012678024SDoug Rabson arp_ifinit(ifp, ifa); 62112678024SDoug Rabson } 62212678024SDoug Rabson } 62312678024SDoug Rabson } 624a0ae8f04SBjoern A. Zeeb #endif 62512678024SDoug Rabson 62612678024SDoug Rabson /** 62789e0f4d2SKip Macy * Callback received when the backend's state changes. 62889e0f4d2SKip Macy */ 629283d6f72SJustin T. Gibbs static void 63023dc5621SKip Macy netfront_backend_changed(device_t dev, XenbusState newstate) 63189e0f4d2SKip Macy { 63223dc5621SKip Macy struct netfront_info *sc = device_get_softc(dev); 63389e0f4d2SKip Macy 63423dc5621SKip Macy DPRINTK("newstate=%d\n", newstate); 63589e0f4d2SKip Macy 63623dc5621SKip Macy switch (newstate) { 63789e0f4d2SKip Macy case XenbusStateInitialising: 63889e0f4d2SKip Macy case XenbusStateInitialised: 63989e0f4d2SKip Macy case XenbusStateUnknown: 64089e0f4d2SKip Macy case XenbusStateClosed: 641920ba15bSKip Macy case XenbusStateReconfigured: 642920ba15bSKip Macy case XenbusStateReconfiguring: 64389e0f4d2SKip Macy break; 64489e0f4d2SKip Macy case XenbusStateInitWait: 64523dc5621SKip Macy if (xenbus_get_state(dev) != XenbusStateInitialising) 64689e0f4d2SKip Macy break; 64723dc5621SKip Macy if (network_connect(sc) != 0) 64889e0f4d2SKip Macy break; 64923dc5621SKip Macy xenbus_set_state(dev, XenbusStateConnected); 65023dc5621SKip Macy break; 65189e0f4d2SKip Macy case XenbusStateClosing: 65223dc5621SKip Macy xenbus_set_state(dev, XenbusStateClosed); 65389e0f4d2SKip Macy break; 654dbf82bdeSRoger Pau Monné case XenbusStateConnected: 655dbf82bdeSRoger Pau Monné #ifdef INET 656dbf82bdeSRoger Pau Monné netfront_send_fake_arp(dev, sc); 657dbf82bdeSRoger Pau Monné #endif 658dbf82bdeSRoger Pau Monné break; 65989e0f4d2SKip Macy } 66089e0f4d2SKip Macy } 66189e0f4d2SKip Macy 66289e0f4d2SKip Macy static void 66389e0f4d2SKip Macy xn_free_rx_ring(struct netfront_info *sc) 66489e0f4d2SKip Macy { 66589e0f4d2SKip Macy #if 0 66689e0f4d2SKip Macy int i; 66789e0f4d2SKip Macy 66889e0f4d2SKip Macy for (i = 0; i < NET_RX_RING_SIZE; i++) { 669931eeffaSKenneth D. Merry if (sc->xn_cdata.rx_mbufs[i] != NULL) { 670931eeffaSKenneth D. Merry m_freem(sc->rx_mbufs[i]); 671931eeffaSKenneth D. Merry sc->rx_mbufs[i] = NULL; 67289e0f4d2SKip Macy } 67389e0f4d2SKip Macy } 67489e0f4d2SKip Macy 67589e0f4d2SKip Macy sc->rx.rsp_cons = 0; 67689e0f4d2SKip Macy sc->xn_rx_if->req_prod = 0; 67789e0f4d2SKip Macy sc->xn_rx_if->event = sc->rx.rsp_cons ; 67889e0f4d2SKip Macy #endif 67989e0f4d2SKip Macy } 68089e0f4d2SKip Macy 68189e0f4d2SKip Macy static void 68289e0f4d2SKip Macy xn_free_tx_ring(struct netfront_info *sc) 68389e0f4d2SKip Macy { 68489e0f4d2SKip Macy #if 0 68589e0f4d2SKip Macy int i; 68689e0f4d2SKip Macy 68789e0f4d2SKip Macy for (i = 0; i < NET_TX_RING_SIZE; i++) { 688931eeffaSKenneth D. Merry if (sc->tx_mbufs[i] != NULL) { 689931eeffaSKenneth D. Merry m_freem(sc->tx_mbufs[i]); 69089e0f4d2SKip Macy sc->xn_cdata.xn_tx_chain[i] = NULL; 69189e0f4d2SKip Macy } 69289e0f4d2SKip Macy } 69389e0f4d2SKip Macy 69489e0f4d2SKip Macy return; 69589e0f4d2SKip Macy #endif 69689e0f4d2SKip Macy } 69789e0f4d2SKip Macy 698931eeffaSKenneth D. Merry /** 699931eeffaSKenneth D. Merry * \brief Verify that there is sufficient space in the Tx ring 700931eeffaSKenneth D. Merry * buffer for a maximally sized request to be enqueued. 701c099cafaSAdrian Chadd * 702931eeffaSKenneth D. Merry * A transmit request requires a transmit descriptor for each packet 703931eeffaSKenneth D. Merry * fragment, plus up to 2 entries for "options" (e.g. TSO). 704c099cafaSAdrian Chadd */ 70589e0f4d2SKip Macy static inline int 706931eeffaSKenneth D. Merry xn_tx_slot_available(struct netfront_info *np) 70789e0f4d2SKip Macy { 708931eeffaSKenneth D. Merry return (RING_FREE_REQUESTS(&np->tx) > (MAX_TX_REQ_FRAGS + 2)); 70989e0f4d2SKip Macy } 710931eeffaSKenneth D. Merry 71189e0f4d2SKip Macy static void 71289e0f4d2SKip Macy netif_release_tx_bufs(struct netfront_info *np) 71389e0f4d2SKip Macy { 71489e0f4d2SKip Macy int i; 71589e0f4d2SKip Macy 71689e0f4d2SKip Macy for (i = 1; i <= NET_TX_RING_SIZE; i++) { 717931eeffaSKenneth D. Merry struct mbuf *m; 71889e0f4d2SKip Macy 719931eeffaSKenneth D. Merry m = np->tx_mbufs[i]; 720931eeffaSKenneth D. Merry 721931eeffaSKenneth D. Merry /* 722931eeffaSKenneth D. Merry * We assume that no kernel addresses are 723931eeffaSKenneth D. Merry * less than NET_TX_RING_SIZE. Any entry 724931eeffaSKenneth D. Merry * in the table that is below this number 725931eeffaSKenneth D. Merry * must be an index from free-list tracking. 726931eeffaSKenneth D. Merry */ 727931eeffaSKenneth D. Merry if (((uintptr_t)m) <= NET_TX_RING_SIZE) 72889e0f4d2SKip Macy continue; 729cf9c09e1SJustin T. Gibbs gnttab_end_foreign_access_ref(np->grant_tx_ref[i]); 73089e0f4d2SKip Macy gnttab_release_grant_reference(&np->gref_tx_head, 73189e0f4d2SKip Macy np->grant_tx_ref[i]); 732ff662b5cSJustin T. Gibbs np->grant_tx_ref[i] = GRANT_REF_INVALID; 73389e0f4d2SKip Macy add_id_to_freelist(np->tx_mbufs, i); 734a4ec37f5SAdrian Chadd np->xn_cdata.xn_tx_chain_cnt--; 735a4ec37f5SAdrian Chadd if (np->xn_cdata.xn_tx_chain_cnt < 0) { 7366f9767acSMarius Strobl panic("%s: tx_chain_cnt must be >= 0", __func__); 737a4ec37f5SAdrian Chadd } 738cf9c09e1SJustin T. Gibbs m_free(m); 73989e0f4d2SKip Macy } 74089e0f4d2SKip Macy } 74189e0f4d2SKip Macy 74289e0f4d2SKip Macy static void 74389e0f4d2SKip Macy network_alloc_rx_buffers(struct netfront_info *sc) 74489e0f4d2SKip Macy { 74523dc5621SKip Macy int otherend_id = xenbus_get_otherend_id(sc->xbdev); 74689e0f4d2SKip Macy unsigned short id; 74789e0f4d2SKip Macy struct mbuf *m_new; 74889e0f4d2SKip Macy int i, batch_target, notify; 74989e0f4d2SKip Macy RING_IDX req_prod; 75089e0f4d2SKip Macy grant_ref_t ref; 75189e0f4d2SKip Macy netif_rx_request_t *req; 75289e0f4d2SKip Macy vm_offset_t vaddr; 75389e0f4d2SKip Macy u_long pfn; 75489e0f4d2SKip Macy 75589e0f4d2SKip Macy req_prod = sc->rx.req_prod_pvt; 75689e0f4d2SKip Macy 75776acc41fSJustin T. Gibbs if (__predict_false(sc->carrier == 0)) 75889e0f4d2SKip Macy return; 75989e0f4d2SKip Macy 76089e0f4d2SKip Macy /* 761931eeffaSKenneth D. Merry * Allocate mbufs greedily, even though we batch updates to the 76289e0f4d2SKip Macy * receive ring. This creates a less bursty demand on the memory 763931eeffaSKenneth D. Merry * allocator, and so should reduce the chance of failed allocation 76489e0f4d2SKip Macy * requests both for ourself and for other kernel subsystems. 765931eeffaSKenneth D. Merry * 766931eeffaSKenneth D. Merry * Here we attempt to maintain rx_target buffers in flight, counting 767931eeffaSKenneth D. Merry * buffers that we have yet to process in the receive ring. 76889e0f4d2SKip Macy */ 76989e0f4d2SKip Macy batch_target = sc->rx_target - (req_prod - sc->rx.rsp_cons); 77089e0f4d2SKip Macy for (i = mbufq_len(&sc->xn_rx_batch); i < batch_target; i++) { 771c2d9c6f0SGleb Smirnoff m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); 772931eeffaSKenneth D. Merry if (m_new == NULL) { 77389e0f4d2SKip Macy if (i != 0) 77489e0f4d2SKip Macy goto refill; 77589e0f4d2SKip Macy /* 77689e0f4d2SKip Macy * XXX set timer 77789e0f4d2SKip Macy */ 77889e0f4d2SKip Macy break; 77989e0f4d2SKip Macy } 78089e0f4d2SKip Macy m_new->m_len = m_new->m_pkthdr.len = MJUMPAGESIZE; 78189e0f4d2SKip Macy 78289e0f4d2SKip Macy /* queue the mbufs allocated */ 783c578b6acSGleb Smirnoff (void )mbufq_enqueue(&sc->xn_rx_batch, m_new); 78489e0f4d2SKip Macy } 78589e0f4d2SKip Macy 786931eeffaSKenneth D. Merry /* 787931eeffaSKenneth D. Merry * If we've allocated at least half of our target number of entries, 788931eeffaSKenneth D. Merry * submit them to the backend - we have enough to make the overhead 789931eeffaSKenneth D. Merry * of submission worthwhile. Otherwise wait for more mbufs and 790931eeffaSKenneth D. Merry * request entries to become available. 791931eeffaSKenneth D. Merry */ 79289e0f4d2SKip Macy if (i < (sc->rx_target/2)) { 79389e0f4d2SKip Macy if (req_prod >sc->rx.sring->req_prod) 79489e0f4d2SKip Macy goto push; 79589e0f4d2SKip Macy return; 79689e0f4d2SKip Macy } 797931eeffaSKenneth D. Merry 798931eeffaSKenneth D. Merry /* 799931eeffaSKenneth D. Merry * Double floating fill target if we risked having the backend 800931eeffaSKenneth D. Merry * run out of empty buffers for receive traffic. We define "running 801931eeffaSKenneth D. Merry * low" as having less than a fourth of our target buffers free 802931eeffaSKenneth D. Merry * at the time we refilled the queue. 803931eeffaSKenneth D. Merry */ 804931eeffaSKenneth D. Merry if ((req_prod - sc->rx.sring->rsp_prod) < (sc->rx_target / 4)) { 805931eeffaSKenneth D. Merry sc->rx_target *= 2; 806931eeffaSKenneth D. Merry if (sc->rx_target > sc->rx_max_target) 80789e0f4d2SKip Macy sc->rx_target = sc->rx_max_target; 808931eeffaSKenneth D. Merry } 80989e0f4d2SKip Macy 81089e0f4d2SKip Macy refill: 811d0f3a8b9SRoger Pau Monné for (i = 0; ; i++) { 81289e0f4d2SKip Macy if ((m_new = mbufq_dequeue(&sc->xn_rx_batch)) == NULL) 81389e0f4d2SKip Macy break; 81489e0f4d2SKip Macy 81589e0f4d2SKip Macy m_new->m_ext.ext_arg1 = (vm_paddr_t *)(uintptr_t)( 81689e0f4d2SKip Macy vtophys(m_new->m_ext.ext_buf) >> PAGE_SHIFT); 81789e0f4d2SKip Macy 81889e0f4d2SKip Macy id = xennet_rxidx(req_prod + i); 81989e0f4d2SKip Macy 820931eeffaSKenneth D. Merry KASSERT(sc->rx_mbufs[id] == NULL, ("non-NULL xm_rx_chain")); 821931eeffaSKenneth D. Merry sc->rx_mbufs[id] = m_new; 82289e0f4d2SKip Macy 82389e0f4d2SKip Macy ref = gnttab_claim_grant_reference(&sc->gref_rx_head); 824ff662b5cSJustin T. Gibbs KASSERT(ref != GNTTAB_LIST_END, 825ff662b5cSJustin T. Gibbs ("reserved grant references exhuasted")); 82689e0f4d2SKip Macy sc->grant_rx_ref[id] = ref; 82789e0f4d2SKip Macy 82889e0f4d2SKip Macy vaddr = mtod(m_new, vm_offset_t); 82989e0f4d2SKip Macy pfn = vtophys(vaddr) >> PAGE_SHIFT; 83089e0f4d2SKip Macy req = RING_GET_REQUEST(&sc->rx, req_prod + i); 83189e0f4d2SKip Macy 832d0f3a8b9SRoger Pau Monné gnttab_grant_foreign_access_ref(ref, otherend_id, pfn, 0); 83389e0f4d2SKip Macy req->id = id; 83489e0f4d2SKip Macy req->gref = ref; 83589e0f4d2SKip Macy 83689e0f4d2SKip Macy sc->rx_pfn_array[i] = 8373c790178SJohn Baldwin vtophys(mtod(m_new,vm_offset_t)) >> PAGE_SHIFT; 83889e0f4d2SKip Macy } 83989e0f4d2SKip Macy 84089e0f4d2SKip Macy KASSERT(i, ("no mbufs processed")); /* should have returned earlier */ 84189e0f4d2SKip Macy KASSERT(mbufq_len(&sc->xn_rx_batch) == 0, ("not all mbufs processed")); 84289e0f4d2SKip Macy /* 84389e0f4d2SKip Macy * We may have allocated buffers which have entries outstanding 84489e0f4d2SKip Macy * in the page * update queue -- make sure we flush those first! 84589e0f4d2SKip Macy */ 84689e0f4d2SKip Macy wmb(); 84789e0f4d2SKip Macy 84889e0f4d2SKip Macy /* Above is a suitable barrier to ensure backend will see requests. */ 84989e0f4d2SKip Macy sc->rx.req_prod_pvt = req_prod + i; 85089e0f4d2SKip Macy push: 85189e0f4d2SKip Macy RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->rx, notify); 85289e0f4d2SKip Macy if (notify) 85376acc41fSJustin T. Gibbs xen_intr_signal(sc->xen_intr_handle); 85489e0f4d2SKip Macy } 85589e0f4d2SKip Macy 85689e0f4d2SKip Macy static void 85789e0f4d2SKip Macy xn_rxeof(struct netfront_info *np) 85889e0f4d2SKip Macy { 85989e0f4d2SKip Macy struct ifnet *ifp; 860f909bbb4SGleb Smirnoff #if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 86112678024SDoug Rabson struct lro_ctrl *lro = &np->xn_lro; 86212678024SDoug Rabson struct lro_entry *queued; 86312678024SDoug Rabson #endif 86489e0f4d2SKip Macy struct netfront_rx_info rinfo; 86589e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo.rx; 86689e0f4d2SKip Macy struct netif_extra_info *extras = rinfo.extras; 86789e0f4d2SKip Macy RING_IDX i, rp; 86889e0f4d2SKip Macy struct mbuf *m; 869c578b6acSGleb Smirnoff struct mbufq rxq, errq; 870d0f3a8b9SRoger Pau Monné int err, work_to_do; 87189e0f4d2SKip Macy 87249906218SDoug Rabson do { 87389e0f4d2SKip Macy XN_RX_LOCK_ASSERT(np); 87489e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 87589e0f4d2SKip Macy return; 87689e0f4d2SKip Macy 877c578b6acSGleb Smirnoff /* XXX: there should be some sane limit. */ 878c578b6acSGleb Smirnoff mbufq_init(&errq, INT_MAX); 879c578b6acSGleb Smirnoff mbufq_init(&rxq, INT_MAX); 88089e0f4d2SKip Macy 88189e0f4d2SKip Macy ifp = np->xn_ifp; 88289e0f4d2SKip Macy 88389e0f4d2SKip Macy rp = np->rx.sring->rsp_prod; 88489e0f4d2SKip Macy rmb(); /* Ensure we see queued responses up to 'rp'. */ 88589e0f4d2SKip Macy 88689e0f4d2SKip Macy i = np->rx.rsp_cons; 88789e0f4d2SKip Macy while ((i != rp)) { 88889e0f4d2SKip Macy memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx)); 88989e0f4d2SKip Macy memset(extras, 0, sizeof(rinfo.extras)); 89089e0f4d2SKip Macy 89183b92f6eSKip Macy m = NULL; 892d0f3a8b9SRoger Pau Monné err = xennet_get_responses(np, &rinfo, rp, &i, &m); 89389e0f4d2SKip Macy 89476acc41fSJustin T. Gibbs if (__predict_false(err)) { 89583b92f6eSKip Macy if (m) 896c578b6acSGleb Smirnoff (void )mbufq_enqueue(&errq, m); 89789e0f4d2SKip Macy np->stats.rx_errors++; 89889e0f4d2SKip Macy continue; 89989e0f4d2SKip Macy } 90089e0f4d2SKip Macy 90189e0f4d2SKip Macy m->m_pkthdr.rcvif = ifp; 90289e0f4d2SKip Macy if ( rx->flags & NETRXF_data_validated ) { 90389e0f4d2SKip Macy /* Tell the stack the checksums are okay */ 90489e0f4d2SKip Macy /* 90589e0f4d2SKip Macy * XXX this isn't necessarily the case - need to add 90689e0f4d2SKip Macy * check 90789e0f4d2SKip Macy */ 90889e0f4d2SKip Macy 90989e0f4d2SKip Macy m->m_pkthdr.csum_flags |= 91089e0f4d2SKip Macy (CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID 91189e0f4d2SKip Macy | CSUM_PSEUDO_HDR); 91289e0f4d2SKip Macy m->m_pkthdr.csum_data = 0xffff; 91389e0f4d2SKip Macy } 91489e0f4d2SKip Macy 91589e0f4d2SKip Macy np->stats.rx_packets++; 91683b92f6eSKip Macy np->stats.rx_bytes += m->m_pkthdr.len; 91789e0f4d2SKip Macy 918c578b6acSGleb Smirnoff (void )mbufq_enqueue(&rxq, m); 919931eeffaSKenneth D. Merry np->rx.rsp_cons = i; 92089e0f4d2SKip Macy } 92189e0f4d2SKip Macy 922c578b6acSGleb Smirnoff mbufq_drain(&errq); 92389e0f4d2SKip Macy 92489e0f4d2SKip Macy /* 92589e0f4d2SKip Macy * Process all the mbufs after the remapping is complete. 92689e0f4d2SKip Macy * Break the mbuf chain first though. 92789e0f4d2SKip Macy */ 92889e0f4d2SKip Macy while ((m = mbufq_dequeue(&rxq)) != NULL) { 929c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 93089e0f4d2SKip Macy 93189e0f4d2SKip Macy /* 93289e0f4d2SKip Macy * Do we really need to drop the rx lock? 93389e0f4d2SKip Macy */ 93489e0f4d2SKip Macy XN_RX_UNLOCK(np); 935f909bbb4SGleb Smirnoff #if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 93612678024SDoug Rabson /* Use LRO if possible */ 93712678024SDoug Rabson if ((ifp->if_capenable & IFCAP_LRO) == 0 || 93812678024SDoug Rabson lro->lro_cnt == 0 || tcp_lro_rx(lro, m, 0)) { 93912678024SDoug Rabson /* 94012678024SDoug Rabson * If LRO fails, pass up to the stack 94112678024SDoug Rabson * directly. 94212678024SDoug Rabson */ 94389e0f4d2SKip Macy (*ifp->if_input)(ifp, m); 94412678024SDoug Rabson } 94512678024SDoug Rabson #else 94612678024SDoug Rabson (*ifp->if_input)(ifp, m); 94712678024SDoug Rabson #endif 94889e0f4d2SKip Macy XN_RX_LOCK(np); 94989e0f4d2SKip Macy } 95089e0f4d2SKip Macy 95189e0f4d2SKip Macy np->rx.rsp_cons = i; 95289e0f4d2SKip Macy 953f909bbb4SGleb Smirnoff #if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 95412678024SDoug Rabson /* 95512678024SDoug Rabson * Flush any outstanding LRO work 95612678024SDoug Rabson */ 95712678024SDoug Rabson while (!SLIST_EMPTY(&lro->lro_active)) { 95812678024SDoug Rabson queued = SLIST_FIRST(&lro->lro_active); 95912678024SDoug Rabson SLIST_REMOVE_HEAD(&lro->lro_active, next); 96012678024SDoug Rabson tcp_lro_flush(lro, queued); 96112678024SDoug Rabson } 96212678024SDoug Rabson #endif 96312678024SDoug Rabson 96489e0f4d2SKip Macy #if 0 96589e0f4d2SKip Macy /* If we get a callback with very few responses, reduce fill target. */ 96689e0f4d2SKip Macy /* NB. Note exponential increase, linear decrease. */ 96789e0f4d2SKip Macy if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > 96889e0f4d2SKip Macy ((3*np->rx_target) / 4)) && (--np->rx_target < np->rx_min_target)) 96989e0f4d2SKip Macy np->rx_target = np->rx_min_target; 97089e0f4d2SKip Macy #endif 97189e0f4d2SKip Macy 97289e0f4d2SKip Macy network_alloc_rx_buffers(np); 97389e0f4d2SKip Macy 97449906218SDoug Rabson RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, work_to_do); 97549906218SDoug Rabson } while (work_to_do); 97689e0f4d2SKip Macy } 97789e0f4d2SKip Macy 97889e0f4d2SKip Macy static void 97989e0f4d2SKip Macy xn_txeof(struct netfront_info *np) 98089e0f4d2SKip Macy { 98189e0f4d2SKip Macy RING_IDX i, prod; 98289e0f4d2SKip Macy unsigned short id; 98389e0f4d2SKip Macy struct ifnet *ifp; 98412678024SDoug Rabson netif_tx_response_t *txr; 98589e0f4d2SKip Macy struct mbuf *m; 98689e0f4d2SKip Macy 98789e0f4d2SKip Macy XN_TX_LOCK_ASSERT(np); 98889e0f4d2SKip Macy 98989e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 99089e0f4d2SKip Macy return; 99189e0f4d2SKip Macy 99289e0f4d2SKip Macy ifp = np->xn_ifp; 99389e0f4d2SKip Macy 99489e0f4d2SKip Macy do { 99589e0f4d2SKip Macy prod = np->tx.sring->rsp_prod; 99689e0f4d2SKip Macy rmb(); /* Ensure we see responses up to 'rp'. */ 99789e0f4d2SKip Macy 99889e0f4d2SKip Macy for (i = np->tx.rsp_cons; i != prod; i++) { 99912678024SDoug Rabson txr = RING_GET_RESPONSE(&np->tx, i); 100012678024SDoug Rabson if (txr->status == NETIF_RSP_NULL) 100112678024SDoug Rabson continue; 100212678024SDoug Rabson 1003931eeffaSKenneth D. Merry if (txr->status != NETIF_RSP_OKAY) { 1004931eeffaSKenneth D. Merry printf("%s: WARNING: response is %d!\n", 1005931eeffaSKenneth D. Merry __func__, txr->status); 1006931eeffaSKenneth D. Merry } 100712678024SDoug Rabson id = txr->id; 1008931eeffaSKenneth D. Merry m = np->tx_mbufs[id]; 10092d8fae98SAdrian Chadd KASSERT(m != NULL, ("mbuf not found in xn_tx_chain")); 1010931eeffaSKenneth D. Merry KASSERT((uintptr_t)m > NET_TX_RING_SIZE, 1011931eeffaSKenneth D. Merry ("mbuf already on the free list, but we're " 1012931eeffaSKenneth D. Merry "trying to free it again!")); 10132d8fae98SAdrian Chadd M_ASSERTVALID(m); 101489e0f4d2SKip Macy 101512678024SDoug Rabson /* 101612678024SDoug Rabson * Increment packet count if this is the last 101712678024SDoug Rabson * mbuf of the chain. 101812678024SDoug Rabson */ 101912678024SDoug Rabson if (!m->m_next) 1020c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 102176acc41fSJustin T. Gibbs if (__predict_false(gnttab_query_foreign_access( 102289e0f4d2SKip Macy np->grant_tx_ref[id]) != 0)) { 10236f9767acSMarius Strobl panic("%s: grant id %u still in use by the " 10246f9767acSMarius Strobl "backend", __func__, id); 102589e0f4d2SKip Macy } 102689e0f4d2SKip Macy gnttab_end_foreign_access_ref( 1027920ba15bSKip Macy np->grant_tx_ref[id]); 102889e0f4d2SKip Macy gnttab_release_grant_reference( 102989e0f4d2SKip Macy &np->gref_tx_head, np->grant_tx_ref[id]); 1030ff662b5cSJustin T. Gibbs np->grant_tx_ref[id] = GRANT_REF_INVALID; 103189e0f4d2SKip Macy 1032931eeffaSKenneth D. Merry np->tx_mbufs[id] = NULL; 1033931eeffaSKenneth D. Merry add_id_to_freelist(np->tx_mbufs, id); 1034a4ec37f5SAdrian Chadd np->xn_cdata.xn_tx_chain_cnt--; 103512678024SDoug Rabson m_free(m); 1036d76e4550SAdrian Chadd /* Only mark the queue active if we've freed up at least one slot to try */ 1037d76e4550SAdrian Chadd ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 103889e0f4d2SKip Macy } 103989e0f4d2SKip Macy np->tx.rsp_cons = prod; 104089e0f4d2SKip Macy 104189e0f4d2SKip Macy /* 104289e0f4d2SKip Macy * Set a new event, then check for race with update of 104389e0f4d2SKip Macy * tx_cons. Note that it is essential to schedule a 104489e0f4d2SKip Macy * callback, no matter how few buffers are pending. Even if 104589e0f4d2SKip Macy * there is space in the transmit ring, higher layers may 104689e0f4d2SKip Macy * be blocked because too much data is outstanding: in such 104789e0f4d2SKip Macy * cases notification from Xen is likely to be the only kick 104889e0f4d2SKip Macy * that we'll get. 104989e0f4d2SKip Macy */ 105089e0f4d2SKip Macy np->tx.sring->rsp_event = 105189e0f4d2SKip Macy prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; 105289e0f4d2SKip Macy 105389e0f4d2SKip Macy mb(); 105489e0f4d2SKip Macy } while (prod != np->tx.sring->rsp_prod); 105589e0f4d2SKip Macy 105689e0f4d2SKip Macy if (np->tx_full && 105789e0f4d2SKip Macy ((np->tx.sring->req_prod - prod) < NET_TX_RING_SIZE)) { 105889e0f4d2SKip Macy np->tx_full = 0; 105989e0f4d2SKip Macy #if 0 106089e0f4d2SKip Macy if (np->user_state == UST_OPEN) 106189e0f4d2SKip Macy netif_wake_queue(dev); 106289e0f4d2SKip Macy #endif 106389e0f4d2SKip Macy } 106489e0f4d2SKip Macy } 106589e0f4d2SKip Macy 106689e0f4d2SKip Macy static void 106789e0f4d2SKip Macy xn_intr(void *xsc) 106889e0f4d2SKip Macy { 106989e0f4d2SKip Macy struct netfront_info *np = xsc; 107089e0f4d2SKip Macy struct ifnet *ifp = np->xn_ifp; 107189e0f4d2SKip Macy 107289e0f4d2SKip Macy #if 0 107389e0f4d2SKip Macy if (!(np->rx.rsp_cons != np->rx.sring->rsp_prod && 107489e0f4d2SKip Macy likely(netfront_carrier_ok(np)) && 107589e0f4d2SKip Macy ifp->if_drv_flags & IFF_DRV_RUNNING)) 107689e0f4d2SKip Macy return; 107789e0f4d2SKip Macy #endif 1078931eeffaSKenneth D. Merry if (RING_HAS_UNCONSUMED_RESPONSES(&np->tx)) { 107989e0f4d2SKip Macy XN_TX_LOCK(np); 108089e0f4d2SKip Macy xn_txeof(np); 108189e0f4d2SKip Macy XN_TX_UNLOCK(np); 108289e0f4d2SKip Macy } 108389e0f4d2SKip Macy 108489e0f4d2SKip Macy XN_RX_LOCK(np); 108589e0f4d2SKip Macy xn_rxeof(np); 108689e0f4d2SKip Macy XN_RX_UNLOCK(np); 108789e0f4d2SKip Macy 108889e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING && 108989e0f4d2SKip Macy !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 109089e0f4d2SKip Macy xn_start(ifp); 109189e0f4d2SKip Macy } 109289e0f4d2SKip Macy 109389e0f4d2SKip Macy static void 109489e0f4d2SKip Macy xennet_move_rx_slot(struct netfront_info *np, struct mbuf *m, 109589e0f4d2SKip Macy grant_ref_t ref) 109689e0f4d2SKip Macy { 109789e0f4d2SKip Macy int new = xennet_rxidx(np->rx.req_prod_pvt); 109889e0f4d2SKip Macy 109989e0f4d2SKip Macy KASSERT(np->rx_mbufs[new] == NULL, ("rx_mbufs != NULL")); 110089e0f4d2SKip Macy np->rx_mbufs[new] = m; 110189e0f4d2SKip Macy np->grant_rx_ref[new] = ref; 110289e0f4d2SKip Macy RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new; 110389e0f4d2SKip Macy RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref; 110489e0f4d2SKip Macy np->rx.req_prod_pvt++; 110589e0f4d2SKip Macy } 110689e0f4d2SKip Macy 110789e0f4d2SKip Macy static int 110889e0f4d2SKip Macy xennet_get_extras(struct netfront_info *np, 1109931eeffaSKenneth D. Merry struct netif_extra_info *extras, RING_IDX rp, RING_IDX *cons) 111089e0f4d2SKip Macy { 111189e0f4d2SKip Macy struct netif_extra_info *extra; 111289e0f4d2SKip Macy 111389e0f4d2SKip Macy int err = 0; 111489e0f4d2SKip Macy 111589e0f4d2SKip Macy do { 111689e0f4d2SKip Macy struct mbuf *m; 111789e0f4d2SKip Macy grant_ref_t ref; 111889e0f4d2SKip Macy 111976acc41fSJustin T. Gibbs if (__predict_false(*cons + 1 == rp)) { 112089e0f4d2SKip Macy #if 0 112189e0f4d2SKip Macy if (net_ratelimit()) 112289e0f4d2SKip Macy WPRINTK("Missing extra info\n"); 112389e0f4d2SKip Macy #endif 1124931eeffaSKenneth D. Merry err = EINVAL; 112589e0f4d2SKip Macy break; 112689e0f4d2SKip Macy } 112789e0f4d2SKip Macy 112889e0f4d2SKip Macy extra = (struct netif_extra_info *) 1129931eeffaSKenneth D. Merry RING_GET_RESPONSE(&np->rx, ++(*cons)); 113089e0f4d2SKip Macy 113176acc41fSJustin T. Gibbs if (__predict_false(!extra->type || 113289e0f4d2SKip Macy extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { 113389e0f4d2SKip Macy #if 0 113489e0f4d2SKip Macy if (net_ratelimit()) 113589e0f4d2SKip Macy WPRINTK("Invalid extra type: %d\n", 113689e0f4d2SKip Macy extra->type); 113789e0f4d2SKip Macy #endif 1138931eeffaSKenneth D. Merry err = EINVAL; 113989e0f4d2SKip Macy } else { 114089e0f4d2SKip Macy memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); 114189e0f4d2SKip Macy } 114289e0f4d2SKip Macy 1143931eeffaSKenneth D. Merry m = xennet_get_rx_mbuf(np, *cons); 1144931eeffaSKenneth D. Merry ref = xennet_get_rx_ref(np, *cons); 114589e0f4d2SKip Macy xennet_move_rx_slot(np, m, ref); 114689e0f4d2SKip Macy } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); 114789e0f4d2SKip Macy 114889e0f4d2SKip Macy return err; 114989e0f4d2SKip Macy } 115089e0f4d2SKip Macy 115189e0f4d2SKip Macy static int 115289e0f4d2SKip Macy xennet_get_responses(struct netfront_info *np, 1153931eeffaSKenneth D. Merry struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons, 1154d0f3a8b9SRoger Pau Monné struct mbuf **list) 115589e0f4d2SKip Macy { 115689e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo->rx; 115789e0f4d2SKip Macy struct netif_extra_info *extras = rinfo->extras; 115883b92f6eSKip Macy struct mbuf *m, *m0, *m_prev; 1159931eeffaSKenneth D. Merry grant_ref_t ref = xennet_get_rx_ref(np, *cons); 1160931eeffaSKenneth D. Merry RING_IDX ref_cons = *cons; 116189e0f4d2SKip Macy int frags = 1; 116289e0f4d2SKip Macy int err = 0; 116389e0f4d2SKip Macy u_long ret; 116489e0f4d2SKip Macy 1165931eeffaSKenneth D. Merry m0 = m = m_prev = xennet_get_rx_mbuf(np, *cons); 116683b92f6eSKip Macy 116789e0f4d2SKip Macy if (rx->flags & NETRXF_extra_info) { 1168931eeffaSKenneth D. Merry err = xennet_get_extras(np, extras, rp, cons); 116989e0f4d2SKip Macy } 117089e0f4d2SKip Macy 117183b92f6eSKip Macy if (m0 != NULL) { 117283b92f6eSKip Macy m0->m_pkthdr.len = 0; 117383b92f6eSKip Macy m0->m_next = NULL; 117483b92f6eSKip Macy } 117583b92f6eSKip Macy 117689e0f4d2SKip Macy for (;;) { 117783b92f6eSKip Macy #if 0 1178227ca257SKip Macy DPRINTK("rx->status=%hd rx->offset=%hu frags=%u\n", 117983b92f6eSKip Macy rx->status, rx->offset, frags); 118083b92f6eSKip Macy #endif 118176acc41fSJustin T. Gibbs if (__predict_false(rx->status < 0 || 118289e0f4d2SKip Macy rx->offset + rx->status > PAGE_SIZE)) { 1183931eeffaSKenneth D. Merry 118489e0f4d2SKip Macy #if 0 118589e0f4d2SKip Macy if (net_ratelimit()) 118689e0f4d2SKip Macy WPRINTK("rx->offset: %x, size: %u\n", 118789e0f4d2SKip Macy rx->offset, rx->status); 118889e0f4d2SKip Macy #endif 118989e0f4d2SKip Macy xennet_move_rx_slot(np, m, ref); 1190931eeffaSKenneth D. Merry if (m0 == m) 1191931eeffaSKenneth D. Merry m0 = NULL; 1192931eeffaSKenneth D. Merry m = NULL; 1193931eeffaSKenneth D. Merry err = EINVAL; 1194931eeffaSKenneth D. Merry goto next_skip_queue; 119589e0f4d2SKip Macy } 119689e0f4d2SKip Macy 119789e0f4d2SKip Macy /* 119889e0f4d2SKip Macy * This definitely indicates a bug, either in this driver or in 119989e0f4d2SKip Macy * the backend driver. In future this should flag the bad 120089e0f4d2SKip Macy * situation to the system controller to reboot the backed. 120189e0f4d2SKip Macy */ 1202ff662b5cSJustin T. Gibbs if (ref == GRANT_REF_INVALID) { 1203931eeffaSKenneth D. Merry 120489e0f4d2SKip Macy #if 0 120589e0f4d2SKip Macy if (net_ratelimit()) 120689e0f4d2SKip Macy WPRINTK("Bad rx response id %d.\n", rx->id); 120789e0f4d2SKip Macy #endif 1208ff662b5cSJustin T. Gibbs printf("%s: Bad rx response id %d.\n", __func__,rx->id); 1209931eeffaSKenneth D. Merry err = EINVAL; 121089e0f4d2SKip Macy goto next; 121189e0f4d2SKip Macy } 121289e0f4d2SKip Macy 1213920ba15bSKip Macy ret = gnttab_end_foreign_access_ref(ref); 1214d0f3a8b9SRoger Pau Monné KASSERT(ret, ("Unable to end access to grant references")); 121589e0f4d2SKip Macy 121689e0f4d2SKip Macy gnttab_release_grant_reference(&np->gref_rx_head, ref); 121789e0f4d2SKip Macy 121889e0f4d2SKip Macy next: 12193a539122SAdrian Chadd if (m == NULL) 12203a539122SAdrian Chadd break; 12213a539122SAdrian Chadd 122283b92f6eSKip Macy m->m_len = rx->status; 122383b92f6eSKip Macy m->m_data += rx->offset; 122483b92f6eSKip Macy m0->m_pkthdr.len += rx->status; 122583b92f6eSKip Macy 1226931eeffaSKenneth D. Merry next_skip_queue: 122789e0f4d2SKip Macy if (!(rx->flags & NETRXF_more_data)) 122889e0f4d2SKip Macy break; 122989e0f4d2SKip Macy 1230931eeffaSKenneth D. Merry if (*cons + frags == rp) { 123189e0f4d2SKip Macy if (net_ratelimit()) 123289e0f4d2SKip Macy WPRINTK("Need more frags\n"); 1233931eeffaSKenneth D. Merry err = ENOENT; 1234931eeffaSKenneth D. Merry printf("%s: cons %u frags %u rp %u, not enough frags\n", 1235931eeffaSKenneth D. Merry __func__, *cons, frags, rp); 123689e0f4d2SKip Macy break; 123789e0f4d2SKip Macy } 1238931eeffaSKenneth D. Merry /* 1239931eeffaSKenneth D. Merry * Note that m can be NULL, if rx->status < 0 or if 1240931eeffaSKenneth D. Merry * rx->offset + rx->status > PAGE_SIZE above. 1241931eeffaSKenneth D. Merry */ 124283b92f6eSKip Macy m_prev = m; 124389e0f4d2SKip Macy 1244931eeffaSKenneth D. Merry rx = RING_GET_RESPONSE(&np->rx, *cons + frags); 1245931eeffaSKenneth D. Merry m = xennet_get_rx_mbuf(np, *cons + frags); 124683b92f6eSKip Macy 1247931eeffaSKenneth D. Merry /* 1248931eeffaSKenneth D. Merry * m_prev == NULL can happen if rx->status < 0 or if 1249931eeffaSKenneth D. Merry * rx->offset + * rx->status > PAGE_SIZE above. 1250931eeffaSKenneth D. Merry */ 1251931eeffaSKenneth D. Merry if (m_prev != NULL) 125283b92f6eSKip Macy m_prev->m_next = m; 1253931eeffaSKenneth D. Merry 1254931eeffaSKenneth D. Merry /* 1255931eeffaSKenneth D. Merry * m0 can be NULL if rx->status < 0 or if * rx->offset + 1256931eeffaSKenneth D. Merry * rx->status > PAGE_SIZE above. 1257931eeffaSKenneth D. Merry */ 1258931eeffaSKenneth D. Merry if (m0 == NULL) 1259931eeffaSKenneth D. Merry m0 = m; 126083b92f6eSKip Macy m->m_next = NULL; 1261931eeffaSKenneth D. Merry ref = xennet_get_rx_ref(np, *cons + frags); 1262931eeffaSKenneth D. Merry ref_cons = *cons + frags; 126389e0f4d2SKip Macy frags++; 126489e0f4d2SKip Macy } 126583b92f6eSKip Macy *list = m0; 1266931eeffaSKenneth D. Merry *cons += frags; 126789e0f4d2SKip Macy 12688577146eSJustin T. Gibbs return (err); 126989e0f4d2SKip Macy } 127089e0f4d2SKip Macy 127189e0f4d2SKip Macy static void 127289e0f4d2SKip Macy xn_tick_locked(struct netfront_info *sc) 127389e0f4d2SKip Macy { 127489e0f4d2SKip Macy XN_RX_LOCK_ASSERT(sc); 127589e0f4d2SKip Macy callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); 127689e0f4d2SKip Macy 127789e0f4d2SKip Macy /* XXX placeholder for printing debug information */ 127889e0f4d2SKip Macy } 127989e0f4d2SKip Macy 128089e0f4d2SKip Macy static void 128189e0f4d2SKip Macy xn_tick(void *xsc) 128289e0f4d2SKip Macy { 128389e0f4d2SKip Macy struct netfront_info *sc; 128489e0f4d2SKip Macy 128589e0f4d2SKip Macy sc = xsc; 128689e0f4d2SKip Macy XN_RX_LOCK(sc); 128789e0f4d2SKip Macy xn_tick_locked(sc); 128889e0f4d2SKip Macy XN_RX_UNLOCK(sc); 128989e0f4d2SKip Macy } 129089e0f4d2SKip Macy 1291931eeffaSKenneth D. Merry /** 1292931eeffaSKenneth D. Merry * \brief Count the number of fragments in an mbuf chain. 1293931eeffaSKenneth D. Merry * 1294931eeffaSKenneth D. Merry * Surprisingly, there isn't an M* macro for this. 1295c099cafaSAdrian Chadd */ 1296931eeffaSKenneth D. Merry static inline int 1297931eeffaSKenneth D. Merry xn_count_frags(struct mbuf *m) 1298931eeffaSKenneth D. Merry { 1299931eeffaSKenneth D. Merry int nfrags; 1300931eeffaSKenneth D. Merry 1301931eeffaSKenneth D. Merry for (nfrags = 0; m != NULL; m = m->m_next) 1302931eeffaSKenneth D. Merry nfrags++; 1303931eeffaSKenneth D. Merry 1304931eeffaSKenneth D. Merry return (nfrags); 130589e0f4d2SKip Macy } 130689e0f4d2SKip Macy 1307931eeffaSKenneth D. Merry /** 1308931eeffaSKenneth D. Merry * Given an mbuf chain, make sure we have enough room and then push 1309931eeffaSKenneth D. Merry * it onto the transmit ring. 1310931eeffaSKenneth D. Merry */ 1311931eeffaSKenneth D. Merry static int 1312931eeffaSKenneth D. Merry xn_assemble_tx_request(struct netfront_info *sc, struct mbuf *m_head) 1313931eeffaSKenneth D. Merry { 1314931eeffaSKenneth D. Merry struct ifnet *ifp; 1315931eeffaSKenneth D. Merry struct mbuf *m; 1316931eeffaSKenneth D. Merry u_int nfrags; 1317931eeffaSKenneth D. Merry int otherend_id; 1318931eeffaSKenneth D. Merry 1319931eeffaSKenneth D. Merry ifp = sc->xn_ifp; 1320931eeffaSKenneth D. Merry 1321931eeffaSKenneth D. Merry /** 132212678024SDoug Rabson * Defragment the mbuf if necessary. 132312678024SDoug Rabson */ 1324931eeffaSKenneth D. Merry nfrags = xn_count_frags(m_head); 1325931eeffaSKenneth D. Merry 1326931eeffaSKenneth D. Merry /* 1327931eeffaSKenneth D. Merry * Check to see whether this request is longer than netback 1328931eeffaSKenneth D. Merry * can handle, and try to defrag it. 1329931eeffaSKenneth D. Merry */ 1330931eeffaSKenneth D. Merry /** 1331931eeffaSKenneth D. Merry * It is a bit lame, but the netback driver in Linux can't 1332931eeffaSKenneth D. Merry * deal with nfrags > MAX_TX_REQ_FRAGS, which is a quirk of 1333931eeffaSKenneth D. Merry * the Linux network stack. 1334931eeffaSKenneth D. Merry */ 1335578e4bf7SJustin T. Gibbs if (nfrags > sc->maxfrags) { 1336c6499eccSGleb Smirnoff m = m_defrag(m_head, M_NOWAIT); 133712678024SDoug Rabson if (!m) { 1338931eeffaSKenneth D. Merry /* 1339931eeffaSKenneth D. Merry * Defrag failed, so free the mbuf and 1340931eeffaSKenneth D. Merry * therefore drop the packet. 1341931eeffaSKenneth D. Merry */ 134212678024SDoug Rabson m_freem(m_head); 1343931eeffaSKenneth D. Merry return (EMSGSIZE); 134412678024SDoug Rabson } 134512678024SDoug Rabson m_head = m; 134612678024SDoug Rabson } 134789e0f4d2SKip Macy 1348a4ec37f5SAdrian Chadd /* Determine how many fragments now exist */ 1349931eeffaSKenneth D. Merry nfrags = xn_count_frags(m_head); 1350a4ec37f5SAdrian Chadd 1351a4ec37f5SAdrian Chadd /* 1352931eeffaSKenneth D. Merry * Check to see whether the defragmented packet has too many 1353931eeffaSKenneth D. Merry * segments for the Linux netback driver. 1354a4ec37f5SAdrian Chadd */ 1355931eeffaSKenneth D. Merry /** 1356931eeffaSKenneth D. Merry * The FreeBSD TCP stack, with TSO enabled, can produce a chain 1357931eeffaSKenneth D. Merry * of mbufs longer than Linux can handle. Make sure we don't 1358931eeffaSKenneth D. Merry * pass a too-long chain over to the other side by dropping the 1359931eeffaSKenneth D. Merry * packet. It doesn't look like there is currently a way to 1360931eeffaSKenneth D. Merry * tell the TCP stack to generate a shorter chain of packets. 13613fb28bbbSAdrian Chadd */ 1362931eeffaSKenneth D. Merry if (nfrags > MAX_TX_REQ_FRAGS) { 1363ff662b5cSJustin T. Gibbs #ifdef DEBUG 1364ff662b5cSJustin T. Gibbs printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback " 1365ff662b5cSJustin T. Gibbs "won't be able to handle it, dropping\n", 1366ff662b5cSJustin T. Gibbs __func__, nfrags, MAX_TX_REQ_FRAGS); 1367ff662b5cSJustin T. Gibbs #endif 1368931eeffaSKenneth D. Merry m_freem(m_head); 1369931eeffaSKenneth D. Merry return (EMSGSIZE); 1370a4ec37f5SAdrian Chadd } 1371a4ec37f5SAdrian Chadd 13723fb28bbbSAdrian Chadd /* 1373931eeffaSKenneth D. Merry * This check should be redundant. We've already verified that we 1374931eeffaSKenneth D. Merry * have enough slots in the ring to handle a packet of maximum 1375931eeffaSKenneth D. Merry * size, and that our packet is less than the maximum size. Keep 1376931eeffaSKenneth D. Merry * it in here as an assert for now just to make certain that 1377931eeffaSKenneth D. Merry * xn_tx_chain_cnt is accurate. 13783fb28bbbSAdrian Chadd */ 1379931eeffaSKenneth D. Merry KASSERT((sc->xn_cdata.xn_tx_chain_cnt + nfrags) <= NET_TX_RING_SIZE, 1380931eeffaSKenneth D. Merry ("%s: xn_tx_chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE " 1381931eeffaSKenneth D. Merry "(%d)!", __func__, (int) sc->xn_cdata.xn_tx_chain_cnt, 1382931eeffaSKenneth D. Merry (int) nfrags, (int) NET_TX_RING_SIZE)); 1383a4ec37f5SAdrian Chadd 138489e0f4d2SKip Macy /* 138589e0f4d2SKip Macy * Start packing the mbufs in this chain into 138689e0f4d2SKip Macy * the fragment pointers. Stop when we run out 138789e0f4d2SKip Macy * of fragments or hit the end of the mbuf chain. 138889e0f4d2SKip Macy */ 138912678024SDoug Rabson m = m_head; 1390931eeffaSKenneth D. Merry otherend_id = xenbus_get_otherend_id(sc->xbdev); 139112678024SDoug Rabson for (m = m_head; m; m = m->m_next) { 1392931eeffaSKenneth D. Merry netif_tx_request_t *tx; 1393931eeffaSKenneth D. Merry uintptr_t id; 1394931eeffaSKenneth D. Merry grant_ref_t ref; 1395931eeffaSKenneth D. Merry u_long mfn; /* XXX Wrong type? */ 1396931eeffaSKenneth D. Merry 1397931eeffaSKenneth D. Merry tx = RING_GET_REQUEST(&sc->tx, sc->tx.req_prod_pvt); 1398931eeffaSKenneth D. Merry id = get_id_from_freelist(sc->tx_mbufs); 1399a4ec37f5SAdrian Chadd if (id == 0) 14006f9767acSMarius Strobl panic("%s: was allocated the freelist head!\n", 14016f9767acSMarius Strobl __func__); 1402a4ec37f5SAdrian Chadd sc->xn_cdata.xn_tx_chain_cnt++; 1403931eeffaSKenneth D. Merry if (sc->xn_cdata.xn_tx_chain_cnt > NET_TX_RING_SIZE) 14046f9767acSMarius Strobl panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n", 14056f9767acSMarius Strobl __func__); 1406931eeffaSKenneth D. Merry sc->tx_mbufs[id] = m; 140789e0f4d2SKip Macy tx->id = id; 140889e0f4d2SKip Macy ref = gnttab_claim_grant_reference(&sc->gref_tx_head); 140989e0f4d2SKip Macy KASSERT((short)ref >= 0, ("Negative ref")); 141012678024SDoug Rabson mfn = virt_to_mfn(mtod(m, vm_offset_t)); 141123dc5621SKip Macy gnttab_grant_foreign_access_ref(ref, otherend_id, 141289e0f4d2SKip Macy mfn, GNTMAP_readonly); 141389e0f4d2SKip Macy tx->gref = sc->grant_tx_ref[id] = ref; 141412678024SDoug Rabson tx->offset = mtod(m, vm_offset_t) & (PAGE_SIZE - 1); 141589e0f4d2SKip Macy tx->flags = 0; 141612678024SDoug Rabson if (m == m_head) { 141712678024SDoug Rabson /* 141812678024SDoug Rabson * The first fragment has the entire packet 141912678024SDoug Rabson * size, subsequent fragments have just the 142012678024SDoug Rabson * fragment size. The backend works out the 142112678024SDoug Rabson * true size of the first fragment by 142212678024SDoug Rabson * subtracting the sizes of the other 142312678024SDoug Rabson * fragments. 142412678024SDoug Rabson */ 142512678024SDoug Rabson tx->size = m->m_pkthdr.len; 142689e0f4d2SKip Macy 142712678024SDoug Rabson /* 1428931eeffaSKenneth D. Merry * The first fragment contains the checksum flags 1429931eeffaSKenneth D. Merry * and is optionally followed by extra data for 1430931eeffaSKenneth D. Merry * TSO etc. 1431931eeffaSKenneth D. Merry */ 1432931eeffaSKenneth D. Merry /** 1433931eeffaSKenneth D. Merry * CSUM_TSO requires checksum offloading. 1434931eeffaSKenneth D. Merry * Some versions of FreeBSD fail to 1435931eeffaSKenneth D. Merry * set CSUM_TCP in the CSUM_TSO case, 1436931eeffaSKenneth D. Merry * so we have to test for CSUM_TSO 1437931eeffaSKenneth D. Merry * explicitly. 143812678024SDoug Rabson */ 143912678024SDoug Rabson if (m->m_pkthdr.csum_flags 1440931eeffaSKenneth D. Merry & (CSUM_DELAY_DATA | CSUM_TSO)) { 144112678024SDoug Rabson tx->flags |= (NETTXF_csum_blank 144212678024SDoug Rabson | NETTXF_data_validated); 144312678024SDoug Rabson } 144412678024SDoug Rabson #if __FreeBSD_version >= 700000 144512678024SDoug Rabson if (m->m_pkthdr.csum_flags & CSUM_TSO) { 144612678024SDoug Rabson struct netif_extra_info *gso = 144712678024SDoug Rabson (struct netif_extra_info *) 1448931eeffaSKenneth D. Merry RING_GET_REQUEST(&sc->tx, 1449931eeffaSKenneth D. Merry ++sc->tx.req_prod_pvt); 145089e0f4d2SKip Macy 145112678024SDoug Rabson tx->flags |= NETTXF_extra_info; 145289e0f4d2SKip Macy 145312678024SDoug Rabson gso->u.gso.size = m->m_pkthdr.tso_segsz; 145412678024SDoug Rabson gso->u.gso.type = 145512678024SDoug Rabson XEN_NETIF_GSO_TYPE_TCPV4; 145612678024SDoug Rabson gso->u.gso.pad = 0; 145712678024SDoug Rabson gso->u.gso.features = 0; 145812678024SDoug Rabson 145912678024SDoug Rabson gso->type = XEN_NETIF_EXTRA_TYPE_GSO; 146012678024SDoug Rabson gso->flags = 0; 146112678024SDoug Rabson } 146212678024SDoug Rabson #endif 146312678024SDoug Rabson } else { 146412678024SDoug Rabson tx->size = m->m_len; 146512678024SDoug Rabson } 1466931eeffaSKenneth D. Merry if (m->m_next) 146712678024SDoug Rabson tx->flags |= NETTXF_more_data; 146812678024SDoug Rabson 1469931eeffaSKenneth D. Merry sc->tx.req_prod_pvt++; 1470931eeffaSKenneth D. Merry } 147112678024SDoug Rabson BPF_MTAP(ifp, m_head); 147212678024SDoug Rabson 147312678024SDoug Rabson sc->stats.tx_bytes += m_head->m_pkthdr.len; 147489e0f4d2SKip Macy sc->stats.tx_packets++; 1475931eeffaSKenneth D. Merry 1476931eeffaSKenneth D. Merry return (0); 147789e0f4d2SKip Macy } 147889e0f4d2SKip Macy 1479931eeffaSKenneth D. Merry static void 1480931eeffaSKenneth D. Merry xn_start_locked(struct ifnet *ifp) 1481931eeffaSKenneth D. Merry { 1482931eeffaSKenneth D. Merry struct netfront_info *sc; 1483931eeffaSKenneth D. Merry struct mbuf *m_head; 1484931eeffaSKenneth D. Merry int notify; 1485931eeffaSKenneth D. Merry 1486931eeffaSKenneth D. Merry sc = ifp->if_softc; 1487931eeffaSKenneth D. Merry 1488931eeffaSKenneth D. Merry if (!netfront_carrier_ok(sc)) 1489931eeffaSKenneth D. Merry return; 1490931eeffaSKenneth D. Merry 1491931eeffaSKenneth D. Merry /* 1492931eeffaSKenneth D. Merry * While we have enough transmit slots available for at least one 1493931eeffaSKenneth D. Merry * maximum-sized packet, pull mbufs off the queue and put them on 1494931eeffaSKenneth D. Merry * the transmit ring. 1495931eeffaSKenneth D. Merry */ 1496931eeffaSKenneth D. Merry while (xn_tx_slot_available(sc)) { 1497931eeffaSKenneth D. Merry IF_DEQUEUE(&ifp->if_snd, m_head); 1498931eeffaSKenneth D. Merry if (m_head == NULL) 1499931eeffaSKenneth D. Merry break; 1500931eeffaSKenneth D. Merry 1501931eeffaSKenneth D. Merry if (xn_assemble_tx_request(sc, m_head) != 0) 1502931eeffaSKenneth D. Merry break; 1503931eeffaSKenneth D. Merry } 1504931eeffaSKenneth D. Merry 150589e0f4d2SKip Macy RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->tx, notify); 150689e0f4d2SKip Macy if (notify) 150776acc41fSJustin T. Gibbs xen_intr_signal(sc->xen_intr_handle); 150889e0f4d2SKip Macy 150989e0f4d2SKip Macy if (RING_FULL(&sc->tx)) { 151089e0f4d2SKip Macy sc->tx_full = 1; 151189e0f4d2SKip Macy #if 0 151289e0f4d2SKip Macy netif_stop_queue(dev); 151389e0f4d2SKip Macy #endif 151489e0f4d2SKip Macy } 151589e0f4d2SKip Macy } 151689e0f4d2SKip Macy 151789e0f4d2SKip Macy static void 151889e0f4d2SKip Macy xn_start(struct ifnet *ifp) 151989e0f4d2SKip Macy { 152089e0f4d2SKip Macy struct netfront_info *sc; 152189e0f4d2SKip Macy sc = ifp->if_softc; 152289e0f4d2SKip Macy XN_TX_LOCK(sc); 152389e0f4d2SKip Macy xn_start_locked(ifp); 152489e0f4d2SKip Macy XN_TX_UNLOCK(sc); 152589e0f4d2SKip Macy } 152689e0f4d2SKip Macy 152789e0f4d2SKip Macy /* equivalent of network_open() in Linux */ 152889e0f4d2SKip Macy static void 152989e0f4d2SKip Macy xn_ifinit_locked(struct netfront_info *sc) 153089e0f4d2SKip Macy { 153189e0f4d2SKip Macy struct ifnet *ifp; 153289e0f4d2SKip Macy 153389e0f4d2SKip Macy XN_LOCK_ASSERT(sc); 153489e0f4d2SKip Macy 153589e0f4d2SKip Macy ifp = sc->xn_ifp; 153689e0f4d2SKip Macy 153789e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) 153889e0f4d2SKip Macy return; 153989e0f4d2SKip Macy 154089e0f4d2SKip Macy xn_stop(sc); 154189e0f4d2SKip Macy 154289e0f4d2SKip Macy network_alloc_rx_buffers(sc); 154389e0f4d2SKip Macy sc->rx.sring->rsp_event = sc->rx.rsp_cons + 1; 154489e0f4d2SKip Macy 154589e0f4d2SKip Macy ifp->if_drv_flags |= IFF_DRV_RUNNING; 154689e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 15470e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_UP); 154889e0f4d2SKip Macy 154989e0f4d2SKip Macy callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); 155089e0f4d2SKip Macy } 155189e0f4d2SKip Macy 155289e0f4d2SKip Macy static void 155389e0f4d2SKip Macy xn_ifinit(void *xsc) 155489e0f4d2SKip Macy { 155589e0f4d2SKip Macy struct netfront_info *sc = xsc; 155689e0f4d2SKip Macy 155789e0f4d2SKip Macy XN_LOCK(sc); 155889e0f4d2SKip Macy xn_ifinit_locked(sc); 155989e0f4d2SKip Macy XN_UNLOCK(sc); 156089e0f4d2SKip Macy } 156189e0f4d2SKip Macy 156289e0f4d2SKip Macy static int 156389e0f4d2SKip Macy xn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 156489e0f4d2SKip Macy { 156589e0f4d2SKip Macy struct netfront_info *sc = ifp->if_softc; 156689e0f4d2SKip Macy struct ifreq *ifr = (struct ifreq *) data; 1567a0ae8f04SBjoern A. Zeeb #ifdef INET 156889e0f4d2SKip Macy struct ifaddr *ifa = (struct ifaddr *)data; 1569a0ae8f04SBjoern A. Zeeb #endif 157089e0f4d2SKip Macy 157189e0f4d2SKip Macy int mask, error = 0; 157289e0f4d2SKip Macy switch(cmd) { 157389e0f4d2SKip Macy case SIOCSIFADDR: 1574a0ae8f04SBjoern A. Zeeb #ifdef INET 157589e0f4d2SKip Macy XN_LOCK(sc); 157689e0f4d2SKip Macy if (ifa->ifa_addr->sa_family == AF_INET) { 157789e0f4d2SKip Macy ifp->if_flags |= IFF_UP; 157889e0f4d2SKip Macy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 157989e0f4d2SKip Macy xn_ifinit_locked(sc); 158089e0f4d2SKip Macy arp_ifinit(ifp, ifa); 158189e0f4d2SKip Macy XN_UNLOCK(sc); 158249906218SDoug Rabson } else { 158349906218SDoug Rabson XN_UNLOCK(sc); 1584a0ae8f04SBjoern A. Zeeb #endif 158549906218SDoug Rabson error = ether_ioctl(ifp, cmd, data); 1586a0ae8f04SBjoern A. Zeeb #ifdef INET 158749906218SDoug Rabson } 1588a0ae8f04SBjoern A. Zeeb #endif 158989e0f4d2SKip Macy break; 159089e0f4d2SKip Macy case SIOCSIFMTU: 159189e0f4d2SKip Macy /* XXX can we alter the MTU on a VN ?*/ 159289e0f4d2SKip Macy #ifdef notyet 159389e0f4d2SKip Macy if (ifr->ifr_mtu > XN_JUMBO_MTU) 159489e0f4d2SKip Macy error = EINVAL; 159589e0f4d2SKip Macy else 159689e0f4d2SKip Macy #endif 159789e0f4d2SKip Macy { 159889e0f4d2SKip Macy ifp->if_mtu = ifr->ifr_mtu; 159989e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 160089e0f4d2SKip Macy xn_ifinit(sc); 160189e0f4d2SKip Macy } 160289e0f4d2SKip Macy break; 160389e0f4d2SKip Macy case SIOCSIFFLAGS: 160489e0f4d2SKip Macy XN_LOCK(sc); 160589e0f4d2SKip Macy if (ifp->if_flags & IFF_UP) { 160689e0f4d2SKip Macy /* 160789e0f4d2SKip Macy * If only the state of the PROMISC flag changed, 160889e0f4d2SKip Macy * then just use the 'set promisc mode' command 160989e0f4d2SKip Macy * instead of reinitializing the entire NIC. Doing 161089e0f4d2SKip Macy * a full re-init means reloading the firmware and 161189e0f4d2SKip Macy * waiting for it to start up, which may take a 161289e0f4d2SKip Macy * second or two. 161389e0f4d2SKip Macy */ 161489e0f4d2SKip Macy #ifdef notyet 161589e0f4d2SKip Macy /* No promiscuous mode with Xen */ 161689e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING && 161789e0f4d2SKip Macy ifp->if_flags & IFF_PROMISC && 161889e0f4d2SKip Macy !(sc->xn_if_flags & IFF_PROMISC)) { 161989e0f4d2SKip Macy XN_SETBIT(sc, XN_RX_MODE, 162089e0f4d2SKip Macy XN_RXMODE_RX_PROMISC); 162189e0f4d2SKip Macy } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 162289e0f4d2SKip Macy !(ifp->if_flags & IFF_PROMISC) && 162389e0f4d2SKip Macy sc->xn_if_flags & IFF_PROMISC) { 162489e0f4d2SKip Macy XN_CLRBIT(sc, XN_RX_MODE, 162589e0f4d2SKip Macy XN_RXMODE_RX_PROMISC); 162689e0f4d2SKip Macy } else 162789e0f4d2SKip Macy #endif 162889e0f4d2SKip Macy xn_ifinit_locked(sc); 162989e0f4d2SKip Macy } else { 163089e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 163189e0f4d2SKip Macy xn_stop(sc); 163289e0f4d2SKip Macy } 163389e0f4d2SKip Macy } 163489e0f4d2SKip Macy sc->xn_if_flags = ifp->if_flags; 163589e0f4d2SKip Macy XN_UNLOCK(sc); 163689e0f4d2SKip Macy error = 0; 163789e0f4d2SKip Macy break; 163889e0f4d2SKip Macy case SIOCSIFCAP: 163989e0f4d2SKip Macy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 164012678024SDoug Rabson if (mask & IFCAP_TXCSUM) { 164112678024SDoug Rabson if (IFCAP_TXCSUM & ifp->if_capenable) { 164212678024SDoug Rabson ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 164312678024SDoug Rabson ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 164412678024SDoug Rabson | CSUM_IP | CSUM_TSO); 164512678024SDoug Rabson } else { 164612678024SDoug Rabson ifp->if_capenable |= IFCAP_TXCSUM; 164712678024SDoug Rabson ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP 164812678024SDoug Rabson | CSUM_IP); 164989e0f4d2SKip Macy } 165012678024SDoug Rabson } 165112678024SDoug Rabson if (mask & IFCAP_RXCSUM) { 165212678024SDoug Rabson ifp->if_capenable ^= IFCAP_RXCSUM; 165312678024SDoug Rabson } 165412678024SDoug Rabson #if __FreeBSD_version >= 700000 165512678024SDoug Rabson if (mask & IFCAP_TSO4) { 165612678024SDoug Rabson if (IFCAP_TSO4 & ifp->if_capenable) { 165712678024SDoug Rabson ifp->if_capenable &= ~IFCAP_TSO4; 165812678024SDoug Rabson ifp->if_hwassist &= ~CSUM_TSO; 165912678024SDoug Rabson } else if (IFCAP_TXCSUM & ifp->if_capenable) { 166012678024SDoug Rabson ifp->if_capenable |= IFCAP_TSO4; 166112678024SDoug Rabson ifp->if_hwassist |= CSUM_TSO; 166212678024SDoug Rabson } else { 16633552092bSAdrian Chadd IPRINTK("Xen requires tx checksum offload" 166412678024SDoug Rabson " be enabled to use TSO\n"); 166512678024SDoug Rabson error = EINVAL; 166612678024SDoug Rabson } 166712678024SDoug Rabson } 166812678024SDoug Rabson if (mask & IFCAP_LRO) { 166912678024SDoug Rabson ifp->if_capenable ^= IFCAP_LRO; 167012678024SDoug Rabson 167112678024SDoug Rabson } 167212678024SDoug Rabson #endif 167389e0f4d2SKip Macy error = 0; 167489e0f4d2SKip Macy break; 167589e0f4d2SKip Macy case SIOCADDMULTI: 167689e0f4d2SKip Macy case SIOCDELMULTI: 167789e0f4d2SKip Macy #ifdef notyet 167889e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 167989e0f4d2SKip Macy XN_LOCK(sc); 168089e0f4d2SKip Macy xn_setmulti(sc); 168189e0f4d2SKip Macy XN_UNLOCK(sc); 168289e0f4d2SKip Macy error = 0; 168389e0f4d2SKip Macy } 168489e0f4d2SKip Macy #endif 168589e0f4d2SKip Macy /* FALLTHROUGH */ 168689e0f4d2SKip Macy case SIOCSIFMEDIA: 168789e0f4d2SKip Macy case SIOCGIFMEDIA: 16880e509842SJustin T. Gibbs error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 168989e0f4d2SKip Macy break; 169089e0f4d2SKip Macy default: 169189e0f4d2SKip Macy error = ether_ioctl(ifp, cmd, data); 169289e0f4d2SKip Macy } 169389e0f4d2SKip Macy 169489e0f4d2SKip Macy return (error); 169589e0f4d2SKip Macy } 169689e0f4d2SKip Macy 169789e0f4d2SKip Macy static void 169889e0f4d2SKip Macy xn_stop(struct netfront_info *sc) 169989e0f4d2SKip Macy { 170089e0f4d2SKip Macy struct ifnet *ifp; 170189e0f4d2SKip Macy 170289e0f4d2SKip Macy XN_LOCK_ASSERT(sc); 170389e0f4d2SKip Macy 170489e0f4d2SKip Macy ifp = sc->xn_ifp; 170589e0f4d2SKip Macy 170689e0f4d2SKip Macy callout_stop(&sc->xn_stat_ch); 170789e0f4d2SKip Macy 170889e0f4d2SKip Macy xn_free_rx_ring(sc); 170989e0f4d2SKip Macy xn_free_tx_ring(sc); 171089e0f4d2SKip Macy 171189e0f4d2SKip Macy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 17120e509842SJustin T. Gibbs if_link_state_change(ifp, LINK_STATE_DOWN); 171389e0f4d2SKip Macy } 171489e0f4d2SKip Macy 171589e0f4d2SKip Macy /* START of Xenolinux helper functions adapted to FreeBSD */ 171623dc5621SKip Macy int 171723dc5621SKip Macy network_connect(struct netfront_info *np) 171889e0f4d2SKip Macy { 17193a6d1fcfSKip Macy int i, requeue_idx, error; 172089e0f4d2SKip Macy grant_ref_t ref; 172189e0f4d2SKip Macy netif_rx_request_t *req; 1722d0f3a8b9SRoger Pau Monné u_int feature_rx_copy; 172389e0f4d2SKip Macy 1724ff662b5cSJustin T. Gibbs error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 17253a6d1fcfSKip Macy "feature-rx-copy", NULL, "%u", &feature_rx_copy); 17263a6d1fcfSKip Macy if (error) 172789e0f4d2SKip Macy feature_rx_copy = 0; 172889e0f4d2SKip Macy 1729d0f3a8b9SRoger Pau Monné /* We only support rx copy. */ 1730d0f3a8b9SRoger Pau Monné if (!feature_rx_copy) 1731d0f3a8b9SRoger Pau Monné return (EPROTONOSUPPORT); 173289e0f4d2SKip Macy 173389e0f4d2SKip Macy /* Recovery procedure: */ 17343a6d1fcfSKip Macy error = talk_to_backend(np->xbdev, np); 17353a6d1fcfSKip Macy if (error) 17363a6d1fcfSKip Macy return (error); 173789e0f4d2SKip Macy 173889e0f4d2SKip Macy /* Step 1: Reinitialise variables. */ 1739578e4bf7SJustin T. Gibbs xn_query_features(np); 1740578e4bf7SJustin T. Gibbs xn_configure_features(np); 174189e0f4d2SKip Macy netif_release_tx_bufs(np); 174289e0f4d2SKip Macy 174389e0f4d2SKip Macy /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ 174489e0f4d2SKip Macy for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { 174589e0f4d2SKip Macy struct mbuf *m; 17463a6d1fcfSKip Macy u_long pfn; 174789e0f4d2SKip Macy 174889e0f4d2SKip Macy if (np->rx_mbufs[i] == NULL) 174989e0f4d2SKip Macy continue; 175089e0f4d2SKip Macy 175189e0f4d2SKip Macy m = np->rx_mbufs[requeue_idx] = xennet_get_rx_mbuf(np, i); 175289e0f4d2SKip Macy ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i); 1753931eeffaSKenneth D. Merry 175489e0f4d2SKip Macy req = RING_GET_REQUEST(&np->rx, requeue_idx); 17553a6d1fcfSKip Macy pfn = vtophys(mtod(m, vm_offset_t)) >> PAGE_SHIFT; 175689e0f4d2SKip Macy 175789e0f4d2SKip Macy gnttab_grant_foreign_access_ref(ref, 175823dc5621SKip Macy xenbus_get_otherend_id(np->xbdev), 1759ed95805eSJohn Baldwin pfn, 0); 1760d0f3a8b9SRoger Pau Monné 176189e0f4d2SKip Macy req->gref = ref; 176289e0f4d2SKip Macy req->id = requeue_idx; 176389e0f4d2SKip Macy 176489e0f4d2SKip Macy requeue_idx++; 176589e0f4d2SKip Macy } 176689e0f4d2SKip Macy 176789e0f4d2SKip Macy np->rx.req_prod_pvt = requeue_idx; 176889e0f4d2SKip Macy 176989e0f4d2SKip Macy /* Step 3: All public and private state should now be sane. Get 177089e0f4d2SKip Macy * ready to start sending and receiving packets and give the driver 177189e0f4d2SKip Macy * domain a kick because we've probably just requeued some 177289e0f4d2SKip Macy * packets. 177389e0f4d2SKip Macy */ 177489e0f4d2SKip Macy netfront_carrier_on(np); 177576acc41fSJustin T. Gibbs xen_intr_signal(np->xen_intr_handle); 177689e0f4d2SKip Macy XN_TX_LOCK(np); 177789e0f4d2SKip Macy xn_txeof(np); 177889e0f4d2SKip Macy XN_TX_UNLOCK(np); 177989e0f4d2SKip Macy network_alloc_rx_buffers(np); 178089e0f4d2SKip Macy 178189e0f4d2SKip Macy return (0); 178289e0f4d2SKip Macy } 178389e0f4d2SKip Macy 178489e0f4d2SKip Macy static void 1785578e4bf7SJustin T. Gibbs xn_query_features(struct netfront_info *np) 1786578e4bf7SJustin T. Gibbs { 1787578e4bf7SJustin T. Gibbs int val; 1788578e4bf7SJustin T. Gibbs 1789578e4bf7SJustin T. Gibbs device_printf(np->xbdev, "backend features:"); 1790578e4bf7SJustin T. Gibbs 1791578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 1792578e4bf7SJustin T. Gibbs "feature-sg", NULL, "%d", &val) < 0) 1793578e4bf7SJustin T. Gibbs val = 0; 1794578e4bf7SJustin T. Gibbs 1795578e4bf7SJustin T. Gibbs np->maxfrags = 1; 1796578e4bf7SJustin T. Gibbs if (val) { 1797578e4bf7SJustin T. Gibbs np->maxfrags = MAX_TX_REQ_FRAGS; 1798578e4bf7SJustin T. Gibbs printf(" feature-sg"); 1799578e4bf7SJustin T. Gibbs } 1800578e4bf7SJustin T. Gibbs 1801578e4bf7SJustin T. Gibbs if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), 1802578e4bf7SJustin T. Gibbs "feature-gso-tcpv4", NULL, "%d", &val) < 0) 1803578e4bf7SJustin T. Gibbs val = 0; 1804578e4bf7SJustin T. Gibbs 1805578e4bf7SJustin T. Gibbs np->xn_ifp->if_capabilities &= ~(IFCAP_TSO4|IFCAP_LRO); 1806578e4bf7SJustin T. Gibbs if (val) { 1807578e4bf7SJustin T. Gibbs np->xn_ifp->if_capabilities |= IFCAP_TSO4|IFCAP_LRO; 1808578e4bf7SJustin T. Gibbs printf(" feature-gso-tcp4"); 1809578e4bf7SJustin T. Gibbs } 1810578e4bf7SJustin T. Gibbs 1811578e4bf7SJustin T. Gibbs printf("\n"); 1812578e4bf7SJustin T. Gibbs } 1813578e4bf7SJustin T. Gibbs 1814cf9c09e1SJustin T. Gibbs static int 1815578e4bf7SJustin T. Gibbs xn_configure_features(struct netfront_info *np) 1816cf9c09e1SJustin T. Gibbs { 18176a8e9695SRoger Pau Monné int err, cap_enabled; 1818cf9c09e1SJustin T. Gibbs 1819cf9c09e1SJustin T. Gibbs err = 0; 18206a8e9695SRoger Pau Monné 18216a8e9695SRoger Pau Monné if (np->xn_resume && 18226a8e9695SRoger Pau Monné ((np->xn_ifp->if_capenable & np->xn_ifp->if_capabilities) 18236a8e9695SRoger Pau Monné == np->xn_ifp->if_capenable)) { 18246a8e9695SRoger Pau Monné /* Current options are available, no need to do anything. */ 18256a8e9695SRoger Pau Monné return (0); 18266a8e9695SRoger Pau Monné } 18276a8e9695SRoger Pau Monné 18286a8e9695SRoger Pau Monné /* Try to preserve as many options as possible. */ 18296a8e9695SRoger Pau Monné if (np->xn_resume) 18306a8e9695SRoger Pau Monné cap_enabled = np->xn_ifp->if_capenable; 18316a8e9695SRoger Pau Monné else 18326a8e9695SRoger Pau Monné cap_enabled = UINT_MAX; 18336a8e9695SRoger Pau Monné 1834c6b15dd5SGleb Smirnoff #if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 18356a8e9695SRoger Pau Monné if ((np->xn_ifp->if_capenable & IFCAP_LRO) == (cap_enabled & IFCAP_LRO)) 1836cf9c09e1SJustin T. Gibbs tcp_lro_free(&np->xn_lro); 1837578e4bf7SJustin T. Gibbs #endif 1838578e4bf7SJustin T. Gibbs np->xn_ifp->if_capenable = 18396a8e9695SRoger Pau Monné np->xn_ifp->if_capabilities & ~(IFCAP_LRO|IFCAP_TSO4) & cap_enabled; 1840578e4bf7SJustin T. Gibbs np->xn_ifp->if_hwassist &= ~CSUM_TSO; 1841f909bbb4SGleb Smirnoff #if __FreeBSD_version >= 700000 && (defined(INET) || defined(INET6)) 18426a8e9695SRoger Pau Monné if (xn_enable_lro && (np->xn_ifp->if_capabilities & IFCAP_LRO) == 18436a8e9695SRoger Pau Monné (cap_enabled & IFCAP_LRO)) { 1844cf9c09e1SJustin T. Gibbs err = tcp_lro_init(&np->xn_lro); 1845cf9c09e1SJustin T. Gibbs if (err) { 1846cf9c09e1SJustin T. Gibbs device_printf(np->xbdev, "LRO initialization failed\n"); 1847cf9c09e1SJustin T. Gibbs } else { 1848cf9c09e1SJustin T. Gibbs np->xn_lro.ifp = np->xn_ifp; 1849578e4bf7SJustin T. Gibbs np->xn_ifp->if_capenable |= IFCAP_LRO; 1850cf9c09e1SJustin T. Gibbs } 1851cf9c09e1SJustin T. Gibbs } 18526a8e9695SRoger Pau Monné if ((np->xn_ifp->if_capabilities & IFCAP_TSO4) == 18536a8e9695SRoger Pau Monné (cap_enabled & IFCAP_TSO4)) { 1854578e4bf7SJustin T. Gibbs np->xn_ifp->if_capenable |= IFCAP_TSO4; 1855578e4bf7SJustin T. Gibbs np->xn_ifp->if_hwassist |= CSUM_TSO; 1856578e4bf7SJustin T. Gibbs } 1857cf9c09e1SJustin T. Gibbs #endif 1858cf9c09e1SJustin T. Gibbs return (err); 1859cf9c09e1SJustin T. Gibbs } 1860cf9c09e1SJustin T. Gibbs 186176acc41fSJustin T. Gibbs /** 186276acc41fSJustin T. Gibbs * Create a network device. 186376acc41fSJustin T. Gibbs * @param dev Newbus device representing this virtual NIC. 186489e0f4d2SKip Macy */ 186523dc5621SKip Macy int 186623dc5621SKip Macy create_netdev(device_t dev) 186789e0f4d2SKip Macy { 186889e0f4d2SKip Macy int i; 186989e0f4d2SKip Macy struct netfront_info *np; 187089e0f4d2SKip Macy int err; 187189e0f4d2SKip Macy struct ifnet *ifp; 187289e0f4d2SKip Macy 187323dc5621SKip Macy np = device_get_softc(dev); 187489e0f4d2SKip Macy 187589e0f4d2SKip Macy np->xbdev = dev; 187689e0f4d2SKip Macy 1877*177e3f13SRoger Pau Monné mtx_init(&np->tx_lock, "xntx", "network transmit lock", MTX_DEF); 1878*177e3f13SRoger Pau Monné mtx_init(&np->rx_lock, "xnrx", "network receive lock", MTX_DEF); 1879*177e3f13SRoger Pau Monné mtx_init(&np->sc_lock, "xnsc", "netfront softc lock", MTX_DEF); 18800e509842SJustin T. Gibbs 18810e509842SJustin T. Gibbs ifmedia_init(&np->sc_media, 0, xn_ifmedia_upd, xn_ifmedia_sts); 18820e509842SJustin T. Gibbs ifmedia_add(&np->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 18830e509842SJustin T. Gibbs ifmedia_set(&np->sc_media, IFM_ETHER|IFM_MANUAL); 18840e509842SJustin T. Gibbs 188589e0f4d2SKip Macy np->rx_target = RX_MIN_TARGET; 188689e0f4d2SKip Macy np->rx_min_target = RX_MIN_TARGET; 188789e0f4d2SKip Macy np->rx_max_target = RX_MAX_TARGET; 188889e0f4d2SKip Macy 188989e0f4d2SKip Macy /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ 189089e0f4d2SKip Macy for (i = 0; i <= NET_TX_RING_SIZE; i++) { 189189e0f4d2SKip Macy np->tx_mbufs[i] = (void *) ((u_long) i+1); 1892ff662b5cSJustin T. Gibbs np->grant_tx_ref[i] = GRANT_REF_INVALID; 189389e0f4d2SKip Macy } 1894931eeffaSKenneth D. Merry np->tx_mbufs[NET_TX_RING_SIZE] = (void *)0; 1895931eeffaSKenneth D. Merry 189689e0f4d2SKip Macy for (i = 0; i <= NET_RX_RING_SIZE; i++) { 1897931eeffaSKenneth D. Merry 189889e0f4d2SKip Macy np->rx_mbufs[i] = NULL; 1899ff662b5cSJustin T. Gibbs np->grant_rx_ref[i] = GRANT_REF_INVALID; 190089e0f4d2SKip Macy } 190149e6be9cSGleb Smirnoff 190249e6be9cSGleb Smirnoff mbufq_init(&np->xn_rx_batch, INT_MAX); 190349e6be9cSGleb Smirnoff 190489e0f4d2SKip Macy /* A grant for every tx ring slot */ 1905931eeffaSKenneth D. Merry if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, 1906931eeffaSKenneth D. Merry &np->gref_tx_head) != 0) { 1907227ca257SKip Macy IPRINTK("#### netfront can't alloc tx grant refs\n"); 190889e0f4d2SKip Macy err = ENOMEM; 190989e0f4d2SKip Macy goto exit; 191089e0f4d2SKip Macy } 191189e0f4d2SKip Macy /* A grant for every rx ring slot */ 191289e0f4d2SKip Macy if (gnttab_alloc_grant_references(RX_MAX_TARGET, 1913931eeffaSKenneth D. Merry &np->gref_rx_head) != 0) { 1914227ca257SKip Macy WPRINTK("#### netfront can't alloc rx grant refs\n"); 191589e0f4d2SKip Macy gnttab_free_grant_references(np->gref_tx_head); 191689e0f4d2SKip Macy err = ENOMEM; 191789e0f4d2SKip Macy goto exit; 191889e0f4d2SKip Macy } 191989e0f4d2SKip Macy 192089e0f4d2SKip Macy err = xen_net_read_mac(dev, np->mac); 1921ffa06904SJustin T. Gibbs if (err) 192289e0f4d2SKip Macy goto out; 192389e0f4d2SKip Macy 192489e0f4d2SKip Macy /* Set up ifnet structure */ 192523dc5621SKip Macy ifp = np->xn_ifp = if_alloc(IFT_ETHER); 192689e0f4d2SKip Macy ifp->if_softc = np; 192723dc5621SKip Macy if_initname(ifp, "xn", device_get_unit(dev)); 19283a6d1fcfSKip Macy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 192989e0f4d2SKip Macy ifp->if_ioctl = xn_ioctl; 193089e0f4d2SKip Macy ifp->if_output = ether_output; 193189e0f4d2SKip Macy ifp->if_start = xn_start; 1932227ca257SKip Macy #ifdef notyet 1933227ca257SKip Macy ifp->if_watchdog = xn_watchdog; 1934227ca257SKip Macy #endif 193589e0f4d2SKip Macy ifp->if_init = xn_ifinit; 193689e0f4d2SKip Macy ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1; 193789e0f4d2SKip Macy 193889e0f4d2SKip Macy ifp->if_hwassist = XN_CSUM_FEATURES; 193989e0f4d2SKip Macy ifp->if_capabilities = IFCAP_HWCSUM; 19409fd573c3SHans Petter Selasky ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 19419fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegcount = MAX_TX_REQ_FRAGS; 19429fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegsize = PAGE_SIZE; 194389e0f4d2SKip Macy 194489e0f4d2SKip Macy ether_ifattach(ifp, np->mac); 1945fd90e2edSJung-uk Kim callout_init(&np->xn_stat_ch, 1); 194689e0f4d2SKip Macy netfront_carrier_off(np); 194789e0f4d2SKip Macy 194889e0f4d2SKip Macy return (0); 194989e0f4d2SKip Macy 195089e0f4d2SKip Macy exit: 195189e0f4d2SKip Macy gnttab_free_grant_references(np->gref_tx_head); 195289e0f4d2SKip Macy out: 1953ffa06904SJustin T. Gibbs return (err); 195489e0f4d2SKip Macy } 195589e0f4d2SKip Macy 195689e0f4d2SKip Macy /** 195789e0f4d2SKip Macy * Handle the change of state of the backend to Closing. We must delete our 195889e0f4d2SKip Macy * device-layer structures now, to ensure that writes are flushed through to 195989e0f4d2SKip Macy * the backend. Once is this done, we can switch to Closed in 196089e0f4d2SKip Macy * acknowledgement. 196189e0f4d2SKip Macy */ 196289e0f4d2SKip Macy #if 0 19630e509842SJustin T. Gibbs static void 19640e509842SJustin T. Gibbs netfront_closing(device_t dev) 196589e0f4d2SKip Macy { 196689e0f4d2SKip Macy #if 0 196789e0f4d2SKip Macy struct netfront_info *info = dev->dev_driver_data; 196889e0f4d2SKip Macy 196989e0f4d2SKip Macy DPRINTK("netfront_closing: %s removed\n", dev->nodename); 197089e0f4d2SKip Macy 197189e0f4d2SKip Macy close_netdev(info); 197289e0f4d2SKip Macy #endif 197389e0f4d2SKip Macy xenbus_switch_state(dev, XenbusStateClosed); 197489e0f4d2SKip Macy } 197589e0f4d2SKip Macy #endif 197689e0f4d2SKip Macy 19770e509842SJustin T. Gibbs static int 19780e509842SJustin T. Gibbs netfront_detach(device_t dev) 197989e0f4d2SKip Macy { 198023dc5621SKip Macy struct netfront_info *info = device_get_softc(dev); 198189e0f4d2SKip Macy 198223dc5621SKip Macy DPRINTK("%s\n", xenbus_get_node(dev)); 198389e0f4d2SKip Macy 198489e0f4d2SKip Macy netif_free(info); 198589e0f4d2SKip Macy 198689e0f4d2SKip Macy return 0; 198789e0f4d2SKip Macy } 198889e0f4d2SKip Macy 19890e509842SJustin T. Gibbs static void 19900e509842SJustin T. Gibbs netif_free(struct netfront_info *info) 199189e0f4d2SKip Macy { 1992818fe953SJustin T. Gibbs XN_LOCK(info); 1993818fe953SJustin T. Gibbs xn_stop(info); 1994818fe953SJustin T. Gibbs XN_UNLOCK(info); 1995818fe953SJustin T. Gibbs callout_drain(&info->xn_stat_ch); 199689e0f4d2SKip Macy netif_disconnect_backend(info); 1997e3242f9dSJustin T. Gibbs if (info->xn_ifp != NULL) { 1998818fe953SJustin T. Gibbs ether_ifdetach(info->xn_ifp); 1999818fe953SJustin T. Gibbs if_free(info->xn_ifp); 2000e3242f9dSJustin T. Gibbs info->xn_ifp = NULL; 2001e3242f9dSJustin T. Gibbs } 2002d5aeb779SJustin T. Gibbs ifmedia_removeall(&info->sc_media); 200389e0f4d2SKip Macy } 200489e0f4d2SKip Macy 20050e509842SJustin T. Gibbs static void 20060e509842SJustin T. Gibbs netif_disconnect_backend(struct netfront_info *info) 200789e0f4d2SKip Macy { 20083a6d1fcfSKip Macy XN_RX_LOCK(info); 20093a6d1fcfSKip Macy XN_TX_LOCK(info); 20103a6d1fcfSKip Macy netfront_carrier_off(info); 20113a6d1fcfSKip Macy XN_TX_UNLOCK(info); 20123a6d1fcfSKip Macy XN_RX_UNLOCK(info); 20133a6d1fcfSKip Macy 2014cf9c09e1SJustin T. Gibbs free_ring(&info->tx_ring_ref, &info->tx.sring); 2015cf9c09e1SJustin T. Gibbs free_ring(&info->rx_ring_ref, &info->rx.sring); 201689e0f4d2SKip Macy 201776acc41fSJustin T. Gibbs xen_intr_unbind(&info->xen_intr_handle); 201889e0f4d2SKip Macy } 201989e0f4d2SKip Macy 20200e509842SJustin T. Gibbs static void 2021cf9c09e1SJustin T. Gibbs free_ring(int *ref, void *ring_ptr_ref) 202289e0f4d2SKip Macy { 2023cf9c09e1SJustin T. Gibbs void **ring_ptr_ptr = ring_ptr_ref; 2024cf9c09e1SJustin T. Gibbs 2025cf9c09e1SJustin T. Gibbs if (*ref != GRANT_REF_INVALID) { 2026cf9c09e1SJustin T. Gibbs /* This API frees the associated storage. */ 2027cf9c09e1SJustin T. Gibbs gnttab_end_foreign_access(*ref, *ring_ptr_ptr); 2028cf9c09e1SJustin T. Gibbs *ref = GRANT_REF_INVALID; 2029cf9c09e1SJustin T. Gibbs } 2030cf9c09e1SJustin T. Gibbs *ring_ptr_ptr = NULL; 203189e0f4d2SKip Macy } 203289e0f4d2SKip Macy 20330e509842SJustin T. Gibbs static int 20340e509842SJustin T. Gibbs xn_ifmedia_upd(struct ifnet *ifp) 20350e509842SJustin T. Gibbs { 20360e509842SJustin T. Gibbs return (0); 20370e509842SJustin T. Gibbs } 20380e509842SJustin T. Gibbs 20390e509842SJustin T. Gibbs static void 20400e509842SJustin T. Gibbs xn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 20410e509842SJustin T. Gibbs { 20420e509842SJustin T. Gibbs ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE; 20430e509842SJustin T. Gibbs ifmr->ifm_active = IFM_ETHER|IFM_MANUAL; 20440e509842SJustin T. Gibbs } 20450e509842SJustin T. Gibbs 204689e0f4d2SKip Macy /* ** Driver registration ** */ 204723dc5621SKip Macy static device_method_t netfront_methods[] = { 204823dc5621SKip Macy /* Device interface */ 204923dc5621SKip Macy DEVMETHOD(device_probe, netfront_probe), 205023dc5621SKip Macy DEVMETHOD(device_attach, netfront_attach), 205123dc5621SKip Macy DEVMETHOD(device_detach, netfront_detach), 205223dc5621SKip Macy DEVMETHOD(device_shutdown, bus_generic_shutdown), 2053cf9c09e1SJustin T. Gibbs DEVMETHOD(device_suspend, netfront_suspend), 205423dc5621SKip Macy DEVMETHOD(device_resume, netfront_resume), 205589e0f4d2SKip Macy 205623dc5621SKip Macy /* Xenbus interface */ 2057ff662b5cSJustin T. Gibbs DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed), 205889e0f4d2SKip Macy 20596f9767acSMarius Strobl DEVMETHOD_END 206089e0f4d2SKip Macy }; 206189e0f4d2SKip Macy 206223dc5621SKip Macy static driver_t netfront_driver = { 206323dc5621SKip Macy "xn", 206423dc5621SKip Macy netfront_methods, 206523dc5621SKip Macy sizeof(struct netfront_info), 206689e0f4d2SKip Macy }; 206723dc5621SKip Macy devclass_t netfront_devclass; 206889e0f4d2SKip Macy 20696f9767acSMarius Strobl DRIVER_MODULE(xe, xenbusb_front, netfront_driver, netfront_devclass, NULL, 20706f9767acSMarius Strobl NULL); 2071