diff options
| author | Grygorii Strashko <grygorii.strashko@ti.com> | 2021-08-06 17:59:05 +0300 |
|---|---|---|
| committer | Vignesh Raghavendra <vigneshr@ti.com> | 2021-08-15 12:47:25 +0530 |
| commit | 67bcc0100a4c71c1f37c810d6e7b1a4e45170c91 (patch) | |
| tree | 52fa6e308b8ccd473f0cd4f4f1289fb7e4893ceb | |
| parent | 0497909a56bead21aa45d04ce5cdb801ae1629f3 (diff) | |
net: ethernet: ti: j721e-cpsw-virt-mac: add sw irq coalescing based on hrtimers
Add SW IRQ coalescing based on hrtimers for RX/TX data path which can be
enabled by ethtool commands:
ethtool -C eth1 tx-usecs 50
ethtool -C eth1 rx-usecs 50
min value is 20us
Comapring to gro_flush_timeout, napi_defer_hard_irqs this patch allows to
enable IRQ coalesing per RX/TX path separately.
TX:
netperf -l 60 -H 192.168.1.2 -t UDP_STREAM -c -C -j -B "am5 " -s 1 -- -m1470
212992 1470 60.00 4882385 0 956.9 36.50 6.249
212992 60.00 4882385 956.9 35.84 12.272
ethtool -C eth1 tx-usecs 50
212992 1470 60.00 4882253 0 956.9 24.87 4.258
212992 60.00 4881729 956.8 35.81 12.262
netperf -l 60 -H 192.168.1.1 -t TCP_MAERTS -c -C -j -B "am6 " -s 1 -s 1
131072 16384 16384 59.02 941.40 39.60 27.91 13.785 4.858
ethtool -C eth1 tx-usecs 50
131072 16384 16384 59.02 941.36 39.60 21.11 13.786 3.674
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
| -rw-r--r-- | drivers/net/ethernet/ti/j721e-cpsw-virt-mac.c | 82 |
1 files changed, 77 insertions, 5 deletions
diff --git a/drivers/net/ethernet/ti/j721e-cpsw-virt-mac.c b/drivers/net/ethernet/ti/j721e-cpsw-virt-mac.c index e324d8c0968d..2d1d76cc323e 100644 --- a/drivers/net/ethernet/ti/j721e-cpsw-virt-mac.c +++ b/drivers/net/ethernet/ti/j721e-cpsw-virt-mac.c @@ -70,11 +70,15 @@ struct virt_cpsw_common { struct virt_cpsw_tx_chn tx_chns; struct napi_struct napi_tx; + struct hrtimer tx_hrtimer; + unsigned long tx_pace_timeout; struct completion tdown_complete; atomic_t tdown_cnt; struct virt_cpsw_rx_chn rx_chns; struct napi_struct napi_rx; bool rx_irq_disabled; + struct hrtimer rx_hrtimer; + unsigned long rx_pace_timeout; const char *rdev_name; struct rpmsg_remotedev *rdev; @@ -233,6 +237,7 @@ static void virt_cpsw_nuss_common_stop(struct virt_cpsw_common *common) virt_cpsw_nuss_tx_cleanup); k3_udma_glue_disable_tx_chn(common->tx_chns.tx_chn); napi_disable(&common->napi_tx); + hrtimer_cancel(&common->tx_hrtimer); k3_udma_glue_rx_flow_disable(common->rx_chns.rx_chn, 0); /* Need some delay to process RX ring before reset */ @@ -241,6 +246,7 @@ static void virt_cpsw_nuss_common_stop(struct virt_cpsw_common *common) &common->rx_chns, virt_cpsw_nuss_rx_cleanup, false); napi_disable(&common->napi_rx); + hrtimer_cancel(&common->rx_hrtimer); } static int virt_cpsw_nuss_ndo_stop(struct net_device *ndev) @@ -439,6 +445,15 @@ static int virt_cpsw_nuss_rx_packets(struct virt_cpsw_common *common, return ret; } +static enum hrtimer_restart virt_cpsw_nuss_rx_timer_callback(struct hrtimer *timer) +{ + struct virt_cpsw_common *common = + container_of(timer, struct virt_cpsw_common, rx_hrtimer); + + enable_irq(common->rx_chns.irq); + return HRTIMER_NORESTART; +} + static int virt_cpsw_nuss_rx_poll(struct napi_struct *napi_rx, int budget) { struct virt_cpsw_common *common = @@ -462,7 +477,13 @@ static int virt_cpsw_nuss_rx_poll(struct napi_struct *napi_rx, int budget) if (num_rx < budget && napi_complete_done(napi_rx, num_rx)) { if (common->rx_irq_disabled) { common->rx_irq_disabled = false; - enable_irq(common->rx_chns.irq); + if (unlikely(common->rx_pace_timeout)) { + hrtimer_start(&common->rx_hrtimer, + ns_to_ktime(common->rx_pace_timeout), + HRTIMER_MODE_REL_PINNED); + } else { + enable_irq(common->rx_chns.irq); + } } } @@ -518,7 +539,7 @@ static void virt_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma) } static int virt_cpsw_nuss_tx_compl_packets(struct virt_cpsw_common *common, - int chn, unsigned int budget) + int chn, unsigned int budget, bool *tdown) { struct cppi5_host_desc_t *desc_tx; struct device *dev = common->dev; @@ -544,6 +565,7 @@ static int virt_cpsw_nuss_tx_compl_packets(struct virt_cpsw_common *common, if (desc_dma & 0x1) { if (atomic_dec_and_test(&common->tdown_cnt)) complete(&common->tdown_complete); + *tdown = true; break; } @@ -593,20 +615,37 @@ static int virt_cpsw_nuss_tx_compl_packets(struct virt_cpsw_common *common, return num_tx; } +static enum hrtimer_restart virt_cpsw_nuss_tx_timer_callback(struct hrtimer *timer) +{ + struct virt_cpsw_common *common = + container_of(timer, struct virt_cpsw_common, tx_hrtimer); + + enable_irq(common->tx_chns.irq); + return HRTIMER_NORESTART; +} + static int virt_cpsw_nuss_tx_poll(struct napi_struct *napi_tx, int budget) { struct virt_cpsw_common *common = container_of(napi_tx, struct virt_cpsw_common, napi_tx); + bool tdown = false; int num_tx; /* process every unprocessed channel */ - num_tx = virt_cpsw_nuss_tx_compl_packets(common, 0, budget); + num_tx = virt_cpsw_nuss_tx_compl_packets(common, 0, budget, &tdown); if (num_tx >= budget) return budget; - if (napi_complete_done(napi_tx, num_tx)) - enable_irq(common->tx_chns.irq); + if (napi_complete_done(napi_tx, num_tx)) { + if (unlikely(common->tx_pace_timeout && !tdown)) { + hrtimer_start(&common->tx_hrtimer, + ns_to_ktime(common->tx_pace_timeout), + HRTIMER_MODE_REL_PINNED); + } else { + enable_irq(common->tx_chns.irq); + } + } return 0; } @@ -922,12 +961,40 @@ static void virt_cpsw_nuss_self_test(struct net_device *ndev, } } +static int virt_cpsw_nuss_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal) +{ + struct virt_cpsw_common *common = virt_ndev_to_common(ndev); + + coal->rx_coalesce_usecs = common->rx_pace_timeout / 1000; + coal->tx_coalesce_usecs = common->tx_pace_timeout / 1000; + return 0; +} + +static int virt_cpsw_nuss_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal) +{ + struct virt_cpsw_common *common = virt_ndev_to_common(ndev); + + if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20) + coal->rx_coalesce_usecs = 20; + + if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) + coal->tx_coalesce_usecs = 20; + + common->tx_pace_timeout = coal->tx_coalesce_usecs * 1000; + common->rx_pace_timeout = coal->rx_coalesce_usecs * 1000; + + return 0; +} + const struct ethtool_ops virt_cpsw_nuss_ethtool_ops = { .get_drvinfo = virt_cpsw_nuss_get_drvinfo, .get_sset_count = virt_cpsw_nuss_get_sset_count, .get_strings = virt_cpsw_nuss_get_strings, .self_test = virt_cpsw_nuss_self_test, .get_link = ethtool_op_get_link, + .supported_coalesce_params = ETHTOOL_COALESCE_USECS, + .get_coalesce = virt_cpsw_nuss_get_coalesce, + .set_coalesce = virt_cpsw_nuss_set_coalesce, }; static void virt_cpsw_nuss_free_tx_chns(void *data) @@ -1218,6 +1285,11 @@ static int virt_cpsw_nuss_init_ndev(struct virt_cpsw_common *common) netif_napi_add(port->ndev, &common->napi_rx, virt_cpsw_nuss_rx_poll, NAPI_POLL_WEIGHT); + hrtimer_init(&common->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + common->tx_hrtimer.function = &virt_cpsw_nuss_tx_timer_callback; + hrtimer_init(&common->rx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); + common->rx_hrtimer.function = &virt_cpsw_nuss_rx_timer_callback; + ret = register_netdev(port->ndev); if (ret) dev_err(dev, "error registering slave net device %d\n", ret); |
