Commit 32b78d85 authored by Ivan Khoronzhuk's avatar Ivan Khoronzhuk Committed by David S. Miller

net: ethernet: ti: cpsw: combine budget and weight split and check

Re-split weight along with budget. It simplify code a little
and update state after every rate change. Also it's necessarily
to move arguments checks to this combined function. Replace
maximum rate check for an interface on maximum possible rate.
Signed-off-by: default avatarIvan Khoronzhuk <ivan.khoronzhuk@linaro.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 32b5f2d1
...@@ -753,27 +753,18 @@ static void cpsw_rx_handler(void *token, int len, int status) ...@@ -753,27 +753,18 @@ static void cpsw_rx_handler(void *token, int len, int status)
dev_kfree_skb_any(new_skb); dev_kfree_skb_any(new_skb);
} }
/* split budget depending on channel rates */ static void cpsw_split_res(struct net_device *ndev)
static void cpsw_split_budget(struct net_device *ndev)
{ {
struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_priv *priv = netdev_priv(ndev);
u32 consumed_rate = 0, bigest_rate = 0;
struct cpsw_common *cpsw = priv->cpsw; struct cpsw_common *cpsw = priv->cpsw;
struct cpsw_vector *txv = cpsw->txv; 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; int budget, bigest_rate_ch = 0;
struct cpsw_slave *slave; struct cpsw_slave *slave;
int i, rlim_ch_num = 0;
u32 ch_rate, max_rate; u32 ch_rate, max_rate;
int ch_budget = 0; 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++) { for (i = 0; i < cpsw->tx_ch_num; i++) {
ch_rate = cpdma_chan_get_rate(txv[i].ch); ch_rate = cpdma_chan_get_rate(txv[i].ch);
if (!ch_rate) if (!ch_rate)
...@@ -785,7 +776,14 @@ static void cpsw_split_budget(struct net_device *ndev) ...@@ -785,7 +776,14 @@ static void cpsw_split_budget(struct net_device *ndev)
if (cpsw->tx_ch_num == rlim_ch_num) { if (cpsw->tx_ch_num == rlim_ch_num) {
max_rate = consumed_rate; 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 { } 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 = (consumed_rate * CPSW_POLL_WEIGHT) / max_rate;
ch_budget = (CPSW_POLL_WEIGHT - ch_budget) / ch_budget = (CPSW_POLL_WEIGHT - ch_budget) /
(cpsw->tx_ch_num - rlim_ch_num); (cpsw->tx_ch_num - rlim_ch_num);
...@@ -793,22 +791,28 @@ static void cpsw_split_budget(struct net_device *ndev) ...@@ -793,22 +791,28 @@ static void cpsw_split_budget(struct net_device *ndev)
(cpsw->tx_ch_num - rlim_ch_num); (cpsw->tx_ch_num - rlim_ch_num);
} }
/* split tx budget */ /* split tx weight/budget */
budget = CPSW_POLL_WEIGHT; budget = CPSW_POLL_WEIGHT;
for (i = 0; i < cpsw->tx_ch_num; i++) { for (i = 0; i < cpsw->tx_ch_num; i++) {
ch_rate = cpdma_chan_get_rate(txv[i].ch); ch_rate = cpdma_chan_get_rate(txv[i].ch);
if (ch_rate) { if (ch_rate) {
txv[i].budget = (ch_rate * CPSW_POLL_WEIGHT) / max_rate; txv[i].budget = (ch_rate * CPSW_POLL_WEIGHT) / max_rate;
if (!txv[i].budget) if (!txv[i].budget)
txv[i].budget = 1; txv[i].budget++;
if (ch_rate > bigest_rate) { if (ch_rate > bigest_rate) {
bigest_rate_ch = i; bigest_rate_ch = i;
bigest_rate = ch_rate; 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 { } else {
txv[i].budget = ch_budget; txv[i].budget = ch_budget;
if (!bigest_rate_ch) if (!bigest_rate_ch)
bigest_rate_ch = i; bigest_rate_ch = i;
cpdma_chan_set_weight(cpsw->txv[i].ch, 0);
} }
budget -= txv[i].budget; budget -= txv[i].budget;
...@@ -1017,7 +1021,7 @@ static void cpsw_adjust_link(struct net_device *ndev) ...@@ -1017,7 +1021,7 @@ static void cpsw_adjust_link(struct net_device *ndev)
for_each_slave(priv, _cpsw_adjust_link, priv, &link); for_each_slave(priv, _cpsw_adjust_link, priv, &link);
if (link) { if (link) {
cpsw_split_budget(priv->ndev); cpsw_split_res(priv->ndev);
netif_carrier_on(ndev); netif_carrier_on(ndev);
if (netif_running(ndev)) if (netif_running(ndev))
netif_tx_wake_all_queues(ndev); netif_tx_wake_all_queues(ndev);
...@@ -1962,64 +1966,25 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *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) static int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate)
{ {
struct cpsw_priv *priv = netdev_priv(ndev); 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_common *cpsw = priv->cpsw;
struct cpsw_slave *slave; u32 min_rate;
int ret, i, weight;
int rlim_num = 0;
u32 ch_rate; u32 ch_rate;
int ret;
ch_rate = netdev_get_tx_queue(ndev, queue)->tx_maxrate; ch_rate = netdev_get_tx_queue(ndev, queue)->tx_maxrate;
if (ch_rate == rate) if (ch_rate == rate)
return 0; return 0;
if (cpsw->data.dual_emac) ch_rate = rate * 1000;
slave = &cpsw->slaves[priv->emac_port]; min_rate = cpdma_chan_get_min_rate(cpsw->dma);
else if ((ch_rate < min_rate && ch_rate)) {
slave = &cpsw->slaves[cpsw->data.active_slave]; dev_err(priv->dev, "The channel rate cannot be less than %dMbps",
max_rate = slave->phy->speed; min_rate);
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);
return -EINVAL; return -EINVAL;
} }
rate *= 1000; if (rate > 2000) {
min_rate = cpdma_chan_get_min_rate(cpsw->dma); dev_err(priv->dev, "The channel rate cannot be more than 2Gbps");
if ((rate < min_rate && rate)) {
dev_err(priv->dev, "The common rate cannot be less than %dMbps",
min_rate);
return -EINVAL; return -EINVAL;
} }
...@@ -2029,17 +1994,13 @@ static int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) ...@@ -2029,17 +1994,13 @@ static int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate)
return ret; return ret;
} }
if (rlim_num == tx_ch_num) ret = cpdma_chan_set_rate(cpsw->txv[queue].ch, ch_rate);
max_rate = consumed_rate; pm_runtime_put(cpsw->dev);
weight = (rate * 100) / (max_rate * 1000); if (ret)
cpdma_chan_set_weight(cpsw->txv[queue].ch, weight); return ret;
ret = cpdma_chan_set_rate(cpsw->txv[queue].ch, rate);
/* re-split budget between channels */ cpsw_split_res(ndev);
if (!rate)
cpsw_split_budget(ndev);
pm_runtime_put(cpsw->dev);
return ret; return ret;
} }
...@@ -2399,7 +2360,7 @@ static int cpsw_set_channels(struct net_device *ndev, ...@@ -2399,7 +2360,7 @@ static int cpsw_set_channels(struct net_device *ndev,
if (ret) if (ret)
goto err; goto err;
cpsw_split_budget(ndev); cpsw_split_res(ndev);
/* After this receive is started */ /* After this receive is started */
cpdma_ctlr_start(cpsw->dma); cpdma_ctlr_start(cpsw->dma);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment