Forum | Documentation | Website | Blog

Skip to content
Snippets Groups Projects
Commit 014e8f1a authored by Grygorii Strashko's avatar Grygorii Strashko Committed by Vignesh Raghavendra
Browse files

net: ethernet: ti: am65-cpsw: add .ndo to set dma per-queue rate


This patch allows to rate limit TX queues (DMA) for cpsw interface by
configuring the rate in absolute Mb/s units per TX queue.

Example:
    ethtool -L eth0 tx 4

    echo 100 > /sys/class/net/eth0/queues/tx-0/tx_maxrate
    echo 200 > /sys/class/net/eth0/queues/tx-1/tx_maxrate
    echo 50 > /sys/class/net/eth0/queues/tx-2/tx_maxrate
    echo 30 > /sys/class/net/eth0/queues/tx-3/tx_maxrate

Signed-off-by: default avatarGrygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: default avatarVignesh Raghavendra <vigneshr@ti.com>
parent 508e426b
Branches
Tags
No related merge requests found
...@@ -498,6 +498,8 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common, ...@@ -498,6 +498,8 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common,
else else
am65_cpsw_init_host_port_switch(common); am65_cpsw_init_host_port_switch(common);
am65_cpsw_qos_tx_p0_rate_init(common);
for (i = 0; i < common->rx_chns.descs_num; i++) { for (i = 0; i < common->rx_chns.descs_num; i++) {
skb = __netdev_alloc_skb_ip_align(NULL, skb = __netdev_alloc_skb_ip_align(NULL,
AM65_CPSW_MAX_PACKET_SIZE, AM65_CPSW_MAX_PACKET_SIZE,
...@@ -655,8 +657,12 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev) ...@@ -655,8 +657,12 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev)
return ret; return ret;
} }
for (i = 0; i < common->tx_ch_num; i++) for (i = 0; i < common->tx_ch_num; i++) {
netdev_tx_reset_queue(netdev_get_tx_queue(ndev, i)); struct netdev_queue *txq = netdev_get_tx_queue(ndev, i);
netdev_tx_reset_queue(txq);
txq->tx_maxrate = common->tx_chns[i].rate_mbps;
}
ret = am65_cpsw_nuss_common_open(common, ndev->features); ret = am65_cpsw_nuss_common_open(common, ndev->features);
if (ret) if (ret)
...@@ -1550,6 +1556,7 @@ static const struct net_device_ops am65_cpsw_nuss_netdev_ops = { ...@@ -1550,6 +1556,7 @@ static const struct net_device_ops am65_cpsw_nuss_netdev_ops = {
.ndo_vlan_rx_kill_vid = am65_cpsw_nuss_ndo_slave_kill_vid, .ndo_vlan_rx_kill_vid = am65_cpsw_nuss_ndo_slave_kill_vid,
.ndo_do_ioctl = am65_cpsw_nuss_ndo_slave_ioctl, .ndo_do_ioctl = am65_cpsw_nuss_ndo_slave_ioctl,
.ndo_setup_tc = am65_cpsw_qos_ndo_setup_tc, .ndo_setup_tc = am65_cpsw_qos_ndo_setup_tc,
.ndo_set_tx_maxrate = am65_cpsw_qos_ndo_tx_p0_set_maxrate,
.ndo_get_devlink_port = am65_cpsw_ndo_get_devlink_port, .ndo_get_devlink_port = am65_cpsw_ndo_get_devlink_port,
}; };
...@@ -1592,6 +1599,7 @@ void am65_cpsw_nuss_remove_tx_chns(struct am65_cpsw_common *common) ...@@ -1592,6 +1599,7 @@ void am65_cpsw_nuss_remove_tx_chns(struct am65_cpsw_common *common)
devm_remove_action(dev, am65_cpsw_nuss_free_tx_chns, common); devm_remove_action(dev, am65_cpsw_nuss_free_tx_chns, common);
common->tx_ch_rate_msk = 0;
for (i = 0; i < common->tx_ch_num; i++) { for (i = 0; i < common->tx_ch_num; i++) {
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i]; struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
......
...@@ -74,6 +74,7 @@ struct am65_cpsw_tx_chn { ...@@ -74,6 +74,7 @@ struct am65_cpsw_tx_chn {
u32 id; u32 id;
u32 descs_num; u32 descs_num;
char tx_chn_name[128]; char tx_chn_name[128];
u32 rate_mbps;
}; };
struct am65_cpsw_rx_chn { struct am65_cpsw_rx_chn {
...@@ -120,6 +121,7 @@ struct am65_cpsw_common { ...@@ -120,6 +121,7 @@ struct am65_cpsw_common {
int usage_count; /* number of opened ports */ int usage_count; /* number of opened ports */
struct cpsw_ale *ale; struct cpsw_ale *ale;
int tx_ch_num; int tx_ch_num;
u32 tx_ch_rate_msk;
u32 rx_flow_id_base; u32 rx_flow_id_base;
struct am65_cpsw_tx_chn tx_chns[AM65_CPSW_MAX_TX_QUEUES]; struct am65_cpsw_tx_chn tx_chns[AM65_CPSW_MAX_TX_QUEUES];
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define AM65_CPSW_PN_REG_IET_VERIFY 0x048 #define AM65_CPSW_PN_REG_IET_VERIFY 0x048
#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050 #define AM65_CPSW_PN_REG_FIFO_STATUS 0x050
#define AM65_CPSW_PN_REG_EST_CTL 0x060 #define AM65_CPSW_PN_REG_EST_CTL 0x060
#define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri))
#define AM64_CPSW_PN_CUT_THRU 0x3C0 #define AM64_CPSW_PN_CUT_THRU 0x3C0
#define AM64_CPSW_PN_SPEED 0x3C4 #define AM64_CPSW_PN_SPEED 0x3C4
...@@ -1072,3 +1073,113 @@ static void am65_cpsw_cut_thru_link_up(struct am65_cpsw_port *port) ...@@ -1072,3 +1073,113 @@ static void am65_cpsw_cut_thru_link_up(struct am65_cpsw_port *port)
} }
am65_cpsw_cut_thru_dump(port); am65_cpsw_cut_thru_dump(port);
} }
static u32
am65_cpsw_qos_tx_rate_calc(u32 rate_mbps, unsigned long bus_freq)
{
u32 ir;
bus_freq /= 1000000;
ir = DIV_ROUND_UP(((u64)rate_mbps * 32768), bus_freq);
return ir;
}
static void
am65_cpsw_qos_tx_p0_rate_apply(struct am65_cpsw_common *common,
int tx_ch, u32 rate_mbps)
{
struct am65_cpsw_host *host = am65_common_get_host(common);
u32 ch_cir;
int i;
ch_cir = am65_cpsw_qos_tx_rate_calc(rate_mbps, common->bus_freq);
writel(ch_cir, host->port_base + AM65_CPSW_PN_REG_PRI_CIR(tx_ch));
/* update rates for every port tx queues */
for (i = 0; i < common->port_num; i++) {
struct net_device *ndev = common->ports[i].ndev;
if (!ndev)
continue;
netdev_get_tx_queue(ndev, tx_ch)->tx_maxrate = rate_mbps;
}
}
int am65_cpsw_qos_ndo_tx_p0_set_maxrate(struct net_device *ndev,
int queue, u32 rate_mbps)
{
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
struct am65_cpsw_common *common = port->common;
struct am65_cpsw_tx_chn *tx_chn;
u32 ch_rate, ch_msk, tx_ch_rate_msk_new;
int ret;
dev_dbg(common->dev, "apply TX%d rate limiting %uMbps tx_rate_msk%x\n",
queue, rate_mbps, common->tx_ch_rate_msk);
if (common->pf_p0_rx_ptype_rrobin) {
dev_err(common->dev, "TX Rate Limiting failed - rrobin mode\n");
return -EINVAL;
}
ch_rate = netdev_get_tx_queue(ndev, queue)->tx_maxrate;
if (ch_rate == rate_mbps)
return 0;
ret = pm_runtime_get_sync(common->dev);
if (ret < 0) {
pm_runtime_put_noidle(common->dev);
return ret;
}
ret = 0;
tx_ch_rate_msk_new = common->tx_ch_rate_msk;
if (rate_mbps)
tx_ch_rate_msk_new |= BIT(queue);
else
tx_ch_rate_msk_new &= ~BIT(queue);
ch_msk = GENMASK(common->tx_ch_num - 1, queue);
if (tx_ch_rate_msk_new ^ ch_msk) {
dev_err(common->dev, "TX rate limiting has to be enabled sequentially hi->lo tx_rate_msk%x\n",
common->tx_ch_rate_msk);
ret = -EINVAL;
goto exit_put;
}
tx_chn = &common->tx_chns[queue];
tx_chn->rate_mbps = rate_mbps;
if (rate_mbps)
common->tx_ch_rate_msk |= BIT(queue);
else
common->tx_ch_rate_msk &= ~BIT(queue);
if (!common->usage_count)
/* will be applied on next netif up */
goto exit_put;
am65_cpsw_qos_tx_p0_rate_apply(common, queue, rate_mbps);
exit_put:
pm_runtime_put(common->dev);
return ret;
}
void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common)
{
struct am65_cpsw_host *host = am65_common_get_host(common);
int tx_ch;
for (tx_ch = 0; tx_ch < common->tx_ch_num; tx_ch++) {
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[tx_ch];
u32 ch_cir;
if (!tx_chn->rate_mbps)
continue;
ch_cir = am65_cpsw_qos_tx_rate_calc(tx_chn->rate_mbps,
common->bus_freq);
writel(ch_cir,
host->port_base + AM65_CPSW_PN_REG_PRI_CIR(tx_ch));
}
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
struct am65_cpsw_port; struct am65_cpsw_port;
struct am65_cpsw_common;
struct am65_cpsw_est { struct am65_cpsw_est {
int buf; int buf;
...@@ -56,5 +57,8 @@ void am65_cpsw_qos_iet_init(struct net_device *ndev); ...@@ -56,5 +57,8 @@ void am65_cpsw_qos_iet_init(struct net_device *ndev);
void am65_cpsw_qos_iet_cleanup(struct net_device *ndev); void am65_cpsw_qos_iet_cleanup(struct net_device *ndev);
void am65_cpsw_qos_cut_thru_init(struct am65_cpsw_port *port); void am65_cpsw_qos_cut_thru_init(struct am65_cpsw_port *port);
void am65_cpsw_qos_cut_thru_cleanup(struct am65_cpsw_port *port); void am65_cpsw_qos_cut_thru_cleanup(struct am65_cpsw_port *port);
int am65_cpsw_qos_ndo_tx_p0_set_maxrate(struct net_device *ndev,
int queue, u32 rate_mbps);
void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common);
#endif /* AM65_CPSW_QOS_H_ */ #endif /* AM65_CPSW_QOS_H_ */
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