18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Back-end of the driver for virtual network devices. This portion of the 38c2ecf20Sopenharmony_ci * driver exports a 'unified' network-device interface that can be accessed 48c2ecf20Sopenharmony_ci * by any operating system that implements a compatible front end. A 58c2ecf20Sopenharmony_ci * reference front-end implementation can be found in: 68c2ecf20Sopenharmony_ci * drivers/net/xen-netfront.c 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (c) 2002-2005, K A Fraser 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 118c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2 128c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; or, when distributed 138c2ecf20Sopenharmony_ci * separately from the Linux kernel or incorporated into other 148c2ecf20Sopenharmony_ci * software packages, subject to the following license: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 178c2ecf20Sopenharmony_ci * of this source file (the "Software"), to deal in the Software without 188c2ecf20Sopenharmony_ci * restriction, including without limitation the rights to use, copy, modify, 198c2ecf20Sopenharmony_ci * merge, publish, distribute, sublicense, and/or sell copies of the Software, 208c2ecf20Sopenharmony_ci * and to permit persons to whom the Software is furnished to do so, subject to 218c2ecf20Sopenharmony_ci * the following conditions: 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 248c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 278c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 288c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 298c2ecf20Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 308c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 318c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 328c2ecf20Sopenharmony_ci * IN THE SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "common.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/kthread.h> 388c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 398c2ecf20Sopenharmony_ci#include <linux/udp.h> 408c2ecf20Sopenharmony_ci#include <linux/highmem.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include <net/tcp.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <xen/xen.h> 458c2ecf20Sopenharmony_ci#include <xen/events.h> 468c2ecf20Sopenharmony_ci#include <xen/interface/memory.h> 478c2ecf20Sopenharmony_ci#include <xen/page.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <asm/xen/hypercall.h> 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* Provide an option to disable split event channels at load time as 528c2ecf20Sopenharmony_ci * event channels are limited resource. Split event channels are 538c2ecf20Sopenharmony_ci * enabled by default. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cibool separate_tx_rx_irq = true; 568c2ecf20Sopenharmony_cimodule_param(separate_tx_rx_irq, bool, 0644); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* The time that packets can stay on the guest Rx internal queue 598c2ecf20Sopenharmony_ci * before they are dropped. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ciunsigned int rx_drain_timeout_msecs = 10000; 628c2ecf20Sopenharmony_cimodule_param(rx_drain_timeout_msecs, uint, 0444); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* The length of time before the frontend is considered unresponsive 658c2ecf20Sopenharmony_ci * because it isn't providing Rx slots. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ciunsigned int rx_stall_timeout_msecs = 60000; 688c2ecf20Sopenharmony_cimodule_param(rx_stall_timeout_msecs, uint, 0444); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define MAX_QUEUES_DEFAULT 8 718c2ecf20Sopenharmony_ciunsigned int xenvif_max_queues; 728c2ecf20Sopenharmony_cimodule_param_named(max_queues, xenvif_max_queues, uint, 0644); 738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_queues, 748c2ecf20Sopenharmony_ci "Maximum number of queues per virtual interface"); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * This is the maximum slots a skb can have. If a guest sends a skb 788c2ecf20Sopenharmony_ci * which exceeds this limit it is considered malicious. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci#define FATAL_SKB_SLOTS_DEFAULT 20 818c2ecf20Sopenharmony_cistatic unsigned int fatal_skb_slots = FATAL_SKB_SLOTS_DEFAULT; 828c2ecf20Sopenharmony_cimodule_param(fatal_skb_slots, uint, 0444); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* The amount to copy out of the first guest Tx slot into the skb's 858c2ecf20Sopenharmony_ci * linear area. If the first slot has more data, it will be mapped 868c2ecf20Sopenharmony_ci * and put into the first frag. 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * This is sized to avoid pulling headers from the frags for most 898c2ecf20Sopenharmony_ci * TCP/IP packets. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci#define XEN_NETBACK_TX_COPY_LEN 128 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* This is the maximum number of flows in the hash cache. */ 948c2ecf20Sopenharmony_ci#define XENVIF_HASH_CACHE_SIZE_DEFAULT 64 958c2ecf20Sopenharmony_ciunsigned int xenvif_hash_cache_size = XENVIF_HASH_CACHE_SIZE_DEFAULT; 968c2ecf20Sopenharmony_cimodule_param_named(hash_cache_size, xenvif_hash_cache_size, uint, 0644); 978c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hash_cache_size, "Number of flows in the hash cache"); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* The module parameter tells that we have to put data 1008c2ecf20Sopenharmony_ci * for xen-netfront with the XDP_PACKET_HEADROOM offset 1018c2ecf20Sopenharmony_ci * needed for XDP processing 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_cibool provides_xdp_headroom = true; 1048c2ecf20Sopenharmony_cimodule_param(provides_xdp_headroom, bool, 0644); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, 1078c2ecf20Sopenharmony_ci s8 status); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void make_tx_response(struct xenvif_queue *queue, 1108c2ecf20Sopenharmony_ci const struct xen_netif_tx_request *txp, 1118c2ecf20Sopenharmony_ci unsigned int extra_count, 1128c2ecf20Sopenharmony_ci s8 status); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic inline int tx_work_todo(struct xenvif_queue *queue); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic inline unsigned long idx_to_pfn(struct xenvif_queue *queue, 1198c2ecf20Sopenharmony_ci u16 idx) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci return page_to_pfn(queue->mmap_pages[idx]); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic inline unsigned long idx_to_kaddr(struct xenvif_queue *queue, 1258c2ecf20Sopenharmony_ci u16 idx) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci return (unsigned long)pfn_to_kaddr(idx_to_pfn(queue, idx)); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define callback_param(vif, pending_idx) \ 1318c2ecf20Sopenharmony_ci (vif->pending_tx_info[pending_idx].callback_struct) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* Find the containing VIF's structure from a pointer in pending_tx_info array 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_cistatic inline struct xenvif_queue *ubuf_to_queue(const struct ubuf_info *ubuf) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci u16 pending_idx = ubuf->desc; 1388c2ecf20Sopenharmony_ci struct pending_tx_info *temp = 1398c2ecf20Sopenharmony_ci container_of(ubuf, struct pending_tx_info, callback_struct); 1408c2ecf20Sopenharmony_ci return container_of(temp - pending_idx, 1418c2ecf20Sopenharmony_ci struct xenvif_queue, 1428c2ecf20Sopenharmony_ci pending_tx_info[0]); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic u16 frag_get_pending_idx(skb_frag_t *frag) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci return (u16)skb_frag_off(frag); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void frag_set_pending_idx(skb_frag_t *frag, u16 pending_idx) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci skb_frag_off_set(frag, pending_idx); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic inline pending_ring_idx_t pending_index(unsigned i) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return i & (MAX_PENDING_REQS-1); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_civoid xenvif_kick_thread(struct xenvif_queue *queue) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci wake_up(&queue->wq); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_civoid xenvif_napi_schedule_or_enable_events(struct xenvif_queue *queue) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci int more_to_do; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci RING_FINAL_CHECK_FOR_REQUESTS(&queue->tx, more_to_do); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (more_to_do) 1728c2ecf20Sopenharmony_ci napi_schedule(&queue->napi); 1738c2ecf20Sopenharmony_ci else if (atomic_fetch_andnot(NETBK_TX_EOI | NETBK_COMMON_EOI, 1748c2ecf20Sopenharmony_ci &queue->eoi_pending) & 1758c2ecf20Sopenharmony_ci (NETBK_TX_EOI | NETBK_COMMON_EOI)) 1768c2ecf20Sopenharmony_ci xen_irq_lateeoi(queue->tx_irq, 0); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic void tx_add_credit(struct xenvif_queue *queue) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci unsigned long max_burst, max_credit; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * Allow a burst big enough to transmit a jumbo packet of up to 128kB. 1858c2ecf20Sopenharmony_ci * Otherwise the interface can seize up due to insufficient credit. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci max_burst = max(131072UL, queue->credit_bytes); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Take care that adding a new chunk of credit doesn't wrap to zero. */ 1908c2ecf20Sopenharmony_ci max_credit = queue->remaining_credit + queue->credit_bytes; 1918c2ecf20Sopenharmony_ci if (max_credit < queue->remaining_credit) 1928c2ecf20Sopenharmony_ci max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */ 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci queue->remaining_credit = min(max_credit, max_burst); 1958c2ecf20Sopenharmony_ci queue->rate_limited = false; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_civoid xenvif_tx_credit_callback(struct timer_list *t) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct xenvif_queue *queue = from_timer(queue, t, credit_timeout); 2018c2ecf20Sopenharmony_ci tx_add_credit(queue); 2028c2ecf20Sopenharmony_ci xenvif_napi_schedule_or_enable_events(queue); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void xenvif_tx_err(struct xenvif_queue *queue, 2068c2ecf20Sopenharmony_ci struct xen_netif_tx_request *txp, 2078c2ecf20Sopenharmony_ci unsigned int extra_count, RING_IDX end) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci RING_IDX cons = queue->tx.req_cons; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci do { 2128c2ecf20Sopenharmony_ci make_tx_response(queue, txp, extra_count, XEN_NETIF_RSP_ERROR); 2138c2ecf20Sopenharmony_ci if (cons == end) 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci RING_COPY_REQUEST(&queue->tx, cons++, txp); 2168c2ecf20Sopenharmony_ci extra_count = 0; /* only the first frag can have extras */ 2178c2ecf20Sopenharmony_ci } while (1); 2188c2ecf20Sopenharmony_ci queue->tx.req_cons = cons; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void xenvif_fatal_tx_err(struct xenvif *vif) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci netdev_err(vif->dev, "fatal error; disabling device\n"); 2248c2ecf20Sopenharmony_ci vif->disabled = true; 2258c2ecf20Sopenharmony_ci /* Disable the vif from queue 0's kthread */ 2268c2ecf20Sopenharmony_ci if (vif->num_queues) 2278c2ecf20Sopenharmony_ci xenvif_kick_thread(&vif->queues[0]); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int xenvif_count_requests(struct xenvif_queue *queue, 2318c2ecf20Sopenharmony_ci struct xen_netif_tx_request *first, 2328c2ecf20Sopenharmony_ci unsigned int extra_count, 2338c2ecf20Sopenharmony_ci struct xen_netif_tx_request *txp, 2348c2ecf20Sopenharmony_ci int work_to_do) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci RING_IDX cons = queue->tx.req_cons; 2378c2ecf20Sopenharmony_ci int slots = 0; 2388c2ecf20Sopenharmony_ci int drop_err = 0; 2398c2ecf20Sopenharmony_ci int more_data; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (!(first->flags & XEN_NETTXF_more_data)) 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci do { 2458c2ecf20Sopenharmony_ci struct xen_netif_tx_request dropped_tx = { 0 }; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (slots >= work_to_do) { 2488c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 2498c2ecf20Sopenharmony_ci "Asked for %d slots but exceeds this limit\n", 2508c2ecf20Sopenharmony_ci work_to_do); 2518c2ecf20Sopenharmony_ci xenvif_fatal_tx_err(queue->vif); 2528c2ecf20Sopenharmony_ci return -ENODATA; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* This guest is really using too many slots and 2568c2ecf20Sopenharmony_ci * considered malicious. 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci if (unlikely(slots >= fatal_skb_slots)) { 2598c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 2608c2ecf20Sopenharmony_ci "Malicious frontend using %d slots, threshold %u\n", 2618c2ecf20Sopenharmony_ci slots, fatal_skb_slots); 2628c2ecf20Sopenharmony_ci xenvif_fatal_tx_err(queue->vif); 2638c2ecf20Sopenharmony_ci return -E2BIG; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* Xen network protocol had implicit dependency on 2678c2ecf20Sopenharmony_ci * MAX_SKB_FRAGS. XEN_NETBK_LEGACY_SLOTS_MAX is set to 2688c2ecf20Sopenharmony_ci * the historical MAX_SKB_FRAGS value 18 to honor the 2698c2ecf20Sopenharmony_ci * same behavior as before. Any packet using more than 2708c2ecf20Sopenharmony_ci * 18 slots but less than fatal_skb_slots slots is 2718c2ecf20Sopenharmony_ci * dropped 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci if (!drop_err && slots >= XEN_NETBK_LEGACY_SLOTS_MAX) { 2748c2ecf20Sopenharmony_ci if (net_ratelimit()) 2758c2ecf20Sopenharmony_ci netdev_dbg(queue->vif->dev, 2768c2ecf20Sopenharmony_ci "Too many slots (%d) exceeding limit (%d), dropping packet\n", 2778c2ecf20Sopenharmony_ci slots, XEN_NETBK_LEGACY_SLOTS_MAX); 2788c2ecf20Sopenharmony_ci drop_err = -E2BIG; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (drop_err) 2828c2ecf20Sopenharmony_ci txp = &dropped_tx; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci RING_COPY_REQUEST(&queue->tx, cons + slots, txp); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* If the guest submitted a frame >= 64 KiB then 2878c2ecf20Sopenharmony_ci * first->size overflowed and following slots will 2888c2ecf20Sopenharmony_ci * appear to be larger than the frame. 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci * This cannot be fatal error as there are buggy 2918c2ecf20Sopenharmony_ci * frontends that do this. 2928c2ecf20Sopenharmony_ci * 2938c2ecf20Sopenharmony_ci * Consume all slots and drop the packet. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci if (!drop_err && txp->size > first->size) { 2968c2ecf20Sopenharmony_ci if (net_ratelimit()) 2978c2ecf20Sopenharmony_ci netdev_dbg(queue->vif->dev, 2988c2ecf20Sopenharmony_ci "Invalid tx request, slot size %u > remaining size %u\n", 2998c2ecf20Sopenharmony_ci txp->size, first->size); 3008c2ecf20Sopenharmony_ci drop_err = -EIO; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci first->size -= txp->size; 3048c2ecf20Sopenharmony_ci slots++; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (unlikely((txp->offset + txp->size) > XEN_PAGE_SIZE)) { 3078c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, "Cross page boundary, txp->offset: %u, size: %u\n", 3088c2ecf20Sopenharmony_ci txp->offset, txp->size); 3098c2ecf20Sopenharmony_ci xenvif_fatal_tx_err(queue->vif); 3108c2ecf20Sopenharmony_ci return -EINVAL; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci more_data = txp->flags & XEN_NETTXF_more_data; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (!drop_err) 3168c2ecf20Sopenharmony_ci txp++; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci } while (more_data); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (drop_err) { 3218c2ecf20Sopenharmony_ci xenvif_tx_err(queue, first, extra_count, cons + slots); 3228c2ecf20Sopenharmony_ci return drop_err; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return slots; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistruct xenvif_tx_cb { 3308c2ecf20Sopenharmony_ci u16 copy_pending_idx[XEN_NETBK_LEGACY_SLOTS_MAX + 1]; 3318c2ecf20Sopenharmony_ci u8 copy_count; 3328c2ecf20Sopenharmony_ci u32 split_mask; 3338c2ecf20Sopenharmony_ci}; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci#define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb) 3368c2ecf20Sopenharmony_ci#define copy_pending_idx(skb, i) (XENVIF_TX_CB(skb)->copy_pending_idx[i]) 3378c2ecf20Sopenharmony_ci#define copy_count(skb) (XENVIF_TX_CB(skb)->copy_count) 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic inline void xenvif_tx_create_map_op(struct xenvif_queue *queue, 3408c2ecf20Sopenharmony_ci u16 pending_idx, 3418c2ecf20Sopenharmony_ci struct xen_netif_tx_request *txp, 3428c2ecf20Sopenharmony_ci unsigned int extra_count, 3438c2ecf20Sopenharmony_ci struct gnttab_map_grant_ref *mop) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci queue->pages_to_map[mop-queue->tx_map_ops] = queue->mmap_pages[pending_idx]; 3468c2ecf20Sopenharmony_ci gnttab_set_map_op(mop, idx_to_kaddr(queue, pending_idx), 3478c2ecf20Sopenharmony_ci GNTMAP_host_map | GNTMAP_readonly, 3488c2ecf20Sopenharmony_ci txp->gref, queue->vif->domid); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci memcpy(&queue->pending_tx_info[pending_idx].req, txp, 3518c2ecf20Sopenharmony_ci sizeof(*txp)); 3528c2ecf20Sopenharmony_ci queue->pending_tx_info[pending_idx].extra_count = extra_count; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic inline struct sk_buff *xenvif_alloc_skb(unsigned int size) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct sk_buff *skb = 3588c2ecf20Sopenharmony_ci alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN, 3598c2ecf20Sopenharmony_ci GFP_ATOMIC | __GFP_NOWARN); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(*XENVIF_TX_CB(skb)) > sizeof(skb->cb)); 3628c2ecf20Sopenharmony_ci if (unlikely(skb == NULL)) 3638c2ecf20Sopenharmony_ci return NULL; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* Packets passed to netif_rx() must have some headroom. */ 3668c2ecf20Sopenharmony_ci skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* Initialize it here to avoid later surprises */ 3698c2ecf20Sopenharmony_ci skb_shinfo(skb)->destructor_arg = NULL; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return skb; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic void xenvif_get_requests(struct xenvif_queue *queue, 3758c2ecf20Sopenharmony_ci struct sk_buff *skb, 3768c2ecf20Sopenharmony_ci struct xen_netif_tx_request *first, 3778c2ecf20Sopenharmony_ci struct xen_netif_tx_request *txfrags, 3788c2ecf20Sopenharmony_ci unsigned *copy_ops, 3798c2ecf20Sopenharmony_ci unsigned *map_ops, 3808c2ecf20Sopenharmony_ci unsigned int frag_overflow, 3818c2ecf20Sopenharmony_ci struct sk_buff *nskb, 3828c2ecf20Sopenharmony_ci unsigned int extra_count, 3838c2ecf20Sopenharmony_ci unsigned int data_len) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct skb_shared_info *shinfo = skb_shinfo(skb); 3868c2ecf20Sopenharmony_ci skb_frag_t *frags = shinfo->frags; 3878c2ecf20Sopenharmony_ci u16 pending_idx; 3888c2ecf20Sopenharmony_ci pending_ring_idx_t index; 3898c2ecf20Sopenharmony_ci unsigned int nr_slots; 3908c2ecf20Sopenharmony_ci struct gnttab_copy *cop = queue->tx_copy_ops + *copy_ops; 3918c2ecf20Sopenharmony_ci struct gnttab_map_grant_ref *gop = queue->tx_map_ops + *map_ops; 3928c2ecf20Sopenharmony_ci struct xen_netif_tx_request *txp = first; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci nr_slots = shinfo->nr_frags + frag_overflow + 1; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci copy_count(skb) = 0; 3978c2ecf20Sopenharmony_ci XENVIF_TX_CB(skb)->split_mask = 0; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Create copy ops for exactly data_len bytes into the skb head. */ 4008c2ecf20Sopenharmony_ci __skb_put(skb, data_len); 4018c2ecf20Sopenharmony_ci while (data_len > 0) { 4028c2ecf20Sopenharmony_ci int amount = data_len > txp->size ? txp->size : data_len; 4038c2ecf20Sopenharmony_ci bool split = false; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci cop->source.u.ref = txp->gref; 4068c2ecf20Sopenharmony_ci cop->source.domid = queue->vif->domid; 4078c2ecf20Sopenharmony_ci cop->source.offset = txp->offset; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci cop->dest.domid = DOMID_SELF; 4108c2ecf20Sopenharmony_ci cop->dest.offset = (offset_in_page(skb->data + 4118c2ecf20Sopenharmony_ci skb_headlen(skb) - 4128c2ecf20Sopenharmony_ci data_len)) & ~XEN_PAGE_MASK; 4138c2ecf20Sopenharmony_ci cop->dest.u.gmfn = virt_to_gfn(skb->data + skb_headlen(skb) 4148c2ecf20Sopenharmony_ci - data_len); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Don't cross local page boundary! */ 4178c2ecf20Sopenharmony_ci if (cop->dest.offset + amount > XEN_PAGE_SIZE) { 4188c2ecf20Sopenharmony_ci amount = XEN_PAGE_SIZE - cop->dest.offset; 4198c2ecf20Sopenharmony_ci XENVIF_TX_CB(skb)->split_mask |= 1U << copy_count(skb); 4208c2ecf20Sopenharmony_ci split = true; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci cop->len = amount; 4248c2ecf20Sopenharmony_ci cop->flags = GNTCOPY_source_gref; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci index = pending_index(queue->pending_cons); 4278c2ecf20Sopenharmony_ci pending_idx = queue->pending_ring[index]; 4288c2ecf20Sopenharmony_ci callback_param(queue, pending_idx).ctx = NULL; 4298c2ecf20Sopenharmony_ci copy_pending_idx(skb, copy_count(skb)) = pending_idx; 4308c2ecf20Sopenharmony_ci if (!split) 4318c2ecf20Sopenharmony_ci copy_count(skb)++; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci cop++; 4348c2ecf20Sopenharmony_ci data_len -= amount; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (amount == txp->size) { 4378c2ecf20Sopenharmony_ci /* The copy op covered the full tx_request */ 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci memcpy(&queue->pending_tx_info[pending_idx].req, 4408c2ecf20Sopenharmony_ci txp, sizeof(*txp)); 4418c2ecf20Sopenharmony_ci queue->pending_tx_info[pending_idx].extra_count = 4428c2ecf20Sopenharmony_ci (txp == first) ? extra_count : 0; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (txp == first) 4458c2ecf20Sopenharmony_ci txp = txfrags; 4468c2ecf20Sopenharmony_ci else 4478c2ecf20Sopenharmony_ci txp++; 4488c2ecf20Sopenharmony_ci queue->pending_cons++; 4498c2ecf20Sopenharmony_ci nr_slots--; 4508c2ecf20Sopenharmony_ci } else { 4518c2ecf20Sopenharmony_ci /* The copy op partially covered the tx_request. 4528c2ecf20Sopenharmony_ci * The remainder will be mapped or copied in the next 4538c2ecf20Sopenharmony_ci * iteration. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_ci txp->offset += amount; 4568c2ecf20Sopenharmony_ci txp->size -= amount; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS; 4618c2ecf20Sopenharmony_ci nr_slots--) { 4628c2ecf20Sopenharmony_ci if (unlikely(!txp->size)) { 4638c2ecf20Sopenharmony_ci make_tx_response(queue, txp, 0, XEN_NETIF_RSP_OKAY); 4648c2ecf20Sopenharmony_ci ++txp; 4658c2ecf20Sopenharmony_ci continue; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci index = pending_index(queue->pending_cons++); 4698c2ecf20Sopenharmony_ci pending_idx = queue->pending_ring[index]; 4708c2ecf20Sopenharmony_ci xenvif_tx_create_map_op(queue, pending_idx, txp, 4718c2ecf20Sopenharmony_ci txp == first ? extra_count : 0, gop); 4728c2ecf20Sopenharmony_ci frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx); 4738c2ecf20Sopenharmony_ci ++shinfo->nr_frags; 4748c2ecf20Sopenharmony_ci ++gop; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (txp == first) 4778c2ecf20Sopenharmony_ci txp = txfrags; 4788c2ecf20Sopenharmony_ci else 4798c2ecf20Sopenharmony_ci txp++; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (nr_slots > 0) { 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci shinfo = skb_shinfo(nskb); 4858c2ecf20Sopenharmony_ci frags = shinfo->frags; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots; ++txp) { 4888c2ecf20Sopenharmony_ci if (unlikely(!txp->size)) { 4898c2ecf20Sopenharmony_ci make_tx_response(queue, txp, 0, 4908c2ecf20Sopenharmony_ci XEN_NETIF_RSP_OKAY); 4918c2ecf20Sopenharmony_ci continue; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci index = pending_index(queue->pending_cons++); 4958c2ecf20Sopenharmony_ci pending_idx = queue->pending_ring[index]; 4968c2ecf20Sopenharmony_ci xenvif_tx_create_map_op(queue, pending_idx, txp, 0, 4978c2ecf20Sopenharmony_ci gop); 4988c2ecf20Sopenharmony_ci frag_set_pending_idx(&frags[shinfo->nr_frags], 4998c2ecf20Sopenharmony_ci pending_idx); 5008c2ecf20Sopenharmony_ci ++shinfo->nr_frags; 5018c2ecf20Sopenharmony_ci ++gop; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (shinfo->nr_frags) { 5058c2ecf20Sopenharmony_ci skb_shinfo(skb)->frag_list = nskb; 5068c2ecf20Sopenharmony_ci nskb = NULL; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (nskb) { 5118c2ecf20Sopenharmony_ci /* A frag_list skb was allocated but it is no longer needed 5128c2ecf20Sopenharmony_ci * because enough slots were converted to copy ops above or some 5138c2ecf20Sopenharmony_ci * were empty. 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci kfree_skb(nskb); 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci (*copy_ops) = cop - queue->tx_copy_ops; 5198c2ecf20Sopenharmony_ci (*map_ops) = gop - queue->tx_map_ops; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic inline void xenvif_grant_handle_set(struct xenvif_queue *queue, 5238c2ecf20Sopenharmony_ci u16 pending_idx, 5248c2ecf20Sopenharmony_ci grant_handle_t handle) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci if (unlikely(queue->grant_tx_handle[pending_idx] != 5278c2ecf20Sopenharmony_ci NETBACK_INVALID_HANDLE)) { 5288c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 5298c2ecf20Sopenharmony_ci "Trying to overwrite active handle! pending_idx: 0x%x\n", 5308c2ecf20Sopenharmony_ci pending_idx); 5318c2ecf20Sopenharmony_ci BUG(); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci queue->grant_tx_handle[pending_idx] = handle; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic inline void xenvif_grant_handle_reset(struct xenvif_queue *queue, 5378c2ecf20Sopenharmony_ci u16 pending_idx) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci if (unlikely(queue->grant_tx_handle[pending_idx] == 5408c2ecf20Sopenharmony_ci NETBACK_INVALID_HANDLE)) { 5418c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 5428c2ecf20Sopenharmony_ci "Trying to unmap invalid handle! pending_idx: 0x%x\n", 5438c2ecf20Sopenharmony_ci pending_idx); 5448c2ecf20Sopenharmony_ci BUG(); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci queue->grant_tx_handle[pending_idx] = NETBACK_INVALID_HANDLE; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic int xenvif_tx_check_gop(struct xenvif_queue *queue, 5508c2ecf20Sopenharmony_ci struct sk_buff *skb, 5518c2ecf20Sopenharmony_ci struct gnttab_map_grant_ref **gopp_map, 5528c2ecf20Sopenharmony_ci struct gnttab_copy **gopp_copy) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct gnttab_map_grant_ref *gop_map = *gopp_map; 5558c2ecf20Sopenharmony_ci u16 pending_idx; 5568c2ecf20Sopenharmony_ci /* This always points to the shinfo of the skb being checked, which 5578c2ecf20Sopenharmony_ci * could be either the first or the one on the frag_list 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci struct skb_shared_info *shinfo = skb_shinfo(skb); 5608c2ecf20Sopenharmony_ci /* If this is non-NULL, we are currently checking the frag_list skb, and 5618c2ecf20Sopenharmony_ci * this points to the shinfo of the first one 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_ci struct skb_shared_info *first_shinfo = NULL; 5648c2ecf20Sopenharmony_ci int nr_frags = shinfo->nr_frags; 5658c2ecf20Sopenharmony_ci const bool sharedslot = nr_frags && 5668c2ecf20Sopenharmony_ci frag_get_pending_idx(&shinfo->frags[0]) == 5678c2ecf20Sopenharmony_ci copy_pending_idx(skb, copy_count(skb) - 1); 5688c2ecf20Sopenharmony_ci int i, err = 0; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci for (i = 0; i < copy_count(skb); i++) { 5718c2ecf20Sopenharmony_ci int newerr; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Check status of header. */ 5748c2ecf20Sopenharmony_ci pending_idx = copy_pending_idx(skb, i); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci newerr = (*gopp_copy)->status; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Split copies need to be handled together. */ 5798c2ecf20Sopenharmony_ci if (XENVIF_TX_CB(skb)->split_mask & (1U << i)) { 5808c2ecf20Sopenharmony_ci (*gopp_copy)++; 5818c2ecf20Sopenharmony_ci if (!newerr) 5828c2ecf20Sopenharmony_ci newerr = (*gopp_copy)->status; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci if (likely(!newerr)) { 5858c2ecf20Sopenharmony_ci /* The first frag might still have this slot mapped */ 5868c2ecf20Sopenharmony_ci if (i < copy_count(skb) - 1 || !sharedslot) 5878c2ecf20Sopenharmony_ci xenvif_idx_release(queue, pending_idx, 5888c2ecf20Sopenharmony_ci XEN_NETIF_RSP_OKAY); 5898c2ecf20Sopenharmony_ci } else { 5908c2ecf20Sopenharmony_ci err = newerr; 5918c2ecf20Sopenharmony_ci if (net_ratelimit()) 5928c2ecf20Sopenharmony_ci netdev_dbg(queue->vif->dev, 5938c2ecf20Sopenharmony_ci "Grant copy of header failed! status: %d pending_idx: %u ref: %u\n", 5948c2ecf20Sopenharmony_ci (*gopp_copy)->status, 5958c2ecf20Sopenharmony_ci pending_idx, 5968c2ecf20Sopenharmony_ci (*gopp_copy)->source.u.ref); 5978c2ecf20Sopenharmony_ci /* The first frag might still have this slot mapped */ 5988c2ecf20Sopenharmony_ci if (i < copy_count(skb) - 1 || !sharedslot) 5998c2ecf20Sopenharmony_ci xenvif_idx_release(queue, pending_idx, 6008c2ecf20Sopenharmony_ci XEN_NETIF_RSP_ERROR); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci (*gopp_copy)++; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cicheck_frags: 6068c2ecf20Sopenharmony_ci for (i = 0; i < nr_frags; i++, gop_map++) { 6078c2ecf20Sopenharmony_ci int j, newerr; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci pending_idx = frag_get_pending_idx(&shinfo->frags[i]); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* Check error status: if okay then remember grant handle. */ 6128c2ecf20Sopenharmony_ci newerr = gop_map->status; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (likely(!newerr)) { 6158c2ecf20Sopenharmony_ci xenvif_grant_handle_set(queue, 6168c2ecf20Sopenharmony_ci pending_idx, 6178c2ecf20Sopenharmony_ci gop_map->handle); 6188c2ecf20Sopenharmony_ci /* Had a previous error? Invalidate this fragment. */ 6198c2ecf20Sopenharmony_ci if (unlikely(err)) { 6208c2ecf20Sopenharmony_ci xenvif_idx_unmap(queue, pending_idx); 6218c2ecf20Sopenharmony_ci /* If the mapping of the first frag was OK, but 6228c2ecf20Sopenharmony_ci * the header's copy failed, and they are 6238c2ecf20Sopenharmony_ci * sharing a slot, send an error 6248c2ecf20Sopenharmony_ci */ 6258c2ecf20Sopenharmony_ci if (i == 0 && !first_shinfo && sharedslot) 6268c2ecf20Sopenharmony_ci xenvif_idx_release(queue, pending_idx, 6278c2ecf20Sopenharmony_ci XEN_NETIF_RSP_ERROR); 6288c2ecf20Sopenharmony_ci else 6298c2ecf20Sopenharmony_ci xenvif_idx_release(queue, pending_idx, 6308c2ecf20Sopenharmony_ci XEN_NETIF_RSP_OKAY); 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci continue; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* Error on this fragment: respond to client with an error. */ 6368c2ecf20Sopenharmony_ci if (net_ratelimit()) 6378c2ecf20Sopenharmony_ci netdev_dbg(queue->vif->dev, 6388c2ecf20Sopenharmony_ci "Grant map of %d. frag failed! status: %d pending_idx: %u ref: %u\n", 6398c2ecf20Sopenharmony_ci i, 6408c2ecf20Sopenharmony_ci gop_map->status, 6418c2ecf20Sopenharmony_ci pending_idx, 6428c2ecf20Sopenharmony_ci gop_map->ref); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_ERROR); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* Not the first error? Preceding frags already invalidated. */ 6478c2ecf20Sopenharmony_ci if (err) 6488c2ecf20Sopenharmony_ci continue; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Invalidate preceding fragments of this skb. */ 6518c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 6528c2ecf20Sopenharmony_ci pending_idx = frag_get_pending_idx(&shinfo->frags[j]); 6538c2ecf20Sopenharmony_ci xenvif_idx_unmap(queue, pending_idx); 6548c2ecf20Sopenharmony_ci xenvif_idx_release(queue, pending_idx, 6558c2ecf20Sopenharmony_ci XEN_NETIF_RSP_OKAY); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* And if we found the error while checking the frag_list, unmap 6598c2ecf20Sopenharmony_ci * the first skb's frags 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_ci if (first_shinfo) { 6628c2ecf20Sopenharmony_ci for (j = 0; j < first_shinfo->nr_frags; j++) { 6638c2ecf20Sopenharmony_ci pending_idx = frag_get_pending_idx(&first_shinfo->frags[j]); 6648c2ecf20Sopenharmony_ci xenvif_idx_unmap(queue, pending_idx); 6658c2ecf20Sopenharmony_ci xenvif_idx_release(queue, pending_idx, 6668c2ecf20Sopenharmony_ci XEN_NETIF_RSP_OKAY); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* Remember the error: invalidate all subsequent fragments. */ 6718c2ecf20Sopenharmony_ci err = newerr; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (skb_has_frag_list(skb) && !first_shinfo) { 6758c2ecf20Sopenharmony_ci first_shinfo = skb_shinfo(skb); 6768c2ecf20Sopenharmony_ci shinfo = skb_shinfo(skb_shinfo(skb)->frag_list); 6778c2ecf20Sopenharmony_ci nr_frags = shinfo->nr_frags; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci goto check_frags; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci *gopp_map = gop_map; 6838c2ecf20Sopenharmony_ci return err; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct skb_shared_info *shinfo = skb_shinfo(skb); 6898c2ecf20Sopenharmony_ci int nr_frags = shinfo->nr_frags; 6908c2ecf20Sopenharmony_ci int i; 6918c2ecf20Sopenharmony_ci u16 prev_pending_idx = INVALID_PENDING_IDX; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci for (i = 0; i < nr_frags; i++) { 6948c2ecf20Sopenharmony_ci skb_frag_t *frag = shinfo->frags + i; 6958c2ecf20Sopenharmony_ci struct xen_netif_tx_request *txp; 6968c2ecf20Sopenharmony_ci struct page *page; 6978c2ecf20Sopenharmony_ci u16 pending_idx; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci pending_idx = frag_get_pending_idx(frag); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* If this is not the first frag, chain it to the previous*/ 7028c2ecf20Sopenharmony_ci if (prev_pending_idx == INVALID_PENDING_IDX) 7038c2ecf20Sopenharmony_ci skb_shinfo(skb)->destructor_arg = 7048c2ecf20Sopenharmony_ci &callback_param(queue, pending_idx); 7058c2ecf20Sopenharmony_ci else 7068c2ecf20Sopenharmony_ci callback_param(queue, prev_pending_idx).ctx = 7078c2ecf20Sopenharmony_ci &callback_param(queue, pending_idx); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci callback_param(queue, pending_idx).ctx = NULL; 7108c2ecf20Sopenharmony_ci prev_pending_idx = pending_idx; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci txp = &queue->pending_tx_info[pending_idx].req; 7138c2ecf20Sopenharmony_ci page = virt_to_page(idx_to_kaddr(queue, pending_idx)); 7148c2ecf20Sopenharmony_ci __skb_fill_page_desc(skb, i, page, txp->offset, txp->size); 7158c2ecf20Sopenharmony_ci skb->len += txp->size; 7168c2ecf20Sopenharmony_ci skb->data_len += txp->size; 7178c2ecf20Sopenharmony_ci skb->truesize += txp->size; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* Take an extra reference to offset network stack's put_page */ 7208c2ecf20Sopenharmony_ci get_page(queue->mmap_pages[pending_idx]); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic int xenvif_get_extras(struct xenvif_queue *queue, 7258c2ecf20Sopenharmony_ci struct xen_netif_extra_info *extras, 7268c2ecf20Sopenharmony_ci unsigned int *extra_count, 7278c2ecf20Sopenharmony_ci int work_to_do) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct xen_netif_extra_info extra; 7308c2ecf20Sopenharmony_ci RING_IDX cons = queue->tx.req_cons; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci do { 7338c2ecf20Sopenharmony_ci if (unlikely(work_to_do-- <= 0)) { 7348c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, "Missing extra info\n"); 7358c2ecf20Sopenharmony_ci xenvif_fatal_tx_err(queue->vif); 7368c2ecf20Sopenharmony_ci return -EBADR; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci RING_COPY_REQUEST(&queue->tx, cons, &extra); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci queue->tx.req_cons = ++cons; 7428c2ecf20Sopenharmony_ci (*extra_count)++; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (unlikely(!extra.type || 7458c2ecf20Sopenharmony_ci extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) { 7468c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 7478c2ecf20Sopenharmony_ci "Invalid extra type: %d\n", extra.type); 7488c2ecf20Sopenharmony_ci xenvif_fatal_tx_err(queue->vif); 7498c2ecf20Sopenharmony_ci return -EINVAL; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci memcpy(&extras[extra.type - 1], &extra, sizeof(extra)); 7538c2ecf20Sopenharmony_ci } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci return work_to_do; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic int xenvif_set_skb_gso(struct xenvif *vif, 7598c2ecf20Sopenharmony_ci struct sk_buff *skb, 7608c2ecf20Sopenharmony_ci struct xen_netif_extra_info *gso) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci if (!gso->u.gso.size) { 7638c2ecf20Sopenharmony_ci netdev_err(vif->dev, "GSO size must not be zero.\n"); 7648c2ecf20Sopenharmony_ci xenvif_fatal_tx_err(vif); 7658c2ecf20Sopenharmony_ci return -EINVAL; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci switch (gso->u.gso.type) { 7698c2ecf20Sopenharmony_ci case XEN_NETIF_GSO_TYPE_TCPV4: 7708c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci case XEN_NETIF_GSO_TYPE_TCPV6: 7738c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci default: 7768c2ecf20Sopenharmony_ci netdev_err(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type); 7778c2ecf20Sopenharmony_ci xenvif_fatal_tx_err(vif); 7788c2ecf20Sopenharmony_ci return -EINVAL; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_size = gso->u.gso.size; 7828c2ecf20Sopenharmony_ci /* gso_segs will be calculated later */ 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci return 0; 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_cistatic int checksum_setup(struct xenvif_queue *queue, struct sk_buff *skb) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci bool recalculate_partial_csum = false; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy 7928c2ecf20Sopenharmony_ci * peers can fail to set NETRXF_csum_blank when sending a GSO 7938c2ecf20Sopenharmony_ci * frame. In this case force the SKB to CHECKSUM_PARTIAL and 7948c2ecf20Sopenharmony_ci * recalculate the partial checksum. 7958c2ecf20Sopenharmony_ci */ 7968c2ecf20Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) { 7978c2ecf20Sopenharmony_ci queue->stats.rx_gso_checksum_fixup++; 7988c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_PARTIAL; 7998c2ecf20Sopenharmony_ci recalculate_partial_csum = true; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci /* A non-CHECKSUM_PARTIAL SKB does not require setup. */ 8038c2ecf20Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL) 8048c2ecf20Sopenharmony_ci return 0; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return skb_checksum_setup(skb, recalculate_partial_csum); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic bool tx_credit_exceeded(struct xenvif_queue *queue, unsigned size) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci u64 now = get_jiffies_64(); 8128c2ecf20Sopenharmony_ci u64 next_credit = queue->credit_window_start + 8138c2ecf20Sopenharmony_ci msecs_to_jiffies(queue->credit_usec / 1000); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* Timer could already be pending in rare cases. */ 8168c2ecf20Sopenharmony_ci if (timer_pending(&queue->credit_timeout)) { 8178c2ecf20Sopenharmony_ci queue->rate_limited = true; 8188c2ecf20Sopenharmony_ci return true; 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci /* Passed the point where we can replenish credit? */ 8228c2ecf20Sopenharmony_ci if (time_after_eq64(now, next_credit)) { 8238c2ecf20Sopenharmony_ci queue->credit_window_start = now; 8248c2ecf20Sopenharmony_ci tx_add_credit(queue); 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci /* Still too big to send right now? Set a callback. */ 8288c2ecf20Sopenharmony_ci if (size > queue->remaining_credit) { 8298c2ecf20Sopenharmony_ci mod_timer(&queue->credit_timeout, 8308c2ecf20Sopenharmony_ci next_credit); 8318c2ecf20Sopenharmony_ci queue->credit_window_start = next_credit; 8328c2ecf20Sopenharmony_ci queue->rate_limited = true; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci return true; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return false; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci/* No locking is required in xenvif_mcast_add/del() as they are 8418c2ecf20Sopenharmony_ci * only ever invoked from NAPI poll. An RCU list is used because 8428c2ecf20Sopenharmony_ci * xenvif_mcast_match() is called asynchronously, during start_xmit. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic int xenvif_mcast_add(struct xenvif *vif, const u8 *addr) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct xenvif_mcast_addr *mcast; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (vif->fe_mcast_count == XEN_NETBK_MCAST_MAX) { 8508c2ecf20Sopenharmony_ci if (net_ratelimit()) 8518c2ecf20Sopenharmony_ci netdev_err(vif->dev, 8528c2ecf20Sopenharmony_ci "Too many multicast addresses\n"); 8538c2ecf20Sopenharmony_ci return -ENOSPC; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci mcast = kzalloc(sizeof(*mcast), GFP_ATOMIC); 8578c2ecf20Sopenharmony_ci if (!mcast) 8588c2ecf20Sopenharmony_ci return -ENOMEM; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci ether_addr_copy(mcast->addr, addr); 8618c2ecf20Sopenharmony_ci list_add_tail_rcu(&mcast->entry, &vif->fe_mcast_addr); 8628c2ecf20Sopenharmony_ci vif->fe_mcast_count++; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic void xenvif_mcast_del(struct xenvif *vif, const u8 *addr) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct xenvif_mcast_addr *mcast; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci list_for_each_entry_rcu(mcast, &vif->fe_mcast_addr, entry) { 8728c2ecf20Sopenharmony_ci if (ether_addr_equal(addr, mcast->addr)) { 8738c2ecf20Sopenharmony_ci --vif->fe_mcast_count; 8748c2ecf20Sopenharmony_ci list_del_rcu(&mcast->entry); 8758c2ecf20Sopenharmony_ci kfree_rcu(mcast, rcu); 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cibool xenvif_mcast_match(struct xenvif *vif, const u8 *addr) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci struct xenvif_mcast_addr *mcast; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci rcu_read_lock(); 8868c2ecf20Sopenharmony_ci list_for_each_entry_rcu(mcast, &vif->fe_mcast_addr, entry) { 8878c2ecf20Sopenharmony_ci if (ether_addr_equal(addr, mcast->addr)) { 8888c2ecf20Sopenharmony_ci rcu_read_unlock(); 8898c2ecf20Sopenharmony_ci return true; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci rcu_read_unlock(); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return false; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_civoid xenvif_mcast_addr_list_free(struct xenvif *vif) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci /* No need for locking or RCU here. NAPI poll and TX queue 9008c2ecf20Sopenharmony_ci * are stopped. 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_ci while (!list_empty(&vif->fe_mcast_addr)) { 9038c2ecf20Sopenharmony_ci struct xenvif_mcast_addr *mcast; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci mcast = list_first_entry(&vif->fe_mcast_addr, 9068c2ecf20Sopenharmony_ci struct xenvif_mcast_addr, 9078c2ecf20Sopenharmony_ci entry); 9088c2ecf20Sopenharmony_ci --vif->fe_mcast_count; 9098c2ecf20Sopenharmony_ci list_del(&mcast->entry); 9108c2ecf20Sopenharmony_ci kfree(mcast); 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic void xenvif_tx_build_gops(struct xenvif_queue *queue, 9158c2ecf20Sopenharmony_ci int budget, 9168c2ecf20Sopenharmony_ci unsigned *copy_ops, 9178c2ecf20Sopenharmony_ci unsigned *map_ops) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci struct sk_buff *skb, *nskb; 9208c2ecf20Sopenharmony_ci int ret; 9218c2ecf20Sopenharmony_ci unsigned int frag_overflow; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci while (skb_queue_len(&queue->tx_queue) < budget) { 9248c2ecf20Sopenharmony_ci struct xen_netif_tx_request txreq; 9258c2ecf20Sopenharmony_ci struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; 9268c2ecf20Sopenharmony_ci struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1]; 9278c2ecf20Sopenharmony_ci unsigned int extra_count; 9288c2ecf20Sopenharmony_ci u16 pending_idx; 9298c2ecf20Sopenharmony_ci RING_IDX idx; 9308c2ecf20Sopenharmony_ci int work_to_do; 9318c2ecf20Sopenharmony_ci unsigned int data_len; 9328c2ecf20Sopenharmony_ci pending_ring_idx_t index; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if (queue->tx.sring->req_prod - queue->tx.req_cons > 9358c2ecf20Sopenharmony_ci XEN_NETIF_TX_RING_SIZE) { 9368c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 9378c2ecf20Sopenharmony_ci "Impossible number of requests. " 9388c2ecf20Sopenharmony_ci "req_prod %d, req_cons %d, size %ld\n", 9398c2ecf20Sopenharmony_ci queue->tx.sring->req_prod, queue->tx.req_cons, 9408c2ecf20Sopenharmony_ci XEN_NETIF_TX_RING_SIZE); 9418c2ecf20Sopenharmony_ci xenvif_fatal_tx_err(queue->vif); 9428c2ecf20Sopenharmony_ci break; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&queue->tx); 9468c2ecf20Sopenharmony_ci if (!work_to_do) 9478c2ecf20Sopenharmony_ci break; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci idx = queue->tx.req_cons; 9508c2ecf20Sopenharmony_ci rmb(); /* Ensure that we see the request before we copy it. */ 9518c2ecf20Sopenharmony_ci RING_COPY_REQUEST(&queue->tx, idx, &txreq); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci /* Credit-based scheduling. */ 9548c2ecf20Sopenharmony_ci if (txreq.size > queue->remaining_credit && 9558c2ecf20Sopenharmony_ci tx_credit_exceeded(queue, txreq.size)) 9568c2ecf20Sopenharmony_ci break; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci queue->remaining_credit -= txreq.size; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci work_to_do--; 9618c2ecf20Sopenharmony_ci queue->tx.req_cons = ++idx; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci memset(extras, 0, sizeof(extras)); 9648c2ecf20Sopenharmony_ci extra_count = 0; 9658c2ecf20Sopenharmony_ci if (txreq.flags & XEN_NETTXF_extra_info) { 9668c2ecf20Sopenharmony_ci work_to_do = xenvif_get_extras(queue, extras, 9678c2ecf20Sopenharmony_ci &extra_count, 9688c2ecf20Sopenharmony_ci work_to_do); 9698c2ecf20Sopenharmony_ci idx = queue->tx.req_cons; 9708c2ecf20Sopenharmony_ci if (unlikely(work_to_do < 0)) 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (extras[XEN_NETIF_EXTRA_TYPE_MCAST_ADD - 1].type) { 9758c2ecf20Sopenharmony_ci struct xen_netif_extra_info *extra; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_ADD - 1]; 9788c2ecf20Sopenharmony_ci ret = xenvif_mcast_add(queue->vif, extra->u.mcast.addr); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci make_tx_response(queue, &txreq, extra_count, 9818c2ecf20Sopenharmony_ci (ret == 0) ? 9828c2ecf20Sopenharmony_ci XEN_NETIF_RSP_OKAY : 9838c2ecf20Sopenharmony_ci XEN_NETIF_RSP_ERROR); 9848c2ecf20Sopenharmony_ci continue; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (extras[XEN_NETIF_EXTRA_TYPE_MCAST_DEL - 1].type) { 9888c2ecf20Sopenharmony_ci struct xen_netif_extra_info *extra; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_DEL - 1]; 9918c2ecf20Sopenharmony_ci xenvif_mcast_del(queue->vif, extra->u.mcast.addr); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci make_tx_response(queue, &txreq, extra_count, 9948c2ecf20Sopenharmony_ci XEN_NETIF_RSP_OKAY); 9958c2ecf20Sopenharmony_ci continue; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci data_len = (txreq.size > XEN_NETBACK_TX_COPY_LEN) ? 9998c2ecf20Sopenharmony_ci XEN_NETBACK_TX_COPY_LEN : txreq.size; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci ret = xenvif_count_requests(queue, &txreq, extra_count, 10028c2ecf20Sopenharmony_ci txfrags, work_to_do); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 10058c2ecf20Sopenharmony_ci break; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci idx += ret; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (unlikely(txreq.size < ETH_HLEN)) { 10108c2ecf20Sopenharmony_ci netdev_dbg(queue->vif->dev, 10118c2ecf20Sopenharmony_ci "Bad packet size: %d\n", txreq.size); 10128c2ecf20Sopenharmony_ci xenvif_tx_err(queue, &txreq, extra_count, idx); 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci /* No crossing a page as the payload mustn't fragment. */ 10178c2ecf20Sopenharmony_ci if (unlikely((txreq.offset + txreq.size) > XEN_PAGE_SIZE)) { 10188c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, "Cross page boundary, txreq.offset: %u, size: %u\n", 10198c2ecf20Sopenharmony_ci txreq.offset, txreq.size); 10208c2ecf20Sopenharmony_ci xenvif_fatal_tx_err(queue->vif); 10218c2ecf20Sopenharmony_ci break; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci index = pending_index(queue->pending_cons); 10258c2ecf20Sopenharmony_ci pending_idx = queue->pending_ring[index]; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (ret >= XEN_NETBK_LEGACY_SLOTS_MAX - 1 && data_len < txreq.size) 10288c2ecf20Sopenharmony_ci data_len = txreq.size; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci skb = xenvif_alloc_skb(data_len); 10318c2ecf20Sopenharmony_ci if (unlikely(skb == NULL)) { 10328c2ecf20Sopenharmony_ci netdev_dbg(queue->vif->dev, 10338c2ecf20Sopenharmony_ci "Can't allocate a skb in start_xmit.\n"); 10348c2ecf20Sopenharmony_ci xenvif_tx_err(queue, &txreq, extra_count, idx); 10358c2ecf20Sopenharmony_ci break; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags = ret; 10398c2ecf20Sopenharmony_ci /* At this point shinfo->nr_frags is in fact the number of 10408c2ecf20Sopenharmony_ci * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX. 10418c2ecf20Sopenharmony_ci */ 10428c2ecf20Sopenharmony_ci frag_overflow = 0; 10438c2ecf20Sopenharmony_ci nskb = NULL; 10448c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->nr_frags > MAX_SKB_FRAGS) { 10458c2ecf20Sopenharmony_ci frag_overflow = skb_shinfo(skb)->nr_frags - MAX_SKB_FRAGS; 10468c2ecf20Sopenharmony_ci BUG_ON(frag_overflow > MAX_SKB_FRAGS); 10478c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags = MAX_SKB_FRAGS; 10488c2ecf20Sopenharmony_ci nskb = xenvif_alloc_skb(0); 10498c2ecf20Sopenharmony_ci if (unlikely(nskb == NULL)) { 10508c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags = 0; 10518c2ecf20Sopenharmony_ci kfree_skb(skb); 10528c2ecf20Sopenharmony_ci xenvif_tx_err(queue, &txreq, extra_count, idx); 10538c2ecf20Sopenharmony_ci if (net_ratelimit()) 10548c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 10558c2ecf20Sopenharmony_ci "Can't allocate the frag_list skb.\n"); 10568c2ecf20Sopenharmony_ci break; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { 10618c2ecf20Sopenharmony_ci struct xen_netif_extra_info *gso; 10628c2ecf20Sopenharmony_ci gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (xenvif_set_skb_gso(queue->vif, skb, gso)) { 10658c2ecf20Sopenharmony_ci /* Failure in xenvif_set_skb_gso is fatal. */ 10668c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags = 0; 10678c2ecf20Sopenharmony_ci kfree_skb(skb); 10688c2ecf20Sopenharmony_ci kfree_skb(nskb); 10698c2ecf20Sopenharmony_ci break; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (extras[XEN_NETIF_EXTRA_TYPE_HASH - 1].type) { 10748c2ecf20Sopenharmony_ci struct xen_netif_extra_info *extra; 10758c2ecf20Sopenharmony_ci enum pkt_hash_types type = PKT_HASH_TYPE_NONE; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci extra = &extras[XEN_NETIF_EXTRA_TYPE_HASH - 1]; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci switch (extra->u.hash.type) { 10808c2ecf20Sopenharmony_ci case _XEN_NETIF_CTRL_HASH_TYPE_IPV4: 10818c2ecf20Sopenharmony_ci case _XEN_NETIF_CTRL_HASH_TYPE_IPV6: 10828c2ecf20Sopenharmony_ci type = PKT_HASH_TYPE_L3; 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci case _XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP: 10868c2ecf20Sopenharmony_ci case _XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP: 10878c2ecf20Sopenharmony_ci type = PKT_HASH_TYPE_L4; 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci default: 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (type != PKT_HASH_TYPE_NONE) 10958c2ecf20Sopenharmony_ci skb_set_hash(skb, 10968c2ecf20Sopenharmony_ci *(u32 *)extra->u.hash.value, 10978c2ecf20Sopenharmony_ci type); 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci xenvif_get_requests(queue, skb, &txreq, txfrags, copy_ops, 11018c2ecf20Sopenharmony_ci map_ops, frag_overflow, nskb, extra_count, 11028c2ecf20Sopenharmony_ci data_len); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci __skb_queue_tail(&queue->tx_queue, skb); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci queue->tx.req_cons = idx; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if ((*map_ops >= ARRAY_SIZE(queue->tx_map_ops)) || 11098c2ecf20Sopenharmony_ci (*copy_ops >= ARRAY_SIZE(queue->tx_copy_ops))) 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci return; 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci/* Consolidate skb with a frag_list into a brand new one with local pages on 11178c2ecf20Sopenharmony_ci * frags. Returns 0 or -ENOMEM if can't allocate new pages. 11188c2ecf20Sopenharmony_ci */ 11198c2ecf20Sopenharmony_cistatic int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *skb) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci unsigned int offset = skb_headlen(skb); 11228c2ecf20Sopenharmony_ci skb_frag_t frags[MAX_SKB_FRAGS]; 11238c2ecf20Sopenharmony_ci int i, f; 11248c2ecf20Sopenharmony_ci struct ubuf_info *uarg; 11258c2ecf20Sopenharmony_ci struct sk_buff *nskb = skb_shinfo(skb)->frag_list; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci queue->stats.tx_zerocopy_sent += 2; 11288c2ecf20Sopenharmony_ci queue->stats.tx_frag_overflow++; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci xenvif_fill_frags(queue, nskb); 11318c2ecf20Sopenharmony_ci /* Subtract frags size, we will correct it later */ 11328c2ecf20Sopenharmony_ci skb->truesize -= skb->data_len; 11338c2ecf20Sopenharmony_ci skb->len += nskb->len; 11348c2ecf20Sopenharmony_ci skb->data_len += nskb->len; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* create a brand new frags array and coalesce there */ 11378c2ecf20Sopenharmony_ci for (i = 0; offset < skb->len; i++) { 11388c2ecf20Sopenharmony_ci struct page *page; 11398c2ecf20Sopenharmony_ci unsigned int len; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci BUG_ON(i >= MAX_SKB_FRAGS); 11428c2ecf20Sopenharmony_ci page = alloc_page(GFP_ATOMIC); 11438c2ecf20Sopenharmony_ci if (!page) { 11448c2ecf20Sopenharmony_ci int j; 11458c2ecf20Sopenharmony_ci skb->truesize += skb->data_len; 11468c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 11478c2ecf20Sopenharmony_ci put_page(skb_frag_page(&frags[j])); 11488c2ecf20Sopenharmony_ci return -ENOMEM; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (offset + PAGE_SIZE < skb->len) 11528c2ecf20Sopenharmony_ci len = PAGE_SIZE; 11538c2ecf20Sopenharmony_ci else 11548c2ecf20Sopenharmony_ci len = skb->len - offset; 11558c2ecf20Sopenharmony_ci if (skb_copy_bits(skb, offset, page_address(page), len)) 11568c2ecf20Sopenharmony_ci BUG(); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci offset += len; 11598c2ecf20Sopenharmony_ci __skb_frag_set_page(&frags[i], page); 11608c2ecf20Sopenharmony_ci skb_frag_off_set(&frags[i], 0); 11618c2ecf20Sopenharmony_ci skb_frag_size_set(&frags[i], len); 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* Release all the original (foreign) frags. */ 11658c2ecf20Sopenharmony_ci for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) 11668c2ecf20Sopenharmony_ci skb_frag_unref(skb, f); 11678c2ecf20Sopenharmony_ci uarg = skb_shinfo(skb)->destructor_arg; 11688c2ecf20Sopenharmony_ci /* increase inflight counter to offset decrement in callback */ 11698c2ecf20Sopenharmony_ci atomic_inc(&queue->inflight_packets); 11708c2ecf20Sopenharmony_ci uarg->callback(uarg, true); 11718c2ecf20Sopenharmony_ci skb_shinfo(skb)->destructor_arg = NULL; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* Fill the skb with the new (local) frags. */ 11748c2ecf20Sopenharmony_ci memcpy(skb_shinfo(skb)->frags, frags, i * sizeof(skb_frag_t)); 11758c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags = i; 11768c2ecf20Sopenharmony_ci skb->truesize += i * PAGE_SIZE; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci return 0; 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_cistatic int xenvif_tx_submit(struct xenvif_queue *queue) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci struct gnttab_map_grant_ref *gop_map = queue->tx_map_ops; 11848c2ecf20Sopenharmony_ci struct gnttab_copy *gop_copy = queue->tx_copy_ops; 11858c2ecf20Sopenharmony_ci struct sk_buff *skb; 11868c2ecf20Sopenharmony_ci int work_done = 0; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&queue->tx_queue)) != NULL) { 11898c2ecf20Sopenharmony_ci struct xen_netif_tx_request *txp; 11908c2ecf20Sopenharmony_ci u16 pending_idx; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci pending_idx = copy_pending_idx(skb, 0); 11938c2ecf20Sopenharmony_ci txp = &queue->pending_tx_info[pending_idx].req; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci /* Check the remap error code. */ 11968c2ecf20Sopenharmony_ci if (unlikely(xenvif_tx_check_gop(queue, skb, &gop_map, &gop_copy))) { 11978c2ecf20Sopenharmony_ci /* If there was an error, xenvif_tx_check_gop is 11988c2ecf20Sopenharmony_ci * expected to release all the frags which were mapped, 11998c2ecf20Sopenharmony_ci * so kfree_skb shouldn't do it again 12008c2ecf20Sopenharmony_ci */ 12018c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags = 0; 12028c2ecf20Sopenharmony_ci if (skb_has_frag_list(skb)) { 12038c2ecf20Sopenharmony_ci struct sk_buff *nskb = 12048c2ecf20Sopenharmony_ci skb_shinfo(skb)->frag_list; 12058c2ecf20Sopenharmony_ci skb_shinfo(nskb)->nr_frags = 0; 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci kfree_skb(skb); 12088c2ecf20Sopenharmony_ci continue; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (txp->flags & XEN_NETTXF_csum_blank) 12128c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_PARTIAL; 12138c2ecf20Sopenharmony_ci else if (txp->flags & XEN_NETTXF_data_validated) 12148c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci xenvif_fill_frags(queue, skb); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (unlikely(skb_has_frag_list(skb))) { 12198c2ecf20Sopenharmony_ci struct sk_buff *nskb = skb_shinfo(skb)->frag_list; 12208c2ecf20Sopenharmony_ci xenvif_skb_zerocopy_prepare(queue, nskb); 12218c2ecf20Sopenharmony_ci if (xenvif_handle_frag_list(queue, skb)) { 12228c2ecf20Sopenharmony_ci if (net_ratelimit()) 12238c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 12248c2ecf20Sopenharmony_ci "Not enough memory to consolidate frag_list!\n"); 12258c2ecf20Sopenharmony_ci xenvif_skb_zerocopy_prepare(queue, skb); 12268c2ecf20Sopenharmony_ci kfree_skb(skb); 12278c2ecf20Sopenharmony_ci continue; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci /* Copied all the bits from the frag list -- free it. */ 12308c2ecf20Sopenharmony_ci skb_frag_list_init(skb); 12318c2ecf20Sopenharmony_ci kfree_skb(nskb); 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci skb->dev = queue->vif->dev; 12358c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, skb->dev); 12368c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (checksum_setup(queue, skb)) { 12398c2ecf20Sopenharmony_ci netdev_dbg(queue->vif->dev, 12408c2ecf20Sopenharmony_ci "Can't setup checksum in net_tx_action\n"); 12418c2ecf20Sopenharmony_ci /* We have to set this flag to trigger the callback */ 12428c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->destructor_arg) 12438c2ecf20Sopenharmony_ci xenvif_skb_zerocopy_prepare(queue, skb); 12448c2ecf20Sopenharmony_ci kfree_skb(skb); 12458c2ecf20Sopenharmony_ci continue; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci skb_probe_transport_header(skb); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* If the packet is GSO then we will have just set up the 12518c2ecf20Sopenharmony_ci * transport header offset in checksum_setup so it's now 12528c2ecf20Sopenharmony_ci * straightforward to calculate gso_segs. 12538c2ecf20Sopenharmony_ci */ 12548c2ecf20Sopenharmony_ci if (skb_is_gso(skb)) { 12558c2ecf20Sopenharmony_ci int mss, hdrlen; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* GSO implies having the L4 header. */ 12588c2ecf20Sopenharmony_ci WARN_ON_ONCE(!skb_transport_header_was_set(skb)); 12598c2ecf20Sopenharmony_ci if (unlikely(!skb_transport_header_was_set(skb))) { 12608c2ecf20Sopenharmony_ci kfree_skb(skb); 12618c2ecf20Sopenharmony_ci continue; 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci mss = skb_shinfo(skb)->gso_size; 12658c2ecf20Sopenharmony_ci hdrlen = skb_transport_header(skb) - 12668c2ecf20Sopenharmony_ci skb_mac_header(skb) + 12678c2ecf20Sopenharmony_ci tcp_hdrlen(skb); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_segs = 12708c2ecf20Sopenharmony_ci DIV_ROUND_UP(skb->len - hdrlen, mss); 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci queue->stats.rx_bytes += skb->len; 12748c2ecf20Sopenharmony_ci queue->stats.rx_packets++; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci work_done++; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci /* Set this flag right before netif_receive_skb, otherwise 12798c2ecf20Sopenharmony_ci * someone might think this packet already left netback, and 12808c2ecf20Sopenharmony_ci * do a skb_copy_ubufs while we are still in control of the 12818c2ecf20Sopenharmony_ci * skb. E.g. the __pskb_pull_tail earlier can do such thing. 12828c2ecf20Sopenharmony_ci */ 12838c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->destructor_arg) { 12848c2ecf20Sopenharmony_ci xenvif_skb_zerocopy_prepare(queue, skb); 12858c2ecf20Sopenharmony_ci queue->stats.tx_zerocopy_sent++; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci netif_receive_skb(skb); 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci return work_done; 12928c2ecf20Sopenharmony_ci} 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_civoid xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci unsigned long flags; 12978c2ecf20Sopenharmony_ci pending_ring_idx_t index; 12988c2ecf20Sopenharmony_ci struct xenvif_queue *queue = ubuf_to_queue(ubuf); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* This is the only place where we grab this lock, to protect callbacks 13018c2ecf20Sopenharmony_ci * from each other. 13028c2ecf20Sopenharmony_ci */ 13038c2ecf20Sopenharmony_ci spin_lock_irqsave(&queue->callback_lock, flags); 13048c2ecf20Sopenharmony_ci do { 13058c2ecf20Sopenharmony_ci u16 pending_idx = ubuf->desc; 13068c2ecf20Sopenharmony_ci ubuf = (struct ubuf_info *) ubuf->ctx; 13078c2ecf20Sopenharmony_ci BUG_ON(queue->dealloc_prod - queue->dealloc_cons >= 13088c2ecf20Sopenharmony_ci MAX_PENDING_REQS); 13098c2ecf20Sopenharmony_ci index = pending_index(queue->dealloc_prod); 13108c2ecf20Sopenharmony_ci queue->dealloc_ring[index] = pending_idx; 13118c2ecf20Sopenharmony_ci /* Sync with xenvif_tx_dealloc_action: 13128c2ecf20Sopenharmony_ci * insert idx then incr producer. 13138c2ecf20Sopenharmony_ci */ 13148c2ecf20Sopenharmony_ci smp_wmb(); 13158c2ecf20Sopenharmony_ci queue->dealloc_prod++; 13168c2ecf20Sopenharmony_ci } while (ubuf); 13178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&queue->callback_lock, flags); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (likely(zerocopy_success)) 13208c2ecf20Sopenharmony_ci queue->stats.tx_zerocopy_success++; 13218c2ecf20Sopenharmony_ci else 13228c2ecf20Sopenharmony_ci queue->stats.tx_zerocopy_fail++; 13238c2ecf20Sopenharmony_ci xenvif_skb_zerocopy_complete(queue); 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cistatic inline void xenvif_tx_dealloc_action(struct xenvif_queue *queue) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct gnttab_unmap_grant_ref *gop; 13298c2ecf20Sopenharmony_ci pending_ring_idx_t dc, dp; 13308c2ecf20Sopenharmony_ci u16 pending_idx, pending_idx_release[MAX_PENDING_REQS]; 13318c2ecf20Sopenharmony_ci unsigned int i = 0; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci dc = queue->dealloc_cons; 13348c2ecf20Sopenharmony_ci gop = queue->tx_unmap_ops; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci /* Free up any grants we have finished using */ 13378c2ecf20Sopenharmony_ci do { 13388c2ecf20Sopenharmony_ci dp = queue->dealloc_prod; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* Ensure we see all indices enqueued by all 13418c2ecf20Sopenharmony_ci * xenvif_zerocopy_callback(). 13428c2ecf20Sopenharmony_ci */ 13438c2ecf20Sopenharmony_ci smp_rmb(); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci while (dc != dp) { 13468c2ecf20Sopenharmony_ci BUG_ON(gop - queue->tx_unmap_ops >= MAX_PENDING_REQS); 13478c2ecf20Sopenharmony_ci pending_idx = 13488c2ecf20Sopenharmony_ci queue->dealloc_ring[pending_index(dc++)]; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci pending_idx_release[gop - queue->tx_unmap_ops] = 13518c2ecf20Sopenharmony_ci pending_idx; 13528c2ecf20Sopenharmony_ci queue->pages_to_unmap[gop - queue->tx_unmap_ops] = 13538c2ecf20Sopenharmony_ci queue->mmap_pages[pending_idx]; 13548c2ecf20Sopenharmony_ci gnttab_set_unmap_op(gop, 13558c2ecf20Sopenharmony_ci idx_to_kaddr(queue, pending_idx), 13568c2ecf20Sopenharmony_ci GNTMAP_host_map, 13578c2ecf20Sopenharmony_ci queue->grant_tx_handle[pending_idx]); 13588c2ecf20Sopenharmony_ci xenvif_grant_handle_reset(queue, pending_idx); 13598c2ecf20Sopenharmony_ci ++gop; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci } while (dp != queue->dealloc_prod); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci queue->dealloc_cons = dc; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci if (gop - queue->tx_unmap_ops > 0) { 13678c2ecf20Sopenharmony_ci int ret; 13688c2ecf20Sopenharmony_ci ret = gnttab_unmap_refs(queue->tx_unmap_ops, 13698c2ecf20Sopenharmony_ci NULL, 13708c2ecf20Sopenharmony_ci queue->pages_to_unmap, 13718c2ecf20Sopenharmony_ci gop - queue->tx_unmap_ops); 13728c2ecf20Sopenharmony_ci if (ret) { 13738c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, "Unmap fail: nr_ops %tu ret %d\n", 13748c2ecf20Sopenharmony_ci gop - queue->tx_unmap_ops, ret); 13758c2ecf20Sopenharmony_ci for (i = 0; i < gop - queue->tx_unmap_ops; ++i) { 13768c2ecf20Sopenharmony_ci if (gop[i].status != GNTST_okay) 13778c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 13788c2ecf20Sopenharmony_ci " host_addr: 0x%llx handle: 0x%x status: %d\n", 13798c2ecf20Sopenharmony_ci gop[i].host_addr, 13808c2ecf20Sopenharmony_ci gop[i].handle, 13818c2ecf20Sopenharmony_ci gop[i].status); 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci BUG(); 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci for (i = 0; i < gop - queue->tx_unmap_ops; ++i) 13888c2ecf20Sopenharmony_ci xenvif_idx_release(queue, pending_idx_release[i], 13898c2ecf20Sopenharmony_ci XEN_NETIF_RSP_OKAY); 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci/* Called after netfront has transmitted */ 13948c2ecf20Sopenharmony_ciint xenvif_tx_action(struct xenvif_queue *queue, int budget) 13958c2ecf20Sopenharmony_ci{ 13968c2ecf20Sopenharmony_ci unsigned nr_mops = 0, nr_cops = 0; 13978c2ecf20Sopenharmony_ci int work_done, ret; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (unlikely(!tx_work_todo(queue))) 14008c2ecf20Sopenharmony_ci return 0; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci xenvif_tx_build_gops(queue, budget, &nr_cops, &nr_mops); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci if (nr_cops == 0) 14058c2ecf20Sopenharmony_ci return 0; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci gnttab_batch_copy(queue->tx_copy_ops, nr_cops); 14088c2ecf20Sopenharmony_ci if (nr_mops != 0) { 14098c2ecf20Sopenharmony_ci ret = gnttab_map_refs(queue->tx_map_ops, 14108c2ecf20Sopenharmony_ci NULL, 14118c2ecf20Sopenharmony_ci queue->pages_to_map, 14128c2ecf20Sopenharmony_ci nr_mops); 14138c2ecf20Sopenharmony_ci if (ret) { 14148c2ecf20Sopenharmony_ci unsigned int i; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, "Map fail: nr %u ret %d\n", 14178c2ecf20Sopenharmony_ci nr_mops, ret); 14188c2ecf20Sopenharmony_ci for (i = 0; i < nr_mops; ++i) 14198c2ecf20Sopenharmony_ci WARN_ON_ONCE(queue->tx_map_ops[i].status == 14208c2ecf20Sopenharmony_ci GNTST_okay); 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci work_done = xenvif_tx_submit(queue); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci return work_done; 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic void _make_tx_response(struct xenvif_queue *queue, 14308c2ecf20Sopenharmony_ci const struct xen_netif_tx_request *txp, 14318c2ecf20Sopenharmony_ci unsigned int extra_count, 14328c2ecf20Sopenharmony_ci s8 status) 14338c2ecf20Sopenharmony_ci{ 14348c2ecf20Sopenharmony_ci RING_IDX i = queue->tx.rsp_prod_pvt; 14358c2ecf20Sopenharmony_ci struct xen_netif_tx_response *resp; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci resp = RING_GET_RESPONSE(&queue->tx, i); 14388c2ecf20Sopenharmony_ci resp->id = txp->id; 14398c2ecf20Sopenharmony_ci resp->status = status; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci while (extra_count-- != 0) 14428c2ecf20Sopenharmony_ci RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci queue->tx.rsp_prod_pvt = ++i; 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_cistatic void push_tx_responses(struct xenvif_queue *queue) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci int notify; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify); 14528c2ecf20Sopenharmony_ci if (notify) 14538c2ecf20Sopenharmony_ci notify_remote_via_irq(queue->tx_irq); 14548c2ecf20Sopenharmony_ci} 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_cistatic void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, 14578c2ecf20Sopenharmony_ci s8 status) 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci struct pending_tx_info *pending_tx_info; 14608c2ecf20Sopenharmony_ci pending_ring_idx_t index; 14618c2ecf20Sopenharmony_ci unsigned long flags; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci pending_tx_info = &queue->pending_tx_info[pending_idx]; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci spin_lock_irqsave(&queue->response_lock, flags); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci _make_tx_response(queue, &pending_tx_info->req, 14688c2ecf20Sopenharmony_ci pending_tx_info->extra_count, status); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* Release the pending index before pusing the Tx response so 14718c2ecf20Sopenharmony_ci * its available before a new Tx request is pushed by the 14728c2ecf20Sopenharmony_ci * frontend. 14738c2ecf20Sopenharmony_ci */ 14748c2ecf20Sopenharmony_ci index = pending_index(queue->pending_prod++); 14758c2ecf20Sopenharmony_ci queue->pending_ring[index] = pending_idx; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci push_tx_responses(queue); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&queue->response_lock, flags); 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic void make_tx_response(struct xenvif_queue *queue, 14838c2ecf20Sopenharmony_ci const struct xen_netif_tx_request *txp, 14848c2ecf20Sopenharmony_ci unsigned int extra_count, 14858c2ecf20Sopenharmony_ci s8 status) 14868c2ecf20Sopenharmony_ci{ 14878c2ecf20Sopenharmony_ci unsigned long flags; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci spin_lock_irqsave(&queue->response_lock, flags); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci _make_tx_response(queue, txp, extra_count, status); 14928c2ecf20Sopenharmony_ci push_tx_responses(queue); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&queue->response_lock, flags); 14958c2ecf20Sopenharmony_ci} 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_cistatic void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx) 14988c2ecf20Sopenharmony_ci{ 14998c2ecf20Sopenharmony_ci int ret; 15008c2ecf20Sopenharmony_ci struct gnttab_unmap_grant_ref tx_unmap_op; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci gnttab_set_unmap_op(&tx_unmap_op, 15038c2ecf20Sopenharmony_ci idx_to_kaddr(queue, pending_idx), 15048c2ecf20Sopenharmony_ci GNTMAP_host_map, 15058c2ecf20Sopenharmony_ci queue->grant_tx_handle[pending_idx]); 15068c2ecf20Sopenharmony_ci xenvif_grant_handle_reset(queue, pending_idx); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci ret = gnttab_unmap_refs(&tx_unmap_op, NULL, 15098c2ecf20Sopenharmony_ci &queue->mmap_pages[pending_idx], 1); 15108c2ecf20Sopenharmony_ci if (ret) { 15118c2ecf20Sopenharmony_ci netdev_err(queue->vif->dev, 15128c2ecf20Sopenharmony_ci "Unmap fail: ret: %d pending_idx: %d host_addr: %llx handle: 0x%x status: %d\n", 15138c2ecf20Sopenharmony_ci ret, 15148c2ecf20Sopenharmony_ci pending_idx, 15158c2ecf20Sopenharmony_ci tx_unmap_op.host_addr, 15168c2ecf20Sopenharmony_ci tx_unmap_op.handle, 15178c2ecf20Sopenharmony_ci tx_unmap_op.status); 15188c2ecf20Sopenharmony_ci BUG(); 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_cistatic inline int tx_work_todo(struct xenvif_queue *queue) 15238c2ecf20Sopenharmony_ci{ 15248c2ecf20Sopenharmony_ci if (likely(RING_HAS_UNCONSUMED_REQUESTS(&queue->tx))) 15258c2ecf20Sopenharmony_ci return 1; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci return 0; 15288c2ecf20Sopenharmony_ci} 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_cistatic inline bool tx_dealloc_work_todo(struct xenvif_queue *queue) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci return queue->dealloc_cons != queue->dealloc_prod; 15338c2ecf20Sopenharmony_ci} 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_civoid xenvif_unmap_frontend_data_rings(struct xenvif_queue *queue) 15368c2ecf20Sopenharmony_ci{ 15378c2ecf20Sopenharmony_ci if (queue->tx.sring) 15388c2ecf20Sopenharmony_ci xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(queue->vif), 15398c2ecf20Sopenharmony_ci queue->tx.sring); 15408c2ecf20Sopenharmony_ci if (queue->rx.sring) 15418c2ecf20Sopenharmony_ci xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(queue->vif), 15428c2ecf20Sopenharmony_ci queue->rx.sring); 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ciint xenvif_map_frontend_data_rings(struct xenvif_queue *queue, 15468c2ecf20Sopenharmony_ci grant_ref_t tx_ring_ref, 15478c2ecf20Sopenharmony_ci grant_ref_t rx_ring_ref) 15488c2ecf20Sopenharmony_ci{ 15498c2ecf20Sopenharmony_ci void *addr; 15508c2ecf20Sopenharmony_ci struct xen_netif_tx_sring *txs; 15518c2ecf20Sopenharmony_ci struct xen_netif_rx_sring *rxs; 15528c2ecf20Sopenharmony_ci RING_IDX rsp_prod, req_prod; 15538c2ecf20Sopenharmony_ci int err = -ENOMEM; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), 15568c2ecf20Sopenharmony_ci &tx_ring_ref, 1, &addr); 15578c2ecf20Sopenharmony_ci if (err) 15588c2ecf20Sopenharmony_ci goto err; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci txs = (struct xen_netif_tx_sring *)addr; 15618c2ecf20Sopenharmony_ci rsp_prod = READ_ONCE(txs->rsp_prod); 15628c2ecf20Sopenharmony_ci req_prod = READ_ONCE(txs->req_prod); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci BACK_RING_ATTACH(&queue->tx, txs, rsp_prod, XEN_PAGE_SIZE); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci err = -EIO; 15678c2ecf20Sopenharmony_ci if (req_prod - rsp_prod > RING_SIZE(&queue->tx)) 15688c2ecf20Sopenharmony_ci goto err; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), 15718c2ecf20Sopenharmony_ci &rx_ring_ref, 1, &addr); 15728c2ecf20Sopenharmony_ci if (err) 15738c2ecf20Sopenharmony_ci goto err; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci rxs = (struct xen_netif_rx_sring *)addr; 15768c2ecf20Sopenharmony_ci rsp_prod = READ_ONCE(rxs->rsp_prod); 15778c2ecf20Sopenharmony_ci req_prod = READ_ONCE(rxs->req_prod); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci BACK_RING_ATTACH(&queue->rx, rxs, rsp_prod, XEN_PAGE_SIZE); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci err = -EIO; 15828c2ecf20Sopenharmony_ci if (req_prod - rsp_prod > RING_SIZE(&queue->rx)) 15838c2ecf20Sopenharmony_ci goto err; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci return 0; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cierr: 15888c2ecf20Sopenharmony_ci xenvif_unmap_frontend_data_rings(queue); 15898c2ecf20Sopenharmony_ci return err; 15908c2ecf20Sopenharmony_ci} 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_cistatic bool xenvif_dealloc_kthread_should_stop(struct xenvif_queue *queue) 15938c2ecf20Sopenharmony_ci{ 15948c2ecf20Sopenharmony_ci /* Dealloc thread must remain running until all inflight 15958c2ecf20Sopenharmony_ci * packets complete. 15968c2ecf20Sopenharmony_ci */ 15978c2ecf20Sopenharmony_ci return kthread_should_stop() && 15988c2ecf20Sopenharmony_ci !atomic_read(&queue->inflight_packets); 15998c2ecf20Sopenharmony_ci} 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ciint xenvif_dealloc_kthread(void *data) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci struct xenvif_queue *queue = data; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci for (;;) { 16068c2ecf20Sopenharmony_ci wait_event_interruptible(queue->dealloc_wq, 16078c2ecf20Sopenharmony_ci tx_dealloc_work_todo(queue) || 16088c2ecf20Sopenharmony_ci xenvif_dealloc_kthread_should_stop(queue)); 16098c2ecf20Sopenharmony_ci if (xenvif_dealloc_kthread_should_stop(queue)) 16108c2ecf20Sopenharmony_ci break; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci xenvif_tx_dealloc_action(queue); 16138c2ecf20Sopenharmony_ci cond_resched(); 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci /* Unmap anything remaining*/ 16178c2ecf20Sopenharmony_ci if (tx_dealloc_work_todo(queue)) 16188c2ecf20Sopenharmony_ci xenvif_tx_dealloc_action(queue); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci return 0; 16218c2ecf20Sopenharmony_ci} 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_cistatic void make_ctrl_response(struct xenvif *vif, 16248c2ecf20Sopenharmony_ci const struct xen_netif_ctrl_request *req, 16258c2ecf20Sopenharmony_ci u32 status, u32 data) 16268c2ecf20Sopenharmony_ci{ 16278c2ecf20Sopenharmony_ci RING_IDX idx = vif->ctrl.rsp_prod_pvt; 16288c2ecf20Sopenharmony_ci struct xen_netif_ctrl_response rsp = { 16298c2ecf20Sopenharmony_ci .id = req->id, 16308c2ecf20Sopenharmony_ci .type = req->type, 16318c2ecf20Sopenharmony_ci .status = status, 16328c2ecf20Sopenharmony_ci .data = data, 16338c2ecf20Sopenharmony_ci }; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci *RING_GET_RESPONSE(&vif->ctrl, idx) = rsp; 16368c2ecf20Sopenharmony_ci vif->ctrl.rsp_prod_pvt = ++idx; 16378c2ecf20Sopenharmony_ci} 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cistatic void push_ctrl_response(struct xenvif *vif) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci int notify; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->ctrl, notify); 16448c2ecf20Sopenharmony_ci if (notify) 16458c2ecf20Sopenharmony_ci notify_remote_via_irq(vif->ctrl_irq); 16468c2ecf20Sopenharmony_ci} 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic void process_ctrl_request(struct xenvif *vif, 16498c2ecf20Sopenharmony_ci const struct xen_netif_ctrl_request *req) 16508c2ecf20Sopenharmony_ci{ 16518c2ecf20Sopenharmony_ci u32 status = XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED; 16528c2ecf20Sopenharmony_ci u32 data = 0; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci switch (req->type) { 16558c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_TYPE_SET_HASH_ALGORITHM: 16568c2ecf20Sopenharmony_ci status = xenvif_set_hash_alg(vif, req->data[0]); 16578c2ecf20Sopenharmony_ci break; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_TYPE_GET_HASH_FLAGS: 16608c2ecf20Sopenharmony_ci status = xenvif_get_hash_flags(vif, &data); 16618c2ecf20Sopenharmony_ci break; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_TYPE_SET_HASH_FLAGS: 16648c2ecf20Sopenharmony_ci status = xenvif_set_hash_flags(vif, req->data[0]); 16658c2ecf20Sopenharmony_ci break; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_TYPE_SET_HASH_KEY: 16688c2ecf20Sopenharmony_ci status = xenvif_set_hash_key(vif, req->data[0], 16698c2ecf20Sopenharmony_ci req->data[1]); 16708c2ecf20Sopenharmony_ci break; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_TYPE_GET_HASH_MAPPING_SIZE: 16738c2ecf20Sopenharmony_ci status = XEN_NETIF_CTRL_STATUS_SUCCESS; 16748c2ecf20Sopenharmony_ci data = XEN_NETBK_MAX_HASH_MAPPING_SIZE; 16758c2ecf20Sopenharmony_ci break; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING_SIZE: 16788c2ecf20Sopenharmony_ci status = xenvif_set_hash_mapping_size(vif, 16798c2ecf20Sopenharmony_ci req->data[0]); 16808c2ecf20Sopenharmony_ci break; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci case XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING: 16838c2ecf20Sopenharmony_ci status = xenvif_set_hash_mapping(vif, req->data[0], 16848c2ecf20Sopenharmony_ci req->data[1], 16858c2ecf20Sopenharmony_ci req->data[2]); 16868c2ecf20Sopenharmony_ci break; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci default: 16898c2ecf20Sopenharmony_ci break; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci make_ctrl_response(vif, req, status, data); 16938c2ecf20Sopenharmony_ci push_ctrl_response(vif); 16948c2ecf20Sopenharmony_ci} 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_cistatic void xenvif_ctrl_action(struct xenvif *vif) 16978c2ecf20Sopenharmony_ci{ 16988c2ecf20Sopenharmony_ci for (;;) { 16998c2ecf20Sopenharmony_ci RING_IDX req_prod, req_cons; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci req_prod = vif->ctrl.sring->req_prod; 17028c2ecf20Sopenharmony_ci req_cons = vif->ctrl.req_cons; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci /* Make sure we can see requests before we process them. */ 17058c2ecf20Sopenharmony_ci rmb(); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci if (req_cons == req_prod) 17088c2ecf20Sopenharmony_ci break; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci while (req_cons != req_prod) { 17118c2ecf20Sopenharmony_ci struct xen_netif_ctrl_request req; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci RING_COPY_REQUEST(&vif->ctrl, req_cons, &req); 17148c2ecf20Sopenharmony_ci req_cons++; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci process_ctrl_request(vif, &req); 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci vif->ctrl.req_cons = req_cons; 17208c2ecf20Sopenharmony_ci vif->ctrl.sring->req_event = req_cons + 1; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci} 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_cistatic bool xenvif_ctrl_work_todo(struct xenvif *vif) 17258c2ecf20Sopenharmony_ci{ 17268c2ecf20Sopenharmony_ci if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->ctrl))) 17278c2ecf20Sopenharmony_ci return true; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci return false; 17308c2ecf20Sopenharmony_ci} 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ciirqreturn_t xenvif_ctrl_irq_fn(int irq, void *data) 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci struct xenvif *vif = data; 17358c2ecf20Sopenharmony_ci unsigned int eoi_flag = XEN_EOI_FLAG_SPURIOUS; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci while (xenvif_ctrl_work_todo(vif)) { 17388c2ecf20Sopenharmony_ci xenvif_ctrl_action(vif); 17398c2ecf20Sopenharmony_ci eoi_flag = 0; 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci xen_irq_lateeoi(irq, eoi_flag); 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci return IRQ_HANDLED; 17458c2ecf20Sopenharmony_ci} 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_cistatic int __init netback_init(void) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci int rc = 0; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci if (!xen_domain()) 17528c2ecf20Sopenharmony_ci return -ENODEV; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci /* Allow as many queues as there are CPUs but max. 8 if user has not 17558c2ecf20Sopenharmony_ci * specified a value. 17568c2ecf20Sopenharmony_ci */ 17578c2ecf20Sopenharmony_ci if (xenvif_max_queues == 0) 17588c2ecf20Sopenharmony_ci xenvif_max_queues = min_t(unsigned int, MAX_QUEUES_DEFAULT, 17598c2ecf20Sopenharmony_ci num_online_cpus()); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) { 17628c2ecf20Sopenharmony_ci pr_info("fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n", 17638c2ecf20Sopenharmony_ci fatal_skb_slots, XEN_NETBK_LEGACY_SLOTS_MAX); 17648c2ecf20Sopenharmony_ci fatal_skb_slots = XEN_NETBK_LEGACY_SLOTS_MAX; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci rc = xenvif_xenbus_init(); 17688c2ecf20Sopenharmony_ci if (rc) 17698c2ecf20Sopenharmony_ci goto failed_init; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 17728c2ecf20Sopenharmony_ci xen_netback_dbg_root = debugfs_create_dir("xen-netback", NULL); 17738c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci return 0; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cifailed_init: 17788c2ecf20Sopenharmony_ci return rc; 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_cimodule_init(netback_init); 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cistatic void __exit netback_fini(void) 17848c2ecf20Sopenharmony_ci{ 17858c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 17868c2ecf20Sopenharmony_ci debugfs_remove_recursive(xen_netback_dbg_root); 17878c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 17888c2ecf20Sopenharmony_ci xenvif_xenbus_fini(); 17898c2ecf20Sopenharmony_ci} 17908c2ecf20Sopenharmony_cimodule_exit(netback_fini); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 17938c2ecf20Sopenharmony_ciMODULE_ALIAS("xen-backend:vif"); 1794