linux/drivers/net/hyperv/netvsc.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2009, Microsoft Corporation.
 *
 * Authors:
 *   Haiyang Zhang <[email protected]>
 *   Hank Janssen  <[email protected]>
 */
#define pr_fmt(fmt)

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/vmalloc.h>
#include <linux/rtnetlink.h>
#include <linux/prefetch.h>
#include <linux/filter.h>

#include <asm/sync_bitops.h>
#include <asm/mshyperv.h>

#include "hyperv_net.h"
#include "netvsc_trace.h"

/*
 * Switch the data path from the synthetic interface to the VF
 * interface.
 */
int netvsc_switch_datapath(struct net_device *ndev, bool vf)
{}

/* Worker to setup sub channels on initial setup
 * Initial hotplug event occurs in softirq context
 * and can't wait for channels.
 */
static void netvsc_subchan_work(struct work_struct *w)
{}

static struct netvsc_device *alloc_net_device(void)
{}

static void free_netvsc_device(struct rcu_head *head)
{}

static void free_netvsc_device_rcu(struct netvsc_device *nvdev)
{}

static void netvsc_revoke_recv_buf(struct hv_device *device,
				   struct netvsc_device *net_device,
				   struct net_device *ndev)
{}

static void netvsc_revoke_send_buf(struct hv_device *device,
				   struct netvsc_device *net_device,
				   struct net_device *ndev)
{}

static void netvsc_teardown_recv_gpadl(struct hv_device *device,
				       struct netvsc_device *net_device,
				       struct net_device *ndev)
{}

static void netvsc_teardown_send_gpadl(struct hv_device *device,
				       struct netvsc_device *net_device,
				       struct net_device *ndev)
{}

int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx)
{}

static int netvsc_init_buf(struct hv_device *device,
			   struct netvsc_device *net_device,
			   const struct netvsc_device_info *device_info)
{}

/* Negotiate NVSP protocol version */
static int negotiate_nvsp_ver(struct hv_device *device,
			      struct netvsc_device *net_device,
			      struct nvsp_message *init_packet,
			      u32 nvsp_ver)
{}

static int netvsc_connect_vsp(struct hv_device *device,
			      struct netvsc_device *net_device,
			      const struct netvsc_device_info *device_info)
{}

/*
 * netvsc_device_remove - Callback when the root bus device is removed
 */
void netvsc_device_remove(struct hv_device *device)
{}

#define RING_AVAIL_PERCENT_HIWATER
#define RING_AVAIL_PERCENT_LOWATER

static inline void netvsc_free_send_slot(struct netvsc_device *net_device,
					 u32 index)
{}

static void netvsc_send_tx_complete(struct net_device *ndev,
				    struct netvsc_device *net_device,
				    struct vmbus_channel *channel,
				    const struct vmpacket_descriptor *desc,
				    int budget)
{}

static void netvsc_send_completion(struct net_device *ndev,
				   struct netvsc_device *net_device,
				   struct vmbus_channel *incoming_channel,
				   const struct vmpacket_descriptor *desc,
				   int budget)
{}

static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
{}

static void netvsc_copy_to_send_buf(struct netvsc_device *net_device,
				    unsigned int section_index,
				    u32 pend_size,
				    struct hv_netvsc_packet *packet,
				    struct rndis_message *rndis_msg,
				    struct hv_page_buffer *pb,
				    bool xmit_more)
{}

void netvsc_dma_unmap(struct hv_device *hv_dev,
		      struct hv_netvsc_packet *packet)
{}

/* netvsc_dma_map - Map swiotlb bounce buffer with data page of
 * packet sent by vmbus_sendpacket_pagebuffer() in the Isolation
 * VM.
 *
 * In isolation VM, netvsc send buffer has been marked visible to
 * host and so the data copied to send buffer doesn't need to use
 * bounce buffer. The data pages handled by vmbus_sendpacket_pagebuffer()
 * may not be copied to send buffer and so these pages need to be
 * mapped with swiotlb bounce buffer. netvsc_dma_map() is to do
 * that. The pfns in the struct hv_page_buffer need to be converted
 * to bounce buffer's pfn. The loop here is necessary because the
 * entries in the page buffer array are not necessarily full
 * pages of data.  Each entry in the array has a separate offset and
 * len that may be non-zero, even for entries in the middle of the
 * array.  And the entries are not physically contiguous.  So each
 * entry must be individually mapped rather than as a contiguous unit.
 * So not use dma_map_sg() here.
 */
static int netvsc_dma_map(struct hv_device *hv_dev,
			  struct hv_netvsc_packet *packet,
			  struct hv_page_buffer *pb)
{}

static inline int netvsc_send_pkt(
	struct hv_device *device,
	struct hv_netvsc_packet *packet,
	struct netvsc_device *net_device,
	struct hv_page_buffer *pb,
	struct sk_buff *skb)
{}

/* Move packet out of multi send data (msd), and clear msd */
static inline void move_pkt_msd(struct hv_netvsc_packet **msd_send,
				struct sk_buff **msd_skb,
				struct multi_send_data *msdp)
{}

/* RCU already held by caller */
/* Batching/bouncing logic is designed to attempt to optimize
 * performance.
 *
 * For small, non-LSO packets we copy the packet to a send buffer
 * which is pre-registered with the Hyper-V side. This enables the
 * hypervisor to avoid remapping the aperture to access the packet
 * descriptor and data.
 *
 * If we already started using a buffer and the netdev is transmitting
 * a burst of packets, keep on copying into the buffer until it is
 * full or we are done collecting a burst. If there is an existing
 * buffer with space for the RNDIS descriptor but not the packet, copy
 * the RNDIS descriptor to the buffer, keeping the packet in place.
 *
 * If we do batching and send more than one packet using a single
 * NetVSC message, free the SKBs of the packets copied, except for the
 * last packet. This is done to streamline the handling of the case
 * where the last packet only had the RNDIS descriptor copied to the
 * send buffer, with the data pointers included in the NetVSC message.
 */
int netvsc_send(struct net_device *ndev,
		struct hv_netvsc_packet *packet,
		struct rndis_message *rndis_msg,
		struct hv_page_buffer *pb,
		struct sk_buff *skb,
		bool xdp_tx)
{}

/* Send pending recv completions */
static int send_recv_completions(struct net_device *ndev,
				 struct netvsc_device *nvdev,
				 struct netvsc_channel *nvchan)
{}

/* Count how many receive completions are outstanding */
static void recv_comp_slot_avail(const struct netvsc_device *nvdev,
				 const struct multi_recv_comp *mrc,
				 u32 *filled, u32 *avail)
{}

/* Add receive complete to ring to send to host. */
static void enq_receive_complete(struct net_device *ndev,
				 struct netvsc_device *nvdev, u16 q_idx,
				 u64 tid, u32 status)
{}

static int netvsc_receive(struct net_device *ndev,
			  struct netvsc_device *net_device,
			  struct netvsc_channel *nvchan,
			  const struct vmpacket_descriptor *desc)
{}

static void netvsc_send_table(struct net_device *ndev,
			      struct netvsc_device *nvscdev,
			      const struct nvsp_message *nvmsg,
			      u32 msglen)
{}

static void netvsc_send_vf(struct net_device *ndev,
			   const struct nvsp_message *nvmsg,
			   u32 msglen)
{}

static void netvsc_receive_inband(struct net_device *ndev,
				  struct netvsc_device *nvscdev,
				  const struct vmpacket_descriptor *desc)
{}

static int netvsc_process_raw_pkt(struct hv_device *device,
				  struct netvsc_channel *nvchan,
				  struct netvsc_device *net_device,
				  struct net_device *ndev,
				  const struct vmpacket_descriptor *desc,
				  int budget)
{}

static struct hv_device *netvsc_channel_to_device(struct vmbus_channel *channel)
{}

/* Network processing softirq
 * Process data in incoming ring buffer from host
 * Stops when ring is empty or budget is met or exceeded.
 */
int netvsc_poll(struct napi_struct *napi, int budget)
{}

/* Call back when data is available in host ring buffer.
 * Processing is deferred until network softirq (NAPI)
 */
void netvsc_channel_cb(void *context)
{}

/*
 * netvsc_device_add - Callback when the device belonging to this
 * driver is added
 */
struct netvsc_device *netvsc_device_add(struct hv_device *device,
				const struct netvsc_device_info *device_info)
{}