Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / ethernet / broadcom / bnxt / bnxt_ethtool.c
index 1b0ae4a..b83e174 100644 (file)
@@ -56,6 +56,8 @@ static int bnxt_get_coalesce(struct net_device *dev,
        coal->tx_coalesce_usecs_irq = bp->tx_coal_ticks_irq;
        coal->tx_max_coalesced_frames_irq = bp->tx_coal_bufs_irq;
 
+       coal->stats_block_coalesce_usecs = bp->stats_coal_ticks;
+
        return 0;
 }
 
@@ -63,6 +65,7 @@ static int bnxt_set_coalesce(struct net_device *dev,
                             struct ethtool_coalesce *coal)
 {
        struct bnxt *bp = netdev_priv(dev);
+       bool update_stats = false;
        int rc = 0;
 
        bp->rx_coal_ticks = coal->rx_coalesce_usecs;
@@ -76,8 +79,26 @@ static int bnxt_set_coalesce(struct net_device *dev,
        bp->tx_coal_ticks_irq = coal->tx_coalesce_usecs_irq;
        bp->tx_coal_bufs_irq = coal->tx_max_coalesced_frames_irq;
 
-       if (netif_running(dev))
-               rc = bnxt_hwrm_set_coal(bp);
+       if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) {
+               u32 stats_ticks = coal->stats_block_coalesce_usecs;
+
+               stats_ticks = clamp_t(u32, stats_ticks,
+                                     BNXT_MIN_STATS_COAL_TICKS,
+                                     BNXT_MAX_STATS_COAL_TICKS);
+               stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS);
+               bp->stats_coal_ticks = stats_ticks;
+               update_stats = true;
+       }
+
+       if (netif_running(dev)) {
+               if (update_stats) {
+                       rc = bnxt_close_nic(bp, true, false);
+                       if (!rc)
+                               rc = bnxt_open_nic(bp, true, false);
+               } else {
+                       rc = bnxt_hwrm_set_coal(bp);
+               }
+       }
 
        return rc;
 }
@@ -341,9 +362,13 @@ static void bnxt_get_channels(struct net_device *dev,
        channel->max_other = 0;
        if (bp->flags & BNXT_FLAG_SHARED_RINGS) {
                channel->combined_count = bp->rx_nr_rings;
+               if (BNXT_CHIP_TYPE_NITRO_A0(bp))
+                       channel->combined_count--;
        } else {
-               channel->rx_count = bp->rx_nr_rings;
-               channel->tx_count = bp->tx_nr_rings_per_tc;
+               if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) {
+                       channel->rx_count = bp->rx_nr_rings;
+                       channel->tx_count = bp->tx_nr_rings_per_tc;
+               }
        }
 }
 
@@ -366,6 +391,10 @@ static int bnxt_set_channels(struct net_device *dev,
            (channel->rx_count || channel->tx_count))
                return -EINVAL;
 
+       if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count ||
+                                           channel->tx_count))
+               return -EINVAL;
+
        if (channel->combined_count)
                sh = true;
 
@@ -628,7 +657,66 @@ u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause)
        return speed_mask;
 }
 
-static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info)
+#define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\
+{                                                                      \
+       if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB)                    \
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
+                                                    100baseT_Full);    \
+       if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB)                      \
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
+                                                    1000baseT_Full);   \
+       if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB)                     \
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
+                                                    10000baseT_Full);  \
+       if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB)                     \
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
+                                                    25000baseCR_Full); \
+       if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB)                     \
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
+                                                    40000baseCR4_Full);\
+       if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB)                     \
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
+                                                    50000baseCR2_Full);\
+       if ((fw_pause) & BNXT_LINK_PAUSE_RX) {                          \
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
+                                                    Pause);            \
+               if (!((fw_pause) & BNXT_LINK_PAUSE_TX))                 \
+                       ethtool_link_ksettings_add_link_mode(           \
+                                       lk_ksettings, name, Asym_Pause);\
+       } else if ((fw_pause) & BNXT_LINK_PAUSE_TX) {                   \
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
+                                                    Asym_Pause);       \
+       }                                                               \
+}
+
+#define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name)         \
+{                                                                      \
+       if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,   \
+                                                 100baseT_Full) ||     \
+           ethtool_link_ksettings_test_link_mode(lk_ksettings, name,   \
+                                                 100baseT_Half))       \
+               (fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB;               \
+       if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,   \
+                                                 1000baseT_Full) ||    \
+           ethtool_link_ksettings_test_link_mode(lk_ksettings, name,   \
+                                                 1000baseT_Half))      \
+               (fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB;                 \
+       if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,   \
+                                                 10000baseT_Full))     \
+               (fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB;                \
+       if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,   \
+                                                 25000baseCR_Full))    \
+               (fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB;                \
+       if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,   \
+                                                 40000baseCR4_Full))   \
+               (fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB;                \
+       if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,   \
+                                                 50000baseCR2_Full))   \
+               (fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB;                \
+}
+
+static void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info,
+                               struct ethtool_link_ksettings *lk_ksettings)
 {
        u16 fw_speeds = link_info->auto_link_speeds;
        u8 fw_pause = 0;
@@ -636,10 +724,11 @@ static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info)
        if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
                fw_pause = link_info->auto_pause_setting;
 
-       return _bnxt_fw_to_ethtool_adv_spds(fw_speeds, fw_pause);
+       BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising);
 }
 
-static u32 bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info)
+static void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info,
+                               struct ethtool_link_ksettings *lk_ksettings)
 {
        u16 fw_speeds = link_info->lp_auto_link_speeds;
        u8 fw_pause = 0;
@@ -647,16 +736,24 @@ static u32 bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info)
        if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
                fw_pause = link_info->lp_pause;
 
-       return _bnxt_fw_to_ethtool_adv_spds(fw_speeds, fw_pause);
+       BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings,
+                               lp_advertising);
 }
 
-static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info)
+static void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info,
+                               struct ethtool_link_ksettings *lk_ksettings)
 {
        u16 fw_speeds = link_info->support_speeds;
-       u32 supported;
 
-       supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0);
-       return supported | SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+       BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported);
+
+       ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, Pause);
+       ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
+                                            Asym_Pause);
+
+       if (link_info->support_auto_speeds)
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
+                                                    Autoneg);
 }
 
 u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
@@ -683,65 +780,62 @@ u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
        }
 }
 
-static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int bnxt_get_link_ksettings(struct net_device *dev,
+                                  struct ethtool_link_ksettings *lk_ksettings)
 {
        struct bnxt *bp = netdev_priv(dev);
        struct bnxt_link_info *link_info = &bp->link_info;
-       u16 ethtool_speed;
+       struct ethtool_link_settings *base = &lk_ksettings->base;
+       u32 ethtool_speed;
 
-       cmd->supported = bnxt_fw_to_ethtool_support_spds(link_info);
-
-       if (link_info->auto_link_speeds)
-               cmd->supported |= SUPPORTED_Autoneg;
+       ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported);
+       bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings);
 
+       ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising);
        if (link_info->autoneg) {
-               cmd->advertising =
-                       bnxt_fw_to_ethtool_advertised_spds(link_info);
-               cmd->advertising |= ADVERTISED_Autoneg;
-               cmd->autoneg = AUTONEG_ENABLE;
+               bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings);
+               ethtool_link_ksettings_add_link_mode(lk_ksettings,
+                                                    advertising, Autoneg);
+               base->autoneg = AUTONEG_ENABLE;
                if (link_info->phy_link_status == BNXT_LINK_LINK)
-                       cmd->lp_advertising =
-                               bnxt_fw_to_ethtool_lp_adv(link_info);
+                       bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings);
                ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
                if (!netif_carrier_ok(dev))
-                       cmd->duplex = DUPLEX_UNKNOWN;
+                       base->duplex = DUPLEX_UNKNOWN;
                else if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
-                       cmd->duplex = DUPLEX_FULL;
+                       base->duplex = DUPLEX_FULL;
                else
-                       cmd->duplex = DUPLEX_HALF;
+                       base->duplex = DUPLEX_HALF;
        } else {
-               cmd->autoneg = AUTONEG_DISABLE;
-               cmd->advertising = 0;
+               base->autoneg = AUTONEG_DISABLE;
                ethtool_speed =
                        bnxt_fw_to_ethtool_speed(link_info->req_link_speed);
-               cmd->duplex = DUPLEX_HALF;
+               base->duplex = DUPLEX_HALF;
                if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL)
-                       cmd->duplex = DUPLEX_FULL;
+                       base->duplex = DUPLEX_FULL;
        }
-       ethtool_cmd_speed_set(cmd, ethtool_speed);
+       base->speed = ethtool_speed;
 
-       cmd->port = PORT_NONE;
+       base->port = PORT_NONE;
        if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
-               cmd->port = PORT_TP;
-               cmd->supported |= SUPPORTED_TP;
-               cmd->advertising |= ADVERTISED_TP;
+               base->port = PORT_TP;
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
+                                                    TP);
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
+                                                    TP);
        } else {
-               cmd->supported |= SUPPORTED_FIBRE;
-               cmd->advertising |= ADVERTISED_FIBRE;
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
+                                                    FIBRE);
+               ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
+                                                    FIBRE);
 
                if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC)
-                       cmd->port = PORT_DA;
+                       base->port = PORT_DA;
                else if (link_info->media_type ==
                         PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE)
-                       cmd->port = PORT_FIBRE;
+                       base->port = PORT_FIBRE;
        }
-
-       if (link_info->transceiver ==
-           PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_INTERNAL)
-               cmd->transceiver = XCVR_INTERNAL;
-       else
-               cmd->transceiver = XCVR_EXTERNAL;
-       cmd->phy_address = link_info->phy_addr;
+       base->phy_address = link_info->phy_addr;
 
        return 0;
 }
@@ -815,37 +909,25 @@ u16 bnxt_get_fw_auto_link_speeds(u32 advertising)
        return fw_speed_mask;
 }
 
-static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int bnxt_set_link_ksettings(struct net_device *dev,
+                          const struct ethtool_link_ksettings *lk_ksettings)
 {
-       int rc = 0;
        struct bnxt *bp = netdev_priv(dev);
        struct bnxt_link_info *link_info = &bp->link_info;
+       const struct ethtool_link_settings *base = &lk_ksettings->base;
        u32 speed, fw_advertising = 0;
        bool set_pause = false;
+       int rc = 0;
 
-       if (BNXT_VF(bp))
-               return rc;
-
-       if (cmd->autoneg == AUTONEG_ENABLE) {
-               u32 supported_spds = bnxt_fw_to_ethtool_support_spds(link_info);
+       if (!BNXT_SINGLE_PF(bp))
+               return -EOPNOTSUPP;
 
-               if (cmd->advertising & ~(supported_spds | ADVERTISED_Autoneg |
-                                        ADVERTISED_TP | ADVERTISED_FIBRE)) {
-                       netdev_err(dev, "Unsupported advertising mask (adv: 0x%x)\n",
-                                  cmd->advertising);
-                       rc = -EINVAL;
-                       goto set_setting_exit;
-               }
-               fw_advertising = bnxt_get_fw_auto_link_speeds(cmd->advertising);
-               if (fw_advertising & ~link_info->support_speeds) {
-                       netdev_err(dev, "Advertising parameters are not supported! (adv: 0x%x)\n",
-                                  cmd->advertising);
-                       rc = -EINVAL;
-                       goto set_setting_exit;
-               }
+       if (base->autoneg == AUTONEG_ENABLE) {
+               BNXT_ETHTOOL_TO_FW_SPDS(fw_advertising, lk_ksettings,
+                                       advertising);
                link_info->autoneg |= BNXT_AUTONEG_SPEED;
                if (!fw_advertising)
-                       link_info->advertising = link_info->support_speeds;
+                       link_info->advertising = link_info->support_auto_speeds;
                else
                        link_info->advertising = fw_advertising;
                /* any change to autoneg will cause link change, therefore the
@@ -863,16 +945,12 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                        rc = -EINVAL;
                        goto set_setting_exit;
                }
-               /* TODO: currently don't support half duplex */
-               if (cmd->duplex == DUPLEX_HALF) {
+               if (base->duplex == DUPLEX_HALF) {
                        netdev_err(dev, "HALF DUPLEX is not supported!\n");
                        rc = -EINVAL;
                        goto set_setting_exit;
                }
-               /* If received a request for an unknown duplex, assume full*/
-               if (cmd->duplex == DUPLEX_UNKNOWN)
-                       cmd->duplex = DUPLEX_FULL;
-               speed = ethtool_cmd_speed(cmd);
+               speed = base->speed;
                fw_speed = bnxt_get_fw_speed(dev, speed);
                if (!fw_speed) {
                        rc = -EINVAL;
@@ -911,8 +989,8 @@ static int bnxt_set_pauseparam(struct net_device *dev,
        struct bnxt *bp = netdev_priv(dev);
        struct bnxt_link_info *link_info = &bp->link_info;
 
-       if (BNXT_VF(bp))
-               return rc;
+       if (!BNXT_SINGLE_PF(bp))
+               return -EOPNOTSUPP;
 
        if (epause->autoneg) {
                if (!(link_info->autoneg & BNXT_AUTONEG_SPEED))
@@ -1010,6 +1088,8 @@ static int bnxt_firmware_reset(struct net_device *dev,
        case BNX_DIR_TYPE_APE_FW:
        case BNX_DIR_TYPE_APE_PATCH:
                req.embedded_proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT;
+               /* Self-reset APE upon next PCIe reset: */
+               req.selfrst_status = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST;
                break;
        case BNX_DIR_TYPE_KONG_FW:
        case BNX_DIR_TYPE_KONG_PATCH:
@@ -1043,9 +1123,27 @@ static int bnxt_flash_firmware(struct net_device *dev,
        case BNX_DIR_TYPE_BOOTCODE_2:
                code_type = CODE_BOOT;
                break;
+       case BNX_DIR_TYPE_CHIMP_PATCH:
+               code_type = CODE_CHIMP_PATCH;
+               break;
        case BNX_DIR_TYPE_APE_FW:
                code_type = CODE_MCTP_PASSTHRU;
                break;
+       case BNX_DIR_TYPE_APE_PATCH:
+               code_type = CODE_APE_PATCH;
+               break;
+       case BNX_DIR_TYPE_KONG_FW:
+               code_type = CODE_KONG_FW;
+               break;
+       case BNX_DIR_TYPE_KONG_PATCH:
+               code_type = CODE_KONG_PATCH;
+               break;
+       case BNX_DIR_TYPE_BONO_FW:
+               code_type = CODE_BONO_FW;
+               break;
+       case BNX_DIR_TYPE_BONO_PATCH:
+               code_type = CODE_BONO_PATCH;
+               break;
        default:
                netdev_err(dev, "Unsupported directory entry type: %u\n",
                           dir_type);
@@ -1100,6 +1198,8 @@ static bool bnxt_dir_type_is_ape_bin_format(u16 dir_type)
        case BNX_DIR_TYPE_APE_PATCH:
        case BNX_DIR_TYPE_KONG_FW:
        case BNX_DIR_TYPE_KONG_PATCH:
+       case BNX_DIR_TYPE_BONO_FW:
+       case BNX_DIR_TYPE_BONO_PATCH:
                return true;
        }
 
@@ -1137,7 +1237,8 @@ static int bnxt_flash_firmware_from_file(struct net_device *dev,
        const struct firmware  *fw;
        int                     rc;
 
-       if (bnxt_dir_type_is_executable(dir_type) == false)
+       if (dir_type != BNX_DIR_TYPE_UPDATE &&
+           bnxt_dir_type_is_executable(dir_type) == false)
                return -EINVAL;
 
        rc = request_firmware(&fw, filename, &dev->dev);
@@ -1433,8 +1534,8 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
                 _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
        int rc = 0;
 
-       if (BNXT_VF(bp))
-               return 0;
+       if (!BNXT_SINGLE_PF(bp))
+               return -EOPNOTSUPP;
 
        if (!(bp->flags & BNXT_FLAG_EEE_CAP))
                return -EOPNOTSUPP;
@@ -1618,8 +1719,8 @@ static int bnxt_get_module_eeprom(struct net_device *dev,
 }
 
 const struct ethtool_ops bnxt_ethtool_ops = {
-       .get_settings           = bnxt_get_settings,
-       .set_settings           = bnxt_set_settings,
+       .get_link_ksettings     = bnxt_get_link_ksettings,
+       .set_link_ksettings     = bnxt_set_link_ksettings,
        .get_pauseparam         = bnxt_get_pauseparam,
        .set_pauseparam         = bnxt_set_pauseparam,
        .get_drvinfo            = bnxt_get_drvinfo,