Skip to content

Commit 489e8a2

Browse files
wingmankwokdavem330
authored andcommitted
net: netcp: Fixes to CPSW statistics collection
In certain applications it's beneficial to allow the CPSW h/w stats counters to continue to increment even while the kernel polls them. This patch implements this behavior for both 1G and 10G ethernet subsystem modules. Signed-off-by: WingMan Kwok <w-kwok2@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent fbf64c1 commit 489e8a2

File tree

1 file changed

+75
-11
lines changed

1 file changed

+75
-11
lines changed

drivers/net/ethernet/ti/netcp_ethss.c

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ struct gbe_priv {
642642
bool enable_ale;
643643
u8 max_num_slaves;
644644
u8 max_num_ports; /* max_num_slaves + 1 */
645+
u8 num_stats_mods;
645646
struct netcp_tx_pipe tx_pipe;
646647

647648
int host_port;
@@ -671,6 +672,7 @@ struct gbe_priv {
671672
struct net_device *dummy_ndev;
672673

673674
u64 *hw_stats;
675+
u32 *hw_stats_prev;
674676
const struct netcp_ethtool_stat *et_stats;
675677
int num_et_stats;
676678
/* Lock for updating the hwstats */
@@ -1550,25 +1552,37 @@ static int keystone_get_sset_count(struct net_device *ndev, int stringset)
15501552
}
15511553
}
15521554

1555+
static void gbe_reset_mod_stats(struct gbe_priv *gbe_dev, int stats_mod)
1556+
{
1557+
void __iomem *base = gbe_dev->hw_stats_regs[stats_mod];
1558+
u32 __iomem *p_stats_entry;
1559+
int i;
1560+
1561+
for (i = 0; i < gbe_dev->num_et_stats; i++) {
1562+
if (gbe_dev->et_stats[i].type == stats_mod) {
1563+
p_stats_entry = base + gbe_dev->et_stats[i].offset;
1564+
gbe_dev->hw_stats[i] = 0;
1565+
gbe_dev->hw_stats_prev[i] = readl(p_stats_entry);
1566+
}
1567+
}
1568+
}
1569+
15531570
static inline void gbe_update_hw_stats_entry(struct gbe_priv *gbe_dev,
15541571
int et_stats_entry)
15551572
{
15561573
void __iomem *base = NULL;
1557-
u32 __iomem *p;
1558-
u32 tmp = 0;
1574+
u32 __iomem *p_stats_entry;
1575+
u32 curr, delta;
15591576

15601577
/* The hw_stats_regs pointers are already
15611578
* properly set to point to the right base:
15621579
*/
15631580
base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[et_stats_entry].type];
1564-
p = base + gbe_dev->et_stats[et_stats_entry].offset;
1565-
tmp = readl(p);
1566-
gbe_dev->hw_stats[et_stats_entry] += tmp;
1567-
1568-
/* write-to-decrement:
1569-
* new register value = old register value - write value
1570-
*/
1571-
writel(tmp, p);
1581+
p_stats_entry = base + gbe_dev->et_stats[et_stats_entry].offset;
1582+
curr = readl(p_stats_entry);
1583+
delta = curr - gbe_dev->hw_stats_prev[et_stats_entry];
1584+
gbe_dev->hw_stats_prev[et_stats_entry] = curr;
1585+
gbe_dev->hw_stats[et_stats_entry] += delta;
15721586
}
15731587

15741588
static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data)
@@ -1607,6 +1621,12 @@ static inline void gbe_stats_mod_visible_ver14(struct gbe_priv *gbe_dev,
16071621
writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en));
16081622
}
16091623

1624+
static void gbe_reset_mod_stats_ver14(struct gbe_priv *gbe_dev, int stats_mod)
1625+
{
1626+
gbe_stats_mod_visible_ver14(gbe_dev, stats_mod);
1627+
gbe_reset_mod_stats(gbe_dev, stats_mod);
1628+
}
1629+
16101630
static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data)
16111631
{
16121632
u32 half_num_et_stats = (gbe_dev->num_et_stats / 2);
@@ -2560,6 +2580,7 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev,
25602580
}
25612581
gbe_dev->xgbe_serdes_regs = regs;
25622582

2583+
gbe_dev->num_stats_mods = gbe_dev->max_num_ports;
25632584
gbe_dev->et_stats = xgbe10_et_stats;
25642585
gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats);
25652586

@@ -2571,6 +2592,16 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev,
25712592
return -ENOMEM;
25722593
}
25732594

2595+
gbe_dev->hw_stats_prev =
2596+
devm_kzalloc(gbe_dev->dev,
2597+
gbe_dev->num_et_stats * sizeof(u32),
2598+
GFP_KERNEL);
2599+
if (!gbe_dev->hw_stats_prev) {
2600+
dev_err(gbe_dev->dev,
2601+
"hw_stats_prev memory allocation failed\n");
2602+
return -ENOMEM;
2603+
}
2604+
25742605
gbe_dev->ss_version = XGBE_SS_VERSION_10;
25752606
gbe_dev->sgmii_port_regs = gbe_dev->ss_regs +
25762607
XGBE10_SGMII_MODULE_OFFSET;
@@ -2668,6 +2699,7 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev,
26682699
}
26692700
gbe_dev->switch_regs = regs;
26702701

2702+
gbe_dev->num_stats_mods = gbe_dev->max_num_slaves;
26712703
gbe_dev->et_stats = gbe13_et_stats;
26722704
gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats);
26732705

@@ -2679,6 +2711,16 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev,
26792711
return -ENOMEM;
26802712
}
26812713

2714+
gbe_dev->hw_stats_prev =
2715+
devm_kzalloc(gbe_dev->dev,
2716+
gbe_dev->num_et_stats * sizeof(u32),
2717+
GFP_KERNEL);
2718+
if (!gbe_dev->hw_stats_prev) {
2719+
dev_err(gbe_dev->dev,
2720+
"hw_stats_prev memory allocation failed\n");
2721+
return -ENOMEM;
2722+
}
2723+
26822724
gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBE13_SGMII_MODULE_OFFSET;
26832725
gbe_dev->host_port_regs = gbe_dev->switch_regs + GBE13_HOST_PORT_OFFSET;
26842726

@@ -2722,6 +2764,7 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev,
27222764
void __iomem *regs;
27232765
int i, ret;
27242766

2767+
gbe_dev->num_stats_mods = gbe_dev->max_num_ports;
27252768
gbe_dev->et_stats = gbenu_et_stats;
27262769

27272770
if (IS_SS_ID_NU(gbe_dev))
@@ -2739,6 +2782,16 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev,
27392782
return -ENOMEM;
27402783
}
27412784

2785+
gbe_dev->hw_stats_prev =
2786+
devm_kzalloc(gbe_dev->dev,
2787+
gbe_dev->num_et_stats * sizeof(u32),
2788+
GFP_KERNEL);
2789+
if (!gbe_dev->hw_stats_prev) {
2790+
dev_err(gbe_dev->dev,
2791+
"hw_stats_prev memory allocation failed\n");
2792+
return -ENOMEM;
2793+
}
2794+
27422795
ret = of_address_to_resource(node, GBENU_SM_REG_INDEX, &res);
27432796
if (ret) {
27442797
dev_err(gbe_dev->dev,
@@ -2797,7 +2850,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
27972850
struct cpsw_ale_params ale_params;
27982851
struct gbe_priv *gbe_dev;
27992852
u32 slave_num;
2800-
int ret = 0;
2853+
int i, ret = 0;
28012854

28022855
if (!node) {
28032856
dev_err(dev, "device tree info unavailable\n");
@@ -2945,6 +2998,15 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
29452998
/* initialize host port */
29462999
gbe_init_host_port(gbe_dev);
29473000

3001+
spin_lock_bh(&gbe_dev->hw_stats_lock);
3002+
for (i = 0; i < gbe_dev->num_stats_mods; i++) {
3003+
if (gbe_dev->ss_version == GBE_SS_VERSION_14)
3004+
gbe_reset_mod_stats_ver14(gbe_dev, i);
3005+
else
3006+
gbe_reset_mod_stats(gbe_dev, i);
3007+
}
3008+
spin_unlock_bh(&gbe_dev->hw_stats_lock);
3009+
29483010
init_timer(&gbe_dev->timer);
29493011
gbe_dev->timer.data = (unsigned long)gbe_dev;
29503012
gbe_dev->timer.function = netcp_ethss_timer;
@@ -2956,6 +3018,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
29563018
quit:
29573019
if (gbe_dev->hw_stats)
29583020
devm_kfree(dev, gbe_dev->hw_stats);
3021+
if (gbe_dev->hw_stats_prev)
3022+
devm_kfree(dev, gbe_dev->hw_stats_prev);
29593023
cpsw_ale_destroy(gbe_dev->ale);
29603024
if (gbe_dev->ss_regs)
29613025
devm_iounmap(dev, gbe_dev->ss_regs);

0 commit comments

Comments
 (0)