Skip to content

Commit e4918f9

Browse files
grygoriySdavem330
authored andcommitted
net: ethernet: ti: am65-cpsw: add sw tx/rx irq coalescing based on hrtimers
Add SW IRQ coalescing based on hrtimers for TX and RX data path which can be enabled by ethtool commands: - RX coalescing ethtool -C eth1 rx-usecs 50 - TX coalescing can be enabled per TX queue - by default enables coalesing for TX0 ethtool -C eth1 tx-usecs 50 - configure TX0 ethtool -Q eth0 queue_mask 1 --coalesce tx-usecs 100 - configure TX1 ethtool -Q eth0 queue_mask 2 --coalesce tx-usecs 100 - configure TX0 and TX1 ethtool -Q eth0 queue_mask 3 --coalesce tx-usecs 100 --coalesce tx-usecs 100 show configuration for TX0 and TX1: ethtool -Q eth0 queue_mask 3 --show-coalesce Comparing to gro_flush_timeout and napi_defer_hard_irqs, this patch allows to enable IRQ coalesing for RX path separately. Signed-off-by: Grygorii Strashko <[email protected]> Signed-off-by: Roger Quadros <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 49a2eb9 commit e4918f9

File tree

3 files changed

+134
-8
lines changed

3 files changed

+134
-8
lines changed

drivers/net/ethernet/ti/am65-cpsw-ethtool.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,80 @@ static void am65_cpsw_get_mm_stats(struct net_device *ndev,
904904
s->MACMergeHoldCount = readl(base + AM65_CPSW_STATN_IET_TX_HOLD);
905905
}
906906

907+
static int am65_cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
908+
struct kernel_ethtool_coalesce *kernel_coal,
909+
struct netlink_ext_ack *extack)
910+
{
911+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
912+
struct am65_cpsw_tx_chn *tx_chn;
913+
914+
tx_chn = &common->tx_chns[0];
915+
916+
coal->rx_coalesce_usecs = common->rx_pace_timeout / 1000;
917+
coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;
918+
919+
return 0;
920+
}
921+
922+
static int am65_cpsw_get_per_queue_coalesce(struct net_device *ndev, u32 queue,
923+
struct ethtool_coalesce *coal)
924+
{
925+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
926+
struct am65_cpsw_tx_chn *tx_chn;
927+
928+
if (queue >= AM65_CPSW_MAX_TX_QUEUES)
929+
return -EINVAL;
930+
931+
tx_chn = &common->tx_chns[queue];
932+
933+
coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;
934+
935+
return 0;
936+
}
937+
938+
static int am65_cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
939+
struct kernel_ethtool_coalesce *kernel_coal,
940+
struct netlink_ext_ack *extack)
941+
{
942+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
943+
struct am65_cpsw_tx_chn *tx_chn;
944+
945+
tx_chn = &common->tx_chns[0];
946+
947+
if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20)
948+
return -EINVAL;
949+
950+
if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20)
951+
return -EINVAL;
952+
953+
common->rx_pace_timeout = coal->rx_coalesce_usecs * 1000;
954+
tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;
955+
956+
return 0;
957+
}
958+
959+
static int am65_cpsw_set_per_queue_coalesce(struct net_device *ndev, u32 queue,
960+
struct ethtool_coalesce *coal)
961+
{
962+
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
963+
struct am65_cpsw_tx_chn *tx_chn;
964+
965+
if (queue >= AM65_CPSW_MAX_TX_QUEUES)
966+
return -EINVAL;
967+
968+
tx_chn = &common->tx_chns[queue];
969+
970+
if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) {
971+
dev_info(common->dev, "defaulting to min value of 20us for tx-usecs for tx-%u\n",
972+
queue);
973+
coal->tx_coalesce_usecs = 20;
974+
}
975+
976+
tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;
977+
978+
return 0;
979+
}
980+
907981
const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
908982
.begin = am65_cpsw_ethtool_op_begin,
909983
.complete = am65_cpsw_ethtool_op_complete,
@@ -922,6 +996,11 @@ const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
922996
.get_ts_info = am65_cpsw_get_ethtool_ts_info,
923997
.get_priv_flags = am65_cpsw_get_ethtool_priv_flags,
924998
.set_priv_flags = am65_cpsw_set_ethtool_priv_flags,
999+
.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
1000+
.get_coalesce = am65_cpsw_get_coalesce,
1001+
.set_coalesce = am65_cpsw_set_coalesce,
1002+
.get_per_queue_coalesce = am65_cpsw_get_per_queue_coalesce,
1003+
.set_per_queue_coalesce = am65_cpsw_set_per_queue_coalesce,
9251004

9261005
.get_link = ethtool_op_get_link,
9271006
.get_link_ksettings = am65_cpsw_get_link_ksettings,

drivers/net/ethernet/ti/am65-cpsw-nuss.c

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,10 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
596596
msecs_to_jiffies(1000));
597597
if (!i)
598598
dev_err(common->dev, "tx timeout\n");
599-
for (i = 0; i < common->tx_ch_num; i++)
599+
for (i = 0; i < common->tx_ch_num; i++) {
600600
napi_disable(&common->tx_chns[i].napi_tx);
601+
hrtimer_cancel(&common->tx_chns[i].tx_hrtimer);
602+
}
601603

602604
for (i = 0; i < common->tx_ch_num; i++) {
603605
k3_udma_glue_reset_tx_chn(common->tx_chns[i].tx_chn,
@@ -616,6 +618,7 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
616618
}
617619

618620
napi_disable(&common->napi_rx);
621+
hrtimer_cancel(&common->rx_hrtimer);
619622

620623
for (i = 0; i < AM65_CPSW_MAX_RX_FLOWS; i++)
621624
k3_udma_glue_reset_rx_chn(common->rx_chns.rx_chn, i,
@@ -885,6 +888,15 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common,
885888
return ret;
886889
}
887890

891+
static enum hrtimer_restart am65_cpsw_nuss_rx_timer_callback(struct hrtimer *timer)
892+
{
893+
struct am65_cpsw_common *common =
894+
container_of(timer, struct am65_cpsw_common, rx_hrtimer);
895+
896+
enable_irq(common->rx_chns.irq);
897+
return HRTIMER_NORESTART;
898+
}
899+
888900
static int am65_cpsw_nuss_rx_poll(struct napi_struct *napi_rx, int budget)
889901
{
890902
struct am65_cpsw_common *common = am65_cpsw_napi_to_common(napi_rx);
@@ -912,7 +924,13 @@ static int am65_cpsw_nuss_rx_poll(struct napi_struct *napi_rx, int budget)
912924
if (num_rx < budget && napi_complete_done(napi_rx, num_rx)) {
913925
if (common->rx_irq_disabled) {
914926
common->rx_irq_disabled = false;
915-
enable_irq(common->rx_chns.irq);
927+
if (unlikely(common->rx_pace_timeout)) {
928+
hrtimer_start(&common->rx_hrtimer,
929+
ns_to_ktime(common->rx_pace_timeout),
930+
HRTIMER_MODE_REL_PINNED);
931+
} else {
932+
enable_irq(common->rx_chns.irq);
933+
}
916934
}
917935
}
918936

@@ -968,7 +986,7 @@ static void am65_cpsw_nuss_tx_wake(struct am65_cpsw_tx_chn *tx_chn, struct net_d
968986
}
969987

970988
static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
971-
int chn, unsigned int budget)
989+
int chn, unsigned int budget, bool *tdown)
972990
{
973991
struct device *dev = common->dev;
974992
struct am65_cpsw_tx_chn *tx_chn;
@@ -991,6 +1009,7 @@ static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
9911009
if (cppi5_desc_is_tdcm(desc_dma)) {
9921010
if (atomic_dec_and_test(&common->tdown_cnt))
9931011
complete(&common->tdown_complete);
1012+
*tdown = true;
9941013
break;
9951014
}
9961015

@@ -1013,7 +1032,7 @@ static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
10131032
}
10141033

10151034
static int am65_cpsw_nuss_tx_compl_packets_2g(struct am65_cpsw_common *common,
1016-
int chn, unsigned int budget)
1035+
int chn, unsigned int budget, bool *tdown)
10171036
{
10181037
struct device *dev = common->dev;
10191038
struct am65_cpsw_tx_chn *tx_chn;
@@ -1034,6 +1053,7 @@ static int am65_cpsw_nuss_tx_compl_packets_2g(struct am65_cpsw_common *common,
10341053
if (cppi5_desc_is_tdcm(desc_dma)) {
10351054
if (atomic_dec_and_test(&common->tdown_cnt))
10361055
complete(&common->tdown_complete);
1056+
*tdown = true;
10371057
break;
10381058
}
10391059

@@ -1059,21 +1079,40 @@ static int am65_cpsw_nuss_tx_compl_packets_2g(struct am65_cpsw_common *common,
10591079
return num_tx;
10601080
}
10611081

1082+
static enum hrtimer_restart am65_cpsw_nuss_tx_timer_callback(struct hrtimer *timer)
1083+
{
1084+
struct am65_cpsw_tx_chn *tx_chns =
1085+
container_of(timer, struct am65_cpsw_tx_chn, tx_hrtimer);
1086+
1087+
enable_irq(tx_chns->irq);
1088+
return HRTIMER_NORESTART;
1089+
}
1090+
10621091
static int am65_cpsw_nuss_tx_poll(struct napi_struct *napi_tx, int budget)
10631092
{
10641093
struct am65_cpsw_tx_chn *tx_chn = am65_cpsw_napi_to_tx_chn(napi_tx);
1094+
bool tdown = false;
10651095
int num_tx;
10661096

10671097
if (AM65_CPSW_IS_CPSW2G(tx_chn->common))
1068-
num_tx = am65_cpsw_nuss_tx_compl_packets_2g(tx_chn->common, tx_chn->id, budget);
1098+
num_tx = am65_cpsw_nuss_tx_compl_packets_2g(tx_chn->common, tx_chn->id,
1099+
budget, &tdown);
10691100
else
1070-
num_tx = am65_cpsw_nuss_tx_compl_packets(tx_chn->common, tx_chn->id, budget);
1101+
num_tx = am65_cpsw_nuss_tx_compl_packets(tx_chn->common,
1102+
tx_chn->id, budget, &tdown);
10711103

10721104
if (num_tx >= budget)
10731105
return budget;
10741106

1075-
if (napi_complete_done(napi_tx, num_tx))
1076-
enable_irq(tx_chn->irq);
1107+
if (napi_complete_done(napi_tx, num_tx)) {
1108+
if (unlikely(tx_chn->tx_pace_timeout && !tdown)) {
1109+
hrtimer_start(&tx_chn->tx_hrtimer,
1110+
ns_to_ktime(tx_chn->tx_pace_timeout),
1111+
HRTIMER_MODE_REL_PINNED);
1112+
} else {
1113+
enable_irq(tx_chn->irq);
1114+
}
1115+
}
10771116

10781117
return 0;
10791118
}
@@ -1705,6 +1744,8 @@ static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
17051744

17061745
netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
17071746
am65_cpsw_nuss_tx_poll);
1747+
hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
1748+
tx_chn->tx_hrtimer.function = &am65_cpsw_nuss_tx_timer_callback;
17081749

17091750
ret = devm_request_irq(dev, tx_chn->irq,
17101751
am65_cpsw_nuss_tx_irq,
@@ -1930,6 +1971,8 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
19301971

19311972
netif_napi_add(common->dma_ndev, &common->napi_rx,
19321973
am65_cpsw_nuss_rx_poll);
1974+
hrtimer_init(&common->rx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
1975+
common->rx_hrtimer.function = &am65_cpsw_nuss_rx_timer_callback;
19331976

19341977
ret = devm_request_irq(dev, rx_chn->irq,
19351978
am65_cpsw_nuss_rx_irq,

drivers/net/ethernet/ti/am65-cpsw-nuss.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ struct am65_cpsw_tx_chn {
7575
struct k3_cppi_desc_pool *desc_pool;
7676
struct k3_udma_glue_tx_channel *tx_chn;
7777
spinlock_t lock; /* protect TX rings in multi-port mode */
78+
struct hrtimer tx_hrtimer;
79+
unsigned long tx_pace_timeout;
7880
int irq;
7981
u32 id;
8082
u32 descs_num;
@@ -138,6 +140,8 @@ struct am65_cpsw_common {
138140
struct napi_struct napi_rx;
139141

140142
bool rx_irq_disabled;
143+
struct hrtimer rx_hrtimer;
144+
unsigned long rx_pace_timeout;
141145

142146
u32 nuss_ver;
143147
u32 cpsw_ver;

0 commit comments

Comments
 (0)