Skip to content

Commit 82463d9

Browse files
committed
Merge branch 'fix-trainwreck-with-ocelot-switch-statistics-counters'
Vladimir Oltean says: ==================== Fix trainwreck with Ocelot switch statistics counters While testing the patch set for preemptible traffic classes with some controlled traffic and measuring counter deltas: https://lore.kernel.org/netdev/[email protected]/ I noticed that in the output of "ethtool -S swp0 --groups eth-mac eth-phy eth-ctrl rmon -- --src emac | grep -v ': 0'", the TX counters were off. Quickly I realized that their values were permutated by 1 compared to their names, and that for example tx-rmon-etherStatsPkts64to64Octets was incrementing when tx-rmon-etherStatsPkts65to127Octets should have. Initially I suspected something having to do with the bulk reading logic, and indeed I found a bug there (fixed as 1/3), but that was not the source of the problems. Instead it revealed other problems. While dumping the regions created by the driver on my switch, I figured out that it sees a discontinuity which shouldn't have existed between reg 0x278 and reg 0x280. Discontinuity between last reg 0x0 and new reg 0x0, creating new region Discontinuity between last reg 0x108 and new reg 0x200, creating new region Discontinuity between last reg 0x278 and new reg 0x280, creating new region Discontinuity between last reg 0x2b0 and new reg 0x400, creating new region region of 67 contiguous counters starting with SYS:STAT:CNT[0x000] region of 31 contiguous counters starting with SYS:STAT:CNT[0x080] region of 13 contiguous counters starting with SYS:STAT:CNT[0x0a0] region of 18 contiguous counters starting with SYS:STAT:CNT[0x100] That is where TX_MM_HOLD should have been, and that was the bug, since it was missing. After adding it, the regions look like this and the off-by-one issue is resolved: Discontinuity between last reg 0x000000 and new reg 0x000000, creating new region Discontinuity between last reg 0x000108 and new reg 0x000200, creating new region Discontinuity between last reg 0x0002b0 and new reg 0x000400, creating new region region of 67 contiguous counters starting with SYS:STAT:CNT[0x000] region of 45 contiguous counters starting with SYS:STAT:CNT[0x080] region of 18 contiguous counters starting with SYS:STAT:CNT[0x100] However, as I am thinking out loud, it should have not reported the other counters as off by one even when skipping TX_MM_HOLD... after all, on Ocelot/Seville, there are more counters which need to be skipped. Which is when I investigated and noticed the bug solved in 2/3. I've validated that both on native VSC9959 (which uses ocelot_mm_stats_layout) as well as by faking the other switches by making VSC9959 use the plain ocelot_stats_layout. To summarize: on all Ocelot switches, the TX counters and drop counters are completely broken. The RX counters are mostly fine. With this occasion, I have collected more cleanup patches in this area, which I'm going to submit after the net -> net-next merge. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 8e50ed7 + 5291099 commit 82463d9

File tree

1 file changed

+7
-4
lines changed

1 file changed

+7
-4
lines changed

drivers/net/ethernet/mscc/ocelot_stats.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ struct ocelot_stat_layout {
258258
struct ocelot_stats_region {
259259
struct list_head node;
260260
u32 base;
261+
enum ocelot_stat first_stat;
261262
int count;
262263
u32 *buf;
263264
};
@@ -273,6 +274,7 @@ static const struct ocelot_stat_layout ocelot_mm_stats_layout[OCELOT_NUM_STATS]
273274
OCELOT_STAT(RX_ASSEMBLY_OK),
274275
OCELOT_STAT(RX_MERGE_FRAGMENTS),
275276
OCELOT_STAT(TX_MERGE_FRAGMENTS),
277+
OCELOT_STAT(TX_MM_HOLD),
276278
OCELOT_STAT(RX_PMAC_OCTETS),
277279
OCELOT_STAT(RX_PMAC_UNICAST),
278280
OCELOT_STAT(RX_PMAC_MULTICAST),
@@ -341,11 +343,12 @@ static int ocelot_port_update_stats(struct ocelot *ocelot, int port)
341343
*/
342344
static void ocelot_port_transfer_stats(struct ocelot *ocelot, int port)
343345
{
344-
unsigned int idx = port * OCELOT_NUM_STATS;
345346
struct ocelot_stats_region *region;
346347
int j;
347348

348349
list_for_each_entry(region, &ocelot->stats_regions, node) {
350+
unsigned int idx = port * OCELOT_NUM_STATS + region->first_stat;
351+
349352
for (j = 0; j < region->count; j++) {
350353
u64 *stat = &ocelot->stats[idx + j];
351354
u64 val = region->buf[j];
@@ -355,8 +358,6 @@ static void ocelot_port_transfer_stats(struct ocelot *ocelot, int port)
355358

356359
*stat = (*stat & ~(u64)U32_MAX) + val;
357360
}
358-
359-
idx += region->count;
360361
}
361362
}
362363

@@ -899,7 +900,8 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
899900
if (!layout[i].reg)
900901
continue;
901902

902-
if (region && layout[i].reg == last + 4) {
903+
if (region && ocelot->map[SYS][layout[i].reg & REG_MASK] ==
904+
ocelot->map[SYS][last & REG_MASK] + 4) {
903905
region->count++;
904906
} else {
905907
region = devm_kzalloc(ocelot->dev, sizeof(*region),
@@ -914,6 +916,7 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
914916
WARN_ON(last >= layout[i].reg);
915917

916918
region->base = layout[i].reg;
919+
region->first_stat = i;
917920
region->count = 1;
918921
list_add_tail(&region->node, &ocelot->stats_regions);
919922
}

0 commit comments

Comments
 (0)