igb: Fix reg pattern test in ethtool for i350 devices
[linux-block.git] / drivers / net / igb / igb_main.c
index 58c665b7513d1cea3ff9a80464e92260def6deff..eef380af05378869b03a71c02cf351981125c5ac 100644 (file)
 #endif
 #include "igb.h"
 
-#define DRV_VERSION "2.1.0-k2"
+#define DRV_VERSION "2.4.13-k2"
 char igb_driver_name[] = "igb";
 char igb_driver_version[] = DRV_VERSION;
 static const char igb_driver_string[] =
                                "Intel(R) Gigabit Ethernet Network Driver";
-static const char igb_copyright[] = "Copyright (c) 2007-2009 Intel Corporation.";
+static const char igb_copyright[] = "Copyright (c) 2007-2011 Intel Corporation.";
 
 static const struct e1000_info *igb_info_tbl[] = {
        [board_82575] = &e1000_82575_info,
@@ -68,6 +68,7 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SGMII), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_QUAD_FIBER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 },
@@ -149,6 +150,7 @@ static int igb_ndo_set_vf_vlan(struct net_device *netdev,
 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);
+static void igb_check_vf_rate_limit(struct igb_adapter *);
 
 #ifdef CONFIG_PM
 static int igb_suspend(struct pci_dev *, pm_message_t);
@@ -2286,9 +2288,19 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
 
        spin_lock_init(&adapter->stats64_lock);
 #ifdef CONFIG_PCI_IOV
-       if (hw->mac.type == e1000_82576)
-               adapter->vfs_allocated_count = (max_vfs > 7) ? 7 : max_vfs;
-
+       switch (hw->mac.type) {
+       case e1000_82576:
+       case e1000_i350:
+               if (max_vfs > 7) {
+                       dev_warn(&pdev->dev,
+                                "Maximum of 7 VFs per PF, using max\n");
+                       adapter->vfs_allocated_count = 7;
+               } else
+                       adapter->vfs_allocated_count = max_vfs;
+               break;
+       default:
+               break;
+       }
 #endif /* CONFIG_PCI_IOV */
        adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus());
 
@@ -3505,6 +3517,7 @@ static void igb_watchdog_task(struct work_struct *work)
                        netif_carrier_on(netdev);
 
                        igb_ping_all_vfs(adapter);
+                       igb_check_vf_rate_limit(adapter);
 
                        /* link state has changed, schedule phy info update */
                        if (!test_bit(__IGB_DOWN, &adapter->state))
@@ -6593,9 +6606,91 @@ static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
        return igb_set_vf_mac(adapter, vf, mac);
 }
 
+static int igb_link_mbps(int internal_link_speed)
+{
+       switch (internal_link_speed) {
+       case SPEED_100:
+               return 100;
+       case SPEED_1000:
+               return 1000;
+       default:
+               return 0;
+       }
+}
+
+static void igb_set_vf_rate_limit(struct e1000_hw *hw, int vf, int tx_rate,
+                                 int link_speed)
+{
+       int rf_dec, rf_int;
+       u32 bcnrc_val;
+
+       if (tx_rate != 0) {
+               /* Calculate the rate factor values to set */
+               rf_int = link_speed / tx_rate;
+               rf_dec = (link_speed - (rf_int * tx_rate));
+               rf_dec = (rf_dec * (1<<E1000_RTTBCNRC_RF_INT_SHIFT)) / tx_rate;
+
+               bcnrc_val = E1000_RTTBCNRC_RS_ENA;
+               bcnrc_val |= ((rf_int<<E1000_RTTBCNRC_RF_INT_SHIFT) &
+                              E1000_RTTBCNRC_RF_INT_MASK);
+               bcnrc_val |= (rf_dec & E1000_RTTBCNRC_RF_DEC_MASK);
+       } else {
+               bcnrc_val = 0;
+       }
+
+       wr32(E1000_RTTDQSEL, vf); /* vf X uses queue X */
+       wr32(E1000_RTTBCNRC, bcnrc_val);
+}
+
+static void igb_check_vf_rate_limit(struct igb_adapter *adapter)
+{
+       int actual_link_speed, i;
+       bool reset_rate = false;
+
+       /* VF TX rate limit was not set or not supported */
+       if ((adapter->vf_rate_link_speed == 0) ||
+           (adapter->hw.mac.type != e1000_82576))
+               return;
+
+       actual_link_speed = igb_link_mbps(adapter->link_speed);
+       if (actual_link_speed != adapter->vf_rate_link_speed) {
+               reset_rate = true;
+               adapter->vf_rate_link_speed = 0;
+               dev_info(&adapter->pdev->dev,
+                        "Link speed has been changed. VF Transmit "
+                        "rate is disabled\n");
+       }
+
+       for (i = 0; i < adapter->vfs_allocated_count; i++) {
+               if (reset_rate)
+                       adapter->vf_data[i].tx_rate = 0;
+
+               igb_set_vf_rate_limit(&adapter->hw, i,
+                                     adapter->vf_data[i].tx_rate,
+                                     actual_link_speed);
+       }
+}
+
 static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate)
 {
-       return -EOPNOTSUPP;
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       int actual_link_speed;
+
+       if (hw->mac.type != e1000_82576)
+               return -EOPNOTSUPP;
+
+       actual_link_speed = igb_link_mbps(adapter->link_speed);
+       if ((vf >= adapter->vfs_allocated_count) ||
+           (!(rd32(E1000_STATUS) & E1000_STATUS_LU)) ||
+           (tx_rate < 0) || (tx_rate > actual_link_speed))
+               return -EINVAL;
+
+       adapter->vf_rate_link_speed = actual_link_speed;
+       adapter->vf_data[vf].tx_rate = (u16)tx_rate;
+       igb_set_vf_rate_limit(hw, vf, tx_rate, actual_link_speed);
+
+       return 0;
 }
 
 static int igb_ndo_get_vf_config(struct net_device *netdev,
@@ -6606,7 +6701,7 @@ static int igb_ndo_get_vf_config(struct net_device *netdev,
                return -EINVAL;
        ivi->vf = vf;
        memcpy(&ivi->mac, adapter->vf_data[vf].vf_mac_addresses, ETH_ALEN);
-       ivi->tx_rate = 0;
+       ivi->tx_rate = adapter->vf_data[vf].tx_rate;
        ivi->vlan = adapter->vf_data[vf].pf_vlan;
        ivi->qos = adapter->vf_data[vf].pf_qos;
        return 0;