|
@@ -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);
|