1903 lines · 53.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (c) 2009, Microsoft Corporation. * * Authors: *   Haiyang Zhang <haiyangz@microsoft.com> *   Hank Janssen  <hjanssen@microsoft.com> */#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h>#include <linux/sched.h>#include <linux/wait.h>#include <linux/mm.h>#include <linux/highmem.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" static struct workqueue_struct *netvsc_wq; /* * Switch the data path from the synthetic interface to the VF * interface. */int netvsc_switch_datapath(struct net_device *ndev, bool vf){	struct net_device_context *net_device_ctx = netdev_priv(ndev);	struct hv_device *dev = net_device_ctx->device_ctx;	struct netvsc_device *nv_dev = rtnl_dereference(net_device_ctx->nvdev);	struct nvsp_message *init_pkt = &nv_dev->channel_init_pkt;	int ret, retry = 0; 	/* Block sending traffic to VF if it's about to be gone */	if (!vf)		net_device_ctx->data_path_is_vf = vf; 	memset(init_pkt, 0, sizeof(struct nvsp_message));	init_pkt->hdr.msg_type = NVSP_MSG4_TYPE_SWITCH_DATA_PATH;	if (vf)		init_pkt->msg.v4_msg.active_dp.active_datapath =			NVSP_DATAPATH_VF;	else		init_pkt->msg.v4_msg.active_dp.active_datapath =			NVSP_DATAPATH_SYNTHETIC; again:	trace_nvsp_send(ndev, init_pkt); 	ret = vmbus_sendpacket(dev->channel, init_pkt,			       sizeof(struct nvsp_message),			       (unsigned long)init_pkt, VM_PKT_DATA_INBAND,			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 	/* If failed to switch to/from VF, let data_path_is_vf stay false,	 * so we use synthetic path to send data.	 */	if (ret) {		if (ret != -EAGAIN) {			netdev_err(ndev,				   "Unable to send sw datapath msg, err: %d\n",				   ret);			return ret;		} 		if (retry++ < RETRY_MAX) {			usleep_range(RETRY_US_LO, RETRY_US_HI);			goto again;		} else {			netdev_err(				ndev,				"Retry failed to send sw datapath msg, err: %d\n",				ret);			return ret;		}	} 	wait_for_completion(&nv_dev->channel_init_wait);	net_device_ctx->data_path_is_vf = vf; 	return 0;} /* 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){	struct netvsc_device *nvdev =		container_of(w, struct netvsc_device, subchan_work);	struct rndis_device *rdev;	int i, ret; 	/* Avoid deadlock with device removal already under RTNL */	if (!rtnl_trylock()) {		schedule_work(w);		return;	} 	rdev = nvdev->extension;	if (rdev) {		ret = rndis_set_subchannel(rdev->ndev, nvdev, NULL);		if (ret == 0) {			netif_device_attach(rdev->ndev);		} else {			/* fallback to only primary channel */			for (i = 1; i < nvdev->num_chn; i++)				netif_napi_del(&nvdev->chan_table[i].napi); 			nvdev->max_chn = 1;			nvdev->num_chn = 1;		}	} 	rtnl_unlock();} static void __free_netvsc_device(struct netvsc_device *nvdev){	int i; 	kfree(nvdev->extension); 	vmbus_free_buffer(nvdev->recv_buf, nvdev->recv_buf_chunks,			  nvdev->recv_buf_chunk_cnt);	vmbus_free_buffer(nvdev->send_buf, nvdev->send_buf_chunks,			  nvdev->send_buf_chunk_cnt);	bitmap_free(nvdev->send_section_map); 	for (i = 0; i < VRSS_CHANNEL_MAX; i++) {		xdp_rxq_info_unreg(&nvdev->chan_table[i].xdp_rxq);		kfree(nvdev->chan_table[i].recv_buf);		vfree(nvdev->chan_table[i].mrc.slots);	} 	kfree(nvdev);} static void free_netvsc_device(struct work_struct *w){	struct rcu_work *rwork = to_rcu_work(w); 	__free_netvsc_device(container_of(rwork, struct netvsc_device, rwork));} int netvsc_workqueue_init(void){	netvsc_wq = alloc_workqueue("hv_netvsc", WQ_UNBOUND, 0); 	return netvsc_wq ? 0 : -ENOMEM;} void netvsc_workqueue_destroy(void){	rcu_barrier();	destroy_workqueue(netvsc_wq);} static struct netvsc_device *alloc_net_device(void){	struct netvsc_device *net_device; 	net_device = kzalloc_obj(struct netvsc_device);	if (!net_device)		return NULL; 	init_waitqueue_head(&net_device->wait_drain);	net_device->destroy = false;	net_device->tx_disable = true; 	net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;	net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT; 	init_completion(&net_device->channel_init_wait);	init_waitqueue_head(&net_device->subchan_open);	INIT_WORK(&net_device->subchan_work, netvsc_subchan_work);	INIT_RCU_WORK(&net_device->rwork, free_netvsc_device); 	return net_device;} static void free_netvsc_device_rcu(struct netvsc_device *nvdev){	/*	 * Defer the actual free to process context: vunmap() and	 * set_memory_encrypted() cannot run from RCU softirq context.	 */	queue_rcu_work(netvsc_wq, &nvdev->rwork);} static void netvsc_revoke_recv_buf(struct hv_device *device,				   struct netvsc_device *net_device,				   struct net_device *ndev){	struct nvsp_message *revoke_packet;	int ret; 	/*	 * If we got a section count, it means we received a	 * SendReceiveBufferComplete msg (ie sent	 * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need	 * to send a revoke msg here	 */	if (net_device->recv_section_cnt) {		/* Send the revoke receive buffer */		revoke_packet = &net_device->revoke_packet;		memset(revoke_packet, 0, sizeof(struct nvsp_message)); 		revoke_packet->hdr.msg_type =			NVSP_MSG1_TYPE_REVOKE_RECV_BUF;		revoke_packet->msg.v1_msg.		revoke_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; 		trace_nvsp_send(ndev, revoke_packet); 		ret = vmbus_sendpacket(device->channel,				       revoke_packet,				       sizeof(struct nvsp_message),				       VMBUS_RQST_ID_NO_RESPONSE,				       VM_PKT_DATA_INBAND, 0);		/* If the failure is because the channel is rescinded;		 * ignore the failure since we cannot send on a rescinded		 * channel. This would allow us to properly cleanup		 * even when the channel is rescinded.		 */		if (device->channel->rescind)			ret = 0;		/*		 * If we failed here, we might as well return and		 * have a leak rather than continue and a bugchk		 */		if (ret != 0) {			netdev_err(ndev, "unable to send "				"revoke receive buffer to netvsp\n");			return;		}		net_device->recv_section_cnt = 0;	}} static void netvsc_revoke_send_buf(struct hv_device *device,				   struct netvsc_device *net_device,				   struct net_device *ndev){	struct nvsp_message *revoke_packet;	int ret; 	/* Deal with the send buffer we may have setup.	 * If we got a  send section size, it means we received a	 * NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE msg (ie sent	 * NVSP_MSG1_TYPE_SEND_SEND_BUF msg) therefore, we need	 * to send a revoke msg here	 */	if (net_device->send_section_cnt) {		/* Send the revoke receive buffer */		revoke_packet = &net_device->revoke_packet;		memset(revoke_packet, 0, sizeof(struct nvsp_message)); 		revoke_packet->hdr.msg_type =			NVSP_MSG1_TYPE_REVOKE_SEND_BUF;		revoke_packet->msg.v1_msg.revoke_send_buf.id =			NETVSC_SEND_BUFFER_ID; 		trace_nvsp_send(ndev, revoke_packet); 		ret = vmbus_sendpacket(device->channel,				       revoke_packet,				       sizeof(struct nvsp_message),				       VMBUS_RQST_ID_NO_RESPONSE,				       VM_PKT_DATA_INBAND, 0); 		/* If the failure is because the channel is rescinded;		 * ignore the failure since we cannot send on a rescinded		 * channel. This would allow us to properly cleanup		 * even when the channel is rescinded.		 */		if (device->channel->rescind)			ret = 0; 		/* If we failed here, we might as well return and		 * have a leak rather than continue and a bugchk		 */		if (ret != 0) {			netdev_err(ndev, "unable to send "				   "revoke send buffer to netvsp\n");			return;		}		net_device->send_section_cnt = 0;	}} static void netvsc_teardown_recv_gpadl(struct hv_device *device,				       struct netvsc_device *net_device,				       struct net_device *ndev){	int ret; 	if (net_device->recv_buf_gpadl_handle.gpadl_handle) {		ret = vmbus_teardown_gpadl(device->channel,					   &net_device->recv_buf_gpadl_handle); 		/* If we failed here, we might as well return and have a leak		 * rather than continue and a bugchk		 */		if (ret != 0) {			netdev_err(ndev,				   "unable to teardown receive buffer's gpadl\n");			return;		}	}} static void netvsc_teardown_send_gpadl(struct hv_device *device,				       struct netvsc_device *net_device,				       struct net_device *ndev){	int ret; 	if (net_device->send_buf_gpadl_handle.gpadl_handle) {		ret = vmbus_teardown_gpadl(device->channel,					   &net_device->send_buf_gpadl_handle); 		/* If we failed here, we might as well return and have a leak		 * rather than continue and a bugchk		 */		if (ret != 0) {			netdev_err(ndev,				   "unable to teardown send buffer's gpadl\n");			return;		}	}} int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx){	struct netvsc_channel *nvchan = &net_device->chan_table[q_idx];	int node = cpu_to_node(nvchan->channel->target_cpu);	size_t size; 	size = net_device->recv_completion_cnt * sizeof(struct recv_comp_data);	nvchan->mrc.slots = vzalloc_node(size, node);	if (!nvchan->mrc.slots)		nvchan->mrc.slots = vzalloc(size); 	return nvchan->mrc.slots ? 0 : -ENOMEM;} static int netvsc_init_buf(struct hv_device *device,			   struct netvsc_device *net_device,			   const struct netvsc_device_info *device_info){	struct nvsp_1_message_send_receive_buffer_complete *resp;	struct net_device *ndev = hv_get_drvdata(device);	struct nvsp_message *init_packet;	unsigned int buf_size;	int i, ret = 0; 	/* Get receive buffer area. */	buf_size = device_info->recv_sections * device_info->recv_section_size;	buf_size = roundup(buf_size, PAGE_SIZE); 	/* Legacy hosts only allow smaller receive buffer */	if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_2)		buf_size = min_t(unsigned int, buf_size,				 NETVSC_RECEIVE_BUFFER_SIZE_LEGACY); 	net_device->recv_buf =		vmbus_alloc_buffer(device->channel, buf_size,				   &net_device->recv_buf_chunks,				   &net_device->recv_buf_chunk_cnt);	if (!net_device->recv_buf) {		netdev_err(ndev,			   "unable to allocate receive buffer of size %u\n",			   buf_size);		ret = -ENOMEM;		goto cleanup;	} 	net_device->recv_buf_size = buf_size; 	/*	 * Establish the gpadl handle for this buffer on this	 * channel.  Note: This call uses the vmbus connection rather	 * than the channel to establish the gpadl handle.	 */	ret = vmbus_establish_gpadl_caller_decrypted(device->channel,						     net_device->recv_buf,						     buf_size,						     &net_device->recv_buf_gpadl_handle);	if (ret != 0) {		netdev_err(ndev,			"unable to establish receive buffer's gpadl\n");		goto cleanup;	} 	/* Notify the NetVsp of the gpadl handle */	init_packet = &net_device->channel_init_pkt;	memset(init_packet, 0, sizeof(struct nvsp_message));	init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_RECV_BUF;	init_packet->msg.v1_msg.send_recv_buf.		gpadl_handle = net_device->recv_buf_gpadl_handle.gpadl_handle;	init_packet->msg.v1_msg.		send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; 	trace_nvsp_send(ndev, init_packet); 	/* Send the gpadl notification request */	ret = vmbus_sendpacket(device->channel, init_packet,			       sizeof(struct nvsp_message),			       (unsigned long)init_packet,			       VM_PKT_DATA_INBAND,			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);	if (ret != 0) {		netdev_err(ndev,			"unable to send receive buffer's gpadl to netvsp\n");		goto cleanup;	} 	wait_for_completion(&net_device->channel_init_wait); 	/* Check the response */	resp = &init_packet->msg.v1_msg.send_recv_buf_complete;	if (resp->status != NVSP_STAT_SUCCESS) {		netdev_err(ndev,			   "Unable to complete receive buffer initialization with NetVsp - status %d\n",			   resp->status);		ret = -EINVAL;		goto cleanup;	} 	/* Parse the response */	netdev_dbg(ndev, "Receive sections: %u sub_allocs: size %u count: %u\n",		   resp->num_sections, resp->sections[0].sub_alloc_size,		   resp->sections[0].num_sub_allocs); 	/* There should only be one section for the entire receive buffer */	if (resp->num_sections != 1 || resp->sections[0].offset != 0) {		ret = -EINVAL;		goto cleanup;	} 	net_device->recv_section_size = resp->sections[0].sub_alloc_size;	net_device->recv_section_cnt = resp->sections[0].num_sub_allocs; 	/* Ensure buffer will not overflow */	if (net_device->recv_section_size < NETVSC_MTU_MIN || (u64)net_device->recv_section_size *	    (u64)net_device->recv_section_cnt > (u64)buf_size) {		netdev_err(ndev, "invalid recv_section_size %u\n",			   net_device->recv_section_size);		ret = -EINVAL;		goto cleanup;	} 	for (i = 0; i < VRSS_CHANNEL_MAX; i++) {		struct netvsc_channel *nvchan = &net_device->chan_table[i]; 		nvchan->recv_buf = kzalloc(net_device->recv_section_size, GFP_KERNEL);		if (nvchan->recv_buf == NULL) {			ret = -ENOMEM;			goto cleanup;		}	} 	/* Setup receive completion ring.	 * Add 1 to the recv_section_cnt because at least one entry in a	 * ring buffer has to be empty.	 */	net_device->recv_completion_cnt = net_device->recv_section_cnt + 1;	ret = netvsc_alloc_recv_comp_ring(net_device, 0);	if (ret)		goto cleanup; 	/* Now setup the send buffer. */	buf_size = device_info->send_sections * device_info->send_section_size;	buf_size = round_up(buf_size, PAGE_SIZE); 	net_device->send_buf =		vmbus_alloc_buffer(device->channel, buf_size,				   &net_device->send_buf_chunks,				   &net_device->send_buf_chunk_cnt);	if (!net_device->send_buf) {		netdev_err(ndev, "unable to allocate send buffer of size %u\n",			   buf_size);		ret = -ENOMEM;		goto cleanup;	}	net_device->send_buf_size = buf_size;

Lines 1–500 of 1903.