Skip to content

Commit 2db9569

Browse files
committed
Merge branch 'broadcom-Adaptive-interrupt-coalescing'
Florian Fainelli says: ==================== net: broadcom: Adaptive interrupt coalescing This patch series adds adaptive interrupt coalescing for the Gigabit Ethernet drivers SYSTEMPORT and GENET. This really helps lower the interrupt count and system load, as measured by vmstat for a Gigabit TCP RX session: SYSTEMPORT: without: 1 0 0 192188 0 25472 0 0 0 0 122100 38870 1 42 57 0 0 [ ID] Interval Transfer Bandwidth [ 4] 0.0-10.0 sec 1.03 GBytes 884 Mbits/sec with: 1 0 0 192288 0 25468 0 0 0 0 58806 44401 0 100 0 0 0 [ 5] 0.0-10.0 sec 1.04 GBytes 888 Mbits/sec GENET: without: 1 0 0 1170404 0 25420 0 0 0 0 130785 63402 2 85 12 0 0 [ ID] Interval Transfer Bandwidth [ 4] 0.0-10.0 sec 1.04 GBytes 888 Mbits/sec with: 1 0 0 1170560 0 25420 0 0 0 0 50610 48477 0 100 0 0 0 [ 5] 0.0-10.0 sec 1.05 GBytes 899 Mbits/sec Please look at the implementation and let me know if you see any problems, this was largely inspired by bnxt_en. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 9259f13 + 9f4ca05 commit 2db9569

File tree

4 files changed

+243
-33
lines changed

4 files changed

+243
-33
lines changed

drivers/net/ethernet/broadcom/bcmsysport.c

Lines changed: 126 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/module.h>
1616
#include <linux/kernel.h>
1717
#include <linux/netdevice.h>
18+
#include <linux/net_dim.h>
1819
#include <linux/etherdevice.h>
1920
#include <linux/platform_device.h>
2021
#include <linux/of.h>
@@ -574,21 +575,55 @@ static int bcm_sysport_set_wol(struct net_device *dev,
574575
return 0;
575576
}
576577

578+
static void bcm_sysport_set_rx_coalesce(struct bcm_sysport_priv *priv)
579+
{
580+
u32 reg;
581+
582+
reg = rdma_readl(priv, RDMA_MBDONE_INTR);
583+
reg &= ~(RDMA_INTR_THRESH_MASK |
584+
RDMA_TIMEOUT_MASK << RDMA_TIMEOUT_SHIFT);
585+
reg |= priv->dim.coal_pkts;
586+
reg |= DIV_ROUND_UP(priv->dim.coal_usecs * 1000, 8192) <<
587+
RDMA_TIMEOUT_SHIFT;
588+
rdma_writel(priv, reg, RDMA_MBDONE_INTR);
589+
}
590+
591+
static void bcm_sysport_set_tx_coalesce(struct bcm_sysport_tx_ring *ring)
592+
{
593+
struct bcm_sysport_priv *priv = ring->priv;
594+
u32 reg;
595+
596+
reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(ring->index));
597+
reg &= ~(RING_INTR_THRESH_MASK |
598+
RING_TIMEOUT_MASK << RING_TIMEOUT_SHIFT);
599+
reg |= ring->dim.coal_pkts;
600+
reg |= DIV_ROUND_UP(ring->dim.coal_usecs * 1000, 8192) <<
601+
RING_TIMEOUT_SHIFT;
602+
tdma_writel(priv, reg, TDMA_DESC_RING_INTR_CONTROL(ring->index));
603+
}
604+
577605
static int bcm_sysport_get_coalesce(struct net_device *dev,
578606
struct ethtool_coalesce *ec)
579607
{
580608
struct bcm_sysport_priv *priv = netdev_priv(dev);
609+
struct bcm_sysport_tx_ring *ring;
610+
unsigned int i;
581611
u32 reg;
582612

583613
reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(0));
584614

585615
ec->tx_coalesce_usecs = (reg >> RING_TIMEOUT_SHIFT) * 8192 / 1000;
586616
ec->tx_max_coalesced_frames = reg & RING_INTR_THRESH_MASK;
617+
for (i = 0; i < dev->num_tx_queues; i++) {
618+
ring = &priv->tx_rings[i];
619+
ec->use_adaptive_tx_coalesce |= ring->dim.use_dim;
620+
}
587621

588622
reg = rdma_readl(priv, RDMA_MBDONE_INTR);
589623

590624
ec->rx_coalesce_usecs = (reg >> RDMA_TIMEOUT_SHIFT) * 8192 / 1000;
591625
ec->rx_max_coalesced_frames = reg & RDMA_INTR_THRESH_MASK;
626+
ec->use_adaptive_rx_coalesce = priv->dim.use_dim;
592627

593628
return 0;
594629
}
@@ -597,8 +632,8 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
597632
struct ethtool_coalesce *ec)
598633
{
599634
struct bcm_sysport_priv *priv = netdev_priv(dev);
635+
struct bcm_sysport_tx_ring *ring;
600636
unsigned int i;
601-
u32 reg;
602637

603638
/* Base system clock is 125Mhz, DMA timeout is this reference clock
604639
* divided by 1024, which yield roughly 8.192 us, our maximum value has
@@ -615,22 +650,26 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
615650
return -EINVAL;
616651

617652
for (i = 0; i < dev->num_tx_queues; i++) {
618-
reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(i));
619-
reg &= ~(RING_INTR_THRESH_MASK |
620-
RING_TIMEOUT_MASK << RING_TIMEOUT_SHIFT);
621-
reg |= ec->tx_max_coalesced_frames;
622-
reg |= DIV_ROUND_UP(ec->tx_coalesce_usecs * 1000, 8192) <<
623-
RING_TIMEOUT_SHIFT;
624-
tdma_writel(priv, reg, TDMA_DESC_RING_INTR_CONTROL(i));
653+
ring = &priv->tx_rings[i];
654+
ring->dim.coal_pkts = ec->tx_max_coalesced_frames;
655+
ring->dim.coal_usecs = ec->tx_coalesce_usecs;
656+
if (!ec->use_adaptive_tx_coalesce && ring->dim.use_dim) {
657+
ring->dim.coal_pkts = 1;
658+
ring->dim.coal_usecs = 0;
659+
}
660+
ring->dim.use_dim = ec->use_adaptive_tx_coalesce;
661+
bcm_sysport_set_tx_coalesce(ring);
625662
}
626663

627-
reg = rdma_readl(priv, RDMA_MBDONE_INTR);
628-
reg &= ~(RDMA_INTR_THRESH_MASK |
629-
RDMA_TIMEOUT_MASK << RDMA_TIMEOUT_SHIFT);
630-
reg |= ec->rx_max_coalesced_frames;
631-
reg |= DIV_ROUND_UP(ec->rx_coalesce_usecs * 1000, 8192) <<
632-
RDMA_TIMEOUT_SHIFT;
633-
rdma_writel(priv, reg, RDMA_MBDONE_INTR);
664+
priv->dim.coal_usecs = ec->rx_coalesce_usecs;
665+
priv->dim.coal_pkts = ec->rx_max_coalesced_frames;
666+
667+
if (!ec->use_adaptive_rx_coalesce && priv->dim.use_dim) {
668+
priv->dim.coal_pkts = 1;
669+
priv->dim.coal_usecs = 0;
670+
}
671+
priv->dim.use_dim = ec->use_adaptive_rx_coalesce;
672+
bcm_sysport_set_rx_coalesce(priv);
634673

635674
return 0;
636675
}
@@ -709,6 +748,7 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
709748
struct bcm_sysport_stats64 *stats64 = &priv->stats64;
710749
struct net_device *ndev = priv->netdev;
711750
unsigned int processed = 0, to_process;
751+
unsigned int processed_bytes = 0;
712752
struct bcm_sysport_cb *cb;
713753
struct sk_buff *skb;
714754
unsigned int p_index;
@@ -800,6 +840,7 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
800840
*/
801841
skb_pull(skb, sizeof(*rsb) + 2);
802842
len -= (sizeof(*rsb) + 2);
843+
processed_bytes += len;
803844

804845
/* UniMAC may forward CRC */
805846
if (priv->crc_fwd) {
@@ -824,6 +865,9 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
824865
priv->rx_read_ptr = 0;
825866
}
826867

868+
priv->dim.packets = processed;
869+
priv->dim.bytes = processed_bytes;
870+
827871
return processed;
828872
}
829873

@@ -896,6 +940,8 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
896940
ring->packets += pkts_compl;
897941
ring->bytes += bytes_compl;
898942
u64_stats_update_end(&priv->syncp);
943+
ring->dim.packets = pkts_compl;
944+
ring->dim.bytes = bytes_compl;
899945

900946
ring->c_index = c_index;
901947

@@ -941,6 +987,7 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
941987
{
942988
struct bcm_sysport_tx_ring *ring =
943989
container_of(napi, struct bcm_sysport_tx_ring, napi);
990+
struct net_dim_sample dim_sample;
944991
unsigned int work_done = 0;
945992

946993
work_done = bcm_sysport_tx_reclaim(ring->priv, ring);
@@ -957,6 +1004,12 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
9571004
return 0;
9581005
}
9591006

1007+
if (ring->dim.use_dim) {
1008+
net_dim_sample(ring->dim.event_ctr, ring->dim.packets,
1009+
ring->dim.bytes, &dim_sample);
1010+
net_dim(&ring->dim.dim, dim_sample);
1011+
}
1012+
9601013
return budget;
9611014
}
9621015

@@ -972,6 +1025,7 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
9721025
{
9731026
struct bcm_sysport_priv *priv =
9741027
container_of(napi, struct bcm_sysport_priv, napi);
1028+
struct net_dim_sample dim_sample;
9751029
unsigned int work_done = 0;
9761030

9771031
work_done = bcm_sysport_desc_rx(priv, budget);
@@ -994,6 +1048,12 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
9941048
intrl2_0_mask_clear(priv, INTRL2_0_RDMA_MBDONE);
9951049
}
9961050

1051+
if (priv->dim.use_dim) {
1052+
net_dim_sample(priv->dim.event_ctr, priv->dim.packets,
1053+
priv->dim.bytes, &dim_sample);
1054+
net_dim(&priv->dim.dim, dim_sample);
1055+
}
1056+
9971057
return work_done;
9981058
}
9991059

@@ -1012,6 +1072,40 @@ static void bcm_sysport_resume_from_wol(struct bcm_sysport_priv *priv)
10121072
netif_dbg(priv, wol, priv->netdev, "resumed from WOL\n");
10131073
}
10141074

1075+
static void bcm_sysport_dim_work(struct work_struct *work)
1076+
{
1077+
struct net_dim *dim = container_of(work, struct net_dim, work);
1078+
struct bcm_sysport_net_dim *ndim =
1079+
container_of(dim, struct bcm_sysport_net_dim, dim);
1080+
struct bcm_sysport_priv *priv =
1081+
container_of(ndim, struct bcm_sysport_priv, dim);
1082+
struct net_dim_cq_moder cur_profile =
1083+
net_dim_get_profile(dim->mode, dim->profile_ix);
1084+
1085+
priv->dim.coal_usecs = cur_profile.usec;
1086+
priv->dim.coal_pkts = cur_profile.pkts;
1087+
1088+
bcm_sysport_set_rx_coalesce(priv);
1089+
dim->state = NET_DIM_START_MEASURE;
1090+
}
1091+
1092+
static void bcm_sysport_dim_tx_work(struct work_struct *work)
1093+
{
1094+
struct net_dim *dim = container_of(work, struct net_dim, work);
1095+
struct bcm_sysport_net_dim *ndim =
1096+
container_of(dim, struct bcm_sysport_net_dim, dim);
1097+
struct bcm_sysport_tx_ring *ring =
1098+
container_of(ndim, struct bcm_sysport_tx_ring, dim);
1099+
struct net_dim_cq_moder cur_profile =
1100+
net_dim_get_profile(dim->mode, dim->profile_ix);
1101+
1102+
ring->dim.coal_usecs = cur_profile.usec;
1103+
ring->dim.coal_pkts = cur_profile.pkts;
1104+
1105+
bcm_sysport_set_tx_coalesce(ring);
1106+
dim->state = NET_DIM_START_MEASURE;
1107+
}
1108+
10151109
/* RX and misc interrupt routine */
10161110
static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
10171111
{
@@ -1030,6 +1124,7 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
10301124
}
10311125

10321126
if (priv->irq0_stat & INTRL2_0_RDMA_MBDONE) {
1127+
priv->dim.event_ctr++;
10331128
if (likely(napi_schedule_prep(&priv->napi))) {
10341129
/* disable RX interrupts */
10351130
intrl2_0_mask_set(priv, INTRL2_0_RDMA_MBDONE);
@@ -1057,6 +1152,7 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
10571152
continue;
10581153

10591154
txr = &priv->tx_rings[ring];
1155+
txr->dim.event_ctr++;
10601156

10611157
if (likely(napi_schedule_prep(&txr->napi))) {
10621158
intrl2_0_mask_set(priv, ring_bit);
@@ -1089,6 +1185,7 @@ static irqreturn_t bcm_sysport_tx_isr(int irq, void *dev_id)
10891185
continue;
10901186

10911187
txr = &priv->tx_rings[ring];
1188+
txr->dim.event_ctr++;
10921189

10931190
if (likely(napi_schedule_prep(&txr->napi))) {
10941191
intrl2_1_mask_set(priv, BIT(ring));
@@ -1354,6 +1451,16 @@ static void bcm_sysport_adj_link(struct net_device *dev)
13541451
phy_print_status(phydev);
13551452
}
13561453

1454+
static void bcm_sysport_init_dim(struct bcm_sysport_net_dim *dim,
1455+
void (*cb)(struct work_struct *work))
1456+
{
1457+
INIT_WORK(&dim->dim.work, cb);
1458+
dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
1459+
dim->event_ctr = 0;
1460+
dim->packets = 0;
1461+
dim->bytes = 0;
1462+
}
1463+
13571464
static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
13581465
unsigned int index)
13591466
{
@@ -1444,6 +1551,7 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
14441551
reg |= (1 << index);
14451552
tdma_writel(priv, reg, TDMA_TIER1_ARB_0_QUEUE_EN);
14461553

1554+
bcm_sysport_init_dim(&ring->dim, bcm_sysport_dim_tx_work);
14471555
napi_enable(&ring->napi);
14481556

14491557
netif_dbg(priv, hw, priv->netdev,
@@ -1474,6 +1582,7 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv,
14741582
return;
14751583

14761584
napi_disable(&ring->napi);
1585+
cancel_work_sync(&ring->dim.dim.work);
14771586
netif_napi_del(&ring->napi);
14781587

14791588
bcm_sysport_tx_clean(priv, ring);
@@ -1763,6 +1872,7 @@ static void bcm_sysport_netif_start(struct net_device *dev)
17631872
struct bcm_sysport_priv *priv = netdev_priv(dev);
17641873

17651874
/* Enable NAPI */
1875+
bcm_sysport_init_dim(&priv->dim, bcm_sysport_dim_work);
17661876
napi_enable(&priv->napi);
17671877

17681878
/* Enable RX interrupt and TX ring full interrupt */
@@ -1948,6 +2058,7 @@ static void bcm_sysport_netif_stop(struct net_device *dev)
19482058
/* stop all software from updating hardware */
19492059
netif_tx_stop_all_queues(dev);
19502060
napi_disable(&priv->napi);
2061+
cancel_work_sync(&priv->dim.dim.work);
19512062
phy_stop(dev->phydev);
19522063

19532064
/* mask all interrupts */

drivers/net/ethernet/broadcom/bcmsysport.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define __BCM_SYSPORT_H
1313

1414
#include <linux/if_vlan.h>
15+
#include <linux/net_dim.h>
1516

1617
/* Receive/transmit descriptor format */
1718
#define DESC_ADDR_HI_STATUS_LEN 0x00
@@ -695,6 +696,16 @@ struct bcm_sysport_hw_params {
695696
unsigned int num_rx_desc_words;
696697
};
697698

699+
struct bcm_sysport_net_dim {
700+
u16 use_dim;
701+
u16 event_ctr;
702+
unsigned long packets;
703+
unsigned long bytes;
704+
u32 coal_usecs;
705+
u32 coal_pkts;
706+
struct net_dim dim;
707+
};
708+
698709
/* Software view of the TX ring */
699710
struct bcm_sysport_tx_ring {
700711
spinlock_t lock; /* Ring lock for tx reclaim/xmit */
@@ -712,6 +723,7 @@ struct bcm_sysport_tx_ring {
712723
struct bcm_sysport_priv *priv; /* private context backpointer */
713724
unsigned long packets; /* packets statistics */
714725
unsigned long bytes; /* bytes statistics */
726+
struct bcm_sysport_net_dim dim; /* Net DIM context */
715727
unsigned int switch_queue; /* switch port queue number */
716728
unsigned int switch_port; /* switch port queue number */
717729
bool inspect; /* inspect switch port and queue */
@@ -743,6 +755,8 @@ struct bcm_sysport_priv {
743755
unsigned int rx_read_ptr;
744756
unsigned int rx_c_index;
745757

758+
struct bcm_sysport_net_dim dim;
759+
746760
/* PHY device */
747761
struct device_node *phy_dn;
748762
phy_interface_t phy_interface;

0 commit comments

Comments
 (0)