diff options
Diffstat (limited to 'drivers/net/ethernet/ti/cpsw.c')
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 107 |
1 files changed, 34 insertions, 73 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 23213a369c43..a2c2c06e38e4 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -753,27 +753,18 @@ requeue: dev_kfree_skb_any(new_skb); } -/* split budget depending on channel rates */ -static void cpsw_split_budget(struct net_device *ndev) +static void cpsw_split_res(struct net_device *ndev) { struct cpsw_priv *priv = netdev_priv(ndev); + u32 consumed_rate = 0, bigest_rate = 0; struct cpsw_common *cpsw = priv->cpsw; struct cpsw_vector *txv = cpsw->txv; - u32 consumed_rate, bigest_rate = 0; + int i, ch_weight, rlim_ch_num = 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) @@ -785,7 +776,14 @@ static void cpsw_split_budget(struct net_device *ndev) if (cpsw->tx_ch_num == rlim_ch_num) { max_rate = consumed_rate; + } else if (!rlim_ch_num) { + ch_budget = CPSW_POLL_WEIGHT / cpsw->tx_ch_num; + bigest_rate = 0; + max_rate = consumed_rate; } else { + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + max_rate = slave->phy->speed * 1000; + ch_budget = (consumed_rate * CPSW_POLL_WEIGHT) / max_rate; ch_budget = (CPSW_POLL_WEIGHT - ch_budget) / (cpsw->tx_ch_num - rlim_ch_num); @@ -793,22 +791,28 @@ static void cpsw_split_budget(struct net_device *ndev) (cpsw->tx_ch_num - rlim_ch_num); } - /* split tx budget */ + /* split tx weight/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; + txv[i].budget++; if (ch_rate > bigest_rate) { bigest_rate_ch = i; bigest_rate = ch_rate; } + + ch_weight = (ch_rate * 100) / max_rate; + if (!ch_weight) + ch_weight++; + cpdma_chan_set_weight(cpsw->txv[i].ch, ch_weight); } else { txv[i].budget = ch_budget; if (!bigest_rate_ch) bigest_rate_ch = i; + cpdma_chan_set_weight(cpsw->txv[i].ch, 0); } budget -= txv[i].budget; @@ -1017,7 +1021,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); + cpsw_split_res(priv->ndev); netif_carrier_on(ndev); if (netif_running(ndev)) netif_tx_wake_all_queues(ndev); @@ -1962,64 +1966,25 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, static int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) { struct cpsw_priv *priv = netdev_priv(ndev); - int tx_ch_num = ndev->real_num_tx_queues; - u32 consumed_rate, min_rate, max_rate; struct cpsw_common *cpsw = priv->cpsw; - struct cpsw_slave *slave; - int ret, i, weight; - int rlim_num = 0; + u32 min_rate; u32 ch_rate; + int ret; ch_rate = netdev_get_tx_queue(ndev, queue)->tx_maxrate; if (ch_rate == rate) return 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; - - consumed_rate = 0; - for (i = 0; i < tx_ch_num; i++) { - if (i == queue) - ch_rate = rate; - else - ch_rate = netdev_get_tx_queue(ndev, i)->tx_maxrate; - if (!ch_rate) - continue; - - rlim_num++; - consumed_rate += ch_rate; - } - - if (consumed_rate > max_rate) - dev_info(priv->dev, "The common rate shouldn't be more than %dMbps", - max_rate); - - if (consumed_rate > max_rate) { - if (max_rate == 10 && consumed_rate <= 100) { - max_rate = 100; - } else if (max_rate <= 100 && consumed_rate <= 1000) { - max_rate = 1000; - } else { - dev_err(priv->dev, "The common rate cannot be more than %dMbps", - max_rate); - return -EINVAL; - } - } - - if (consumed_rate > max_rate) { - dev_err(priv->dev, "The common rate cannot be more than %dMbps", - max_rate); + ch_rate = rate * 1000; + min_rate = cpdma_chan_get_min_rate(cpsw->dma); + if ((ch_rate < min_rate && ch_rate)) { + dev_err(priv->dev, "The channel rate cannot be less than %dMbps", + min_rate); return -EINVAL; } - rate *= 1000; - min_rate = cpdma_chan_get_min_rate(cpsw->dma); - if ((rate < min_rate && rate)) { - dev_err(priv->dev, "The common rate cannot be less than %dMbps", - min_rate); + if (rate > 2000) { + dev_err(priv->dev, "The channel rate cannot be more than 2Gbps"); return -EINVAL; } @@ -2029,17 +1994,13 @@ static int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) return ret; } - if (rlim_num == tx_ch_num) - max_rate = consumed_rate; + ret = cpdma_chan_set_rate(cpsw->txv[queue].ch, ch_rate); + pm_runtime_put(cpsw->dev); - weight = (rate * 100) / (max_rate * 1000); - cpdma_chan_set_weight(cpsw->txv[queue].ch, weight); - ret = cpdma_chan_set_rate(cpsw->txv[queue].ch, rate); + if (ret) + return ret; - /* re-split budget between channels */ - if (!rate) - cpsw_split_budget(ndev); - pm_runtime_put(cpsw->dev); + cpsw_split_res(ndev); return ret; } @@ -2399,7 +2360,7 @@ static int cpsw_set_channels(struct net_device *ndev, if (ret) goto err; - cpsw_split_budget(ndev); + cpsw_split_res(ndev); /* After this receive is started */ cpdma_ctlr_start(cpsw->dma); |