Skip to content

Commit f5e2ed0

Browse files
lunndavem330
authored andcommitted
dsa: mv88e6xxx: Add Second back of statistics
The 6320 family of switch chips has a second bank for statistics, but is missing three statistics in the port registers. Generalise and extend the code: * adding a field to the statistics table indicating the bank/register set where each statistics is. * add a function indicating if an individual statistics is available on this device * calculate at run time the sset_count. * return strings based on the available statistics of the device * return statistics based on the available statistics of the device * Add support for reading from the second bank. Signed-off-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ff5756d commit f5e2ed0

File tree

2 files changed

+129
-109
lines changed

2 files changed

+129
-109
lines changed

drivers/net/dsa/mv88e6xxx.c

Lines changed: 121 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -617,98 +617,112 @@ static void _mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val)
617617
}
618618

619619
static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
620-
{ "in_good_octets", 8, 0x00, },
621-
{ "in_bad_octets", 4, 0x02, },
622-
{ "in_unicast", 4, 0x04, },
623-
{ "in_broadcasts", 4, 0x06, },
624-
{ "in_multicasts", 4, 0x07, },
625-
{ "in_pause", 4, 0x16, },
626-
{ "in_undersize", 4, 0x18, },
627-
{ "in_fragments", 4, 0x19, },
628-
{ "in_oversize", 4, 0x1a, },
629-
{ "in_jabber", 4, 0x1b, },
630-
{ "in_rx_error", 4, 0x1c, },
631-
{ "in_fcs_error", 4, 0x1d, },
632-
{ "out_octets", 8, 0x0e, },
633-
{ "out_unicast", 4, 0x10, },
634-
{ "out_broadcasts", 4, 0x13, },
635-
{ "out_multicasts", 4, 0x12, },
636-
{ "out_pause", 4, 0x15, },
637-
{ "excessive", 4, 0x11, },
638-
{ "collisions", 4, 0x1e, },
639-
{ "deferred", 4, 0x05, },
640-
{ "single", 4, 0x14, },
641-
{ "multiple", 4, 0x17, },
642-
{ "out_fcs_error", 4, 0x03, },
643-
{ "late", 4, 0x1f, },
644-
{ "hist_64bytes", 4, 0x08, },
645-
{ "hist_65_127bytes", 4, 0x09, },
646-
{ "hist_128_255bytes", 4, 0x0a, },
647-
{ "hist_256_511bytes", 4, 0x0b, },
648-
{ "hist_512_1023bytes", 4, 0x0c, },
649-
{ "hist_1024_max_bytes", 4, 0x0d, },
650-
/* Not all devices have the following counters */
651-
{ "sw_in_discards", 4, 0x110, },
652-
{ "sw_in_filtered", 2, 0x112, },
653-
{ "sw_out_filtered", 2, 0x113, },
654-
620+
{ "in_good_octets", 8, 0x00, BANK0, },
621+
{ "in_bad_octets", 4, 0x02, BANK0, },
622+
{ "in_unicast", 4, 0x04, BANK0, },
623+
{ "in_broadcasts", 4, 0x06, BANK0, },
624+
{ "in_multicasts", 4, 0x07, BANK0, },
625+
{ "in_pause", 4, 0x16, BANK0, },
626+
{ "in_undersize", 4, 0x18, BANK0, },
627+
{ "in_fragments", 4, 0x19, BANK0, },
628+
{ "in_oversize", 4, 0x1a, BANK0, },
629+
{ "in_jabber", 4, 0x1b, BANK0, },
630+
{ "in_rx_error", 4, 0x1c, BANK0, },
631+
{ "in_fcs_error", 4, 0x1d, BANK0, },
632+
{ "out_octets", 8, 0x0e, BANK0, },
633+
{ "out_unicast", 4, 0x10, BANK0, },
634+
{ "out_broadcasts", 4, 0x13, BANK0, },
635+
{ "out_multicasts", 4, 0x12, BANK0, },
636+
{ "out_pause", 4, 0x15, BANK0, },
637+
{ "excessive", 4, 0x11, BANK0, },
638+
{ "collisions", 4, 0x1e, BANK0, },
639+
{ "deferred", 4, 0x05, BANK0, },
640+
{ "single", 4, 0x14, BANK0, },
641+
{ "multiple", 4, 0x17, BANK0, },
642+
{ "out_fcs_error", 4, 0x03, BANK0, },
643+
{ "late", 4, 0x1f, BANK0, },
644+
{ "hist_64bytes", 4, 0x08, BANK0, },
645+
{ "hist_65_127bytes", 4, 0x09, BANK0, },
646+
{ "hist_128_255bytes", 4, 0x0a, BANK0, },
647+
{ "hist_256_511bytes", 4, 0x0b, BANK0, },
648+
{ "hist_512_1023bytes", 4, 0x0c, BANK0, },
649+
{ "hist_1024_max_bytes", 4, 0x0d, BANK0, },
650+
{ "sw_in_discards", 4, 0x10, PORT, },
651+
{ "sw_in_filtered", 2, 0x12, PORT, },
652+
{ "sw_out_filtered", 2, 0x13, PORT, },
653+
{ "in_discards", 4, 0x00 | GLOBAL_STATS_OP_BANK_1, BANK1, },
654+
{ "in_filtered", 4, 0x01 | GLOBAL_STATS_OP_BANK_1, BANK1, },
655+
{ "in_accepted", 4, 0x02 | GLOBAL_STATS_OP_BANK_1, BANK1, },
656+
{ "in_bad_accepted", 4, 0x03 | GLOBAL_STATS_OP_BANK_1, BANK1, },
657+
{ "in_good_avb_class_a", 4, 0x04 | GLOBAL_STATS_OP_BANK_1, BANK1, },
658+
{ "in_good_avb_class_b", 4, 0x05 | GLOBAL_STATS_OP_BANK_1, BANK1, },
659+
{ "in_bad_avb_class_a", 4, 0x06 | GLOBAL_STATS_OP_BANK_1, BANK1, },
660+
{ "in_bad_avb_class_b", 4, 0x07 | GLOBAL_STATS_OP_BANK_1, BANK1, },
661+
{ "tcam_counter_0", 4, 0x08 | GLOBAL_STATS_OP_BANK_1, BANK1, },
662+
{ "tcam_counter_1", 4, 0x09 | GLOBAL_STATS_OP_BANK_1, BANK1, },
663+
{ "tcam_counter_2", 4, 0x0a | GLOBAL_STATS_OP_BANK_1, BANK1, },
664+
{ "tcam_counter_3", 4, 0x0b | GLOBAL_STATS_OP_BANK_1, BANK1, },
665+
{ "in_da_unknown", 4, 0x0e | GLOBAL_STATS_OP_BANK_1, BANK1, },
666+
{ "in_management", 4, 0x0f | GLOBAL_STATS_OP_BANK_1, BANK1, },
667+
{ "out_queue_0", 4, 0x10 | GLOBAL_STATS_OP_BANK_1, BANK1, },
668+
{ "out_queue_1", 4, 0x11 | GLOBAL_STATS_OP_BANK_1, BANK1, },
669+
{ "out_queue_2", 4, 0x12 | GLOBAL_STATS_OP_BANK_1, BANK1, },
670+
{ "out_queue_3", 4, 0x13 | GLOBAL_STATS_OP_BANK_1, BANK1, },
671+
{ "out_queue_4", 4, 0x14 | GLOBAL_STATS_OP_BANK_1, BANK1, },
672+
{ "out_queue_5", 4, 0x15 | GLOBAL_STATS_OP_BANK_1, BANK1, },
673+
{ "out_queue_6", 4, 0x16 | GLOBAL_STATS_OP_BANK_1, BANK1, },
674+
{ "out_queue_7", 4, 0x17 | GLOBAL_STATS_OP_BANK_1, BANK1, },
675+
{ "out_cut_through", 4, 0x18 | GLOBAL_STATS_OP_BANK_1, BANK1, },
676+
{ "out_octets_a", 4, 0x1a | GLOBAL_STATS_OP_BANK_1, BANK1, },
677+
{ "out_octets_b", 4, 0x1b | GLOBAL_STATS_OP_BANK_1, BANK1, },
678+
{ "out_management", 4, 0x1f | GLOBAL_STATS_OP_BANK_1, BANK1, },
655679
};
656680

657-
static bool have_sw_in_discards(struct dsa_switch *ds)
681+
static bool mv88e6xxx_has_stat(struct dsa_switch *ds,
682+
struct mv88e6xxx_hw_stat *stat)
658683
{
659-
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
660-
661-
switch (ps->id) {
662-
case PORT_SWITCH_ID_6095: case PORT_SWITCH_ID_6161:
663-
case PORT_SWITCH_ID_6165: case PORT_SWITCH_ID_6171:
664-
case PORT_SWITCH_ID_6172: case PORT_SWITCH_ID_6176:
665-
case PORT_SWITCH_ID_6182: case PORT_SWITCH_ID_6185:
666-
case PORT_SWITCH_ID_6352:
684+
switch (stat->type) {
685+
case BANK0:
667686
return true;
668-
default:
669-
return false;
670-
}
671-
}
672-
673-
static void _mv88e6xxx_get_strings(struct dsa_switch *ds,
674-
int nr_stats,
675-
struct mv88e6xxx_hw_stat *stats,
676-
int port, uint8_t *data)
677-
{
678-
int i;
679-
680-
for (i = 0; i < nr_stats; i++) {
681-
memcpy(data + i * ETH_GSTRING_LEN,
682-
stats[i].string, ETH_GSTRING_LEN);
687+
case BANK1:
688+
return mv88e6xxx_6320_family(ds);
689+
case PORT:
690+
return mv88e6xxx_6095_family(ds) ||
691+
mv88e6xxx_6185_family(ds) ||
692+
mv88e6xxx_6097_family(ds) ||
693+
mv88e6xxx_6165_family(ds) ||
694+
mv88e6xxx_6351_family(ds) ||
695+
mv88e6xxx_6352_family(ds);
683696
}
697+
return false;
684698
}
685699

686700
static uint64_t _mv88e6xxx_get_ethtool_stat(struct dsa_switch *ds,
687-
int stat,
688-
struct mv88e6xxx_hw_stat *stats,
701+
struct mv88e6xxx_hw_stat *s,
689702
int port)
690703
{
691-
struct mv88e6xxx_hw_stat *s = stats + stat;
692704
u32 low;
693705
u32 high = 0;
694706
int ret;
695707
u64 value;
696708

697-
if (s->reg >= 0x100) {
698-
ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
699-
s->reg - 0x100);
709+
switch (s->type) {
710+
case PORT:
711+
ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), s->reg);
700712
if (ret < 0)
701713
return UINT64_MAX;
702714

703715
low = ret;
704716
if (s->sizeof_stat == 4) {
705717
ret = _mv88e6xxx_reg_read(ds, REG_PORT(port),
706-
s->reg - 0x100 + 1);
718+
s->reg + 1);
707719
if (ret < 0)
708720
return UINT64_MAX;
709721
high = ret;
710722
}
711-
} else {
723+
break;
724+
case BANK0:
725+
case BANK1:
712726
_mv88e6xxx_stats_read(ds, s->reg, &low);
713727
if (s->sizeof_stat == 8)
714728
_mv88e6xxx_stats_read(ds, s->reg + 1, &high);
@@ -717,61 +731,59 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct dsa_switch *ds,
717731
return value;
718732
}
719733

720-
static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
721-
int nr_stats,
722-
struct mv88e6xxx_hw_stat *stats,
723-
int port, uint64_t *data)
734+
void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
724735
{
725-
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
726-
int ret;
727-
int i;
728-
729-
mutex_lock(&ps->smi_mutex);
736+
struct mv88e6xxx_hw_stat *stat;
737+
int i, j;
730738

731-
ret = _mv88e6xxx_stats_snapshot(ds, port);
732-
if (ret < 0) {
733-
mutex_unlock(&ps->smi_mutex);
734-
return;
739+
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
740+
stat = &mv88e6xxx_hw_stats[i];
741+
if (mv88e6xxx_has_stat(ds, stat)) {
742+
memcpy(data + j * ETH_GSTRING_LEN, stat->string,
743+
ETH_GSTRING_LEN);
744+
j++;
745+
}
735746
}
736-
737-
/* Read each of the counters. */
738-
for (i = 0; i < nr_stats; i++)
739-
data[i] = _mv88e6xxx_get_ethtool_stat(ds, i, stats, port);
740-
741-
mutex_unlock(&ps->smi_mutex);
742-
}
743-
744-
/* All the statistics in the table */
745-
void
746-
mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
747-
{
748-
if (have_sw_in_discards(ds))
749-
_mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
750-
mv88e6xxx_hw_stats, port, data);
751-
else
752-
_mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
753-
mv88e6xxx_hw_stats, port, data);
754747
}
755748

756749
int mv88e6xxx_get_sset_count(struct dsa_switch *ds)
757750
{
758-
if (have_sw_in_discards(ds))
759-
return ARRAY_SIZE(mv88e6xxx_hw_stats);
760-
return ARRAY_SIZE(mv88e6xxx_hw_stats) - 3;
751+
struct mv88e6xxx_hw_stat *stat;
752+
int i, j;
753+
754+
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
755+
stat = &mv88e6xxx_hw_stats[i];
756+
if (mv88e6xxx_has_stat(ds, stat))
757+
j++;
758+
}
759+
return j;
761760
}
762761

763762
void
764763
mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
765764
int port, uint64_t *data)
766765
{
767-
if (have_sw_in_discards(ds))
768-
_mv88e6xxx_get_ethtool_stats(
769-
ds, ARRAY_SIZE(mv88e6xxx_hw_stats),
770-
mv88e6xxx_hw_stats, port, data);
771-
else
772-
_mv88e6xxx_get_ethtool_stats(
773-
ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3,
774-
mv88e6xxx_hw_stats, port, data);
766+
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
767+
struct mv88e6xxx_hw_stat *stat;
768+
int ret;
769+
int i, j;
770+
771+
mutex_lock(&ps->smi_mutex);
772+
773+
ret = _mv88e6xxx_stats_snapshot(ds, port);
774+
if (ret < 0) {
775+
mutex_unlock(&ps->smi_mutex);
776+
return;
777+
}
778+
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
779+
stat = &mv88e6xxx_hw_stats[i];
780+
if (mv88e6xxx_has_stat(ds, stat)) {
781+
data[j] = _mv88e6xxx_get_ethtool_stat(ds, stat, port);
782+
j++;
783+
}
784+
}
785+
786+
mutex_unlock(&ps->smi_mutex);
775787
}
776788

777789
int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)

drivers/net/dsa/mv88e6xxx.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@
288288
#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY)
289289
#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY)
290290
#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY)
291+
#define GLOBAL_STATS_OP_BANK_1 BIT(9)
291292
#define GLOBAL_STATS_COUNTER_32 0x1e
292293
#define GLOBAL_STATS_COUNTER_01 0x1f
293294

@@ -420,10 +421,17 @@ struct mv88e6xxx_priv_state {
420421
struct work_struct bridge_work;
421422
};
422423

424+
enum stat_type {
425+
BANK0,
426+
BANK1,
427+
PORT,
428+
};
429+
423430
struct mv88e6xxx_hw_stat {
424431
char string[ETH_GSTRING_LEN];
425432
int sizeof_stat;
426433
int reg;
434+
enum stat_type type;
427435
};
428436

429437
int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active);

0 commit comments

Comments
 (0)