summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/net/xen-netback
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /ANDROID_3.4.5/drivers/net/xen-netback
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure.
Diffstat (limited to 'ANDROID_3.4.5/drivers/net/xen-netback')
-rw-r--r--ANDROID_3.4.5/drivers/net/xen-netback/Makefile3
-rw-r--r--ANDROID_3.4.5/drivers/net/xen-netback/common.h157
-rw-r--r--ANDROID_3.4.5/drivers/net/xen-netback/interface.c371
-rw-r--r--ANDROID_3.4.5/drivers/net/xen-netback/netback.c1706
-rw-r--r--ANDROID_3.4.5/drivers/net/xen-netback/xenbus.c487
5 files changed, 0 insertions, 2724 deletions
diff --git a/ANDROID_3.4.5/drivers/net/xen-netback/Makefile b/ANDROID_3.4.5/drivers/net/xen-netback/Makefile
deleted file mode 100644
index e346e812..00000000
--- a/ANDROID_3.4.5/drivers/net/xen-netback/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_XEN_NETDEV_BACKEND) := xen-netback.o
-
-xen-netback-y := netback.o xenbus.o interface.o
diff --git a/ANDROID_3.4.5/drivers/net/xen-netback/common.h b/ANDROID_3.4.5/drivers/net/xen-netback/common.h
deleted file mode 100644
index 94b79c33..00000000
--- a/ANDROID_3.4.5/drivers/net/xen-netback/common.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef __XEN_NETBACK__COMMON_H__
-#define __XEN_NETBACK__COMMON_H__
-
-#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/ip.h>
-#include <linux/in.h>
-#include <linux/io.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-
-#include <xen/interface/io/netif.h>
-#include <xen/interface/grant_table.h>
-#include <xen/grant_table.h>
-#include <xen/xenbus.h>
-
-struct xen_netbk;
-
-struct xenvif {
- /* Unique identifier for this interface. */
- domid_t domid;
- unsigned int handle;
-
- /* Reference to netback processing backend. */
- struct xen_netbk *netbk;
-
- u8 fe_dev_addr[6];
-
- /* Physical parameters of the comms window. */
- unsigned int irq;
-
- /* List of frontends to notify after a batch of frames sent. */
- struct list_head notify_list;
-
- /* The shared rings and indexes. */
- struct xen_netif_tx_back_ring tx;
- struct xen_netif_rx_back_ring rx;
-
- /* Frontend feature information. */
- u8 can_sg:1;
- u8 gso:1;
- u8 gso_prefix:1;
- u8 csum:1;
-
- /* Internal feature information. */
- u8 can_queue:1; /* can queue packets for receiver? */
-
- /*
- * Allow xenvif_start_xmit() to peek ahead in the rx request
- * ring. This is a prediction of what rx_req_cons will be
- * once all queued skbs are put on the ring.
- */
- RING_IDX rx_req_cons_peek;
-
- /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
- unsigned long credit_bytes;
- unsigned long credit_usec;
- unsigned long remaining_credit;
- struct timer_list credit_timeout;
-
- /* Statistics */
- unsigned long rx_gso_checksum_fixup;
-
- /* Miscellaneous private stuff. */
- struct list_head schedule_list;
- atomic_t refcnt;
- struct net_device *dev;
-
- wait_queue_head_t waiting_to_free;
-};
-
-static inline struct xenbus_device *xenvif_to_xenbus_device(struct xenvif *vif)
-{
- return to_xenbus_device(vif->dev->dev.parent);
-}
-
-#define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
-#define XEN_NETIF_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE)
-
-struct xenvif *xenvif_alloc(struct device *parent,
- domid_t domid,
- unsigned int handle);
-
-int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn);
-void xenvif_disconnect(struct xenvif *vif);
-
-void xenvif_get(struct xenvif *vif);
-void xenvif_put(struct xenvif *vif);
-
-int xenvif_xenbus_init(void);
-
-int xenvif_schedulable(struct xenvif *vif);
-
-int xen_netbk_rx_ring_full(struct xenvif *vif);
-
-int xen_netbk_must_stop_queue(struct xenvif *vif);
-
-/* (Un)Map communication rings. */
-void xen_netbk_unmap_frontend_rings(struct xenvif *vif);
-int xen_netbk_map_frontend_rings(struct xenvif *vif,
- grant_ref_t tx_ring_ref,
- grant_ref_t rx_ring_ref);
-
-/* (De)Register a xenvif with the netback backend. */
-void xen_netbk_add_xenvif(struct xenvif *vif);
-void xen_netbk_remove_xenvif(struct xenvif *vif);
-
-/* (De)Schedule backend processing for a xenvif */
-void xen_netbk_schedule_xenvif(struct xenvif *vif);
-void xen_netbk_deschedule_xenvif(struct xenvif *vif);
-
-/* Check for SKBs from frontend and schedule backend processing */
-void xen_netbk_check_rx_xenvif(struct xenvif *vif);
-/* Receive an SKB from the frontend */
-void xenvif_receive_skb(struct xenvif *vif, struct sk_buff *skb);
-
-/* Queue an SKB for transmission to the frontend */
-void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb);
-/* Notify xenvif that ring now has space to send an skb to the frontend */
-void xenvif_notify_tx_completion(struct xenvif *vif);
-
-/* Returns number of ring slots required to send an skb to the frontend */
-unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb);
-
-#endif /* __XEN_NETBACK__COMMON_H__ */
diff --git a/ANDROID_3.4.5/drivers/net/xen-netback/interface.c b/ANDROID_3.4.5/drivers/net/xen-netback/interface.c
deleted file mode 100644
index b7d41f8c..00000000
--- a/ANDROID_3.4.5/drivers/net/xen-netback/interface.c
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Network-device interface management.
- *
- * Copyright (c) 2004-2005, Keir Fraser
- *
- * 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 "common.h"
-
-#include <linux/ethtool.h>
-#include <linux/rtnetlink.h>
-#include <linux/if_vlan.h>
-
-#include <xen/events.h>
-#include <asm/xen/hypercall.h>
-
-#define XENVIF_QUEUE_LENGTH 32
-
-void xenvif_get(struct xenvif *vif)
-{
- atomic_inc(&vif->refcnt);
-}
-
-void xenvif_put(struct xenvif *vif)
-{
- if (atomic_dec_and_test(&vif->refcnt))
- wake_up(&vif->waiting_to_free);
-}
-
-int xenvif_schedulable(struct xenvif *vif)
-{
- return netif_running(vif->dev) && netif_carrier_ok(vif->dev);
-}
-
-static int xenvif_rx_schedulable(struct xenvif *vif)
-{
- return xenvif_schedulable(vif) && !xen_netbk_rx_ring_full(vif);
-}
-
-static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
-{
- struct xenvif *vif = dev_id;
-
- if (vif->netbk == NULL)
- return IRQ_NONE;
-
- xen_netbk_schedule_xenvif(vif);
-
- if (xenvif_rx_schedulable(vif))
- netif_wake_queue(vif->dev);
-
- return IRQ_HANDLED;
-}
-
-static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct xenvif *vif = netdev_priv(dev);
-
- BUG_ON(skb->dev != dev);
-
- if (vif->netbk == NULL)
- goto drop;
-
- /* Drop the packet if the target domain has no receive buffers. */
- if (!xenvif_rx_schedulable(vif))
- goto drop;
-
- /* Reserve ring slots for the worst-case number of fragments. */
- vif->rx_req_cons_peek += xen_netbk_count_skb_slots(vif, skb);
- xenvif_get(vif);
-
- if (vif->can_queue && xen_netbk_must_stop_queue(vif))
- netif_stop_queue(dev);
-
- xen_netbk_queue_tx_skb(vif, skb);
-
- return NETDEV_TX_OK;
-
- drop:
- vif->dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-void xenvif_receive_skb(struct xenvif *vif, struct sk_buff *skb)
-{
- netif_rx_ni(skb);
-}
-
-void xenvif_notify_tx_completion(struct xenvif *vif)
-{
- if (netif_queue_stopped(vif->dev) && xenvif_rx_schedulable(vif))
- netif_wake_queue(vif->dev);
-}
-
-static struct net_device_stats *xenvif_get_stats(struct net_device *dev)
-{
- struct xenvif *vif = netdev_priv(dev);
- return &vif->dev->stats;
-}
-
-static void xenvif_up(struct xenvif *vif)
-{
- xen_netbk_add_xenvif(vif);
- enable_irq(vif->irq);
- xen_netbk_check_rx_xenvif(vif);
-}
-
-static void xenvif_down(struct xenvif *vif)
-{
- disable_irq(vif->irq);
- xen_netbk_deschedule_xenvif(vif);
- xen_netbk_remove_xenvif(vif);
-}
-
-static int xenvif_open(struct net_device *dev)
-{
- struct xenvif *vif = netdev_priv(dev);
- if (netif_carrier_ok(dev))
- xenvif_up(vif);
- netif_start_queue(dev);
- return 0;
-}
-
-static int xenvif_close(struct net_device *dev)
-{
- struct xenvif *vif = netdev_priv(dev);
- if (netif_carrier_ok(dev))
- xenvif_down(vif);
- netif_stop_queue(dev);
- return 0;
-}
-
-static int xenvif_change_mtu(struct net_device *dev, int mtu)
-{
- struct xenvif *vif = netdev_priv(dev);
- int max = vif->can_sg ? 65535 - VLAN_ETH_HLEN : ETH_DATA_LEN;
-
- if (mtu > max)
- return -EINVAL;
- dev->mtu = mtu;
- return 0;
-}
-
-static netdev_features_t xenvif_fix_features(struct net_device *dev,
- netdev_features_t features)
-{
- struct xenvif *vif = netdev_priv(dev);
-
- if (!vif->can_sg)
- features &= ~NETIF_F_SG;
- if (!vif->gso && !vif->gso_prefix)
- features &= ~NETIF_F_TSO;
- if (!vif->csum)
- features &= ~NETIF_F_IP_CSUM;
-
- return features;
-}
-
-static const struct xenvif_stat {
- char name[ETH_GSTRING_LEN];
- u16 offset;
-} xenvif_stats[] = {
- {
- "rx_gso_checksum_fixup",
- offsetof(struct xenvif, rx_gso_checksum_fixup)
- },
-};
-
-static int xenvif_get_sset_count(struct net_device *dev, int string_set)
-{
- switch (string_set) {
- case ETH_SS_STATS:
- return ARRAY_SIZE(xenvif_stats);
- default:
- return -EINVAL;
- }
-}
-
-static void xenvif_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 * data)
-{
- void *vif = netdev_priv(dev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++)
- data[i] = *(unsigned long *)(vif + xenvif_stats[i].offset);
-}
-
-static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * data)
-{
- int i;
-
- switch (stringset) {
- case ETH_SS_STATS:
- for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++)
- memcpy(data + i * ETH_GSTRING_LEN,
- xenvif_stats[i].name, ETH_GSTRING_LEN);
- break;
- }
-}
-
-static const struct ethtool_ops xenvif_ethtool_ops = {
- .get_link = ethtool_op_get_link,
-
- .get_sset_count = xenvif_get_sset_count,
- .get_ethtool_stats = xenvif_get_ethtool_stats,
- .get_strings = xenvif_get_strings,
-};
-
-static const struct net_device_ops xenvif_netdev_ops = {
- .ndo_start_xmit = xenvif_start_xmit,
- .ndo_get_stats = xenvif_get_stats,
- .ndo_open = xenvif_open,
- .ndo_stop = xenvif_close,
- .ndo_change_mtu = xenvif_change_mtu,
- .ndo_fix_features = xenvif_fix_features,
-};
-
-struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
- unsigned int handle)
-{
- int err;
- struct net_device *dev;
- struct xenvif *vif;
- char name[IFNAMSIZ] = {};
-
- snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
- dev = alloc_netdev(sizeof(struct xenvif), name, ether_setup);
- if (dev == NULL) {
- pr_warn("Could not allocate netdev\n");
- return ERR_PTR(-ENOMEM);
- }
-
- SET_NETDEV_DEV(dev, parent);
-
- vif = netdev_priv(dev);
- vif->domid = domid;
- vif->handle = handle;
- vif->netbk = NULL;
- vif->can_sg = 1;
- vif->csum = 1;
- atomic_set(&vif->refcnt, 1);
- init_waitqueue_head(&vif->waiting_to_free);
- vif->dev = dev;
- INIT_LIST_HEAD(&vif->schedule_list);
- INIT_LIST_HEAD(&vif->notify_list);
-
- vif->credit_bytes = vif->remaining_credit = ~0UL;
- vif->credit_usec = 0UL;
- init_timer(&vif->credit_timeout);
- /* Initialize 'expires' now: it's used to track the credit window. */
- vif->credit_timeout.expires = jiffies;
-
- dev->netdev_ops = &xenvif_netdev_ops;
- dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
- dev->features = dev->hw_features;
- SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops);
-
- dev->tx_queue_len = XENVIF_QUEUE_LENGTH;
-
- /*
- * Initialise a dummy MAC address. We choose the numerically
- * largest non-broadcast address to prevent the address getting
- * stolen by an Ethernet bridge for STP purposes.
- * (FE:FF:FF:FF:FF:FF)
- */
- memset(dev->dev_addr, 0xFF, ETH_ALEN);
- dev->dev_addr[0] &= ~0x01;
-
- netif_carrier_off(dev);
-
- err = register_netdev(dev);
- if (err) {
- netdev_warn(dev, "Could not register device: err=%d\n", err);
- free_netdev(dev);
- return ERR_PTR(err);
- }
-
- netdev_dbg(dev, "Successfully created xenvif\n");
- return vif;
-}
-
-int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn)
-{
- int err = -ENOMEM;
-
- /* Already connected through? */
- if (vif->irq)
- return 0;
-
- err = xen_netbk_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
- if (err < 0)
- goto err;
-
- err = bind_interdomain_evtchn_to_irqhandler(
- vif->domid, evtchn, xenvif_interrupt, 0,
- vif->dev->name, vif);
- if (err < 0)
- goto err_unmap;
- vif->irq = err;
- disable_irq(vif->irq);
-
- xenvif_get(vif);
-
- rtnl_lock();
- if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
- dev_set_mtu(vif->dev, ETH_DATA_LEN);
- netdev_update_features(vif->dev);
- netif_carrier_on(vif->dev);
- if (netif_running(vif->dev))
- xenvif_up(vif);
- rtnl_unlock();
-
- return 0;
-err_unmap:
- xen_netbk_unmap_frontend_rings(vif);
-err:
- return err;
-}
-
-void xenvif_disconnect(struct xenvif *vif)
-{
- struct net_device *dev = vif->dev;
- if (netif_carrier_ok(dev)) {
- rtnl_lock();
- netif_carrier_off(dev); /* discard queued packets */
- if (netif_running(dev))
- xenvif_down(vif);
- rtnl_unlock();
- xenvif_put(vif);
- }
-
- atomic_dec(&vif->refcnt);
- wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0);
-
- del_timer_sync(&vif->credit_timeout);
-
- if (vif->irq)
- unbind_from_irqhandler(vif->irq, vif);
-
- unregister_netdev(vif->dev);
-
- xen_netbk_unmap_frontend_rings(vif);
-
- free_netdev(vif->dev);
-}
diff --git a/ANDROID_3.4.5/drivers/net/xen-netback/netback.c b/ANDROID_3.4.5/drivers/net/xen-netback/netback.c
deleted file mode 100644
index 25964013..00000000
--- a/ANDROID_3.4.5/drivers/net/xen-netback/netback.c
+++ /dev/null
@@ -1,1706 +0,0 @@
-/*
- * Back-end of the driver for virtual network devices. This portion of the
- * driver exports a 'unified' network-device interface that can be accessed
- * by any operating system that implements a compatible front end. A
- * reference front-end implementation can be found in:
- * drivers/net/xen-netfront.c
- *
- * Copyright (c) 2002-2005, K A Fraser
- *
- * 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 "common.h"
-
-#include <linux/kthread.h>
-#include <linux/if_vlan.h>
-#include <linux/udp.h>
-
-#include <net/tcp.h>
-
-#include <xen/events.h>
-#include <xen/interface/memory.h>
-
-#include <asm/xen/hypercall.h>
-#include <asm/xen/page.h>
-
-struct pending_tx_info {
- struct xen_netif_tx_request req;
- struct xenvif *vif;
-};
-typedef unsigned int pending_ring_idx_t;
-
-struct netbk_rx_meta {
- int id;
- int size;
- int gso_size;
-};
-
-#define MAX_PENDING_REQS 256
-
-/* Discriminate from any valid pending_idx value. */
-#define INVALID_PENDING_IDX 0xFFFF
-
-#define MAX_BUFFER_OFFSET PAGE_SIZE
-
-/* extra field used in struct page */
-union page_ext {
- struct {
-#if BITS_PER_LONG < 64
-#define IDX_WIDTH 8
-#define GROUP_WIDTH (BITS_PER_LONG - IDX_WIDTH)
- unsigned int group:GROUP_WIDTH;
- unsigned int idx:IDX_WIDTH;
-#else
- unsigned int group, idx;
-#endif
- } e;
- void *mapping;
-};
-
-struct xen_netbk {
- wait_queue_head_t wq;
- struct task_struct *task;
-
- struct sk_buff_head rx_queue;
- struct sk_buff_head tx_queue;
-
- struct timer_list net_timer;
-
- struct page *mmap_pages[MAX_PENDING_REQS];
-
- pending_ring_idx_t pending_prod;
- pending_ring_idx_t pending_cons;
- struct list_head net_schedule_list;
-
- /* Protect the net_schedule_list in netif. */
- spinlock_t net_schedule_list_lock;
-
- atomic_t netfront_count;
-
- struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
- struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
-
- u16 pending_ring[MAX_PENDING_REQS];
-
- /*
- * Given MAX_BUFFER_OFFSET of 4096 the worst case is that each
- * head/fragment page uses 2 copy operations because it
- * straddles two buffers in the frontend.
- */
- struct gnttab_copy grant_copy_op[2*XEN_NETIF_RX_RING_SIZE];
- struct netbk_rx_meta meta[2*XEN_NETIF_RX_RING_SIZE];
-};
-
-static struct xen_netbk *xen_netbk;
-static int xen_netbk_group_nr;
-
-void xen_netbk_add_xenvif(struct xenvif *vif)
-{
- int i;
- int min_netfront_count;
- int min_group = 0;
- struct xen_netbk *netbk;
-
- min_netfront_count = atomic_read(&xen_netbk[0].netfront_count);
- for (i = 0; i < xen_netbk_group_nr; i++) {
- int netfront_count = atomic_read(&xen_netbk[i].netfront_count);
- if (netfront_count < min_netfront_count) {
- min_group = i;
- min_netfront_count = netfront_count;
- }
- }
-
- netbk = &xen_netbk[min_group];
-
- vif->netbk = netbk;
- atomic_inc(&netbk->netfront_count);
-}
-
-void xen_netbk_remove_xenvif(struct xenvif *vif)
-{
- struct xen_netbk *netbk = vif->netbk;
- vif->netbk = NULL;
- atomic_dec(&netbk->netfront_count);
-}
-
-static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
-static void make_tx_response(struct xenvif *vif,
- struct xen_netif_tx_request *txp,
- s8 st);
-static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
- u16 id,
- s8 st,
- u16 offset,
- u16 size,
- u16 flags);
-
-static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
- u16 idx)
-{
- return page_to_pfn(netbk->mmap_pages[idx]);
-}
-
-static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
- u16 idx)
-{
- return (unsigned long)pfn_to_kaddr(idx_to_pfn(netbk, idx));
-}
-
-/* extra field used in struct page */
-static inline void set_page_ext(struct page *pg, struct xen_netbk *netbk,
- unsigned int idx)
-{
- unsigned int group = netbk - xen_netbk;
- union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
-
- BUILD_BUG_ON(sizeof(ext) > sizeof(ext.mapping));
- pg->mapping = ext.mapping;
-}
-
-static int get_page_ext(struct page *pg,
- unsigned int *pgroup, unsigned int *pidx)
-{
- union page_ext ext = { .mapping = pg->mapping };
- struct xen_netbk *netbk;
- unsigned int group, idx;
-
- group = ext.e.group - 1;
-
- if (group < 0 || group >= xen_netbk_group_nr)
- return 0;
-
- netbk = &xen_netbk[group];
-
- idx = ext.e.idx;
-
- if ((idx < 0) || (idx >= MAX_PENDING_REQS))
- return 0;
-
- if (netbk->mmap_pages[idx] != pg)
- return 0;
-
- *pgroup = group;
- *pidx = idx;
-
- return 1;
-}
-
-/*
- * This is the amount of packet we copy rather than map, so that the
- * guest can't fiddle with the contents of the headers while we do
- * packet processing on them (netfilter, routing, etc).
- */
-#define PKT_PROT_LEN (ETH_HLEN + \
- VLAN_HLEN + \
- sizeof(struct iphdr) + MAX_IPOPTLEN + \
- sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE)
-
-static u16 frag_get_pending_idx(skb_frag_t *frag)
-{
- return (u16)frag->page_offset;
-}
-
-static void frag_set_pending_idx(skb_frag_t *frag, u16 pending_idx)
-{
- frag->page_offset = pending_idx;
-}
-
-static inline pending_ring_idx_t pending_index(unsigned i)
-{
- return i & (MAX_PENDING_REQS-1);
-}
-
-static inline pending_ring_idx_t nr_pending_reqs(struct xen_netbk *netbk)
-{
- return MAX_PENDING_REQS -
- netbk->pending_prod + netbk->pending_cons;
-}
-
-static void xen_netbk_kick_thread(struct xen_netbk *netbk)
-{
- wake_up(&netbk->wq);
-}
-
-static int max_required_rx_slots(struct xenvif *vif)
-{
- int max = DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE);
-
- if (vif->can_sg || vif->gso || vif->gso_prefix)
- max += MAX_SKB_FRAGS + 1; /* extra_info + frags */
-
- return max;
-}
-
-int xen_netbk_rx_ring_full(struct xenvif *vif)
-{
- RING_IDX peek = vif->rx_req_cons_peek;
- RING_IDX needed = max_required_rx_slots(vif);
-
- return ((vif->rx.sring->req_prod - peek) < needed) ||
- ((vif->rx.rsp_prod_pvt + XEN_NETIF_RX_RING_SIZE - peek) < needed);
-}
-
-int xen_netbk_must_stop_queue(struct xenvif *vif)
-{
- if (!xen_netbk_rx_ring_full(vif))
- return 0;
-
- vif->rx.sring->req_event = vif->rx_req_cons_peek +
- max_required_rx_slots(vif);
- mb(); /* request notification /then/ check the queue */
-
- return xen_netbk_rx_ring_full(vif);
-}
-
-/*
- * Returns true if we should start a new receive buffer instead of
- * adding 'size' bytes to a buffer which currently contains 'offset'
- * bytes.
- */
-static bool start_new_rx_buffer(int offset, unsigned long size, int head)
-{
- /* simple case: we have completely filled the current buffer. */
- if (offset == MAX_BUFFER_OFFSET)
- return true;
-
- /*
- * complex case: start a fresh buffer if the current frag
- * would overflow the current buffer but only if:
- * (i) this frag would fit completely in the next buffer
- * and (ii) there is already some data in the current buffer
- * and (iii) this is not the head buffer.
- *
- * Where:
- * - (i) stops us splitting a frag into two copies
- * unless the frag is too large for a single buffer.
- * - (ii) stops us from leaving a buffer pointlessly empty.
- * - (iii) stops us leaving the first buffer
- * empty. Strictly speaking this is already covered
- * by (ii) but is explicitly checked because
- * netfront relies on the first buffer being
- * non-empty and can crash otherwise.
- *
- * This means we will effectively linearise small
- * frags but do not needlessly split large buffers
- * into multiple copies tend to give large frags their
- * own buffers as before.
- */
- if ((offset + size > MAX_BUFFER_OFFSET) &&
- (size <= MAX_BUFFER_OFFSET) && offset && !head)
- return true;
-
- return false;
-}
-
-/*
- * Figure out how many ring slots we're going to need to send @skb to
- * the guest. This function is essentially a dry run of
- * netbk_gop_frag_copy.
- */
-unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb)
-{
- unsigned int count;
- int i, copy_off;
-
- count = DIV_ROUND_UP(
- offset_in_page(skb->data)+skb_headlen(skb), PAGE_SIZE);
-
- copy_off = skb_headlen(skb) % PAGE_SIZE;
-
- if (skb_shinfo(skb)->gso_size)
- count++;
-
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- unsigned long size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
- unsigned long bytes;
- while (size > 0) {
- BUG_ON(copy_off > MAX_BUFFER_OFFSET);
-
- if (start_new_rx_buffer(copy_off, size, 0)) {
- count++;
- copy_off = 0;
- }
-
- bytes = size;
- if (copy_off + bytes > MAX_BUFFER_OFFSET)
- bytes = MAX_BUFFER_OFFSET - copy_off;
-
- copy_off += bytes;
- size -= bytes;
- }
- }
- return count;
-}
-
-struct netrx_pending_operations {
- unsigned copy_prod, copy_cons;
- unsigned meta_prod, meta_cons;
- struct gnttab_copy *copy;
- struct netbk_rx_meta *meta;
- int copy_off;
- grant_ref_t copy_gref;
-};
-
-static struct netbk_rx_meta *get_next_rx_buffer(struct xenvif *vif,
- struct netrx_pending_operations *npo)
-{
- struct netbk_rx_meta *meta;
- struct xen_netif_rx_request *req;
-
- req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
-
- meta = npo->meta + npo->meta_prod++;
- meta->gso_size = 0;
- meta->size = 0;
- meta->id = req->id;
-
- npo->copy_off = 0;
- npo->copy_gref = req->gref;
-
- return meta;
-}
-
-/*
- * Set up the grant operations for this fragment. If it's a flipping
- * interface, we also set up the unmap request from here.
- */
-static void netbk_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
- struct netrx_pending_operations *npo,
- struct page *page, unsigned long size,
- unsigned long offset, int *head)
-{
- struct gnttab_copy *copy_gop;
- struct netbk_rx_meta *meta;
- /*
- * These variables are used iff get_page_ext returns true,
- * in which case they are guaranteed to be initialized.
- */
- unsigned int uninitialized_var(group), uninitialized_var(idx);
- int foreign = get_page_ext(page, &group, &idx);
- unsigned long bytes;
-
- /* Data must not cross a page boundary. */
- BUG_ON(size + offset > PAGE_SIZE);
-
- meta = npo->meta + npo->meta_prod - 1;
-
- while (size > 0) {
- BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
-
- if (start_new_rx_buffer(npo->copy_off, size, *head)) {
- /*
- * Netfront requires there to be some data in the head
- * buffer.
- */
- BUG_ON(*head);
-
- meta = get_next_rx_buffer(vif, npo);
- }
-
- bytes = size;
- if (npo->copy_off + bytes > MAX_BUFFER_OFFSET)
- bytes = MAX_BUFFER_OFFSET - npo->copy_off;
-
- copy_gop = npo->copy + npo->copy_prod++;
- copy_gop->flags = GNTCOPY_dest_gref;
- if (foreign) {
- struct xen_netbk *netbk = &xen_netbk[group];
- struct pending_tx_info *src_pend;
-
- src_pend = &netbk->pending_tx_info[idx];
-
- copy_gop->source.domid = src_pend->vif->domid;
- copy_gop->source.u.ref = src_pend->req.gref;
- copy_gop->flags |= GNTCOPY_source_gref;
- } else {
- void *vaddr = page_address(page);
- copy_gop->source.domid = DOMID_SELF;
- copy_gop->source.u.gmfn = virt_to_mfn(vaddr);
- }
- copy_gop->source.offset = offset;
- copy_gop->dest.domid = vif->domid;
-
- copy_gop->dest.offset = npo->copy_off;
- copy_gop->dest.u.ref = npo->copy_gref;
- copy_gop->len = bytes;
-
- npo->copy_off += bytes;
- meta->size += bytes;
-
- offset += bytes;
- size -= bytes;
-
- /* Leave a gap for the GSO descriptor. */
- if (*head && skb_shinfo(skb)->gso_size && !vif->gso_prefix)
- vif->rx.req_cons++;
-
- *head = 0; /* There must be something in this buffer now. */
-
- }
-}
-
-/*
- * Prepare an SKB to be transmitted to the frontend.
- *
- * This function is responsible for allocating grant operations, meta
- * structures, etc.
- *
- * It returns the number of meta structures consumed. The number of
- * ring slots used is always equal to the number of meta slots used
- * plus the number of GSO descriptors used. Currently, we use either
- * zero GSO descriptors (for non-GSO packets) or one descriptor (for
- * frontend-side LRO).
- */
-static int netbk_gop_skb(struct sk_buff *skb,
- struct netrx_pending_operations *npo)
-{
- struct xenvif *vif = netdev_priv(skb->dev);
- int nr_frags = skb_shinfo(skb)->nr_frags;
- int i;
- struct xen_netif_rx_request *req;
- struct netbk_rx_meta *meta;
- unsigned char *data;
- int head = 1;
- int old_meta_prod;
-
- old_meta_prod = npo->meta_prod;
-
- /* Set up a GSO prefix descriptor, if necessary */
- if (skb_shinfo(skb)->gso_size && vif->gso_prefix) {
- req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
- meta = npo->meta + npo->meta_prod++;
- meta->gso_size = skb_shinfo(skb)->gso_size;
- meta->size = 0;
- meta->id = req->id;
- }
-
- req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
- meta = npo->meta + npo->meta_prod++;
-
- if (!vif->gso_prefix)
- meta->gso_size = skb_shinfo(skb)->gso_size;
- else
- meta->gso_size = 0;
-
- meta->size = 0;
- meta->id = req->id;
- npo->copy_off = 0;
- npo->copy_gref = req->gref;
-
- data = skb->data;
- while (data < skb_tail_pointer(skb)) {
- unsigned int offset = offset_in_page(data);
- unsigned int len = PAGE_SIZE - offset;
-
- if (data + len > skb_tail_pointer(skb))
- len = skb_tail_pointer(skb) - data;
-
- netbk_gop_frag_copy(vif, skb, npo,
- virt_to_page(data), len, offset, &head);
- data += len;
- }
-
- for (i = 0; i < nr_frags; i++) {
- netbk_gop_frag_copy(vif, skb, npo,
- skb_frag_page(&skb_shinfo(skb)->frags[i]),
- skb_frag_size(&skb_shinfo(skb)->frags[i]),
- skb_shinfo(skb)->frags[i].page_offset,
- &head);
- }
-
- return npo->meta_prod - old_meta_prod;
-}
-
-/*
- * This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
- * used to set up the operations on the top of
- * netrx_pending_operations, which have since been done. Check that
- * they didn't give any errors and advance over them.
- */
-static int netbk_check_gop(struct xenvif *vif, int nr_meta_slots,
- struct netrx_pending_operations *npo)
-{
- struct gnttab_copy *copy_op;
- int status = XEN_NETIF_RSP_OKAY;
- int i;
-
- for (i = 0; i < nr_meta_slots; i++) {
- copy_op = npo->copy + npo->copy_cons++;
- if (copy_op->status != GNTST_okay) {
- netdev_dbg(vif->dev,
- "Bad status %d from copy to DOM%d.\n",
- copy_op->status, vif->domid);
- status = XEN_NETIF_RSP_ERROR;
- }
- }
-
- return status;
-}
-
-static void netbk_add_frag_responses(struct xenvif *vif, int status,
- struct netbk_rx_meta *meta,
- int nr_meta_slots)
-{
- int i;
- unsigned long offset;
-
- /* No fragments used */
- if (nr_meta_slots <= 1)
- return;
-
- nr_meta_slots--;
-
- for (i = 0; i < nr_meta_slots; i++) {
- int flags;
- if (i == nr_meta_slots - 1)
- flags = 0;
- else
- flags = XEN_NETRXF_more_data;
-
- offset = 0;
- make_rx_response(vif, meta[i].id, status, offset,
- meta[i].size, flags);
- }
-}
-
-struct skb_cb_overlay {
- int meta_slots_used;
-};
-
-static void xen_netbk_rx_action(struct xen_netbk *netbk)
-{
- struct xenvif *vif = NULL, *tmp;
- s8 status;
- u16 irq, flags;
- struct xen_netif_rx_response *resp;
- struct sk_buff_head rxq;
- struct sk_buff *skb;
- LIST_HEAD(notify);
- int ret;
- int nr_frags;
- int count;
- unsigned long offset;
- struct skb_cb_overlay *sco;
-
- struct netrx_pending_operations npo = {
- .copy = netbk->grant_copy_op,
- .meta = netbk->meta,
- };
-
- skb_queue_head_init(&rxq);
-
- count = 0;
-
- while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
- vif = netdev_priv(skb->dev);
- nr_frags = skb_shinfo(skb)->nr_frags;
-
- sco = (struct skb_cb_overlay *)skb->cb;
- sco->meta_slots_used = netbk_gop_skb(skb, &npo);
-
- count += nr_frags + 1;
-
- __skb_queue_tail(&rxq, skb);
-
- /* Filled the batch queue? */
- if (count + MAX_SKB_FRAGS >= XEN_NETIF_RX_RING_SIZE)
- break;
- }
-
- BUG_ON(npo.meta_prod > ARRAY_SIZE(netbk->meta));
-
- if (!npo.copy_prod)
- return;
-
- BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op));
- ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, &netbk->grant_copy_op,
- npo.copy_prod);
- BUG_ON(ret != 0);
-
- while ((skb = __skb_dequeue(&rxq)) != NULL) {
- sco = (struct skb_cb_overlay *)skb->cb;
-
- vif = netdev_priv(skb->dev);
-
- if (netbk->meta[npo.meta_cons].gso_size && vif->gso_prefix) {
- resp = RING_GET_RESPONSE(&vif->rx,
- vif->rx.rsp_prod_pvt++);
-
- resp->flags = XEN_NETRXF_gso_prefix | XEN_NETRXF_more_data;
-
- resp->offset = netbk->meta[npo.meta_cons].gso_size;
- resp->id = netbk->meta[npo.meta_cons].id;
- resp->status = sco->meta_slots_used;
-
- npo.meta_cons++;
- sco->meta_slots_used--;
- }
-
-
- vif->dev->stats.tx_bytes += skb->len;
- vif->dev->stats.tx_packets++;
-
- status = netbk_check_gop(vif, sco->meta_slots_used, &npo);
-
- if (sco->meta_slots_used == 1)
- flags = 0;
- else
- flags = XEN_NETRXF_more_data;
-
- if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
- flags |= XEN_NETRXF_csum_blank | XEN_NETRXF_data_validated;
- else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
- /* remote but checksummed. */
- flags |= XEN_NETRXF_data_validated;
-
- offset = 0;
- resp = make_rx_response(vif, netbk->meta[npo.meta_cons].id,
- status, offset,
- netbk->meta[npo.meta_cons].size,
- flags);
-
- if (netbk->meta[npo.meta_cons].gso_size && !vif->gso_prefix) {
- struct xen_netif_extra_info *gso =
- (struct xen_netif_extra_info *)
- RING_GET_RESPONSE(&vif->rx,
- vif->rx.rsp_prod_pvt++);
-
- resp->flags |= XEN_NETRXF_extra_info;
-
- gso->u.gso.size = netbk->meta[npo.meta_cons].gso_size;
- gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
- gso->u.gso.pad = 0;
- gso->u.gso.features = 0;
-
- gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
- gso->flags = 0;
- }
-
- netbk_add_frag_responses(vif, status,
- netbk->meta + npo.meta_cons + 1,
- sco->meta_slots_used);
-
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret);
- irq = vif->irq;
- if (ret && list_empty(&vif->notify_list))
- list_add_tail(&vif->notify_list, &notify);
-
- xenvif_notify_tx_completion(vif);
-
- xenvif_put(vif);
- npo.meta_cons += sco->meta_slots_used;
- dev_kfree_skb(skb);
- }
-
- list_for_each_entry_safe(vif, tmp, &notify, notify_list) {
- notify_remote_via_irq(vif->irq);
- list_del_init(&vif->notify_list);
- }
-
- /* More work to do? */
- if (!skb_queue_empty(&netbk->rx_queue) &&
- !timer_pending(&netbk->net_timer))
- xen_netbk_kick_thread(netbk);
-}
-
-void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb)
-{
- struct xen_netbk *netbk = vif->netbk;
-
- skb_queue_tail(&netbk->rx_queue, skb);
-
- xen_netbk_kick_thread(netbk);
-}
-
-static void xen_netbk_alarm(unsigned long data)
-{
- struct xen_netbk *netbk = (struct xen_netbk *)data;
- xen_netbk_kick_thread(netbk);
-}
-
-static int __on_net_schedule_list(struct xenvif *vif)
-{
- return !list_empty(&vif->schedule_list);
-}
-
-/* Must be called with net_schedule_list_lock held */
-static void remove_from_net_schedule_list(struct xenvif *vif)
-{
- if (likely(__on_net_schedule_list(vif))) {
- list_del_init(&vif->schedule_list);
- xenvif_put(vif);
- }
-}
-
-static struct xenvif *poll_net_schedule_list(struct xen_netbk *netbk)
-{
- struct xenvif *vif = NULL;
-
- spin_lock_irq(&netbk->net_schedule_list_lock);
- if (list_empty(&netbk->net_schedule_list))
- goto out;
-
- vif = list_first_entry(&netbk->net_schedule_list,
- struct xenvif, schedule_list);
- if (!vif)
- goto out;
-
- xenvif_get(vif);
-
- remove_from_net_schedule_list(vif);
-out:
- spin_unlock_irq(&netbk->net_schedule_list_lock);
- return vif;
-}
-
-void xen_netbk_schedule_xenvif(struct xenvif *vif)
-{
- unsigned long flags;
- struct xen_netbk *netbk = vif->netbk;
-
- if (__on_net_schedule_list(vif))
- goto kick;
-
- spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
- if (!__on_net_schedule_list(vif) &&
- likely(xenvif_schedulable(vif))) {
- list_add_tail(&vif->schedule_list, &netbk->net_schedule_list);
- xenvif_get(vif);
- }
- spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
-
-kick:
- smp_mb();
- if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
- !list_empty(&netbk->net_schedule_list))
- xen_netbk_kick_thread(netbk);
-}
-
-void xen_netbk_deschedule_xenvif(struct xenvif *vif)
-{
- struct xen_netbk *netbk = vif->netbk;
- spin_lock_irq(&netbk->net_schedule_list_lock);
- remove_from_net_schedule_list(vif);
- spin_unlock_irq(&netbk->net_schedule_list_lock);
-}
-
-void xen_netbk_check_rx_xenvif(struct xenvif *vif)
-{
- int more_to_do;
-
- RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
-
- if (more_to_do)
- xen_netbk_schedule_xenvif(vif);
-}
-
-static void tx_add_credit(struct xenvif *vif)
-{
- unsigned long max_burst, max_credit;
-
- /*
- * Allow a burst big enough to transmit a jumbo packet of up to 128kB.
- * Otherwise the interface can seize up due to insufficient credit.
- */
- max_burst = RING_GET_REQUEST(&vif->tx, vif->tx.req_cons)->size;
- max_burst = min(max_burst, 131072UL);
- max_burst = max(max_burst, vif->credit_bytes);
-
- /* Take care that adding a new chunk of credit doesn't wrap to zero. */
- max_credit = vif->remaining_credit + vif->credit_bytes;
- if (max_credit < vif->remaining_credit)
- max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
-
- vif->remaining_credit = min(max_credit, max_burst);
-}
-
-static void tx_credit_callback(unsigned long data)
-{
- struct xenvif *vif = (struct xenvif *)data;
- tx_add_credit(vif);
- xen_netbk_check_rx_xenvif(vif);
-}
-
-static void netbk_tx_err(struct xenvif *vif,
- struct xen_netif_tx_request *txp, RING_IDX end)
-{
- RING_IDX cons = vif->tx.req_cons;
-
- do {
- make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- if (cons >= end)
- break;
- txp = RING_GET_REQUEST(&vif->tx, cons++);
- } while (1);
- vif->tx.req_cons = cons;
- xen_netbk_check_rx_xenvif(vif);
- xenvif_put(vif);
-}
-
-static int netbk_count_requests(struct xenvif *vif,
- struct xen_netif_tx_request *first,
- struct xen_netif_tx_request *txp,
- int work_to_do)
-{
- RING_IDX cons = vif->tx.req_cons;
- int frags = 0;
-
- if (!(first->flags & XEN_NETTXF_more_data))
- return 0;
-
- do {
- if (frags >= work_to_do) {
- netdev_dbg(vif->dev, "Need more frags\n");
- return -frags;
- }
-
- if (unlikely(frags >= MAX_SKB_FRAGS)) {
- netdev_dbg(vif->dev, "Too many frags\n");
- return -frags;
- }
-
- memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags),
- sizeof(*txp));
- if (txp->size > first->size) {
- netdev_dbg(vif->dev, "Frags galore\n");
- return -frags;
- }
-
- first->size -= txp->size;
- frags++;
-
- if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
- netdev_dbg(vif->dev, "txp->offset: %x, size: %u\n",
- txp->offset, txp->size);
- return -frags;
- }
- } while ((txp++)->flags & XEN_NETTXF_more_data);
- return frags;
-}
-
-static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
- struct sk_buff *skb,
- u16 pending_idx)
-{
- struct page *page;
- page = alloc_page(GFP_KERNEL|__GFP_COLD);
- if (!page)
- return NULL;
- set_page_ext(page, netbk, pending_idx);
- netbk->mmap_pages[pending_idx] = page;
- return page;
-}
-
-static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
- struct xenvif *vif,
- struct sk_buff *skb,
- struct xen_netif_tx_request *txp,
- struct gnttab_copy *gop)
-{
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- skb_frag_t *frags = shinfo->frags;
- u16 pending_idx = *((u16 *)skb->data);
- int i, start;
-
- /* Skip first skb fragment if it is on same page as header fragment. */
- start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
-
- for (i = start; i < shinfo->nr_frags; i++, txp++) {
- struct page *page;
- pending_ring_idx_t index;
- struct pending_tx_info *pending_tx_info =
- netbk->pending_tx_info;
-
- index = pending_index(netbk->pending_cons++);
- pending_idx = netbk->pending_ring[index];
- page = xen_netbk_alloc_page(netbk, skb, pending_idx);
- if (!page)
- return NULL;
-
- gop->source.u.ref = txp->gref;
- gop->source.domid = vif->domid;
- gop->source.offset = txp->offset;
-
- gop->dest.u.gmfn = virt_to_mfn(page_address(page));
- gop->dest.domid = DOMID_SELF;
- gop->dest.offset = txp->offset;
-
- gop->len = txp->size;
- gop->flags = GNTCOPY_source_gref;
-
- gop++;
-
- memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
- xenvif_get(vif);
- pending_tx_info[pending_idx].vif = vif;
- frag_set_pending_idx(&frags[i], pending_idx);
- }
-
- return gop;
-}
-
-static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
- struct sk_buff *skb,
- struct gnttab_copy **gopp)
-{
- struct gnttab_copy *gop = *gopp;
- u16 pending_idx = *((u16 *)skb->data);
- struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
- struct xenvif *vif = pending_tx_info[pending_idx].vif;
- struct xen_netif_tx_request *txp;
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- int nr_frags = shinfo->nr_frags;
- int i, err, start;
-
- /* Check status of header. */
- err = gop->status;
- if (unlikely(err)) {
- pending_ring_idx_t index;
- index = pending_index(netbk->pending_prod++);
- txp = &pending_tx_info[pending_idx].req;
- make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- netbk->pending_ring[index] = pending_idx;
- xenvif_put(vif);
- }
-
- /* Skip first skb fragment if it is on same page as header fragment. */
- start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
-
- for (i = start; i < nr_frags; i++) {
- int j, newerr;
- pending_ring_idx_t index;
-
- pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
-
- /* Check error status: if okay then remember grant handle. */
- newerr = (++gop)->status;
- if (likely(!newerr)) {
- /* Had a previous error? Invalidate this fragment. */
- if (unlikely(err))
- xen_netbk_idx_release(netbk, pending_idx);
- continue;
- }
-
- /* Error on this fragment: respond to client with an error. */
- txp = &netbk->pending_tx_info[pending_idx].req;
- make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- index = pending_index(netbk->pending_prod++);
- netbk->pending_ring[index] = pending_idx;
- xenvif_put(vif);
-
- /* Not the first error? Preceding frags already invalidated. */
- if (err)
- continue;
-
- /* First error: invalidate header and preceding fragments. */
- pending_idx = *((u16 *)skb->data);
- xen_netbk_idx_release(netbk, pending_idx);
- for (j = start; j < i; j++) {
- pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
- xen_netbk_idx_release(netbk, pending_idx);
- }
-
- /* Remember the error: invalidate all subsequent fragments. */
- err = newerr;
- }
-
- *gopp = gop + 1;
- return err;
-}
-
-static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb)
-{
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- int nr_frags = shinfo->nr_frags;
- int i;
-
- for (i = 0; i < nr_frags; i++) {
- skb_frag_t *frag = shinfo->frags + i;
- struct xen_netif_tx_request *txp;
- struct page *page;
- u16 pending_idx;
-
- pending_idx = frag_get_pending_idx(frag);
-
- txp = &netbk->pending_tx_info[pending_idx].req;
- page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
- __skb_fill_page_desc(skb, i, page, txp->offset, txp->size);
- skb->len += txp->size;
- skb->data_len += txp->size;
- skb->truesize += txp->size;
-
- /* Take an extra reference to offset xen_netbk_idx_release */
- get_page(netbk->mmap_pages[pending_idx]);
- xen_netbk_idx_release(netbk, pending_idx);
- }
-}
-
-static int xen_netbk_get_extras(struct xenvif *vif,
- struct xen_netif_extra_info *extras,
- int work_to_do)
-{
- struct xen_netif_extra_info extra;
- RING_IDX cons = vif->tx.req_cons;
-
- do {
- if (unlikely(work_to_do-- <= 0)) {
- netdev_dbg(vif->dev, "Missing extra info\n");
- return -EBADR;
- }
-
- memcpy(&extra, RING_GET_REQUEST(&vif->tx, cons),
- sizeof(extra));
- if (unlikely(!extra.type ||
- extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
- vif->tx.req_cons = ++cons;
- netdev_dbg(vif->dev,
- "Invalid extra type: %d\n", extra.type);
- return -EINVAL;
- }
-
- memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
- vif->tx.req_cons = ++cons;
- } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
-
- return work_to_do;
-}
-
-static int netbk_set_skb_gso(struct xenvif *vif,
- struct sk_buff *skb,
- struct xen_netif_extra_info *gso)
-{
- if (!gso->u.gso.size) {
- netdev_dbg(vif->dev, "GSO size must not be zero.\n");
- return -EINVAL;
- }
-
- /* Currently only TCPv4 S.O. is supported. */
- if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
- netdev_dbg(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type);
- return -EINVAL;
- }
-
- skb_shinfo(skb)->gso_size = gso->u.gso.size;
- skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
-
- /* Header must be checked, and gso_segs computed. */
- skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
- skb_shinfo(skb)->gso_segs = 0;
-
- return 0;
-}
-
-static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
-{
- struct iphdr *iph;
- unsigned char *th;
- int err = -EPROTO;
- int recalculate_partial_csum = 0;
-
- /*
- * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
- * peers can fail to set NETRXF_csum_blank when sending a GSO
- * frame. In this case force the SKB to CHECKSUM_PARTIAL and
- * recalculate the partial checksum.
- */
- if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
- vif->rx_gso_checksum_fixup++;
- skb->ip_summed = CHECKSUM_PARTIAL;
- recalculate_partial_csum = 1;
- }
-
- /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
- if (skb->ip_summed != CHECKSUM_PARTIAL)
- return 0;
-
- if (skb->protocol != htons(ETH_P_IP))
- goto out;
-
- iph = (void *)skb->data;
- th = skb->data + 4 * iph->ihl;
- if (th >= skb_tail_pointer(skb))
- goto out;
-
- skb->csum_start = th - skb->head;
- switch (iph->protocol) {
- case IPPROTO_TCP:
- skb->csum_offset = offsetof(struct tcphdr, check);
-
- if (recalculate_partial_csum) {
- struct tcphdr *tcph = (struct tcphdr *)th;
- tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
- skb->len - iph->ihl*4,
- IPPROTO_TCP, 0);
- }
- break;
- case IPPROTO_UDP:
- skb->csum_offset = offsetof(struct udphdr, check);
-
- if (recalculate_partial_csum) {
- struct udphdr *udph = (struct udphdr *)th;
- udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
- skb->len - iph->ihl*4,
- IPPROTO_UDP, 0);
- }
- break;
- default:
- if (net_ratelimit())
- netdev_err(vif->dev,
- "Attempting to checksum a non-TCP/UDP packet, dropping a protocol %d packet\n",
- iph->protocol);
- goto out;
- }
-
- if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
- goto out;
-
- err = 0;
-
-out:
- return err;
-}
-
-static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
-{
- unsigned long now = jiffies;
- unsigned long next_credit =
- vif->credit_timeout.expires +
- msecs_to_jiffies(vif->credit_usec / 1000);
-
- /* Timer could already be pending in rare cases. */
- if (timer_pending(&vif->credit_timeout))
- return true;
-
- /* Passed the point where we can replenish credit? */
- if (time_after_eq(now, next_credit)) {
- vif->credit_timeout.expires = now;
- tx_add_credit(vif);
- }
-
- /* Still too big to send right now? Set a callback. */
- if (size > vif->remaining_credit) {
- vif->credit_timeout.data =
- (unsigned long)vif;
- vif->credit_timeout.function =
- tx_credit_callback;
- mod_timer(&vif->credit_timeout,
- next_credit);
-
- return true;
- }
-
- return false;
-}
-
-static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
-{
- struct gnttab_copy *gop = netbk->tx_copy_ops, *request_gop;
- struct sk_buff *skb;
- int ret;
-
- while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&netbk->net_schedule_list)) {
- struct xenvif *vif;
- struct xen_netif_tx_request txreq;
- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
- struct page *page;
- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
- u16 pending_idx;
- RING_IDX idx;
- int work_to_do;
- unsigned int data_len;
- pending_ring_idx_t index;
-
- /* Get a netif from the list with work to do. */
- vif = poll_net_schedule_list(netbk);
- if (!vif)
- continue;
-
- RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do);
- if (!work_to_do) {
- xenvif_put(vif);
- continue;
- }
-
- idx = vif->tx.req_cons;
- rmb(); /* Ensure that we see the request before we copy it. */
- memcpy(&txreq, RING_GET_REQUEST(&vif->tx, idx), sizeof(txreq));
-
- /* Credit-based scheduling. */
- if (txreq.size > vif->remaining_credit &&
- tx_credit_exceeded(vif, txreq.size)) {
- xenvif_put(vif);
- continue;
- }
-
- vif->remaining_credit -= txreq.size;
-
- work_to_do--;
- vif->tx.req_cons = ++idx;
-
- memset(extras, 0, sizeof(extras));
- if (txreq.flags & XEN_NETTXF_extra_info) {
- work_to_do = xen_netbk_get_extras(vif, extras,
- work_to_do);
- idx = vif->tx.req_cons;
- if (unlikely(work_to_do < 0)) {
- netbk_tx_err(vif, &txreq, idx);
- continue;
- }
- }
-
- ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do);
- if (unlikely(ret < 0)) {
- netbk_tx_err(vif, &txreq, idx - ret);
- continue;
- }
- idx += ret;
-
- if (unlikely(txreq.size < ETH_HLEN)) {
- netdev_dbg(vif->dev,
- "Bad packet size: %d\n", txreq.size);
- netbk_tx_err(vif, &txreq, idx);
- continue;
- }
-
- /* No crossing a page as the payload mustn't fragment. */
- if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
- netdev_dbg(vif->dev,
- "txreq.offset: %x, size: %u, end: %lu\n",
- txreq.offset, txreq.size,
- (txreq.offset&~PAGE_MASK) + txreq.size);
- netbk_tx_err(vif, &txreq, idx);
- continue;
- }
-
- index = pending_index(netbk->pending_cons);
- pending_idx = netbk->pending_ring[index];
-
- data_len = (txreq.size > PKT_PROT_LEN &&
- ret < MAX_SKB_FRAGS) ?
- PKT_PROT_LEN : txreq.size;
-
- skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
- GFP_ATOMIC | __GFP_NOWARN);
- if (unlikely(skb == NULL)) {
- netdev_dbg(vif->dev,
- "Can't allocate a skb in start_xmit.\n");
- netbk_tx_err(vif, &txreq, idx);
- break;
- }
-
- /* Packets passed to netif_rx() must have some headroom. */
- skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
-
- if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
- struct xen_netif_extra_info *gso;
- gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
-
- if (netbk_set_skb_gso(vif, skb, gso)) {
- kfree_skb(skb);
- netbk_tx_err(vif, &txreq, idx);
- continue;
- }
- }
-
- /* XXX could copy straight to head */
- page = xen_netbk_alloc_page(netbk, skb, pending_idx);
- if (!page) {
- kfree_skb(skb);
- netbk_tx_err(vif, &txreq, idx);
- continue;
- }
-
- gop->source.u.ref = txreq.gref;
- gop->source.domid = vif->domid;
- gop->source.offset = txreq.offset;
-
- gop->dest.u.gmfn = virt_to_mfn(page_address(page));
- gop->dest.domid = DOMID_SELF;
- gop->dest.offset = txreq.offset;
-
- gop->len = txreq.size;
- gop->flags = GNTCOPY_source_gref;
-
- gop++;
-
- memcpy(&netbk->pending_tx_info[pending_idx].req,
- &txreq, sizeof(txreq));
- netbk->pending_tx_info[pending_idx].vif = vif;
- *((u16 *)skb->data) = pending_idx;
-
- __skb_put(skb, data_len);
-
- skb_shinfo(skb)->nr_frags = ret;
- if (data_len < txreq.size) {
- skb_shinfo(skb)->nr_frags++;
- frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
- pending_idx);
- } else {
- frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
- INVALID_PENDING_IDX);
- }
-
- __skb_queue_tail(&netbk->tx_queue, skb);
-
- netbk->pending_cons++;
-
- request_gop = xen_netbk_get_requests(netbk, vif,
- skb, txfrags, gop);
- if (request_gop == NULL) {
- kfree_skb(skb);
- netbk_tx_err(vif, &txreq, idx);
- continue;
- }
- gop = request_gop;
-
- vif->tx.req_cons = idx;
- xen_netbk_check_rx_xenvif(vif);
-
- if ((gop-netbk->tx_copy_ops) >= ARRAY_SIZE(netbk->tx_copy_ops))
- break;
- }
-
- return gop - netbk->tx_copy_ops;
-}
-
-static void xen_netbk_tx_submit(struct xen_netbk *netbk)
-{
- struct gnttab_copy *gop = netbk->tx_copy_ops;
- struct sk_buff *skb;
-
- while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
- struct xen_netif_tx_request *txp;
- struct xenvif *vif;
- u16 pending_idx;
- unsigned data_len;
-
- pending_idx = *((u16 *)skb->data);
- vif = netbk->pending_tx_info[pending_idx].vif;
- txp = &netbk->pending_tx_info[pending_idx].req;
-
- /* Check the remap error code. */
- if (unlikely(xen_netbk_tx_check_gop(netbk, skb, &gop))) {
- netdev_dbg(vif->dev, "netback grant failed.\n");
- skb_shinfo(skb)->nr_frags = 0;
- kfree_skb(skb);
- continue;
- }
-
- data_len = skb->len;
- memcpy(skb->data,
- (void *)(idx_to_kaddr(netbk, pending_idx)|txp->offset),
- data_len);
- if (data_len < txp->size) {
- /* Append the packet payload as a fragment. */
- txp->offset += data_len;
- txp->size -= data_len;
- } else {
- /* Schedule a response immediately. */
- xen_netbk_idx_release(netbk, pending_idx);
- }
-
- if (txp->flags & XEN_NETTXF_csum_blank)
- skb->ip_summed = CHECKSUM_PARTIAL;
- else if (txp->flags & XEN_NETTXF_data_validated)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
-
- xen_netbk_fill_frags(netbk, skb);
-
- /*
- * If the initial fragment was < PKT_PROT_LEN then
- * pull through some bytes from the other fragments to
- * increase the linear region to PKT_PROT_LEN bytes.
- */
- if (skb_headlen(skb) < PKT_PROT_LEN && skb_is_nonlinear(skb)) {
- int target = min_t(int, skb->len, PKT_PROT_LEN);
- __pskb_pull_tail(skb, target - skb_headlen(skb));
- }
-
- skb->dev = vif->dev;
- skb->protocol = eth_type_trans(skb, skb->dev);
-
- if (checksum_setup(vif, skb)) {
- netdev_dbg(vif->dev,
- "Can't setup checksum in net_tx_action\n");
- kfree_skb(skb);
- continue;
- }
-
- vif->dev->stats.rx_bytes += skb->len;
- vif->dev->stats.rx_packets++;
-
- xenvif_receive_skb(vif, skb);
- }
-}
-
-/* Called after netfront has transmitted */
-static void xen_netbk_tx_action(struct xen_netbk *netbk)
-{
- unsigned nr_gops;
- int ret;
-
- nr_gops = xen_netbk_tx_build_gops(netbk);
-
- if (nr_gops == 0)
- return;
- ret = HYPERVISOR_grant_table_op(GNTTABOP_copy,
- netbk->tx_copy_ops, nr_gops);
- BUG_ON(ret);
-
- xen_netbk_tx_submit(netbk);
-
-}
-
-static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
-{
- struct xenvif *vif;
- struct pending_tx_info *pending_tx_info;
- pending_ring_idx_t index;
-
- /* Already complete? */
- if (netbk->mmap_pages[pending_idx] == NULL)
- return;
-
- pending_tx_info = &netbk->pending_tx_info[pending_idx];
-
- vif = pending_tx_info->vif;
-
- make_tx_response(vif, &pending_tx_info->req, XEN_NETIF_RSP_OKAY);
-
- index = pending_index(netbk->pending_prod++);
- netbk->pending_ring[index] = pending_idx;
-
- xenvif_put(vif);
-
- netbk->mmap_pages[pending_idx]->mapping = 0;
- put_page(netbk->mmap_pages[pending_idx]);
- netbk->mmap_pages[pending_idx] = NULL;
-}
-
-static void make_tx_response(struct xenvif *vif,
- struct xen_netif_tx_request *txp,
- s8 st)
-{
- RING_IDX i = vif->tx.rsp_prod_pvt;
- struct xen_netif_tx_response *resp;
- int notify;
-
- resp = RING_GET_RESPONSE(&vif->tx, i);
- resp->id = txp->id;
- resp->status = st;
-
- if (txp->flags & XEN_NETTXF_extra_info)
- RING_GET_RESPONSE(&vif->tx, ++i)->status = XEN_NETIF_RSP_NULL;
-
- vif->tx.rsp_prod_pvt = ++i;
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->tx, notify);
- if (notify)
- notify_remote_via_irq(vif->irq);
-}
-
-static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
- u16 id,
- s8 st,
- u16 offset,
- u16 size,
- u16 flags)
-{
- RING_IDX i = vif->rx.rsp_prod_pvt;
- struct xen_netif_rx_response *resp;
-
- resp = RING_GET_RESPONSE(&vif->rx, i);
- resp->offset = offset;
- resp->flags = flags;
- resp->id = id;
- resp->status = (s16)size;
- if (st < 0)
- resp->status = (s16)st;
-
- vif->rx.rsp_prod_pvt = ++i;
-
- return resp;
-}
-
-static inline int rx_work_todo(struct xen_netbk *netbk)
-{
- return !skb_queue_empty(&netbk->rx_queue);
-}
-
-static inline int tx_work_todo(struct xen_netbk *netbk)
-{
-
- if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&netbk->net_schedule_list))
- return 1;
-
- return 0;
-}
-
-static int xen_netbk_kthread(void *data)
-{
- struct xen_netbk *netbk = data;
- while (!kthread_should_stop()) {
- wait_event_interruptible(netbk->wq,
- rx_work_todo(netbk) ||
- tx_work_todo(netbk) ||
- kthread_should_stop());
- cond_resched();
-
- if (kthread_should_stop())
- break;
-
- if (rx_work_todo(netbk))
- xen_netbk_rx_action(netbk);
-
- if (tx_work_todo(netbk))
- xen_netbk_tx_action(netbk);
- }
-
- return 0;
-}
-
-void xen_netbk_unmap_frontend_rings(struct xenvif *vif)
-{
- if (vif->tx.sring)
- xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif),
- vif->tx.sring);
- if (vif->rx.sring)
- xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif),
- vif->rx.sring);
-}
-
-int xen_netbk_map_frontend_rings(struct xenvif *vif,
- grant_ref_t tx_ring_ref,
- grant_ref_t rx_ring_ref)
-{
- void *addr;
- struct xen_netif_tx_sring *txs;
- struct xen_netif_rx_sring *rxs;
-
- int err = -ENOMEM;
-
- err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif),
- tx_ring_ref, &addr);
- if (err)
- goto err;
-
- txs = (struct xen_netif_tx_sring *)addr;
- BACK_RING_INIT(&vif->tx, txs, PAGE_SIZE);
-
- err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif),
- rx_ring_ref, &addr);
- if (err)
- goto err;
-
- rxs = (struct xen_netif_rx_sring *)addr;
- BACK_RING_INIT(&vif->rx, rxs, PAGE_SIZE);
-
- vif->rx_req_cons_peek = 0;
-
- return 0;
-
-err:
- xen_netbk_unmap_frontend_rings(vif);
- return err;
-}
-
-static int __init netback_init(void)
-{
- int i;
- int rc = 0;
- int group;
-
- if (!xen_domain())
- return -ENODEV;
-
- xen_netbk_group_nr = num_online_cpus();
- xen_netbk = vzalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
- if (!xen_netbk)
- return -ENOMEM;
-
- for (group = 0; group < xen_netbk_group_nr; group++) {
- struct xen_netbk *netbk = &xen_netbk[group];
- skb_queue_head_init(&netbk->rx_queue);
- skb_queue_head_init(&netbk->tx_queue);
-
- init_timer(&netbk->net_timer);
- netbk->net_timer.data = (unsigned long)netbk;
- netbk->net_timer.function = xen_netbk_alarm;
-
- netbk->pending_cons = 0;
- netbk->pending_prod = MAX_PENDING_REQS;
- for (i = 0; i < MAX_PENDING_REQS; i++)
- netbk->pending_ring[i] = i;
-
- init_waitqueue_head(&netbk->wq);
- netbk->task = kthread_create(xen_netbk_kthread,
- (void *)netbk,
- "netback/%u", group);
-
- if (IS_ERR(netbk->task)) {
- printk(KERN_ALERT "kthread_create() fails at netback\n");
- del_timer(&netbk->net_timer);
- rc = PTR_ERR(netbk->task);
- goto failed_init;
- }
-
- kthread_bind(netbk->task, group);
-
- INIT_LIST_HEAD(&netbk->net_schedule_list);
-
- spin_lock_init(&netbk->net_schedule_list_lock);
-
- atomic_set(&netbk->netfront_count, 0);
-
- wake_up_process(netbk->task);
- }
-
- rc = xenvif_xenbus_init();
- if (rc)
- goto failed_init;
-
- return 0;
-
-failed_init:
- while (--group >= 0) {
- struct xen_netbk *netbk = &xen_netbk[group];
- for (i = 0; i < MAX_PENDING_REQS; i++) {
- if (netbk->mmap_pages[i])
- __free_page(netbk->mmap_pages[i]);
- }
- del_timer(&netbk->net_timer);
- kthread_stop(netbk->task);
- }
- vfree(xen_netbk);
- return rc;
-
-}
-
-module_init(netback_init);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("xen-backend:vif");
diff --git a/ANDROID_3.4.5/drivers/net/xen-netback/xenbus.c b/ANDROID_3.4.5/drivers/net/xen-netback/xenbus.c
deleted file mode 100644
index 410018c4..00000000
--- a/ANDROID_3.4.5/drivers/net/xen-netback/xenbus.c
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * Xenbus code for netif backend
- *
- * Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
- * Copyright (C) 2005 XenSource Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that 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
-*/
-
-#include "common.h"
-
-struct backend_info {
- struct xenbus_device *dev;
- struct xenvif *vif;
- enum xenbus_state frontend_state;
- struct xenbus_watch hotplug_status_watch;
- u8 have_hotplug_status_watch:1;
-};
-
-static int connect_rings(struct backend_info *);
-static void connect(struct backend_info *);
-static void backend_create_xenvif(struct backend_info *be);
-static void unregister_hotplug_status_watch(struct backend_info *be);
-
-static int netback_remove(struct xenbus_device *dev)
-{
- struct backend_info *be = dev_get_drvdata(&dev->dev);
-
- unregister_hotplug_status_watch(be);
- if (be->vif) {
- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
- xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
- xenvif_disconnect(be->vif);
- be->vif = NULL;
- }
- kfree(be);
- dev_set_drvdata(&dev->dev, NULL);
- return 0;
-}
-
-
-/**
- * Entry point to this code when a new device is created. Allocate the basic
- * structures and switch to InitWait.
- */
-static int netback_probe(struct xenbus_device *dev,
- const struct xenbus_device_id *id)
-{
- const char *message;
- struct xenbus_transaction xbt;
- int err;
- int sg;
- struct backend_info *be = kzalloc(sizeof(struct backend_info),
- GFP_KERNEL);
- if (!be) {
- xenbus_dev_fatal(dev, -ENOMEM,
- "allocating backend structure");
- return -ENOMEM;
- }
-
- be->dev = dev;
- dev_set_drvdata(&dev->dev, be);
-
- sg = 1;
-
- do {
- err = xenbus_transaction_start(&xbt);
- if (err) {
- xenbus_dev_fatal(dev, err, "starting transaction");
- goto fail;
- }
-
- err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", sg);
- if (err) {
- message = "writing feature-sg";
- goto abort_transaction;
- }
-
- err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
- "%d", sg);
- if (err) {
- message = "writing feature-gso-tcpv4";
- goto abort_transaction;
- }
-
- /* We support rx-copy path. */
- err = xenbus_printf(xbt, dev->nodename,
- "feature-rx-copy", "%d", 1);
- if (err) {
- message = "writing feature-rx-copy";
- goto abort_transaction;
- }
-
- /*
- * We don't support rx-flip path (except old guests who don't
- * grok this feature flag).
- */
- err = xenbus_printf(xbt, dev->nodename,
- "feature-rx-flip", "%d", 0);
- if (err) {
- message = "writing feature-rx-flip";
- goto abort_transaction;
- }
-
- err = xenbus_transaction_end(xbt, 0);
- } while (err == -EAGAIN);
-
- if (err) {
- xenbus_dev_fatal(dev, err, "completing transaction");
- goto fail;
- }
-
- err = xenbus_switch_state(dev, XenbusStateInitWait);
- if (err)
- goto fail;
-
- /* This kicks hotplug scripts, so do it immediately. */
- backend_create_xenvif(be);
-
- return 0;
-
-abort_transaction:
- xenbus_transaction_end(xbt, 1);
- xenbus_dev_fatal(dev, err, "%s", message);
-fail:
- pr_debug("failed");
- netback_remove(dev);
- return err;
-}
-
-
-/*
- * Handle the creation of the hotplug script environment. We add the script
- * and vif variables to the environment, for the benefit of the vif-* hotplug
- * scripts.
- */
-static int netback_uevent(struct xenbus_device *xdev,
- struct kobj_uevent_env *env)
-{
- struct backend_info *be = dev_get_drvdata(&xdev->dev);
- char *val;
-
- val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
- if (IS_ERR(val)) {
- int err = PTR_ERR(val);
- xenbus_dev_fatal(xdev, err, "reading script");
- return err;
- } else {
- if (add_uevent_var(env, "script=%s", val)) {
- kfree(val);
- return -ENOMEM;
- }
- kfree(val);
- }
-
- if (!be || !be->vif)
- return 0;
-
- return add_uevent_var(env, "vif=%s", be->vif->dev->name);
-}
-
-
-static void backend_create_xenvif(struct backend_info *be)
-{
- int err;
- long handle;
- struct xenbus_device *dev = be->dev;
-
- if (be->vif != NULL)
- return;
-
- err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle);
- if (err != 1) {
- xenbus_dev_fatal(dev, err, "reading handle");
- return;
- }
-
- be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle);
- if (IS_ERR(be->vif)) {
- err = PTR_ERR(be->vif);
- be->vif = NULL;
- xenbus_dev_fatal(dev, err, "creating interface");
- return;
- }
-
- kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
-}
-
-
-static void disconnect_backend(struct xenbus_device *dev)
-{
- struct backend_info *be = dev_get_drvdata(&dev->dev);
-
- if (be->vif) {
- xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
- xenvif_disconnect(be->vif);
- be->vif = NULL;
- }
-}
-
-/**
- * Callback received when the frontend's state changes.
- */
-static void frontend_changed(struct xenbus_device *dev,
- enum xenbus_state frontend_state)
-{
- struct backend_info *be = dev_get_drvdata(&dev->dev);
-
- pr_debug("frontend state %s", xenbus_strstate(frontend_state));
-
- be->frontend_state = frontend_state;
-
- switch (frontend_state) {
- case XenbusStateInitialising:
- if (dev->state == XenbusStateClosed) {
- printk(KERN_INFO "%s: %s: prepare for reconnect\n",
- __func__, dev->nodename);
- xenbus_switch_state(dev, XenbusStateInitWait);
- }
- break;
-
- case XenbusStateInitialised:
- break;
-
- case XenbusStateConnected:
- if (dev->state == XenbusStateConnected)
- break;
- backend_create_xenvif(be);
- if (be->vif)
- connect(be);
- break;
-
- case XenbusStateClosing:
- if (be->vif)
- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
- disconnect_backend(dev);
- xenbus_switch_state(dev, XenbusStateClosing);
- break;
-
- case XenbusStateClosed:
- xenbus_switch_state(dev, XenbusStateClosed);
- if (xenbus_dev_is_online(dev))
- break;
- /* fall through if not online */
- case XenbusStateUnknown:
- device_unregister(&dev->dev);
- break;
-
- default:
- xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
- frontend_state);
- break;
- }
-}
-
-
-static void xen_net_read_rate(struct xenbus_device *dev,
- unsigned long *bytes, unsigned long *usec)
-{
- char *s, *e;
- unsigned long b, u;
- char *ratestr;
-
- /* Default to unlimited bandwidth. */
- *bytes = ~0UL;
- *usec = 0;
-
- ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
- if (IS_ERR(ratestr))
- return;
-
- s = ratestr;
- b = simple_strtoul(s, &e, 10);
- if ((s == e) || (*e != ','))
- goto fail;
-
- s = e + 1;
- u = simple_strtoul(s, &e, 10);
- if ((s == e) || (*e != '\0'))
- goto fail;
-
- *bytes = b;
- *usec = u;
-
- kfree(ratestr);
- return;
-
- fail:
- pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
- kfree(ratestr);
-}
-
-static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
-{
- char *s, *e, *macstr;
- int i;
-
- macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
- if (IS_ERR(macstr))
- return PTR_ERR(macstr);
-
- for (i = 0; i < ETH_ALEN; i++) {
- mac[i] = simple_strtoul(s, &e, 16);
- if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
- kfree(macstr);
- return -ENOENT;
- }
- s = e+1;
- }
-
- kfree(macstr);
- return 0;
-}
-
-static void unregister_hotplug_status_watch(struct backend_info *be)
-{
- if (be->have_hotplug_status_watch) {
- unregister_xenbus_watch(&be->hotplug_status_watch);
- kfree(be->hotplug_status_watch.node);
- }
- be->have_hotplug_status_watch = 0;
-}
-
-static void hotplug_status_changed(struct xenbus_watch *watch,
- const char **vec,
- unsigned int vec_size)
-{
- struct backend_info *be = container_of(watch,
- struct backend_info,
- hotplug_status_watch);
- char *str;
- unsigned int len;
-
- str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status", &len);
- if (IS_ERR(str))
- return;
- if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) {
- xenbus_switch_state(be->dev, XenbusStateConnected);
- /* Not interested in this watch anymore. */
- unregister_hotplug_status_watch(be);
- }
- kfree(str);
-}
-
-static void connect(struct backend_info *be)
-{
- int err;
- struct xenbus_device *dev = be->dev;
-
- err = connect_rings(be);
- if (err)
- return;
-
- err = xen_net_read_mac(dev, be->vif->fe_dev_addr);
- if (err) {
- xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
- return;
- }
-
- xen_net_read_rate(dev, &be->vif->credit_bytes,
- &be->vif->credit_usec);
- be->vif->remaining_credit = be->vif->credit_bytes;
-
- unregister_hotplug_status_watch(be);
- err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
- hotplug_status_changed,
- "%s/%s", dev->nodename, "hotplug-status");
- if (err) {
- /* Switch now, since we can't do a watch. */
- xenbus_switch_state(dev, XenbusStateConnected);
- } else {
- be->have_hotplug_status_watch = 1;
- }
-
- netif_wake_queue(be->vif->dev);
-}
-
-
-static int connect_rings(struct backend_info *be)
-{
- struct xenvif *vif = be->vif;
- struct xenbus_device *dev = be->dev;
- unsigned long tx_ring_ref, rx_ring_ref;
- unsigned int evtchn, rx_copy;
- int err;
- int val;
-
- err = xenbus_gather(XBT_NIL, dev->otherend,
- "tx-ring-ref", "%lu", &tx_ring_ref,
- "rx-ring-ref", "%lu", &rx_ring_ref,
- "event-channel", "%u", &evtchn, NULL);
- if (err) {
- xenbus_dev_fatal(dev, err,
- "reading %s/ring-ref and event-channel",
- dev->otherend);
- return err;
- }
-
- err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u",
- &rx_copy);
- if (err == -ENOENT) {
- err = 0;
- rx_copy = 0;
- }
- if (err < 0) {
- xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
- dev->otherend);
- return err;
- }
- if (!rx_copy)
- return -EOPNOTSUPP;
-
- if (vif->dev->tx_queue_len != 0) {
- if (xenbus_scanf(XBT_NIL, dev->otherend,
- "feature-rx-notify", "%d", &val) < 0)
- val = 0;
- if (val)
- vif->can_queue = 1;
- else
- /* Must be non-zero for pfifo_fast to work. */
- vif->dev->tx_queue_len = 1;
- }
-
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
- "%d", &val) < 0)
- val = 0;
- vif->can_sg = !!val;
-
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
- "%d", &val) < 0)
- val = 0;
- vif->gso = !!val;
-
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
- "%d", &val) < 0)
- val = 0;
- vif->gso_prefix = !!val;
-
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
- "%d", &val) < 0)
- val = 0;
- vif->csum = !val;
-
- /* Map the shared frame, irq etc. */
- err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, evtchn);
- if (err) {
- xenbus_dev_fatal(dev, err,
- "mapping shared-frames %lu/%lu port %u",
- tx_ring_ref, rx_ring_ref, evtchn);
- return err;
- }
- return 0;
-}
-
-
-/* ** Driver Registration ** */
-
-
-static const struct xenbus_device_id netback_ids[] = {
- { "vif" },
- { "" }
-};
-
-
-static DEFINE_XENBUS_DRIVER(netback, ,
- .probe = netback_probe,
- .remove = netback_remove,
- .uevent = netback_uevent,
- .otherend_changed = frontend_changed,
-);
-
-int xenvif_xenbus_init(void)
-{
- return xenbus_register_backend(&netback_driver);
-}