Skip to content

Commit

Permalink
Merge branch 'net-Broadcom-drivers-coalescing-fixes'
Browse files Browse the repository at this point in the history
Florian Fainelli says:

====================
net: Broadcom drivers coalescing fixes

Following Tal's review of the adaptive RX/TX coalescing feature added to the
SYSTEMPORT and GENET driver a number of things showed up:

- adaptive TX coalescing is not actually a good idea with the current way
  the estimator will program the ring, this results in a higher CPU load, NAPI
  on TX already does a reasonably good job at maintaining the interrupt count low

- both SYSTEMPORT and GENET would suffer from the same issues while configuring
  coalescing parameters where the values would just not be applied correctly
  based on user settings, so we fix that too

Tal, thanks again for your feedback, I would appreciate if you could review that
the new behavior appears to be implemented correctly.

Thanks!

Changes in v2:

- added Tal's reviewed-by to the first patch
- split DIM initialization from coalescing parameters initialization
- avoid duplicating the same code in bcmgenet_set_coalesce() when configuring RX rings
- fixed the condition where default DIM parameters would be applied when
  adaptive RX coalescing would be enabled, do this only if it was disabled before
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Mar 30, 2018
2 parents 9daae9b + 5e6ce1f commit 95e623f
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 109 deletions.
123 changes: 52 additions & 71 deletions drivers/net/ethernet/broadcom/bcmsysport.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/net_dim.h>
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
#include <linux/of.h>
Expand Down Expand Up @@ -575,29 +574,30 @@ static int bcm_sysport_set_wol(struct net_device *dev,
return 0;
}

static void bcm_sysport_set_rx_coalesce(struct bcm_sysport_priv *priv)
static void bcm_sysport_set_rx_coalesce(struct bcm_sysport_priv *priv,
u32 usecs, u32 pkts)
{
u32 reg;

reg = rdma_readl(priv, RDMA_MBDONE_INTR);
reg &= ~(RDMA_INTR_THRESH_MASK |
RDMA_TIMEOUT_MASK << RDMA_TIMEOUT_SHIFT);
reg |= priv->dim.coal_pkts;
reg |= DIV_ROUND_UP(priv->dim.coal_usecs * 1000, 8192) <<
RDMA_TIMEOUT_SHIFT;
reg |= pkts;
reg |= DIV_ROUND_UP(usecs * 1000, 8192) << RDMA_TIMEOUT_SHIFT;
rdma_writel(priv, reg, RDMA_MBDONE_INTR);
}

static void bcm_sysport_set_tx_coalesce(struct bcm_sysport_tx_ring *ring)
static void bcm_sysport_set_tx_coalesce(struct bcm_sysport_tx_ring *ring,
struct ethtool_coalesce *ec)
{
struct bcm_sysport_priv *priv = ring->priv;
u32 reg;

reg = tdma_readl(priv, TDMA_DESC_RING_INTR_CONTROL(ring->index));
reg &= ~(RING_INTR_THRESH_MASK |
RING_TIMEOUT_MASK << RING_TIMEOUT_SHIFT);
reg |= ring->dim.coal_pkts;
reg |= DIV_ROUND_UP(ring->dim.coal_usecs * 1000, 8192) <<
reg |= ec->tx_max_coalesced_frames;
reg |= DIV_ROUND_UP(ec->tx_coalesce_usecs * 1000, 8192) <<
RING_TIMEOUT_SHIFT;
tdma_writel(priv, reg, TDMA_DESC_RING_INTR_CONTROL(ring->index));
}
Expand All @@ -606,18 +606,12 @@ static int bcm_sysport_get_coalesce(struct net_device *dev,
struct ethtool_coalesce *ec)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
struct bcm_sysport_tx_ring *ring;
unsigned int i;
u32 reg;

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

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

reg = rdma_readl(priv, RDMA_MBDONE_INTR);

Expand All @@ -632,7 +626,8 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
struct ethtool_coalesce *ec)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
struct bcm_sysport_tx_ring *ring;
struct net_dim_cq_moder moder;
u32 usecs, pkts;
unsigned int i;

/* Base system clock is 125Mhz, DMA timeout is this reference clock
Expand All @@ -646,30 +641,28 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
return -EINVAL;

if ((ec->tx_coalesce_usecs == 0 && ec->tx_max_coalesced_frames == 0) ||
(ec->rx_coalesce_usecs == 0 && ec->rx_max_coalesced_frames == 0))
(ec->rx_coalesce_usecs == 0 && ec->rx_max_coalesced_frames == 0) ||
ec->use_adaptive_tx_coalesce)
return -EINVAL;

for (i = 0; i < dev->num_tx_queues; i++) {
ring = &priv->tx_rings[i];
ring->dim.coal_pkts = ec->tx_max_coalesced_frames;
ring->dim.coal_usecs = ec->tx_coalesce_usecs;
if (!ec->use_adaptive_tx_coalesce && ring->dim.use_dim) {
ring->dim.coal_pkts = 1;
ring->dim.coal_usecs = 0;
}
ring->dim.use_dim = ec->use_adaptive_tx_coalesce;
bcm_sysport_set_tx_coalesce(ring);
}
for (i = 0; i < dev->num_tx_queues; i++)
bcm_sysport_set_tx_coalesce(&priv->tx_rings[i], ec);

priv->dim.coal_usecs = ec->rx_coalesce_usecs;
priv->dim.coal_pkts = ec->rx_max_coalesced_frames;
priv->rx_coalesce_usecs = ec->rx_coalesce_usecs;
priv->rx_max_coalesced_frames = ec->rx_max_coalesced_frames;
usecs = priv->rx_coalesce_usecs;
pkts = priv->rx_max_coalesced_frames;

if (!ec->use_adaptive_rx_coalesce && priv->dim.use_dim) {
priv->dim.coal_pkts = 1;
priv->dim.coal_usecs = 0;
if (ec->use_adaptive_rx_coalesce && !priv->dim.use_dim) {
moder = net_dim_get_def_profile(priv->dim.dim.mode);
usecs = moder.usec;
pkts = moder.pkts;
}

priv->dim.use_dim = ec->use_adaptive_rx_coalesce;
bcm_sysport_set_rx_coalesce(priv);

/* Apply desired coalescing parameters */
bcm_sysport_set_rx_coalesce(priv, usecs, pkts);

return 0;
}
Expand Down Expand Up @@ -940,8 +933,6 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
ring->packets += pkts_compl;
ring->bytes += bytes_compl;
u64_stats_update_end(&priv->syncp);
ring->dim.packets = pkts_compl;
ring->dim.bytes = bytes_compl;

ring->c_index = c_index;

Expand Down Expand Up @@ -987,7 +978,6 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
{
struct bcm_sysport_tx_ring *ring =
container_of(napi, struct bcm_sysport_tx_ring, napi);
struct net_dim_sample dim_sample;
unsigned int work_done = 0;

work_done = bcm_sysport_tx_reclaim(ring->priv, ring);
Expand All @@ -1004,12 +994,6 @@ static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
return 0;
}

if (ring->dim.use_dim) {
net_dim_sample(ring->dim.event_ctr, ring->dim.packets,
ring->dim.bytes, &dim_sample);
net_dim(&ring->dim.dim, dim_sample);
}

return budget;
}

Expand Down Expand Up @@ -1082,27 +1066,7 @@ static void bcm_sysport_dim_work(struct work_struct *work)
struct net_dim_cq_moder cur_profile =
net_dim_get_profile(dim->mode, dim->profile_ix);

priv->dim.coal_usecs = cur_profile.usec;
priv->dim.coal_pkts = cur_profile.pkts;

bcm_sysport_set_rx_coalesce(priv);
dim->state = NET_DIM_START_MEASURE;
}

static void bcm_sysport_dim_tx_work(struct work_struct *work)
{
struct net_dim *dim = container_of(work, struct net_dim, work);
struct bcm_sysport_net_dim *ndim =
container_of(dim, struct bcm_sysport_net_dim, dim);
struct bcm_sysport_tx_ring *ring =
container_of(ndim, struct bcm_sysport_tx_ring, dim);
struct net_dim_cq_moder cur_profile =
net_dim_get_profile(dim->mode, dim->profile_ix);

ring->dim.coal_usecs = cur_profile.usec;
ring->dim.coal_pkts = cur_profile.pkts;

bcm_sysport_set_tx_coalesce(ring);
bcm_sysport_set_rx_coalesce(priv, cur_profile.usec, cur_profile.pkts);
dim->state = NET_DIM_START_MEASURE;
}

Expand Down Expand Up @@ -1152,7 +1116,6 @@ static irqreturn_t bcm_sysport_rx_isr(int irq, void *dev_id)
continue;

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

if (likely(napi_schedule_prep(&txr->napi))) {
intrl2_0_mask_set(priv, ring_bit);
Expand Down Expand Up @@ -1185,7 +1148,6 @@ static irqreturn_t bcm_sysport_tx_isr(int irq, void *dev_id)
continue;

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

if (likely(napi_schedule_prep(&txr->napi))) {
intrl2_1_mask_set(priv, BIT(ring));
Expand Down Expand Up @@ -1451,16 +1413,37 @@ static void bcm_sysport_adj_link(struct net_device *dev)
phy_print_status(phydev);
}

static void bcm_sysport_init_dim(struct bcm_sysport_net_dim *dim,
static void bcm_sysport_init_dim(struct bcm_sysport_priv *priv,
void (*cb)(struct work_struct *work))
{
struct bcm_sysport_net_dim *dim = &priv->dim;

INIT_WORK(&dim->dim.work, cb);
dim->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
dim->event_ctr = 0;
dim->packets = 0;
dim->bytes = 0;
}

static void bcm_sysport_init_rx_coalesce(struct bcm_sysport_priv *priv)
{
struct bcm_sysport_net_dim *dim = &priv->dim;
struct net_dim_cq_moder moder;
u32 usecs, pkts;

usecs = priv->rx_coalesce_usecs;
pkts = priv->rx_max_coalesced_frames;

/* If DIM was enabled, re-apply default parameters */
if (dim->use_dim) {
moder = net_dim_get_def_profile(dim->dim.mode);
usecs = moder.usec;
pkts = moder.pkts;
}

bcm_sysport_set_rx_coalesce(priv, usecs, pkts);
}

static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
unsigned int index)
{
Expand Down Expand Up @@ -1551,7 +1534,6 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
reg |= (1 << index);
tdma_writel(priv, reg, TDMA_TIER1_ARB_0_QUEUE_EN);

bcm_sysport_init_dim(&ring->dim, bcm_sysport_dim_tx_work);
napi_enable(&ring->napi);

netif_dbg(priv, hw, priv->netdev,
Expand Down Expand Up @@ -1582,7 +1564,6 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv,
return;

napi_disable(&ring->napi);
cancel_work_sync(&ring->dim.dim.work);
netif_napi_del(&ring->napi);

bcm_sysport_tx_clean(priv, ring);
Expand Down Expand Up @@ -1703,8 +1684,6 @@ static int bcm_sysport_init_rx_ring(struct bcm_sysport_priv *priv)
rdma_writel(priv, 0, RDMA_END_ADDR_HI);
rdma_writel(priv, priv->num_rx_desc_words - 1, RDMA_END_ADDR_LO);

rdma_writel(priv, 1, RDMA_MBDONE_INTR);

netif_dbg(priv, hw, priv->netdev,
"RDMA cfg, num_rx_bds=%d, rx_bds=%p\n",
priv->num_rx_bds, priv->rx_bds);
Expand Down Expand Up @@ -1872,7 +1851,8 @@ static void bcm_sysport_netif_start(struct net_device *dev)
struct bcm_sysport_priv *priv = netdev_priv(dev);

/* Enable NAPI */
bcm_sysport_init_dim(&priv->dim, bcm_sysport_dim_work);
bcm_sysport_init_dim(priv, bcm_sysport_dim_work);
bcm_sysport_init_rx_coalesce(priv);
napi_enable(&priv->napi);

/* Enable RX interrupt and TX ring full interrupt */
Expand Down Expand Up @@ -2378,6 +2358,7 @@ static int bcm_sysport_probe(struct platform_device *pdev)
/* libphy will adjust the link state accordingly */
netif_carrier_off(dev);

priv->rx_max_coalesced_frames = 1;
u64_stats_init(&priv->syncp);

priv->dsa_notifier.notifier_call = bcm_sysport_dsa_notifier;
Expand Down
5 changes: 2 additions & 3 deletions drivers/net/ethernet/broadcom/bcmsysport.h
Original file line number Diff line number Diff line change
Expand Up @@ -701,8 +701,6 @@ struct bcm_sysport_net_dim {
u16 event_ctr;
unsigned long packets;
unsigned long bytes;
u32 coal_usecs;
u32 coal_pkts;
struct net_dim dim;
};

Expand All @@ -723,7 +721,6 @@ struct bcm_sysport_tx_ring {
struct bcm_sysport_priv *priv; /* private context backpointer */
unsigned long packets; /* packets statistics */
unsigned long bytes; /* bytes statistics */
struct bcm_sysport_net_dim dim; /* Net DIM context */
unsigned int switch_queue; /* switch port queue number */
unsigned int switch_port; /* switch port queue number */
bool inspect; /* inspect switch port and queue */
Expand Down Expand Up @@ -756,6 +753,8 @@ struct bcm_sysport_priv {
unsigned int rx_c_index;

struct bcm_sysport_net_dim dim;
u32 rx_max_coalesced_frames;
u32 rx_coalesce_usecs;

/* PHY device */
struct device_node *phy_dn;
Expand Down
Loading

0 comments on commit 95e623f

Please sign in to comment.