igb: support for VF configuration tools
authorWilliams, Mitch A <mitch.a.williams@intel.com>
Wed, 10 Feb 2010 01:44:24 +0000 (01:44 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 13 Feb 2010 00:56:09 +0000 (16:56 -0800)
Add support to the igb driver for VF configuration mechanisms through the
PF interface.

Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/igb/e1000_82575.h
drivers/net/igb/e1000_regs.h
drivers/net/igb/igb.h
drivers/net/igb/igb_main.c

index d51c992..bb53083 100644 (file)
@@ -219,6 +219,9 @@ struct e1000_adv_tx_context_desc {
 #define E1000_VLVF_LVLAN          0x00100000
 #define E1000_VLVF_VLANID_ENABLE  0x80000000
 
+#define E1000_VMVIR_VLANA_DEFAULT      0x40000000 /* Always use default VLAN */
+#define E1000_VMVIR_VLANA_NEVER        0x80000000 /* Never insert VLAN tag */
+
 #define E1000_IOVCTL 0x05BBC
 #define E1000_IOVCTL_REUSE_VFQ 0x00000001
 
index dd4e6ff..abb7333 100644 (file)
 #define E1000_VMOLR(_n)        (0x05AD0 + (4 * (_n)))
 #define E1000_VLVF(_n)         (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
                                                        * Filter - RW */
+#define E1000_VMVIR(_n)        (0x03700 + (4 * (_n)))
 
 #define wr32(reg, value) (writel(value, hw->hw_addr + reg))
 #define rd32(reg) (readl(hw->hw_addr + reg))
index b1c1eb8..83ea117 100644 (file)
@@ -75,11 +75,14 @@ struct vf_data_storage {
        u16 vlans_enabled;
        u32 flags;
        unsigned long last_nack;
+       u16 pf_vlan; /* When set, guest VLAN config not allowed. */
+       u16 pf_qos;
 };
 
 #define IGB_VF_FLAG_CTS            0x00000001 /* VF is clear to send data */
 #define IGB_VF_FLAG_UNI_PROMISC    0x00000002 /* VF has unicast promisc */
 #define IGB_VF_FLAG_MULTI_PROMISC  0x00000004 /* VF has multicast promisc */
+#define IGB_VF_FLAG_PF_SET_MAC     0x00000008 /* PF has set MAC address */
 
 /* RX descriptor control thresholds.
  * PTHRESH - MAC will consider prefetch if it has fewer than this number of
index 28371d6..4fe7b0b 100644 (file)
@@ -133,6 +133,12 @@ static void igb_msg_task(struct igb_adapter *);
 static void igb_vmm_control(struct igb_adapter *);
 static int igb_set_vf_mac(struct igb_adapter *, int, unsigned char *);
 static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
+static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac);
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+                              int vf, u16 vlan, u8 qos);
+static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
+static int igb_ndo_get_vf_config(struct net_device *netdev, int vf,
+                                struct ifla_vf_info *ivi);
 
 #ifdef CONFIG_PM
 static int igb_suspend(struct pci_dev *, pm_message_t);
@@ -1352,6 +1358,10 @@ static const struct net_device_ops igb_netdev_ops = {
        .ndo_vlan_rx_register   = igb_vlan_rx_register,
        .ndo_vlan_rx_add_vid    = igb_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = igb_vlan_rx_kill_vid,
+       .ndo_set_vf_mac         = igb_ndo_set_vf_mac,
+       .ndo_set_vf_vlan        = igb_ndo_set_vf_vlan,
+       .ndo_set_vf_tx_rate     = igb_ndo_set_vf_bw,
+       .ndo_get_vf_config      = igb_ndo_get_vf_config,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = igb_netpoll,
 #endif
@@ -2479,7 +2489,8 @@ static void igb_rlpml_set(struct igb_adapter *adapter)
        wr32(E1000_RLPML, max_frame_size);
 }
 
-static inline void igb_set_vmolr(struct igb_adapter *adapter, int vfn)
+static inline void igb_set_vmolr(struct igb_adapter *adapter,
+                                int vfn, bool aupe)
 {
        struct e1000_hw *hw = &adapter->hw;
        u32 vmolr;
@@ -2492,8 +2503,11 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter, int vfn)
                return;
 
        vmolr = rd32(E1000_VMOLR(vfn));
-       vmolr |= E1000_VMOLR_AUPE |        /* Accept untagged packets */
-                E1000_VMOLR_STRVLAN;      /* Strip vlan tags */
+       vmolr |= E1000_VMOLR_STRVLAN;      /* Strip vlan tags */
+       if (aupe)
+               vmolr |= E1000_VMOLR_AUPE;        /* Accept untagged packets */
+       else
+               vmolr &= ~(E1000_VMOLR_AUPE); /* Tagged packets ONLY */
 
        /* clear all bits that might not be set */
        vmolr &= ~(E1000_VMOLR_BAM | E1000_VMOLR_RSSE);
@@ -2564,7 +2578,7 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
        wr32(E1000_SRRCTL(reg_idx), srrctl);
 
        /* set filtering for VMDQ pools */
-       igb_set_vmolr(adapter, reg_idx & 0x7);
+       igb_set_vmolr(adapter, reg_idx & 0x7, true);
 
        /* enable receive descriptor fetching */
        rxdctl = rd32(E1000_RXDCTL(reg_idx));
@@ -4490,10 +4504,57 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
                                reg |= size;
                                wr32(E1000_VMOLR(vf), reg);
                        }
-                       return 0;
                }
        }
-       return -1;
+       return 0;
+}
+
+static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (vid)
+               wr32(E1000_VMVIR(vf), (vid | E1000_VMVIR_VLANA_DEFAULT));
+       else
+               wr32(E1000_VMVIR(vf), 0);
+}
+
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+                              int vf, u16 vlan, u8 qos)
+{
+       int err = 0;
+       struct igb_adapter *adapter = netdev_priv(netdev);
+
+       if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095) || (qos > 7))
+               return -EINVAL;
+       if (vlan || qos) {
+               err = igb_vlvf_set(adapter, vlan, !!vlan, vf);
+               if (err)
+                       goto out;
+               igb_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
+               igb_set_vmolr(adapter, vf, !vlan);
+               adapter->vf_data[vf].pf_vlan = vlan;
+               adapter->vf_data[vf].pf_qos = qos;
+               dev_info(&adapter->pdev->dev,
+                        "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
+               if (test_bit(__IGB_DOWN, &adapter->state)) {
+                       dev_warn(&adapter->pdev->dev,
+                                "The VF VLAN has been set,"
+                                " but the PF device is not up.\n");
+                       dev_warn(&adapter->pdev->dev,
+                                "Bring the PF device up before"
+                                " attempting to use the VF device.\n");
+               }
+       } else {
+               igb_vlvf_set(adapter, adapter->vf_data[vf].pf_vlan,
+                                  false, vf);
+               igb_set_vmvir(adapter, vlan, vf);
+               igb_set_vmolr(adapter, vf, true);
+               adapter->vf_data[vf].pf_vlan = 0;
+               adapter->vf_data[vf].pf_qos = 0;
+       }
+out:
+       return err;
 }
 
 static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
@@ -4506,15 +4567,21 @@ static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
 
 static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
 {
-       /* clear all flags */
-       adapter->vf_data[vf].flags = 0;
+       /* clear flags */
+       adapter->vf_data[vf].flags &= ~(IGB_VF_FLAG_PF_SET_MAC);
        adapter->vf_data[vf].last_nack = jiffies;
 
        /* reset offloads to defaults */
-       igb_set_vmolr(adapter, vf);
+       igb_set_vmolr(adapter, vf, true);
 
        /* reset vlans for device */
        igb_clear_vf_vfta(adapter, vf);
+       if (adapter->vf_data[vf].pf_vlan)
+               igb_ndo_set_vf_vlan(adapter->netdev, vf,
+                                   adapter->vf_data[vf].pf_vlan,
+                                   adapter->vf_data[vf].pf_qos);
+       else
+               igb_clear_vf_vfta(adapter, vf);
 
        /* reset multicast table array for vf */
        adapter->vf_data[vf].num_vf_mc_hashes = 0;
@@ -4528,7 +4595,8 @@ static void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf)
        unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
 
        /* generate a new mac address as we were hotplug removed/added */
-       random_ether_addr(vf_mac);
+       if (!(adapter->vf_data[vf].flags & IGB_VF_FLAG_PF_SET_MAC))
+               random_ether_addr(vf_mac);
 
        /* process remaining reset events */
        igb_vf_reset(adapter, vf);
@@ -4641,7 +4709,10 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
                retval = igb_set_vf_rlpml(adapter, msgbuf[1], vf);
                break;
        case E1000_VF_SET_VLAN:
-               retval = igb_set_vf_vlan(adapter, msgbuf, vf);
+               if (adapter->vf_data[vf].pf_vlan)
+                       retval = -1;
+               else
+                       retval = igb_set_vf_vlan(adapter, msgbuf, vf);
                break;
        default:
                dev_err(&pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]);
@@ -6003,6 +6074,43 @@ static int igb_set_vf_mac(struct igb_adapter *adapter,
        return 0;
 }
 
+static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       if (!is_valid_ether_addr(mac) || (vf >= adapter->vfs_allocated_count))
+               return -EINVAL;
+       adapter->vf_data[vf].flags |= IGB_VF_FLAG_PF_SET_MAC;
+       dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf);
+       dev_info(&adapter->pdev->dev, "Reload the VF driver to make this"
+                                     " change effective.");
+       if (test_bit(__IGB_DOWN, &adapter->state)) {
+               dev_warn(&adapter->pdev->dev, "The VF MAC address has been set,"
+                        " but the PF device is not up.\n");
+               dev_warn(&adapter->pdev->dev, "Bring the PF device up before"
+                        " attempting to use the VF device.\n");
+       }
+       return igb_set_vf_mac(adapter, vf, mac);
+}
+
+static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate)
+{
+       return -EOPNOTSUPP;
+}
+
+static int igb_ndo_get_vf_config(struct net_device *netdev,
+                                int vf, struct ifla_vf_info *ivi)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       if (vf >= adapter->vfs_allocated_count)
+               return -EINVAL;
+       ivi->vf = vf;
+       memcpy(&ivi->mac, adapter->vf_data[vf].vf_mac_addresses, ETH_ALEN);
+       ivi->tx_rate = 0;
+       ivi->vlan = adapter->vf_data[vf].pf_vlan;
+       ivi->qos = adapter->vf_data[vf].pf_qos;
+       return 0;
+}
+
 static void igb_vmm_control(struct igb_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;