[net-next PATCH 1/2] igbvf: add new driver to support 82576 virtual functions

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Jeff Kirsher
Date: Tuesday, March 10, 2009 - 7:09 pm

From: Alexander Duyck <alexander.h.duyck@intel.com>

This adds an igbvf driver to handle virtual functions provided
by the igb driver.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---

 drivers/net/Kconfig         |   21 
 drivers/net/Makefile        |    1 
 drivers/net/igbvf/Makefile  |   38 +
 drivers/net/igbvf/defines.h |  125 ++
 drivers/net/igbvf/ethtool.c |  556 ++++++++
 drivers/net/igbvf/igbvf.h   |  333 +++++
 drivers/net/igbvf/mbx.c     |  350 +++++
 drivers/net/igbvf/mbx.h     |   75 +
 drivers/net/igbvf/netdev.c  | 2901 +++++++++++++++++++++++++++++++++++++++++++
 drivers/net/igbvf/regs.h    |  108 ++
 drivers/net/igbvf/vf.c      |  398 ++++++
 drivers/net/igbvf/vf.h      |  265 ++++
 12 files changed, 5171 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/igbvf/Makefile
 create mode 100644 drivers/net/igbvf/defines.h
 create mode 100644 drivers/net/igbvf/ethtool.c
 create mode 100644 drivers/net/igbvf/igbvf.h
 create mode 100644 drivers/net/igbvf/mbx.c
 create mode 100644 drivers/net/igbvf/mbx.h
 create mode 100644 drivers/net/igbvf/netdev.c
 create mode 100644 drivers/net/igbvf/regs.h
 create mode 100644 drivers/net/igbvf/vf.c
 create mode 100644 drivers/net/igbvf/vf.h

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 45403e6..e7f0713 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2028,6 +2028,27 @@ config IGB_DCA
 	  driver.  DCA is a method for warming the CPU cache before data
 	  is used, with the intent of lessening the impact of cache misses.
 
+config IGBVF
+       tristate "Intel(R) 82576 Virtual Function Ethernet support"
+       depends on PCI
+       ---help---
+         This driver supports Intel(R) 82576 virtual functions.  For more
+         information on how to identify your adapter, go to the Adapter &
+         Driver ID Guide at:
+
+         <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+         For general information and support, go to the Intel support
+         website at:
+
+         <http://support.intel.com>
+
+         More specific information on configuring the driver is in
+         <file:Documentation/networking/e1000.txt>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called igbvf.
+
 source "drivers/net/ixp2000/Kconfig"
 
 config MYRI_SBUS
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 3f8cb31..123d90b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_E1000E) += e1000e/
 obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
 obj-$(CONFIG_IGB) += igb/
+obj-$(CONFIG_IGBVF) += igbvf/
 obj-$(CONFIG_IXGBE) += ixgbe/
 obj-$(CONFIG_IXGB) += ixgb/
 obj-$(CONFIG_IP1000) += ipg.o
diff --git a/drivers/net/igbvf/Makefile b/drivers/net/igbvf/Makefile
new file mode 100644
index 0000000..c2f150d
--- /dev/null
+++ b/drivers/net/igbvf/Makefile
@@ -0,0 +1,38 @@
+################################################################################
+#
+# Intel(R) 82576 Virtual Function Linux driver
+# Copyright(c) 2009 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) 82576 VF ethernet driver
+#
+
+obj-$(CONFIG_IGBVF) += igbvf.o
+
+igbvf-objs := vf.o \
+              mbx.o \
+              ethtool.o \
+              netdev.o
+
diff --git a/drivers/net/igbvf/defines.h b/drivers/net/igbvf/defines.h
new file mode 100644
index 0000000..88a4753
--- /dev/null
+++ b/drivers/net/igbvf/defines.h
@@ -0,0 +1,125 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* IVAR valid bit */
+#define E1000_IVAR_VALID        0x80
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+/* Device Control */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+
+#define MAX_JUMBO_FRAME_SIZE    0x3F00
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_MBX      15
+
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN                 6
+#endif
+
+/* SRRCTL bit definitions */
+#define E1000_SRRCTL_BSIZEPKT_SHIFT                     10 /* Shift _right_ */
+#define E1000_SRRCTL_BSIZEHDRSIZE_MASK                  0x00000F00
+#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT                 2  /* Shift _left_ */
+#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF                0x02000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS          0x0A000000
+#define E1000_SRRCTL_DESCTYPE_MASK                      0x0E000000
+#define E1000_SRRCTL_DROP_EN                            0x80000000
+
+#define E1000_SRRCTL_BSIZEPKT_MASK      0x0000007F
+#define E1000_SRRCTL_BSIZEHDR_MASK      0x00003F00
+
+/* Additional Descriptor Control definitions */
+#define E1000_TXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Tx Queue */
+#define E1000_RXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Rx Queue */
+
+/* Direct Cache Access (DCA) definitions */
+#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
+
+#define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
+
+#endif /* _E1000_DEFINES_H_ */
diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c
new file mode 100644
index 0000000..ea4d29f
--- /dev/null
+++ b/drivers/net/igbvf/ethtool.c
@@ -0,0 +1,556 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for igbvf */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "igbvf.h"
+#include <linux/if_vlan.h>
+
+
+struct igbvf_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+	int base_stat_offset;
+};
+
+#define IGBVF_STAT(m, b) sizeof(((struct igbvf_adapter *)0)->m), \
+		offsetof(struct igbvf_adapter, m), \
+		offsetof(struct igbvf_adapter, b)
+
+static const struct igbvf_stats igbvf_gstrings_stats[] = {
+	{ "rx_packets", IGBVF_STAT(stats.gprc, stats.base_gprc) },
+	{ "tx_packets", IGBVF_STAT(stats.gptc, stats.base_gptc) },
+	{ "rx_bytes", IGBVF_STAT(stats.gorc, stats.base_gorc) },
+	{ "tx_bytes", IGBVF_STAT(stats.gotc, stats.base_gotc) },
+	{ "multicast", IGBVF_STAT(stats.mprc, stats.base_mprc) },
+	{ "lbrx_bytes", IGBVF_STAT(stats.gorlbc, stats.base_gorlbc) },
+	{ "lbrx_packets", IGBVF_STAT(stats.gprlbc, stats.base_gprlbc) },
+	{ "tx_restart_queue", IGBVF_STAT(restart_queue, zero_base) },
+	{ "rx_long_byte_count", IGBVF_STAT(stats.gorc, stats.base_gorc) },
+	{ "rx_csum_offload_good", IGBVF_STAT(hw_csum_good, zero_base) },
+	{ "rx_csum_offload_errors", IGBVF_STAT(hw_csum_err, zero_base) },
+	{ "rx_header_split", IGBVF_STAT(rx_hdr_split, zero_base) },
+	{ "alloc_rx_buff_failed", IGBVF_STAT(alloc_rx_buff_failed, zero_base) },
+};
+
+#define IGBVF_GLOBAL_STATS_LEN	\
+	(sizeof(igbvf_gstrings_stats) / sizeof(struct igbvf_stats))
+
+#define IGBVF_STATS_LEN (IGBVF_GLOBAL_STATS_LEN)
+
+static const char igbvf_gstrings_test[][ETH_GSTRING_LEN] = {
+	"Link test   (on/offline)"
+};
+
+#define IGBVF_TEST_LEN ARRAY_SIZE(igbvf_gstrings_test)
+
+static int igbvf_get_settings(struct net_device *netdev,
+                              struct ethtool_cmd *ecmd)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 status;
+
+	ecmd->supported   = SUPPORTED_1000baseT_Full;
+
+	ecmd->advertising = ADVERTISED_1000baseT_Full;
+
+	ecmd->port = -1;
+	ecmd->transceiver = XCVR_DUMMY1;
+
+	status = er32(STATUS);
+	if (status & E1000_STATUS_LU) {
+		if (status & E1000_STATUS_SPEED_1000)
+			ecmd->speed = 1000;
+		else if (status & E1000_STATUS_SPEED_100)
+			ecmd->speed = 100;
+		else
+			ecmd->speed = 10;
+
+		if (status & E1000_STATUS_FD)
+			ecmd->duplex = DUPLEX_FULL;
+		else
+			ecmd->duplex = DUPLEX_HALF;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+
+	ecmd->autoneg = AUTONEG_DISABLE;
+
+	return 0;
+}
+
+static u32 igbvf_get_link(struct net_device *netdev)
+{
+	return netif_carrier_ok(netdev);
+}
+
+static int igbvf_set_settings(struct net_device *netdev,
+                              struct ethtool_cmd *ecmd)
+{
+	return -EOPNOTSUPP;
+}
+
+static void igbvf_get_pauseparam(struct net_device *netdev,
+                                 struct ethtool_pauseparam *pause)
+{
+	return;
+}
+
+static int igbvf_set_pauseparam(struct net_device *netdev,
+                                struct ethtool_pauseparam *pause)
+{
+	return -EOPNOTSUPP;
+}
+
+static u32 igbvf_get_tx_csum(struct net_device *netdev)
+{
+	return ((netdev->features & NETIF_F_IP_CSUM) != 0);
+}
+
+static int igbvf_set_tx_csum(struct net_device *netdev, u32 data)
+{
+	if (data)
+		netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+	else
+		netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+	return 0;
+}
+
+static int igbvf_set_tso(struct net_device *netdev, u32 data)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	int i;
+	struct net_device *v_netdev;
+
+	if (data) {
+		netdev->features |= NETIF_F_TSO;
+		netdev->features |= NETIF_F_TSO6;
+	} else {
+		netdev->features &= ~NETIF_F_TSO;
+		netdev->features &= ~NETIF_F_TSO6;
+		/* disable TSO on all VLANs if they're present */
+		if (!adapter->vlgrp)
+			goto tso_out;
+		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+			v_netdev = vlan_group_get_device(adapter->vlgrp, i);
+			if (!v_netdev)
+				continue;
+
+			v_netdev->features &= ~NETIF_F_TSO;
+			v_netdev->features &= ~NETIF_F_TSO6;
+			vlan_group_set_device(adapter->vlgrp, i, v_netdev);
+		}
+	}
+
+tso_out:
+	dev_info(&adapter->pdev->dev, "TSO is %s\n",
+	         data ? "Enabled" : "Disabled");
+	adapter->flags |= FLAG_TSO_FORCE;
+	return 0;
+}
+
+static u32 igbvf_get_msglevel(struct net_device *netdev)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	return adapter->msg_enable;
+}
+
+static void igbvf_set_msglevel(struct net_device *netdev, u32 data)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	adapter->msg_enable = data;
+}
+
+static int igbvf_get_regs_len(struct net_device *netdev)
+{
+#define IGBVF_REGS_LEN 8
+	return IGBVF_REGS_LEN * sizeof(u32);
+}
+
+static void igbvf_get_regs(struct net_device *netdev,
+                           struct ethtool_regs *regs, void *p)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 *regs_buff = p;
+	u8 revision_id;
+
+	memset(p, 0, IGBVF_REGS_LEN * sizeof(u32));
+
+	pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id);
+
+	regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device;
+
+	regs_buff[0] = er32(CTRL);
+	regs_buff[1] = er32(STATUS);
+
+	regs_buff[2] = er32(RDLEN(0));
+	regs_buff[3] = er32(RDH(0));
+	regs_buff[4] = er32(RDT(0));
+
+	regs_buff[5] = er32(TDLEN(0));
+	regs_buff[6] = er32(TDH(0));
+	regs_buff[7] = er32(TDT(0));
+}
+
+static int igbvf_get_eeprom_len(struct net_device *netdev)
+{
+	return 0;
+}
+
+static int igbvf_get_eeprom(struct net_device *netdev,
+                            struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	return -EOPNOTSUPP;
+}
+
+static int igbvf_set_eeprom(struct net_device *netdev,
+                            struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	return -EOPNOTSUPP;
+}
+
+static void igbvf_get_drvinfo(struct net_device *netdev,
+                              struct ethtool_drvinfo *drvinfo)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	char firmware_version[32] = "N/A";
+
+	strncpy(drvinfo->driver,  igbvf_driver_name, 32);
+	strncpy(drvinfo->version, igbvf_driver_version, 32);
+	strncpy(drvinfo->fw_version, firmware_version, 32);
+	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+	drvinfo->regdump_len = igbvf_get_regs_len(netdev);
+	drvinfo->eedump_len = igbvf_get_eeprom_len(netdev);
+}
+
+static void igbvf_get_ringparam(struct net_device *netdev,
+                                struct ethtool_ringparam *ring)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	struct igbvf_ring *tx_ring = adapter->tx_ring;
+	struct igbvf_ring *rx_ring = adapter->rx_ring;
+
+	ring->rx_max_pending = IGBVF_MAX_RXD;
+	ring->tx_max_pending = IGBVF_MAX_TXD;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = rx_ring->count;
+	ring->tx_pending = tx_ring->count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static int igbvf_set_ringparam(struct net_device *netdev,
+                               struct ethtool_ringparam *ring)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	struct igbvf_ring *tx_ring, *tx_old;
+	struct igbvf_ring *rx_ring, *rx_old;
+	int err;
+
+	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+		return -EINVAL;
+
+	while (test_and_set_bit(__IGBVF_RESETTING, &adapter->state))
+		msleep(1);
+
+	if (netif_running(adapter->netdev))
+		igbvf_down(adapter);
+
+	tx_old = adapter->tx_ring;
+	rx_old = adapter->rx_ring;
+
+	err = -ENOMEM;
+	tx_ring = kzalloc(sizeof(struct igbvf_ring), GFP_KERNEL);
+	if (!tx_ring)
+		goto err_alloc_tx;
+	/*
+	 * use a memcpy to save any previously configured
+	 * items like napi structs from having to be
+	 * reinitialized
+	 */
+	memcpy(tx_ring, tx_old, sizeof(struct igbvf_ring));
+
+	rx_ring = kzalloc(sizeof(struct igbvf_ring), GFP_KERNEL);
+	if (!rx_ring)
+		goto err_alloc_rx;
+	memcpy(rx_ring, rx_old, sizeof(struct igbvf_ring));
+
+	adapter->tx_ring = tx_ring;
+	adapter->rx_ring = rx_ring;
+
+	rx_ring->count = max(ring->rx_pending, (u32)IGBVF_MIN_RXD);
+	rx_ring->count = min(rx_ring->count, (u32)(IGBVF_MAX_RXD));
+	rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+
+	tx_ring->count = max(ring->tx_pending, (u32)IGBVF_MIN_TXD);
+	tx_ring->count = min(tx_ring->count, (u32)(IGBVF_MAX_TXD));
+	tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+
+	if (netif_running(adapter->netdev)) {
+		/* Try to get new resources before deleting old */
+		err = igbvf_setup_rx_resources(adapter);
+		if (err)
+			goto err_setup_rx;
+		err = igbvf_setup_tx_resources(adapter);
+		if (err)
+			goto err_setup_tx;
+
+		/*
+		 * restore the old in order to free it,
+		 * then add in the new
+		 */
+		adapter->rx_ring = rx_old;
+		adapter->tx_ring = tx_old;
+		igbvf_free_rx_resources(adapter);
+		igbvf_free_tx_resources(adapter);
+		kfree(tx_old);
+		kfree(rx_old);
+		adapter->rx_ring = rx_ring;
+		adapter->tx_ring = tx_ring;
+		err = igbvf_up(adapter);
+		if (err)
+			goto err_setup;
+	}
+
+	clear_bit(__IGBVF_RESETTING, &adapter->state);
+	return 0;
+err_setup_tx:
+	igbvf_free_rx_resources(adapter);
+err_setup_rx:
+	adapter->rx_ring = rx_old;
+	adapter->tx_ring = tx_old;
+	kfree(rx_ring);
+err_alloc_rx:
+	kfree(tx_ring);
+err_alloc_tx:
+	igbvf_up(adapter);
+err_setup:
+	clear_bit(__IGBVF_RESETTING, &adapter->state);
+	return err;
+}
+
+static int igbvf_link_test(struct igbvf_adapter *adapter, u64 *data)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	*data = 0;
+
+	hw->mac.ops.check_for_link(hw);
+
+	if (!(er32(STATUS) & E1000_STATUS_LU))
+		*data = 1;
+
+	return *data;
+}
+
+static int igbvf_get_self_test_count(struct net_device *netdev)
+{
+	return IGBVF_TEST_LEN;
+}
+
+static int igbvf_get_stats_count(struct net_device *netdev)
+{
+	return IGBVF_STATS_LEN;
+}
+
+static void igbvf_diag_test(struct net_device *netdev,
+                            struct ethtool_test *eth_test, u64 *data)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+
+	set_bit(__IGBVF_TESTING, &adapter->state);
+
+	/*
+	 * Link test performed before hardware reset so autoneg doesn't
+	 * interfere with test result
+	 */
+	if (igbvf_link_test(adapter, &data[0]))
+		eth_test->flags |= ETH_TEST_FL_FAILED;
+
+	clear_bit(__IGBVF_TESTING, &adapter->state);
+	msleep_interruptible(4 * 1000);
+}
+
+static void igbvf_get_wol(struct net_device *netdev,
+                          struct ethtool_wolinfo *wol)
+{
+	wol->supported = 0;
+	wol->wolopts = 0;
+
+	return;
+}
+
+static int igbvf_set_wol(struct net_device *netdev,
+                         struct ethtool_wolinfo *wol)
+{
+	return -EOPNOTSUPP;
+}
+
+static int igbvf_phys_id(struct net_device *netdev, u32 data)
+{
+	return 0;
+}
+
+static int igbvf_get_coalesce(struct net_device *netdev,
+                              struct ethtool_coalesce *ec)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+
+	if (adapter->itr_setting <= 3)
+		ec->rx_coalesce_usecs = adapter->itr_setting;
+	else
+		ec->rx_coalesce_usecs = adapter->itr_setting >> 2;
+
+	return 0;
+}
+
+static int igbvf_set_coalesce(struct net_device *netdev,
+                              struct ethtool_coalesce *ec)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	if ((ec->rx_coalesce_usecs > IGBVF_MAX_ITR_USECS) ||
+	    ((ec->rx_coalesce_usecs > 3) &&
+	     (ec->rx_coalesce_usecs < IGBVF_MIN_ITR_USECS)) ||
+	    (ec->rx_coalesce_usecs == 2))
+		return -EINVAL;
+
+	/* convert to rate of irq's per second */
+	if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3) {
+		adapter->itr = IGBVF_START_ITR;
+		adapter->itr_setting = ec->rx_coalesce_usecs;
+	} else {
+		adapter->itr = ec->rx_coalesce_usecs << 2;
+		adapter->itr_setting = adapter->itr;
+	}
+
+	writel(adapter->itr,
+	       hw->hw_addr + adapter->rx_ring[0].itr_register);
+
+	return 0;
+}
+
+static int igbvf_nway_reset(struct net_device *netdev)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	if (netif_running(netdev))
+		igbvf_reinit_locked(adapter);
+	return 0;
+}
+
+
+static void igbvf_get_ethtool_stats(struct net_device *netdev,
+                                    struct ethtool_stats *stats,
+                                    u64 *data)
+{
+	struct igbvf_adapter *adapter = netdev_priv(netdev);
+	int i;
+
+	igbvf_update_stats(adapter);
+	for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) {
+		char *p = (char *)adapter +
+		          igbvf_gstrings_stats[i].stat_offset;
+		char *b = (char *)adapter +
+		          igbvf_gstrings_stats[i].base_stat_offset;
+		data[i] = ((igbvf_gstrings_stats[i].sizeof_stat ==
+		            sizeof(u64)) ? *(u64 *)p : *(u32 *)p) -
+		          ((igbvf_gstrings_stats[i].sizeof_stat ==
+		            sizeof(u64)) ? *(u64 *)b : *(u32 *)b);
+	}
+
+}
+
+static void igbvf_get_strings(struct net_device *netdev, u32 stringset,
+                              u8 *data)
+{
+	u8 *p = data;
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_TEST:
+		memcpy(data, *igbvf_gstrings_test, sizeof(igbvf_gstrings_test));
+		break;
+	case ETH_SS_STATS:
+		for (i = 0; i < IGBVF_GLOBAL_STATS_LEN; i++) {
+			memcpy(p, igbvf_gstrings_stats[i].stat_string,
+			       ETH_GSTRING_LEN);
+			p += ETH_GSTRING_LEN;
+		}
+		break;
+	}
+}
+
+static const struct ethtool_ops igbvf_ethtool_ops = {
+	.get_settings		= igbvf_get_settings,
+	.set_settings		= igbvf_set_settings,
+	.get_drvinfo		= igbvf_get_drvinfo,
+	.get_regs_len		= igbvf_get_regs_len,
+	.get_regs		= igbvf_get_regs,
+	.get_wol		= igbvf_get_wol,
+	.set_wol		= igbvf_set_wol,
+	.get_msglevel		= igbvf_get_msglevel,
+	.set_msglevel		= igbvf_set_msglevel,
+	.nway_reset		= igbvf_nway_reset,
+	.get_link		= igbvf_get_link,
+	.get_eeprom_len		= igbvf_get_eeprom_len,
+	.get_eeprom		= igbvf_get_eeprom,
+	.set_eeprom		= igbvf_set_eeprom,
+	.get_ringparam		= igbvf_get_ringparam,
+	.set_ringparam		= igbvf_set_ringparam,
+	.get_pauseparam		= igbvf_get_pauseparam,
+	.set_pauseparam		= igbvf_set_pauseparam,
+	.get_tx_csum		= igbvf_get_tx_csum,
+	.set_tx_csum		= igbvf_set_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= igbvf_set_tso,
+	.self_test		= igbvf_diag_test,
+	.get_strings		= igbvf_get_strings,
+	.phys_id		= igbvf_phys_id,
+	.get_ethtool_stats	= igbvf_get_ethtool_stats,
+	.self_test_count	= igbvf_get_self_test_count,
+	.get_stats_count	= igbvf_get_stats_count,
+	.get_coalesce		= igbvf_get_coalesce,
+	.set_coalesce		= igbvf_set_coalesce,
+};
+
+void igbvf_set_ethtool_ops(struct net_device *netdev)
+{
+	/* have to "undeclare" const on this struct to remove warnings */
+	SET_ETHTOOL_OPS(netdev, (struct ethtool_ops *)&igbvf_ethtool_ops);
+}
diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/igbvf/igbvf.h
new file mode 100644
index 0000000..b0d5326
--- /dev/null
+++ b/drivers/net/igbvf/igbvf.h
@@ -0,0 +1,333 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _IGBVF_H_
+#define _IGBVF_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+
+
+#include "vf.h"
+
+/* Forward declarations */
+struct igbvf_info;
+struct igbvf_adapter;
+
+/* Interrupt defines */
+#define IGBVF_START_ITR                 648 /* ~6000 ints/sec */
+
+/* Interrupt modes, as used by the IntMode paramter */
+#define IGBVF_INT_MODE_LEGACY           0
+#define IGBVF_INT_MODE_MSI              1
+#define IGBVF_INT_MODE_MSIX             2
+
+/* Tx/Rx descriptor defines */
+#define IGBVF_DEFAULT_TXD               256
+#define IGBVF_MAX_TXD                   4096
+#define IGBVF_MIN_TXD                   80
+
+#define IGBVF_DEFAULT_RXD               256
+#define IGBVF_MAX_RXD                   4096
+#define IGBVF_MIN_RXD                   80
+
+#define IGBVF_MIN_ITR_USECS             10 /* 100000 irq/sec */
+#define IGBVF_MAX_ITR_USECS             10000 /* 100    irq/sec */
+
+/* RX descriptor control thresholds.
+ * PTHRESH - MAC will consider prefetch if it has fewer than this number of
+ *           descriptors available in its onboard memory.
+ *           Setting this to 0 disables RX descriptor prefetch.
+ * HTHRESH - MAC will only prefetch if there are at least this many descriptors
+ *           available in host memory.
+ *           If PTHRESH is 0, this should also be 0.
+ * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
+ *           descriptors until either it has this many to write back, or the
+ *           ITR timer expires.
+ */
+#define IGBVF_RX_PTHRESH                16
+#define IGBVF_RX_HTHRESH                8
+#define IGBVF_RX_WTHRESH                1
+
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE      1522
+
+#define IGBVF_FC_PAUSE_TIME             0x0680 /* 858 usec */
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+#define IGBVF_TX_QUEUE_WAKE             32
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IGBVF_RX_BUFFER_WRITE           16 /* Must be power of 2 */
+
+#define AUTO_ALL_MODES                  0
+#define IGBVF_EEPROM_APME               0x0400
+
+#define IGBVF_MNG_VLAN_NONE             (-1)
+
+/* Number of packet split data buffers (not including the header buffer) */
+#define PS_PAGE_BUFFERS                 (MAX_PS_BUFFERS - 1)
+
+enum igbvf_boards {
+	board_vf,
+};
+
+struct igbvf_queue_stats {
+	u64 packets;
+	u64 bytes;
+};
+
+/*
+ * wrappers around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct igbvf_buffer {
+	dma_addr_t dma;
+	struct sk_buff *skb;
+	union {
+		/* Tx */
+		struct {
+			unsigned long time_stamp;
+			u16 length;
+			u16 next_to_watch;
+		};
+		/* Rx */
+		struct {
+			struct page *page;
+			u64 page_dma;
+			unsigned int page_offset;
+		};
+	};
+	struct page *page;
+};
+
+struct igbvf_ring {
+	struct igbvf_adapter *adapter;  /* backlink */
+	void *desc;                     /* pointer to ring memory  */
+	dma_addr_t dma;                 /* phys address of ring    */
+	unsigned int size;              /* length of ring in bytes */
+	unsigned int count;             /* number of desc. in ring */
+
+	u16 next_to_use;
+	u16 next_to_clean;
+
+	u16 head;
+	u16 tail;
+
+	/* array of buffer information structs */
+	struct igbvf_buffer *buffer_info;
+	struct napi_struct napi;
+
+	char name[IFNAMSIZ + 5];
+	u32 eims_value;
+	u32 itr_val;
+	u16 itr_register;
+	int set_itr;
+
+	struct sk_buff *rx_skb_top;
+
+	struct igbvf_queue_stats stats;
+};
+
+/* board specific private data structure */
+struct igbvf_adapter {
+	struct timer_list watchdog_timer;
+	struct timer_list blink_timer;
+
+	struct work_struct reset_task;
+	struct work_struct watchdog_task;
+
+	const struct igbvf_info *ei;
+
+	struct vlan_group *vlgrp;
+	u32 bd_number;
+	u32 rx_buffer_len;
+	u32 polling_interval;
+	u16 mng_vlan_id;
+	u16 link_speed;
+	u16 link_duplex;
+
+	spinlock_t tx_queue_lock; /* prevent concurrent tail updates */
+
+	/* track device up/down/testing state */
+	unsigned long state;
+
+	/* Interrupt Throttle Rate */
+	u32 itr;
+	u32 itr_setting;
+	u16 tx_itr;
+	u16 rx_itr;
+
+	/*
+	 * Tx
+	 */
+	struct igbvf_ring *tx_ring /* One per active queue */
+	____cacheline_aligned_in_smp;
+
+	unsigned long tx_queue_len;
+	unsigned int restart_queue;
+	u32 txd_cmd;
+
+	bool detect_tx_hung;
+	u8 tx_timeout_factor;
+
+	u32 tx_int_delay;
+	u32 tx_abs_int_delay;
+
+	unsigned int total_tx_bytes;
+	unsigned int total_tx_packets;
+	unsigned int total_rx_bytes;
+	unsigned int total_rx_packets;
+
+	/* Tx stats */
+	u32 tx_timeout_count;
+	u32 tx_fifo_head;
+	u32 tx_head_addr;
+	u32 tx_fifo_size;
+	u32 tx_dma_failed;
+
+	/*
+	 * Rx
+	 */
+	struct igbvf_ring *rx_ring;
+
+	u32 rx_int_delay;
+	u32 rx_abs_int_delay;
+
+	/* Rx stats */
+	u64 hw_csum_err;
+	u64 hw_csum_good;
+	u64 rx_hdr_split;
+	u32 alloc_rx_buff_failed;
+	u32 rx_dma_failed;
+
+	unsigned int rx_ps_hdr_size;
+	u32 max_frame_size;
+	u32 min_frame_size;
+
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct net_device_stats net_stats;
+	spinlock_t stats_lock;      /* prevent concurrent stats updates */
+
+	/* structs defined in e1000_hw.h */
+	struct e1000_hw hw;
+
+	/* The VF counters don't clear on read so we have to get a base
+	 * count on driver start up and always subtract that base on
+	 * on the first update, thus the flag..
+	 */
+	struct e1000_vf_stats stats;
+	u64 zero_base;
+
+	struct igbvf_ring test_tx_ring;
+	struct igbvf_ring test_rx_ring;
+	u32 test_icr;
+
+	u32 msg_enable;
+	struct msix_entry *msix_entries;
+	int int_mode;
+	u32 eims_enable_mask;
+	u32 eims_other;
+	u32 int_counter0;
+	u32 int_counter1;
+
+	u32 eeprom_wol;
+	u32 wol;
+	u32 pba;
+
+	bool fc_autoneg;
+
+	unsigned long led_status;
+
+	unsigned int flags;
+};
+
+struct igbvf_info {
+	enum e1000_mac_type     mac;
+	unsigned int            flags;
+	u32                     pba;
+	void                    (*init_ops)(struct e1000_hw *);
+	s32                     (*get_variants)(struct igbvf_adapter *);
+};
+
+/* hardware capability, feature, and workaround flags */
+#define FLAG_HAS_HW_VLAN_FILTER           (1 << 0)
+#define FLAG_HAS_JUMBO_FRAMES             (1 << 1)
+#define FLAG_MSI_ENABLED                  (1 << 2)
+#define FLAG_RX_CSUM_ENABLED              (1 << 3)
+#define FLAG_TSO_FORCE                    (1 << 4)
+
+#define IGBVF_DESC_UNUSED(R) \
+	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+	(R)->next_to_clean - (R)->next_to_use - 1)
+
+#define IGBVF_RX_DESC_ADV(R, i)     \
+	(&(((union e1000_adv_rx_desc *)((R).desc))[i]))
+#define IGBVF_TX_DESC_ADV(R, i)     \
+	(&(((union e1000_adv_tx_desc *)((R).desc))[i]))
+#define IGBVF_TX_CTXTDESC_ADV(R, i) \
+	(&(((struct e1000_adv_tx_context_desc *)((R).desc))[i]))
+
+enum igbvf_state_t {
+	__IGBVF_TESTING,
+	__IGBVF_RESETTING,
+	__IGBVF_DOWN
+};
+
+enum latency_range {
+	lowest_latency = 0,
+	low_latency = 1,
+	bulk_latency = 2,
+	latency_invalid = 255
+};
+
+extern char igbvf_driver_name[];
+extern const char igbvf_driver_version[];
+
+extern void igbvf_check_options(struct igbvf_adapter *adapter);
+extern void igbvf_set_ethtool_ops(struct net_device *netdev);
+
+extern int igbvf_up(struct igbvf_adapter *adapter);
+extern void igbvf_down(struct igbvf_adapter *adapter);
+extern void igbvf_reinit_locked(struct igbvf_adapter *adapter);
+extern void igbvf_reset(struct igbvf_adapter *adapter);
+extern int igbvf_setup_rx_resources(struct igbvf_adapter *adapter);
+extern int igbvf_setup_tx_resources(struct igbvf_adapter *adapter);
+extern void igbvf_free_rx_resources(struct igbvf_adapter *adapter);
+extern void igbvf_free_tx_resources(struct igbvf_adapter *adapter);
+extern void igbvf_update_stats(struct igbvf_adapter *adapter);
+extern void igbvf_set_interrupt_capability(struct igbvf_adapter *adapter);
+extern void igbvf_reset_interrupt_capability(struct igbvf_adapter *adapter);
+
+extern unsigned int copybreak;
+
+#endif /* _IGBVF_H_ */
diff --git a/drivers/net/igbvf/mbx.c b/drivers/net/igbvf/mbx.c
new file mode 100644
index 0000000..819a8ec
--- /dev/null
+++ b/drivers/net/igbvf/mbx.c
@@ -0,0 +1,350 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "mbx.h"
+
+/**
+ *  e1000_poll_for_msg - Wait for message notification
+ *  @hw: pointer to the HW structure
+ *
+ *  returns SUCCESS if it successfully received a message notification
+ **/
+static s32 e1000_poll_for_msg(struct e1000_hw *hw)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	int countdown = mbx->timeout;
+
+	if (!mbx->ops.check_for_msg)
+		goto out;
+
+	while (countdown && mbx->ops.check_for_msg(hw)) {
+		countdown--;
+		udelay(mbx->usec_delay);
+	}
+
+	/* if we failed, all future posted messages fail until reset */
+	if (!countdown)
+		mbx->timeout = 0;
+out:
+	return countdown ? E1000_SUCCESS : -E1000_ERR_MBX;
+}
+
+/**
+ *  e1000_poll_for_ack - Wait for message acknowledgement
+ *  @hw: pointer to the HW structure
+ *
+ *  returns SUCCESS if it successfully received a message acknowledgement
+ **/
+static s32 e1000_poll_for_ack(struct e1000_hw *hw)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	int countdown = mbx->timeout;
+
+	if (!mbx->ops.check_for_ack)
+		goto out;
+
+	while (countdown && mbx->ops.check_for_ack(hw)) {
+		countdown--;
+		udelay(mbx->usec_delay);
+	}
+
+	/* if we failed, all future posted messages fail until reset */
+	if (!countdown)
+		mbx->timeout = 0;
+out:
+	return countdown ? E1000_SUCCESS : -E1000_ERR_MBX;
+}
+
+/**
+ *  e1000_read_posted_mbx - Wait for message notification and receive message
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *
+ *  returns SUCCESS if it successfully received a message notification and
+ *  copied it into the receive buffer.
+ **/
+static s32 e1000_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	s32 ret_val = -E1000_ERR_MBX;
+
+	if (!mbx->ops.read)
+		goto out;
+
+	ret_val = e1000_poll_for_msg(hw);
+
+	/* if ack received read message, otherwise we timed out */
+	if (!ret_val)
+		ret_val = mbx->ops.read(hw, msg, size);
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_posted_mbx - Write a message to the mailbox, wait for ack
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer and
+ *  received an ack to that message within delay * timeout period
+ **/
+static s32 e1000_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+	s32 ret_val = -E1000_ERR_MBX;
+
+	/* exit if we either can't write or there isn't a defined timeout */
+	if (!mbx->ops.write || !mbx->timeout)
+		goto out;
+
+	/* send msg*/
+	ret_val = mbx->ops.write(hw, msg, size);
+
+	/* if msg sent wait until we receive an ack */
+	if (!ret_val)
+		ret_val = e1000_poll_for_ack(hw);
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_v2p_mailbox - read v2p mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  This function is used to read the v2p mailbox without losing the read to
+ *  clear status bits.
+ **/
+static u32 e1000_read_v2p_mailbox(struct e1000_hw *hw)
+{
+	u32 v2p_mailbox = er32(V2PMAILBOX(0));
+
+	v2p_mailbox |= hw->dev_spec.vf.v2p_mailbox;
+	hw->dev_spec.vf.v2p_mailbox |= v2p_mailbox & E1000_V2PMAILBOX_R2C_BITS;
+
+	return v2p_mailbox;
+}
+
+/**
+ *  e1000_check_for_bit_vf - Determine if a status bit was set
+ *  @hw: pointer to the HW structure
+ *  @mask: bitmask for bits to be tested and cleared
+ *
+ *  This function is used to check for the read to clear bits within
+ *  the V2P mailbox.
+ **/
+static s32 e1000_check_for_bit_vf(struct e1000_hw *hw, u32 mask)
+{
+	u32 v2p_mailbox = e1000_read_v2p_mailbox(hw);
+	s32 ret_val = -E1000_ERR_MBX;
+
+	if (v2p_mailbox & mask)
+		ret_val = E1000_SUCCESS;
+
+	hw->dev_spec.vf.v2p_mailbox &= ~mask;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_msg_vf - checks to see if the PF has sent mail
+ *  @hw: pointer to the HW structure
+ *
+ *  returns SUCCESS if the PF has set the Status bit or else ERR_MBX
+ **/
+static s32 e1000_check_for_msg_vf(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_MBX;
+
+	if (!e1000_check_for_bit_vf(hw, E1000_V2PMAILBOX_PFSTS)) {
+		ret_val = E1000_SUCCESS;
+		hw->mbx.stats.reqs++;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_ack_vf - checks to see if the PF has ACK'd
+ *  @hw: pointer to the HW structure
+ *
+ *  returns SUCCESS if the PF has set the ACK bit or else ERR_MBX
+ **/
+static s32 e1000_check_for_ack_vf(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_MBX;
+
+	if (!e1000_check_for_bit_vf(hw, E1000_V2PMAILBOX_PFACK)) {
+		ret_val = E1000_SUCCESS;
+		hw->mbx.stats.acks++;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_rst_vf - checks to see if the PF has reset
+ *  @hw: pointer to the HW structure
+ *
+ *  returns true if the PF has set the reset done bit or else false
+ **/
+static s32 e1000_check_for_rst_vf(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_MBX;
+
+	if (!e1000_check_for_bit_vf(hw, (E1000_V2PMAILBOX_RSTD |
+	                                 E1000_V2PMAILBOX_RSTI))) {
+		ret_val = E1000_SUCCESS;
+		hw->mbx.stats.rsts++;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_obtain_mbx_lock_vf - obtain mailbox lock
+ *  @hw: pointer to the HW structure
+ *
+ *  return SUCCESS if we obtained the mailbox lock
+ **/
+static s32 e1000_obtain_mbx_lock_vf(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_MBX;
+
+	/* Take ownership of the buffer */
+	ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_VFU);
+
+	/* reserve mailbox for vf use */
+	if (e1000_read_v2p_mailbox(hw) & E1000_V2PMAILBOX_VFU)
+		ret_val = E1000_SUCCESS;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_write_mbx_vf - Write a message to the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+static s32 e1000_write_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size)
+{
+	s32 err;
+	u16 i;
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	err = e1000_obtain_mbx_lock_vf(hw);
+	if (err)
+		goto out_no_write;
+
+	/* flush any ack or msg as we are going to overwrite mailbox */
+	e1000_check_for_ack_vf(hw);
+	e1000_check_for_msg_vf(hw);
+
+	/* copy the caller specified message to the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		array_ew32(VMBMEM(0), i, msg[i]);
+
+	/* update stats */
+	hw->mbx.stats.msgs_tx++;
+
+	/* Drop VFU and interrupt the PF to tell it a message has been sent */
+	ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_REQ);
+
+out_no_write:
+	return err;
+}
+
+/**
+ *  e1000_read_mbx_vf - Reads a message from the inbox intended for vf
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *
+ *  returns SUCCESS if it successfuly read message from buffer
+ **/
+static s32 e1000_read_mbx_vf(struct e1000_hw *hw, u32 *msg, u16 size)
+{
+	s32 err;
+	u16 i;
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	err = e1000_obtain_mbx_lock_vf(hw);
+	if (err)
+		goto out_no_read;
+
+	/* copy the message from the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		msg[i] = array_er32(VMBMEM(0), i);
+
+	/* Acknowledge receipt and release mailbox, then we're done */
+	ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_ACK);
+
+	/* update stats */
+	hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+	return err;
+}
+
+/**
+ *  e1000_init_mbx_params_vf - set initial values for vf mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the hw->mbx struct to correct values for vf mailbox
+ */
+s32 e1000_init_mbx_params_vf(struct e1000_hw *hw)
+{
+	struct e1000_mbx_info *mbx = &hw->mbx;
+
+	/* start mailbox as timed out and let the reset_hw call set the timeout
+	 * value to being communications */
+	mbx->timeout = 0;
+	mbx->usec_delay = E1000_VF_MBX_INIT_DELAY;
+
+	mbx->size = E1000_VFMAILBOX_SIZE;
+
+	mbx->ops.read = e1000_read_mbx_vf;
+	mbx->ops.write = e1000_write_mbx_vf;
+	mbx->ops.read_posted = e1000_read_posted_mbx;
+	mbx->ops.write_posted = e1000_write_posted_mbx;
+	mbx->ops.check_for_msg = e1000_check_for_msg_vf;
+	mbx->ops.check_for_ack = e1000_check_for_ack_vf;
+	mbx->ops.check_for_rst = e1000_check_for_rst_vf;
+
+	mbx->stats.msgs_tx = 0;
+	mbx->stats.msgs_rx = 0;
+	mbx->stats.reqs = 0;
+	mbx->stats.acks = 0;
+	mbx->stats.rsts = 0;
+
+	return E1000_SUCCESS;
+}
+
diff --git a/drivers/net/igbvf/mbx.h b/drivers/net/igbvf/mbx.h
new file mode 100644
index 0000000..4938609
--- /dev/null
+++ b/drivers/net/igbvf/mbx.h
@@ -0,0 +1,75 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_MBX_H_
+#define _E1000_MBX_H_
+
+#include "vf.h"
+
+#define E1000_V2PMAILBOX_REQ   0x00000001 /* Request for PF Ready bit */
+#define E1000_V2PMAILBOX_ACK   0x00000002 /* Ack PF message received */
+#define E1000_V2PMAILBOX_VFU   0x00000004 /* VF owns the mailbox buffer */
+#define E1000_V2PMAILBOX_PFU   0x00000008 /* PF owns the mailbox buffer */
+#define E1000_V2PMAILBOX_PFSTS 0x00000010 /* PF wrote a message in the MB */
+#define E1000_V2PMAILBOX_PFACK 0x00000020 /* PF ack the previous VF msg */
+#define E1000_V2PMAILBOX_RSTI  0x00000040 /* PF has reset indication */
+#define E1000_V2PMAILBOX_RSTD  0x00000080 /* PF has indicated reset done */
+#define E1000_V2PMAILBOX_R2C_BITS 0x000000B0 /* All read to clear bits */
+
+#define E1000_VFMAILBOX_SIZE   16 /* 16 32 bit words - 64 bytes */
+
+/* If it's a E1000_VF_* msg then it originates in the VF and is sent to the
+ * PF.  The reverse is true if it is E1000_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+#define E1000_VT_MSGTYPE_ACK      0x80000000  /* Messages below or'd with
+                                               * this are the ACK */
+#define E1000_VT_MSGTYPE_NACK     0x40000000  /* Messages below or'd with
+                                               * this are the NACK */
+#define E1000_VT_MSGTYPE_CTS      0x20000000  /* Indicates that VF is still
+                                                 clear to send requests */
+
+/* We have a total wait time of 1s for vf mailbox posted messages */
+#define E1000_VF_MBX_INIT_TIMEOUT 2000 /* retry count for mailbox timeout */
+#define E1000_VF_MBX_INIT_DELAY   500  /* usec delay between retries */
+
+#define E1000_VT_MSGINFO_SHIFT    16
+/* bits 23:16 are used for exra info for certain messages */
+#define E1000_VT_MSGINFO_MASK     (0xFF << E1000_VT_MSGINFO_SHIFT)
+
+#define E1000_VF_RESET            0x01 /* VF requests reset */
+#define E1000_VF_SET_MAC_ADDR     0x02 /* VF requests PF to set MAC addr */
+#define E1000_VF_SET_MULTICAST    0x03 /* VF requests PF to set MC addr */
+#define E1000_VF_SET_VLAN         0x04 /* VF requests PF to set VLAN */
+#define E1000_VF_SET_LPE          0x05 /* VF requests PF to set VMOLR.LPE */
+
+#define E1000_PF_CONTROL_MSG      0x0100 /* PF control message */
+
+void e1000_init_mbx_ops_generic(struct e1000_hw *hw);
+s32 e1000_init_mbx_params_vf(struct e1000_hw *);
+
+#endif /* _E1000_MBX_H_ */
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
new file mode 100644
index 0000000..54457e0
--- /dev/null
+++ b/drivers/net/igbvf/netdev.c
@@ -0,0 +1,2901 @@
+/*******************************************************************************
+
+  Intel(R) 82576 Virtual Function Linux driver
+  Copyright(c) 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/pm_qos_params.h>
+
+#include "igbvf.h"
+
+#define DRV_VERSION "1.0.0-k0"
+char igbvf_driver_name[] = "igbvf";
+const char igbvf_driver_version[] = DRV_VERSION;
+static const char igbvf_driver_string[] =
+				"Intel(R) Virtual Function Network Driver";
+static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
+
+static int igbvf_poll(struct napi_struct *napi, int budget);
+
+static struct igbvf_info igbvf_vf_info = {
+	.mac                    = e1000_vfadapt,
+	.flags                  = FLAG_HAS_JUMBO_FRAMES
+	                          | FLAG_RX_CSUM_ENABLED,
+	.pba                    = 10,
+	.init_ops               = e1000_init_function_pointers_vf,
+};
+
+static const struct igbvf_info *igbvf_info_tbl[] = {
+	[board_vf]              = &igbvf_vf_info,
+};
+
+/**
+ * igbvf_desc_unused - calculate if we have unused descriptors
+ **/
+static int igbvf_desc_unused(struct igbvf_ring *ring)
+{
+	if (ring->next_to_clean > ring->next_to_use)
+		return ring->next_to_clean - ring->next_to_use - 1;
+
+	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+}
+
+/**
+ * igbvf_receive_skb - helper function to handle Rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ **/
+static void igbvf_receive_skb(struct igbvf_adapter *adapter,
+                              struct net_device *netdev,
+                              struct sk_buff *skb,
+                              u32 status, u16 vlan)
+{
+	if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
+		vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+		                         le16_to_cpu(vlan) &
+		                         E1000_RXD_SPC_VLAN_MASK);
+	else
+		netif_receive_skb(skb);
+
+	netdev->last_rx = jiffies;
+}
+
+static inline void igbvf_rx_checksum_adv(struct igbvf_adapter *adapter,
+                                         u32 status_err, struct sk_buff *skb)
+{
+	skb->ip_summed = CHECKSUM_NONE;
+
+	/* Ignore Checksum bit is set or checksum is disabled through ethtool */
+	if ((status_err & E1000_RXD_STAT_IXSM))
+		return;
+	/* TCP/UDP checksum error bit is set */
+	if (status_err &
+	    (E1000_RXDEXT_STATERR_TCPE | E1000_RXDEXT_STATERR_IPE)) {
+		/* let the stack verify checksum errors */
+		adapter->hw_csum_err++;
+		return;
+	}
+	/* It must be a TCP or UDP packet with a valid checksum */
+	if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	adapter->hw_csum_good++;
+}
+
+/**
+ * igbvf_alloc_rx_buffers - Replace used receive buffers; packet split
+ * @rx_ring: address of ring structure to repopulate
+ * @cleaned_count: number of buffers to repopulate
+ **/
+static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
+                                   int cleaned_count)
+{
+	struct igbvf_adapter *adapter = rx_ring->adapter;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	union e1000_adv_rx_desc *rx_desc;
+	struct igbvf_buffer *buffer_info;
+	struct sk_buff *skb;
+	unsigned int i;
+	int bufsz;
+
+	i = rx_ring->next_to_use;
+	buffer_info = &rx_ring->buffer_info[i];
+
+	if (adapter->rx_ps_hdr_size)
+		bufsz = adapter->rx_ps_hdr_size;
+	else
+		bufsz = adapter->rx_buffer_len;
+	bufsz += NET_IP_ALIGN;
+
+	while (cleaned_count--) {
+		rx_desc = IGBVF_RX_DESC_ADV(*rx_ring, i);
+
+		if (adapter->rx_ps_hdr_size && !buffer_info->page_dma) {
+			if (!buffer_info->page) {
+				buffer_info->page = alloc_page(GFP_ATOMIC);
+				if (!buffer_info->page) {
+					adapter->alloc_rx_buff_failed++;
+					goto no_buffers;
+				}
+				buffer_info->page_offset = 0;
+			} else {
+				buffer_info->page_offset ^= PAGE_SIZE / 2;
+			}
+			buffer_info->page_dma =
+				pci_map_page(pdev, buffer_info->page,
+				             buffer_info->page_offset,
+				             PAGE_SIZE / 2,
+				             PCI_DMA_FROMDEVICE);
+		}
+
+		if (!buffer_info->skb) {
+			skb = netdev_alloc_skb(netdev, bufsz);
+			if (!skb) {
+				adapter->alloc_rx_buff_failed++;
+				goto no_buffers;
+			}
+
+			/* Make buffer alignment 2 beyond a 16 byte boundary
+			 * this will result in a 16 byte aligned IP header after
+			 * the 14 byte MAC header is removed
+			 */
+			skb_reserve(skb, NET_IP_ALIGN);
+
+			buffer_info->skb = skb;
+			buffer_info->dma = pci_map_single(pdev, skb->data,
+			                                  bufsz,
+			                                  PCI_DMA_FROMDEVICE);
+		}
+		/* Refresh the desc even if buffer_addrs didn't change because
+		 * each write-back erases this info. */
+		if (adapter->rx_ps_hdr_size) {
+			rx_desc->read.pkt_addr =
+			     cpu_to_le64(buffer_info->page_dma);
+			rx_desc->read.hdr_addr = cpu_to_le64(buffer_info->dma);
+		} else {
+			rx_desc->read.pkt_addr =
+			     cpu_to_le64(buffer_info->dma);
+			rx_desc->read.hdr_addr = 0;
+		}
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		buffer_info = &rx_ring->buffer_info[i];
+	}
+
+no_buffers:
+	if (rx_ring->next_to_use != i) {
+		rx_ring->next_to_use = i;
+		if (i == 0)
+			i = (rx_ring->count - 1);
+		else
+			i--;
+
+		/* Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64). */
+		wmb();
+		writel(i, adapter->hw.hw_addr + rx_ring->tail);
+	}
+}
+
+/**
+ * igbvf_clean_rx_irq - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+static bool igbvf_clean_rx_irq(struct igbvf_adapter *adapter,
+                               int *work_done, int work_to_do)
+{
+	struct igbvf_ring *rx_ring = adapter->rx_ring;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	union e1000_adv_rx_desc *rx_desc, *next_rxd;
+	struct igbvf_buffer *buffer_info, *next_buffer;
+	struct sk_buff *skb;
+	bool cleaned = false;
+	int cleaned_count = 0;
+	unsigned int total_bytes = 0, total_packets = 0;
+	unsigned int i;
+	u32 length, hlen, staterr;
+
+	i = rx_ring->next_to_clean;
+	rx_desc = IGBVF_RX_DESC_ADV(*rx_ring, i);
+	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+
+	while (staterr & E1000_RXD_STAT_DD) {
+		if (*work_done >= work_to_do)
+			break;
+		(*work_done)++;
+
+		buffer_info = &rx_ring->buffer_info[i];
+
+		/* HW will not DMA in data larger than the given buffer, even
+		 * if it parses the (NFS, of course) header to be larger.  In
+		 * that case, it fills the header buffer and spills the rest
+		 * into the page.
+		 */
+		hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.hdr_info) &
+		  E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
+		if (hlen > adapter->rx_ps_hdr_size)
+			hlen = adapter->rx_ps_hdr_size;
+
+		length = le16_to_cpu(rx_desc->wb.upper.length);
+		cleaned = true;
+		cleaned_count++;
+
+		skb = buffer_info->skb;
+		prefetch(skb->data - NET_IP_ALIGN);
+		buffer_info->skb = NULL;
+		if (!adapter->rx_ps_hdr_size) {
+			pci_unmap_single(pdev, buffer_info->dma,
+			                 adapter->rx_buffer_len,
+			                 PCI_DMA_FROMDEVICE);
+			buffer_info->dma = 0;
+			skb_put(skb, length);
+			goto send_up;
+		}
+
+		if (!skb_shinfo(skb)->nr_frags) {
+			pci_unmap_single(pdev, buffer_info->dma,
+			                 adapter->rx_ps_hdr_size + NET_IP_ALIGN,
+			                 PCI_DMA_FROMDEVICE);
+			skb_put(skb, hlen);
+		}
+
+		if (length) {
+			pci_unmap_page(pdev, buffer_info->page_dma,
+			               PAGE_SIZE / 2,
+			               PCI_DMA_FROMDEVICE);
+			buffer_info->page_dma = 0;
+
+			skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags++,
+			                   buffer_info->page,
+			                   buffer_info->page_offset,
+			                   length);
+
+			if ((adapter->rx_buffer_len > (PAGE_SIZE / 2)) ||
+			    (page_count(buffer_info->page) != 1))
+				buffer_info->page = NULL;
+			else
+				get_page(buffer_info->page);
+
+			skb->len += length;
+			skb->data_len += length;
+			skb->truesize += length;
+		}
+send_up:
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		next_rxd = IGBVF_RX_DESC_ADV(*rx_ring, i);
+		prefetch(next_rxd);
+		next_buffer = &rx_ring->buffer_info[i];
+
+		if (!(staterr & E1000_RXD_STAT_EOP)) {
+			buffer_info->skb = next_buffer->skb;
+			buffer_info->dma = next_buffer->dma;
+			next_buffer->skb = skb;
+			next_buffer->dma = 0;
+			goto next_desc;
+		}
+
+		if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
+			dev_kfree_skb_irq(skb);
+			goto next_desc;
+		}
+
+		total_bytes += skb->len;
+		total_packets++;
+
+		igbvf_rx_checksum_adv(adapter, staterr, skb);
+
+		skb->protocol = eth_type_trans(skb, netdev);
+
+		igbvf_receive_skb(adapter, netdev, skb, staterr,
+		                  rx_desc->wb.upper.vlan);
+
+		netdev->last_rx = jiffies;
+
+next_desc:
+		rx_desc->wb.upper.status_error = 0;
+
+		/* return some buffers to hardware, one at a time is too slow */
+		if (cleaned_count >= IGBVF_RX_BUFFER_WRITE) {
+			igbvf_alloc_rx_buffers(rx_ring, cleaned_count);
+			cleaned_count = 0;
+		}
+
+		/* use prefetched values */
+		rx_desc = next_rxd;
+		buffer_info = next_buffer;
+
+		staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+	}
+
+	rx_ring->next_to_clean = i;
+	cleaned_count = igbvf_desc_unused(rx_ring);
+
+	if (cleaned_count)
+		igbvf_alloc_rx_buffers(rx_ring, cleaned_count);
+
+	adapter->total_rx_packets += total_packets;
+	adapter->total_rx_bytes += total_bytes;
+	adapter->net_stats.rx_bytes += total_bytes;
+	adapter->net_stats.rx_packets += total_packets;
+	return cleaned;
+}
+
+static void igbvf_put_txbuf(struct igbvf_adapter *adapter,
+                            struct igbvf_buffer *buffer_info)
+{
+	if (buffer_info->dma) {
+		pci_unmap_page(adapter->pdev, buffer_info->dma,
+		               buffer_info->length, PCI_DMA_TODEVICE);
+		buffer_info->dma = 0;
+	}
+	if (buffer_info->skb) {
+		dev_kfree_skb_any(buffer_info->skb);
+		buffer_info->skb = NULL;
+	}
+	buffer_info->time_stamp = 0;
+}
+
+static void igbvf_print_tx_hang(struct igbvf_adapter *adapter)
+{
+	struct igbvf_ring *tx_ring = adapter->tx_ring;
+	unsigned int i = tx_ring->next_to_clean;
+	unsigned int eop = tx_ring->buffer_info[i].next_to_watch;
+	union e1000_adv_tx_desc *eop_desc = IGBVF_TX_DESC_ADV(*tx_ring, eop);
+
+	/* detected Tx unit hang */
+	dev_err(&adapter->pdev->dev,
+	        "Detected Tx Unit Hang:\n"
+	        "  TDH                  <%x>\n"
+	        "  TDT                  <%x>\n"
+	        "  next_to_use          <%x>\n"
+	        "  next_to_clean        <%x>\n"
+	        "buffer_info[next_to_clean]:\n"
+	        "  time_stamp           <%lx>\n"
+	        "  next_to_watch        <%x>\n"
+	        "  jiffies              <%lx>\n"
+	        "  next_to_watch.status <%x>\n",
+	        readl(adapter->hw.hw_addr + tx_ring->head),
+	        readl(adapter->hw.hw_addr + tx_ring->tail),
+	        tx_ring->next_to_use,
+	        tx_ring->next_to_clean,
+	        tx_ring->buffer_info[eop].time_stamp,
+	        eop,
+	        jiffies,
+	        eop_desc->wb.status);
+}
+
+/**
+ * igbvf_alloc_ring_dma - allocate memory for a ring structure
+ **/
+static int igbvf_alloc_ring_dma(struct igbvf_adapter *adapter,
+                                struct igbvf_ring *ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	ring->desc = dma_alloc_coherent(&pdev->dev, (ring->size + sizeof(u32)), &ring->dma,
+	                                GFP_KERNEL);
+	if (!ring->desc)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * igbvf_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+int igbvf_setup_tx_resources(struct igbvf_adapter *adapter)
+{
+	struct igbvf_ring *tx_ring = adapter->tx_ring;
+	int err = -ENOMEM, size;
+
+	size = sizeof(struct igbvf_buffer) * tx_ring->count;
+	tx_ring->buffer_info = vmalloc(size);
+	if (!tx_ring->buffer_info)
+		goto err;
+	memset(tx_ring->buffer_info, 0, size);
+
+	/* round up to nearest 4K */
+	tx_ring->size = tx_ring->count * sizeof(union e1000_adv_tx_desc);
+	tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+	err = igbvf_alloc_ring_dma(adapter, tx_ring);
+	if (err)
+		goto err;
+
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+	spin_lock_init(&adapter->tx_queue_lock);
+
+	return 0;
+err:
+	vfree(tx_ring->buffer_info);
+	dev_err(&adapter->pdev->dev,
+	        "Unable to allocate memory for the transmit descriptor ring\n");
+	return err;
+}
+
+/**
+ * igbvf_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int igbvf_setup_r
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[net-next PATCH 1/2] igbvf: add new driver to support 8257 ..., Jeff Kirsher, (Tue Mar 10, 7:09 pm)