@@ -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_XEN_PMD),y)
+DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += xen_uio
+endif
include $(RTE_SDK)/mk/rte.subdir.mk
new file mode 100644
@@ -0,0 +1,55 @@
+# BSD LICENSE
+#
+# 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 = xen_uio
+MODULE_PATH = drivers/net/xen_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
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-y := xen_uio.c
+
+
+include $(RTE_SDK)/mk/rte.module.mk
new file mode 100644
@@ -0,0 +1,837 @@
+/*
+ * Virtual network driver for conversing with remote driver backends.
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ * Copyright (c) 2005, XenSource Ltd
+ * Copyright (c) 2013-2015 Brocade Communications Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/if_ether.h>
+#include <linux/proc_fs.h>
+
+#include <xen/xenbus.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+#include <xen/interface/io/netif.h>
+#include <xen/platform_pci.h>
+
+#include <xen/events.h>
+#include <xen/evtchn.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <linux/uio_driver.h>
+
+#include "../../../librte_pmd_xen/xen_adapter_info.h"
+
+#define GRANT_INVALID_REF 0
+
+#define NET_TX_RING_SIZE \
+ __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
+#define NET_RX_RING_SIZE \
+ __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE)
+
+#define TX_MAX_TARGET \
+ min_t(int, NET_RX_RING_SIZE, 256)
+#define RX_MAX_TARGET \
+ min_t(int, NET_RX_RING_SIZE, 256)
+
+#define RXTX_GREFS (TX_MAX_TARGET + RX_MAX_TARGET)
+
+#define DOMAIN_PROC "xen/domain"
+struct proc_dir_entry *domain_proc;
+char domain_name[9];
+size_t domain_len = sizeof(domain_name);
+static const char *domains[] = { "native", "pv", "hvm", "unknown" };
+
+struct netfront_info *xennet_alloc_resources(struct xenbus_device *xbdev);
+static void xennet_free_resources(struct xenbus_device *xbdev);
+static int xennet_connect_backend(struct netfront_info *info);
+static void xennet_disconnect_backend(struct netfront_info *info,
+ int deffered_free);
+
+/* some helpers */
+static int __gnttab_version(void)
+{
+ int err;
+ struct gnttab_get_version ggv;
+
+ ggv.dom = DOMID_SELF;
+
+ err = HYPERVISOR_grant_table_op(GNTTABOP_get_version, &ggv, 1);
+ if (err >= 0)
+ return (int)ggv.version;
+
+ return err;
+}
+
+static void xennet_end_access(int ref, void *page)
+{
+ /* This frees the page as a side-effect */
+ if (ref != GRANT_INVALID_REF)
+ gnttab_end_foreign_access(ref, 0, (unsigned long)page);
+}
+
+static int xen_net_read_mac(struct xenbus_device *xbdev, u8 *mac)
+{
+ char *macstr;
+ int ret = 0;
+
+ macstr = xenbus_read(XBT_NIL, xbdev->nodename, "mac", NULL);
+ if (IS_ERR(macstr))
+ return PTR_ERR(macstr);
+
+ pr_info("mac addr: %s\n", macstr);
+
+ if (sscanf(macstr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1],
+ &mac[2], &mac[3], &mac[4], &mac[5]) != ETH_ALEN) {
+ pr_warn("can't parse mac address\n");
+ ret = -ENOENT;
+ }
+
+ kfree(macstr);
+ return ret;
+}
+
+struct xen_uio_dev {
+ struct uio_info info;
+};
+
+struct netfront_info {
+ struct xenbus_device *xbdev;
+
+ int tx_ring_ref;
+ struct xen_netif_tx_front_ring tx;
+
+ int rx_ring_ref;
+ struct xen_netif_rx_front_ring rx;
+
+ struct xen_netif_tx_sring *txs;
+ struct xen_netif_rx_sring *rxs;
+
+ grant_ref_t gref_rxtx_head;
+
+ struct xen_uio_dev *xen_udev;
+
+ struct xen_adapter_info *shared_info_page;
+};
+
+static int xennet_uio_init(struct xenbus_device *xbdev,
+ struct netfront_info *info)
+{
+ int err;
+ struct xen_uio_dev *udev;
+
+ udev = kzalloc(sizeof(struct xen_uio_dev), GFP_KERNEL);
+ if (!udev)
+ return -ENOMEM;
+
+ info->xen_udev = udev;
+
+ /* fill uio infos */
+ udev->info.name = "xen_uio";
+ udev->info.version = "0.1";
+ udev->info.irq = UIO_IRQ_NONE;
+ udev->info.irq_flags = 0;
+
+ /*share all working info here*/
+ udev->info.mem[INFO_MAP].name = "xennet info page";
+ udev->info.mem[INFO_MAP].memtype = UIO_MEM_LOGICAL;
+ udev->info.mem[INFO_MAP].addr = (phys_addr_t)info->shared_info_page;
+ udev->info.mem[INFO_MAP].size = PAGE_SIZE;
+
+ udev->info.mem[RX_RING_MAP].name = "xennet front rx ring";
+ udev->info.mem[RX_RING_MAP].memtype = UIO_MEM_LOGICAL;
+ udev->info.mem[RX_RING_MAP].addr = (phys_addr_t)info->rxs;
+ udev->info.mem[RX_RING_MAP].size = PAGE_SIZE;
+
+ udev->info.mem[TX_RING_MAP].name = "xennet front tx ring";
+ udev->info.mem[TX_RING_MAP].memtype = UIO_MEM_LOGICAL;
+ udev->info.mem[TX_RING_MAP].addr = (phys_addr_t)info->txs;
+ udev->info.mem[TX_RING_MAP].size = PAGE_SIZE;
+
+ err = uio_register_device(&xbdev->dev, &info->xen_udev->info);
+ if (err) {
+ pr_err("uio register failed: %d\n", err);
+ kfree(info->xen_udev);
+ info->xen_udev = NULL;
+ } else {
+ pr_info("uio device registered with irq %lx\n",
+ info->xen_udev->info.irq);
+ }
+
+ return err;
+}
+
+
+static void xennet_uio_uninit(struct netfront_info *info)
+{
+ if (info->xen_udev)
+ uio_unregister_device(&info->xen_udev->info);
+ info->xen_udev = NULL;
+}
+
+struct netfront_info *xennet_alloc_resources(struct xenbus_device *xbdev)
+{
+ int ret;
+ uint16_t i;
+ int gref = 0;
+ grant_ref_t gref_rxtx_head;
+
+ struct netfront_info *info =
+ kzalloc(sizeof(struct netfront_info), GFP_KERNEL);
+ if (NULL == info)
+ goto exit;
+
+ info->gref_rxtx_head = GRANT_INVALID_REF;
+ info->xbdev = xbdev;
+
+ /* allocate place for tx ring */
+ info->txs = (struct xen_netif_tx_sring *)get_zeroed_page(
+ GFP_NOIO | __GFP_HIGH);
+ if (!info->txs) {
+ ret = -ENOMEM;
+ xenbus_dev_fatal(xbdev, ret, "allocating tx ring page");
+ goto exit;
+ }
+
+ /* allocate place for rx ring */
+ info->rxs = (struct xen_netif_rx_sring *)get_zeroed_page(
+ GFP_NOIO | __GFP_HIGH);
+ if (!info->rxs) {
+ ret = -ENOMEM;
+ xenbus_dev_fatal(xbdev, ret, "allocating rx ring page");
+ goto exit;
+ }
+
+ /* allocate shared with user page (info page) */
+ info->shared_info_page =
+ (struct xen_adapter_info *)__get_free_page(GFP_KERNEL);
+ if (NULL == info->shared_info_page) {
+ pr_alert("xen_uio can't alloc shared page\n");
+ goto exit;
+ }
+
+ /* just assertion */
+ if (((char *)&info->shared_info_page->rxtx_grefs[RXTX_GREFS - 1])
+ - ((char *)info->shared_info_page) > PAGE_SIZE) {
+ pr_err("ASSERT: no mem for grefs\n");
+ goto exit;
+ }
+
+ /* allocate grefs for every tx ring and rx ring slot */
+ ret = gnttab_alloc_grant_references(RXTX_GREFS, &info->gref_rxtx_head);
+ if (ret < 0) {
+ pr_err("xen_uio can't alloc rx and tx grefs\n");
+ goto exit;
+ }
+
+ /* fill in all grefs*/
+ gref_rxtx_head = info->gref_rxtx_head;
+ info->shared_info_page->rx_grefs_count = RX_MAX_TARGET;
+ info->shared_info_page->tx_grefs_count = TX_MAX_TARGET;
+ info->shared_info_page->rx_evtchn = 0;
+ info->shared_info_page->tx_evtchn = 0;
+
+ /*go through the list and collect put all grefs to array*/
+ for (i = 0; i < (RXTX_GREFS); i++) {
+ gref = gnttab_claim_grant_reference(&gref_rxtx_head);
+ if (gref < 0) {
+ pr_err("not expected end of list\n");
+ goto exit;
+ }
+ info->shared_info_page->rxtx_grefs[i] = (grant_ref_t)gref;
+ }
+
+ /*setup shared_info_page*/
+ info->shared_info_page->rx_ring = &info->rx;
+ info->shared_info_page->tx_ring = &info->tx;
+ /*it's not secure - we need here something else*/
+ info->shared_info_page->info = info;
+
+ info->shared_info_page->is_connected = 0;
+ info->shared_info_page->disconnect_count = 0;
+
+ /* share struct by UIO */
+ ret = xennet_uio_init(xbdev, info);
+ if (ret) {
+ pr_err("xennet_uio_init failed\n");
+ goto exit;
+ }
+
+ return info;
+exit:
+ if (info) {
+ if (info->gref_rxtx_head != GRANT_INVALID_REF)
+ gnttab_free_grant_references(info->gref_rxtx_head);
+ if (info->shared_info_page)
+ free_page((unsigned long)info->shared_info_page);
+ if (info->rxs)
+ free_page((unsigned long)info->rxs);
+ if (info->txs)
+ free_page((unsigned long)info->txs);
+ kfree(info);
+ }
+ return NULL;
+}
+
+void xennet_free_resources(struct xenbus_device *xbdev)
+{
+ struct netfront_info *info = dev_get_drvdata(&xbdev->dev);
+
+ xennet_uio_uninit(info);
+
+ gnttab_free_grant_references(info->gref_rxtx_head);
+
+ free_page((unsigned long)info->shared_info_page);
+ /*can be deferred free- in that case these pointers are NULL*/
+ if (info->rxs)
+ free_page((unsigned long)info->rxs);
+ if (info->txs)
+ free_page((unsigned long)info->txs);
+
+ kfree(info);
+}
+
+static int setup_netfront(struct xenbus_device *xbdev,
+ struct netfront_info *info)
+{
+ unsigned int feature_split_evtchn;
+ int err;
+
+ info->tx_ring_ref = GRANT_INVALID_REF;
+ info->rx_ring_ref = GRANT_INVALID_REF;
+ info->rx.sring = NULL;
+ info->tx.sring = NULL;
+
+ /* share otherend_id with user */
+ info->shared_info_page->otherend_id = xbdev->otherend_id;
+
+ err = xenbus_scanf(XBT_NIL, xbdev->otherend,
+ "feature-split-event-channels", "%u",
+ &feature_split_evtchn);
+ if (err < 0)
+ feature_split_evtchn = 0;
+
+ /* read mac */
+ err = xen_net_read_mac(xbdev, info->shared_info_page->mac);
+ if (err) {
+ xenbus_dev_fatal(xbdev, err, "parsing %s/mac",
+ xbdev->nodename);
+ goto fail;
+ }
+
+ /* set up queues */
+ SHARED_RING_INIT(info->txs);
+ FRONT_RING_INIT(&info->tx, info->txs, PAGE_SIZE);
+
+ SHARED_RING_INIT(info->rxs);
+ FRONT_RING_INIT(&info->rx, info->rxs, PAGE_SIZE);
+
+ err = xenbus_grant_ring(info->xbdev, virt_to_mfn(info->txs));
+ if (err < 0) {
+ pr_err("xenbus_grant_ring for txs failed!\n");
+ goto fail;
+ }
+ info->tx_ring_ref = err;
+
+ err = xenbus_grant_ring(info->xbdev, virt_to_mfn(info->rxs));
+ if (err < 0) {
+ pr_err("xenbus_grant_ring for rxs failed!\n");
+ goto fail;
+ }
+ info->rx_ring_ref = err;
+
+ /* alloc eventchn */
+ pr_info("feature_split_evtchn: %d\n",
+ (int)feature_split_evtchn);
+
+ err = xenbus_alloc_evtchn(xbdev, &info->shared_info_page->tx_evtchn);
+ if (err)
+ goto fail;
+
+ if (feature_split_evtchn) {
+ err = xenbus_alloc_evtchn(xbdev,
+ &info->shared_info_page->rx_evtchn);
+ if (err)
+ goto fail_split;
+ } else {
+ info->shared_info_page->rx_evtchn =
+ info->shared_info_page->tx_evtchn;
+ }
+
+ return 0;
+fail_split:
+ xenbus_free_evtchn(info->xbdev, info->shared_info_page->tx_evtchn);
+fail:
+ pr_err("setup_netfront failed\n");
+ return err;
+}
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_netback(struct xenbus_device *xbdev,
+ struct netfront_info *info)
+{
+ const char *message;
+ struct xenbus_transaction xbt;
+ int err;
+
+ /* Create shared ring, alloc event channel. */
+ err = setup_netfront(xbdev, info);
+ if (err)
+ goto out;
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(xbdev, err, "starting transaction");
+ goto destroy_ring;
+ }
+
+ err = xenbus_printf(xbt, xbdev->nodename, "tx-ring-ref",
+ "%u", info->tx_ring_ref);
+ if (err) {
+ message = "writing tx ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, xbdev->nodename, "rx-ring-ref",
+ "%u", info->rx_ring_ref);
+ if (err) {
+ message = "writing rx ring-ref";
+ goto abort_transaction;
+ }
+
+ if (info->shared_info_page->tx_evtchn ==
+ info->shared_info_page->rx_evtchn) {
+ err = xenbus_printf(xbt, xbdev->nodename, "event-channel",
+ "%u", info->shared_info_page->tx_evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+ } else {
+ err = xenbus_printf(xbt, xbdev->nodename, "event-channel-tx",
+ "%u", info->shared_info_page->tx_evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, xbdev->nodename, "event-channel-rx",
+ "%u", info->shared_info_page->rx_evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+ }
+
+ err = xenbus_printf(xbt, xbdev->nodename, "request-rx-copy", "%u", 1);
+ if (err) {
+ message = "writing request-rx-copy";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, xbdev->nodename, "feature-rx-notify",
+ "%d", 1);
+ if (err) {
+ message = "writing feature-rx-notify";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, xbdev->nodename, "feature-sg", "%d", 1);
+ if (err) {
+ message = "writing feature-sg";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, xbdev->nodename, "feature-gso-tcpv4",
+ "%d", 1);
+ if (err) {
+ message = "writing feature-gso-tcpv4";
+ goto abort_transaction;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(xbdev, err, "completing transaction");
+ goto destroy_ring;
+ }
+
+ return 0;
+abort_transaction:
+ xenbus_transaction_end(xbt, 1);
+ xenbus_dev_fatal(xbdev, err, "%s", message);
+destroy_ring:
+ xennet_disconnect_backend(info, 1);
+out:
+ pr_err("talk_to_netback failed\n");
+ return err;
+}
+
+static int xennet_connect_backend(struct netfront_info *info)
+{
+ int err;
+ unsigned int feature_rx_copy;
+
+ err = xenbus_scanf(XBT_NIL, info->xbdev->otherend, "feature-rx-copy",
+ "%u", &feature_rx_copy);
+ if (err != 1)
+ feature_rx_copy = 0;
+
+ if (!feature_rx_copy) {
+ pr_info("backend does not support copying receive path\n");
+ return -ENODEV;
+ }
+
+ err = talk_to_netback(info->xbdev, info);
+ if (err)
+ pr_err("talk_to_netback failed!\n");
+
+ info->shared_info_page->is_connected = 1;
+
+ return err;
+}
+
+static void xennet_disconnect_backend(struct netfront_info *info,
+ int deffered_free)
+{
+ if (info->shared_info_page->tx_evtchn !=
+ info->shared_info_page->rx_evtchn) {
+ xenbus_free_evtchn(info->xbdev,
+ info->shared_info_page->rx_evtchn);
+ }
+ xenbus_free_evtchn(info->xbdev, info->shared_info_page->tx_evtchn);
+
+ if (deffered_free) {
+ xennet_end_access(info->tx_ring_ref, info->txs);
+ xennet_end_access(info->rx_ring_ref, info->rxs);
+ info->txs = NULL;
+ info->rxs = NULL;
+ } else {
+ xennet_end_access(info->tx_ring_ref, NULL);
+ xennet_end_access(info->rx_ring_ref, NULL);
+ }
+
+ info->tx_ring_ref = GRANT_INVALID_REF;
+ info->rx_ring_ref = GRANT_INVALID_REF;
+ info->rx.sring = NULL;
+ info->tx.sring = NULL;
+
+ info->shared_info_page->is_connected = 0;
+ info->shared_info_page->disconnect_count++;
+}
+
+
+/**
+ * Entry point to this code when a new device is created. Allocate the basic
+ * structures and the ring buffers for communication with the backend, and
+ * inform the backend of the appropriate details for those.
+ */
+static int xennet_probe(struct xenbus_device *xbdev,
+ const struct xenbus_device_id *id)
+{
+ struct netfront_info *info;
+
+ info = xennet_alloc_resources(xbdev);
+
+ dev_set_drvdata(&xbdev->dev, info);
+
+ return 0;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart. We tear down our netif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int xennet_resume(struct xenbus_device *xbdev)
+{
+ struct netfront_info *info = dev_get_drvdata(&xbdev->dev);
+
+ pr_devel("%s\n", xbdev->nodename);
+
+ /*we can use the same memory region - disable deffered free*/
+ xennet_disconnect_backend(info, 0);
+
+ return 0;
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void netback_changed(struct xenbus_device *xbdev,
+ enum xenbus_state backend_state)
+{
+ struct netfront_info *info = dev_get_drvdata(&xbdev->dev);
+
+ pr_devel("%s\n", xenbus_strstate(backend_state));
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitialised:
+ case XenbusStateReconfiguring:
+ case XenbusStateReconfigured:
+ break;
+ case XenbusStateUnknown:
+ break;
+
+ case XenbusStateInitWait:
+ if (xbdev->state != XenbusStateInitialising)
+ break;
+ if (xennet_connect_backend(info) != 0) {
+ pr_err("%s\n", xbdev->nodename);
+ break;
+ }
+ xenbus_switch_state(xbdev, XenbusStateConnected);
+ break;
+
+ case XenbusStateConnected:
+ break;
+
+ case XenbusStateClosed:
+ if (xbdev->state == XenbusStateClosed) {
+ xenbus_switch_state(xbdev, XenbusStateInitialising);
+ break;
+ }
+
+ case XenbusStateClosing:
+ xenbus_frontend_closed(xbdev);
+ break;
+ }
+}
+
+static const struct xenbus_device_id netfront_ids[] = {
+ { "vif" },
+ { "" }
+};
+
+static int xennet_remove(struct xenbus_device *xbdev)
+{
+ struct netfront_info *info = dev_get_drvdata(&xbdev->dev);
+
+ pr_devel("%s\n", xbdev->nodename);
+
+ xennet_disconnect_backend(info, 1);
+
+ xennet_free_resources(xbdev);
+
+ return 0;
+}
+
+static struct xenbus_driver xenuio_driver = {
+ .ids = netfront_ids,
+ .probe = xennet_probe,
+ .remove = xennet_remove,
+ .resume = xennet_resume,
+ .otherend_changed = netback_changed,
+};
+
+/*operations that we can't do through the shared memory*/
+static long xennet_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg) {
+ int rc;
+ void __user *uarg = (void __user *) arg;
+
+ switch (cmd) {
+ case IOCTL_EVTCHN_NOTIFY:
+ {
+ struct ioctl_evtchn_notify notify;
+
+ rc = -EFAULT;
+ if (copy_from_user(¬ify, uarg, sizeof(notify)))
+ break;
+ notify_remote_via_evtchn(notify.port);
+ rc = 0;
+ }
+ break;
+ case IOCTL_EVTCHN_NOTIFY_GRANT:
+ {
+ uint16_t i;
+ int notify;
+ struct ioctl_evtchn_notify_grant *ng;
+
+ rc = -EFAULT;
+
+ if (access_ok(VERIFY_READ, uarg, sizeof(ng)))
+ ng = uarg;
+ else
+ break;
+
+ for (i = 0; i < ng->rel_count; i++) {
+ gnttab_end_foreign_access_ref(ng->rel_gref[i],
+ 0);
+ }
+
+ if (ng->count) {
+ union {
+ struct xen_netif_rx_front_ring *rx;
+ struct xen_netif_tx_front_ring *tx;
+ } ring;
+
+ for (i = 0; i < ng->count; i++) {
+ gnttab_grant_foreign_access_ref(
+ ng->s[i].gref,
+ ng->otherend_id,
+ pfn_to_mfn(ng->s[i].paddr),
+ (!ng->is_rx));
+ }
+
+ if (ng->is_rx) {
+ ring.rx = ng->u.rx_ring;
+ if (&ng->info->rx != ring.rx) {
+ pr_err(
+ "bad info or rx ring addr\n");
+ return -(ENOSYS);
+ }
+ ring.rx->req_prod_pvt += ng->count;
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(
+ ring.rx, notify);
+ } else {
+ ring.tx = ng->u.tx_ring;
+ if (&ng->info->tx != ring.tx) {
+ pr_err(
+ "bad info or tx ring addr\n");
+ return -(ENOSYS);
+ }
+ ring.tx->req_prod_pvt += ng->count;
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(
+ ring.tx, notify);
+ }
+
+ if (notify)
+ notify_remote_via_evtchn(ng->port);
+ }
+
+ rc = 0;
+ }
+ break;
+ default:
+ rc = -ENOSYS;
+ break;
+ }
+ return rc;
+}
+
+static const struct file_operations xennet_fops = {
+ .owner = THIS_MODULE,
+ .read = NULL/*xennet_read*/,
+ .write = NULL/*xennet_write*/,
+ .unlocked_ioctl = xennet_ioctl,
+ .poll = NULL/*xennet_poll*/,
+ .fasync = NULL/*xennet_fasync*/,
+ .open = NULL/*xennet_open*/,
+ .mmap = NULL/*xennet_mmap*/,
+ .release = NULL/*xennet_release*/,
+ .llseek = no_llseek,
+};
+
+static struct miscdevice xennet_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = XEN_PMD_UIO_NAME,
+ .fops = &xennet_fops,
+};
+
+static ssize_t read_domain(struct file *f, char __user *buf,
+ size_t count, loff_t *off)
+{
+ if (count > domain_len)
+ count = domain_len;
+
+ if (copy_to_user(buf, domain_name, count))
+ return -EFAULT;
+
+ domain_len = (count ? domain_len - count : sizeof(domain_name));
+
+ return count;
+}
+
+static const struct file_operations domain_fops = {
+ .owner = THIS_MODULE,
+ .read = read_domain,
+};
+
+static int __init netif_init(void)
+{
+ int err;
+
+ if (!xen_domain()) {
+ pr_err(KERN_INFO "xen bare hw\n");
+ return -ENODEV;
+ }
+
+ pr_info("xen %s domain\n", domains[xen_domain_type]);
+
+ snprintf(domain_name, sizeof(domain_name),
+ "%s\n", domains[xen_domain_type]);
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap))
+ pr_info("feature auto_translated_physmap is disabled\n");
+
+ pr_info("gnttab version: %d\n", (int)__gnttab_version());
+
+ domain_proc = proc_create(DOMAIN_PROC, S_IRUGO, NULL, &domain_fops);
+ if (domain_proc == NULL) {
+ pr_err("could not create /proc/%s\n", DOMAIN_PROC);
+ return -ENOMEM;
+ }
+
+ pr_info("/proc/%s created\n", DOMAIN_PROC);
+
+ err = misc_register(&xennet_miscdev);
+ if (err != 0) {
+ pr_err("could not register char device\n");
+ return err;
+ }
+
+ pr_info("initialising xen virtual ethernet driver\n");
+
+ err = xenbus_register_frontend(&xenuio_driver);
+
+ return err;
+}
+module_init(netif_init);
+
+static void __exit netif_exit(void)
+{
+ remove_proc_entry(DOMAIN_PROC, NULL);
+
+ xenbus_unregister_driver(&xenuio_driver);
+
+ misc_deregister(&xennet_miscdev);
+}
+module_exit(netif_exit);
+
+MODULE_DESCRIPTION("Xen virtual network device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("xen:vif");
+MODULE_ALIAS("xennet");