summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/ti/cpsw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/ti/cpsw.c')
-rw-r--r--drivers/net/ethernet/ti/cpsw.c107
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);