|
@@ -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(¤t_link, 0, sizeof(current_link));
|
|
|
edev->ops->common->get_link(edev->cdev, ¤t_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 :
|
|
|
- AUTONEG_DISABLE;
|
|
|
- cmd->lp_advertising = current_link.lp_caps;
|
|
|
+ base->port = current_link.port;
|
|
|
+ base->autoneg = (current_link.autoneg) ? AUTONEG_ENABLE :
|
|
|
+ AUTONEG_DISABLE;
|
|
|
|
|
|
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(¤t_link, 0, sizeof(current_link));
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
|
edev->ops->common->get_link(edev->cdev, ¤t_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;
|
|
|
- } else { /* forced speed */
|
|
|
+ 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,
|