Commit 054c67d1 authored by Sudarsana Reddy Kalluru's avatar Sudarsana Reddy Kalluru Committed by David S. Miller

qed*: Add support for ethtool link_ksettings callbacks.

This patch adds the driver implementation for ethtool link_ksettings
callbacks. qed driver now defines/uses the qed specific masks for
representing link capability values. qede driver maps these values to
to new link modes defined by the kernel implementation of link_ksettings.

Please consider applying this to 'net-next' branch.
Signed-off-by: default avatarSudarsana Reddy Kalluru <sudarsana.kalluru@qlogic.com>
Signed-off-by: default avatarYuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e27d6cf5
......@@ -1025,20 +1025,23 @@ static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params)
link_params->speed.autoneg = params->autoneg;
if (params->override_flags & QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS) {
link_params->speed.advertised_speeds = 0;
if ((params->adv_speeds & SUPPORTED_1000baseT_Half) ||
(params->adv_speeds & SUPPORTED_1000baseT_Full))
if ((params->adv_speeds & QED_LM_1000baseT_Half_BIT) ||
(params->adv_speeds & QED_LM_1000baseT_Full_BIT))
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G;
if (params->adv_speeds & SUPPORTED_10000baseKR_Full)
if (params->adv_speeds & QED_LM_10000baseKR_Full_BIT)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G;
if (params->adv_speeds & SUPPORTED_40000baseLR4_Full)
if (params->adv_speeds & QED_LM_25000baseKR_Full_BIT)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G;
if (params->adv_speeds & QED_LM_40000baseLR4_Full_BIT)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G;
if (params->adv_speeds & 0)
if (params->adv_speeds & QED_LM_50000baseKR2_Full_BIT)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G;
if (params->adv_speeds & 0)
if (params->adv_speeds & QED_LM_100000baseKR4_Full_BIT)
link_params->speed.advertised_speeds |=
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G;
}
......@@ -1168,50 +1171,56 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
if_link->link_up = true;
/* TODO - at the moment assume supported and advertised speed equal */
if_link->supported_caps = SUPPORTED_FIBRE;
if_link->supported_caps = QED_LM_FIBRE_BIT;
if (params.speed.autoneg)
if_link->supported_caps |= SUPPORTED_Autoneg;
if_link->supported_caps |= QED_LM_Autoneg_BIT;
if (params.pause.autoneg ||
(params.pause.forced_rx && params.pause.forced_tx))
if_link->supported_caps |= SUPPORTED_Asym_Pause;
if_link->supported_caps |= QED_LM_Asym_Pause_BIT;
if (params.pause.autoneg || params.pause.forced_rx ||
params.pause.forced_tx)
if_link->supported_caps |= SUPPORTED_Pause;
if_link->supported_caps |= QED_LM_Pause_BIT;
if_link->advertised_caps = if_link->supported_caps;
if (params.speed.advertised_speeds &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
if_link->advertised_caps |= SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full;
if_link->advertised_caps |= QED_LM_1000baseT_Half_BIT |
QED_LM_1000baseT_Full_BIT;
if (params.speed.advertised_speeds &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
if_link->advertised_caps |= SUPPORTED_10000baseKR_Full;
if_link->advertised_caps |= QED_LM_10000baseKR_Full_BIT;
if (params.speed.advertised_speeds &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
if_link->advertised_caps |= QED_LM_25000baseKR_Full_BIT;
if (params.speed.advertised_speeds &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
if_link->advertised_caps |= SUPPORTED_40000baseLR4_Full;
if_link->advertised_caps |= QED_LM_40000baseLR4_Full_BIT;
if (params.speed.advertised_speeds &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
if_link->advertised_caps |= 0;
if_link->advertised_caps |= QED_LM_50000baseKR2_Full_BIT;
if (params.speed.advertised_speeds &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
if_link->advertised_caps |= 0;
if_link->advertised_caps |= QED_LM_100000baseKR4_Full_BIT;
if (link_caps.speed_capabilities &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
if_link->supported_caps |= SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full;
if_link->supported_caps |= QED_LM_1000baseT_Half_BIT |
QED_LM_1000baseT_Full_BIT;
if (link_caps.speed_capabilities &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G)
if_link->supported_caps |= SUPPORTED_10000baseKR_Full;
if_link->supported_caps |= QED_LM_10000baseKR_Full_BIT;
if (link_caps.speed_capabilities &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G)
if_link->supported_caps |= QED_LM_25000baseKR_Full_BIT;
if (link_caps.speed_capabilities &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G)
if_link->supported_caps |= SUPPORTED_40000baseLR4_Full;
if_link->supported_caps |= QED_LM_40000baseLR4_Full_BIT;
if (link_caps.speed_capabilities &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G)
if_link->supported_caps |= 0;
if_link->supported_caps |= QED_LM_50000baseKR2_Full_BIT;
if (link_caps.speed_capabilities &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G)
if_link->supported_caps |= 0;
if_link->supported_caps |= QED_LM_100000baseKR4_Full_BIT;
if (link.link_up)
if_link->speed = link.speed;
......@@ -1231,33 +1240,29 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE;
/* Link partner capabilities */
if (link.partner_adv_speed &
QED_LINK_PARTNER_SPEED_1G_HD)
if_link->lp_caps |= SUPPORTED_1000baseT_Half;
if (link.partner_adv_speed &
QED_LINK_PARTNER_SPEED_1G_FD)
if_link->lp_caps |= SUPPORTED_1000baseT_Full;
if (link.partner_adv_speed &
QED_LINK_PARTNER_SPEED_10G)
if_link->lp_caps |= SUPPORTED_10000baseKR_Full;
if (link.partner_adv_speed &
QED_LINK_PARTNER_SPEED_40G)
if_link->lp_caps |= SUPPORTED_40000baseLR4_Full;
if (link.partner_adv_speed &
QED_LINK_PARTNER_SPEED_50G)
if_link->lp_caps |= 0;
if (link.partner_adv_speed &
QED_LINK_PARTNER_SPEED_100G)
if_link->lp_caps |= 0;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_HD)
if_link->lp_caps |= QED_LM_1000baseT_Half_BIT;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_1G_FD)
if_link->lp_caps |= QED_LM_1000baseT_Full_BIT;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_10G)
if_link->lp_caps |= QED_LM_10000baseKR_Full_BIT;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_25G)
if_link->lp_caps |= QED_LM_25000baseKR_Full_BIT;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_40G)
if_link->lp_caps |= QED_LM_40000baseLR4_Full_BIT;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_50G)
if_link->lp_caps |= QED_LM_50000baseKR2_Full_BIT;
if (link.partner_adv_speed & QED_LINK_PARTNER_SPEED_100G)
if_link->lp_caps |= QED_LM_100000baseKR4_Full_BIT;
if (link.an_complete)
if_link->lp_caps |= SUPPORTED_Autoneg;
if_link->lp_caps |= QED_LM_Autoneg_BIT;
if (link.partner_adv_pause)
if_link->lp_caps |= SUPPORTED_Pause;
if_link->lp_caps |= QED_LM_Pause_BIT;
if (link.partner_adv_pause == QED_LINK_PARTNER_ASYMMETRIC_PAUSE ||
link.partner_adv_pause == QED_LINK_PARTNER_BOTH_PAUSE)
if_link->lp_caps |= SUPPORTED_Asym_Pause;
if_link->lp_caps |= QED_LM_Asym_Pause_BIT;
}
static void qed_get_current_link(struct qed_dev *cdev,
......
......@@ -634,6 +634,9 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
p_link->partner_adv_speed |=
(status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ?
QED_LINK_PARTNER_SPEED_20G : 0;
p_link->partner_adv_speed |=
(status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ?
QED_LINK_PARTNER_SPEED_25G : 0;
p_link->partner_adv_speed |=
(status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ?
QED_LINK_PARTNER_SPEED_40G : 0;
......
......@@ -60,9 +60,10 @@ struct qed_mcp_link_state {
#define QED_LINK_PARTNER_SPEED_1G_FD BIT(1)
#define QED_LINK_PARTNER_SPEED_10G BIT(2)
#define QED_LINK_PARTNER_SPEED_20G BIT(3)
#define QED_LINK_PARTNER_SPEED_40G BIT(4)
#define QED_LINK_PARTNER_SPEED_50G BIT(5)
#define QED_LINK_PARTNER_SPEED_100G BIT(6)
#define QED_LINK_PARTNER_SPEED_25G BIT(4)
#define QED_LINK_PARTNER_SPEED_40G BIT(5)
#define QED_LINK_PARTNER_SPEED_50G BIT(6)
#define QED_LINK_PARTNER_SPEED_100G BIT(7)
u32 partner_adv_speed;
bool partner_tx_flow_ctrl_en;
......
......@@ -249,78 +249,150 @@ static u32 qede_get_priv_flags(struct net_device *dev)
return (!!(edev->dev_info.common.num_hwfns > 1)) << QEDE_PRI_FLAG_CMT;
}
static int qede_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
struct qede_link_mode_mapping {
u32 qed_link_mode;
u32 ethtool_link_mode;
};
static const struct qede_link_mode_mapping qed_lm_map[] = {
{QED_LM_FIBRE_BIT, ETHTOOL_LINK_MODE_FIBRE_BIT},
{QED_LM_Autoneg_BIT, ETHTOOL_LINK_MODE_Autoneg_BIT},
{QED_LM_Asym_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT},
{QED_LM_Pause_BIT, ETHTOOL_LINK_MODE_Pause_BIT},
{QED_LM_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT},
{QED_LM_1000baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
{QED_LM_10000baseKR_Full_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT},
{QED_LM_25000baseKR_Full_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT},
{QED_LM_40000baseLR4_Full_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT},
{QED_LM_50000baseKR2_Full_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT},
{QED_LM_100000baseKR4_Full_BIT,
ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT},
};
#define QEDE_DRV_TO_ETHTOOL_CAPS(caps, lk_ksettings, name) \
{ \
int i; \
\
for (i = 0; i < QED_LM_COUNT; i++) { \
if ((caps) & (qed_lm_map[i].qed_link_mode)) \
__set_bit(qed_lm_map[i].ethtool_link_mode,\
lk_ksettings->link_modes.name); \
} \
}
#define QEDE_ETHTOOL_TO_DRV_CAPS(caps, lk_ksettings, name) \
{ \
int i; \
\
for (i = 0; i < QED_LM_COUNT; i++) { \
if (test_bit(qed_lm_map[i].ethtool_link_mode, \
lk_ksettings->link_modes.name)) \
caps |= qed_lm_map[i].qed_link_mode; \
} \
}
static int qede_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
struct ethtool_link_settings *base = &cmd->base;
struct qede_dev *edev = netdev_priv(dev);
struct qed_link_output current_link;
memset(&current_link, 0, sizeof(current_link));
edev->ops->common->get_link(edev->cdev, &current_link);
cmd->supported = current_link.supported_caps;
cmd->advertising = current_link.advertised_caps;
ethtool_link_ksettings_zero_link_mode(cmd, supported);
QEDE_DRV_TO_ETHTOOL_CAPS(current_link.supported_caps, cmd, supported)
ethtool_link_ksettings_zero_link_mode(cmd, advertising);
QEDE_DRV_TO_ETHTOOL_CAPS(current_link.advertised_caps, cmd, advertising)
ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising);
QEDE_DRV_TO_ETHTOOL_CAPS(current_link.lp_caps, cmd, lp_advertising)
if ((edev->state == QEDE_STATE_OPEN) && (current_link.link_up)) {
ethtool_cmd_speed_set(cmd, current_link.speed);
cmd->duplex = current_link.duplex;
base->speed = current_link.speed;
base->duplex = current_link.duplex;
} else {
cmd->duplex = DUPLEX_UNKNOWN;
ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
base->speed = SPEED_UNKNOWN;
base->duplex = DUPLEX_UNKNOWN;
}
cmd->port = current_link.port;
cmd->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE :
base->port = current_link.port;
base->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE :
AUTONEG_DISABLE;
cmd->lp_advertising = current_link.lp_caps;
return 0;
}
static int qede_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static int qede_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd)
{
const struct ethtool_link_settings *base = &cmd->base;
struct qede_dev *edev = netdev_priv(dev);
struct qed_link_output current_link;
struct qed_link_params params;
u32 speed;
if (!edev->ops || !edev->ops->common->can_link_change(edev->cdev)) {
DP_INFO(edev,
"Link settings are not allowed to be changed\n");
DP_INFO(edev, "Link settings are not allowed to be changed\n");
return -EOPNOTSUPP;
}
memset(&current_link, 0, sizeof(current_link));
memset(&params, 0, sizeof(params));
edev->ops->common->get_link(edev->cdev, &current_link);
speed = ethtool_cmd_speed(cmd);
params.override_flags |= QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS;
params.override_flags |= QED_LINK_OVERRIDE_SPEED_AUTONEG;
if (cmd->autoneg == AUTONEG_ENABLE) {
if (base->autoneg == AUTONEG_ENABLE) {
params.autoneg = true;
params.forced_speed = 0;
params.adv_speeds = cmd->advertising;
QEDE_ETHTOOL_TO_DRV_CAPS(params.adv_speeds, cmd, advertising)
} else { /* forced speed */
params.override_flags |= QED_LINK_OVERRIDE_SPEED_FORCED_SPEED;
params.autoneg = false;
params.forced_speed = speed;
switch (speed) {
params.forced_speed = base->speed;
switch (base->speed) {
case SPEED_10000:
if (!(current_link.supported_caps &
SUPPORTED_10000baseKR_Full)) {
QED_LM_10000baseKR_Full_BIT)) {
DP_INFO(edev, "10G speed not supported\n");
return -EINVAL;
}
params.adv_speeds = SUPPORTED_10000baseKR_Full;
params.adv_speeds = QED_LM_10000baseKR_Full_BIT;
break;
case SPEED_25000:
if (!(current_link.supported_caps &
QED_LM_25000baseKR_Full_BIT)) {
DP_INFO(edev, "25G speed not supported\n");
return -EINVAL;
}
params.adv_speeds = QED_LM_25000baseKR_Full_BIT;
break;
case SPEED_40000:
if (!(current_link.supported_caps &
SUPPORTED_40000baseLR4_Full)) {
QED_LM_40000baseLR4_Full_BIT)) {
DP_INFO(edev, "40G speed not supported\n");
return -EINVAL;
}
params.adv_speeds = SUPPORTED_40000baseLR4_Full;
params.adv_speeds = QED_LM_40000baseLR4_Full_BIT;
break;
case 0xdead:
if (!(current_link.supported_caps &
QED_LM_50000baseKR2_Full_BIT)) {
DP_INFO(edev, "50G speed not supported\n");
return -EINVAL;
}
params.adv_speeds = QED_LM_50000baseKR2_Full_BIT;
break;
case 0xbeef:
if (!(current_link.supported_caps &
QED_LM_100000baseKR4_Full_BIT)) {
DP_INFO(edev, "100G speed not supported\n");
return -EINVAL;
}
params.adv_speeds = QED_LM_100000baseKR4_Full_BIT;
break;
default:
DP_INFO(edev, "Unsupported speed %u\n", speed);
DP_INFO(edev, "Unsupported speed %u\n", base->speed);
return -EINVAL;
}
}
......@@ -1228,8 +1300,8 @@ static int qede_get_tunable(struct net_device *dev,
}
static const struct ethtool_ops qede_ethtool_ops = {
.get_settings = qede_get_settings,
.set_settings = qede_set_settings,
.get_link_ksettings = qede_get_link_ksettings,
.set_link_ksettings = qede_set_link_ksettings,
.get_drvinfo = qede_get_drvinfo,
.get_msglevel = qede_get_msglevel,
.set_msglevel = qede_set_msglevel,
......@@ -1260,7 +1332,7 @@ static const struct ethtool_ops qede_ethtool_ops = {
};
static const struct ethtool_ops qede_vf_ethtool_ops = {
.get_settings = qede_get_settings,
.get_link_ksettings = qede_get_link_ksettings,
.get_drvinfo = qede_get_drvinfo,
.get_msglevel = qede_get_msglevel,
.set_msglevel = qede_set_msglevel,
......
......@@ -268,6 +268,21 @@ enum qed_protocol {
QED_PROTOCOL_ISCSI,
};
enum qed_link_mode_bits {
QED_LM_FIBRE_BIT = BIT(0),
QED_LM_Autoneg_BIT = BIT(1),
QED_LM_Asym_Pause_BIT = BIT(2),
QED_LM_Pause_BIT = BIT(3),
QED_LM_1000baseT_Half_BIT = BIT(4),
QED_LM_1000baseT_Full_BIT = BIT(5),
QED_LM_10000baseKR_Full_BIT = BIT(6),
QED_LM_25000baseKR_Full_BIT = BIT(7),
QED_LM_40000baseLR4_Full_BIT = BIT(8),
QED_LM_50000baseKR2_Full_BIT = BIT(9),
QED_LM_100000baseKR4_Full_BIT = BIT(10),
QED_LM_COUNT = 11
};
struct qed_link_params {
bool link_up;
......
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