net: ethernet: ti: cpsw: fix early budget split
authorIvan Khoronzhuk <ivan.khoronzhuk@linaro.org>
Tue, 6 Dec 2016 01:45:00 +0000 (03:45 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 6 Dec 2016 16:37:21 +0000 (11:37 -0500)
The budget split function requires the phy speed to be known.
While ndo open a phy speed identification is postponed till the
moment link is up. Hence, move it to appropriate callback, when link
is up.

Reported-by: Grygorii Strashko <grygorii.strashko@ti.com>
Fixes: 8feb0a196507 ("net: ethernet: ti: cpsw: split tx budget according between channels")
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ti/cpsw.c

index 3f96c57f3580c8ff094882f478c0d4392a8f4241..f373a4b4485779c00dfe1fe9cc56e7b95bdbf9d1 100644 (file)
@@ -753,6 +753,82 @@ requeue:
                dev_kfree_skb_any(new_skb);
 }
 
+/* split budget depending on channel rates */
+static void cpsw_split_budget(struct net_device *ndev)
+{
+       struct cpsw_priv *priv = netdev_priv(ndev);
+       struct cpsw_common *cpsw = priv->cpsw;
+       struct cpsw_vector *txv = cpsw->txv;
+       u32 consumed_rate, bigest_rate = 0;
+       int budget, bigest_rate_ch = 0;
+       struct cpsw_slave *slave;
+       int i, rlim_ch_num = 0;
+       u32 ch_rate, max_rate;
+       int ch_budget = 0;
+
+       if (cpsw->data.dual_emac)
+               slave = &cpsw->slaves[priv->emac_port];
+       else
+               slave = &cpsw->slaves[cpsw->data.active_slave];
+
+       max_rate = slave->phy->speed * 1000;
+
+       consumed_rate = 0;
+       for (i = 0; i < cpsw->tx_ch_num; i++) {
+               ch_rate = cpdma_chan_get_rate(txv[i].ch);
+               if (!ch_rate)
+                       continue;
+
+               rlim_ch_num++;
+               consumed_rate += ch_rate;
+       }
+
+       if (cpsw->tx_ch_num == rlim_ch_num) {
+               max_rate = consumed_rate;
+       } else {
+               ch_budget = (consumed_rate * CPSW_POLL_WEIGHT) / max_rate;
+               ch_budget = (CPSW_POLL_WEIGHT - ch_budget) /
+                           (cpsw->tx_ch_num - rlim_ch_num);
+               bigest_rate = (max_rate - consumed_rate) /
+                             (cpsw->tx_ch_num - rlim_ch_num);
+       }
+
+       /* split tx budget */
+       budget = CPSW_POLL_WEIGHT;
+       for (i = 0; i < cpsw->tx_ch_num; i++) {
+               ch_rate = cpdma_chan_get_rate(txv[i].ch);
+               if (ch_rate) {
+                       txv[i].budget = (ch_rate * CPSW_POLL_WEIGHT) / max_rate;
+                       if (!txv[i].budget)
+                               txv[i].budget = 1;
+                       if (ch_rate > bigest_rate) {
+                               bigest_rate_ch = i;
+                               bigest_rate = ch_rate;
+                       }
+               } else {
+                       txv[i].budget = ch_budget;
+                       if (!bigest_rate_ch)
+                               bigest_rate_ch = i;
+               }
+
+               budget -= txv[i].budget;
+       }
+
+       if (budget)
+               txv[bigest_rate_ch].budget += budget;
+
+       /* split rx budget */
+       budget = CPSW_POLL_WEIGHT;
+       ch_budget = budget / cpsw->rx_ch_num;
+       for (i = 0; i < cpsw->rx_ch_num; i++) {
+               cpsw->rxv[i].budget = ch_budget;
+               budget -= ch_budget;
+       }
+
+       if (budget)
+               cpsw->rxv[0].budget += budget;
+}
+
 static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id)
 {
        struct cpsw_common *cpsw = dev_id;
@@ -941,6 +1017,7 @@ static void cpsw_adjust_link(struct net_device *ndev)
        for_each_slave(priv, _cpsw_adjust_link, priv, &link);
 
        if (link) {
+               cpsw_split_budget(priv->ndev);
                netif_carrier_on(ndev);
                if (netif_running(ndev))
                        netif_tx_wake_all_queues(ndev);
@@ -1280,82 +1357,6 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
        }
 }
 
-/* split budget depending on channel rates */
-static void cpsw_split_budget(struct net_device *ndev)
-{
-       struct cpsw_priv *priv = netdev_priv(ndev);
-       struct cpsw_common *cpsw = priv->cpsw;
-       struct cpsw_vector *txv = cpsw->txv;
-       u32 consumed_rate, bigest_rate = 0;
-       int budget, bigest_rate_ch = 0;
-       struct cpsw_slave *slave;
-       int i, rlim_ch_num = 0;
-       u32 ch_rate, max_rate;
-       int ch_budget = 0;
-
-       if (cpsw->data.dual_emac)
-               slave = &cpsw->slaves[priv->emac_port];
-       else
-               slave = &cpsw->slaves[cpsw->data.active_slave];
-
-       max_rate = slave->phy->speed * 1000;
-
-       consumed_rate = 0;
-       for (i = 0; i < cpsw->tx_ch_num; i++) {
-               ch_rate = cpdma_chan_get_rate(txv[i].ch);
-               if (!ch_rate)
-                       continue;
-
-               rlim_ch_num++;
-               consumed_rate += ch_rate;
-       }
-
-       if (cpsw->tx_ch_num == rlim_ch_num) {
-               max_rate = consumed_rate;
-       } else {
-               ch_budget = (consumed_rate * CPSW_POLL_WEIGHT) / max_rate;
-               ch_budget = (CPSW_POLL_WEIGHT - ch_budget) /
-                           (cpsw->tx_ch_num - rlim_ch_num);
-               bigest_rate = (max_rate - consumed_rate) /
-                             (cpsw->tx_ch_num - rlim_ch_num);
-       }
-
-       /* split tx budget */
-       budget = CPSW_POLL_WEIGHT;
-       for (i = 0; i < cpsw->tx_ch_num; i++) {
-               ch_rate = cpdma_chan_get_rate(txv[i].ch);
-               if (ch_rate) {
-                       txv[i].budget = (ch_rate * CPSW_POLL_WEIGHT) / max_rate;
-                       if (!txv[i].budget)
-                               txv[i].budget = 1;
-                       if (ch_rate > bigest_rate) {
-                               bigest_rate_ch = i;
-                               bigest_rate = ch_rate;
-                       }
-               } else {
-                       txv[i].budget = ch_budget;
-                       if (!bigest_rate_ch)
-                               bigest_rate_ch = i;
-               }
-
-               budget -= txv[i].budget;
-       }
-
-       if (budget)
-               txv[bigest_rate_ch].budget += budget;
-
-       /* split rx budget */
-       budget = CPSW_POLL_WEIGHT;
-       ch_budget = budget / cpsw->rx_ch_num;
-       for (i = 0; i < cpsw->rx_ch_num; i++) {
-               cpsw->rxv[i].budget = ch_budget;
-               budget -= ch_budget;
-       }
-
-       if (budget)
-               cpsw->rxv[0].budget += budget;
-}
-
 static int cpsw_fill_rx_channels(struct cpsw_priv *priv)
 {
        struct cpsw_common *cpsw = priv->cpsw;
@@ -1501,7 +1502,6 @@ static int cpsw_ndo_open(struct net_device *ndev)
                cpsw_set_coalesce(ndev, &coal);
        }
 
-       cpsw_split_budget(ndev);
        cpdma_ctlr_start(cpsw->dma);
        cpsw_intr_enable(cpsw);