// 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. Load more
// 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;