From 09840f70b088df1ec24f9b4e345983e7d5f63628 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 17 Nov 2020 17:15:13 +0100 Subject: s390/qeth: reduce rtnl locking for switchdev events call_switchdev_notifiers() doesn't require holding the RTNL lock since commit ff5cf100110c ("net: switchdev: Change notifier chain to be atomic"). We still need it for the "lost event" slow path, to avoid racing against a concurrent .ndo_bridge_setlink(). Signed-off-by: Julian Wiedmann Reviewed-by: Alexandra Winter Signed-off-by: Jakub Kicinski --- drivers/s390/net/qeth_l2_main.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 28f6dda95736..daeb837abec3 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -737,8 +737,6 @@ static void qeth_l2_dev2br_an_set_cb(void *priv, * * On enable, emits a series of address notifications for all * currently registered hosts. - * - * Must be called under rtnl_lock */ static int qeth_l2_dev2br_an_set(struct qeth_card *card, bool enable) { @@ -1289,16 +1287,19 @@ static void qeth_l2_dev2br_worker(struct work_struct *work) if (READ_ONCE(card->info.pnso_mode) == QETH_PNSO_NONE) goto free; - /* Potential re-config in progress, try again later: */ - if (!rtnl_trylock()) { - queue_delayed_work(card->event_wq, dwork, - msecs_to_jiffies(100)); - return; - } - if (!netif_device_present(card->dev)) - goto out_unlock; - if (data->ac_event.lost_event_mask) { + /* Potential re-config in progress, try again later: */ + if (!rtnl_trylock()) { + queue_delayed_work(card->event_wq, dwork, + msecs_to_jiffies(100)); + return; + } + + if (!netif_device_present(card->dev)) { + rtnl_unlock(); + goto free; + } + QETH_DBF_MESSAGE(3, "Address change notification overflow on device %x\n", CARD_DEVID(card)); @@ -1328,6 +1329,8 @@ static void qeth_l2_dev2br_worker(struct work_struct *work) "Address Notification resynced on device %x\n", CARD_DEVID(card)); } + + rtnl_unlock(); } else { for (i = 0; i < data->ac_event.num_entries; i++) { struct qeth_ipacmd_addr_change_entry *entry = @@ -1339,9 +1342,6 @@ static void qeth_l2_dev2br_worker(struct work_struct *work) } } -out_unlock: - rtnl_unlock(); - free: kfree(data); } @@ -2310,11 +2310,8 @@ static void qeth_l2_set_offline(struct qeth_card *card) card->state = CARD_STATE_DOWN; qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE); - if (priv->brport_features & BR_LEARNING_SYNC) { - rtnl_lock(); + if (priv->brport_features & BR_LEARNING_SYNC) qeth_l2_dev2br_fdb_flush(card); - rtnl_unlock(); - } } /* Returns zero if the command is successfully "consumed" */ -- cgit From 215d2836d714dbc1f52c7d14c6c1716bd4f4ff7b Mon Sep 17 00:00:00 2001 From: Kaixu Xia Date: Tue, 17 Nov 2020 17:15:14 +0100 Subject: s390/qeth: remove useless if/else Fix the following coccinelle report: ./drivers/s390/net/qeth_l3_main.c:107:2-4: WARNING: possible condition with no effect (if == else) Both branches are the same since commit ab29c480b194 ("s390/qeth: replace deprecated simple_stroul()"), so remove them. Reported-by: Tosk Robot Signed-off-by: Kaixu Xia [jwi: point to the commit that introduced this] Signed-off-by: Julian Wiedmann Signed-off-by: Jakub Kicinski --- drivers/s390/net/qeth_l3_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index b1c1d2510d55..264b6c782382 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -104,10 +104,7 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, qeth_l3_convert_addr_to_bits(ipatoe->addr, ipatoe_bits, (ipatoe->proto == QETH_PROT_IPV4) ? 4 : 16); - if (addr->proto == QETH_PROT_IPV4) - rc = !memcmp(addr_bits, ipatoe_bits, ipatoe->mask_bits); - else - rc = !memcmp(addr_bits, ipatoe_bits, ipatoe->mask_bits); + rc = !memcmp(addr_bits, ipatoe_bits, ipatoe->mask_bits); if (rc) break; } -- cgit From 88ad4d9bb16624e6ea81aac9fb83dc34cd12460f Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 17 Nov 2020 17:15:15 +0100 Subject: s390/qeth: tolerate error when querying card info By the time that our .get_link_ksettings() code issues a QUERY CARD INFO cmd to get link-related information, we already set up a good amount of static link data. Return this data when the cmd fails, same as when the cmd is not supported. Signed-off-by: Julian Wiedmann Signed-off-by: Jakub Kicinski --- drivers/s390/net/qeth_ethtool.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index b5caa723326e..b843df2c14b1 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -413,7 +413,6 @@ static int qeth_get_link_ksettings(struct net_device *netdev, struct qeth_card *card = netdev->ml_priv; enum qeth_link_types link_type; struct carrier_info carrier_info; - int rc; if (IS_IQD(card) || IS_VM_NIC(card)) link_type = QETH_LINK_TYPE_10GBIT_ETH; @@ -455,12 +454,8 @@ static int qeth_get_link_ksettings(struct net_device *netdev, /* Check if we can obtain more accurate information. */ /* If QUERY_CARD_INFO command is not supported or fails, */ /* just return the heuristics that was filled above. */ - rc = qeth_query_card_info(card, &carrier_info); - if (rc == -EOPNOTSUPP) /* for old hardware, return heuristic */ + if (qeth_query_card_info(card, &carrier_info)) return 0; - if (rc) /* report error from the hardware operation */ - return rc; - /* on success, fill in the information got from the hardware */ netdev_dbg(netdev, "card info: card_type=0x%02x, port_mode=0x%04x, port_speed=0x%08x\n", -- cgit From 4139b2b138dd44ca215976a06846839774ca7cd4 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 17 Nov 2020 17:15:16 +0100 Subject: s390/qeth: improve QUERY CARD INFO processing Move all the HW reply data parsing into qeth_query_card_info_cb(), and use common ethtool enums for transporting the information back to the caller. Also only look at the .port_speed field when we couldn't determine the speed from the .card_type field, and introduce some 'default' cases for SPEED_UNKNOWN, PORT_OTHER and DUPLEX_UNKNOWN. Signed-off-by: Julian Wiedmann Signed-off-by: Jakub Kicinski --- drivers/s390/net/qeth_core.h | 14 ++++---- drivers/s390/net/qeth_core_main.c | 67 +++++++++++++++++++++++++++++++---- drivers/s390/net/qeth_ethtool.c | 74 +++++++-------------------------------- 3 files changed, 79 insertions(+), 76 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index f73b4756ed5e..a4db7684d084 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -701,6 +701,12 @@ enum qeth_pnso_mode { QETH_PNSO_ADDR_INFO, }; +struct qeth_link_info { + u32 speed; + u8 duplex; + u8 port; +}; + #define QETH_BROADCAST_WITH_ECHO 0x01 #define QETH_BROADCAST_WITHOUT_ECHO 0x02 struct qeth_card_info { @@ -796,12 +802,6 @@ struct qeth_rx { u8 bufs_refill; }; -struct carrier_info { - __u8 card_type; - __u16 port_mode; - __u32 port_speed; -}; - struct qeth_switch_info { __u32 capabilities; __u32 settings; @@ -1108,7 +1108,7 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, int qeth_query_switch_attributes(struct qeth_card *card, struct qeth_switch_info *sw_info); int qeth_query_card_info(struct qeth_card *card, - struct carrier_info *carrier_info); + struct qeth_link_info *link_info); int qeth_setadpparms_set_access_ctrl(struct qeth_card *card, enum qeth_ipa_isolation_modes mode); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 93c9b30ab17a..39530f8e477f 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4868,8 +4868,8 @@ out_free: static int qeth_query_card_info_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { - struct carrier_info *carrier_info = (struct carrier_info *)reply->param; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data; + struct qeth_link_info *link_info = reply->param; struct qeth_query_card_info *card_info; QETH_CARD_TEXT(card, 2, "qcrdincb"); @@ -4877,14 +4877,67 @@ static int qeth_query_card_info_cb(struct qeth_card *card, return -EIO; card_info = &cmd->data.setadapterparms.data.card_info; - carrier_info->card_type = card_info->card_type; - carrier_info->port_mode = card_info->port_mode; - carrier_info->port_speed = card_info->port_speed; + netdev_dbg(card->dev, + "card info: card_type=0x%02x, port_mode=0x%04x, port_speed=0x%08x\n", + card_info->card_type, card_info->port_mode, + card_info->port_speed); + + switch (card_info->port_mode) { + case CARD_INFO_PORTM_FULLDUPLEX: + link_info->duplex = DUPLEX_FULL; + break; + case CARD_INFO_PORTM_HALFDUPLEX: + link_info->duplex = DUPLEX_HALF; + break; + default: + link_info->duplex = DUPLEX_UNKNOWN; + } + + switch (card_info->card_type) { + case CARD_INFO_TYPE_1G_COPPER_A: + case CARD_INFO_TYPE_1G_COPPER_B: + link_info->speed = SPEED_1000; + link_info->port = PORT_TP; + break; + case CARD_INFO_TYPE_1G_FIBRE_A: + case CARD_INFO_TYPE_1G_FIBRE_B: + link_info->speed = SPEED_1000; + link_info->port = PORT_FIBRE; + break; + case CARD_INFO_TYPE_10G_FIBRE_A: + case CARD_INFO_TYPE_10G_FIBRE_B: + link_info->speed = SPEED_10000; + link_info->port = PORT_FIBRE; + break; + default: + switch (card_info->port_speed) { + case CARD_INFO_PORTS_10M: + link_info->speed = SPEED_10; + break; + case CARD_INFO_PORTS_100M: + link_info->speed = SPEED_100; + break; + case CARD_INFO_PORTS_1G: + link_info->speed = SPEED_1000; + break; + case CARD_INFO_PORTS_10G: + link_info->speed = SPEED_10000; + break; + case CARD_INFO_PORTS_25G: + link_info->speed = SPEED_25000; + break; + default: + link_info->speed = SPEED_UNKNOWN; + } + + link_info->port = PORT_OTHER; + } + return 0; } int qeth_query_card_info(struct qeth_card *card, - struct carrier_info *carrier_info) + struct qeth_link_info *link_info) { struct qeth_cmd_buffer *iob; @@ -4894,8 +4947,8 @@ int qeth_query_card_info(struct qeth_card *card, iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_CARD_INFO, 0); if (!iob) return -ENOMEM; - return qeth_send_ipa_cmd(card, iob, qeth_query_card_info_cb, - (void *)carrier_info); + + return qeth_send_ipa_cmd(card, iob, qeth_query_card_info_cb, link_info); } /** diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index b843df2c14b1..a6455819f403 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -324,8 +324,7 @@ 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_cmd_adv_sup(struct ethtool_link_ksettings *cmd, - int maxspeed, int porttype) +static void qeth_set_ethtool_link_modes(struct ethtool_link_ksettings *cmd) { ethtool_link_ksettings_zero_link_mode(cmd, supported); ethtool_link_ksettings_zero_link_mode(cmd, advertising); @@ -334,7 +333,7 @@ static void qeth_set_cmd_adv_sup(struct ethtool_link_ksettings *cmd, ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); - switch (porttype) { + switch (cmd->base.port) { case PORT_TP: ethtool_link_ksettings_add_link_mode(cmd, supported, TP); ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); @@ -350,7 +349,7 @@ static void qeth_set_cmd_adv_sup(struct ethtool_link_ksettings *cmd, } /* partially does fall through, to also select lower speeds */ - switch (maxspeed) { + switch (cmd->base.speed) { case SPEED_25000: ethtool_link_ksettings_add_link_mode(cmd, supported, 25000baseSR_Full); @@ -406,13 +405,12 @@ static void qeth_set_cmd_adv_sup(struct ethtool_link_ksettings *cmd, } } - static int qeth_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct qeth_card *card = netdev->ml_priv; + struct qeth_link_info link_info; enum qeth_link_types link_type; - struct carrier_info carrier_info; if (IS_IQD(card) || IS_VM_NIC(card)) link_type = QETH_LINK_TYPE_10GBIT_ETH; @@ -449,66 +447,18 @@ static int qeth_get_link_ksettings(struct net_device *netdev, cmd->base.speed = SPEED_10; cmd->base.port = PORT_TP; } - qeth_set_cmd_adv_sup(cmd, cmd->base.speed, cmd->base.port); /* Check if we can obtain more accurate information. */ - /* If QUERY_CARD_INFO command is not supported or fails, */ - /* just return the heuristics that was filled above. */ - if (qeth_query_card_info(card, &carrier_info)) - return 0; - - netdev_dbg(netdev, - "card info: card_type=0x%02x, port_mode=0x%04x, port_speed=0x%08x\n", - carrier_info.card_type, - carrier_info.port_mode, - carrier_info.port_speed); - - /* Update attributes for which we've obtained more authoritative */ - /* information, leave the rest the way they where filled above. */ - switch (carrier_info.card_type) { - case CARD_INFO_TYPE_1G_COPPER_A: - case CARD_INFO_TYPE_1G_COPPER_B: - cmd->base.port = PORT_TP; - qeth_set_cmd_adv_sup(cmd, SPEED_1000, cmd->base.port); - break; - case CARD_INFO_TYPE_1G_FIBRE_A: - case CARD_INFO_TYPE_1G_FIBRE_B: - cmd->base.port = PORT_FIBRE; - qeth_set_cmd_adv_sup(cmd, SPEED_1000, cmd->base.port); - break; - case CARD_INFO_TYPE_10G_FIBRE_A: - case CARD_INFO_TYPE_10G_FIBRE_B: - cmd->base.port = PORT_FIBRE; - qeth_set_cmd_adv_sup(cmd, SPEED_10000, cmd->base.port); - break; - } - - switch (carrier_info.port_mode) { - case CARD_INFO_PORTM_FULLDUPLEX: - cmd->base.duplex = DUPLEX_FULL; - break; - case CARD_INFO_PORTM_HALFDUPLEX: - cmd->base.duplex = DUPLEX_HALF; - break; + if (!qeth_query_card_info(card, &link_info)) { + if (link_info.speed != SPEED_UNKNOWN) + cmd->base.speed = link_info.speed; + if (link_info.duplex != DUPLEX_UNKNOWN) + cmd->base.duplex = link_info.duplex; + if (link_info.port != PORT_OTHER) + cmd->base.port = link_info.port; } - switch (carrier_info.port_speed) { - case CARD_INFO_PORTS_10M: - cmd->base.speed = SPEED_10; - break; - case CARD_INFO_PORTS_100M: - cmd->base.speed = SPEED_100; - break; - case CARD_INFO_PORTS_1G: - cmd->base.speed = SPEED_1000; - break; - case CARD_INFO_PORTS_10G: - cmd->base.speed = SPEED_10000; - break; - case CARD_INFO_PORTS_25G: - cmd->base.speed = SPEED_25000; - break; - } + qeth_set_ethtool_link_modes(cmd); return 0; } -- cgit From baf7998d5f2116ab991236ac0d67f7021dc2ae55 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 17 Nov 2020 17:15:17 +0100 Subject: s390/qeth: set static link info during initialization Hard-code the minimal link info at initialization time, after we obtained the link_type. qeth_get_link_ksettings() can still override this with more accurate data from QUERY CARD INFO later on. Don't set arbitrary defaults for unknown OSA link types, they certainly won't match any future type. Signed-off-by: Julian Wiedmann Signed-off-by: Jakub Kicinski --- drivers/s390/net/qeth_core.h | 1 + drivers/s390/net/qeth_core_main.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/s390/net/qeth_ethtool.c | 34 +++------------------------------- 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index a4db7684d084..843385f9eae0 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -738,6 +738,7 @@ struct qeth_card_info { struct qeth_card_blkt blkt; __u32 diagass_support; __u32 hwtrap; + struct qeth_link_info link_info; }; enum qeth_discipline_id { diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 39530f8e477f..10997118d0b6 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4951,6 +4951,42 @@ int qeth_query_card_info(struct qeth_card *card, return qeth_send_ipa_cmd(card, iob, qeth_query_card_info_cb, link_info); } +static void qeth_init_link_info(struct qeth_card *card) +{ + card->info.link_info.duplex = DUPLEX_FULL; + + if (IS_IQD(card) || IS_VM_NIC(card)) { + card->info.link_info.speed = SPEED_10000; + card->info.link_info.port = PORT_FIBRE; + } else { + switch (card->info.link_type) { + case QETH_LINK_TYPE_FAST_ETH: + case QETH_LINK_TYPE_LANE_ETH100: + card->info.link_info.speed = SPEED_100; + card->info.link_info.port = PORT_TP; + break; + case QETH_LINK_TYPE_GBIT_ETH: + case QETH_LINK_TYPE_LANE_ETH1000: + card->info.link_info.speed = SPEED_1000; + card->info.link_info.port = PORT_FIBRE; + break; + case QETH_LINK_TYPE_10GBIT_ETH: + card->info.link_info.speed = SPEED_10000; + card->info.link_info.port = PORT_FIBRE; + break; + case QETH_LINK_TYPE_25GBIT_ETH: + card->info.link_info.speed = SPEED_25000; + card->info.link_info.port = PORT_FIBRE; + break; + default: + dev_info(&card->gdev->dev, "Unknown link type %x\n", + card->info.link_type); + card->info.link_info.speed = SPEED_UNKNOWN; + card->info.link_info.port = PORT_OTHER; + } + } +} + /** * qeth_vm_request_mac() - Request a hypervisor-managed MAC address * @card: pointer to a qeth_card @@ -5335,6 +5371,8 @@ retriable: goto out; } + qeth_init_link_info(card); + rc = qeth_init_qdio_queues(card); if (rc) { QETH_CARD_TEXT_(card, 2, "9err%d", rc); diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index a6455819f403..b8e74018b44f 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -410,44 +410,16 @@ static int qeth_get_link_ksettings(struct net_device *netdev, { struct qeth_card *card = netdev->ml_priv; struct qeth_link_info link_info; - enum qeth_link_types link_type; - if (IS_IQD(card) || IS_VM_NIC(card)) - link_type = QETH_LINK_TYPE_10GBIT_ETH; - else - link_type = card->info.link_type; - - cmd->base.duplex = DUPLEX_FULL; + cmd->base.speed = card->info.link_info.speed; + cmd->base.duplex = card->info.link_info.duplex; + cmd->base.port = card->info.link_info.port; cmd->base.autoneg = AUTONEG_ENABLE; cmd->base.phy_address = 0; cmd->base.mdio_support = 0; cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID; cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_INVALID; - switch (link_type) { - case QETH_LINK_TYPE_FAST_ETH: - case QETH_LINK_TYPE_LANE_ETH100: - cmd->base.speed = SPEED_100; - cmd->base.port = PORT_TP; - break; - case QETH_LINK_TYPE_GBIT_ETH: - case QETH_LINK_TYPE_LANE_ETH1000: - cmd->base.speed = SPEED_1000; - cmd->base.port = PORT_FIBRE; - break; - case QETH_LINK_TYPE_10GBIT_ETH: - cmd->base.speed = SPEED_10000; - cmd->base.port = PORT_FIBRE; - break; - case QETH_LINK_TYPE_25GBIT_ETH: - cmd->base.speed = SPEED_25000; - cmd->base.port = PORT_FIBRE; - break; - default: - cmd->base.speed = SPEED_10; - cmd->base.port = PORT_TP; - } - /* Check if we can obtain more accurate information. */ if (!qeth_query_card_info(card, &link_info)) { if (link_info.speed != SPEED_UNKNOWN) -- cgit From f252fa8ea0a0fa3fe05c0b1af5087313c8ec7813 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 17 Nov 2020 17:15:18 +0100 Subject: s390/qeth: clean up default cases for ethtool link mode Remove the default case for PORT_* and SPEED_* in our ethtool code. The only time these could be hit is if qeth_init_link_info() was unable to determine the port type from an OSA adapter's link_type. We already throw a message in this case, so reduce the noise and don't report bad data (ie. it's much more likely that any future link_type will represent a PORT_FIBRE link ...). Signed-off-by: Julian Wiedmann Signed-off-by: Jakub Kicinski --- drivers/s390/net/qeth_ethtool.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index b8e74018b44f..50b0c1810850 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -343,9 +343,7 @@ static void qeth_set_ethtool_link_modes(struct ethtool_link_ksettings *cmd) ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); break; default: - ethtool_link_ksettings_add_link_mode(cmd, supported, TP); - ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); - WARN_ON_ONCE(1); + break; } /* partially does fall through, to also select lower speeds */ @@ -393,15 +391,7 @@ static void qeth_set_ethtool_link_modes(struct ethtool_link_ksettings *cmd) 10baseT_Half); break; default: - 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); - WARN_ON_ONCE(1); + break; } } -- cgit From e92d42e7602b97b9eb73ce810c5bf62cc65cbb7a Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 17 Nov 2020 17:15:19 +0100 Subject: s390/qeth: use QUERY OAT for initial link info Improve the initial link info with data obtained from QUERY OAT. Doing so _only_ at initialization time avoids 1. dealing with multi-part replies, and 2. sifting through all the data that may get returned at runtime. This allows us to determine the correct port type for the 1000BT variant of recent OSA adapter generations (where the .card_type field in QUERY CARD INFO is no longer sufficient). Signed-off-by: Julian Wiedmann Signed-off-by: Jakub Kicinski --- drivers/s390/net/qeth_core_main.c | 107 ++++++++++++++++++++++++++++++++++++++ drivers/s390/net/qeth_core_mpc.h | 40 +++++++++++++- 2 files changed, 145 insertions(+), 2 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 10997118d0b6..43d8a0a9c121 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4951,6 +4951,86 @@ int qeth_query_card_info(struct qeth_card *card, return qeth_send_ipa_cmd(card, iob, qeth_query_card_info_cb, link_info); } +static int qeth_init_link_info_oat_cb(struct qeth_card *card, + struct qeth_reply *reply_priv, + unsigned long data) +{ + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data; + struct qeth_link_info *link_info = reply_priv->param; + struct qeth_query_oat_physical_if *phys_if; + struct qeth_query_oat_reply *reply; + + if (qeth_setadpparms_inspect_rc(cmd)) + return -EIO; + + /* Multi-part reply is unexpected, don't bother: */ + if (cmd->data.setadapterparms.hdr.used_total > 1) + return -EINVAL; + + /* Expect the reply to start with phys_if data: */ + reply = &cmd->data.setadapterparms.data.query_oat.reply[0]; + if (reply->type != QETH_QOAT_REPLY_TYPE_PHYS_IF || + reply->length < sizeof(*reply)) + return -EINVAL; + + phys_if = &reply->phys_if; + + switch (phys_if->speed_duplex) { + case QETH_QOAT_PHYS_SPEED_10M_HALF: + link_info->speed = SPEED_10; + link_info->duplex = DUPLEX_HALF; + break; + case QETH_QOAT_PHYS_SPEED_10M_FULL: + link_info->speed = SPEED_10; + link_info->duplex = DUPLEX_FULL; + break; + case QETH_QOAT_PHYS_SPEED_100M_HALF: + link_info->speed = SPEED_100; + link_info->duplex = DUPLEX_HALF; + break; + case QETH_QOAT_PHYS_SPEED_100M_FULL: + link_info->speed = SPEED_100; + link_info->duplex = DUPLEX_FULL; + break; + case QETH_QOAT_PHYS_SPEED_1000M_HALF: + link_info->speed = SPEED_1000; + link_info->duplex = DUPLEX_HALF; + break; + case QETH_QOAT_PHYS_SPEED_1000M_FULL: + link_info->speed = SPEED_1000; + link_info->duplex = DUPLEX_FULL; + break; + case QETH_QOAT_PHYS_SPEED_10G_FULL: + link_info->speed = SPEED_10000; + link_info->duplex = DUPLEX_FULL; + break; + case QETH_QOAT_PHYS_SPEED_25G_FULL: + link_info->speed = SPEED_25000; + link_info->duplex = DUPLEX_FULL; + break; + case QETH_QOAT_PHYS_SPEED_UNKNOWN: + default: + link_info->speed = SPEED_UNKNOWN; + link_info->duplex = DUPLEX_UNKNOWN; + break; + } + + switch (phys_if->media_type) { + case QETH_QOAT_PHYS_MEDIA_COPPER: + link_info->port = PORT_TP; + break; + case QETH_QOAT_PHYS_MEDIA_FIBRE_SHORT: + case QETH_QOAT_PHYS_MEDIA_FIBRE_LONG: + link_info->port = PORT_FIBRE; + break; + default: + link_info->port = PORT_OTHER; + break; + } + + return 0; +} + static void qeth_init_link_info(struct qeth_card *card) { card->info.link_info.duplex = DUPLEX_FULL; @@ -4985,6 +5065,33 @@ static void qeth_init_link_info(struct qeth_card *card) card->info.link_info.port = PORT_OTHER; } } + + /* Get more accurate data via QUERY OAT: */ + if (qeth_adp_supported(card, IPA_SETADP_QUERY_OAT)) { + struct qeth_link_info link_info; + struct qeth_cmd_buffer *iob; + + iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_OAT, + SETADP_DATA_SIZEOF(query_oat)); + if (iob) { + struct qeth_ipa_cmd *cmd = __ipa_cmd(iob); + struct qeth_query_oat *oat_req; + + oat_req = &cmd->data.setadapterparms.data.query_oat; + oat_req->subcmd_code = QETH_QOAT_SCOPE_INTERFACE; + + if (!qeth_send_ipa_cmd(card, iob, + qeth_init_link_info_oat_cb, + &link_info)) { + if (link_info.speed != SPEED_UNKNOWN) + card->info.link_info.speed = link_info.speed; + if (link_info.duplex != DUPLEX_UNKNOWN) + card->info.link_info.duplex = link_info.duplex; + if (link_info.port != PORT_OTHER) + card->info.link_info.port = link_info.port; + } + } + } } /** diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 6541bab96822..e4bde7daf083 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -489,9 +489,45 @@ struct qeth_set_access_ctrl { __u8 reserved[8]; } __attribute__((packed)); +#define QETH_QOAT_PHYS_SPEED_UNKNOWN 0x00 +#define QETH_QOAT_PHYS_SPEED_10M_HALF 0x01 +#define QETH_QOAT_PHYS_SPEED_10M_FULL 0x02 +#define QETH_QOAT_PHYS_SPEED_100M_HALF 0x03 +#define QETH_QOAT_PHYS_SPEED_100M_FULL 0x04 +#define QETH_QOAT_PHYS_SPEED_1000M_HALF 0x05 +#define QETH_QOAT_PHYS_SPEED_1000M_FULL 0x06 +// n/a 0x07 +#define QETH_QOAT_PHYS_SPEED_10G_FULL 0x08 +// n/a 0x09 +#define QETH_QOAT_PHYS_SPEED_25G_FULL 0x0A + +#define QETH_QOAT_PHYS_MEDIA_COPPER 0x01 +#define QETH_QOAT_PHYS_MEDIA_FIBRE_SHORT 0x02 +#define QETH_QOAT_PHYS_MEDIA_FIBRE_LONG 0x04 + +struct qeth_query_oat_physical_if { + u8 res_head[33]; + u8 speed_duplex; + u8 media_type; + u8 res_tail[29]; +}; + +#define QETH_QOAT_REPLY_TYPE_PHYS_IF 0x0004 + +struct qeth_query_oat_reply { + u16 type; + u16 length; + u16 version; + u8 res[10]; + struct qeth_query_oat_physical_if phys_if; +}; + +#define QETH_QOAT_SCOPE_INTERFACE 0x00000001 + struct qeth_query_oat { - __u32 subcmd_code; - __u8 reserved[12]; + u32 subcmd_code; + u8 reserved[12]; + struct qeth_query_oat_reply reply[]; } __packed; struct qeth_qoat_priv { -- cgit From 235db5278316cc516de6b44e161a2afa5ccac61c Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 17 Nov 2020 17:15:20 +0100 Subject: s390/qeth: improve selection of ethtool link modes 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 Signed-off-by: Jakub Kicinski --- 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 843385f9eae0..32ea41b4356b 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 43d8a0a9c121..d9ba0586373b 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5018,13 +5018,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; } @@ -5038,6 +5044,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: @@ -5064,6 +5071,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: */ @@ -5089,6 +5098,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; } -- cgit