162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 - 2019 Cambridge Greys Limited 462306a36Sopenharmony_ci * Copyright (C) 2011 - 2014 Cisco Systems Inc 562306a36Sopenharmony_ci * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 662306a36Sopenharmony_ci * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 762306a36Sopenharmony_ci * James Leu (jleu@mindspring.net). 862306a36Sopenharmony_ci * Copyright (C) 2001 by various other people who didn't put their name here. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/memblock.h> 1262306a36Sopenharmony_ci#include <linux/etherdevice.h> 1362306a36Sopenharmony_ci#include <linux/ethtool.h> 1462306a36Sopenharmony_ci#include <linux/inetdevice.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/list.h> 1762306a36Sopenharmony_ci#include <linux/netdevice.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/rtnetlink.h> 2062306a36Sopenharmony_ci#include <linux/skbuff.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/interrupt.h> 2362306a36Sopenharmony_ci#include <linux/firmware.h> 2462306a36Sopenharmony_ci#include <linux/fs.h> 2562306a36Sopenharmony_ci#include <uapi/linux/filter.h> 2662306a36Sopenharmony_ci#include <init.h> 2762306a36Sopenharmony_ci#include <irq_kern.h> 2862306a36Sopenharmony_ci#include <irq_user.h> 2962306a36Sopenharmony_ci#include <net_kern.h> 3062306a36Sopenharmony_ci#include <os.h> 3162306a36Sopenharmony_ci#include "mconsole_kern.h" 3262306a36Sopenharmony_ci#include "vector_user.h" 3362306a36Sopenharmony_ci#include "vector_kern.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * Adapted from network devices with the following major changes: 3762306a36Sopenharmony_ci * All transports are static - simplifies the code significantly 3862306a36Sopenharmony_ci * Multiple FDs/IRQs per device 3962306a36Sopenharmony_ci * Vector IO optionally used for read/write, falling back to legacy 4062306a36Sopenharmony_ci * based on configuration and/or availability 4162306a36Sopenharmony_ci * Configuration is no longer positional - L2TPv3 and GRE require up to 4262306a36Sopenharmony_ci * 10 parameters, passing this as positional is not fit for purpose. 4362306a36Sopenharmony_ci * Only socket transports are supported 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define DRIVER_NAME "uml-vector" 4862306a36Sopenharmony_cistruct vector_cmd_line_arg { 4962306a36Sopenharmony_ci struct list_head list; 5062306a36Sopenharmony_ci int unit; 5162306a36Sopenharmony_ci char *arguments; 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct vector_device { 5562306a36Sopenharmony_ci struct list_head list; 5662306a36Sopenharmony_ci struct net_device *dev; 5762306a36Sopenharmony_ci struct platform_device pdev; 5862306a36Sopenharmony_ci int unit; 5962306a36Sopenharmony_ci int opened; 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic LIST_HEAD(vec_cmd_line); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(vector_devices_lock); 6562306a36Sopenharmony_cistatic LIST_HEAD(vector_devices); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int driver_registered; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void vector_eth_configure(int n, struct arglist *def); 7062306a36Sopenharmony_cistatic int vector_mmsg_rx(struct vector_private *vp, int budget); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* Argument accessors to set variables (and/or set default values) 7362306a36Sopenharmony_ci * mtu, buffer sizing, default headroom, etc 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define DEFAULT_HEADROOM 2 7762306a36Sopenharmony_ci#define SAFETY_MARGIN 32 7862306a36Sopenharmony_ci#define DEFAULT_VECTOR_SIZE 64 7962306a36Sopenharmony_ci#define TX_SMALL_PACKET 128 8062306a36Sopenharmony_ci#define MAX_IOV_SIZE (MAX_SKB_FRAGS + 1) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic const struct { 8362306a36Sopenharmony_ci const char string[ETH_GSTRING_LEN]; 8462306a36Sopenharmony_ci} ethtool_stats_keys[] = { 8562306a36Sopenharmony_ci { "rx_queue_max" }, 8662306a36Sopenharmony_ci { "rx_queue_running_average" }, 8762306a36Sopenharmony_ci { "tx_queue_max" }, 8862306a36Sopenharmony_ci { "tx_queue_running_average" }, 8962306a36Sopenharmony_ci { "rx_encaps_errors" }, 9062306a36Sopenharmony_ci { "tx_timeout_count" }, 9162306a36Sopenharmony_ci { "tx_restart_queue" }, 9262306a36Sopenharmony_ci { "tx_kicks" }, 9362306a36Sopenharmony_ci { "tx_flow_control_xon" }, 9462306a36Sopenharmony_ci { "tx_flow_control_xoff" }, 9562306a36Sopenharmony_ci { "rx_csum_offload_good" }, 9662306a36Sopenharmony_ci { "rx_csum_offload_errors"}, 9762306a36Sopenharmony_ci { "sg_ok"}, 9862306a36Sopenharmony_ci { "sg_linearized"}, 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define VECTOR_NUM_STATS ARRAY_SIZE(ethtool_stats_keys) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void vector_reset_stats(struct vector_private *vp) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci vp->estats.rx_queue_max = 0; 10662306a36Sopenharmony_ci vp->estats.rx_queue_running_average = 0; 10762306a36Sopenharmony_ci vp->estats.tx_queue_max = 0; 10862306a36Sopenharmony_ci vp->estats.tx_queue_running_average = 0; 10962306a36Sopenharmony_ci vp->estats.rx_encaps_errors = 0; 11062306a36Sopenharmony_ci vp->estats.tx_timeout_count = 0; 11162306a36Sopenharmony_ci vp->estats.tx_restart_queue = 0; 11262306a36Sopenharmony_ci vp->estats.tx_kicks = 0; 11362306a36Sopenharmony_ci vp->estats.tx_flow_control_xon = 0; 11462306a36Sopenharmony_ci vp->estats.tx_flow_control_xoff = 0; 11562306a36Sopenharmony_ci vp->estats.sg_ok = 0; 11662306a36Sopenharmony_ci vp->estats.sg_linearized = 0; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int get_mtu(struct arglist *def) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci char *mtu = uml_vector_fetch_arg(def, "mtu"); 12262306a36Sopenharmony_ci long result; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (mtu != NULL) { 12562306a36Sopenharmony_ci if (kstrtoul(mtu, 10, &result) == 0) 12662306a36Sopenharmony_ci if ((result < (1 << 16) - 1) && (result >= 576)) 12762306a36Sopenharmony_ci return result; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci return ETH_MAX_PACKET; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic char *get_bpf_file(struct arglist *def) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return uml_vector_fetch_arg(def, "bpffile"); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic bool get_bpf_flash(struct arglist *def) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci char *allow = uml_vector_fetch_arg(def, "bpfflash"); 14062306a36Sopenharmony_ci long result; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (allow != NULL) { 14362306a36Sopenharmony_ci if (kstrtoul(allow, 10, &result) == 0) 14462306a36Sopenharmony_ci return (allow > 0); 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci return false; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int get_depth(struct arglist *def) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci char *mtu = uml_vector_fetch_arg(def, "depth"); 15262306a36Sopenharmony_ci long result; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (mtu != NULL) { 15562306a36Sopenharmony_ci if (kstrtoul(mtu, 10, &result) == 0) 15662306a36Sopenharmony_ci return result; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci return DEFAULT_VECTOR_SIZE; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int get_headroom(struct arglist *def) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci char *mtu = uml_vector_fetch_arg(def, "headroom"); 16462306a36Sopenharmony_ci long result; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (mtu != NULL) { 16762306a36Sopenharmony_ci if (kstrtoul(mtu, 10, &result) == 0) 16862306a36Sopenharmony_ci return result; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci return DEFAULT_HEADROOM; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int get_req_size(struct arglist *def) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci char *gro = uml_vector_fetch_arg(def, "gro"); 17662306a36Sopenharmony_ci long result; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (gro != NULL) { 17962306a36Sopenharmony_ci if (kstrtoul(gro, 10, &result) == 0) { 18062306a36Sopenharmony_ci if (result > 0) 18162306a36Sopenharmony_ci return 65536; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci return get_mtu(def) + ETH_HEADER_OTHER + 18562306a36Sopenharmony_ci get_headroom(def) + SAFETY_MARGIN; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int get_transport_options(struct arglist *def) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci char *transport = uml_vector_fetch_arg(def, "transport"); 19262306a36Sopenharmony_ci char *vector = uml_vector_fetch_arg(def, "vec"); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci int vec_rx = VECTOR_RX; 19562306a36Sopenharmony_ci int vec_tx = VECTOR_TX; 19662306a36Sopenharmony_ci long parsed; 19762306a36Sopenharmony_ci int result = 0; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (transport == NULL) 20062306a36Sopenharmony_ci return -EINVAL; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (vector != NULL) { 20362306a36Sopenharmony_ci if (kstrtoul(vector, 10, &parsed) == 0) { 20462306a36Sopenharmony_ci if (parsed == 0) { 20562306a36Sopenharmony_ci vec_rx = 0; 20662306a36Sopenharmony_ci vec_tx = 0; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (get_bpf_flash(def)) 21262306a36Sopenharmony_ci result = VECTOR_BPF_FLASH; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) 21562306a36Sopenharmony_ci return result; 21662306a36Sopenharmony_ci if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) 21762306a36Sopenharmony_ci return (result | vec_rx | VECTOR_BPF); 21862306a36Sopenharmony_ci if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) 21962306a36Sopenharmony_ci return (result | vec_rx | vec_tx | VECTOR_QDISC_BYPASS); 22062306a36Sopenharmony_ci return (result | vec_rx | vec_tx); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/* A mini-buffer for packet drop read 22562306a36Sopenharmony_ci * All of our supported transports are datagram oriented and we always 22662306a36Sopenharmony_ci * read using recvmsg or recvmmsg. If we pass a buffer which is smaller 22762306a36Sopenharmony_ci * than the packet size it still counts as full packet read and will 22862306a36Sopenharmony_ci * clean the incoming stream to keep sigio/epoll happy 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci#define DROP_BUFFER_SIZE 32 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic char *drop_buffer; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* Array backed queues optimized for bulk enqueue/dequeue and 23662306a36Sopenharmony_ci * 1:N (small values of N) or 1:1 enqueuer/dequeuer ratios. 23762306a36Sopenharmony_ci * For more details and full design rationale see 23862306a36Sopenharmony_ci * http://foswiki.cambridgegreys.com/Main/EatYourTailAndEnjoyIt 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* 24362306a36Sopenharmony_ci * Advance the mmsg queue head by n = advance. Resets the queue to 24462306a36Sopenharmony_ci * maximum enqueue/dequeue-at-once capacity if possible. Called by 24562306a36Sopenharmony_ci * dequeuers. Caller must hold the head_lock! 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int vector_advancehead(struct vector_queue *qi, int advance) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci int queue_depth; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci qi->head = 25362306a36Sopenharmony_ci (qi->head + advance) 25462306a36Sopenharmony_ci % qi->max_depth; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci spin_lock(&qi->tail_lock); 25862306a36Sopenharmony_ci qi->queue_depth -= advance; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* we are at 0, use this to 26162306a36Sopenharmony_ci * reset head and tail so we can use max size vectors 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (qi->queue_depth == 0) { 26562306a36Sopenharmony_ci qi->head = 0; 26662306a36Sopenharmony_ci qi->tail = 0; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci queue_depth = qi->queue_depth; 26962306a36Sopenharmony_ci spin_unlock(&qi->tail_lock); 27062306a36Sopenharmony_ci return queue_depth; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* Advance the queue tail by n = advance. 27462306a36Sopenharmony_ci * This is called by enqueuers which should hold the 27562306a36Sopenharmony_ci * head lock already 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int vector_advancetail(struct vector_queue *qi, int advance) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci int queue_depth; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci qi->tail = 28362306a36Sopenharmony_ci (qi->tail + advance) 28462306a36Sopenharmony_ci % qi->max_depth; 28562306a36Sopenharmony_ci spin_lock(&qi->head_lock); 28662306a36Sopenharmony_ci qi->queue_depth += advance; 28762306a36Sopenharmony_ci queue_depth = qi->queue_depth; 28862306a36Sopenharmony_ci spin_unlock(&qi->head_lock); 28962306a36Sopenharmony_ci return queue_depth; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic int prep_msg(struct vector_private *vp, 29362306a36Sopenharmony_ci struct sk_buff *skb, 29462306a36Sopenharmony_ci struct iovec *iov) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci int iov_index = 0; 29762306a36Sopenharmony_ci int nr_frags, frag; 29862306a36Sopenharmony_ci skb_frag_t *skb_frag; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 30162306a36Sopenharmony_ci if (nr_frags > MAX_IOV_SIZE) { 30262306a36Sopenharmony_ci if (skb_linearize(skb) != 0) 30362306a36Sopenharmony_ci goto drop; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci if (vp->header_size > 0) { 30662306a36Sopenharmony_ci iov[iov_index].iov_len = vp->header_size; 30762306a36Sopenharmony_ci vp->form_header(iov[iov_index].iov_base, skb, vp); 30862306a36Sopenharmony_ci iov_index++; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci iov[iov_index].iov_base = skb->data; 31162306a36Sopenharmony_ci if (nr_frags > 0) { 31262306a36Sopenharmony_ci iov[iov_index].iov_len = skb->len - skb->data_len; 31362306a36Sopenharmony_ci vp->estats.sg_ok++; 31462306a36Sopenharmony_ci } else 31562306a36Sopenharmony_ci iov[iov_index].iov_len = skb->len; 31662306a36Sopenharmony_ci iov_index++; 31762306a36Sopenharmony_ci for (frag = 0; frag < nr_frags; frag++) { 31862306a36Sopenharmony_ci skb_frag = &skb_shinfo(skb)->frags[frag]; 31962306a36Sopenharmony_ci iov[iov_index].iov_base = skb_frag_address_safe(skb_frag); 32062306a36Sopenharmony_ci iov[iov_index].iov_len = skb_frag_size(skb_frag); 32162306a36Sopenharmony_ci iov_index++; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci return iov_index; 32462306a36Sopenharmony_cidrop: 32562306a36Sopenharmony_ci return -1; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci/* 32862306a36Sopenharmony_ci * Generic vector enqueue with support for forming headers using transport 32962306a36Sopenharmony_ci * specific callback. Allows GRE, L2TPv3, RAW and other transports 33062306a36Sopenharmony_ci * to use a common enqueue procedure in vector mode 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int vector_enqueue(struct vector_queue *qi, struct sk_buff *skb) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(qi->dev); 33662306a36Sopenharmony_ci int queue_depth; 33762306a36Sopenharmony_ci int packet_len; 33862306a36Sopenharmony_ci struct mmsghdr *mmsg_vector = qi->mmsg_vector; 33962306a36Sopenharmony_ci int iov_count; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci spin_lock(&qi->tail_lock); 34262306a36Sopenharmony_ci spin_lock(&qi->head_lock); 34362306a36Sopenharmony_ci queue_depth = qi->queue_depth; 34462306a36Sopenharmony_ci spin_unlock(&qi->head_lock); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (skb) 34762306a36Sopenharmony_ci packet_len = skb->len; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (queue_depth < qi->max_depth) { 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci *(qi->skbuff_vector + qi->tail) = skb; 35262306a36Sopenharmony_ci mmsg_vector += qi->tail; 35362306a36Sopenharmony_ci iov_count = prep_msg( 35462306a36Sopenharmony_ci vp, 35562306a36Sopenharmony_ci skb, 35662306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_iov 35762306a36Sopenharmony_ci ); 35862306a36Sopenharmony_ci if (iov_count < 1) 35962306a36Sopenharmony_ci goto drop; 36062306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_iovlen = iov_count; 36162306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_name = vp->fds->remote_addr; 36262306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_namelen = vp->fds->remote_addr_size; 36362306a36Sopenharmony_ci queue_depth = vector_advancetail(qi, 1); 36462306a36Sopenharmony_ci } else 36562306a36Sopenharmony_ci goto drop; 36662306a36Sopenharmony_ci spin_unlock(&qi->tail_lock); 36762306a36Sopenharmony_ci return queue_depth; 36862306a36Sopenharmony_cidrop: 36962306a36Sopenharmony_ci qi->dev->stats.tx_dropped++; 37062306a36Sopenharmony_ci if (skb != NULL) { 37162306a36Sopenharmony_ci packet_len = skb->len; 37262306a36Sopenharmony_ci dev_consume_skb_any(skb); 37362306a36Sopenharmony_ci netdev_completed_queue(qi->dev, 1, packet_len); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci spin_unlock(&qi->tail_lock); 37662306a36Sopenharmony_ci return queue_depth; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int consume_vector_skbs(struct vector_queue *qi, int count) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct sk_buff *skb; 38262306a36Sopenharmony_ci int skb_index; 38362306a36Sopenharmony_ci int bytes_compl = 0; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci for (skb_index = qi->head; skb_index < qi->head + count; skb_index++) { 38662306a36Sopenharmony_ci skb = *(qi->skbuff_vector + skb_index); 38762306a36Sopenharmony_ci /* mark as empty to ensure correct destruction if 38862306a36Sopenharmony_ci * needed 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci bytes_compl += skb->len; 39162306a36Sopenharmony_ci *(qi->skbuff_vector + skb_index) = NULL; 39262306a36Sopenharmony_ci dev_consume_skb_any(skb); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci qi->dev->stats.tx_bytes += bytes_compl; 39562306a36Sopenharmony_ci qi->dev->stats.tx_packets += count; 39662306a36Sopenharmony_ci netdev_completed_queue(qi->dev, count, bytes_compl); 39762306a36Sopenharmony_ci return vector_advancehead(qi, count); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* 40162306a36Sopenharmony_ci * Generic vector deque via sendmmsg with support for forming headers 40262306a36Sopenharmony_ci * using transport specific callback. Allows GRE, L2TPv3, RAW and 40362306a36Sopenharmony_ci * other transports to use a common dequeue procedure in vector mode 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic int vector_send(struct vector_queue *qi) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(qi->dev); 41062306a36Sopenharmony_ci struct mmsghdr *send_from; 41162306a36Sopenharmony_ci int result = 0, send_len, queue_depth = qi->max_depth; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (spin_trylock(&qi->head_lock)) { 41462306a36Sopenharmony_ci if (spin_trylock(&qi->tail_lock)) { 41562306a36Sopenharmony_ci /* update queue_depth to current value */ 41662306a36Sopenharmony_ci queue_depth = qi->queue_depth; 41762306a36Sopenharmony_ci spin_unlock(&qi->tail_lock); 41862306a36Sopenharmony_ci while (queue_depth > 0) { 41962306a36Sopenharmony_ci /* Calculate the start of the vector */ 42062306a36Sopenharmony_ci send_len = queue_depth; 42162306a36Sopenharmony_ci send_from = qi->mmsg_vector; 42262306a36Sopenharmony_ci send_from += qi->head; 42362306a36Sopenharmony_ci /* Adjust vector size if wraparound */ 42462306a36Sopenharmony_ci if (send_len + qi->head > qi->max_depth) 42562306a36Sopenharmony_ci send_len = qi->max_depth - qi->head; 42662306a36Sopenharmony_ci /* Try to TX as many packets as possible */ 42762306a36Sopenharmony_ci if (send_len > 0) { 42862306a36Sopenharmony_ci result = uml_vector_sendmmsg( 42962306a36Sopenharmony_ci vp->fds->tx_fd, 43062306a36Sopenharmony_ci send_from, 43162306a36Sopenharmony_ci send_len, 43262306a36Sopenharmony_ci 0 43362306a36Sopenharmony_ci ); 43462306a36Sopenharmony_ci vp->in_write_poll = 43562306a36Sopenharmony_ci (result != send_len); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci /* For some of the sendmmsg error scenarios 43862306a36Sopenharmony_ci * we may end being unsure in the TX success 43962306a36Sopenharmony_ci * for all packets. It is safer to declare 44062306a36Sopenharmony_ci * them all TX-ed and blame the network. 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci if (result < 0) { 44362306a36Sopenharmony_ci if (net_ratelimit()) 44462306a36Sopenharmony_ci netdev_err(vp->dev, "sendmmsg err=%i\n", 44562306a36Sopenharmony_ci result); 44662306a36Sopenharmony_ci vp->in_error = true; 44762306a36Sopenharmony_ci result = send_len; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci if (result > 0) { 45062306a36Sopenharmony_ci queue_depth = 45162306a36Sopenharmony_ci consume_vector_skbs(qi, result); 45262306a36Sopenharmony_ci /* This is equivalent to an TX IRQ. 45362306a36Sopenharmony_ci * Restart the upper layers to feed us 45462306a36Sopenharmony_ci * more packets. 45562306a36Sopenharmony_ci */ 45662306a36Sopenharmony_ci if (result > vp->estats.tx_queue_max) 45762306a36Sopenharmony_ci vp->estats.tx_queue_max = result; 45862306a36Sopenharmony_ci vp->estats.tx_queue_running_average = 45962306a36Sopenharmony_ci (vp->estats.tx_queue_running_average + result) >> 1; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci netif_wake_queue(qi->dev); 46262306a36Sopenharmony_ci /* if TX is busy, break out of the send loop, 46362306a36Sopenharmony_ci * poll write IRQ will reschedule xmit for us 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci if (result != send_len) { 46662306a36Sopenharmony_ci vp->estats.tx_restart_queue++; 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci spin_unlock(&qi->head_lock); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci return queue_depth; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/* Queue destructor. Deliberately stateless so we can use 47762306a36Sopenharmony_ci * it in queue cleanup if initialization fails. 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic void destroy_queue(struct vector_queue *qi) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci int i; 48362306a36Sopenharmony_ci struct iovec *iov; 48462306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(qi->dev); 48562306a36Sopenharmony_ci struct mmsghdr *mmsg_vector; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (qi == NULL) 48862306a36Sopenharmony_ci return; 48962306a36Sopenharmony_ci /* deallocate any skbuffs - we rely on any unused to be 49062306a36Sopenharmony_ci * set to NULL. 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_ci if (qi->skbuff_vector != NULL) { 49362306a36Sopenharmony_ci for (i = 0; i < qi->max_depth; i++) { 49462306a36Sopenharmony_ci if (*(qi->skbuff_vector + i) != NULL) 49562306a36Sopenharmony_ci dev_kfree_skb_any(*(qi->skbuff_vector + i)); 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci kfree(qi->skbuff_vector); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci /* deallocate matching IOV structures including header buffs */ 50062306a36Sopenharmony_ci if (qi->mmsg_vector != NULL) { 50162306a36Sopenharmony_ci mmsg_vector = qi->mmsg_vector; 50262306a36Sopenharmony_ci for (i = 0; i < qi->max_depth; i++) { 50362306a36Sopenharmony_ci iov = mmsg_vector->msg_hdr.msg_iov; 50462306a36Sopenharmony_ci if (iov != NULL) { 50562306a36Sopenharmony_ci if ((vp->header_size > 0) && 50662306a36Sopenharmony_ci (iov->iov_base != NULL)) 50762306a36Sopenharmony_ci kfree(iov->iov_base); 50862306a36Sopenharmony_ci kfree(iov); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci mmsg_vector++; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci kfree(qi->mmsg_vector); 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci kfree(qi); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci/* 51862306a36Sopenharmony_ci * Queue constructor. Create a queue with a given side. 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_cistatic struct vector_queue *create_queue( 52162306a36Sopenharmony_ci struct vector_private *vp, 52262306a36Sopenharmony_ci int max_size, 52362306a36Sopenharmony_ci int header_size, 52462306a36Sopenharmony_ci int num_extra_frags) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct vector_queue *result; 52762306a36Sopenharmony_ci int i; 52862306a36Sopenharmony_ci struct iovec *iov; 52962306a36Sopenharmony_ci struct mmsghdr *mmsg_vector; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci result = kmalloc(sizeof(struct vector_queue), GFP_KERNEL); 53262306a36Sopenharmony_ci if (result == NULL) 53362306a36Sopenharmony_ci return NULL; 53462306a36Sopenharmony_ci result->max_depth = max_size; 53562306a36Sopenharmony_ci result->dev = vp->dev; 53662306a36Sopenharmony_ci result->mmsg_vector = kmalloc( 53762306a36Sopenharmony_ci (sizeof(struct mmsghdr) * max_size), GFP_KERNEL); 53862306a36Sopenharmony_ci if (result->mmsg_vector == NULL) 53962306a36Sopenharmony_ci goto out_mmsg_fail; 54062306a36Sopenharmony_ci result->skbuff_vector = kmalloc( 54162306a36Sopenharmony_ci (sizeof(void *) * max_size), GFP_KERNEL); 54262306a36Sopenharmony_ci if (result->skbuff_vector == NULL) 54362306a36Sopenharmony_ci goto out_skb_fail; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci /* further failures can be handled safely by destroy_queue*/ 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci mmsg_vector = result->mmsg_vector; 54862306a36Sopenharmony_ci for (i = 0; i < max_size; i++) { 54962306a36Sopenharmony_ci /* Clear all pointers - we use non-NULL as marking on 55062306a36Sopenharmony_ci * what to free on destruction 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_ci *(result->skbuff_vector + i) = NULL; 55362306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_iov = NULL; 55462306a36Sopenharmony_ci mmsg_vector++; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci mmsg_vector = result->mmsg_vector; 55762306a36Sopenharmony_ci result->max_iov_frags = num_extra_frags; 55862306a36Sopenharmony_ci for (i = 0; i < max_size; i++) { 55962306a36Sopenharmony_ci if (vp->header_size > 0) 56062306a36Sopenharmony_ci iov = kmalloc_array(3 + num_extra_frags, 56162306a36Sopenharmony_ci sizeof(struct iovec), 56262306a36Sopenharmony_ci GFP_KERNEL 56362306a36Sopenharmony_ci ); 56462306a36Sopenharmony_ci else 56562306a36Sopenharmony_ci iov = kmalloc_array(2 + num_extra_frags, 56662306a36Sopenharmony_ci sizeof(struct iovec), 56762306a36Sopenharmony_ci GFP_KERNEL 56862306a36Sopenharmony_ci ); 56962306a36Sopenharmony_ci if (iov == NULL) 57062306a36Sopenharmony_ci goto out_fail; 57162306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_iov = iov; 57262306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_iovlen = 1; 57362306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_control = NULL; 57462306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_controllen = 0; 57562306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_flags = MSG_DONTWAIT; 57662306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_name = NULL; 57762306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_namelen = 0; 57862306a36Sopenharmony_ci if (vp->header_size > 0) { 57962306a36Sopenharmony_ci iov->iov_base = kmalloc(header_size, GFP_KERNEL); 58062306a36Sopenharmony_ci if (iov->iov_base == NULL) 58162306a36Sopenharmony_ci goto out_fail; 58262306a36Sopenharmony_ci iov->iov_len = header_size; 58362306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_iovlen = 2; 58462306a36Sopenharmony_ci iov++; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci iov->iov_base = NULL; 58762306a36Sopenharmony_ci iov->iov_len = 0; 58862306a36Sopenharmony_ci mmsg_vector++; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci spin_lock_init(&result->head_lock); 59162306a36Sopenharmony_ci spin_lock_init(&result->tail_lock); 59262306a36Sopenharmony_ci result->queue_depth = 0; 59362306a36Sopenharmony_ci result->head = 0; 59462306a36Sopenharmony_ci result->tail = 0; 59562306a36Sopenharmony_ci return result; 59662306a36Sopenharmony_ciout_skb_fail: 59762306a36Sopenharmony_ci kfree(result->mmsg_vector); 59862306a36Sopenharmony_ciout_mmsg_fail: 59962306a36Sopenharmony_ci kfree(result); 60062306a36Sopenharmony_ci return NULL; 60162306a36Sopenharmony_ciout_fail: 60262306a36Sopenharmony_ci destroy_queue(result); 60362306a36Sopenharmony_ci return NULL; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci/* 60762306a36Sopenharmony_ci * We do not use the RX queue as a proper wraparound queue for now 60862306a36Sopenharmony_ci * This is not necessary because the consumption via napi_gro_receive() 60962306a36Sopenharmony_ci * happens in-line. While we can try using the return code of 61062306a36Sopenharmony_ci * netif_rx() for flow control there are no drivers doing this today. 61162306a36Sopenharmony_ci * For this RX specific use we ignore the tail/head locks and 61262306a36Sopenharmony_ci * just read into a prepared queue filled with skbuffs. 61362306a36Sopenharmony_ci */ 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic struct sk_buff *prep_skb( 61662306a36Sopenharmony_ci struct vector_private *vp, 61762306a36Sopenharmony_ci struct user_msghdr *msg) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci int linear = vp->max_packet + vp->headroom + SAFETY_MARGIN; 62062306a36Sopenharmony_ci struct sk_buff *result; 62162306a36Sopenharmony_ci int iov_index = 0, len; 62262306a36Sopenharmony_ci struct iovec *iov = msg->msg_iov; 62362306a36Sopenharmony_ci int err, nr_frags, frag; 62462306a36Sopenharmony_ci skb_frag_t *skb_frag; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (vp->req_size <= linear) 62762306a36Sopenharmony_ci len = linear; 62862306a36Sopenharmony_ci else 62962306a36Sopenharmony_ci len = vp->req_size; 63062306a36Sopenharmony_ci result = alloc_skb_with_frags( 63162306a36Sopenharmony_ci linear, 63262306a36Sopenharmony_ci len - vp->max_packet, 63362306a36Sopenharmony_ci 3, 63462306a36Sopenharmony_ci &err, 63562306a36Sopenharmony_ci GFP_ATOMIC 63662306a36Sopenharmony_ci ); 63762306a36Sopenharmony_ci if (vp->header_size > 0) 63862306a36Sopenharmony_ci iov_index++; 63962306a36Sopenharmony_ci if (result == NULL) { 64062306a36Sopenharmony_ci iov[iov_index].iov_base = NULL; 64162306a36Sopenharmony_ci iov[iov_index].iov_len = 0; 64262306a36Sopenharmony_ci goto done; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci skb_reserve(result, vp->headroom); 64562306a36Sopenharmony_ci result->dev = vp->dev; 64662306a36Sopenharmony_ci skb_put(result, vp->max_packet); 64762306a36Sopenharmony_ci result->data_len = len - vp->max_packet; 64862306a36Sopenharmony_ci result->len += len - vp->max_packet; 64962306a36Sopenharmony_ci skb_reset_mac_header(result); 65062306a36Sopenharmony_ci result->ip_summed = CHECKSUM_NONE; 65162306a36Sopenharmony_ci iov[iov_index].iov_base = result->data; 65262306a36Sopenharmony_ci iov[iov_index].iov_len = vp->max_packet; 65362306a36Sopenharmony_ci iov_index++; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci nr_frags = skb_shinfo(result)->nr_frags; 65662306a36Sopenharmony_ci for (frag = 0; frag < nr_frags; frag++) { 65762306a36Sopenharmony_ci skb_frag = &skb_shinfo(result)->frags[frag]; 65862306a36Sopenharmony_ci iov[iov_index].iov_base = skb_frag_address_safe(skb_frag); 65962306a36Sopenharmony_ci if (iov[iov_index].iov_base != NULL) 66062306a36Sopenharmony_ci iov[iov_index].iov_len = skb_frag_size(skb_frag); 66162306a36Sopenharmony_ci else 66262306a36Sopenharmony_ci iov[iov_index].iov_len = 0; 66362306a36Sopenharmony_ci iov_index++; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_cidone: 66662306a36Sopenharmony_ci msg->msg_iovlen = iov_index; 66762306a36Sopenharmony_ci return result; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci/* Prepare queue for recvmmsg one-shot rx - fill with fresh sk_buffs*/ 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic void prep_queue_for_rx(struct vector_queue *qi) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(qi->dev); 67662306a36Sopenharmony_ci struct mmsghdr *mmsg_vector = qi->mmsg_vector; 67762306a36Sopenharmony_ci void **skbuff_vector = qi->skbuff_vector; 67862306a36Sopenharmony_ci int i; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (qi->queue_depth == 0) 68162306a36Sopenharmony_ci return; 68262306a36Sopenharmony_ci for (i = 0; i < qi->queue_depth; i++) { 68362306a36Sopenharmony_ci /* it is OK if allocation fails - recvmmsg with NULL data in 68462306a36Sopenharmony_ci * iov argument still performs an RX, just drops the packet 68562306a36Sopenharmony_ci * This allows us stop faffing around with a "drop buffer" 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci *skbuff_vector = prep_skb(vp, &mmsg_vector->msg_hdr); 68962306a36Sopenharmony_ci skbuff_vector++; 69062306a36Sopenharmony_ci mmsg_vector++; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci qi->queue_depth = 0; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic struct vector_device *find_device(int n) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct vector_device *device; 69862306a36Sopenharmony_ci struct list_head *ele; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci spin_lock(&vector_devices_lock); 70162306a36Sopenharmony_ci list_for_each(ele, &vector_devices) { 70262306a36Sopenharmony_ci device = list_entry(ele, struct vector_device, list); 70362306a36Sopenharmony_ci if (device->unit == n) 70462306a36Sopenharmony_ci goto out; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci device = NULL; 70762306a36Sopenharmony_ci out: 70862306a36Sopenharmony_ci spin_unlock(&vector_devices_lock); 70962306a36Sopenharmony_ci return device; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic int vector_parse(char *str, int *index_out, char **str_out, 71362306a36Sopenharmony_ci char **error_out) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci int n, len, err; 71662306a36Sopenharmony_ci char *start = str; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci len = strlen(str); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci while ((*str != ':') && (strlen(str) > 1)) 72162306a36Sopenharmony_ci str++; 72262306a36Sopenharmony_ci if (*str != ':') { 72362306a36Sopenharmony_ci *error_out = "Expected ':' after device number"; 72462306a36Sopenharmony_ci return -EINVAL; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci *str = '\0'; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci err = kstrtouint(start, 0, &n); 72962306a36Sopenharmony_ci if (err < 0) { 73062306a36Sopenharmony_ci *error_out = "Bad device number"; 73162306a36Sopenharmony_ci return err; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci str++; 73562306a36Sopenharmony_ci if (find_device(n)) { 73662306a36Sopenharmony_ci *error_out = "Device already configured"; 73762306a36Sopenharmony_ci return -EINVAL; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci *index_out = n; 74162306a36Sopenharmony_ci *str_out = str; 74262306a36Sopenharmony_ci return 0; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int vector_config(char *str, char **error_out) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci int err, n; 74862306a36Sopenharmony_ci char *params; 74962306a36Sopenharmony_ci struct arglist *parsed; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci err = vector_parse(str, &n, ¶ms, error_out); 75262306a36Sopenharmony_ci if (err != 0) 75362306a36Sopenharmony_ci return err; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* This string is broken up and the pieces used by the underlying 75662306a36Sopenharmony_ci * driver. We should copy it to make sure things do not go wrong 75762306a36Sopenharmony_ci * later. 75862306a36Sopenharmony_ci */ 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci params = kstrdup(params, GFP_KERNEL); 76162306a36Sopenharmony_ci if (params == NULL) { 76262306a36Sopenharmony_ci *error_out = "vector_config failed to strdup string"; 76362306a36Sopenharmony_ci return -ENOMEM; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci parsed = uml_parse_vector_ifspec(params); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (parsed == NULL) { 76962306a36Sopenharmony_ci *error_out = "vector_config failed to parse parameters"; 77062306a36Sopenharmony_ci kfree(params); 77162306a36Sopenharmony_ci return -EINVAL; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci vector_eth_configure(n, parsed); 77562306a36Sopenharmony_ci return 0; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic int vector_id(char **str, int *start_out, int *end_out) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci char *end; 78162306a36Sopenharmony_ci int n; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci n = simple_strtoul(*str, &end, 0); 78462306a36Sopenharmony_ci if ((*end != '\0') || (end == *str)) 78562306a36Sopenharmony_ci return -1; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci *start_out = n; 78862306a36Sopenharmony_ci *end_out = n; 78962306a36Sopenharmony_ci *str = end; 79062306a36Sopenharmony_ci return n; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic int vector_remove(int n, char **error_out) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct vector_device *vec_d; 79662306a36Sopenharmony_ci struct net_device *dev; 79762306a36Sopenharmony_ci struct vector_private *vp; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci vec_d = find_device(n); 80062306a36Sopenharmony_ci if (vec_d == NULL) 80162306a36Sopenharmony_ci return -ENODEV; 80262306a36Sopenharmony_ci dev = vec_d->dev; 80362306a36Sopenharmony_ci vp = netdev_priv(dev); 80462306a36Sopenharmony_ci if (vp->fds != NULL) 80562306a36Sopenharmony_ci return -EBUSY; 80662306a36Sopenharmony_ci unregister_netdev(dev); 80762306a36Sopenharmony_ci platform_device_unregister(&vec_d->pdev); 80862306a36Sopenharmony_ci return 0; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci/* 81262306a36Sopenharmony_ci * There is no shared per-transport initialization code, so 81362306a36Sopenharmony_ci * we will just initialize each interface one by one and 81462306a36Sopenharmony_ci * add them to a list 81562306a36Sopenharmony_ci */ 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic struct platform_driver uml_net_driver = { 81862306a36Sopenharmony_ci .driver = { 81962306a36Sopenharmony_ci .name = DRIVER_NAME, 82062306a36Sopenharmony_ci }, 82162306a36Sopenharmony_ci}; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic void vector_device_release(struct device *dev) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci struct vector_device *device = dev_get_drvdata(dev); 82762306a36Sopenharmony_ci struct net_device *netdev = device->dev; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci list_del(&device->list); 83062306a36Sopenharmony_ci kfree(device); 83162306a36Sopenharmony_ci free_netdev(netdev); 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci/* Bog standard recv using recvmsg - not used normally unless the user 83562306a36Sopenharmony_ci * explicitly specifies not to use recvmmsg vector RX. 83662306a36Sopenharmony_ci */ 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic int vector_legacy_rx(struct vector_private *vp) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci int pkt_len; 84162306a36Sopenharmony_ci struct user_msghdr hdr; 84262306a36Sopenharmony_ci struct iovec iov[2 + MAX_IOV_SIZE]; /* header + data use case only */ 84362306a36Sopenharmony_ci int iovpos = 0; 84462306a36Sopenharmony_ci struct sk_buff *skb; 84562306a36Sopenharmony_ci int header_check; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci hdr.msg_name = NULL; 84862306a36Sopenharmony_ci hdr.msg_namelen = 0; 84962306a36Sopenharmony_ci hdr.msg_iov = (struct iovec *) &iov; 85062306a36Sopenharmony_ci hdr.msg_control = NULL; 85162306a36Sopenharmony_ci hdr.msg_controllen = 0; 85262306a36Sopenharmony_ci hdr.msg_flags = 0; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (vp->header_size > 0) { 85562306a36Sopenharmony_ci iov[0].iov_base = vp->header_rxbuffer; 85662306a36Sopenharmony_ci iov[0].iov_len = vp->header_size; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci skb = prep_skb(vp, &hdr); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (skb == NULL) { 86262306a36Sopenharmony_ci /* Read a packet into drop_buffer and don't do 86362306a36Sopenharmony_ci * anything with it. 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_ci iov[iovpos].iov_base = drop_buffer; 86662306a36Sopenharmony_ci iov[iovpos].iov_len = DROP_BUFFER_SIZE; 86762306a36Sopenharmony_ci hdr.msg_iovlen = 1; 86862306a36Sopenharmony_ci vp->dev->stats.rx_dropped++; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci pkt_len = uml_vector_recvmsg(vp->fds->rx_fd, &hdr, 0); 87262306a36Sopenharmony_ci if (pkt_len < 0) { 87362306a36Sopenharmony_ci vp->in_error = true; 87462306a36Sopenharmony_ci return pkt_len; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (skb != NULL) { 87862306a36Sopenharmony_ci if (pkt_len > vp->header_size) { 87962306a36Sopenharmony_ci if (vp->header_size > 0) { 88062306a36Sopenharmony_ci header_check = vp->verify_header( 88162306a36Sopenharmony_ci vp->header_rxbuffer, skb, vp); 88262306a36Sopenharmony_ci if (header_check < 0) { 88362306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 88462306a36Sopenharmony_ci vp->dev->stats.rx_dropped++; 88562306a36Sopenharmony_ci vp->estats.rx_encaps_errors++; 88662306a36Sopenharmony_ci return 0; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci if (header_check > 0) { 88962306a36Sopenharmony_ci vp->estats.rx_csum_offload_good++; 89062306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci pskb_trim(skb, pkt_len - vp->rx_header_size); 89462306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, skb->dev); 89562306a36Sopenharmony_ci vp->dev->stats.rx_bytes += skb->len; 89662306a36Sopenharmony_ci vp->dev->stats.rx_packets++; 89762306a36Sopenharmony_ci napi_gro_receive(&vp->napi, skb); 89862306a36Sopenharmony_ci } else { 89962306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci return pkt_len; 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci/* 90662306a36Sopenharmony_ci * Packet at a time TX which falls back to vector TX if the 90762306a36Sopenharmony_ci * underlying transport is busy. 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cistatic int writev_tx(struct vector_private *vp, struct sk_buff *skb) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci struct iovec iov[3 + MAX_IOV_SIZE]; 91562306a36Sopenharmony_ci int iov_count, pkt_len = 0; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci iov[0].iov_base = vp->header_txbuffer; 91862306a36Sopenharmony_ci iov_count = prep_msg(vp, skb, (struct iovec *) &iov); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (iov_count < 1) 92162306a36Sopenharmony_ci goto drop; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci pkt_len = uml_vector_writev( 92462306a36Sopenharmony_ci vp->fds->tx_fd, 92562306a36Sopenharmony_ci (struct iovec *) &iov, 92662306a36Sopenharmony_ci iov_count 92762306a36Sopenharmony_ci ); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (pkt_len < 0) 93062306a36Sopenharmony_ci goto drop; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci netif_trans_update(vp->dev); 93362306a36Sopenharmony_ci netif_wake_queue(vp->dev); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (pkt_len > 0) { 93662306a36Sopenharmony_ci vp->dev->stats.tx_bytes += skb->len; 93762306a36Sopenharmony_ci vp->dev->stats.tx_packets++; 93862306a36Sopenharmony_ci } else { 93962306a36Sopenharmony_ci vp->dev->stats.tx_dropped++; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci consume_skb(skb); 94262306a36Sopenharmony_ci return pkt_len; 94362306a36Sopenharmony_cidrop: 94462306a36Sopenharmony_ci vp->dev->stats.tx_dropped++; 94562306a36Sopenharmony_ci consume_skb(skb); 94662306a36Sopenharmony_ci if (pkt_len < 0) 94762306a36Sopenharmony_ci vp->in_error = true; 94862306a36Sopenharmony_ci return pkt_len; 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci/* 95262306a36Sopenharmony_ci * Receive as many messages as we can in one call using the special 95362306a36Sopenharmony_ci * mmsg vector matched to an skb vector which we prepared earlier. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic int vector_mmsg_rx(struct vector_private *vp, int budget) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci int packet_count, i; 95962306a36Sopenharmony_ci struct vector_queue *qi = vp->rx_queue; 96062306a36Sopenharmony_ci struct sk_buff *skb; 96162306a36Sopenharmony_ci struct mmsghdr *mmsg_vector = qi->mmsg_vector; 96262306a36Sopenharmony_ci void **skbuff_vector = qi->skbuff_vector; 96362306a36Sopenharmony_ci int header_check; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* Refresh the vector and make sure it is with new skbs and the 96662306a36Sopenharmony_ci * iovs are updated to point to them. 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci prep_queue_for_rx(qi); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* Fire the Lazy Gun - get as many packets as we can in one go. */ 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (budget > qi->max_depth) 97462306a36Sopenharmony_ci budget = qi->max_depth; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci packet_count = uml_vector_recvmmsg( 97762306a36Sopenharmony_ci vp->fds->rx_fd, qi->mmsg_vector, qi->max_depth, 0); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (packet_count < 0) 98062306a36Sopenharmony_ci vp->in_error = true; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (packet_count <= 0) 98362306a36Sopenharmony_ci return packet_count; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* We treat packet processing as enqueue, buffer refresh as dequeue 98662306a36Sopenharmony_ci * The queue_depth tells us how many buffers have been used and how 98762306a36Sopenharmony_ci * many do we need to prep the next time prep_queue_for_rx() is called. 98862306a36Sopenharmony_ci */ 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci qi->queue_depth = packet_count; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci for (i = 0; i < packet_count; i++) { 99362306a36Sopenharmony_ci skb = (*skbuff_vector); 99462306a36Sopenharmony_ci if (mmsg_vector->msg_len > vp->header_size) { 99562306a36Sopenharmony_ci if (vp->header_size > 0) { 99662306a36Sopenharmony_ci header_check = vp->verify_header( 99762306a36Sopenharmony_ci mmsg_vector->msg_hdr.msg_iov->iov_base, 99862306a36Sopenharmony_ci skb, 99962306a36Sopenharmony_ci vp 100062306a36Sopenharmony_ci ); 100162306a36Sopenharmony_ci if (header_check < 0) { 100262306a36Sopenharmony_ci /* Overlay header failed to verify - discard. 100362306a36Sopenharmony_ci * We can actually keep this skb and reuse it, 100462306a36Sopenharmony_ci * but that will make the prep logic too 100562306a36Sopenharmony_ci * complex. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 100862306a36Sopenharmony_ci vp->estats.rx_encaps_errors++; 100962306a36Sopenharmony_ci continue; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci if (header_check > 0) { 101262306a36Sopenharmony_ci vp->estats.rx_csum_offload_good++; 101362306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci pskb_trim(skb, 101762306a36Sopenharmony_ci mmsg_vector->msg_len - vp->rx_header_size); 101862306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, skb->dev); 101962306a36Sopenharmony_ci /* 102062306a36Sopenharmony_ci * We do not need to lock on updating stats here 102162306a36Sopenharmony_ci * The interrupt loop is non-reentrant. 102262306a36Sopenharmony_ci */ 102362306a36Sopenharmony_ci vp->dev->stats.rx_bytes += skb->len; 102462306a36Sopenharmony_ci vp->dev->stats.rx_packets++; 102562306a36Sopenharmony_ci napi_gro_receive(&vp->napi, skb); 102662306a36Sopenharmony_ci } else { 102762306a36Sopenharmony_ci /* Overlay header too short to do anything - discard. 102862306a36Sopenharmony_ci * We can actually keep this skb and reuse it, 102962306a36Sopenharmony_ci * but that will make the prep logic too complex. 103062306a36Sopenharmony_ci */ 103162306a36Sopenharmony_ci if (skb != NULL) 103262306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci (*skbuff_vector) = NULL; 103562306a36Sopenharmony_ci /* Move to the next buffer element */ 103662306a36Sopenharmony_ci mmsg_vector++; 103762306a36Sopenharmony_ci skbuff_vector++; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci if (packet_count > 0) { 104062306a36Sopenharmony_ci if (vp->estats.rx_queue_max < packet_count) 104162306a36Sopenharmony_ci vp->estats.rx_queue_max = packet_count; 104262306a36Sopenharmony_ci vp->estats.rx_queue_running_average = 104362306a36Sopenharmony_ci (vp->estats.rx_queue_running_average + packet_count) >> 1; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci return packet_count; 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(dev); 105162306a36Sopenharmony_ci int queue_depth = 0; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (vp->in_error) { 105462306a36Sopenharmony_ci deactivate_fd(vp->fds->rx_fd, vp->rx_irq); 105562306a36Sopenharmony_ci if ((vp->fds->rx_fd != vp->fds->tx_fd) && (vp->tx_irq != 0)) 105662306a36Sopenharmony_ci deactivate_fd(vp->fds->tx_fd, vp->tx_irq); 105762306a36Sopenharmony_ci return NETDEV_TX_BUSY; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if ((vp->options & VECTOR_TX) == 0) { 106162306a36Sopenharmony_ci writev_tx(vp, skb); 106262306a36Sopenharmony_ci return NETDEV_TX_OK; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* We do BQL only in the vector path, no point doing it in 106662306a36Sopenharmony_ci * packet at a time mode as there is no device queue 106762306a36Sopenharmony_ci */ 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci netdev_sent_queue(vp->dev, skb->len); 107062306a36Sopenharmony_ci queue_depth = vector_enqueue(vp->tx_queue, skb); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (queue_depth < vp->tx_queue->max_depth && netdev_xmit_more()) { 107362306a36Sopenharmony_ci mod_timer(&vp->tl, vp->coalesce); 107462306a36Sopenharmony_ci return NETDEV_TX_OK; 107562306a36Sopenharmony_ci } else { 107662306a36Sopenharmony_ci queue_depth = vector_send(vp->tx_queue); 107762306a36Sopenharmony_ci if (queue_depth > 0) 107862306a36Sopenharmony_ci napi_schedule(&vp->napi); 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci return NETDEV_TX_OK; 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_cistatic irqreturn_t vector_rx_interrupt(int irq, void *dev_id) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct net_device *dev = dev_id; 108762306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(dev); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (!netif_running(dev)) 109062306a36Sopenharmony_ci return IRQ_NONE; 109162306a36Sopenharmony_ci napi_schedule(&vp->napi); 109262306a36Sopenharmony_ci return IRQ_HANDLED; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic irqreturn_t vector_tx_interrupt(int irq, void *dev_id) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci struct net_device *dev = dev_id; 109962306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(dev); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (!netif_running(dev)) 110262306a36Sopenharmony_ci return IRQ_NONE; 110362306a36Sopenharmony_ci /* We need to pay attention to it only if we got 110462306a36Sopenharmony_ci * -EAGAIN or -ENOBUFFS from sendmmsg. Otherwise 110562306a36Sopenharmony_ci * we ignore it. In the future, it may be worth 110662306a36Sopenharmony_ci * it to improve the IRQ controller a bit to make 110762306a36Sopenharmony_ci * tweaking the IRQ mask less costly 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci napi_schedule(&vp->napi); 111162306a36Sopenharmony_ci return IRQ_HANDLED; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cistatic int irq_rr; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic int vector_net_close(struct net_device *dev) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(dev); 112062306a36Sopenharmony_ci unsigned long flags; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci netif_stop_queue(dev); 112362306a36Sopenharmony_ci del_timer(&vp->tl); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (vp->fds == NULL) 112662306a36Sopenharmony_ci return 0; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* Disable and free all IRQS */ 112962306a36Sopenharmony_ci if (vp->rx_irq > 0) { 113062306a36Sopenharmony_ci um_free_irq(vp->rx_irq, dev); 113162306a36Sopenharmony_ci vp->rx_irq = 0; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci if (vp->tx_irq > 0) { 113462306a36Sopenharmony_ci um_free_irq(vp->tx_irq, dev); 113562306a36Sopenharmony_ci vp->tx_irq = 0; 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci napi_disable(&vp->napi); 113862306a36Sopenharmony_ci netif_napi_del(&vp->napi); 113962306a36Sopenharmony_ci if (vp->fds->rx_fd > 0) { 114062306a36Sopenharmony_ci if (vp->bpf) 114162306a36Sopenharmony_ci uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf); 114262306a36Sopenharmony_ci os_close_file(vp->fds->rx_fd); 114362306a36Sopenharmony_ci vp->fds->rx_fd = -1; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci if (vp->fds->tx_fd > 0) { 114662306a36Sopenharmony_ci os_close_file(vp->fds->tx_fd); 114762306a36Sopenharmony_ci vp->fds->tx_fd = -1; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci if (vp->bpf != NULL) 115062306a36Sopenharmony_ci kfree(vp->bpf->filter); 115162306a36Sopenharmony_ci kfree(vp->bpf); 115262306a36Sopenharmony_ci vp->bpf = NULL; 115362306a36Sopenharmony_ci kfree(vp->fds->remote_addr); 115462306a36Sopenharmony_ci kfree(vp->transport_data); 115562306a36Sopenharmony_ci kfree(vp->header_rxbuffer); 115662306a36Sopenharmony_ci kfree(vp->header_txbuffer); 115762306a36Sopenharmony_ci if (vp->rx_queue != NULL) 115862306a36Sopenharmony_ci destroy_queue(vp->rx_queue); 115962306a36Sopenharmony_ci if (vp->tx_queue != NULL) 116062306a36Sopenharmony_ci destroy_queue(vp->tx_queue); 116162306a36Sopenharmony_ci kfree(vp->fds); 116262306a36Sopenharmony_ci vp->fds = NULL; 116362306a36Sopenharmony_ci spin_lock_irqsave(&vp->lock, flags); 116462306a36Sopenharmony_ci vp->opened = false; 116562306a36Sopenharmony_ci vp->in_error = false; 116662306a36Sopenharmony_ci spin_unlock_irqrestore(&vp->lock, flags); 116762306a36Sopenharmony_ci return 0; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic int vector_poll(struct napi_struct *napi, int budget) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct vector_private *vp = container_of(napi, struct vector_private, napi); 117362306a36Sopenharmony_ci int work_done = 0; 117462306a36Sopenharmony_ci int err; 117562306a36Sopenharmony_ci bool tx_enqueued = false; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if ((vp->options & VECTOR_TX) != 0) 117862306a36Sopenharmony_ci tx_enqueued = (vector_send(vp->tx_queue) > 0); 117962306a36Sopenharmony_ci if ((vp->options & VECTOR_RX) > 0) 118062306a36Sopenharmony_ci err = vector_mmsg_rx(vp, budget); 118162306a36Sopenharmony_ci else { 118262306a36Sopenharmony_ci err = vector_legacy_rx(vp); 118362306a36Sopenharmony_ci if (err > 0) 118462306a36Sopenharmony_ci err = 1; 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci if (err > 0) 118762306a36Sopenharmony_ci work_done += err; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (tx_enqueued || err > 0) 119062306a36Sopenharmony_ci napi_schedule(napi); 119162306a36Sopenharmony_ci if (work_done < budget) 119262306a36Sopenharmony_ci napi_complete_done(napi, work_done); 119362306a36Sopenharmony_ci return work_done; 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic void vector_reset_tx(struct work_struct *work) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci struct vector_private *vp = 119962306a36Sopenharmony_ci container_of(work, struct vector_private, reset_tx); 120062306a36Sopenharmony_ci netdev_reset_queue(vp->dev); 120162306a36Sopenharmony_ci netif_start_queue(vp->dev); 120262306a36Sopenharmony_ci netif_wake_queue(vp->dev); 120362306a36Sopenharmony_ci} 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_cistatic int vector_net_open(struct net_device *dev) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(dev); 120862306a36Sopenharmony_ci unsigned long flags; 120962306a36Sopenharmony_ci int err = -EINVAL; 121062306a36Sopenharmony_ci struct vector_device *vdevice; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci spin_lock_irqsave(&vp->lock, flags); 121362306a36Sopenharmony_ci if (vp->opened) { 121462306a36Sopenharmony_ci spin_unlock_irqrestore(&vp->lock, flags); 121562306a36Sopenharmony_ci return -ENXIO; 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci vp->opened = true; 121862306a36Sopenharmony_ci spin_unlock_irqrestore(&vp->lock, flags); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci vp->bpf = uml_vector_user_bpf(get_bpf_file(vp->parsed)); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci vp->fds = uml_vector_user_open(vp->unit, vp->parsed); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if (vp->fds == NULL) 122562306a36Sopenharmony_ci goto out_close; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (build_transport_data(vp) < 0) 122862306a36Sopenharmony_ci goto out_close; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if ((vp->options & VECTOR_RX) > 0) { 123162306a36Sopenharmony_ci vp->rx_queue = create_queue( 123262306a36Sopenharmony_ci vp, 123362306a36Sopenharmony_ci get_depth(vp->parsed), 123462306a36Sopenharmony_ci vp->rx_header_size, 123562306a36Sopenharmony_ci MAX_IOV_SIZE 123662306a36Sopenharmony_ci ); 123762306a36Sopenharmony_ci vp->rx_queue->queue_depth = get_depth(vp->parsed); 123862306a36Sopenharmony_ci } else { 123962306a36Sopenharmony_ci vp->header_rxbuffer = kmalloc( 124062306a36Sopenharmony_ci vp->rx_header_size, 124162306a36Sopenharmony_ci GFP_KERNEL 124262306a36Sopenharmony_ci ); 124362306a36Sopenharmony_ci if (vp->header_rxbuffer == NULL) 124462306a36Sopenharmony_ci goto out_close; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci if ((vp->options & VECTOR_TX) > 0) { 124762306a36Sopenharmony_ci vp->tx_queue = create_queue( 124862306a36Sopenharmony_ci vp, 124962306a36Sopenharmony_ci get_depth(vp->parsed), 125062306a36Sopenharmony_ci vp->header_size, 125162306a36Sopenharmony_ci MAX_IOV_SIZE 125262306a36Sopenharmony_ci ); 125362306a36Sopenharmony_ci } else { 125462306a36Sopenharmony_ci vp->header_txbuffer = kmalloc(vp->header_size, GFP_KERNEL); 125562306a36Sopenharmony_ci if (vp->header_txbuffer == NULL) 125662306a36Sopenharmony_ci goto out_close; 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci netif_napi_add_weight(vp->dev, &vp->napi, vector_poll, 126062306a36Sopenharmony_ci get_depth(vp->parsed)); 126162306a36Sopenharmony_ci napi_enable(&vp->napi); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci /* READ IRQ */ 126462306a36Sopenharmony_ci err = um_request_irq( 126562306a36Sopenharmony_ci irq_rr + VECTOR_BASE_IRQ, vp->fds->rx_fd, 126662306a36Sopenharmony_ci IRQ_READ, vector_rx_interrupt, 126762306a36Sopenharmony_ci IRQF_SHARED, dev->name, dev); 126862306a36Sopenharmony_ci if (err < 0) { 126962306a36Sopenharmony_ci netdev_err(dev, "vector_open: failed to get rx irq(%d)\n", err); 127062306a36Sopenharmony_ci err = -ENETUNREACH; 127162306a36Sopenharmony_ci goto out_close; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci vp->rx_irq = irq_rr + VECTOR_BASE_IRQ; 127462306a36Sopenharmony_ci dev->irq = irq_rr + VECTOR_BASE_IRQ; 127562306a36Sopenharmony_ci irq_rr = (irq_rr + 1) % VECTOR_IRQ_SPACE; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci /* WRITE IRQ - we need it only if we have vector TX */ 127862306a36Sopenharmony_ci if ((vp->options & VECTOR_TX) > 0) { 127962306a36Sopenharmony_ci err = um_request_irq( 128062306a36Sopenharmony_ci irq_rr + VECTOR_BASE_IRQ, vp->fds->tx_fd, 128162306a36Sopenharmony_ci IRQ_WRITE, vector_tx_interrupt, 128262306a36Sopenharmony_ci IRQF_SHARED, dev->name, dev); 128362306a36Sopenharmony_ci if (err < 0) { 128462306a36Sopenharmony_ci netdev_err(dev, 128562306a36Sopenharmony_ci "vector_open: failed to get tx irq(%d)\n", err); 128662306a36Sopenharmony_ci err = -ENETUNREACH; 128762306a36Sopenharmony_ci goto out_close; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci vp->tx_irq = irq_rr + VECTOR_BASE_IRQ; 129062306a36Sopenharmony_ci irq_rr = (irq_rr + 1) % VECTOR_IRQ_SPACE; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci if ((vp->options & VECTOR_QDISC_BYPASS) != 0) { 129462306a36Sopenharmony_ci if (!uml_raw_enable_qdisc_bypass(vp->fds->rx_fd)) 129562306a36Sopenharmony_ci vp->options |= VECTOR_BPF; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci if (((vp->options & VECTOR_BPF) != 0) && (vp->bpf == NULL)) 129862306a36Sopenharmony_ci vp->bpf = uml_vector_default_bpf(dev->dev_addr); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci if (vp->bpf != NULL) 130162306a36Sopenharmony_ci uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci netif_start_queue(dev); 130462306a36Sopenharmony_ci vector_reset_stats(vp); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci /* clear buffer - it can happen that the host side of the interface 130762306a36Sopenharmony_ci * is full when we get here. In this case, new data is never queued, 130862306a36Sopenharmony_ci * SIGIOs never arrive, and the net never works. 130962306a36Sopenharmony_ci */ 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci napi_schedule(&vp->napi); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci vdevice = find_device(vp->unit); 131462306a36Sopenharmony_ci vdevice->opened = 1; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci if ((vp->options & VECTOR_TX) != 0) 131762306a36Sopenharmony_ci add_timer(&vp->tl); 131862306a36Sopenharmony_ci return 0; 131962306a36Sopenharmony_ciout_close: 132062306a36Sopenharmony_ci vector_net_close(dev); 132162306a36Sopenharmony_ci return err; 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_cistatic void vector_net_set_multicast_list(struct net_device *dev) 132662306a36Sopenharmony_ci{ 132762306a36Sopenharmony_ci /* TODO: - we can do some BPF games here */ 132862306a36Sopenharmony_ci return; 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cistatic void vector_net_tx_timeout(struct net_device *dev, unsigned int txqueue) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(dev); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci vp->estats.tx_timeout_count++; 133662306a36Sopenharmony_ci netif_trans_update(dev); 133762306a36Sopenharmony_ci schedule_work(&vp->reset_tx); 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic netdev_features_t vector_fix_features(struct net_device *dev, 134162306a36Sopenharmony_ci netdev_features_t features) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); 134462306a36Sopenharmony_ci return features; 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic int vector_set_features(struct net_device *dev, 134862306a36Sopenharmony_ci netdev_features_t features) 134962306a36Sopenharmony_ci{ 135062306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(dev); 135162306a36Sopenharmony_ci /* Adjust buffer sizes for GSO/GRO. Unfortunately, there is 135262306a36Sopenharmony_ci * no way to negotiate it on raw sockets, so we can change 135362306a36Sopenharmony_ci * only our side. 135462306a36Sopenharmony_ci */ 135562306a36Sopenharmony_ci if (features & NETIF_F_GRO) 135662306a36Sopenharmony_ci /* All new frame buffers will be GRO-sized */ 135762306a36Sopenharmony_ci vp->req_size = 65536; 135862306a36Sopenharmony_ci else 135962306a36Sopenharmony_ci /* All new frame buffers will be normal sized */ 136062306a36Sopenharmony_ci vp->req_size = vp->max_packet + vp->headroom + SAFETY_MARGIN; 136162306a36Sopenharmony_ci return 0; 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 136562306a36Sopenharmony_cistatic void vector_net_poll_controller(struct net_device *dev) 136662306a36Sopenharmony_ci{ 136762306a36Sopenharmony_ci disable_irq(dev->irq); 136862306a36Sopenharmony_ci vector_rx_interrupt(dev->irq, dev); 136962306a36Sopenharmony_ci enable_irq(dev->irq); 137062306a36Sopenharmony_ci} 137162306a36Sopenharmony_ci#endif 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_cistatic void vector_net_get_drvinfo(struct net_device *dev, 137462306a36Sopenharmony_ci struct ethtool_drvinfo *info) 137562306a36Sopenharmony_ci{ 137662306a36Sopenharmony_ci strscpy(info->driver, DRIVER_NAME, sizeof(info->driver)); 137762306a36Sopenharmony_ci} 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic int vector_net_load_bpf_flash(struct net_device *dev, 138062306a36Sopenharmony_ci struct ethtool_flash *efl) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(dev); 138362306a36Sopenharmony_ci struct vector_device *vdevice; 138462306a36Sopenharmony_ci const struct firmware *fw; 138562306a36Sopenharmony_ci int result = 0; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci if (!(vp->options & VECTOR_BPF_FLASH)) { 138862306a36Sopenharmony_ci netdev_err(dev, "loading firmware not permitted: %s\n", efl->data); 138962306a36Sopenharmony_ci return -1; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci spin_lock(&vp->lock); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci if (vp->bpf != NULL) { 139562306a36Sopenharmony_ci if (vp->opened) 139662306a36Sopenharmony_ci uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf); 139762306a36Sopenharmony_ci kfree(vp->bpf->filter); 139862306a36Sopenharmony_ci vp->bpf->filter = NULL; 139962306a36Sopenharmony_ci } else { 140062306a36Sopenharmony_ci vp->bpf = kmalloc(sizeof(struct sock_fprog), GFP_ATOMIC); 140162306a36Sopenharmony_ci if (vp->bpf == NULL) { 140262306a36Sopenharmony_ci netdev_err(dev, "failed to allocate memory for firmware\n"); 140362306a36Sopenharmony_ci goto flash_fail; 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci vdevice = find_device(vp->unit); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci if (request_firmware(&fw, efl->data, &vdevice->pdev.dev)) 141062306a36Sopenharmony_ci goto flash_fail; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci vp->bpf->filter = kmemdup(fw->data, fw->size, GFP_ATOMIC); 141362306a36Sopenharmony_ci if (!vp->bpf->filter) 141462306a36Sopenharmony_ci goto free_buffer; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci vp->bpf->len = fw->size / sizeof(struct sock_filter); 141762306a36Sopenharmony_ci release_firmware(fw); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci if (vp->opened) 142062306a36Sopenharmony_ci result = uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci spin_unlock(&vp->lock); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return result; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_cifree_buffer: 142762306a36Sopenharmony_ci release_firmware(fw); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ciflash_fail: 143062306a36Sopenharmony_ci spin_unlock(&vp->lock); 143162306a36Sopenharmony_ci if (vp->bpf != NULL) 143262306a36Sopenharmony_ci kfree(vp->bpf->filter); 143362306a36Sopenharmony_ci kfree(vp->bpf); 143462306a36Sopenharmony_ci vp->bpf = NULL; 143562306a36Sopenharmony_ci return -1; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic void vector_get_ringparam(struct net_device *netdev, 143962306a36Sopenharmony_ci struct ethtool_ringparam *ring, 144062306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 144162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 144262306a36Sopenharmony_ci{ 144362306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(netdev); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci ring->rx_max_pending = vp->rx_queue->max_depth; 144662306a36Sopenharmony_ci ring->tx_max_pending = vp->tx_queue->max_depth; 144762306a36Sopenharmony_ci ring->rx_pending = vp->rx_queue->max_depth; 144862306a36Sopenharmony_ci ring->tx_pending = vp->tx_queue->max_depth; 144962306a36Sopenharmony_ci} 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_cistatic void vector_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 145262306a36Sopenharmony_ci{ 145362306a36Sopenharmony_ci switch (stringset) { 145462306a36Sopenharmony_ci case ETH_SS_TEST: 145562306a36Sopenharmony_ci *buf = '\0'; 145662306a36Sopenharmony_ci break; 145762306a36Sopenharmony_ci case ETH_SS_STATS: 145862306a36Sopenharmony_ci memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); 145962306a36Sopenharmony_ci break; 146062306a36Sopenharmony_ci default: 146162306a36Sopenharmony_ci WARN_ON(1); 146262306a36Sopenharmony_ci break; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic int vector_get_sset_count(struct net_device *dev, int sset) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci switch (sset) { 146962306a36Sopenharmony_ci case ETH_SS_TEST: 147062306a36Sopenharmony_ci return 0; 147162306a36Sopenharmony_ci case ETH_SS_STATS: 147262306a36Sopenharmony_ci return VECTOR_NUM_STATS; 147362306a36Sopenharmony_ci default: 147462306a36Sopenharmony_ci return -EOPNOTSUPP; 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_cistatic void vector_get_ethtool_stats(struct net_device *dev, 147962306a36Sopenharmony_ci struct ethtool_stats *estats, 148062306a36Sopenharmony_ci u64 *tmp_stats) 148162306a36Sopenharmony_ci{ 148262306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(dev); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci memcpy(tmp_stats, &vp->estats, sizeof(struct vector_estats)); 148562306a36Sopenharmony_ci} 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_cistatic int vector_get_coalesce(struct net_device *netdev, 148862306a36Sopenharmony_ci struct ethtool_coalesce *ec, 148962306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 149062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 149162306a36Sopenharmony_ci{ 149262306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(netdev); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci ec->tx_coalesce_usecs = (vp->coalesce * 1000000) / HZ; 149562306a36Sopenharmony_ci return 0; 149662306a36Sopenharmony_ci} 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_cistatic int vector_set_coalesce(struct net_device *netdev, 149962306a36Sopenharmony_ci struct ethtool_coalesce *ec, 150062306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 150162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci struct vector_private *vp = netdev_priv(netdev); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci vp->coalesce = (ec->tx_coalesce_usecs * HZ) / 1000000; 150662306a36Sopenharmony_ci if (vp->coalesce == 0) 150762306a36Sopenharmony_ci vp->coalesce = 1; 150862306a36Sopenharmony_ci return 0; 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic const struct ethtool_ops vector_net_ethtool_ops = { 151262306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_TX_USECS, 151362306a36Sopenharmony_ci .get_drvinfo = vector_net_get_drvinfo, 151462306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 151562306a36Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 151662306a36Sopenharmony_ci .get_ringparam = vector_get_ringparam, 151762306a36Sopenharmony_ci .get_strings = vector_get_strings, 151862306a36Sopenharmony_ci .get_sset_count = vector_get_sset_count, 151962306a36Sopenharmony_ci .get_ethtool_stats = vector_get_ethtool_stats, 152062306a36Sopenharmony_ci .get_coalesce = vector_get_coalesce, 152162306a36Sopenharmony_ci .set_coalesce = vector_set_coalesce, 152262306a36Sopenharmony_ci .flash_device = vector_net_load_bpf_flash, 152362306a36Sopenharmony_ci}; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_cistatic const struct net_device_ops vector_netdev_ops = { 152762306a36Sopenharmony_ci .ndo_open = vector_net_open, 152862306a36Sopenharmony_ci .ndo_stop = vector_net_close, 152962306a36Sopenharmony_ci .ndo_start_xmit = vector_net_start_xmit, 153062306a36Sopenharmony_ci .ndo_set_rx_mode = vector_net_set_multicast_list, 153162306a36Sopenharmony_ci .ndo_tx_timeout = vector_net_tx_timeout, 153262306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 153362306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 153462306a36Sopenharmony_ci .ndo_fix_features = vector_fix_features, 153562306a36Sopenharmony_ci .ndo_set_features = vector_set_features, 153662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 153762306a36Sopenharmony_ci .ndo_poll_controller = vector_net_poll_controller, 153862306a36Sopenharmony_ci#endif 153962306a36Sopenharmony_ci}; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cistatic void vector_timer_expire(struct timer_list *t) 154262306a36Sopenharmony_ci{ 154362306a36Sopenharmony_ci struct vector_private *vp = from_timer(vp, t, tl); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci vp->estats.tx_kicks++; 154662306a36Sopenharmony_ci napi_schedule(&vp->napi); 154762306a36Sopenharmony_ci} 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_cistatic void vector_eth_configure( 155262306a36Sopenharmony_ci int n, 155362306a36Sopenharmony_ci struct arglist *def 155462306a36Sopenharmony_ci ) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci struct vector_device *device; 155762306a36Sopenharmony_ci struct net_device *dev; 155862306a36Sopenharmony_ci struct vector_private *vp; 155962306a36Sopenharmony_ci int err; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci device = kzalloc(sizeof(*device), GFP_KERNEL); 156262306a36Sopenharmony_ci if (device == NULL) { 156362306a36Sopenharmony_ci printk(KERN_ERR "eth_configure failed to allocate struct " 156462306a36Sopenharmony_ci "vector_device\n"); 156562306a36Sopenharmony_ci return; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct vector_private)); 156862306a36Sopenharmony_ci if (dev == NULL) { 156962306a36Sopenharmony_ci printk(KERN_ERR "eth_configure: failed to allocate struct " 157062306a36Sopenharmony_ci "net_device for vec%d\n", n); 157162306a36Sopenharmony_ci goto out_free_device; 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci dev->mtu = get_mtu(def); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci INIT_LIST_HEAD(&device->list); 157762306a36Sopenharmony_ci device->unit = n; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci /* If this name ends up conflicting with an existing registered 158062306a36Sopenharmony_ci * netdevice, that is OK, register_netdev{,ice}() will notice this 158162306a36Sopenharmony_ci * and fail. 158262306a36Sopenharmony_ci */ 158362306a36Sopenharmony_ci snprintf(dev->name, sizeof(dev->name), "vec%d", n); 158462306a36Sopenharmony_ci uml_net_setup_etheraddr(dev, uml_vector_fetch_arg(def, "mac")); 158562306a36Sopenharmony_ci vp = netdev_priv(dev); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci /* sysfs register */ 158862306a36Sopenharmony_ci if (!driver_registered) { 158962306a36Sopenharmony_ci platform_driver_register(¨_net_driver); 159062306a36Sopenharmony_ci driver_registered = 1; 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci device->pdev.id = n; 159362306a36Sopenharmony_ci device->pdev.name = DRIVER_NAME; 159462306a36Sopenharmony_ci device->pdev.dev.release = vector_device_release; 159562306a36Sopenharmony_ci dev_set_drvdata(&device->pdev.dev, device); 159662306a36Sopenharmony_ci if (platform_device_register(&device->pdev)) 159762306a36Sopenharmony_ci goto out_free_netdev; 159862306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &device->pdev.dev); 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci device->dev = dev; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci *vp = ((struct vector_private) 160362306a36Sopenharmony_ci { 160462306a36Sopenharmony_ci .list = LIST_HEAD_INIT(vp->list), 160562306a36Sopenharmony_ci .dev = dev, 160662306a36Sopenharmony_ci .unit = n, 160762306a36Sopenharmony_ci .options = get_transport_options(def), 160862306a36Sopenharmony_ci .rx_irq = 0, 160962306a36Sopenharmony_ci .tx_irq = 0, 161062306a36Sopenharmony_ci .parsed = def, 161162306a36Sopenharmony_ci .max_packet = get_mtu(def) + ETH_HEADER_OTHER, 161262306a36Sopenharmony_ci /* TODO - we need to calculate headroom so that ip header 161362306a36Sopenharmony_ci * is 16 byte aligned all the time 161462306a36Sopenharmony_ci */ 161562306a36Sopenharmony_ci .headroom = get_headroom(def), 161662306a36Sopenharmony_ci .form_header = NULL, 161762306a36Sopenharmony_ci .verify_header = NULL, 161862306a36Sopenharmony_ci .header_rxbuffer = NULL, 161962306a36Sopenharmony_ci .header_txbuffer = NULL, 162062306a36Sopenharmony_ci .header_size = 0, 162162306a36Sopenharmony_ci .rx_header_size = 0, 162262306a36Sopenharmony_ci .rexmit_scheduled = false, 162362306a36Sopenharmony_ci .opened = false, 162462306a36Sopenharmony_ci .transport_data = NULL, 162562306a36Sopenharmony_ci .in_write_poll = false, 162662306a36Sopenharmony_ci .coalesce = 2, 162762306a36Sopenharmony_ci .req_size = get_req_size(def), 162862306a36Sopenharmony_ci .in_error = false, 162962306a36Sopenharmony_ci .bpf = NULL 163062306a36Sopenharmony_ci }); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST); 163362306a36Sopenharmony_ci INIT_WORK(&vp->reset_tx, vector_reset_tx); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci timer_setup(&vp->tl, vector_timer_expire, 0); 163662306a36Sopenharmony_ci spin_lock_init(&vp->lock); 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci /* FIXME */ 163962306a36Sopenharmony_ci dev->netdev_ops = &vector_netdev_ops; 164062306a36Sopenharmony_ci dev->ethtool_ops = &vector_net_ethtool_ops; 164162306a36Sopenharmony_ci dev->watchdog_timeo = (HZ >> 1); 164262306a36Sopenharmony_ci /* primary IRQ - fixme */ 164362306a36Sopenharmony_ci dev->irq = 0; /* we will adjust this once opened */ 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci rtnl_lock(); 164662306a36Sopenharmony_ci err = register_netdevice(dev); 164762306a36Sopenharmony_ci rtnl_unlock(); 164862306a36Sopenharmony_ci if (err) 164962306a36Sopenharmony_ci goto out_undo_user_init; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci spin_lock(&vector_devices_lock); 165262306a36Sopenharmony_ci list_add(&device->list, &vector_devices); 165362306a36Sopenharmony_ci spin_unlock(&vector_devices_lock); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci return; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ciout_undo_user_init: 165862306a36Sopenharmony_ci return; 165962306a36Sopenharmony_ciout_free_netdev: 166062306a36Sopenharmony_ci free_netdev(dev); 166162306a36Sopenharmony_ciout_free_device: 166262306a36Sopenharmony_ci kfree(device); 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci/* 166962306a36Sopenharmony_ci * Invoked late in the init 167062306a36Sopenharmony_ci */ 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_cistatic int __init vector_init(void) 167362306a36Sopenharmony_ci{ 167462306a36Sopenharmony_ci struct list_head *ele; 167562306a36Sopenharmony_ci struct vector_cmd_line_arg *def; 167662306a36Sopenharmony_ci struct arglist *parsed; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci list_for_each(ele, &vec_cmd_line) { 167962306a36Sopenharmony_ci def = list_entry(ele, struct vector_cmd_line_arg, list); 168062306a36Sopenharmony_ci parsed = uml_parse_vector_ifspec(def->arguments); 168162306a36Sopenharmony_ci if (parsed != NULL) 168262306a36Sopenharmony_ci vector_eth_configure(def->unit, parsed); 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci return 0; 168562306a36Sopenharmony_ci} 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci/* Invoked at initial argument parsing, only stores 168962306a36Sopenharmony_ci * arguments until a proper vector_init is called 169062306a36Sopenharmony_ci * later 169162306a36Sopenharmony_ci */ 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_cistatic int __init vector_setup(char *str) 169462306a36Sopenharmony_ci{ 169562306a36Sopenharmony_ci char *error; 169662306a36Sopenharmony_ci int n, err; 169762306a36Sopenharmony_ci struct vector_cmd_line_arg *new; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci err = vector_parse(str, &n, &str, &error); 170062306a36Sopenharmony_ci if (err) { 170162306a36Sopenharmony_ci printk(KERN_ERR "vector_setup - Couldn't parse '%s' : %s\n", 170262306a36Sopenharmony_ci str, error); 170362306a36Sopenharmony_ci return 1; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci new = memblock_alloc(sizeof(*new), SMP_CACHE_BYTES); 170662306a36Sopenharmony_ci if (!new) 170762306a36Sopenharmony_ci panic("%s: Failed to allocate %zu bytes\n", __func__, 170862306a36Sopenharmony_ci sizeof(*new)); 170962306a36Sopenharmony_ci INIT_LIST_HEAD(&new->list); 171062306a36Sopenharmony_ci new->unit = n; 171162306a36Sopenharmony_ci new->arguments = str; 171262306a36Sopenharmony_ci list_add_tail(&new->list, &vec_cmd_line); 171362306a36Sopenharmony_ci return 1; 171462306a36Sopenharmony_ci} 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci__setup("vec", vector_setup); 171762306a36Sopenharmony_ci__uml_help(vector_setup, 171862306a36Sopenharmony_ci"vec[0-9]+:<option>=<value>,<option>=<value>\n" 171962306a36Sopenharmony_ci" Configure a vector io network device.\n\n" 172062306a36Sopenharmony_ci); 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_cilate_initcall(vector_init); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_cistatic struct mc_device vector_mc = { 172562306a36Sopenharmony_ci .list = LIST_HEAD_INIT(vector_mc.list), 172662306a36Sopenharmony_ci .name = "vec", 172762306a36Sopenharmony_ci .config = vector_config, 172862306a36Sopenharmony_ci .get_config = NULL, 172962306a36Sopenharmony_ci .id = vector_id, 173062306a36Sopenharmony_ci .remove = vector_remove, 173162306a36Sopenharmony_ci}; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci#ifdef CONFIG_INET 173462306a36Sopenharmony_cistatic int vector_inetaddr_event( 173562306a36Sopenharmony_ci struct notifier_block *this, 173662306a36Sopenharmony_ci unsigned long event, 173762306a36Sopenharmony_ci void *ptr) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci return NOTIFY_DONE; 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_cistatic struct notifier_block vector_inetaddr_notifier = { 174362306a36Sopenharmony_ci .notifier_call = vector_inetaddr_event, 174462306a36Sopenharmony_ci}; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_cistatic void inet_register(void) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci register_inetaddr_notifier(&vector_inetaddr_notifier); 174962306a36Sopenharmony_ci} 175062306a36Sopenharmony_ci#else 175162306a36Sopenharmony_cistatic inline void inet_register(void) 175262306a36Sopenharmony_ci{ 175362306a36Sopenharmony_ci} 175462306a36Sopenharmony_ci#endif 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_cistatic int vector_net_init(void) 175762306a36Sopenharmony_ci{ 175862306a36Sopenharmony_ci mconsole_register_dev(&vector_mc); 175962306a36Sopenharmony_ci inet_register(); 176062306a36Sopenharmony_ci return 0; 176162306a36Sopenharmony_ci} 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci__initcall(vector_net_init); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci 1767