Commit 00c04a92 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller

bnxt_en: Support new ETHTOOL_{G|S}LINKSETTINGS API.

To fully support 25G and 50G link settings.
Signed-off-by: default avatarMichael Chan <michael.chan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 93ed8117
...@@ -628,7 +628,66 @@ u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) ...@@ -628,7 +628,66 @@ u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause)
return speed_mask; 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; u16 fw_speeds = link_info->auto_link_speeds;
u8 fw_pause = 0; u8 fw_pause = 0;
...@@ -636,10 +695,11 @@ static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info) ...@@ -636,10 +695,11 @@ static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info)
if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
fw_pause = link_info->auto_pause_setting; 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; u16 fw_speeds = link_info->lp_auto_link_speeds;
u8 fw_pause = 0; u8 fw_pause = 0;
...@@ -647,27 +707,24 @@ static u32 bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info) ...@@ -647,27 +707,24 @@ static u32 bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info)
if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
fw_pause = link_info->lp_pause; 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; u16 fw_speeds = link_info->support_speeds;
u32 supported;
supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported);
return supported | SUPPORTED_Pause | SUPPORTED_Asym_Pause;
}
static u32 bnxt_fw_to_ethtool_support_adv_spds(struct bnxt_link_info *link_info) ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, Pause);
{ ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
u16 fw_speeds = link_info->support_auto_speeds; Asym_Pause);
u32 supported;
supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); if (link_info->support_auto_speeds)
if (supported) ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; Autoneg);
return supported;
} }
u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
...@@ -694,65 +751,62 @@ u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) ...@@ -694,65 +751,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 *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info; 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->support_auto_speeds) ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported);
cmd->supported |= SUPPORTED_Autoneg; bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings);
ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising);
if (link_info->autoneg) { if (link_info->autoneg) {
cmd->advertising = bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings);
bnxt_fw_to_ethtool_advertised_spds(link_info); ethtool_link_ksettings_add_link_mode(lk_ksettings,
cmd->advertising |= ADVERTISED_Autoneg; advertising, Autoneg);
cmd->autoneg = AUTONEG_ENABLE; base->autoneg = AUTONEG_ENABLE;
if (link_info->phy_link_status == BNXT_LINK_LINK) if (link_info->phy_link_status == BNXT_LINK_LINK)
cmd->lp_advertising = bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings);
bnxt_fw_to_ethtool_lp_adv(link_info);
ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed); ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
if (!netif_carrier_ok(dev)) if (!netif_carrier_ok(dev))
cmd->duplex = DUPLEX_UNKNOWN; base->duplex = DUPLEX_UNKNOWN;
else if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) else if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
cmd->duplex = DUPLEX_FULL; base->duplex = DUPLEX_FULL;
else else
cmd->duplex = DUPLEX_HALF; base->duplex = DUPLEX_HALF;
} else { } else {
cmd->autoneg = AUTONEG_DISABLE; base->autoneg = AUTONEG_DISABLE;
cmd->advertising = 0;
ethtool_speed = ethtool_speed =
bnxt_fw_to_ethtool_speed(link_info->req_link_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) 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) { if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
cmd->port = PORT_TP; base->port = PORT_TP;
cmd->supported |= SUPPORTED_TP; ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
cmd->advertising |= ADVERTISED_TP; TP);
ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
TP);
} else { } else {
cmd->supported |= SUPPORTED_FIBRE; ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
cmd->advertising |= ADVERTISED_FIBRE; FIBRE);
ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
FIBRE);
if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) 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 == else if (link_info->media_type ==
PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE) PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE)
cmd->port = PORT_FIBRE; base->port = PORT_FIBRE;
} }
base->phy_address = link_info->phy_addr;
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;
return 0; return 0;
} }
...@@ -826,34 +880,22 @@ u16 bnxt_get_fw_auto_link_speeds(u32 advertising) ...@@ -826,34 +880,22 @@ u16 bnxt_get_fw_auto_link_speeds(u32 advertising)
return fw_speed_mask; 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 *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info; struct bnxt_link_info *link_info = &bp->link_info;
const struct ethtool_link_settings *base = &lk_ksettings->base;
u32 speed, fw_advertising = 0; u32 speed, fw_advertising = 0;
bool set_pause = false; bool set_pause = false;
int rc = 0;
if (!BNXT_SINGLE_PF(bp)) if (!BNXT_SINGLE_PF(bp))
return rc; return -EOPNOTSUPP;
if (cmd->autoneg == AUTONEG_ENABLE) {
u32 supported_spds =
bnxt_fw_to_ethtool_support_adv_spds(link_info);
if (!supported_spds) { if (base->autoneg == AUTONEG_ENABLE) {
netdev_err(dev, "Autoneg not supported\n"); BNXT_ETHTOOL_TO_FW_SPDS(fw_advertising, lk_ksettings,
rc = -EINVAL; advertising);
goto set_setting_exit;
}
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);
link_info->autoneg |= BNXT_AUTONEG_SPEED; link_info->autoneg |= BNXT_AUTONEG_SPEED;
if (!fw_advertising) if (!fw_advertising)
link_info->advertising = link_info->support_auto_speeds; link_info->advertising = link_info->support_auto_speeds;
...@@ -874,16 +916,12 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -874,16 +916,12 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
rc = -EINVAL; rc = -EINVAL;
goto set_setting_exit; goto set_setting_exit;
} }
/* TODO: currently don't support half duplex */ if (base->duplex == DUPLEX_HALF) {
if (cmd->duplex == DUPLEX_HALF) {
netdev_err(dev, "HALF DUPLEX is not supported!\n"); netdev_err(dev, "HALF DUPLEX is not supported!\n");
rc = -EINVAL; rc = -EINVAL;
goto set_setting_exit; goto set_setting_exit;
} }
/* If received a request for an unknown duplex, assume full*/ speed = base->speed;
if (cmd->duplex == DUPLEX_UNKNOWN)
cmd->duplex = DUPLEX_FULL;
speed = ethtool_cmd_speed(cmd);
fw_speed = bnxt_get_fw_speed(dev, speed); fw_speed = bnxt_get_fw_speed(dev, speed);
if (!fw_speed) { if (!fw_speed) {
rc = -EINVAL; rc = -EINVAL;
...@@ -1629,8 +1667,8 @@ static int bnxt_get_module_eeprom(struct net_device *dev, ...@@ -1629,8 +1667,8 @@ static int bnxt_get_module_eeprom(struct net_device *dev,
} }
const struct ethtool_ops bnxt_ethtool_ops = { const struct ethtool_ops bnxt_ethtool_ops = {
.get_settings = bnxt_get_settings, .get_link_ksettings = bnxt_get_link_ksettings,
.set_settings = bnxt_set_settings, .set_link_ksettings = bnxt_set_link_ksettings,
.get_pauseparam = bnxt_get_pauseparam, .get_pauseparam = bnxt_get_pauseparam,
.set_pauseparam = bnxt_set_pauseparam, .set_pauseparam = bnxt_set_pauseparam,
.get_drvinfo = bnxt_get_drvinfo, .get_drvinfo = bnxt_get_drvinfo,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment