162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2016 Citrix Systems Inc. 362306a36Sopenharmony_ci * Copyright (c) 2002-2005, K A Fraser 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or 662306a36Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2 762306a36Sopenharmony_ci * as published by the Free Software Foundation; or, when distributed 862306a36Sopenharmony_ci * separately from the Linux kernel or incorporated into other 962306a36Sopenharmony_ci * software packages, subject to the following license: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 1262306a36Sopenharmony_ci * of this source file (the "Software"), to deal in the Software without 1362306a36Sopenharmony_ci * restriction, including without limitation the rights to use, copy, modify, 1462306a36Sopenharmony_ci * merge, publish, distribute, sublicense, and/or sell copies of the Software, 1562306a36Sopenharmony_ci * and to permit persons to whom the Software is furnished to do so, subject to 1662306a36Sopenharmony_ci * the following conditions: 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1962306a36Sopenharmony_ci * all copies or substantial portions of the Software. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2262306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2362306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2462306a36Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2562306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2662306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2762306a36Sopenharmony_ci * IN THE SOFTWARE. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci#include "common.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/kthread.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <xen/xen.h> 3462306a36Sopenharmony_ci#include <xen/events.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* 3762306a36Sopenharmony_ci * Update the needed ring page slots for the first SKB queued. 3862306a36Sopenharmony_ci * Note that any call sequence outside the RX thread calling this function 3962306a36Sopenharmony_ci * needs to wake up the RX thread via a call of xenvif_kick_thread() 4062306a36Sopenharmony_ci * afterwards in order to avoid a race with putting the thread to sleep. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistatic void xenvif_update_needed_slots(struct xenvif_queue *queue, 4362306a36Sopenharmony_ci const struct sk_buff *skb) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci unsigned int needed = 0; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (skb) { 4862306a36Sopenharmony_ci needed = DIV_ROUND_UP(skb->len, XEN_PAGE_SIZE); 4962306a36Sopenharmony_ci if (skb_is_gso(skb)) 5062306a36Sopenharmony_ci needed++; 5162306a36Sopenharmony_ci if (skb->sw_hash) 5262306a36Sopenharmony_ci needed++; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci WRITE_ONCE(queue->rx_slots_needed, needed); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci RING_IDX prod, cons; 6162306a36Sopenharmony_ci unsigned int needed; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci needed = READ_ONCE(queue->rx_slots_needed); 6462306a36Sopenharmony_ci if (!needed) 6562306a36Sopenharmony_ci return false; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci do { 6862306a36Sopenharmony_ci prod = queue->rx.sring->req_prod; 6962306a36Sopenharmony_ci cons = queue->rx.req_cons; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (prod - cons >= needed) 7262306a36Sopenharmony_ci return true; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci queue->rx.sring->req_event = prod + 1; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* Make sure event is visible before we check prod 7762306a36Sopenharmony_ci * again. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci mb(); 8062306a36Sopenharmony_ci } while (queue->rx.sring->req_prod != prod); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return false; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cibool xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci unsigned long flags; 8862306a36Sopenharmony_ci bool ret = true; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci spin_lock_irqsave(&queue->rx_queue.lock, flags); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (queue->rx_queue_len >= queue->rx_queue_max) { 9362306a36Sopenharmony_ci struct net_device *dev = queue->vif->dev; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci netif_tx_stop_queue(netdev_get_tx_queue(dev, queue->id)); 9662306a36Sopenharmony_ci ret = false; 9762306a36Sopenharmony_ci } else { 9862306a36Sopenharmony_ci if (skb_queue_empty(&queue->rx_queue)) 9962306a36Sopenharmony_ci xenvif_update_needed_slots(queue, skb); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci __skb_queue_tail(&queue->rx_queue, skb); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci queue->rx_queue_len += skb->len; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci spin_unlock_irqrestore(&queue->rx_queue.lock, flags); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return ret; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic struct sk_buff *xenvif_rx_dequeue(struct xenvif_queue *queue) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct sk_buff *skb; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci spin_lock_irq(&queue->rx_queue.lock); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci skb = __skb_dequeue(&queue->rx_queue); 11862306a36Sopenharmony_ci if (skb) { 11962306a36Sopenharmony_ci xenvif_update_needed_slots(queue, skb_peek(&queue->rx_queue)); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci queue->rx_queue_len -= skb->len; 12262306a36Sopenharmony_ci if (queue->rx_queue_len < queue->rx_queue_max) { 12362306a36Sopenharmony_ci struct netdev_queue *txq; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci txq = netdev_get_tx_queue(queue->vif->dev, queue->id); 12662306a36Sopenharmony_ci netif_tx_wake_queue(txq); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci spin_unlock_irq(&queue->rx_queue.lock); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return skb; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void xenvif_rx_queue_purge(struct xenvif_queue *queue) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct sk_buff *skb; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci while ((skb = xenvif_rx_dequeue(queue)) != NULL) 14062306a36Sopenharmony_ci kfree_skb(skb); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void xenvif_rx_queue_drop_expired(struct xenvif_queue *queue) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct sk_buff *skb; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci for (;;) { 14862306a36Sopenharmony_ci skb = skb_peek(&queue->rx_queue); 14962306a36Sopenharmony_ci if (!skb) 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci if (time_before(jiffies, XENVIF_RX_CB(skb)->expires)) 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci xenvif_rx_dequeue(queue); 15462306a36Sopenharmony_ci kfree_skb(skb); 15562306a36Sopenharmony_ci queue->vif->dev->stats.rx_dropped++; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic void xenvif_rx_copy_flush(struct xenvif_queue *queue) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci unsigned int i; 16262306a36Sopenharmony_ci int notify; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci gnttab_batch_copy(queue->rx_copy.op, queue->rx_copy.num); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci for (i = 0; i < queue->rx_copy.num; i++) { 16762306a36Sopenharmony_ci struct gnttab_copy *op; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci op = &queue->rx_copy.op[i]; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* If the copy failed, overwrite the status field in 17262306a36Sopenharmony_ci * the corresponding response. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci if (unlikely(op->status != GNTST_okay)) { 17562306a36Sopenharmony_ci struct xen_netif_rx_response *rsp; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci rsp = RING_GET_RESPONSE(&queue->rx, 17862306a36Sopenharmony_ci queue->rx_copy.idx[i]); 17962306a36Sopenharmony_ci rsp->status = op->status; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci queue->rx_copy.num = 0; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Push responses for all completed packets. */ 18662306a36Sopenharmony_ci RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->rx, notify); 18762306a36Sopenharmony_ci if (notify) 18862306a36Sopenharmony_ci notify_remote_via_irq(queue->rx_irq); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci __skb_queue_purge(queue->rx_copy.completed); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void xenvif_rx_copy_add(struct xenvif_queue *queue, 19462306a36Sopenharmony_ci struct xen_netif_rx_request *req, 19562306a36Sopenharmony_ci unsigned int offset, void *data, size_t len) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct gnttab_copy *op; 19862306a36Sopenharmony_ci struct page *page; 19962306a36Sopenharmony_ci struct xen_page_foreign *foreign; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (queue->rx_copy.num == COPY_BATCH_SIZE) 20262306a36Sopenharmony_ci xenvif_rx_copy_flush(queue); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci op = &queue->rx_copy.op[queue->rx_copy.num]; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci page = virt_to_page(data); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci op->flags = GNTCOPY_dest_gref; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci foreign = xen_page_foreign(page); 21162306a36Sopenharmony_ci if (foreign) { 21262306a36Sopenharmony_ci op->source.domid = foreign->domid; 21362306a36Sopenharmony_ci op->source.u.ref = foreign->gref; 21462306a36Sopenharmony_ci op->flags |= GNTCOPY_source_gref; 21562306a36Sopenharmony_ci } else { 21662306a36Sopenharmony_ci op->source.u.gmfn = virt_to_gfn(data); 21762306a36Sopenharmony_ci op->source.domid = DOMID_SELF; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci op->source.offset = xen_offset_in_page(data); 22162306a36Sopenharmony_ci op->dest.u.ref = req->gref; 22262306a36Sopenharmony_ci op->dest.domid = queue->vif->domid; 22362306a36Sopenharmony_ci op->dest.offset = offset; 22462306a36Sopenharmony_ci op->len = len; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci queue->rx_copy.idx[queue->rx_copy.num] = queue->rx.req_cons; 22762306a36Sopenharmony_ci queue->rx_copy.num++; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic unsigned int xenvif_gso_type(struct sk_buff *skb) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci if (skb_is_gso(skb)) { 23362306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) 23462306a36Sopenharmony_ci return XEN_NETIF_GSO_TYPE_TCPV4; 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci return XEN_NETIF_GSO_TYPE_TCPV6; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci return XEN_NETIF_GSO_TYPE_NONE; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistruct xenvif_pkt_state { 24262306a36Sopenharmony_ci struct sk_buff *skb; 24362306a36Sopenharmony_ci size_t remaining_len; 24462306a36Sopenharmony_ci struct sk_buff *frag_iter; 24562306a36Sopenharmony_ci int frag; /* frag == -1 => frag_iter->head */ 24662306a36Sopenharmony_ci unsigned int frag_offset; 24762306a36Sopenharmony_ci struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; 24862306a36Sopenharmony_ci unsigned int extra_count; 24962306a36Sopenharmony_ci unsigned int slot; 25062306a36Sopenharmony_ci}; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic void xenvif_rx_next_skb(struct xenvif_queue *queue, 25362306a36Sopenharmony_ci struct xenvif_pkt_state *pkt) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct sk_buff *skb; 25662306a36Sopenharmony_ci unsigned int gso_type; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci skb = xenvif_rx_dequeue(queue); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci queue->stats.tx_bytes += skb->len; 26162306a36Sopenharmony_ci queue->stats.tx_packets++; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Reset packet state. */ 26462306a36Sopenharmony_ci memset(pkt, 0, sizeof(struct xenvif_pkt_state)); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci pkt->skb = skb; 26762306a36Sopenharmony_ci pkt->frag_iter = skb; 26862306a36Sopenharmony_ci pkt->remaining_len = skb->len; 26962306a36Sopenharmony_ci pkt->frag = -1; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci gso_type = xenvif_gso_type(skb); 27262306a36Sopenharmony_ci if ((1 << gso_type) & queue->vif->gso_mask) { 27362306a36Sopenharmony_ci struct xen_netif_extra_info *extra; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci extra = &pkt->extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci extra->u.gso.type = gso_type; 27862306a36Sopenharmony_ci extra->u.gso.size = skb_shinfo(skb)->gso_size; 27962306a36Sopenharmony_ci extra->u.gso.pad = 0; 28062306a36Sopenharmony_ci extra->u.gso.features = 0; 28162306a36Sopenharmony_ci extra->type = XEN_NETIF_EXTRA_TYPE_GSO; 28262306a36Sopenharmony_ci extra->flags = 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci pkt->extra_count++; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (queue->vif->xdp_headroom) { 28862306a36Sopenharmony_ci struct xen_netif_extra_info *extra; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci extra = &pkt->extras[XEN_NETIF_EXTRA_TYPE_XDP - 1]; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci memset(extra, 0, sizeof(struct xen_netif_extra_info)); 29362306a36Sopenharmony_ci extra->u.xdp.headroom = queue->vif->xdp_headroom; 29462306a36Sopenharmony_ci extra->type = XEN_NETIF_EXTRA_TYPE_XDP; 29562306a36Sopenharmony_ci extra->flags = 0; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci pkt->extra_count++; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (skb->sw_hash) { 30162306a36Sopenharmony_ci struct xen_netif_extra_info *extra; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci extra = &pkt->extras[XEN_NETIF_EXTRA_TYPE_HASH - 1]; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci extra->u.hash.algorithm = 30662306a36Sopenharmony_ci XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (skb->l4_hash) 30962306a36Sopenharmony_ci extra->u.hash.type = 31062306a36Sopenharmony_ci skb->protocol == htons(ETH_P_IP) ? 31162306a36Sopenharmony_ci _XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP : 31262306a36Sopenharmony_ci _XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP; 31362306a36Sopenharmony_ci else 31462306a36Sopenharmony_ci extra->u.hash.type = 31562306a36Sopenharmony_ci skb->protocol == htons(ETH_P_IP) ? 31662306a36Sopenharmony_ci _XEN_NETIF_CTRL_HASH_TYPE_IPV4 : 31762306a36Sopenharmony_ci _XEN_NETIF_CTRL_HASH_TYPE_IPV6; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci *(uint32_t *)extra->u.hash.value = skb_get_hash_raw(skb); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci extra->type = XEN_NETIF_EXTRA_TYPE_HASH; 32262306a36Sopenharmony_ci extra->flags = 0; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci pkt->extra_count++; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void xenvif_rx_complete(struct xenvif_queue *queue, 32962306a36Sopenharmony_ci struct xenvif_pkt_state *pkt) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci /* All responses are ready to be pushed. */ 33262306a36Sopenharmony_ci queue->rx.rsp_prod_pvt = queue->rx.req_cons; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci __skb_queue_tail(queue->rx_copy.completed, pkt->skb); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic void xenvif_rx_next_frag(struct xenvif_pkt_state *pkt) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct sk_buff *frag_iter = pkt->frag_iter; 34062306a36Sopenharmony_ci unsigned int nr_frags = skb_shinfo(frag_iter)->nr_frags; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci pkt->frag++; 34362306a36Sopenharmony_ci pkt->frag_offset = 0; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (pkt->frag >= nr_frags) { 34662306a36Sopenharmony_ci if (frag_iter == pkt->skb) 34762306a36Sopenharmony_ci pkt->frag_iter = skb_shinfo(frag_iter)->frag_list; 34862306a36Sopenharmony_ci else 34962306a36Sopenharmony_ci pkt->frag_iter = frag_iter->next; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci pkt->frag = -1; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void xenvif_rx_next_chunk(struct xenvif_queue *queue, 35662306a36Sopenharmony_ci struct xenvif_pkt_state *pkt, 35762306a36Sopenharmony_ci unsigned int offset, void **data, 35862306a36Sopenharmony_ci size_t *len) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct sk_buff *frag_iter = pkt->frag_iter; 36162306a36Sopenharmony_ci void *frag_data; 36262306a36Sopenharmony_ci size_t frag_len, chunk_len; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci BUG_ON(!frag_iter); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (pkt->frag == -1) { 36762306a36Sopenharmony_ci frag_data = frag_iter->data; 36862306a36Sopenharmony_ci frag_len = skb_headlen(frag_iter); 36962306a36Sopenharmony_ci } else { 37062306a36Sopenharmony_ci skb_frag_t *frag = &skb_shinfo(frag_iter)->frags[pkt->frag]; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci frag_data = skb_frag_address(frag); 37362306a36Sopenharmony_ci frag_len = skb_frag_size(frag); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci frag_data += pkt->frag_offset; 37762306a36Sopenharmony_ci frag_len -= pkt->frag_offset; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci chunk_len = min_t(size_t, frag_len, XEN_PAGE_SIZE - offset); 38062306a36Sopenharmony_ci chunk_len = min_t(size_t, chunk_len, XEN_PAGE_SIZE - 38162306a36Sopenharmony_ci xen_offset_in_page(frag_data)); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci pkt->frag_offset += chunk_len; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* Advance to next frag? */ 38662306a36Sopenharmony_ci if (frag_len == chunk_len) 38762306a36Sopenharmony_ci xenvif_rx_next_frag(pkt); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci *data = frag_data; 39062306a36Sopenharmony_ci *len = chunk_len; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic void xenvif_rx_data_slot(struct xenvif_queue *queue, 39462306a36Sopenharmony_ci struct xenvif_pkt_state *pkt, 39562306a36Sopenharmony_ci struct xen_netif_rx_request *req, 39662306a36Sopenharmony_ci struct xen_netif_rx_response *rsp) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci unsigned int offset = queue->vif->xdp_headroom; 39962306a36Sopenharmony_ci unsigned int flags; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci do { 40262306a36Sopenharmony_ci size_t len; 40362306a36Sopenharmony_ci void *data; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci xenvif_rx_next_chunk(queue, pkt, offset, &data, &len); 40662306a36Sopenharmony_ci xenvif_rx_copy_add(queue, req, offset, data, len); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci offset += len; 40962306a36Sopenharmony_ci pkt->remaining_len -= len; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci } while (offset < XEN_PAGE_SIZE && pkt->remaining_len > 0); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (pkt->remaining_len > 0) 41462306a36Sopenharmony_ci flags = XEN_NETRXF_more_data; 41562306a36Sopenharmony_ci else 41662306a36Sopenharmony_ci flags = 0; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (pkt->slot == 0) { 41962306a36Sopenharmony_ci struct sk_buff *skb = pkt->skb; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) 42262306a36Sopenharmony_ci flags |= XEN_NETRXF_csum_blank | 42362306a36Sopenharmony_ci XEN_NETRXF_data_validated; 42462306a36Sopenharmony_ci else if (skb->ip_summed == CHECKSUM_UNNECESSARY) 42562306a36Sopenharmony_ci flags |= XEN_NETRXF_data_validated; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (pkt->extra_count != 0) 42862306a36Sopenharmony_ci flags |= XEN_NETRXF_extra_info; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci rsp->offset = 0; 43262306a36Sopenharmony_ci rsp->flags = flags; 43362306a36Sopenharmony_ci rsp->id = req->id; 43462306a36Sopenharmony_ci rsp->status = (s16)offset; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic void xenvif_rx_extra_slot(struct xenvif_queue *queue, 43862306a36Sopenharmony_ci struct xenvif_pkt_state *pkt, 43962306a36Sopenharmony_ci struct xen_netif_rx_request *req, 44062306a36Sopenharmony_ci struct xen_netif_rx_response *rsp) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct xen_netif_extra_info *extra = (void *)rsp; 44362306a36Sopenharmony_ci unsigned int i; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci pkt->extra_count--; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pkt->extras); i++) { 44862306a36Sopenharmony_ci if (pkt->extras[i].type) { 44962306a36Sopenharmony_ci *extra = pkt->extras[i]; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (pkt->extra_count != 0) 45262306a36Sopenharmony_ci extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci pkt->extras[i].type = 0; 45562306a36Sopenharmony_ci return; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci BUG(); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void xenvif_rx_skb(struct xenvif_queue *queue) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct xenvif_pkt_state pkt; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci xenvif_rx_next_skb(queue, &pkt); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci queue->last_rx_time = jiffies; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci do { 47062306a36Sopenharmony_ci struct xen_netif_rx_request *req; 47162306a36Sopenharmony_ci struct xen_netif_rx_response *rsp; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons); 47462306a36Sopenharmony_ci rsp = RING_GET_RESPONSE(&queue->rx, queue->rx.req_cons); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* Extras must go after the first data slot */ 47762306a36Sopenharmony_ci if (pkt.slot != 0 && pkt.extra_count != 0) 47862306a36Sopenharmony_ci xenvif_rx_extra_slot(queue, &pkt, req, rsp); 47962306a36Sopenharmony_ci else 48062306a36Sopenharmony_ci xenvif_rx_data_slot(queue, &pkt, req, rsp); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci queue->rx.req_cons++; 48362306a36Sopenharmony_ci pkt.slot++; 48462306a36Sopenharmony_ci } while (pkt.remaining_len > 0 || pkt.extra_count != 0); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci xenvif_rx_complete(queue, &pkt); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci#define RX_BATCH_SIZE 64 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic void xenvif_rx_action(struct xenvif_queue *queue) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct sk_buff_head completed_skbs; 49462306a36Sopenharmony_ci unsigned int work_done = 0; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci __skb_queue_head_init(&completed_skbs); 49762306a36Sopenharmony_ci queue->rx_copy.completed = &completed_skbs; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci while (xenvif_rx_ring_slots_available(queue) && 50062306a36Sopenharmony_ci !skb_queue_empty(&queue->rx_queue) && 50162306a36Sopenharmony_ci work_done < RX_BATCH_SIZE) { 50262306a36Sopenharmony_ci xenvif_rx_skb(queue); 50362306a36Sopenharmony_ci work_done++; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* Flush any pending copies and complete all skbs. */ 50762306a36Sopenharmony_ci xenvif_rx_copy_flush(queue); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic RING_IDX xenvif_rx_queue_slots(const struct xenvif_queue *queue) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci RING_IDX prod, cons; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci prod = queue->rx.sring->req_prod; 51562306a36Sopenharmony_ci cons = queue->rx.req_cons; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return prod - cons; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic bool xenvif_rx_queue_stalled(const struct xenvif_queue *queue) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci unsigned int needed = READ_ONCE(queue->rx_slots_needed); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci return !queue->stalled && 52562306a36Sopenharmony_ci xenvif_rx_queue_slots(queue) < needed && 52662306a36Sopenharmony_ci time_after(jiffies, 52762306a36Sopenharmony_ci queue->last_rx_time + queue->vif->stall_timeout); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic bool xenvif_rx_queue_ready(struct xenvif_queue *queue) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci unsigned int needed = READ_ONCE(queue->rx_slots_needed); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return queue->stalled && xenvif_rx_queue_slots(queue) >= needed; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cibool xenvif_have_rx_work(struct xenvif_queue *queue, bool test_kthread) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci return xenvif_rx_ring_slots_available(queue) || 54062306a36Sopenharmony_ci (queue->vif->stall_timeout && 54162306a36Sopenharmony_ci (xenvif_rx_queue_stalled(queue) || 54262306a36Sopenharmony_ci xenvif_rx_queue_ready(queue))) || 54362306a36Sopenharmony_ci (test_kthread && kthread_should_stop()) || 54462306a36Sopenharmony_ci queue->vif->disabled; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic long xenvif_rx_queue_timeout(struct xenvif_queue *queue) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct sk_buff *skb; 55062306a36Sopenharmony_ci long timeout; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci skb = skb_peek(&queue->rx_queue); 55362306a36Sopenharmony_ci if (!skb) 55462306a36Sopenharmony_ci return MAX_SCHEDULE_TIMEOUT; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci timeout = XENVIF_RX_CB(skb)->expires - jiffies; 55762306a36Sopenharmony_ci return timeout < 0 ? 0 : timeout; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/* Wait until the guest Rx thread has work. 56162306a36Sopenharmony_ci * 56262306a36Sopenharmony_ci * The timeout needs to be adjusted based on the current head of the 56362306a36Sopenharmony_ci * queue (and not just the head at the beginning). In particular, if 56462306a36Sopenharmony_ci * the queue is initially empty an infinite timeout is used and this 56562306a36Sopenharmony_ci * needs to be reduced when a skb is queued. 56662306a36Sopenharmony_ci * 56762306a36Sopenharmony_ci * This cannot be done with wait_event_timeout() because it only 56862306a36Sopenharmony_ci * calculates the timeout once. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_cistatic void xenvif_wait_for_rx_work(struct xenvif_queue *queue) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci DEFINE_WAIT(wait); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (xenvif_have_rx_work(queue, true)) 57562306a36Sopenharmony_ci return; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci for (;;) { 57862306a36Sopenharmony_ci long ret; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci prepare_to_wait(&queue->wq, &wait, TASK_INTERRUPTIBLE); 58162306a36Sopenharmony_ci if (xenvif_have_rx_work(queue, true)) 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci if (atomic_fetch_andnot(NETBK_RX_EOI | NETBK_COMMON_EOI, 58462306a36Sopenharmony_ci &queue->eoi_pending) & 58562306a36Sopenharmony_ci (NETBK_RX_EOI | NETBK_COMMON_EOI)) 58662306a36Sopenharmony_ci xen_irq_lateeoi(queue->rx_irq, 0); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci ret = schedule_timeout(xenvif_rx_queue_timeout(queue)); 58962306a36Sopenharmony_ci if (!ret) 59062306a36Sopenharmony_ci break; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci finish_wait(&queue->wq, &wait); 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic void xenvif_queue_carrier_off(struct xenvif_queue *queue) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct xenvif *vif = queue->vif; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci queue->stalled = true; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* At least one queue has stalled? Disable the carrier. */ 60262306a36Sopenharmony_ci spin_lock(&vif->lock); 60362306a36Sopenharmony_ci if (vif->stalled_queues++ == 0) { 60462306a36Sopenharmony_ci netdev_info(vif->dev, "Guest Rx stalled"); 60562306a36Sopenharmony_ci netif_carrier_off(vif->dev); 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci spin_unlock(&vif->lock); 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic void xenvif_queue_carrier_on(struct xenvif_queue *queue) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct xenvif *vif = queue->vif; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci queue->last_rx_time = jiffies; /* Reset Rx stall detection. */ 61562306a36Sopenharmony_ci queue->stalled = false; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* All queues are ready? Enable the carrier. */ 61862306a36Sopenharmony_ci spin_lock(&vif->lock); 61962306a36Sopenharmony_ci if (--vif->stalled_queues == 0) { 62062306a36Sopenharmony_ci netdev_info(vif->dev, "Guest Rx ready"); 62162306a36Sopenharmony_ci netif_carrier_on(vif->dev); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci spin_unlock(&vif->lock); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ciint xenvif_kthread_guest_rx(void *data) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct xenvif_queue *queue = data; 62962306a36Sopenharmony_ci struct xenvif *vif = queue->vif; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (!vif->stall_timeout) 63262306a36Sopenharmony_ci xenvif_queue_carrier_on(queue); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci for (;;) { 63562306a36Sopenharmony_ci xenvif_wait_for_rx_work(queue); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (kthread_should_stop()) 63862306a36Sopenharmony_ci break; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* This frontend is found to be rogue, disable it in 64162306a36Sopenharmony_ci * kthread context. Currently this is only set when 64262306a36Sopenharmony_ci * netback finds out frontend sends malformed packet, 64362306a36Sopenharmony_ci * but we cannot disable the interface in softirq 64462306a36Sopenharmony_ci * context so we defer it here, if this thread is 64562306a36Sopenharmony_ci * associated with queue 0. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ci if (unlikely(vif->disabled && queue->id == 0)) { 64862306a36Sopenharmony_ci xenvif_carrier_off(vif); 64962306a36Sopenharmony_ci break; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (!skb_queue_empty(&queue->rx_queue)) 65362306a36Sopenharmony_ci xenvif_rx_action(queue); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* If the guest hasn't provided any Rx slots for a 65662306a36Sopenharmony_ci * while it's probably not responsive, drop the 65762306a36Sopenharmony_ci * carrier so packets are dropped earlier. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_ci if (vif->stall_timeout) { 66062306a36Sopenharmony_ci if (xenvif_rx_queue_stalled(queue)) 66162306a36Sopenharmony_ci xenvif_queue_carrier_off(queue); 66262306a36Sopenharmony_ci else if (xenvif_rx_queue_ready(queue)) 66362306a36Sopenharmony_ci xenvif_queue_carrier_on(queue); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* Queued packets may have foreign pages from other 66762306a36Sopenharmony_ci * domains. These cannot be queued indefinitely as 66862306a36Sopenharmony_ci * this would starve guests of grant refs and transmit 66962306a36Sopenharmony_ci * slots. 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ci xenvif_rx_queue_drop_expired(queue); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci cond_resched(); 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* Bin any remaining skbs */ 67762306a36Sopenharmony_ci xenvif_rx_queue_purge(queue); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return 0; 68062306a36Sopenharmony_ci} 681