From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pa0-f48.google.com (mail-pa0-f48.google.com [209.85.220.48]) by dpdk.org (Postfix) with ESMTP id C94269AC4 for ; Wed, 25 Mar 2015 19:11:57 +0100 (CET) Received: by pagj7 with SMTP id j7so36614720pag.2 for ; Wed, 25 Mar 2015 11:11:57 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=sqySb7kkFFmkASDJpAHquKmexdQT6VhePsm/s2Nwu60=; b=ldh6Ra/XzjDxl3plrbGyu9WH+ug2lNW7XDyzLexDsK//4pdHLNGb2LWYEvagwFfIMn 1NQIcpmxKiJuf9wJO/NrcPTGUZREGrn9j5O4YSkgco5UVYf7hJsGSo5yuzZWifdXaslh GCiuoF/inJKcPJTg3LDkbr47A/WokPSqILEN/GUlwn0X3eXiU3HUslitbuoatYdGOuzd pWIleZ233nCf6VSBZ/y2Nc/WZF4tDFxiM4/J0Oe9zyeEhHbO0dX79LPsCBSBIUYqX+1P 2VuJXd0UFYm1RzMlXQ+p3yK1IaAGJF53OB1hhbToXXhKRxun4BJ3xRhg2NjRekMo3lwd cFvg== X-Gm-Message-State: ALoCoQmxFLpukTQhHn32tGos9KZhG3fY6pIhrMrVx1GA0o7KnFx2TZiGzcPiSPhhrX/5Y7+BxmdJ X-Received: by 10.66.63.72 with SMTP id e8mr19019946pas.3.1427307117062; Wed, 25 Mar 2015 11:11:57 -0700 (PDT) Received: from uryu.home.lan ([144.49.132.3]) by mx.google.com with ESMTPSA id h9sm3161177pdo.5.2015.03.25.11.11.55 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 25 Mar 2015 11:11:56 -0700 (PDT) From: Stephen Hemminger X-Google-Original-From: Stephen Hemminger To: simonxiaolinux@hotmail.com, alexmay@microsoft.com, kys@microsoft.com Date: Wed, 25 Mar 2015 11:11:22 -0700 Message-Id: <1427307085-5493-5-git-send-email-shemming@brocade.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1427307085-5493-1-git-send-email-shemming@brocade.com> References: <1427307085-5493-1-git-send-email-shemming@brocade.com> Cc: dev@dpdk.org, Stas Egorov Subject: [dpdk-dev] [PATCH v2 4/7] hv: uio driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 25 Mar 2015 18:11:58 -0000 From: Stephen Hemminger Add new UIO driver in kernel to support DPDK Poll Mode Driver. Signed-off-by: Stas Egorov Signed-off-by: Stephen Hemminger --- lib/librte_eal/linuxapp/Makefile | 3 + lib/librte_eal/linuxapp/hv_uio/Makefile | 57 ++ lib/librte_eal/linuxapp/hv_uio/hv_uio.c | 551 +++++++++++++++++ lib/librte_eal/linuxapp/hv_uio/hyperv_net.h | 907 ++++++++++++++++++++++++++++ 4 files changed, 1518 insertions(+) create mode 100644 lib/librte_eal/linuxapp/hv_uio/Makefile create mode 100644 lib/librte_eal/linuxapp/hv_uio/hv_uio.c create mode 100644 lib/librte_eal/linuxapp/hv_uio/hyperv_net.h diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile index 8fcfdf6..a28d289 100644 --- a/lib/librte_eal/linuxapp/Makefile +++ b/lib/librte_eal/linuxapp/Makefile @@ -41,5 +41,8 @@ endif ifeq ($(CONFIG_RTE_LIBRTE_XEN_DOM0),y) DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += xen_dom0 endif +ifeq ($(CONFIG_RTE_LIBRTE_HV_PMD),y) +DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += hv_uio +endif include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/lib/librte_eal/linuxapp/hv_uio/Makefile b/lib/librte_eal/linuxapp/hv_uio/Makefile new file mode 100644 index 0000000..2ed7771 --- /dev/null +++ b/lib/librte_eal/linuxapp/hv_uio/Makefile @@ -0,0 +1,57 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2015 Intel Corporation. All rights reserved. +# Copyright(c) 2013-2015 Brocade Communications Systems, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# module name and path +# +MODULE = hv_uio +MODULE_PATH = drivers/net/hv_uio + +# +# CFLAGS +# +MODULE_CFLAGS += -I$(SRCDIR) --param max-inline-insns-single=100 +MODULE_CFLAGS += -I$(RTE_OUTPUT)/include +MODULE_CFLAGS += -Winline -Wall -Werror +MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h +ifeq ($(CONFIG_RTE_LIBRTE_HV_DEBUG),y) +MODULE_CFLAGS += -DDBG +endif + +# +# all source are stored in SRCS-y +# +SRCS-y := hv_uio.c + +include $(RTE_SDK)/mk/rte.module.mk diff --git a/lib/librte_eal/linuxapp/hv_uio/hv_uio.c b/lib/librte_eal/linuxapp/hv_uio/hv_uio.c new file mode 100644 index 0000000..4cac075 --- /dev/null +++ b/lib/librte_eal/linuxapp/hv_uio/hv_uio.c @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2013-2015 Brocade Communications Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see . + * + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "hyperv_net.h" + +#define HV_DEVICE_ADD 0 +#define HV_DEVICE_REMOVE 1 +#define HV_RING_SIZE 512 + +static uint mtu = ETH_DATA_LEN; +/* + * List of resources to be mapped to uspace + * can be extended up to MAX_UIO_MAPS(5) items + */ +enum { + TXRX_RING_MAP, + INT_PAGE_MAP, + MON_PAGE_MAP, + RECV_BUF_MAP +}; + +struct hyperv_private_data { + struct netvsc_device *net_device; + struct uio_info *info; +}; + +extern void vmbus_get_monitor_pages(unsigned long *int_page, + unsigned long monitor_pages[2]); + +/* phys addrs of pages in vmbus_connection from hv_vmbus */ +static long unsigned int_page, monitor_pages[2]; + +static inline int +hyperv_uio_find_mem_index(struct uio_info *info, struct vm_area_struct *vma) +{ + if (vma->vm_pgoff < MAX_UIO_MAPS) { + if (unlikely(info->mem[vma->vm_pgoff].size == 0)) + return -1; + return (int)vma->vm_pgoff; + } + return -1; +} + +static int +hyperv_uio_mmap(struct uio_info *info, struct vm_area_struct *vma) +{ + int mi = hyperv_uio_find_mem_index(info, vma); + if (mi < 0) + return -EINVAL; + + return remap_pfn_range(vma, + vma->vm_start, + virt_to_phys((void*)info->mem[mi].addr) >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +static struct netvsc_device * +alloc_net_device(struct hv_device *dev) +{ + struct netvsc_device *net_device; + + net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL); + if (!net_device) { + pr_err("unable to allocate memory for netvsc_device\n"); + return NULL; + } + + init_waitqueue_head(&net_device->wait_drain); + net_device->start_remove = false; + net_device->destroy = false; + net_device->dev = dev; + net_device->ndev = hv_get_drvdata(dev); + net_device->recv_section_cnt = 0; + + return net_device; +} + +/* Negotiate NVSP protocol version */ +static int +negotiate_nvsp_ver(struct hv_device *dev, + struct netvsc_device *net_device, + struct nvsp_message *init_packet, + u32 nvsp_ver) +{ + int ret; + + memset(init_packet, 0, sizeof(struct nvsp_message)); + init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; + init_packet->msg.init_msg.init.min_protocol_ver = nvsp_ver; + init_packet->msg.init_msg.init.max_protocol_ver = nvsp_ver; + + /* Send the init request */ + ret = vmbus_sendpacket(dev->channel, init_packet, + sizeof(struct nvsp_message), + (unsigned long)init_packet, + VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + + if (ret) { + pr_err("unable to send nvsp negotiation packet\n"); + return ret; + } + + if (nvsp_ver != NVSP_PROTOCOL_VERSION_2) + return 0; + + /* NVSPv2 only: Send NDIS config */ + memset(init_packet, 0, sizeof(struct nvsp_message)); + init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG; + init_packet->msg.v2_msg.send_ndis_config.mtu = mtu; + init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1; + + ret = vmbus_sendpacket(dev->channel, init_packet, + sizeof(struct nvsp_message), + (unsigned long)init_packet, + VM_PKT_DATA_INBAND, 0); + + return ret; +} + +static int +netvsc_destroy_recv_buf(struct netvsc_device *net_device) +{ + struct nvsp_message *revoke_packet; + int ret = 0; + + /* + * 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; + + ret = vmbus_sendpacket(net_device->dev->channel, + revoke_packet, + sizeof(struct nvsp_message), + (unsigned long)revoke_packet, + VM_PKT_DATA_INBAND, 0); + /* + * If we failed here, we might as well return and + * have a leak rather than continue and a bugchk + */ + if (ret != 0) { + pr_err("unable to send " + "revoke receive buffer to netvsp\n"); + return ret; + } + } + + /* Teardown the gpadl on the vsp end */ + if (net_device->recv_buf_gpadl_handle) { + pr_devel("trying to teardown gpadl...\n"); + ret = vmbus_teardown_gpadl(net_device->dev->channel, + net_device->recv_buf_gpadl_handle); + + if (ret) { + pr_err("unable to teardown receive buffer's gpadl\n"); + return ret; + } + net_device->recv_buf_gpadl_handle = 0; + } + + if (net_device->recv_buf) { + /* Free up the receive buffer */ + free_pages((unsigned long)net_device->recv_buf, + get_order(net_device->recv_buf_size)); + net_device->recv_buf = NULL; + } + + if (net_device->recv_section) { + net_device->recv_section_cnt = 0; + kfree(net_device->recv_section); + net_device->recv_section = NULL; + } + + return ret; +} + +static int +netvsc_init_recv_buf(struct hv_device *dev, struct netvsc_device *net_dev) +{ + int ret = 0; + struct nvsp_message *init_packet; + + if (!net_dev) + return -ENODEV; + + net_dev->recv_buf = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, + get_order(net_dev->recv_buf_size)); + if (!net_dev->recv_buf) { + pr_err("unable to allocate receive " + "buffer of size %d\n", net_dev->recv_buf_size); + ret = -ENOMEM; + goto cleanup; + } + + /* + * 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(dev->channel, net_dev->recv_buf, + net_dev->recv_buf_size, + &net_dev->recv_buf_gpadl_handle); + if (ret != 0) { + pr_err("unable to establish receive buffer's gpadl\n"); + goto cleanup; + } + + + /* Notify the NetVsp of the gpadl handle */ + init_packet = &net_dev->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_dev->recv_buf_gpadl_handle; + init_packet->msg.v1_msg. + send_recv_buf.id = NETVSC_RECEIVE_BUFFER_ID; + + /* Send the gpadl notification request */ + ret = vmbus_sendpacket(dev->channel, init_packet, + sizeof(struct nvsp_message), + (unsigned long)init_packet, + VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (ret != 0) { + pr_err("unable to send receive buffer's gpadl to netvsp\n"); + goto cleanup; + } + + net_dev->recv_section_cnt = 1; + goto exit; + +cleanup: + netvsc_destroy_recv_buf(net_dev); + +exit: + return ret; +} + +static int +netvsc_connect_vsp(struct hv_device *dev, struct netvsc_device *net_dev) +{ + int ret; + struct nvsp_message *init_packet; + int ndis_version; + + if (!net_dev) + return -ENODEV; + + init_packet = &net_dev->channel_init_pkt; + + /* Negotiate the latest NVSP protocol supported */ + if (negotiate_nvsp_ver(dev, net_dev, init_packet, + NVSP_PROTOCOL_VERSION_2) == 0) { + net_dev->nvsp_version = NVSP_PROTOCOL_VERSION_2; + } else if (negotiate_nvsp_ver(dev, net_dev, init_packet, + NVSP_PROTOCOL_VERSION_1) == 0) { + net_dev->nvsp_version = NVSP_PROTOCOL_VERSION_1; + } else { + return -EPROTO; + } + + pr_devel("Negotiated NVSP version:%x\n", net_dev->nvsp_version); + + /* Send the ndis version */ + memset(init_packet, 0, sizeof(struct nvsp_message)); + + ndis_version = 0x00050001; + + init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER; + init_packet->msg.v1_msg. + send_ndis_ver.ndis_major_ver = + (ndis_version & 0xFFFF0000) >> 16; + init_packet->msg.v1_msg. + send_ndis_ver.ndis_minor_ver = + ndis_version & 0xFFFF; + + /* Send the init request */ + ret = vmbus_sendpacket(dev->channel, init_packet, + sizeof(struct nvsp_message), + (unsigned long)init_packet, + VM_PKT_DATA_INBAND, 0); + if (ret != 0) { + pr_err("unable to send init_packet via vmbus\n"); + return ret; + } + + /* Post the big receive buffer to NetVSP */ + ret = netvsc_init_recv_buf(dev, net_dev); + + return ret; +} + +static int +hyperv_dev_add(struct hv_device *dev, struct netvsc_device *net_dev) +{ + int ret = 0; + + net_dev->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; + + ret = vmbus_open(dev->channel, HV_RING_SIZE * PAGE_SIZE, + HV_RING_SIZE * PAGE_SIZE, NULL, 0, NULL, dev); + if (ret) { + pr_err("unable to open channel: %d\n", ret); + return ret; + } + dev->channel->inbound.ring_buffer->interrupt_mask = 1; + + ret = netvsc_connect_vsp(dev, net_dev); + if (ret) { + pr_err("unable to connect to NetVSP: %d\n", ret); + goto close; + } + + return ret; + +close: + vmbus_close(dev->channel); + + return ret; +} + +static void +hyperv_dev_remove(struct hv_device *dev, struct netvsc_device *net_dev) +{ + if (net_dev->recv_buf) { + netvsc_destroy_recv_buf(net_dev); + vmbus_close(dev->channel); + } +} + +#define MAX_HV_DEVICE_NUM 256 +static struct hv_device *hv_device_list[MAX_HV_DEVICE_NUM]; + +/* + * This callback is set as irqcontrol for uio, it can be used for mtu changing + * The variable arg consists of command, device number(see HV_DEV_ID) + * and value of MTU(see HV_MTU) + */ +static int +hyperv_write_cb(struct uio_info *info, s32 arg) +{ + struct hv_device *dev; + int ret, cmd = arg & 1, dev_num = (arg >> 1) & 0xFF; + struct hyperv_private_data *pdata; + struct netvsc_device *net_device; + + dev = hv_device_list[dev_num]; + if (!dev) + return 0; + pdata = hv_get_drvdata(dev); + net_device = pdata->net_device; + switch (cmd) { + case HV_DEVICE_ADD: + mtu = arg >> 9; + pr_devel("New mtu = %u\n", mtu); + ret = hyperv_dev_add(dev, net_device); + if (!ret) { + info->mem[TXRX_RING_MAP].addr = + (phys_addr_t)(dev->channel->ringbuffer_pages); + info->mem[RECV_BUF_MAP].addr = (phys_addr_t)(net_device->recv_buf); + return sizeof(s32); + } + break; + case HV_DEVICE_REMOVE: + hyperv_dev_remove(dev, net_device); + return sizeof(s32); + } + + return 0; +} + +static int +hyperv_probe(struct hv_device *dev, + const struct hv_vmbus_device_id *dev_id) +{ + int ret; + struct hyperv_private_data *pdata; + struct uio_info *info; + struct netvsc_device *net_device; + + pdata = kzalloc(sizeof(struct hyperv_private_data), GFP_KERNEL); + if (!pdata) { + pr_err("Failed to allocate hyperv_private_data\n"); + return -ENOMEM; + } + + info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); + if (!info) { + pr_err("Failed to allocate uio_info\n"); + kfree(pdata); + return -ENOMEM; + } + + net_device = alloc_net_device(dev); + if (!net_device) { + kfree(pdata); + kfree(info); + return -ENOMEM; + } + + ret = hyperv_dev_add(dev, net_device); + if (ret) { + kfree(pdata); + kfree(info); + kfree(net_device); + return ret; + } + + /* Fill general uio info */ + info->name = "hv_uio"; + info->version = "1.0"; + info->irqcontrol = hyperv_write_cb; + info->irq = UIO_IRQ_CUSTOM; + + /* mem resources */ + info->mem[TXRX_RING_MAP].name = "txrx_rings"; + info->mem[TXRX_RING_MAP].addr = + (phys_addr_t)(dev->channel->ringbuffer_pages); + info->mem[TXRX_RING_MAP].size = HV_RING_SIZE * PAGE_SIZE * 2; + info->mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL; + + info->mem[INT_PAGE_MAP].name = "int_page"; + info->mem[INT_PAGE_MAP].addr = + (phys_addr_t)(int_page); + info->mem[INT_PAGE_MAP].size = PAGE_SIZE; + info->mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL; + + info->mem[MON_PAGE_MAP].name = "monitor_pages"; + info->mem[MON_PAGE_MAP].addr = + (phys_addr_t)(monitor_pages[1]); + info->mem[MON_PAGE_MAP].size = PAGE_SIZE; + info->mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL; + + info->mem[RECV_BUF_MAP].name = "recv_buf"; + info->mem[RECV_BUF_MAP].addr = (phys_addr_t)(net_device->recv_buf); + info->mem[RECV_BUF_MAP].size = net_device->recv_buf_size; + info->mem[RECV_BUF_MAP].memtype = UIO_MEM_LOGICAL; + + info->mmap = hyperv_uio_mmap; + + pr_devel("register hyperv driver for hv_device {%pUl}\n", dev->dev_instance.b); + ret = uio_register_device(&dev->device, info); + if (ret) + pr_err("Failed to register uio device for hyperv\n"); + else + hv_device_list[dev->channel->offermsg.child_relid] = dev; + + pdata->info = info; + pdata->net_device = net_device; + hv_set_drvdata(dev, pdata); + + return ret; +} + +static int +hyperv_remove(struct hv_device *dev) +{ + struct hyperv_private_data *pdata; + struct uio_info *info; + struct netvsc_device *net_dev; + + pr_devel("unregister hyperv driver for hv_device {%pUl}\n", + dev->dev_instance.b); + + pdata = hv_get_drvdata(dev); + info = pdata->info; + uio_unregister_device(info); + kfree(info); + + net_dev = pdata->net_device; + hv_set_drvdata(dev, NULL); + + hyperv_dev_remove(dev, net_dev); + + kfree(net_dev); + kfree(pdata); + + return 0; +} + +static const struct hv_vmbus_device_id hyperv_id_table[] = { + { HV_NIC_GUID, }, + { }, +}; + +MODULE_DEVICE_TABLE(vmbus, hyperv_id_table); + +static struct hv_driver hv_uio_drv = { + .name = KBUILD_MODNAME, + .id_table = hyperv_id_table, + .probe = hyperv_probe, + .remove = hyperv_remove, +}; + +static int __init +hyperv_module_init(void) +{ + vmbus_get_monitor_pages(&int_page, monitor_pages); + + return vmbus_driver_register(&hv_uio_drv); +} + +static void __exit +hyperv_module_exit(void) +{ + vmbus_driver_unregister(&hv_uio_drv); +} + +module_init(hyperv_module_init); +module_exit(hyperv_module_exit); + +MODULE_DESCRIPTION("UIO driver for Hyper-V netVSC"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Brocade"); diff --git a/lib/librte_eal/linuxapp/hv_uio/hyperv_net.h b/lib/librte_eal/linuxapp/hv_uio/hyperv_net.h new file mode 100644 index 0000000..8097779 --- /dev/null +++ b/lib/librte_eal/linuxapp/hv_uio/hyperv_net.h @@ -0,0 +1,907 @@ +/* + * + * Copyright (c) 2011, Microsoft Corporation. + * Copyright (c) 2013-2015 Brocade Communications Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Authors: + * Haiyang Zhang + * Hank Janssen + * K. Y. Srinivasan + * + */ + +#ifndef _HYPERV_NET_H +#define _HYPERV_NET_H + +#include +#include +#include + +/* Fwd declaration */ +struct hv_netvsc_packet; + +/* Represent the xfer page packet which contains 1 or more netvsc packet */ +struct xferpage_packet { + struct list_head list_ent; + u32 status; + + /* # of netvsc packets this xfer packet contains */ + u32 count; +}; + +/* + * Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame + * within the RNDIS + */ +struct hv_netvsc_packet { + /* Bookkeeping stuff */ + struct list_head list_ent; + u32 status; + + struct hv_device *device; + bool is_data_pkt; + u16 vlan_tci; + + /* + * Valid only for receives when we break a xfer page packet + * into multiple netvsc packets + */ + struct xferpage_packet *xfer_page_pkt; + + union { + struct { + u64 recv_completion_tid; + void *recv_completion_ctx; + void (*recv_completion)(void *context); + } recv; + struct { + u64 send_completion_tid; + void *send_completion_ctx; + void (*send_completion)(void *context); + } send; + } completion; + + /* This points to the memory after page_buf */ + void *extension; + + u32 total_data_buflen; + /* Points to the send/receive buffer where the ethernet frame is */ + void *data; + u32 page_buf_cnt; + struct hv_page_buffer page_buf[0]; +}; + +struct netvsc_device_info { + unsigned char mac_adr[ETH_ALEN]; + bool link_state; /* 0 - link up, 1 - link down */ + int ring_size; +}; + +enum rndis_device_state { + RNDIS_DEV_UNINITIALIZED = 0, + RNDIS_DEV_INITIALIZING, + RNDIS_DEV_INITIALIZED, + RNDIS_DEV_DATAINITIALIZED, +}; + +struct rndis_device { + struct netvsc_device *net_dev; + + enum rndis_device_state state; + bool link_state; + atomic_t new_req_id; + + spinlock_t request_lock; + struct list_head req_list; + + unsigned char hw_mac_adr[ETH_ALEN]; +}; + + +/* Interface */ +int netvsc_device_add(struct hv_device *device, void *additional_info); +int netvsc_device_remove(struct hv_device *device); +int netvsc_send(struct hv_device *device, + struct hv_netvsc_packet *packet); +void netvsc_linkstatus_callback(struct hv_device *device_obj, + unsigned int status); +int netvsc_recv_callback(struct hv_device *device_obj, + struct hv_netvsc_packet *packet); +int rndis_filter_open(struct hv_device *dev); +int rndis_filter_close(struct hv_device *dev); +int rndis_filter_device_add(struct hv_device *dev, + void *additional_info); +void rndis_filter_device_remove(struct hv_device *dev); +int rndis_filter_receive(struct hv_device *dev, + struct hv_netvsc_packet *pkt); + + + +int rndis_filter_send(struct hv_device *dev, + struct hv_netvsc_packet *pkt); + +int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); +int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac); + + +#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF) + +#define NVSP_PROTOCOL_VERSION_1 2 +#define NVSP_PROTOCOL_VERSION_2 0x30002 + +enum { + NVSP_MSG_TYPE_NONE = 0, + + /* Init Messages */ + NVSP_MSG_TYPE_INIT = 1, + NVSP_MSG_TYPE_INIT_COMPLETE = 2, + + NVSP_VERSION_MSG_START = 100, + + /* Version 1 Messages */ + NVSP_MSG1_TYPE_SEND_NDIS_VER = NVSP_VERSION_MSG_START, + + NVSP_MSG1_TYPE_SEND_RECV_BUF, + NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE, + NVSP_MSG1_TYPE_REVOKE_RECV_BUF, + + NVSP_MSG1_TYPE_SEND_SEND_BUF, + NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE, + NVSP_MSG1_TYPE_REVOKE_SEND_BUF, + + NVSP_MSG1_TYPE_SEND_RNDIS_PKT, + NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE, + + /* Version 2 messages */ + NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF, + NVSP_MSG2_TYPE_SEND_CHIMNEY_DELEGATED_BUF_COMP, + NVSP_MSG2_TYPE_REVOKE_CHIMNEY_DELEGATED_BUF, + + NVSP_MSG2_TYPE_RESUME_CHIMNEY_RX_INDICATION, + + NVSP_MSG2_TYPE_TERMINATE_CHIMNEY, + NVSP_MSG2_TYPE_TERMINATE_CHIMNEY_COMP, + + NVSP_MSG2_TYPE_INDICATE_CHIMNEY_EVENT, + + NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT, + NVSP_MSG2_TYPE_SEND_CHIMNEY_PKT_COMP, + + NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ, + NVSP_MSG2_TYPE_POST_CHIMNEY_RECV_REQ_COMP, + + NVSP_MSG2_TYPE_ALLOC_RXBUF, + NVSP_MSG2_TYPE_ALLOC_RXBUF_COMP, + + NVSP_MSG2_TYPE_FREE_RXBUF, + + NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT, + NVSP_MSG2_TYPE_SEND_VMQ_RNDIS_PKT_COMP, + + NVSP_MSG2_TYPE_SEND_NDIS_CONFIG, + + NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE, + NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP, +}; + +enum { + NVSP_STAT_NONE = 0, + NVSP_STAT_SUCCESS, + NVSP_STAT_FAIL, + NVSP_STAT_PROTOCOL_TOO_NEW, + NVSP_STAT_PROTOCOL_TOO_OLD, + NVSP_STAT_INVALID_RNDIS_PKT, + NVSP_STAT_BUSY, + NVSP_STAT_PROTOCOL_UNSUPPORTED, + NVSP_STAT_MAX, +}; + +struct nvsp_message_header { + u32 msg_type; +}; + +/* Init Messages */ + +/* + * This message is used by the VSC to initialize the channel after the channels + * has been opened. This message should never include anything other then + * versioning (i.e. this message will be the same for ever). + */ +struct nvsp_message_init { + u32 min_protocol_ver; + u32 max_protocol_ver; +} __packed; + +/* + * This message is used by the VSP to complete the initialization of the + * channel. This message should never include anything other then versioning + * (i.e. this message will be the same for ever). + */ +struct nvsp_message_init_complete { + u32 negotiated_protocol_ver; + u32 max_mdl_chain_len; + u32 status; +} __packed; + +union nvsp_message_init_uber { + struct nvsp_message_init init; + struct nvsp_message_init_complete init_complete; +} __packed; + +/* Version 1 Messages */ + +/* + * This message is used by the VSC to send the NDIS version to the VSP. The VSP + * can use this information when handling OIDs sent by the VSC. + */ +struct nvsp_1_message_send_ndis_version { + u32 ndis_major_ver; + u32 ndis_minor_ver; +} __packed; + +/* + * This message is used by the VSC to send a receive buffer to the VSP. The VSP + * can then use the receive buffer to send data to the VSC. + */ +struct nvsp_1_message_send_receive_buffer { + u32 gpadl_handle; + u16 id; +} __packed; + +struct nvsp_1_receive_buffer_section { + u32 offset; + u32 sub_alloc_size; + u32 num_sub_allocs; + u32 end_offset; +} __packed; + +/* + * This message is used by the VSP to acknowledge a receive buffer send by the + * VSC. This message must be sent by the VSP before the VSP uses the receive + * buffer. + */ +struct nvsp_1_message_send_receive_buffer_complete { + u32 status; + u32 num_sections; + + /* + * The receive buffer is split into two parts, a large suballocation + * section and a small suballocation section. These sections are then + * suballocated by a certain size. + */ + + /* + * For example, the following break up of the receive buffer has 6 + * large suballocations and 10 small suballocations. + */ + + /* + * | Large Section | | Small Section | + * ------------------------------------------------------------ + * | | | | | | | | | | | | | | | | | | + * | | + * LargeOffset SmallOffset + */ + + struct nvsp_1_receive_buffer_section sections[1]; +} __packed; + +/* + * This message is sent by the VSC to revoke the receive buffer. After the VSP + * completes this transaction, the vsp should never use the receive buffer + * again. + */ +struct nvsp_1_message_revoke_receive_buffer { + u16 id; +}; + +/* + * This message is used by the VSC to send a send buffer to the VSP. The VSC + * can then use the send buffer to send data to the VSP. + */ +struct nvsp_1_message_send_send_buffer { + u32 gpadl_handle; + u16 id; +} __packed; + +/* + * This message is used by the VSP to acknowledge a send buffer sent by the + * VSC. This message must be sent by the VSP before the VSP uses the sent + * buffer. + */ +struct nvsp_1_message_send_send_buffer_complete { + u32 status; + + /* + * The VSC gets to choose the size of the send buffer and the VSP gets + * to choose the sections size of the buffer. This was done to enable + * dynamic reconfigurations when the cost of GPA-direct buffers + * decreases. + */ + u32 section_size; +} __packed; + +/* + * This message is sent by the VSC to revoke the send buffer. After the VSP + * completes this transaction, the vsp should never use the send buffer again. + */ +struct nvsp_1_message_revoke_send_buffer { + u16 id; +}; + +/* + * This message is used by both the VSP and the VSC to send a RNDIS message to + * the opposite channel endpoint. + */ +struct nvsp_1_message_send_rndis_packet { + /* + * This field is specified by RNIDS. They assume there's two different + * channels of communication. However, the Network VSP only has one. + * Therefore, the channel travels with the RNDIS packet. + */ + u32 channel_type; + + /* + * This field is used to send part or all of the data through a send + * buffer. This values specifies an index into the send buffer. If the + * index is 0xFFFFFFFF, then the send buffer is not being used and all + * of the data was sent through other VMBus mechanisms. + */ + u32 send_buf_section_index; + u32 send_buf_section_size; +} __packed; + +/* + * This message is used by both the VSP and the VSC to complete a RNDIS message + * to the opposite channel endpoint. At this point, the initiator of this + * message cannot use any resources associated with the original RNDIS packet. + */ +struct nvsp_1_message_send_rndis_packet_complete { + u32 status; +}; + +union nvsp_1_message_uber { + struct nvsp_1_message_send_ndis_version send_ndis_ver; + + struct nvsp_1_message_send_receive_buffer send_recv_buf; + struct nvsp_1_message_send_receive_buffer_complete + send_recv_buf_complete; + struct nvsp_1_message_revoke_receive_buffer revoke_recv_buf; + + struct nvsp_1_message_send_send_buffer send_send_buf; + struct nvsp_1_message_send_send_buffer_complete send_send_buf_complete; + struct nvsp_1_message_revoke_send_buffer revoke_send_buf; + + struct nvsp_1_message_send_rndis_packet send_rndis_pkt; + struct nvsp_1_message_send_rndis_packet_complete + send_rndis_pkt_complete; +} __packed; + + +/* + * Network VSP protocol version 2 messages: + */ +struct nvsp_2_vsc_capability { + union { + u64 data; + struct { + u64 vmq:1; + u64 chimney:1; + u64 sriov:1; + u64 ieee8021q:1; + u64 correlation_id:1; + }; + }; +} __packed; + +struct nvsp_2_send_ndis_config { + u32 mtu; + u32 reserved; + struct nvsp_2_vsc_capability capability; +} __packed; + +/* Allocate receive buffer */ +struct nvsp_2_alloc_rxbuf { + /* Allocation ID to match the allocation request and response */ + u32 alloc_id; + + /* Length of the VM shared memory receive buffer that needs to + * be allocated + */ + u32 len; +} __packed; + +/* Allocate receive buffer complete */ +struct nvsp_2_alloc_rxbuf_comp { + /* The NDIS_STATUS code for buffer allocation */ + u32 status; + + u32 alloc_id; + + /* GPADL handle for the allocated receive buffer */ + u32 gpadl_handle; + + /* Receive buffer ID */ + u64 recv_buf_id; +} __packed; + +struct nvsp_2_free_rxbuf { + u64 recv_buf_id; +} __packed; + +union nvsp_2_message_uber { + struct nvsp_2_send_ndis_config send_ndis_config; + struct nvsp_2_alloc_rxbuf alloc_rxbuf; + struct nvsp_2_alloc_rxbuf_comp alloc_rxbuf_comp; + struct nvsp_2_free_rxbuf free_rxbuf; +} __packed; + +union nvsp_all_messages { + union nvsp_message_init_uber init_msg; + union nvsp_1_message_uber v1_msg; + union nvsp_2_message_uber v2_msg; +} __packed; + +/* ALL Messages */ +struct nvsp_message { + struct nvsp_message_header hdr; + union nvsp_all_messages msg; +} __packed; + + +#define NETVSC_MTU 65536 + +#define NETVSC_RECEIVE_BUFFER_SIZE (MAX_ORDER_NR_PAGES * PAGE_SIZE) + +#define NETVSC_RECEIVE_BUFFER_ID 0xcafe + +/* Per netvsc channel-specific */ +struct netvsc_device { + struct hv_device *dev; + + u32 nvsp_version; + + atomic_t num_outstanding_sends; + wait_queue_head_t wait_drain; + bool start_remove; + bool destroy; + /* + * List of free preallocated hv_netvsc_packet to represent receive + * packet + */ + struct list_head recv_pkt_list; + spinlock_t recv_pkt_list_lock; + + /* Receive buffer allocated by us but manages by NetVSP */ + void *recv_buf; + u32 recv_buf_size; + u32 recv_buf_gpadl_handle; + u32 recv_section_cnt; + struct nvsp_1_receive_buffer_section *recv_section; + + /* Used for NetVSP initialization protocol */ + struct completion channel_init_wait; + struct nvsp_message channel_init_pkt; + + struct nvsp_message revoke_packet; + /* unsigned char HwMacAddr[HW_MACADDR_LEN]; */ + + struct net_device *ndev; + + /* Holds rndis device info */ + void *extension; +}; + +/* NdisInitialize message */ +struct rndis_initialize_request { + u32 req_id; + u32 major_ver; + u32 minor_ver; + u32 max_xfer_size; +}; + +/* Response to NdisInitialize */ +struct rndis_initialize_complete { + u32 req_id; + u32 status; + u32 major_ver; + u32 minor_ver; + u32 dev_flags; + u32 medium; + u32 max_pkt_per_msg; + u32 max_xfer_size; + u32 pkt_alignment_factor; + u32 af_list_offset; + u32 af_list_size; +}; + +/* Call manager devices only: Information about an address family */ +/* supported by the device is appended to the response to NdisInitialize. */ +struct rndis_co_address_family { + u32 address_family; + u32 major_ver; + u32 minor_ver; +}; + +/* NdisHalt message */ +struct rndis_halt_request { + u32 req_id; +}; + +/* NdisQueryRequest message */ +struct rndis_query_request { + u32 req_id; + u32 oid; + u32 info_buflen; + u32 info_buf_offset; + u32 dev_vc_handle; +}; + +/* Response to NdisQueryRequest */ +struct rndis_query_complete { + u32 req_id; + u32 status; + u32 info_buflen; + u32 info_buf_offset; +}; + +/* NdisSetRequest message */ +struct rndis_set_request { + u32 req_id; + u32 oid; + u32 info_buflen; + u32 info_buf_offset; + u32 dev_vc_handle; +}; + +/* Response to NdisSetRequest */ +struct rndis_set_complete { + u32 req_id; + u32 status; +}; + +/* NdisReset message */ +struct rndis_reset_request { + u32 reserved; +}; + +/* Response to NdisReset */ +struct rndis_reset_complete { + u32 status; + u32 addressing_reset; +}; + +/* NdisMIndicateStatus message */ +struct rndis_indicate_status { + u32 status; + u32 status_buflen; + u32 status_buf_offset; +}; + +/* Diagnostic information passed as the status buffer in */ +/* struct rndis_indicate_status messages signifying error conditions. */ +struct rndis_diagnostic_info { + u32 diag_status; + u32 error_offset; +}; + +/* NdisKeepAlive message */ +struct rndis_keepalive_request { + u32 req_id; +}; + +/* Response to NdisKeepAlive */ +struct rndis_keepalive_complete { + u32 req_id; + u32 status; +}; + +/* + * Data message. All Offset fields contain byte offsets from the beginning of + * struct rndis_packet. All Length fields are in bytes. VcHandle is set + * to 0 for connectionless data, otherwise it contains the VC handle. + */ +struct rndis_packet { + u32 data_offset; + u32 data_len; + u32 oob_data_offset; + u32 oob_data_len; + u32 num_oob_data_elements; + u32 per_pkt_info_offset; + u32 per_pkt_info_len; + u32 vc_handle; + u32 reserved; +}; + +/* Optional Out of Band data associated with a Data message. */ +struct rndis_oobd { + u32 size; + u32 type; + u32 class_info_offset; +}; + +/* Packet extension field contents associated with a Data message. */ +struct rndis_per_packet_info { + u32 size; + u32 type; + u32 ppi_offset; +}; + +enum ndis_per_pkt_info_type { + TCPIP_CHKSUM_PKTINFO, + IPSEC_PKTINFO, + TCP_LARGESEND_PKTINFO, + CLASSIFICATION_HANDLE_PKTINFO, + NDIS_RESERVED, + SG_LIST_PKTINFO, + IEEE_8021Q_INFO, + ORIGINAL_PKTINFO, + PACKET_CANCEL_ID, + ORIGINAL_NET_BUFLIST, + CACHED_NET_BUFLIST, + SHORT_PKT_PADINFO, + MAX_PER_PKT_INFO +}; + +struct ndis_pkt_8021q_info { + union { + struct { + u32 pri:3; /* User Priority */ + u32 cfi:1; /* Canonical Format ID */ + u32 vlanid:12; /* VLAN ID */ + u32 reserved:16; + }; + u32 value; + }; +}; + +#define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ + sizeof(struct ndis_pkt_8021q_info)) + +/* Format of Information buffer passed in a SetRequest for the OID */ +/* OID_GEN_RNDIS_CONFIG_PARAMETER. */ +struct rndis_config_parameter_info { + u32 parameter_name_offset; + u32 parameter_name_length; + u32 parameter_type; + u32 parameter_value_offset; + u32 parameter_value_length; +}; + +/* Values for ParameterType in struct rndis_config_parameter_info */ +#define RNDIS_CONFIG_PARAM_TYPE_INTEGER 0 +#define RNDIS_CONFIG_PARAM_TYPE_STRING 2 + +/* CONDIS Miniport messages for connection oriented devices */ +/* that do not implement a call manager. */ + +/* CoNdisMiniportCreateVc message */ +struct rcondis_mp_create_vc { + u32 req_id; + u32 ndis_vc_handle; +}; + +/* Response to CoNdisMiniportCreateVc */ +struct rcondis_mp_create_vc_complete { + u32 req_id; + u32 dev_vc_handle; + u32 status; +}; + +/* CoNdisMiniportDeleteVc message */ +struct rcondis_mp_delete_vc { + u32 req_id; + u32 dev_vc_handle; +}; + +/* Response to CoNdisMiniportDeleteVc */ +struct rcondis_mp_delete_vc_complete { + u32 req_id; + u32 status; +}; + +/* CoNdisMiniportQueryRequest message */ +struct rcondis_mp_query_request { + u32 req_id; + u32 request_type; + u32 oid; + u32 dev_vc_handle; + u32 info_buflen; + u32 info_buf_offset; +}; + +/* CoNdisMiniportSetRequest message */ +struct rcondis_mp_set_request { + u32 req_id; + u32 request_type; + u32 oid; + u32 dev_vc_handle; + u32 info_buflen; + u32 info_buf_offset; +}; + +/* CoNdisIndicateStatus message */ +struct rcondis_indicate_status { + u32 ndis_vc_handle; + u32 status; + u32 status_buflen; + u32 status_buf_offset; +}; + +/* CONDIS Call/VC parameters */ +struct rcondis_specific_parameters { + u32 parameter_type; + u32 parameter_length; + u32 parameter_lffset; +}; + +struct rcondis_media_parameters { + u32 flags; + u32 reserved1; + u32 reserved2; + struct rcondis_specific_parameters media_specific; +}; + +struct rndis_flowspec { + u32 token_rate; + u32 token_bucket_size; + u32 peak_bandwidth; + u32 latency; + u32 delay_variation; + u32 service_type; + u32 max_sdu_size; + u32 minimum_policed_size; +}; + +struct rcondis_call_manager_parameters { + struct rndis_flowspec transmit; + struct rndis_flowspec receive; + struct rcondis_specific_parameters call_mgr_specific; +}; + +/* CoNdisMiniportActivateVc message */ +struct rcondis_mp_activate_vc_request { + u32 req_id; + u32 flags; + u32 dev_vc_handle; + u32 media_params_offset; + u32 media_params_length; + u32 call_mgr_params_offset; + u32 call_mgr_params_length; +}; + +/* Response to CoNdisMiniportActivateVc */ +struct rcondis_mp_activate_vc_complete { + u32 req_id; + u32 status; +}; + +/* CoNdisMiniportDeactivateVc message */ +struct rcondis_mp_deactivate_vc_request { + u32 req_id; + u32 flags; + u32 dev_vc_handle; +}; + +/* Response to CoNdisMiniportDeactivateVc */ +struct rcondis_mp_deactivate_vc_complete { + u32 req_id; + u32 status; +}; + + +/* union with all of the RNDIS messages */ +union rndis_message_container { + struct rndis_packet pkt; + struct rndis_initialize_request init_req; + struct rndis_halt_request halt_req; + struct rndis_query_request query_req; + struct rndis_set_request set_req; + struct rndis_reset_request reset_req; + struct rndis_keepalive_request keep_alive_req; + struct rndis_indicate_status indicate_status; + struct rndis_initialize_complete init_complete; + struct rndis_query_complete query_complete; + struct rndis_set_complete set_complete; + struct rndis_reset_complete reset_complete; + struct rndis_keepalive_complete keep_alive_complete; + struct rcondis_mp_create_vc co_miniport_create_vc; + struct rcondis_mp_delete_vc co_miniport_delete_vc; + struct rcondis_indicate_status co_indicate_status; + struct rcondis_mp_activate_vc_request co_miniport_activate_vc; + struct rcondis_mp_deactivate_vc_request co_miniport_deactivate_vc; + struct rcondis_mp_create_vc_complete co_miniport_create_vc_complete; + struct rcondis_mp_delete_vc_complete co_miniport_delete_vc_complete; + struct rcondis_mp_activate_vc_complete co_miniport_activate_vc_complete; + struct rcondis_mp_deactivate_vc_complete + co_miniport_deactivate_vc_complete; +}; + +/* Remote NDIS message format */ +struct rndis_message { + u32 ndis_msg_type; + + /* Total length of this message, from the beginning */ + /* of the sruct rndis_message, in bytes. */ + u32 msg_len; + + /* Actual message */ + union rndis_message_container msg; +}; + + +struct rndis_filter_packet { + void *completion_ctx; + void (*completion)(void *context); + struct rndis_message msg; +}; + +/* Handy macros */ + +/* get the size of an RNDIS message. Pass in the message type, */ +/* struct rndis_set_request, struct rndis_packet for example */ +#define RNDIS_MESSAGE_SIZE(msg) \ + (sizeof(msg) + (sizeof(struct rndis_message) - \ + sizeof(union rndis_message_container))) + +/* get pointer to info buffer with message pointer */ +#define MESSAGE_TO_INFO_BUFFER(msg) \ + (((unsigned char *)(msg)) + msg->info_buf_offset) + +/* get pointer to status buffer with message pointer */ +#define MESSAGE_TO_STATUS_BUFFER(msg) \ + (((unsigned char *)(msg)) + msg->status_buf_offset) + +/* get pointer to OOBD buffer with message pointer */ +#define MESSAGE_TO_OOBD_BUFFER(msg) \ + (((unsigned char *)(msg)) + msg->oob_data_offset) + +/* get pointer to data buffer with message pointer */ +#define MESSAGE_TO_DATA_BUFFER(msg) \ + (((unsigned char *)(msg)) + msg->per_pkt_info_offset) + +/* get pointer to contained message from NDIS_MESSAGE pointer */ +#define RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(rndis_msg) \ + ((void *) &rndis_msg->msg) + +/* get pointer to contained message from NDIS_MESSAGE pointer */ +#define RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(rndis_msg) \ + ((void *) rndis_msg) + + +#define __struct_bcount(x) + + + +#define RNDIS_HEADER_SIZE (sizeof(struct rndis_message) - \ + sizeof(union rndis_message_container)) + +#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 +#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 +#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 +#define NDIS_PACKET_TYPE_SMT 0x00000040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 +#define NDIS_PACKET_TYPE_GROUP 0x00000100 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 + + + +#endif /* _HYPERV_NET_H */ -- 2.1.4