ixgbe: Add support for VF MAC and VLAN configuration
authorGreg Rose <gregory.v.rose@intel.com>
Tue, 4 May 2010 22:12:06 +0000 (22:12 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 6 May 2010 04:15:33 +0000 (21:15 -0700)
Add support for the "ip link set" and "ip link show" commands that allow
configuration of the virtual functions' MAC and port VLAN via user space
command line.

Signed-off-by: Greg Rose <gregory.v.rose@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_sriov.c
drivers/net/ixgbe/ixgbe_sriov.h
drivers/net/ixgbe/ixgbe_type.h

index 79c35ae3718c96186898452e286d59d5e0482814..d0ea3d6dea95f6f26b2fe3f9534c8b445c810cc6 100644 (file)
@@ -111,7 +111,10 @@ struct vf_data_storage {
        u16 default_vf_vlan_id;
        u16 vlans_enabled;
        bool clear_to_send;
+       bool pf_set_mac;
        int rar;
+       u16 pf_vlan; /* When set, guest VLAN config not allowed. */
+       u16 pf_qos;
 };
 
 /* wrapper around a pointer to a socket buffer,
index 0a0e90e800255540ea6bfa3517cdde85657c051f..d1a1868df817950855cd9f72e959c8cf209d6250 100644 (file)
@@ -6311,6 +6311,10 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_vlan_rx_add_vid    = ixgbe_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = ixgbe_vlan_rx_kill_vid,
        .ndo_do_ioctl           = ixgbe_ioctl,
+       .ndo_set_vf_mac         = ixgbe_ndo_set_vf_mac,
+       .ndo_set_vf_vlan        = ixgbe_ndo_set_vf_vlan,
+       .ndo_set_vf_tx_rate     = ixgbe_ndo_set_vf_bw,
+       .ndo_get_vf_config      = ixgbe_ndo_get_vf_config,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = ixgbe_netpoll,
 #endif
index 53f364d577399b15d07db5a07309d637a9539b4b..221b2ca994e6d25539c3dfd56bccfc34f3b60f30 100644 (file)
@@ -126,13 +126,34 @@ void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe)
        IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr);
 }
 
+static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter, u32 vid, u32 vf)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       if (vid)
+               IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf),
+                               (vid | IXGBE_VMVIR_VLANA_DEFAULT));
+       else
+               IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), 0);
+}
+
 inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
 {
        struct ixgbe_hw *hw = &adapter->hw;
 
        /* reset offloads to defaults */
-       ixgbe_set_vmolr(hw, vf, true);
-
+       if (adapter->vfinfo[vf].pf_vlan) {
+               ixgbe_set_vf_vlan(adapter, true,
+                                 adapter->vfinfo[vf].pf_vlan, vf);
+               ixgbe_set_vmvir(adapter,
+                               (adapter->vfinfo[vf].pf_vlan |
+                                (adapter->vfinfo[vf].pf_qos <<
+                                 VLAN_PRIO_SHIFT)), vf);
+               ixgbe_set_vmolr(hw, vf, false);
+       } else {
+               ixgbe_set_vmvir(adapter, 0, vf);
+               ixgbe_set_vmolr(hw, vf, true);
+       }
 
        /* reset multicast table array for vf */
        adapter->vfinfo[vf].num_vf_mc_hashes = 0;
@@ -266,10 +287,12 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
        case IXGBE_VF_SET_MAC_ADDR:
                {
                        u8 *new_mac = ((u8 *)(&msgbuf[1]));
-                       if (is_valid_ether_addr(new_mac))
+                       if (is_valid_ether_addr(new_mac) &&
+                           !adapter->vfinfo[vf].pf_set_mac)
                                ixgbe_set_vf_mac(adapter, vf, new_mac);
                        else
-                               retval = -1;
+                               ixgbe_set_vf_mac(adapter,
+                                 vf, adapter->vfinfo[vf].vf_mac_addresses);
                }
                break;
        case IXGBE_VF_SET_MULTICAST:
@@ -363,3 +386,76 @@ void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter)
        }
 }
 
+int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       if (!is_valid_ether_addr(mac) || (vf >= adapter->num_vfs))
+               return -EINVAL;
+       adapter->vfinfo[vf].pf_set_mac = true;
+       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(__IXGBE_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 ixgbe_set_vf_mac(adapter, vf, mac);
+}
+
+int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
+{
+       int err = 0;
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+       if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7))
+               return -EINVAL;
+       if (vlan || qos) {
+               err = ixgbe_set_vf_vlan(adapter, true, vlan, vf);
+               if (err)
+                       goto out;
+               ixgbe_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
+               ixgbe_set_vmolr(&adapter->hw, vf, false);
+               adapter->vfinfo[vf].pf_vlan = vlan;
+               adapter->vfinfo[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(__IXGBE_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 {
+               err = ixgbe_set_vf_vlan(adapter, false,
+                                       adapter->vfinfo[vf].pf_vlan, vf);
+               ixgbe_set_vmvir(adapter, vlan, vf);
+               ixgbe_set_vmolr(&adapter->hw, vf, true);
+               adapter->vfinfo[vf].pf_vlan = 0;
+               adapter->vfinfo[vf].pf_qos = 0;
+       }
+out:
+       return err;
+}
+
+int ixgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate)
+{
+       return -EOPNOTSUPP;
+}
+
+int ixgbe_ndo_get_vf_config(struct net_device *netdev,
+                           int vf, struct ifla_vf_info *ivi)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       if (vf >= adapter->num_vfs)
+               return -EINVAL;
+       ivi->vf = vf;
+       memcpy(&ivi->mac, adapter->vfinfo[vf].vf_mac_addresses, ETH_ALEN);
+       ivi->tx_rate = 0;
+       ivi->vlan = adapter->vfinfo[vf].pf_vlan;
+       ivi->qos = adapter->vfinfo[vf].pf_qos;
+       return 0;
+}
index 7fb12885cf5d52720c06c7be8fb8c7eed2596bce..184730ecdfb66c4f668b298b5d411fc4a1a4d47f 100644 (file)
@@ -42,6 +42,12 @@ int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask);
 void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter);
 void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter);
 void ixgbe_dump_registers(struct ixgbe_adapter *adapter);
+int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int queue, u8 *mac);
+int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int queue, u16 vlan,
+                          u8 qos);
+int ixgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
+int ixgbe_ndo_get_vf_config(struct net_device *netdev,
+                           int vf, struct ifla_vf_info *ivi);
 
 #endif /* _IXGBE_SRIOV_H_ */
 
index a0f9084c81cdc6ac5b35ed04515e38545f94c663..4277cbbb8126bad591dc30efc263d8dfe8fe310a 100644 (file)
 #define IXGBE_MTQC      0x08120
 #define IXGBE_VLVF(_i)  (0x0F100 + ((_i) * 4))  /* 64 of these (0-63) */
 #define IXGBE_VLVFB(_i) (0x0F200 + ((_i) * 4))  /* 128 of these (0-127) */
+#define IXGBE_VMVIR(_i) (0x08000 + ((_i) * 4))  /* 64 of these (0-63) */
 #define IXGBE_VT_CTL    0x051B0
 #define IXGBE_VFRE(_i)  (0x051E0 + ((_i) * 4))
 #define IXGBE_VFTE(_i)  (0x08110 + ((_i) * 4))
 #define IXGBE_VLVF_ENTRIES      64
 #define IXGBE_VLVF_VLANID_MASK  0x00000FFF
 
+/* Per VF Port VLAN insertion rules */
+#define IXGBE_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */
+#define IXGBE_VMVIR_VLANA_NEVER   0x80000000 /* Never insert VLAN tag */
+
 #define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.1q protocol */
 
 /* STATUS Bit Masks */