Skip to content

Commit db2f284

Browse files
elvinongbldavem330
authored andcommitted
net: stmmac: add per-queue TX & RX coalesce ethtool support
Extending the driver to support per-queue RX and TX coalesce settings in order to support below commands: To show per-queue coalesce setting:- $ ethtool --per-queue <DEVNAME> queue_mask <MASK> --show-coalesce To set per-queue coalesce setting:- $ ethtool --per-queue <DEVNAME> queue_mask <MASK> --coalesce \ [rx-usecs N] [rx-frames M] [tx-usecs P] [tx-frames Q] Signed-off-by: Ong Boon Leong <[email protected]> Acked-by: Jakub Kicinski <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6ef4f40 commit db2f284

File tree

7 files changed

+143
-49
lines changed

7 files changed

+143
-49
lines changed

drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ static void dwmac1000_get_hw_feature(void __iomem *ioaddr,
255255
}
256256

257257
static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt,
258-
u32 number_chan)
258+
u32 queue)
259259
{
260260
writel(riwt, ioaddr + DMA_RX_WATCHDOG);
261261
}

drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,9 @@ static void dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
210210
_dwmac4_dump_dma_regs(ioaddr, i, reg_space);
211211
}
212212

213-
static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 number_chan)
213+
static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 queue)
214214
{
215-
u32 chan;
216-
217-
for (chan = 0; chan < number_chan; chan++)
218-
writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(chan));
215+
writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(queue));
219216
}
220217

221218
static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,

drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -441,12 +441,9 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
441441
dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
442442
}
443443

444-
static void dwxgmac2_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 nchan)
444+
static void dwxgmac2_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 queue)
445445
{
446-
u32 i;
447-
448-
for (i = 0; i < nchan; i++)
449-
writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(i));
446+
writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(queue));
450447
}
451448

452449
static void dwxgmac2_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)

drivers/net/ethernet/stmicro/stmmac/hwif.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ struct stmmac_dma_ops {
206206
void (*get_hw_feature)(void __iomem *ioaddr,
207207
struct dma_features *dma_cap);
208208
/* Program the HW RX Watchdog */
209-
void (*rx_watchdog)(void __iomem *ioaddr, u32 riwt, u32 number_chan);
209+
void (*rx_watchdog)(void __iomem *ioaddr, u32 riwt, u32 queue);
210210
void (*set_tx_ring_len)(void __iomem *ioaddr, u32 len, u32 chan);
211211
void (*set_rx_ring_len)(void __iomem *ioaddr, u32 len, u32 chan);
212212
void (*set_rx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);

drivers/net/ethernet/stmicro/stmmac/stmmac.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ struct stmmac_flow_entry {
147147

148148
struct stmmac_priv {
149149
/* Frequently used values are kept adjacent for cache effect */
150-
u32 tx_coal_frames;
151-
u32 tx_coal_timer;
152-
u32 rx_coal_frames;
150+
u32 tx_coal_frames[MTL_MAX_TX_QUEUES];
151+
u32 tx_coal_timer[MTL_MAX_TX_QUEUES];
152+
u32 rx_coal_frames[MTL_MAX_TX_QUEUES];
153153

154154
int tx_coalesce;
155155
int hwts_tx_en;
@@ -160,7 +160,7 @@ struct stmmac_priv {
160160

161161
unsigned int dma_buf_sz;
162162
unsigned int rx_copybreak;
163-
u32 rx_riwt;
163+
u32 rx_riwt[MTL_MAX_TX_QUEUES];
164164
int hwts_rx_en;
165165

166166
void __iomem *ioaddr;

drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c

Lines changed: 103 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -756,37 +756,99 @@ static u32 stmmac_riwt2usec(u32 riwt, struct stmmac_priv *priv)
756756
return (riwt * 256) / (clk / 1000000);
757757
}
758758

759-
static int stmmac_get_coalesce(struct net_device *dev,
760-
struct ethtool_coalesce *ec)
759+
static int __stmmac_get_coalesce(struct net_device *dev,
760+
struct ethtool_coalesce *ec,
761+
int queue)
761762
{
762763
struct stmmac_priv *priv = netdev_priv(dev);
764+
u32 max_cnt;
765+
u32 rx_cnt;
766+
u32 tx_cnt;
763767

764-
ec->tx_coalesce_usecs = priv->tx_coal_timer;
765-
ec->tx_max_coalesced_frames = priv->tx_coal_frames;
768+
rx_cnt = priv->plat->rx_queues_to_use;
769+
tx_cnt = priv->plat->tx_queues_to_use;
770+
max_cnt = max(rx_cnt, tx_cnt);
766771

767-
if (priv->use_riwt) {
768-
ec->rx_max_coalesced_frames = priv->rx_coal_frames;
769-
ec->rx_coalesce_usecs = stmmac_riwt2usec(priv->rx_riwt, priv);
772+
if (queue < 0)
773+
queue = 0;
774+
else if (queue >= max_cnt)
775+
return -EINVAL;
776+
777+
if (queue < tx_cnt) {
778+
ec->tx_coalesce_usecs = priv->tx_coal_timer[queue];
779+
ec->tx_max_coalesced_frames = priv->tx_coal_frames[queue];
780+
} else {
781+
ec->tx_coalesce_usecs = 0;
782+
ec->tx_max_coalesced_frames = 0;
783+
}
784+
785+
if (priv->use_riwt && queue < rx_cnt) {
786+
ec->rx_max_coalesced_frames = priv->rx_coal_frames[queue];
787+
ec->rx_coalesce_usecs = stmmac_riwt2usec(priv->rx_riwt[queue],
788+
priv);
789+
} else {
790+
ec->rx_max_coalesced_frames = 0;
791+
ec->rx_coalesce_usecs = 0;
770792
}
771793

772794
return 0;
773795
}
774796

775-
static int stmmac_set_coalesce(struct net_device *dev,
797+
static int stmmac_get_coalesce(struct net_device *dev,
776798
struct ethtool_coalesce *ec)
799+
{
800+
return __stmmac_get_coalesce(dev, ec, -1);
801+
}
802+
803+
static int stmmac_get_per_queue_coalesce(struct net_device *dev, u32 queue,
804+
struct ethtool_coalesce *ec)
805+
{
806+
return __stmmac_get_coalesce(dev, ec, queue);
807+
}
808+
809+
static int __stmmac_set_coalesce(struct net_device *dev,
810+
struct ethtool_coalesce *ec,
811+
int queue)
777812
{
778813
struct stmmac_priv *priv = netdev_priv(dev);
779-
u32 rx_cnt = priv->plat->rx_queues_to_use;
814+
bool all_queues = false;
780815
unsigned int rx_riwt;
816+
u32 max_cnt;
817+
u32 rx_cnt;
818+
u32 tx_cnt;
819+
820+
rx_cnt = priv->plat->rx_queues_to_use;
821+
tx_cnt = priv->plat->tx_queues_to_use;
822+
max_cnt = max(rx_cnt, tx_cnt);
823+
824+
if (queue < 0)
825+
all_queues = true;
826+
else if (queue >= max_cnt)
827+
return -EINVAL;
781828

782829
if (priv->use_riwt && (ec->rx_coalesce_usecs > 0)) {
783830
rx_riwt = stmmac_usec2riwt(ec->rx_coalesce_usecs, priv);
784831

785832
if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT))
786833
return -EINVAL;
787834

788-
priv->rx_riwt = rx_riwt;
789-
stmmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt);
835+
if (all_queues) {
836+
int i;
837+
838+
for (i = 0; i < rx_cnt; i++) {
839+
priv->rx_riwt[i] = rx_riwt;
840+
stmmac_rx_watchdog(priv, priv->ioaddr,
841+
rx_riwt, i);
842+
priv->rx_coal_frames[i] =
843+
ec->rx_max_coalesced_frames;
844+
}
845+
} else if (queue < rx_cnt) {
846+
priv->rx_riwt[queue] = rx_riwt;
847+
stmmac_rx_watchdog(priv, priv->ioaddr,
848+
rx_riwt, queue);
849+
priv->rx_coal_frames[queue] =
850+
ec->rx_max_coalesced_frames;
851+
}
790852
}
791853

792854
if ((ec->tx_coalesce_usecs == 0) &&
@@ -797,13 +859,37 @@ static int stmmac_set_coalesce(struct net_device *dev,
797859
(ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES))
798860
return -EINVAL;
799861

800-
/* Only copy relevant parameters, ignore all others. */
801-
priv->tx_coal_frames = ec->tx_max_coalesced_frames;
802-
priv->tx_coal_timer = ec->tx_coalesce_usecs;
803-
priv->rx_coal_frames = ec->rx_max_coalesced_frames;
862+
if (all_queues) {
863+
int i;
864+
865+
for (i = 0; i < tx_cnt; i++) {
866+
priv->tx_coal_frames[i] =
867+
ec->tx_max_coalesced_frames;
868+
priv->tx_coal_timer[i] =
869+
ec->tx_coalesce_usecs;
870+
}
871+
} else if (queue < tx_cnt) {
872+
priv->tx_coal_frames[queue] =
873+
ec->tx_max_coalesced_frames;
874+
priv->tx_coal_timer[queue] =
875+
ec->tx_coalesce_usecs;
876+
}
877+
804878
return 0;
805879
}
806880

881+
static int stmmac_set_coalesce(struct net_device *dev,
882+
struct ethtool_coalesce *ec)
883+
{
884+
return __stmmac_set_coalesce(dev, ec, -1);
885+
}
886+
887+
static int stmmac_set_per_queue_coalesce(struct net_device *dev, u32 queue,
888+
struct ethtool_coalesce *ec)
889+
{
890+
return __stmmac_set_coalesce(dev, ec, queue);
891+
}
892+
807893
static int stmmac_get_rxnfc(struct net_device *dev,
808894
struct ethtool_rxnfc *rxnfc, u32 *rule_locs)
809895
{
@@ -1001,6 +1087,8 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
10011087
.get_ts_info = stmmac_get_ts_info,
10021088
.get_coalesce = stmmac_get_coalesce,
10031089
.set_coalesce = stmmac_set_coalesce,
1090+
.get_per_queue_coalesce = stmmac_get_per_queue_coalesce,
1091+
.set_per_queue_coalesce = stmmac_set_per_queue_coalesce,
10041092
.get_channels = stmmac_get_channels,
10051093
.set_channels = stmmac_set_channels,
10061094
.get_tunable = stmmac_get_tunable,

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2234,7 +2234,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
22342234

22352235
/* We still have pending packets, let's call for a new scheduling */
22362236
if (tx_q->dirty_tx != tx_q->cur_tx)
2237-
hrtimer_start(&tx_q->txtimer, STMMAC_COAL_TIMER(priv->tx_coal_timer),
2237+
hrtimer_start(&tx_q->txtimer,
2238+
STMMAC_COAL_TIMER(priv->tx_coal_timer[queue]),
22382239
HRTIMER_MODE_REL);
22392240

22402241
__netif_tx_unlock_bh(netdev_get_tx_queue(priv->dev, queue));
@@ -2519,7 +2520,8 @@ static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue)
25192520
{
25202521
struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
25212522

2522-
hrtimer_start(&tx_q->txtimer, STMMAC_COAL_TIMER(priv->tx_coal_timer),
2523+
hrtimer_start(&tx_q->txtimer,
2524+
STMMAC_COAL_TIMER(priv->tx_coal_timer[queue]),
25232525
HRTIMER_MODE_REL);
25242526
}
25252527

@@ -2560,18 +2562,21 @@ static enum hrtimer_restart stmmac_tx_timer(struct hrtimer *t)
25602562
static void stmmac_init_coalesce(struct stmmac_priv *priv)
25612563
{
25622564
u32 tx_channel_count = priv->plat->tx_queues_to_use;
2565+
u32 rx_channel_count = priv->plat->rx_queues_to_use;
25632566
u32 chan;
25642567

2565-
priv->tx_coal_frames = STMMAC_TX_FRAMES;
2566-
priv->tx_coal_timer = STMMAC_COAL_TX_TIMER;
2567-
priv->rx_coal_frames = STMMAC_RX_FRAMES;
2568-
25692568
for (chan = 0; chan < tx_channel_count; chan++) {
25702569
struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan];
25712570

2571+
priv->tx_coal_frames[chan] = STMMAC_TX_FRAMES;
2572+
priv->tx_coal_timer[chan] = STMMAC_COAL_TX_TIMER;
2573+
25722574
hrtimer_init(&tx_q->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
25732575
tx_q->txtimer.function = stmmac_tx_timer;
25742576
}
2577+
2578+
for (chan = 0; chan < rx_channel_count; chan++)
2579+
priv->rx_coal_frames[chan] = STMMAC_RX_FRAMES;
25752580
}
25762581

25772582
static void stmmac_set_rings_length(struct stmmac_priv *priv)
@@ -2876,10 +2881,15 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
28762881
priv->tx_lpi_timer = eee_timer * 1000;
28772882

28782883
if (priv->use_riwt) {
2879-
if (!priv->rx_riwt)
2880-
priv->rx_riwt = DEF_DMA_RIWT;
2884+
u32 queue;
2885+
2886+
for (queue = 0; queue < rx_cnt; queue++) {
2887+
if (!priv->rx_riwt[queue])
2888+
priv->rx_riwt[queue] = DEF_DMA_RIWT;
28812889

2882-
ret = stmmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt);
2890+
stmmac_rx_watchdog(priv, priv->ioaddr,
2891+
priv->rx_riwt[queue], queue);
2892+
}
28832893
}
28842894

28852895
if (priv->hw->pcs)
@@ -3378,11 +3388,12 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
33783388

33793389
if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en)
33803390
set_ic = true;
3381-
else if (!priv->tx_coal_frames)
3391+
else if (!priv->tx_coal_frames[queue])
33823392
set_ic = false;
3383-
else if (tx_packets > priv->tx_coal_frames)
3393+
else if (tx_packets > priv->tx_coal_frames[queue])
33843394
set_ic = true;
3385-
else if ((tx_q->tx_count_frames % priv->tx_coal_frames) < tx_packets)
3395+
else if ((tx_q->tx_count_frames %
3396+
priv->tx_coal_frames[queue]) < tx_packets)
33863397
set_ic = true;
33873398
else
33883399
set_ic = false;
@@ -3607,11 +3618,12 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
36073618

36083619
if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en)
36093620
set_ic = true;
3610-
else if (!priv->tx_coal_frames)
3621+
else if (!priv->tx_coal_frames[queue])
36113622
set_ic = false;
3612-
else if (tx_packets > priv->tx_coal_frames)
3623+
else if (tx_packets > priv->tx_coal_frames[queue])
36133624
set_ic = true;
3614-
else if ((tx_q->tx_count_frames % priv->tx_coal_frames) < tx_packets)
3625+
else if ((tx_q->tx_count_frames %
3626+
priv->tx_coal_frames[queue]) < tx_packets)
36153627
set_ic = true;
36163628
else
36173629
set_ic = false;
@@ -3810,11 +3822,11 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
38103822
stmmac_refill_desc3(priv, rx_q, p);
38113823

38123824
rx_q->rx_count_frames++;
3813-
rx_q->rx_count_frames += priv->rx_coal_frames;
3814-
if (rx_q->rx_count_frames > priv->rx_coal_frames)
3825+
rx_q->rx_count_frames += priv->rx_coal_frames[queue];
3826+
if (rx_q->rx_count_frames > priv->rx_coal_frames[queue])
38153827
rx_q->rx_count_frames = 0;
38163828

3817-
use_rx_wd = !priv->rx_coal_frames;
3829+
use_rx_wd = !priv->rx_coal_frames[queue];
38183830
use_rx_wd |= rx_q->rx_count_frames > 0;
38193831
if (!priv->use_riwt)
38203832
use_rx_wd = false;

0 commit comments

Comments
 (0)