s390/qeth: keep track of wanted TX queues
authorJulian Wiedmann <jwi@linux.ibm.com>
Thu, 1 Oct 2020 17:11:30 +0000 (19:11 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 2 Oct 2020 23:22:49 +0000 (16:22 -0700)
When re-initializing a device, we can hit a situation where
qeth_osa_set_output_queues() detects that it supports more or less
HW TX queues than before. Right now we adjust dev->real_num_tx_queues
from right there, but
1. it's getting more & more complicated to cover all cases, and
2. we can't re-enable the actually expected number of TX queues later
because we lost the needed information.

So keep track of the wanted TX queues (on initial setup, and whenever
its changed via .set_channels), and later use that information when
re-enabling the netdevice.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_ethtool.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c

index f321eab..f1c9a69 100644 (file)
@@ -538,7 +538,7 @@ struct qeth_qdio_info {
        int in_buf_size;
 
        /* output */
-       int no_out_queues;
+       unsigned int no_out_queues;
        struct qeth_qdio_out_q *out_qs[QETH_MAX_OUT_QUEUES];
        struct qdio_outbuf_state *out_bufstates;
 
@@ -788,6 +788,7 @@ struct qeth_switch_info {
 
 struct qeth_priv {
        unsigned int rx_copybreak;
+       unsigned int tx_wanted_queues;
        u32 brport_hw_features;
        u32 brport_features;
 };
@@ -873,6 +874,13 @@ struct qeth_trap_id {
 /*some helper functions*/
 #define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
 
+static inline unsigned int qeth_tx_actual_queues(struct qeth_card *card)
+{
+       struct qeth_priv *priv = netdev_priv(card->dev);
+
+       return min(priv->tx_wanted_queues, card->qdio.no_out_queues);
+}
+
 static inline u16 qeth_iqd_translate_txq(struct net_device *dev, u16 txq)
 {
        if (txq == QETH_IQD_MCAST_TXQ)
@@ -1087,7 +1095,6 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
 int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
 int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
 int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
-int qeth_setup_netdev(struct qeth_card *card);
 int qeth_set_features(struct net_device *, netdev_features_t);
 void qeth_enable_hw_features(struct net_device *dev);
 netdev_features_t qeth_fix_features(struct net_device *, netdev_features_t);
index fc2c3db..b61078b 100644 (file)
@@ -1511,23 +1511,12 @@ static void qeth_drain_output_queues(struct qeth_card *card)
        }
 }
 
-static int qeth_osa_set_output_queues(struct qeth_card *card, bool single)
+static void qeth_osa_set_output_queues(struct qeth_card *card, bool single)
 {
        unsigned int max = single ? 1 : card->dev->num_tx_queues;
-       unsigned int count;
-       int rc;
-
-       count = IS_VM_NIC(card) ? min(max, card->dev->real_num_tx_queues) : max;
-
-       rtnl_lock();
-       rc = netif_set_real_num_tx_queues(card->dev, count);
-       rtnl_unlock();
-
-       if (rc)
-               return rc;
 
        if (card->qdio.no_out_queues == max)
-               return 0;
+               return;
 
        if (atomic_read(&card->qdio.state) != QETH_QDIO_UNINITIALIZED)
                qeth_free_qdio_queues(card);
@@ -1536,14 +1525,12 @@ static int qeth_osa_set_output_queues(struct qeth_card *card, bool single)
                dev_info(&card->gdev->dev, "Priority Queueing not supported\n");
 
        card->qdio.no_out_queues = max;
-       return 0;
 }
 
 static int qeth_update_from_chp_desc(struct qeth_card *card)
 {
        struct ccw_device *ccwdev;
        struct channel_path_desc_fmt0 *chp_dsc;
-       int rc = 0;
 
        QETH_CARD_TEXT(card, 2, "chp_desc");
 
@@ -1556,12 +1543,12 @@ static int qeth_update_from_chp_desc(struct qeth_card *card)
 
        if (IS_OSD(card) || IS_OSX(card))
                /* CHPP field bit 6 == 1 -> single queue */
-               rc = qeth_osa_set_output_queues(card, chp_dsc->chpp & 0x02);
+               qeth_osa_set_output_queues(card, chp_dsc->chpp & 0x02);
 
        kfree(chp_dsc);
        QETH_CARD_TEXT_(card, 2, "nr:%x", card->qdio.no_out_queues);
        QETH_CARD_TEXT_(card, 2, "lvl:%02x", card->info.func_level);
-       return rc;
+       return 0;
 }
 
 static void qeth_init_qdio_info(struct qeth_card *card)
@@ -5316,6 +5303,20 @@ static int qeth_set_online(struct qeth_card *card)
 
        qeth_print_status_message(card);
 
+       if (card->dev->reg_state != NETREG_REGISTERED) {
+               struct qeth_priv *priv = netdev_priv(card->dev);
+
+               if (IS_IQD(card))
+                       priv->tx_wanted_queues = QETH_IQD_MIN_TXQ;
+               else if (IS_VM_NIC(card))
+                       priv->tx_wanted_queues = 1;
+               else
+                       priv->tx_wanted_queues = card->dev->num_tx_queues;
+
+               /* no need for locking / error handling at this early stage: */
+               qeth_set_real_num_tx_queues(card, qeth_tx_actual_queues(card));
+       }
+
        rc = card->discipline->set_online(card, carrier_ok);
        if (rc)
                goto err_online;
@@ -6250,8 +6251,16 @@ static struct net_device *qeth_alloc_netdev(struct qeth_card *card)
        SET_NETDEV_DEV(dev, &card->gdev->dev);
        netif_carrier_off(dev);
 
-       dev->ethtool_ops = IS_OSN(card) ? &qeth_osn_ethtool_ops :
-                                         &qeth_ethtool_ops;
+       if (IS_OSN(card)) {
+               dev->ethtool_ops = &qeth_osn_ethtool_ops;
+       } else {
+               dev->ethtool_ops = &qeth_ethtool_ops;
+               dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+               dev->hw_features |= NETIF_F_SG;
+               dev->vlan_features |= NETIF_F_SG;
+               if (IS_IQD(card))
+                       dev->features |= NETIF_F_SG;
+       }
 
        return dev;
 }
@@ -6267,28 +6276,6 @@ struct net_device *qeth_clone_netdev(struct net_device *orig)
        return clone;
 }
 
-int qeth_setup_netdev(struct qeth_card *card)
-{
-       struct net_device *dev = card->dev;
-       unsigned int num_tx_queues;
-
-       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
-       dev->hw_features |= NETIF_F_SG;
-       dev->vlan_features |= NETIF_F_SG;
-
-       if (IS_IQD(card)) {
-               dev->features |= NETIF_F_SG;
-               num_tx_queues = QETH_IQD_MIN_TXQ;
-       } else if (IS_VM_NIC(card)) {
-               num_tx_queues = 1;
-       } else {
-               num_tx_queues = dev->real_num_tx_queues;
-       }
-
-       return qeth_set_real_num_tx_queues(card, num_tx_queues);
-}
-EXPORT_SYMBOL_GPL(qeth_setup_netdev);
-
 static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card;
@@ -6959,6 +6946,7 @@ int qeth_set_real_num_tx_queues(struct qeth_card *card, unsigned int count)
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(qeth_set_real_num_tx_queues);
 
 u16 qeth_iqd_select_queue(struct net_device *dev, struct sk_buff *skb,
                          u8 cast_type, struct net_device *sb_dev)
index f870c53..bc3ea0e 100644 (file)
@@ -211,7 +211,9 @@ static void qeth_get_channels(struct net_device *dev,
 static int qeth_set_channels(struct net_device *dev,
                             struct ethtool_channels *channels)
 {
+       struct qeth_priv *priv = netdev_priv(dev);
        struct qeth_card *card = dev->ml_priv;
+       int rc;
 
        if (channels->rx_count == 0 || channels->tx_count == 0)
                return -EINVAL;
@@ -234,7 +236,11 @@ static int qeth_set_channels(struct net_device *dev,
                        return -EOPNOTSUPP;
        }
 
-       return qeth_set_real_num_tx_queues(card, channels->tx_count);
+       rc = qeth_set_real_num_tx_queues(card, channels->tx_count);
+       if (!rc)
+               priv->tx_wanted_queues = channels->tx_count;
+
+       return rc;
 }
 
 static int qeth_get_ts_info(struct net_device *dev,
index 1852d0a..290389f 100644 (file)
@@ -894,18 +894,12 @@ static const struct net_device_ops qeth_osn_netdev_ops = {
 
 static int qeth_l2_setup_netdev(struct qeth_card *card)
 {
-       int rc;
-
        if (IS_OSN(card)) {
                card->dev->netdev_ops = &qeth_osn_netdev_ops;
                card->dev->flags |= IFF_NOARP;
                goto add_napi;
        }
 
-       rc = qeth_setup_netdev(card);
-       if (rc)
-               return rc;
-
        card->dev->needed_headroom = sizeof(struct qeth_hdr);
        card->dev->netdev_ops = &qeth_l2_netdev_ops;
        card->dev->priv_flags |= IFF_UNICAST_FLT;
@@ -2274,6 +2268,13 @@ static int qeth_l2_set_online(struct qeth_card *card, bool carrier_ok)
                        netif_carrier_on(dev);
        } else {
                rtnl_lock();
+               rc = qeth_set_real_num_tx_queues(card,
+                                                qeth_tx_actual_queues(card));
+               if (rc) {
+                       rtnl_unlock();
+                       goto err_set_queues;
+               }
+
                if (carrier_ok)
                        netif_carrier_on(dev);
                else
@@ -2291,6 +2292,7 @@ static int qeth_l2_set_online(struct qeth_card *card, bool carrier_ok)
        }
        return 0;
 
+err_set_queues:
 err_setup:
        qeth_set_allowed_threads(card, 0, 1);
        card->state = CARD_STATE_DOWN;
index a6f8878..ea5f258 100644 (file)
@@ -1875,10 +1875,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
        unsigned int headroom;
        int rc;
 
-       rc = qeth_setup_netdev(card);
-       if (rc)
-               return rc;
-
        if (IS_OSD(card) || IS_OSX(card)) {
                card->dev->netdev_ops = &qeth_l3_osa_netdev_ops;
 
@@ -2022,6 +2018,13 @@ static int qeth_l3_set_online(struct qeth_card *card, bool carrier_ok)
                        netif_carrier_on(dev);
        } else {
                rtnl_lock();
+               rc = qeth_set_real_num_tx_queues(card,
+                                                qeth_tx_actual_queues(card));
+               if (rc) {
+                       rtnl_unlock();
+                       goto err_set_queues;
+               }
+
                if (carrier_ok)
                        netif_carrier_on(dev);
                else
@@ -2038,6 +2041,7 @@ static int qeth_l3_set_online(struct qeth_card *card, bool carrier_ok)
        }
        return 0;
 
+err_set_queues:
 err_setup:
        qeth_set_allowed_threads(card, 0, 1);
        card->state = CARD_STATE_DOWN;