The link mode is a combination of port speed and port mode. But we currently only consider the speed, and then typically select the corresponding TP-based link mode. For 1G and 10G Fibre links this means we display the wrong link modes. Move the SPEED_* switch statements inside the PORT_* cases, and only consider valid combinations where we can select the corresponding link mode. Add the relevant link modes (1000baseX, 10000baseSR and 1000baseLR) that were introduced back with commit 5711a9822144 ("net: ethtool: add support for 1000BaseX and missing 10G link modes"). To differentiate between 10000baseSR and 10000baseLR, use the detailed media_type information that QUERY OAT provides. Signed-off-by: Julian Wiedmann <jwi@xxxxxxxxxxxxx> --- drivers/s390/net/qeth_core.h | 7 ++ drivers/s390/net/qeth_core_main.c | 11 +++ drivers/s390/net/qeth_ethtool.c | 124 ++++++++++++++++++------------ 3 files changed, 93 insertions(+), 49 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index c604e20a5e48..9e00917286a5 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -701,10 +701,17 @@ enum qeth_pnso_mode { QETH_PNSO_ADDR_INFO, }; +enum qeth_link_mode { + QETH_LINK_MODE_UNKNOWN, + QETH_LINK_MODE_FIBRE_SHORT, + QETH_LINK_MODE_FIBRE_LONG, +}; + struct qeth_link_info { u32 speed; u8 duplex; u8 port; + enum qeth_link_mode link_mode; }; #define QETH_BROADCAST_WITH_ECHO 0x01 diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 57dad31aab4d..2752a585849d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5017,13 +5017,19 @@ static int qeth_init_link_info_oat_cb(struct qeth_card *card, switch (phys_if->media_type) { case QETH_QOAT_PHYS_MEDIA_COPPER: link_info->port = PORT_TP; + link_info->link_mode = QETH_LINK_MODE_UNKNOWN; break; case QETH_QOAT_PHYS_MEDIA_FIBRE_SHORT: + link_info->port = PORT_FIBRE; + link_info->link_mode = QETH_LINK_MODE_FIBRE_SHORT; + break; case QETH_QOAT_PHYS_MEDIA_FIBRE_LONG: link_info->port = PORT_FIBRE; + link_info->link_mode = QETH_LINK_MODE_FIBRE_LONG; break; default: link_info->port = PORT_OTHER; + link_info->link_mode = QETH_LINK_MODE_UNKNOWN; break; } @@ -5037,6 +5043,7 @@ static void qeth_init_link_info(struct qeth_card *card) if (IS_IQD(card) || IS_VM_NIC(card)) { card->info.link_info.speed = SPEED_10000; card->info.link_info.port = PORT_FIBRE; + card->info.link_info.link_mode = QETH_LINK_MODE_FIBRE_SHORT; } else { switch (card->info.link_type) { case QETH_LINK_TYPE_FAST_ETH: @@ -5063,6 +5070,8 @@ static void qeth_init_link_info(struct qeth_card *card) card->info.link_info.speed = SPEED_UNKNOWN; card->info.link_info.port = PORT_OTHER; } + + card->info.link_info.link_mode = QETH_LINK_MODE_UNKNOWN; } /* Get more accurate data via QUERY OAT: */ @@ -5088,6 +5097,8 @@ static void qeth_init_link_info(struct qeth_card *card) card->info.link_info.duplex = link_info.duplex; if (link_info.port != PORT_OTHER) card->info.link_info.port = link_info.port; + if (link_info.link_mode != QETH_LINK_MODE_UNKNOWN) + card->info.link_info.link_mode = link_info.link_mode; } } } diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 50b0c1810850..3a51bbff0ffe 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -324,7 +324,8 @@ static int qeth_set_per_queue_coalesce(struct net_device *dev, u32 queue, /* Autoneg and full-duplex are supported and advertised unconditionally. */ /* Always advertise and support all speeds up to specified, and only one */ /* specified port type. */ -static void qeth_set_ethtool_link_modes(struct ethtool_link_ksettings *cmd) +static void qeth_set_ethtool_link_modes(struct ethtool_link_ksettings *cmd, + enum qeth_link_mode link_mode) { ethtool_link_ksettings_zero_link_mode(cmd, supported); ethtool_link_ksettings_zero_link_mode(cmd, advertising); @@ -337,58 +338,83 @@ static void qeth_set_ethtool_link_modes(struct ethtool_link_ksettings *cmd) case PORT_TP: ethtool_link_ksettings_add_link_mode(cmd, supported, TP); ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); + + switch (cmd->base.speed) { + case SPEED_10000: + ethtool_link_ksettings_add_link_mode(cmd, supported, + 10000baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 10000baseT_Full); + fallthrough; + case SPEED_1000: + ethtool_link_ksettings_add_link_mode(cmd, supported, + 1000baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 1000baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, supported, + 1000baseT_Half); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 1000baseT_Half); + fallthrough; + case SPEED_100: + ethtool_link_ksettings_add_link_mode(cmd, supported, + 100baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 100baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, supported, + 100baseT_Half); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 100baseT_Half); + fallthrough; + case SPEED_10: + ethtool_link_ksettings_add_link_mode(cmd, supported, + 10baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 10baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, supported, + 10baseT_Half); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 10baseT_Half); + break; + default: + break; + } + break; case PORT_FIBRE: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); - break; - default: - break; - } - /* partially does fall through, to also select lower speeds */ - switch (cmd->base.speed) { - case SPEED_25000: - ethtool_link_ksettings_add_link_mode(cmd, supported, - 25000baseSR_Full); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - 25000baseSR_Full); - break; - case SPEED_10000: - ethtool_link_ksettings_add_link_mode(cmd, supported, - 10000baseT_Full); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - 10000baseT_Full); - fallthrough; - case SPEED_1000: - ethtool_link_ksettings_add_link_mode(cmd, supported, - 1000baseT_Full); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - 1000baseT_Full); - ethtool_link_ksettings_add_link_mode(cmd, supported, - 1000baseT_Half); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - 1000baseT_Half); - fallthrough; - case SPEED_100: - ethtool_link_ksettings_add_link_mode(cmd, supported, - 100baseT_Full); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - 100baseT_Full); - ethtool_link_ksettings_add_link_mode(cmd, supported, - 100baseT_Half); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - 100baseT_Half); - fallthrough; - case SPEED_10: - ethtool_link_ksettings_add_link_mode(cmd, supported, - 10baseT_Full); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - 10baseT_Full); - ethtool_link_ksettings_add_link_mode(cmd, supported, - 10baseT_Half); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - 10baseT_Half); + switch (cmd->base.speed) { + case SPEED_25000: + ethtool_link_ksettings_add_link_mode(cmd, supported, + 25000baseSR_Full); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 25000baseSR_Full); + break; + case SPEED_10000: + if (link_mode == QETH_LINK_MODE_FIBRE_LONG) { + ethtool_link_ksettings_add_link_mode(cmd, supported, + 10000baseLR_Full); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 10000baseLR_Full); + } else if (link_mode == QETH_LINK_MODE_FIBRE_SHORT) { + ethtool_link_ksettings_add_link_mode(cmd, supported, + 10000baseSR_Full); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 10000baseSR_Full); + } + break; + case SPEED_1000: + ethtool_link_ksettings_add_link_mode(cmd, supported, + 1000baseX_Full); + ethtool_link_ksettings_add_link_mode(cmd, advertising, + 1000baseX_Full); + break; + default: + break; + } + break; default: break; @@ -420,7 +446,7 @@ static int qeth_get_link_ksettings(struct net_device *netdev, cmd->base.port = link_info.port; } - qeth_set_ethtool_link_modes(cmd); + qeth_set_ethtool_link_modes(cmd, card->info.link_info.link_mode); return 0; } -- 2.17.1