WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [SR-IOV driver example 1/3] PF driver: allocate hardware spe

This patch makes the IGB driver allocate hardware resource (rx/tx queues)
for Virtual Functions. All operations in this patch are hardware specific.

---
 drivers/net/igb/Makefile        |    2 +-
 drivers/net/igb/e1000_82575.c   |    1 +
 drivers/net/igb/e1000_82575.h   |   61 ++++
 drivers/net/igb/e1000_defines.h |    7 +
 drivers/net/igb/e1000_hw.h      |    2 +
 drivers/net/igb/e1000_regs.h    |   13 +
 drivers/net/igb/e1000_vf.c      |  223 ++++++++++++++
 drivers/net/igb/igb.h           |   10 +
 drivers/net/igb/igb_main.c      |  604 ++++++++++++++++++++++++++++++++++++++-
 9 files changed, 910 insertions(+), 13 deletions(-)
 create mode 100644 drivers/net/igb/e1000_vf.c

diff --git a/drivers/net/igb/Makefile b/drivers/net/igb/Makefile
index 1927b3f..ab3944c 100644
--- a/drivers/net/igb/Makefile
+++ b/drivers/net/igb/Makefile
@@ -33,5 +33,5 @@
 obj-$(CONFIG_IGB) += igb.o
 
 igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
-           e1000_mac.o e1000_nvm.o e1000_phy.o
+           e1000_mac.o e1000_nvm.o e1000_phy.o e1000_vf.o
 
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index f5e2e72..bb823ac 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -87,6 +87,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
        case E1000_DEV_ID_82576:
        case E1000_DEV_ID_82576_FIBER:
        case E1000_DEV_ID_82576_SERDES:
+       case E1000_DEV_ID_82576_QUAD_COPPER:
                mac->type = e1000_82576;
                break;
        default:
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
index c1928b5..8c488ab 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/igb/e1000_82575.h
@@ -170,4 +170,65 @@ struct e1000_adv_tx_context_desc {
 #define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */
 #define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */
 
+#define MAX_NUM_VFS                   8
+
+#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31)  /* global VF LB enable */
+
+/* Easy defines for setting default pool, would normally be left a zero */
+#define E1000_VT_CTL_DEFAULT_POOL_SHIFT 7
+#define E1000_VT_CTL_DEFAULT_POOL_MASK  (0x7 << 
E1000_VT_CTL_DEFAULT_POOL_SHIFT)
+
+/* Other useful VMD_CTL register defines */
+#define E1000_VT_CTL_DISABLE_DEF_POOL   (1 << 29)
+#define E1000_VT_CTL_VM_REPL_EN         (1 << 30)
+
+/* Per VM Offload register setup */
+#define E1000_VMOLR_LPE        0x00010000 /* Accept Long packet */
+#define E1000_VMOLR_AUPE       0x01000000 /* Accept untagged packets */
+#define E1000_VMOLR_BAM        0x08000000 /* Accept Broadcast packets */
+#define E1000_VMOLR_MPME       0x10000000 /* Multicast promiscuous mode */
+#define E1000_VMOLR_STRVLAN    0x40000000 /* Vlan stripping enable */
+
+#define E1000_P2VMAILBOX_STS   0x00000001 /* Initiate message send to VF */
+#define E1000_P2VMAILBOX_ACK   0x00000002 /* Ack message recv'd from VF */
+#define E1000_P2VMAILBOX_VFU   0x00000004 /* VF owns the mailbox buffer */
+#define E1000_P2VMAILBOX_PFU   0x00000008 /* PF owns the mailbox buffer */
+
+#define E1000_VLVF_ARRAY_SIZE     32
+#define E1000_VLVF_VLANID_MASK    0x00000FFF
+#define E1000_VLVF_POOLSEL_SHIFT  12
+#define E1000_VLVF_POOLSEL_MASK   (0xFF << E1000_VLVF_POOLSEL_SHIFT)
+#define E1000_VLVF_VLANID_ENABLE  0x80000000
+
+#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      0xF0000000  /* Messages below or'd with
+                                               * this are the ACK */
+#define E1000_VT_MSGTYPE_NACK     0xFF000000  /* Messages below or'd with
+                                               * this are the NACK */
+#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_MSGTYPE_REQ_MAC  1 /* VF needs to know its MAC */
+#define E1000_VF_MSGTYPE_VFLR     2 /* VF notifies VFLR to PF */
+#define E1000_VF_SET_MULTICAST    3 /* VF requests PF to set MC addr */
+#define E1000_VF_SET_VLAN         4 /* VF requests PF to set VLAN */
+#define E1000_VF_SET_LPE          5 /* VF requests PF to set VMOLR.LPE */
+
+s32  e1000_send_mail_to_vf(struct e1000_hw *hw, u32 *msg,
+                           u32 vf_number, s16 size);
+s32  e1000_receive_mail_from_vf(struct e1000_hw *hw, u32 *msg,
+                                u32 vf_number, s16 size);
+void e1000_vmdq_loopback_enable_vf(struct e1000_hw *hw);
+void e1000_vmdq_loopback_disable_vf(struct e1000_hw *hw);
+void e1000_vmdq_replication_enable_vf(struct e1000_hw *hw, u32 enables);
+void e1000_vmdq_replication_disable_vf(struct e1000_hw *hw);
+bool e1000_check_for_pf_ack_vf(struct e1000_hw *hw);
+bool e1000_check_for_pf_mail_vf(struct e1000_hw *hw, u32*);
+
 #endif
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index ce70068..08f9db0 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -389,6 +389,7 @@
 #define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
 #define E1000_ICR_RXO           0x00000040 /* rx overrun */
 #define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
 #define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
 #define E1000_ICR_RXCFG         0x00000400 /* Rx /c/ ordered set */
 #define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
@@ -451,6 +452,7 @@
 /* Interrupt Mask Set */
 #define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back 
*/
 #define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_VMMB      E1000_ICR_VMMB      /* Mail box activity */
 #define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
 #define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
 #define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
@@ -768,4 +770,9 @@
 #define E1000_GEN_CTL_ADDRESS_SHIFT     8
 #define E1000_GEN_POLL_TIMEOUT          640
 
+#define E1000_WRITE_FLUSH(a)   (readl((a)->hw_addr + E1000_STATUS))
+#define E1000_MRQC_ENABLE_MASK 0x00000007
+#define E1000_MRQC_ENABLE_VMDQ 0x00000003
+#define E1000_CTRL_EXT_PFRSTD  0x00004000
+
 #endif
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index 99504a6..b57ecfd 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -41,6 +41,7 @@ struct e1000_hw;
 #define E1000_DEV_ID_82576                    0x10C9
 #define E1000_DEV_ID_82576_FIBER              0x10E6
 #define E1000_DEV_ID_82576_SERDES             0x10E7
+#define E1000_DEV_ID_82576_QUAD_COPPER        0x10E8
 #define E1000_DEV_ID_82575EB_COPPER           0x10A7
 #define E1000_DEV_ID_82575EB_FIBER_SERDES     0x10A9
 #define E1000_DEV_ID_82575GB_QUAD_COPPER      0x10D6
@@ -91,6 +92,7 @@ enum e1000_phy_type {
        e1000_phy_gg82563,
        e1000_phy_igp_3,
        e1000_phy_ife,
+       e1000_phy_vf,
 };
 
 enum e1000_bus_type {
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index 95523af..8a39bbc 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -262,6 +262,19 @@
 #define E1000_RETA(_i)  (0x05C00 + ((_i) * 4))
 #define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */
 
+/* VT Registers */
+#define E1000_MBVFICR   0x00C80 /* Mailbox VF Cause - RWC */
+#define E1000_MBVFIMR   0x00C84 /* Mailbox VF int Mask - RW */
+#define E1000_VFLRE     0x00C88 /* VF Register Events - RWC */
+#define E1000_VFRE      0x00C8C /* VF Receive Enables */
+#define E1000_VFTE      0x00C90 /* VF Transmit Enables */
+#define E1000_DTXSWC    0x03500 /* DMA Tx Switch Control - RW */
+/* These act per VF so an array friendly macro is used */
+#define E1000_P2VMAILBOX(_n)   (0x00C00 + (4 * (_n)))
+#define E1000_VMBMEM(_n)       (0x00800 + (64 * (_n)))
+#define E1000_VMOLR(_n)        (0x05AD0 + (4 * (_n)))
+#define E1000_VLVF(_n)         (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine 
*/
+
 #define wr32(reg, value) (writel(value, hw->hw_addr + reg))
 #define rd32(reg) (readl(hw->hw_addr + reg))
 #define wrfl() ((void)rd32(E1000_STATUS))
diff --git a/drivers/net/igb/e1000_vf.c b/drivers/net/igb/e1000_vf.c
new file mode 100644
index 0000000..9e4e566
--- /dev/null
+++ b/drivers/net/igb/e1000_vf.c
@@ -0,0 +1,223 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2008 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@xxxxxxxxxxxxxxxxxxxxx>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+#include <linux/if_ether.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include "igb.h"
+
+/**
+ *  e1000_send_mail_to_vf - Sends a mailbox message from PF to VF
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @vf_number: the VF index
+ *  @size: Length of buffer
+ **/
+s32 e1000_send_mail_to_vf(struct e1000_hw *hw, u32 *msg, u32 vf_number,
+                          s16 size)
+{
+       u32 p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
+       s32 ret_val = 0;
+       s16 i;
+
+       /*
+        * if the VF owns the mailbox then we can't grab the mailbox buffer
+        * - mostly an indication of a programming error
+        */
+       if (p2v_mailbox & E1000_P2VMAILBOX_VFU) {
+               ret_val = -1;
+               goto out_no_write;
+       } else {
+               /* Take ownership of the buffer */
+               p2v_mailbox |= E1000_P2VMAILBOX_PFU;
+               wr32(E1000_P2VMAILBOX(vf_number), p2v_mailbox);
+               p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
+               /* Make sure we have ownership now... */
+               if (p2v_mailbox & E1000_P2VMAILBOX_VFU) {
+                       /*
+                        * oops, VF grabbed ownership while we were attempting
+                        * to take ownership - avoid the race condition
+                        */
+                       ret_val = -2;
+                       goto out_no_write;
+               }
+       }
+
+       /*
+        * At this point we have established ownership of the PF mailbox memory
+        * buffer.  IT IS IMPORTANT THAT THIS OWNERSHIP BE GIVEN UP!  Whether
+        * success or failure, the PF ownership bit must be cleared before
+        * exiting this function - so if you change this function keep that
+        * in mind
+        */
+
+       /* Clear PF ownership of the mail box memory buffer */
+       /*
+        * Do this whether success or failure on the wait for ack from
+        * the PF
+        */
+       p2v_mailbox &= ~(E1000_P2VMAILBOX_PFU);
+
+       /* check for overflow */
+       if (size > E1000_VFMAILBOX_SIZE) {
+               ret_val = -3;
+               goto out;
+       }
+
+       /*
+        * copy the caller specified message to the mailbox
+        * memory buffer
+        */
+       for (i = 0; i < size; i++)
+               wr32(((E1000_VMBMEM(vf_number)) + (i * 4)), msg[i]);
+
+       /* Interrupt the VF to tell it a message has been sent */
+       p2v_mailbox |= E1000_P2VMAILBOX_STS;
+
+out:
+       wr32(E1000_P2VMAILBOX(vf_number), p2v_mailbox);
+
+out_no_write:
+       return ret_val;
+
+}
+
+/**
+ *  e1000_receive_mail_from_vf - Receives a mailbox message from VF to PF
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @vf_number: the VF index
+ *  @size: Length of buffer
+ **/
+s32 e1000_receive_mail_from_vf(struct e1000_hw *hw,
+                               u32 *msg, u32 vf_number, s16 size)
+{
+       u32 p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
+       s16 i;
+
+       /*
+        * Should we be checking if the VF has set the ownership bit?
+        * I don't know... presumably well written software will set the
+        * VF mailbox memory ownership bit but I can't think of a reason
+        * to call it an error if it doesn't... I'll think 'pon it some more
+        */
+
+       /*
+        * No message ready polling mechanism - the presumption is that
+        * the caller knows there is a message because of the interrupt
+        * ack
+        */
+
+       /*
+        * copy the caller specified message to the mailbox
+        * memory buffer
+        */
+       for (i = 0; i < size; i++)
+               msg[i] = rd32(((E1000_VMBMEM(vf_number)) + (i * 4)));
+
+       /*
+        * Acknowledge receipt of the message to the VF and then
+        * we're done
+        */
+       p2v_mailbox |= E1000_P2VMAILBOX_ACK;        /* Set PF Ack bit */
+       wr32(E1000_P2VMAILBOX(vf_number), p2v_mailbox);
+
+       return 0;       /* Success is the only option  */
+}
+
+/**
+ *  e1000_vmdq_loopback_enable_vf - Enables VM to VM queue loopback replication
+ *  @hw: pointer to the HW structure
+ **/
+void e1000_vmdq_loopback_enable_vf(struct e1000_hw *hw)
+{
+       u32 reg;
+
+       reg = rd32(E1000_DTXSWC);
+       reg |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+       wr32(E1000_DTXSWC, reg);
+}
+
+/**
+ *  e1000_vmdq_loopback_disable_vf - Disable VM to VM queue loopbk replication
+ *  @hw: pointer to the HW structure
+ **/
+void e1000_vmdq_loopback_disable_vf(struct e1000_hw *hw)
+{
+       u32 reg;
+
+       reg = rd32(E1000_DTXSWC);
+       reg &= ~(E1000_DTXSWC_VMDQ_LOOPBACK_EN);
+       wr32(E1000_DTXSWC, reg);
+}
+
+/**
+ *  e1000_vmdq_replication_enable_vf - Enable replication of brdcst & multicst
+ *  @hw: pointer to the HW structure
+ *
+ *  Enables replication of broadcast and multicast packets from the network
+ *  to VM's which have their respective broadcast and multicast accept
+ *  bits set in the VM Offload Register.  This gives the PF driver per
+ *  VM granularity control over which VM's get replicated broadcast traffic.
+ **/
+void e1000_vmdq_replication_enable_vf(struct e1000_hw *hw, u32 enables)
+{
+       u32 reg;
+       u32 i;
+
+       for (i = 0; i < MAX_NUM_VFS; i++) {
+               if (enables & (1 << i)) {
+                       reg = rd32(E1000_VMOLR(i));
+                       reg |= (E1000_VMOLR_AUPE |
+                               E1000_VMOLR_BAM |
+                               E1000_VMOLR_MPME);
+                       wr32(E1000_VMOLR(i), reg);
+               }
+       }
+
+       reg = rd32(E1000_VMD_CTL);
+       reg |= E1000_VT_CTL_VM_REPL_EN;
+       wr32(E1000_VMD_CTL, reg);
+}
+
+/**
+ *  e1000_vmdq_replication_disable_vf - Disable replication of brdcst & 
multicst
+ *  @hw: pointer to the HW structure
+ *
+ *  Disables replication of broadcast and multicast packets to the VM's.
+ **/
+void e1000_vmdq_replication_disable_vf(struct e1000_hw *hw)
+{
+       u32 reg;
+
+       reg = rd32(E1000_VMD_CTL);
+       reg &= ~(E1000_VT_CTL_VM_REPL_EN);
+       wr32(E1000_VMD_CTL, reg);
+}
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index 4ff6f05..81dfd66 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -294,6 +294,16 @@ struct igb_adapter {
        unsigned int lro_flushed;
        unsigned int lro_no_desc;
 #endif
+#ifdef CONFIG_PCI_IOV
+       unsigned int vfs_allocated_count;
+       struct work_struct msg_task;
+       u32 vf_icr;
+       u32 vflre;
+       unsigned char vf_mac_addresses[8][6];
+       u8 vfta_tracking_entry[128];
+       int int0counter;
+       int int1counter;
+#endif
 };
 
 #define IGB_FLAG_HAS_MSI           (1 << 0)
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 1cbae85..bc063d4 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -62,6 +62,7 @@ static struct pci_device_id igb_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 },
@@ -126,6 +127,19 @@ static void igb_vlan_rx_register(struct net_device *, 
struct vlan_group *);
 static void igb_vlan_rx_add_vid(struct net_device *, u16);
 static void igb_vlan_rx_kill_vid(struct net_device *, u16);
 static void igb_restore_vlan(struct igb_adapter *);
+#ifdef CONFIG_PCI_IOV
+static void igb_msg_task(struct work_struct *);
+int igb_send_msg_to_vf(struct igb_adapter *, u32 *, u32);
+static int igb_get_vf_msg_ack(struct igb_adapter *, u32);
+static int igb_rcv_msg_from_vf(struct igb_adapter *, u32);
+static int igb_set_pf_mac(struct net_device *, int, u8*);
+static void igb_enable_pf_queues(struct igb_adapter *adapter);
+static void igb_set_vf_vmolr(struct igb_adapter *adapter, int vfn);
+void igb_set_mc_list_pools(struct igb_adapter *, struct e1000_hw *, int, u16);
+static int igb_vmm_control(struct igb_adapter *, bool);
+static int igb_set_vf_mac(struct net_device *, int, u8*);
+static void igb_mbox_handler(struct igb_adapter *);
+#endif
 
 static int igb_suspend(struct pci_dev *, pm_message_t);
 #ifdef CONFIG_PM
@@ -169,7 +183,7 @@ static struct pci_driver igb_driver = {
        .resume   = igb_resume,
 #endif
        .shutdown = igb_shutdown,
-       .err_handler = &igb_err_handler
+       .err_handler = &igb_err_handler,
 };
 
 static int global_quad_port_a; /* global quad port a indication */
@@ -292,6 +306,11 @@ static void igb_assign_vector(struct igb_adapter *adapter, 
int rx_queue,
        u32 msixbm = 0;
        struct e1000_hw *hw = &adapter->hw;
        u32 ivar, index;
+#ifdef CONFIG_PCI_IOV
+       u32 rbase_offset = adapter->vfs_allocated_count;
+#else
+       u32 rbase_offset = 0;
+#endif
 
        switch (hw->mac.type) {
        case e1000_82575:
@@ -316,9 +335,9 @@ static void igb_assign_vector(struct igb_adapter *adapter, 
int rx_queue,
                   a vector number along with a "valid" bit.  Sadly, the layout
                   of the table is somewhat counterintuitive. */
                if (rx_queue > IGB_N0_QUEUE) {
-                       index = (rx_queue & 0x7);
+                       index = ((rx_queue + rbase_offset) & 0x7);
                        ivar = array_rd32(E1000_IVAR0, index);
-                       if (rx_queue < 8) {
+                       if ((rx_queue + rbase_offset) < 8) {
                                /* vector goes into low byte of register */
                                ivar = ivar & 0xFFFFFF00;
                                ivar |= msix_vector | E1000_IVAR_VALID;
@@ -331,9 +350,9 @@ static void igb_assign_vector(struct igb_adapter *adapter, 
int rx_queue,
                        array_wr32(E1000_IVAR0, index, ivar);
                }
                if (tx_queue > IGB_N0_QUEUE) {
-                       index = (tx_queue & 0x7);
+                       index = ((tx_queue + rbase_offset) & 0x7);
                        ivar = array_rd32(E1000_IVAR0, index);
-                       if (tx_queue < 8) {
+                       if ((tx_queue + rbase_offset) < 8) {
                                /* vector goes into second byte of register */
                                ivar = ivar & 0xFFFF00FF;
                                ivar |= (msix_vector | E1000_IVAR_VALID) << 8;
@@ -419,6 +438,10 @@ static void igb_configure_msix(struct igb_adapter *adapter)
        case e1000_82576:
                tmp = (vector++ | E1000_IVAR_VALID) << 8;
                wr32(E1000_IVAR_MISC, tmp);
+#ifdef CONFIG_PCI_IOV
+               if (adapter->vfs_allocated_count > 0)
+                       wr32(E1000_MBVFIMR, 0xFF);
+#endif
 
                adapter->eims_enable_mask = (1 << (vector)) - 1;
                adapter->eims_other = 1 << (vector - 1);
@@ -440,6 +463,11 @@ static int igb_request_msix(struct igb_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        int i, err = 0, vector = 0;
+#ifdef CONFIG_PCI_IOV
+       u32 rbase_offset = adapter->vfs_allocated_count;
+#else
+       u32 rbase_offset = 0;
+#endif
 
        vector = 0;
 
@@ -451,7 +479,7 @@ static int igb_request_msix(struct igb_adapter *adapter)
                                  &(adapter->tx_ring[i]));
                if (err)
                        goto out;
-               ring->itr_register = E1000_EITR(0) + (vector << 2);
+               ring->itr_register = E1000_EITR(0 + rbase_offset) + (vector << 
2);
                ring->itr_val = 976; /* ~4000 ints/sec */
                vector++;
        }
@@ -466,7 +494,7 @@ static int igb_request_msix(struct igb_adapter *adapter)
                                  &(adapter->rx_ring[i]));
                if (err)
                        goto out;
-               ring->itr_register = E1000_EITR(0) + (vector << 2);
+               ring->itr_register = E1000_EITR(0 + rbase_offset) + (vector << 
2);
                ring->itr_val = adapter->itr;
                /* overwrite the poll routine for MSIX, we've already done
                 * netif_napi_add */
@@ -649,7 +677,11 @@ static void igb_irq_enable(struct igb_adapter *adapter)
                wr32(E1000_EIAC, adapter->eims_enable_mask);
                wr32(E1000_EIAM, adapter->eims_enable_mask);
                wr32(E1000_EIMS, adapter->eims_enable_mask);
+#ifdef CONFIG_PCI_IOV
+               wr32(E1000_IMS, (E1000_IMS_LSC | E1000_IMS_VMMB));
+#else
                wr32(E1000_IMS, E1000_IMS_LSC);
+#endif
        } else {
                wr32(E1000_IMS, IMS_ENABLE_MASK);
                wr32(E1000_IAM, IMS_ENABLE_MASK);
@@ -773,6 +805,16 @@ int igb_up(struct igb_adapter *adapter)
        if (adapter->msix_entries)
                igb_configure_msix(adapter);
 
+#ifdef CONFIG_PCI_IOV
+       if (adapter->vfs_allocated_count > 0) {
+               igb_vmm_control(adapter, true);
+               igb_set_pf_mac(adapter->netdev,
+                              adapter->vfs_allocated_count,
+                              hw->mac.addr);
+               igb_enable_pf_queues(adapter);
+       }
+#endif
+
        /* Clear any pending interrupts. */
        rd32(E1000_ICR);
        igb_irq_enable(adapter);
@@ -1189,6 +1231,9 @@ static int __devinit igb_probe(struct pci_dev *pdev,
 
        INIT_WORK(&adapter->reset_task, igb_reset_task);
        INIT_WORK(&adapter->watchdog_task, igb_watchdog_task);
+#ifdef CONFIG_PCI_IOV
+       INIT_WORK(&adapter->msg_task, igb_msg_task);
+#endif
 
        /* Initialize link & ring properties that are user-changeable */
        adapter->tx_ring->count = 256;
@@ -1404,8 +1449,13 @@ static int __devinit igb_sw_init(struct igb_adapter 
*adapter)
 
        /* Number of supported queues. */
        /* Having more queues than CPUs doesn't make sense. */
+#ifdef CONFIG_PCI_IOV
+       adapter->num_rx_queues = 1;
+       adapter->num_tx_queues = 1;
+#else
        adapter->num_rx_queues = min((u32)IGB_MAX_RX_QUEUES, 
(u32)num_online_cpus());
        adapter->num_tx_queues = min(IGB_MAX_TX_QUEUES, num_online_cpus());
+#endif
 
        /* This call may decrease the number of queues depending on
         * interrupt mode. */
@@ -1469,6 +1519,16 @@ static int igb_open(struct net_device *netdev)
         * clean_rx handler before we do so.  */
        igb_configure(adapter);
 
+#ifdef CONFIG_PCI_IOV
+       if (adapter->vfs_allocated_count > 0) {
+               igb_vmm_control(adapter, true);
+               igb_set_pf_mac(netdev,
+                              adapter->vfs_allocated_count,
+                              hw->mac.addr);
+               igb_enable_pf_queues(adapter);
+       }
+#endif
+
        err = igb_request_irq(adapter);
        if (err)
                goto err_req_irq;
@@ -1623,9 +1683,14 @@ static void igb_configure_tx(struct igb_adapter *adapter)
        u32 tctl;
        u32 txdctl, txctrl;
        int i;
+#ifdef CONFIG_PCI_IOV
+       u32 rbase_offset = adapter->vfs_allocated_count;
+#else
+       u32 rbase_offset = 0;
+#endif
 
-       for (i = 0; i < adapter->num_tx_queues; i++) {
-               struct igb_ring *ring = &(adapter->tx_ring[i]);
+       for (i = rbase_offset; i < (adapter->num_tx_queues + rbase_offset); 
i++) {
+               struct igb_ring *ring = &(adapter->tx_ring[i - rbase_offset]);
 
                wr32(E1000_TDLEN(i),
                                ring->count * sizeof(struct e1000_tx_desc));
@@ -1772,6 +1837,12 @@ static void igb_setup_rctl(struct igb_adapter *adapter)
        u32 rctl;
        u32 srrctl = 0;
        int i;
+#ifdef CONFIG_PCI_IOV
+       u32 rbase_offset = adapter->vfs_allocated_count;
+       u32 vmolr;
+#else
+       u32 rbase_offset = 0;
+#endif
 
        rctl = rd32(E1000_RCTL);
 
@@ -1794,6 +1865,7 @@ static void igb_setup_rctl(struct igb_adapter *adapter)
                rctl &= ~E1000_RCTL_LPE;
        else
                rctl |= E1000_RCTL_LPE;
+#ifndef CONFIG_PCI_IOV
        if (adapter->rx_buffer_len <= IGB_RXBUFFER_2048) {
                /* Setup buffer sizes */
                rctl &= ~E1000_RCTL_SZ_4096;
@@ -1818,9 +1890,12 @@ static void igb_setup_rctl(struct igb_adapter *adapter)
                        break;
                }
        } else {
+#endif
                rctl &= ~E1000_RCTL_BSEX;
                srrctl = adapter->rx_buffer_len >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+#ifndef CONFIG_PCI_IOV
        }
+#endif
 
        /* 82575 and greater support packet-split where the protocol
         * header is placed in skb->data and the packet data is
@@ -1836,13 +1911,36 @@ static void igb_setup_rctl(struct igb_adapter *adapter)
                srrctl |= adapter->rx_ps_hdr_size <<
                         E1000_SRRCTL_BSIZEHDRSIZE_SHIFT;
                srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+#ifdef CONFIG_PCI_IOV
+               srrctl |= 0x80000000;
+#endif
        } else {
                adapter->rx_ps_hdr_size = 0;
                srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
        }
 
-       for (i = 0; i < adapter->num_rx_queues; i++)
+       for (i = rbase_offset; i < (adapter->num_rx_queues + rbase_offset); 
i++) {
                wr32(E1000_SRRCTL(i), srrctl);
+#ifdef CONFIG_PCI_IOV
+               if ((rctl & E1000_RCTL_LPE) && adapter->vfs_allocated_count > 0 
) {
+                       vmolr = rd32(E1000_VMOLR(i));
+                       vmolr |= E1000_VMOLR_LPE;
+                       wr32(E1000_VMOLR(i), vmolr);
+               }
+#endif
+       }
+
+#ifdef CONFIG_PCI_IOV
+       /* Attention!!!  For SR-IOV PF driver operations you must enable
+        * queue drop for the queue 0 or the PF driver will *never* receive
+        * any traffic on it's own default queue, which will be equal to the
+        * number of VFs enabled.
+        */
+       if (adapter->vfs_allocated_count > 0) {
+               srrctl = rd32(E1000_SRRCTL(0));
+               wr32(E1000_SRRCTL(0), (srrctl | 0x80000000));
+       }
+#endif
 
        wr32(E1000_RCTL, rctl);
 }
@@ -1860,6 +1958,11 @@ static void igb_configure_rx(struct igb_adapter *adapter)
        u32 rctl, rxcsum;
        u32 rxdctl;
        int i;
+#ifdef CONFIG_PCI_IOV
+       u32 rbase_offset = adapter->vfs_allocated_count;
+#else
+       u32 rbase_offset = 0;
+#endif
 
        /* disable receives while setting up the descriptors */
        rctl = rd32(E1000_RCTL);
@@ -1872,8 +1975,8 @@ static void igb_configure_rx(struct igb_adapter *adapter)
 
        /* Setup the HW Rx Head and Tail Descriptor Pointers and
         * the Base and Length of the Rx Descriptor Ring */
-       for (i = 0; i < adapter->num_rx_queues; i++) {
-               struct igb_ring *ring = &(adapter->rx_ring[i]);
+       for (i = rbase_offset; i < (adapter->num_rx_queues + rbase_offset); 
i++) {
+               struct igb_ring *ring = &(adapter->rx_ring[i - rbase_offset]);
                rdba = ring->dma;
                wr32(E1000_RDBAL(i),
                                rdba & 0x00000000ffffffffULL);
@@ -2268,8 +2371,25 @@ static void igb_set_multi(struct net_device *netdev)
                memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
                mc_ptr = mc_ptr->next;
        }
+#ifdef CONFIG_PCI_IOV
+       if (adapter->vfs_allocated_count > 0) {
+               igb_update_mc_addr_list_82575(hw, mta_list, i,
+                                         adapter->vfs_allocated_count + 1,
+                                         mac->rar_entry_count);
+               igb_set_mc_list_pools(adapter, hw, i, mac->rar_entry_count);
+       /* TODO - if this is done after VF's are loaded and have their MC
+        * addresses set then we need to restore their entries in the MTA.
+        * This means we have to save them in the adapter structure somewhere
+        * so that we can retrieve them when this particular event occurs
+        */
+       } else {
+               igb_update_mc_addr_list_82575(hw, mta_list, i, 1,
+                                         mac->rar_entry_count);
+       }
+#else
        igb_update_mc_addr_list_82575(hw, mta_list, i, 1,
                                      mac->rar_entry_count);
+#endif
        kfree(mta_list);
 }
 
@@ -3274,6 +3394,22 @@ static irqreturn_t igb_msix_other(int irq, void *data)
        struct e1000_hw *hw = &adapter->hw;
        u32 icr = rd32(E1000_ICR);
 
+#ifdef CONFIG_PCI_IOV
+       adapter->int0counter++;
+
+       /* Check for a mailbox event */
+       if (icr & E1000_ICR_VMMB) {
+               adapter->vf_icr = rd32(E1000_MBVFICR);
+               /* Clear the bits */
+               wr32(E1000_MBVFICR, adapter->vf_icr);
+               E1000_WRITE_FLUSH(hw);
+               adapter->vflre = rd32(E1000_VFLRE);
+               wr32(E1000_VFLRE, adapter->vflre);
+               E1000_WRITE_FLUSH(hw);
+               igb_mbox_handler(adapter);
+       }
+#endif
+
        /* reading ICR causes bit 31 of EICR to be cleared */
        if (!(icr & E1000_ICR_LSC))
                goto no_link_interrupt;
@@ -3283,6 +3419,11 @@ static irqreturn_t igb_msix_other(int irq, void *data)
                mod_timer(&adapter->watchdog_timer, jiffies + 1);
        
 no_link_interrupt:
+#ifdef CONFIG_PCI_IOV
+       if (adapter->vfs_allocated_count != 0)
+               wr32(E1000_IMS, E1000_IMS_LSC | E1000_IMS_VMMB);
+       else
+#endif
        wr32(E1000_IMS, E1000_IMS_LSC);
        wr32(E1000_EIMS, adapter->eims_other);
 
@@ -3342,6 +3483,10 @@ static irqreturn_t igb_msix_rx(int irq, void *data)
         * previous interrupt.
         */
 
+#ifdef CONFIG_PCI_IOV
+       adapter->int1counter++;
+#endif
+
        igb_write_itr(rx_ring);
 
        if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi))
@@ -4192,6 +4337,9 @@ static void igb_vlan_rx_add_vid(struct net_device 
*netdev, u16 vid)
        vfta = array_rd32(E1000_VFTA, index);
        vfta |= (1 << (vid & 0x1F));
        igb_write_vfta(&adapter->hw, index, vfta);
+#ifdef CONFIG_PCI_IOV
+       adapter->vfta_tracking_entry[index] = (u8)vfta;
+#endif
 }
 
 static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
@@ -4219,6 +4367,9 @@ static void igb_vlan_rx_kill_vid(struct net_device 
*netdev, u16 vid)
        vfta = array_rd32(E1000_VFTA, index);
        vfta &= ~(1 << (vid & 0x1F));
        igb_write_vfta(&adapter->hw, index, vfta);
+#ifdef CONFIG_PCI_IOV
+       adapter->vfta_tracking_entry[index] = (u8)vfta;
+#endif
 }
 
 static void igb_restore_vlan(struct igb_adapter *adapter)
@@ -4529,4 +4680,433 @@ static void igb_io_resume(struct pci_dev *pdev)
 
 }
 
+#ifdef CONFIG_PCI_IOV
+static void igb_set_vf_multicasts(struct igb_adapter *adapter,
+                                 u32 *msgbuf, u32 vf)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       int n = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
+       int i;
+       u32 hash_value;
+       u8 *p = (u8 *)&msgbuf[1];
+
+       /* VFs are limited to using the MTA hash table for their multicast
+        * addresses */
+       for (i = 0; i < n; i++) {
+               hash_value = igb_hash_mc_addr(hw, p);
+               printk("Adding MC Addr: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n"
+                      "for VF %d\n",
+                      p[0],
+                      p[1],
+                      p[2],
+                      p[3],
+                      p[4],
+                      p[5],
+                      vf);
+               printk("Hash value = 0x%03X\n", hash_value);
+               igb_mta_set(hw, hash_value);
+               p += ETH_ALEN;
+       }
+}
+
+static void igb_set_vf_vlan(struct igb_adapter *adapter,
+                           u32 *msgbuf, u32 vf)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
+       int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
+       u32 reg, index, vfta;
+       int i;
+
+       if (add) {
+               /* See if a vlan filter for this id is already
+                * set and enabled */
+               for(i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
+                       reg = rd32(E1000_VLVF(i));
+                       if ((reg & E1000_VLVF_VLANID_ENABLE) &&
+                           vid == (reg & E1000_VLVF_VLANID_MASK))
+                               break;
+               }
+               if (i < E1000_VLVF_ARRAY_SIZE) {
+                       /* Found an enabled entry with the same VLAN
+                        * ID.  Just enable the pool select bit for
+                        * this requesting VF
+                        */
+                       reg |= 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
+                       wr32(E1000_VLVF(i), reg);
+                       msgbuf[0] |= E1000_VT_MSGTYPE_ACK;
+               } else {
+                       /* Did not find a matching VLAN ID filter entry
+                        * that was also enabled.  Search for a free
+                        * filter entry, i.e. one without the enable
+                        * bit set
+                        */
+                       for(i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
+                               reg = rd32(E1000_VLVF(i));
+                               if (!(reg & E1000_VLVF_VLANID_ENABLE))
+                                       break;
+                       }
+                       if (i == E1000_VLVF_ARRAY_SIZE) {
+                               /* oops, no free entry, send nack */
+                               msgbuf[0] |= E1000_VT_MSGTYPE_NACK;
+                       } else {
+                               /* add VID to filter table */
+                               index = (vid >> 5) & 0x7F;
+                               vfta = array_rd32(E1000_VFTA, index);
+                               vfta |= (1 << (vid & 0x1F));
+                               igb_write_vfta(hw, index, vfta);
+                               reg |= vid;
+                               reg |= 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
+                               reg |= E1000_VLVF_VLANID_ENABLE;
+                               wr32(E1000_VLVF(i), reg);
+                               msgbuf[0] |= E1000_VT_MSGTYPE_ACK;
+                       }
+               }
+       } else {
+               /* Find the vlan filter for this id */
+               for(i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
+                       reg = rd32(E1000_VLVF(i));
+                       if ((reg & E1000_VLVF_VLANID_ENABLE) &&
+                           vid == (reg & E1000_VLVF_VLANID_MASK))
+                               break;
+               }
+               if (i == E1000_VLVF_ARRAY_SIZE) {
+                       /* oops, not found. send nack */
+                       msgbuf[0] |= E1000_VT_MSGTYPE_NACK;
+               } else {
+                       u32 pool_sel;
+                       /* Check to see if the entry belongs to more than one
+                        * pool.  If so just reset this VF's pool select bit
+                        */
+                       /* mask off the pool select bits */
+                       pool_sel = (reg & E1000_VLVF_POOLSEL_MASK) >>
+                               E1000_VLVF_POOLSEL_SHIFT;
+                       /* reset this VF's pool select bit */
+                       pool_sel &= ~(1 << vf);
+                       /* check if other pools are set */
+                       if (pool_sel != 0) {
+                               reg &= ~(E1000_VLVF_POOLSEL_MASK);
+                               reg |= pool_sel;
+                       } else {
+                               /* just disable the whole entry */
+                               reg = 0;
+                               /* remove VID from filter table *IF AND
+                                * ONLY IF!!!* this entry was enabled for
+                                * VFs only through a write to the VFTA
+                                * table a few lines above here in this
+                                * function.  If this VFTA entry was added
+                                * through the rx_add_vid function then
+                                * we can't delete it here. */
+                               index = (vid >> 5) & 0x7F;
+                               if (adapter->vfta_tracking_entry[index] == 0) {
+                                       vfta = array_rd32(E1000_VFTA, index);
+                                       vfta &= ~(1 << (vid & 0x1F));
+                                       igb_write_vfta(hw, index, vfta);
+                               }
+                       }
+                       wr32(E1000_VLVF(i), reg);
+                       msgbuf[0] |= E1000_VT_MSGTYPE_ACK;
+               }
+       }
+}
+
+static void igb_msg_task(struct work_struct *work)
+{
+       struct igb_adapter *adapter;
+       struct e1000_hw *hw;
+       u32 bit, vf, vfr;
+       u32 vflre;
+       u32 vf_icr;
+
+       adapter = container_of(work, struct igb_adapter, msg_task);
+       hw = &adapter->hw;
+
+       vflre = adapter->vflre;
+       vf_icr = adapter->vf_icr;
+
+       /* Now that we have salted away local values of these events
+        * for processing we can enable the interrupt so more events
+        * can be captured
+        */
+
+       wr32(E1000_IMS, E1000_IMS_VMMB);
+
+       if (vflre & 0xFF) {
+               printk("VFLR Event %2.2X\n", vflre);
+               vfr = rd32(E1000_VFRE);
+               wr32(E1000_VFRE, vfr | vflre);
+               E1000_WRITE_FLUSH(hw);
+               vfr = rd32(E1000_VFTE);
+               wr32(E1000_VFTE, vfr | vflre);
+               E1000_WRITE_FLUSH(hw);
+       }
+
+       if (!vf_icr)
+               return;
+
+       /* Check for message acks from VF first as that may affect
+        * pending messages to the VF
+        */
+       for (bit = 1, vf = 0; bit < 0x100; bit <<= 1, vf++) {
+               if ((bit << 16) & vf_icr)
+                       igb_get_vf_msg_ack(adapter, vf);
+       }
+
+       /* Check for message sent from a VF */
+       for (bit = 1, vf = 0; bit < 0x100; bit <<= 1, vf++) {
+               if (bit & vf_icr)
+                       igb_rcv_msg_from_vf(adapter, vf);
+       }
+}
+
+int igb_send_msg_to_vf(struct igb_adapter *adapter, u32 *msg, u32 vfn)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       return e1000_send_mail_to_vf(hw, msg, vfn, 16);
+}
+
+static int igb_get_vf_msg_ack(struct igb_adapter *adapter, u32 vf)
+{
+       return 0;
+}
+
+static int igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
+{
+       u32 msgbuf[E1000_VFMAILBOX_SIZE];
+       struct net_device *netdev = adapter->netdev;
+       struct e1000_hw *hw = &adapter->hw;
+       u32 reg;
+       s32 retval;
+       int err = 0;
+
+       retval = e1000_receive_mail_from_vf(hw, msgbuf, vf, 16);
+
+       switch ((msgbuf[0] & 0xFFFF)) {
+       case E1000_VF_MSGTYPE_REQ_MAC:
+               {
+                       unsigned char *p;
+                       msgbuf[0] |= E1000_VT_MSGTYPE_ACK;
+                       p = (char *)&msgbuf[1];
+                       memcpy(p, adapter->vf_mac_addresses[vf], ETH_ALEN);
+                       if ((err = igb_send_msg_to_vf(adapter, msgbuf, vf)
+                            == 0)) {
+                               printk(KERN_INFO "Sending MAC Address 
%2.2x:%2.2x:"
+                                      "%2.2x:%2.2x:%2.2x:%2.2x to VF %d\n",
+                                      p[0], p[1], p[2], p[3], p[4], p[5], vf);
+                               igb_set_vf_mac(netdev,
+                                              vf,
+                                              adapter->vf_mac_addresses[vf]);
+                               igb_set_vf_vmolr(adapter, vf);
+                       }
+                       else {
+                               printk(KERN_ERR "Error %d Sending MAC Address 
to VF\n",
+                                      err);
+                       }
+               }
+               break;
+       case E1000_VF_MSGTYPE_VFLR:
+               {
+                       u32 vfe = rd32(E1000_VFTE);
+                       vfe |= (1 << vf);
+                       wr32(E1000_VFTE, vfe);
+                       vfe = rd32(E1000_VFRE);
+                       vfe |= (1 << vf);
+                       wr32(E1000_VFRE, vfe);
+                       printk(KERN_INFO "Enabling VFTE and VFRE for vf %d\n",
+                              vf);
+                       msgbuf[0] |= E1000_VT_MSGTYPE_ACK;
+                       if ((err = igb_send_msg_to_vf(adapter, msgbuf, vf)
+                            != 0))
+                               printk(KERN_ERR "Error %d Sending VFLR Ack"
+                                      "to VF\n", err);
+               }
+               break;
+       case E1000_VF_SET_MULTICAST:
+               igb_set_vf_multicasts(adapter, msgbuf, vf);
+               break;
+       case E1000_VF_SET_LPE:
+               /* Make sure global LPE is set */
+               reg = rd32(E1000_RCTL);
+               reg |= E1000_RCTL_LPE;
+               wr32(E1000_RCTL, reg);
+               /* Set per VM LPE */
+               reg = rd32(E1000_VMOLR(vf));
+               reg |= E1000_VMOLR_LPE;
+               wr32(E1000_VMOLR(vf), reg);
+               msgbuf[0] |= E1000_VT_MSGTYPE_ACK;
+               if ((err = igb_send_msg_to_vf(adapter, msgbuf, vf) != 0))
+                       printk(KERN_ERR "Error %d Sending set VMOLR LPE Ack"
+                              "to VF\n", err);
+               break;
+       case E1000_VF_SET_VLAN:
+               igb_set_vf_vlan(adapter, msgbuf, vf);
+               if ((err = igb_send_msg_to_vf(adapter, msgbuf, vf) != 0))
+                       printk(KERN_ERR "Error %d Sending set VLAN ID Ack"
+                              "to VF\n", err);
+               break;
+       default:
+               if ((msgbuf[0] & 0xFF000000) != E1000_VT_MSGTYPE_ACK &&
+                   (msgbuf[0] & 0xFF000000) != E1000_VT_MSGTYPE_NACK)
+                       printk(KERN_ERR "Unhandled Msg %8.8x\n", msgbuf[0]);
+               break;
+       }
+
+       return retval;
+}
+
+static void igb_mbox_handler(struct igb_adapter *adapter)
+{
+       schedule_work(&adapter->msg_task);
+}
+
+#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : (0x054E4 + 
((_i - 16) * 8)))
+
+static int igb_set_pf_mac(struct net_device *netdev, int queue, u8*mac_addr)
+{
+       struct igb_adapter *adapter;
+       struct e1000_hw *hw;
+       u32 reg_data;
+
+       adapter = netdev_priv(netdev);
+       hw = &adapter->hw;
+
+       /* point the pool selector for our default MAC entry to
+        * the right pool, which is equal to the number of vfs enabled.
+        */
+       reg_data = rd32(E1000_RAH(0));
+       reg_data |= (1 << (18 + queue));
+       wr32(E1000_RAH(0), reg_data);
+
+       return 0;
+}
+
+static void igb_set_vf_vmolr(struct igb_adapter *adapter, int vfn)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 reg_data;
+
+       reg_data = rd32(E1000_VMOLR(vfn));
+       reg_data |= 0xF << 24; /* aupe, rompe, rope, bam */
+       reg_data |= E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+       wr32(E1000_VMOLR(vfn), reg_data);
+}
+
+static int igb_set_vf_mac(struct net_device *netdev,
+                                                int vf,
+                                                unsigned char *mac_addr)
+{
+       struct igb_adapter *adapter;
+       struct e1000_hw *hw;
+       u32 reg_data;
+       int rar_entry = vf + 1; /* VF MAC addresses start at entry 1 */
+
+       adapter = netdev_priv(netdev);
+       hw = &adapter->hw;
+
+       igb_rar_set(hw, mac_addr, rar_entry);
+
+       memcpy(adapter->vf_mac_addresses[vf], mac_addr, 6);
+
+       reg_data = rd32(E1000_RAH(rar_entry));
+       reg_data |= (1 << (18 + vf));
+       wr32(E1000_RAH(rar_entry), reg_data);
+
+       return 0;
+}
+
+static int igb_vmm_control(struct igb_adapter *adapter, bool enable)
+{
+       struct e1000_hw *hw;
+       u32 reg_data;
+
+       hw = &adapter->hw;
+
+       if (enable) {
+               /* Enable multi-queue */
+               reg_data = rd32(E1000_MRQC);
+               reg_data &= E1000_MRQC_ENABLE_MASK;
+               reg_data |= E1000_MRQC_ENABLE_VMDQ;
+               wr32(E1000_MRQC, reg_data);
+               /* VF's need PF reset indication before they
+                * can send/receive mail */
+               reg_data = rd32(E1000_CTRL_EXT);
+               reg_data |= E1000_CTRL_EXT_PFRSTD;
+               wr32(E1000_CTRL_EXT, reg_data);
+
+               /* Set the default pool for the PF's first queue */
+               reg_data = rd32(E1000_VMD_CTL);
+               reg_data &= ~(E1000_VMD_CTL | E1000_VT_CTL_DISABLE_DEF_POOL);
+               reg_data |= adapter->vfs_allocated_count <<
+                       E1000_VT_CTL_DEFAULT_POOL_SHIFT;
+               wr32(E1000_VMD_CTL, reg_data);
+
+               e1000_vmdq_loopback_enable_vf(hw);
+               e1000_vmdq_replication_enable_vf(hw, 0xFF);
+       } else {
+               e1000_vmdq_loopback_disable_vf(hw);
+               e1000_vmdq_replication_disable_vf(hw);
+       }
+
+       return 0;
+}
+
+static void igb_enable_pf_queues(struct igb_adapter *adapter)
+{
+       u64 rdba;
+       int i;
+       u32 rbase_offset = adapter->vfs_allocated_count;
+       struct e1000_hw *hw = &adapter->hw;
+       u32 rxdctl;
+
+       for (i = rbase_offset;
+            i < (adapter->num_rx_queues + rbase_offset); i++) {
+               struct igb_ring *ring = &adapter->rx_ring[i - rbase_offset];
+               rdba = ring->dma;
+
+               rxdctl = rd32(E1000_RXDCTL(i));
+               rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
+               rxdctl &= 0xFFF00000;
+               rxdctl |= IGB_RX_PTHRESH;
+               rxdctl |= IGB_RX_HTHRESH << 8;
+               rxdctl |= IGB_RX_WTHRESH << 16;
+               wr32(E1000_RXDCTL(i), rxdctl);
+               printk("RXDCTL%d == %8.8x\n", i, rxdctl);
+
+               wr32(E1000_RDBAL(i),
+                               rdba & 0x00000000ffffffffULL);
+               wr32(E1000_RDBAH(i), rdba >> 32);
+               wr32(E1000_RDLEN(i),
+                              ring->count * sizeof(union e1000_adv_rx_desc));
+
+               writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail);
+               writel(ring->next_to_clean, adapter->hw.hw_addr + ring->head);
+       }
+}
+
+void igb_set_mc_list_pools(struct igb_adapter *adapter,
+                          struct e1000_hw *hw,
+                          int entry_count, u16 total_rar_filters)
+{
+       u32 reg_data;
+       int i;
+       int pool = adapter->vfs_allocated_count;
+
+       for (i = adapter->vfs_allocated_count + 1; i < total_rar_filters; i++) {
+               reg_data = rd32(E1000_RAH(i));
+               reg_data |= (1 << (18 + pool));
+               wr32(E1000_RAH(i), reg_data);
+               entry_count--;
+               if (!entry_count)
+                       break;
+       }
+
+       reg_data = rd32(E1000_VMOLR(pool));
+       /* Set bit 25 for this pool in the VM Offload register so that
+        * it can accept packets that match the MTA table */
+       reg_data |= (1 << 25);
+       wr32(E1000_VMOLR(pool), reg_data);
+}
+#endif
+
 /* igb_main.c */
-- 
1.5.4.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel