Skip to content

Commit ae0e6a5

Browse files
claudiu-mdavem330
authored andcommitted
enetc: Add adaptive interrupt coalescing
Use the generic dynamic interrupt moderation (dim) framework to implement adaptive interrupt coalescing on Rx. With the per-packet interrupt scheme, a high interrupt rate has been noted for moderate traffic flows leading to high CPU utilization. The 'dim' scheme implemented by the current patch addresses this issue improving CPU utilization while using minimal coalescing time thresholds in order to preserve a good latency. On the Tx side use an optimal time threshold value by default. This value has been optimized for Tx TCP streams at a rate of around 85kpps on a 1G link, at which rate half of the Tx ring size (128) gets filled in 1500 usecs. Scaling this down to 2.5G links yields the current value of 600 usecs, which is conservative and gives good enough results for 1G links too (see next). Below are some measurement results for before and after this patch (and related dependencies) basically, for a 2 ARM Cortex-A72 @1.3Ghz CPUs system (32 KB L1 data cache), using 60secs log netperf TCP stream tests @ 1Gbit link (maximum throughput): 1) 1 Rx TCP flow, both Rx and Tx processed by the same NAPI thread on the same CPU: CPU utilization int rate (ints/sec) Before: 50%-60% (over 50%) 92k After: 13%-22% 3.5k-12k Comment: Major CPU utilization improvement for a single flow Rx TCP flow (i.e. netperf -t TCP_MAERTS) on a single CPU. Usually settles under 16% for longer tests. 2) 4 Rx TCP flows + 4 Tx TCP flows (+ pings to check the latency): Total CPU utilization Total int rate (ints/sec) Before: ~80% (spikes to 90%) ~100k After: 60% (more steady) ~4k Comment: Important improvement for this load test, while the ping test outcome does not show any notable difference compared to before. Signed-off-by: Claudiu Manoil <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9157108 commit ae0e6a5

File tree

4 files changed

+73
-7
lines changed

4 files changed

+73
-7
lines changed

drivers/net/ethernet/freescale/enetc/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ config FSL_ENETC
44
depends on PCI && PCI_MSI
55
select FSL_ENETC_MDIO
66
select PHYLIB
7+
select DIMLIB
78
help
89
This driver supports NXP ENETC gigabit ethernet controller PCIe
910
physical function (PF) devices, managing ENETC Ports at a privileged
@@ -15,6 +16,7 @@ config FSL_ENETC_VF
1516
tristate "ENETC VF driver"
1617
depends on PCI && PCI_MSI
1718
select PHYLIB
19+
select DIMLIB
1820
help
1921
This driver supports NXP ENETC gigabit ethernet controller PCIe
2022
virtual function (VF) devices enabled by the ENETC PF driver.

drivers/net/ethernet/freescale/enetc/enetc.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,34 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget);
279279
static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
280280
struct napi_struct *napi, int work_limit);
281281

282+
static void enetc_rx_dim_work(struct work_struct *w)
283+
{
284+
struct dim *dim = container_of(w, struct dim, work);
285+
struct dim_cq_moder moder =
286+
net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
287+
struct enetc_int_vector *v =
288+
container_of(dim, struct enetc_int_vector, rx_dim);
289+
290+
v->rx_ictt = enetc_usecs_to_cycles(moder.usec);
291+
dim->state = DIM_START_MEASURE;
292+
}
293+
294+
static void enetc_rx_net_dim(struct enetc_int_vector *v)
295+
{
296+
struct dim_sample dim_sample;
297+
298+
v->comp_cnt++;
299+
300+
if (!v->rx_napi_work)
301+
return;
302+
303+
dim_update_sample(v->comp_cnt,
304+
v->rx_ring.stats.packets,
305+
v->rx_ring.stats.bytes,
306+
&dim_sample);
307+
net_dim(&v->rx_dim, dim_sample);
308+
}
309+
282310
static int enetc_poll(struct napi_struct *napi, int budget)
283311
{
284312
struct enetc_int_vector
@@ -294,12 +322,19 @@ static int enetc_poll(struct napi_struct *napi, int budget)
294322
work_done = enetc_clean_rx_ring(&v->rx_ring, napi, budget);
295323
if (work_done == budget)
296324
complete = false;
325+
if (work_done)
326+
v->rx_napi_work = true;
297327

298328
if (!complete)
299329
return budget;
300330

301331
napi_complete_done(napi, work_done);
302332

333+
if (likely(v->rx_dim_en))
334+
enetc_rx_net_dim(v);
335+
336+
v->rx_napi_work = false;
337+
303338
/* enable interrupts */
304339
enetc_wr_reg(v->rbier, ENETC_RBIER_RXTIE);
305340

@@ -1075,6 +1110,8 @@ void enetc_init_si_rings_params(struct enetc_ndev_priv *priv)
10751110
priv->num_rx_rings = min_t(int, cpus, si->num_rx_rings);
10761111
priv->num_tx_rings = si->num_tx_rings;
10771112
priv->bdr_int_num = cpus;
1113+
priv->ic_mode = ENETC_IC_RX_ADAPTIVE | ENETC_IC_TX_MANUAL;
1114+
priv->tx_ictt = ENETC_TXIC_TIMETHR;
10781115

10791116
/* SI specific */
10801117
si->cbd_ring.bd_count = ENETC_CBDR_DEFAULT_SIZE;
@@ -1316,7 +1353,8 @@ static void enetc_setup_interrupts(struct enetc_ndev_priv *priv)
13161353
int i;
13171354

13181355
/* enable Tx & Rx event indication */
1319-
if (priv->ic_mode & ENETC_IC_RX_MANUAL) {
1356+
if (priv->ic_mode &
1357+
(ENETC_IC_RX_MANUAL | ENETC_IC_RX_ADAPTIVE)) {
13201358
icpt = ENETC_RBICR0_SET_ICPT(ENETC_RXIC_PKTTHR);
13211359
/* init to non-0 minimum, will be adjusted later */
13221360
ictt = 0x1;
@@ -1786,6 +1824,12 @@ int enetc_alloc_msix(struct enetc_ndev_priv *priv)
17861824

17871825
priv->int_vector[i] = v;
17881826

1827+
/* init defaults for adaptive IC */
1828+
if (priv->ic_mode & ENETC_IC_RX_ADAPTIVE) {
1829+
v->rx_ictt = 0x1;
1830+
v->rx_dim_en = true;
1831+
}
1832+
INIT_WORK(&v->rx_dim.work, enetc_rx_dim_work);
17891833
netif_napi_add(priv->ndev, &v->napi, enetc_poll,
17901834
NAPI_POLL_WEIGHT);
17911835
v->count_tx_rings = v_tx_rings;
@@ -1821,6 +1865,7 @@ int enetc_alloc_msix(struct enetc_ndev_priv *priv)
18211865
fail:
18221866
while (i--) {
18231867
netif_napi_del(&priv->int_vector[i]->napi);
1868+
cancel_work_sync(&priv->int_vector[i]->rx_dim.work);
18241869
kfree(priv->int_vector[i]);
18251870
}
18261871

@@ -1837,6 +1882,7 @@ void enetc_free_msix(struct enetc_ndev_priv *priv)
18371882
struct enetc_int_vector *v = priv->int_vector[i];
18381883

18391884
netif_napi_del(&v->napi);
1885+
cancel_work_sync(&v->rx_dim.work);
18401886
}
18411887

18421888
for (i = 0; i < priv->num_rx_rings; i++)

drivers/net/ethernet/freescale/enetc/enetc.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/ethtool.h>
1111
#include <linux/if_vlan.h>
1212
#include <linux/phy.h>
13+
#include <linux/dim.h>
1314

1415
#include "enetc_hw.h"
1516

@@ -194,12 +195,15 @@ struct enetc_int_vector {
194195
unsigned long tx_rings_map;
195196
int count_tx_rings;
196197
u32 rx_ictt;
197-
struct napi_struct napi;
198+
u16 comp_cnt;
199+
bool rx_dim_en, rx_napi_work;
200+
struct napi_struct napi ____cacheline_aligned_in_smp;
201+
struct dim rx_dim ____cacheline_aligned_in_smp;
198202
char name[ENETC_INT_NAME_MAX];
199203

200204
struct enetc_bdr rx_ring;
201205
struct enetc_bdr tx_ring[];
202-
};
206+
} ____cacheline_aligned_in_smp;
203207

204208
struct enetc_cls_rule {
205209
struct ethtool_rx_flow_spec fs;
@@ -230,10 +234,13 @@ enum enetc_ic_mode {
230234
/* activated when int coalescing time is set to a non-0 value */
231235
ENETC_IC_RX_MANUAL = BIT(0),
232236
ENETC_IC_TX_MANUAL = BIT(1),
237+
/* use dynamic interrupt moderation */
238+
ENETC_IC_RX_ADAPTIVE = BIT(2),
233239
};
234240

235241
#define ENETC_RXIC_PKTTHR min_t(u32, 256, ENETC_RX_RING_DEFAULT_SIZE / 2)
236242
#define ENETC_TXIC_PKTTHR min_t(u32, 128, ENETC_TX_RING_DEFAULT_SIZE / 2)
243+
#define ENETC_TXIC_TIMETHR enetc_usecs_to_cycles(600)
237244

238245
struct enetc_ndev_priv {
239246
struct net_device *ndev;

drivers/net/ethernet/freescale/enetc/enetc_ethtool.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,8 @@ static int enetc_get_coalesce(struct net_device *ndev,
575575
ic->tx_max_coalesced_frames = ENETC_TXIC_PKTTHR;
576576
ic->rx_max_coalesced_frames = ENETC_RXIC_PKTTHR;
577577

578+
ic->use_adaptive_rx_coalesce = priv->ic_mode & ENETC_IC_RX_ADAPTIVE;
579+
578580
return 0;
579581
}
580582

@@ -596,11 +598,17 @@ static int enetc_set_coalesce(struct net_device *ndev,
596598
return -EOPNOTSUPP;
597599

598600
ic_mode = ENETC_IC_NONE;
601+
if (ic->use_adaptive_rx_coalesce) {
602+
ic_mode |= ENETC_IC_RX_ADAPTIVE;
603+
rx_ictt = 0x1;
604+
} else {
605+
ic_mode |= rx_ictt ? ENETC_IC_RX_MANUAL : 0;
606+
}
607+
599608
ic_mode |= tx_ictt ? ENETC_IC_TX_MANUAL : 0;
600-
ic_mode |= rx_ictt ? ENETC_IC_RX_MANUAL : 0;
601609

602610
/* commit the settings */
603-
changed = (ic_mode != priv->ic_mode);
611+
changed = (ic_mode != priv->ic_mode) || (priv->tx_ictt != tx_ictt);
604612

605613
priv->ic_mode = ic_mode;
606614
priv->tx_ictt = tx_ictt;
@@ -609,6 +617,7 @@ static int enetc_set_coalesce(struct net_device *ndev,
609617
struct enetc_int_vector *v = priv->int_vector[i];
610618

611619
v->rx_ictt = rx_ictt;
620+
v->rx_dim_en = !!(ic_mode & ENETC_IC_RX_ADAPTIVE);
612621
}
613622

614623
if (netif_running(ndev) && changed) {
@@ -679,7 +688,8 @@ static int enetc_set_wol(struct net_device *dev,
679688

680689
static const struct ethtool_ops enetc_pf_ethtool_ops = {
681690
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
682-
ETHTOOL_COALESCE_MAX_FRAMES,
691+
ETHTOOL_COALESCE_MAX_FRAMES |
692+
ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
683693
.get_regs_len = enetc_get_reglen,
684694
.get_regs = enetc_get_regs,
685695
.get_sset_count = enetc_get_sset_count,
@@ -704,7 +714,8 @@ static const struct ethtool_ops enetc_pf_ethtool_ops = {
704714

705715
static const struct ethtool_ops enetc_vf_ethtool_ops = {
706716
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
707-
ETHTOOL_COALESCE_MAX_FRAMES,
717+
ETHTOOL_COALESCE_MAX_FRAMES |
718+
ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
708719
.get_regs_len = enetc_get_reglen,
709720
.get_regs = enetc_get_regs,
710721
.get_sset_count = enetc_get_sset_count,

0 commit comments

Comments
 (0)