]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/intel/i40e/i40e_ethtool.c
Merge remote-tracking branch 'input-current/for-linus'
[karo-tx-linux.git] / drivers / net / ethernet / intel / i40e / i40e_ethtool.c
index 831f97125c8f6d5578d522161f4f135f1050f347..3f385ffe420f712abbda79b14c46e2b6196d8dc8 100644 (file)
@@ -90,9 +90,6 @@ static const struct i40e_stats i40e_gstrings_misc_stats[] = {
        I40E_VSI_STAT("tx_linearize", tx_linearize),
 };
 
-static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
-                                struct ethtool_rxnfc *cmd);
-
 /* These PF_STATs might look like duplicates of some NETDEV_STATs,
  * but they are separate.  This device supports Virtualization, and
  * as such might have several netdevs supporting VMDq and FCoE going
@@ -231,6 +228,8 @@ static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = {
 static const char i40e_priv_flags_strings[][ETH_GSTRING_LEN] = {
        "NPAR",
        "LinkPolling",
+       "flow-director-atr",
+       "veb-stats",
 };
 
 #define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_priv_flags_strings)
@@ -254,7 +253,8 @@ static void i40e_partition_setting_complaint(struct i40e_pf *pf)
  **/
 static void i40e_get_settings_link_up(struct i40e_hw *hw,
                                      struct ethtool_cmd *ecmd,
-                                     struct net_device *netdev)
+                                     struct net_device *netdev,
+                                     struct i40e_pf *pf)
 {
        struct i40e_link_status *hw_link_info = &hw->phy.link_info;
        u32 link_speed = hw_link_info->link_speed;
@@ -298,16 +298,24 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
                break;
        case I40E_PHY_TYPE_10GBASE_T:
        case I40E_PHY_TYPE_1000BASE_T:
-       case I40E_PHY_TYPE_100BASE_TX:
                ecmd->supported = SUPPORTED_Autoneg |
                                  SUPPORTED_10000baseT_Full |
-                                 SUPPORTED_1000baseT_Full |
-                                 SUPPORTED_100baseT_Full;
+                                 SUPPORTED_1000baseT_Full;
                ecmd->advertising = ADVERTISED_Autoneg;
                if (hw_link_info->requested_speeds & I40E_LINK_SPEED_10GB)
                        ecmd->advertising |= ADVERTISED_10000baseT_Full;
                if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB)
                        ecmd->advertising |= ADVERTISED_1000baseT_Full;
+               break;
+       case I40E_PHY_TYPE_1000BASE_T_OPTICAL:
+               ecmd->supported = SUPPORTED_Autoneg |
+                                 SUPPORTED_1000baseT_Full;
+               ecmd->advertising = ADVERTISED_Autoneg |
+                                   ADVERTISED_1000baseT_Full;
+               break;
+       case I40E_PHY_TYPE_100BASE_TX:
+               ecmd->supported = SUPPORTED_Autoneg |
+                                 SUPPORTED_100baseT_Full;
                if (hw_link_info->requested_speeds & I40E_LINK_SPEED_100MB)
                        ecmd->advertising |= ADVERTISED_100baseT_Full;
                break;
@@ -327,12 +335,15 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
                break;
        case I40E_PHY_TYPE_SGMII:
                ecmd->supported = SUPPORTED_Autoneg |
-                                 SUPPORTED_1000baseT_Full |
-                                 SUPPORTED_100baseT_Full;
+                                 SUPPORTED_1000baseT_Full;
                if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB)
                        ecmd->advertising |= ADVERTISED_1000baseT_Full;
-               if (hw_link_info->requested_speeds & I40E_LINK_SPEED_100MB)
-                       ecmd->advertising |= ADVERTISED_100baseT_Full;
+               if (pf->hw.mac.type == I40E_MAC_X722) {
+                       ecmd->supported |= SUPPORTED_100baseT_Full;
+                       if (hw_link_info->requested_speeds &
+                           I40E_LINK_SPEED_100MB)
+                               ecmd->advertising |= ADVERTISED_100baseT_Full;
+               }
                break;
        /* Backplane is set based on supported phy types in get_settings
         * so don't set anything here but don't warn either
@@ -380,7 +391,8 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
  * Reports link settings that can be determined when link is down
  **/
 static void i40e_get_settings_link_down(struct i40e_hw *hw,
-                                       struct ethtool_cmd *ecmd)
+                                       struct ethtool_cmd *ecmd,
+                                       struct i40e_pf *pf)
 {
        enum i40e_aq_capabilities_phy_type phy_types = hw->phy.phy_types;
 
@@ -391,11 +403,13 @@ static void i40e_get_settings_link_down(struct i40e_hw *hw,
        ecmd->advertising = 0x0;
        if (phy_types & I40E_CAP_PHY_TYPE_SGMII) {
                ecmd->supported |= SUPPORTED_Autoneg |
-                                  SUPPORTED_1000baseT_Full |
-                                  SUPPORTED_100baseT_Full;
+                                  SUPPORTED_1000baseT_Full;
                ecmd->advertising |= ADVERTISED_Autoneg |
-                                    ADVERTISED_1000baseT_Full |
-                                    ADVERTISED_100baseT_Full;
+                                    ADVERTISED_1000baseT_Full;
+               if (pf->hw.mac.type == I40E_MAC_X722) {
+                       ecmd->supported |= SUPPORTED_100baseT_Full;
+                       ecmd->advertising |= ADVERTISED_100baseT_Full;
+               }
        }
        if (phy_types & I40E_CAP_PHY_TYPE_XAUI ||
            phy_types & I40E_CAP_PHY_TYPE_XFI ||
@@ -424,7 +438,8 @@ static void i40e_get_settings_link_down(struct i40e_hw *hw,
                ecmd->advertising |= ADVERTISED_Autoneg |
                                    ADVERTISED_40000baseCR4_Full;
        }
-       if (phy_types & I40E_CAP_PHY_TYPE_100BASE_TX) {
+       if ((phy_types & I40E_CAP_PHY_TYPE_100BASE_TX) &&
+           !(phy_types & I40E_CAP_PHY_TYPE_1000BASE_T)) {
                ecmd->supported |= SUPPORTED_Autoneg |
                                   SUPPORTED_100baseT_Full;
                ecmd->advertising |= ADVERTISED_Autoneg |
@@ -466,9 +481,9 @@ static int i40e_get_settings(struct net_device *netdev,
        bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP;
 
        if (link_up)
-               i40e_get_settings_link_up(hw, ecmd, netdev);
+               i40e_get_settings_link_up(hw, ecmd, netdev, pf);
        else
-               i40e_get_settings_link_down(hw, ecmd);
+               i40e_get_settings_link_down(hw, ecmd, pf);
 
        /* Now set the settings that don't rely on link being up/down */
 
@@ -646,28 +661,31 @@ static int i40e_set_settings(struct net_device *netdev,
 
        /* Check autoneg */
        if (autoneg == AUTONEG_ENABLE) {
-               /* If autoneg is not supported, return error */
-               if (!(safe_ecmd.supported & SUPPORTED_Autoneg)) {
-                       netdev_info(netdev, "Autoneg not supported on this phy\n");
-                       return -EINVAL;
-               }
                /* If autoneg was not already enabled */
                if (!(hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED)) {
+                       /* If autoneg is not supported, return error */
+                       if (!(safe_ecmd.supported & SUPPORTED_Autoneg)) {
+                               netdev_info(netdev, "Autoneg not supported on this phy\n");
+                               return -EINVAL;
+                       }
+                       /* Autoneg is allowed to change */
                        config.abilities = abilities.abilities |
                                           I40E_AQ_PHY_ENABLE_AN;
                        change = true;
                }
        } else {
-               /* If autoneg is supported 10GBASE_T is the only phy that
-                * can disable it, so otherwise return error
-                */
-               if (safe_ecmd.supported & SUPPORTED_Autoneg &&
-                   hw->phy.link_info.phy_type != I40E_PHY_TYPE_10GBASE_T) {
-                       netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
-                       return -EINVAL;
-               }
                /* If autoneg is currently enabled */
                if (hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) {
+                       /* If autoneg is supported 10GBASE_T is the only PHY
+                        * that can disable it, so otherwise return error
+                        */
+                       if (safe_ecmd.supported & SUPPORTED_Autoneg &&
+                           hw->phy.link_info.phy_type !=
+                           I40E_PHY_TYPE_10GBASE_T) {
+                               netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
+                               return -EINVAL;
+                       }
+                       /* Autoneg is allowed to change */
                        config.abilities = abilities.abilities &
                                           ~I40E_AQ_PHY_ENABLE_AN;
                        change = true;
@@ -733,9 +751,9 @@ static int i40e_set_settings(struct net_device *netdev,
 
                status = i40e_update_link_info(hw);
                if (status)
-                       netdev_info(netdev, "Updating link info failed with err %s aq_err %s\n",
-                                   i40e_stat_str(hw, status),
-                                   i40e_aq_str(hw, hw->aq.asq_last_status));
+                       netdev_dbg(netdev, "Updating link info failed with err %s aq_err %s\n",
+                                  i40e_stat_str(hw, status),
+                                  i40e_aq_str(hw, hw->aq.asq_last_status));
 
        } else {
                netdev_info(netdev, "Nothing changed, exiting without setting anything.\n");
@@ -985,9 +1003,7 @@ static int i40e_get_eeprom(struct net_device *netdev,
 
                cmd = (struct i40e_nvm_access *)eeprom;
                ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
-               if (ret_val &&
-                   ((hw->aq.asq_last_status != I40E_AQ_RC_EACCES) ||
-                    (hw->debug_mask & I40E_DEBUG_NVM)))
+               if (ret_val && (hw->debug_mask & I40E_DEBUG_NVM))
                        dev_info(&pf->pdev->dev,
                                 "NVMUpdate read failed err=%d status=0x%x errno=%d module=%d offset=0x%x size=%d\n",
                                 ret_val, hw->aq.asq_last_status, errno,
@@ -1091,10 +1107,7 @@ static int i40e_set_eeprom(struct net_device *netdev,
 
        cmd = (struct i40e_nvm_access *)eeprom;
        ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
-       if (ret_val &&
-           ((hw->aq.asq_last_status != I40E_AQ_RC_EPERM &&
-             hw->aq.asq_last_status != I40E_AQ_RC_EBUSY) ||
-            (hw->debug_mask & I40E_DEBUG_NVM)))
+       if (ret_val && (hw->debug_mask & I40E_DEBUG_NVM))
                dev_info(&pf->pdev->dev,
                         "NVMUpdate write failed err=%d status=0x%x errno=%d module=%d offset=0x%x size=%d\n",
                         ret_val, hw->aq.asq_last_status, errno,
@@ -1114,11 +1127,10 @@ static void i40e_get_drvinfo(struct net_device *netdev,
        strlcpy(drvinfo->driver, i40e_driver_name, sizeof(drvinfo->driver));
        strlcpy(drvinfo->version, i40e_driver_version_str,
                sizeof(drvinfo->version));
-       strlcpy(drvinfo->fw_version, i40e_fw_version_str(&pf->hw),
+       strlcpy(drvinfo->fw_version, i40e_nvm_version_str(&pf->hw),
                sizeof(drvinfo->fw_version));
        strlcpy(drvinfo->bus_info, pci_name(pf->pdev),
                sizeof(drvinfo->bus_info));
-       drvinfo->n_priv_flags = I40E_PRIV_FLAGS_STR_LEN;
 }
 
 static void i40e_get_ringparam(struct net_device *netdev,
@@ -1394,6 +1406,12 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
                        data[i++] = (i40e_gstrings_veb_stats[j].sizeof_stat ==
                                     sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
                }
+               for (j = 0; j < I40E_MAX_TRAFFIC_CLASS; j++) {
+                       data[i++] = veb->tc_stats.tc_tx_packets[j];
+                       data[i++] = veb->tc_stats.tc_tx_bytes[j];
+                       data[i++] = veb->tc_stats.tc_rx_packets[j];
+                       data[i++] = veb->tc_stats.tc_rx_bytes[j];
+               }
        }
        for (j = 0; j < I40E_GLOBAL_STATS_LEN; j++) {
                p = (char *)pf + i40e_gstrings_stats[j].stat_offset;
@@ -1842,6 +1860,14 @@ static int i40e_get_coalesce(struct net_device *netdev,
 
        ec->rx_coalesce_usecs = vsi->rx_itr_setting & ~I40E_ITR_DYNAMIC;
        ec->tx_coalesce_usecs = vsi->tx_itr_setting & ~I40E_ITR_DYNAMIC;
+       /* we use the _usecs_high to store/set the interrupt rate limit
+        * that the hardware supports, that almost but not quite
+        * fits the original intent of the ethtool variable,
+        * the rx_coalesce_usecs_high limits total interrupts
+        * per second from both tx/rx sources.
+        */
+       ec->rx_coalesce_usecs_high = vsi->int_rate_limit;
+       ec->tx_coalesce_usecs_high = vsi->int_rate_limit;
 
        return 0;
 }
@@ -1860,6 +1886,17 @@ static int i40e_set_coalesce(struct net_device *netdev,
        if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
                vsi->work_limit = ec->tx_max_coalesced_frames_irq;
 
+       /* tx_coalesce_usecs_high is ignored, use rx-usecs-high instead */
+       if (ec->tx_coalesce_usecs_high != vsi->int_rate_limit) {
+               netif_info(pf, drv, netdev, "tx-usecs-high is not used, please program rx-usecs-high\n");
+               return -EINVAL;
+       }
+
+       if (ec->rx_coalesce_usecs_high >= INTRL_REG_TO_USEC(I40E_MAX_INTRL)) {
+               netif_info(pf, drv, netdev, "Invalid value, rx-usecs-high range is 0-235\n");
+               return -EINVAL;
+       }
+
        vector = vsi->base_vector;
        if ((ec->rx_coalesce_usecs >= (I40E_MIN_ITR << 1)) &&
            (ec->rx_coalesce_usecs <= (I40E_MAX_ITR << 1))) {
@@ -1873,6 +1910,8 @@ static int i40e_set_coalesce(struct net_device *netdev,
                return -EINVAL;
        }
 
+       vsi->int_rate_limit = ec->rx_coalesce_usecs_high;
+
        if ((ec->tx_coalesce_usecs >= (I40E_MIN_ITR << 1)) &&
            (ec->tx_coalesce_usecs <= (I40E_MAX_ITR << 1))) {
                vsi->tx_itr_setting = ec->tx_coalesce_usecs;
@@ -1897,11 +1936,14 @@ static int i40e_set_coalesce(struct net_device *netdev,
                vsi->tx_itr_setting &= ~I40E_ITR_DYNAMIC;
 
        for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
+               u16 intrl = INTRL_USEC_TO_REG(vsi->int_rate_limit);
+
                q_vector = vsi->q_vectors[i];
                q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
                wr32(hw, I40E_PFINT_ITRN(0, vector - 1), q_vector->rx.itr);
                q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
                wr32(hw, I40E_PFINT_ITRN(1, vector - 1), q_vector->tx.itr);
+               wr32(hw, I40E_PFINT_RATEN(vector - 1), intrl);
                i40e_flush(hw);
        }
 
@@ -2666,6 +2708,10 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
                I40E_PRIV_FLAGS_NPAR_FLAG : 0;
        ret_flags |= pf->flags & I40E_FLAG_LINK_POLLING_ENABLED ?
                I40E_PRIV_FLAGS_LINKPOLL_FLAG : 0;
+       ret_flags |= pf->flags & I40E_FLAG_FD_ATR_ENABLED ?
+               I40E_PRIV_FLAGS_FD_ATR : 0;
+       ret_flags |= pf->flags & I40E_FLAG_VEB_STATS_ENABLED ?
+               I40E_PRIV_FLAGS_VEB_STATS : 0;
 
        return ret_flags;
 }
@@ -2686,6 +2732,22 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
        else
                pf->flags &= ~I40E_FLAG_LINK_POLLING_ENABLED;
 
+       /* allow the user to control the state of the Flow
+        * Director ATR (Application Targeted Routing) feature
+        * of the driver
+        */
+       if (flags & I40E_PRIV_FLAGS_FD_ATR) {
+               pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+       } else {
+               pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+               pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
+       }
+
+       if (flags & I40E_PRIV_FLAGS_VEB_STATS)
+               pf->flags |= I40E_FLAG_VEB_STATS_ENABLED;
+       else
+               pf->flags &= ~I40E_FLAG_VEB_STATS_ENABLED;
+
        return 0;
 }