162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT)
262306a36Sopenharmony_ci/* Statistics for Ocelot switch family
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2017 Microsemi Corporation
562306a36Sopenharmony_ci * Copyright 2022 NXP
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/ethtool_netlink.h>
862306a36Sopenharmony_ci#include <linux/spinlock.h>
962306a36Sopenharmony_ci#include <linux/mutex.h>
1062306a36Sopenharmony_ci#include <linux/workqueue.h>
1162306a36Sopenharmony_ci#include "ocelot.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cienum ocelot_stat {
1462306a36Sopenharmony_ci	OCELOT_STAT_RX_OCTETS,
1562306a36Sopenharmony_ci	OCELOT_STAT_RX_UNICAST,
1662306a36Sopenharmony_ci	OCELOT_STAT_RX_MULTICAST,
1762306a36Sopenharmony_ci	OCELOT_STAT_RX_BROADCAST,
1862306a36Sopenharmony_ci	OCELOT_STAT_RX_SHORTS,
1962306a36Sopenharmony_ci	OCELOT_STAT_RX_FRAGMENTS,
2062306a36Sopenharmony_ci	OCELOT_STAT_RX_JABBERS,
2162306a36Sopenharmony_ci	OCELOT_STAT_RX_CRC_ALIGN_ERRS,
2262306a36Sopenharmony_ci	OCELOT_STAT_RX_SYM_ERRS,
2362306a36Sopenharmony_ci	OCELOT_STAT_RX_64,
2462306a36Sopenharmony_ci	OCELOT_STAT_RX_65_127,
2562306a36Sopenharmony_ci	OCELOT_STAT_RX_128_255,
2662306a36Sopenharmony_ci	OCELOT_STAT_RX_256_511,
2762306a36Sopenharmony_ci	OCELOT_STAT_RX_512_1023,
2862306a36Sopenharmony_ci	OCELOT_STAT_RX_1024_1526,
2962306a36Sopenharmony_ci	OCELOT_STAT_RX_1527_MAX,
3062306a36Sopenharmony_ci	OCELOT_STAT_RX_PAUSE,
3162306a36Sopenharmony_ci	OCELOT_STAT_RX_CONTROL,
3262306a36Sopenharmony_ci	OCELOT_STAT_RX_LONGS,
3362306a36Sopenharmony_ci	OCELOT_STAT_RX_CLASSIFIED_DROPS,
3462306a36Sopenharmony_ci	OCELOT_STAT_RX_RED_PRIO_0,
3562306a36Sopenharmony_ci	OCELOT_STAT_RX_RED_PRIO_1,
3662306a36Sopenharmony_ci	OCELOT_STAT_RX_RED_PRIO_2,
3762306a36Sopenharmony_ci	OCELOT_STAT_RX_RED_PRIO_3,
3862306a36Sopenharmony_ci	OCELOT_STAT_RX_RED_PRIO_4,
3962306a36Sopenharmony_ci	OCELOT_STAT_RX_RED_PRIO_5,
4062306a36Sopenharmony_ci	OCELOT_STAT_RX_RED_PRIO_6,
4162306a36Sopenharmony_ci	OCELOT_STAT_RX_RED_PRIO_7,
4262306a36Sopenharmony_ci	OCELOT_STAT_RX_YELLOW_PRIO_0,
4362306a36Sopenharmony_ci	OCELOT_STAT_RX_YELLOW_PRIO_1,
4462306a36Sopenharmony_ci	OCELOT_STAT_RX_YELLOW_PRIO_2,
4562306a36Sopenharmony_ci	OCELOT_STAT_RX_YELLOW_PRIO_3,
4662306a36Sopenharmony_ci	OCELOT_STAT_RX_YELLOW_PRIO_4,
4762306a36Sopenharmony_ci	OCELOT_STAT_RX_YELLOW_PRIO_5,
4862306a36Sopenharmony_ci	OCELOT_STAT_RX_YELLOW_PRIO_6,
4962306a36Sopenharmony_ci	OCELOT_STAT_RX_YELLOW_PRIO_7,
5062306a36Sopenharmony_ci	OCELOT_STAT_RX_GREEN_PRIO_0,
5162306a36Sopenharmony_ci	OCELOT_STAT_RX_GREEN_PRIO_1,
5262306a36Sopenharmony_ci	OCELOT_STAT_RX_GREEN_PRIO_2,
5362306a36Sopenharmony_ci	OCELOT_STAT_RX_GREEN_PRIO_3,
5462306a36Sopenharmony_ci	OCELOT_STAT_RX_GREEN_PRIO_4,
5562306a36Sopenharmony_ci	OCELOT_STAT_RX_GREEN_PRIO_5,
5662306a36Sopenharmony_ci	OCELOT_STAT_RX_GREEN_PRIO_6,
5762306a36Sopenharmony_ci	OCELOT_STAT_RX_GREEN_PRIO_7,
5862306a36Sopenharmony_ci	OCELOT_STAT_RX_ASSEMBLY_ERRS,
5962306a36Sopenharmony_ci	OCELOT_STAT_RX_SMD_ERRS,
6062306a36Sopenharmony_ci	OCELOT_STAT_RX_ASSEMBLY_OK,
6162306a36Sopenharmony_ci	OCELOT_STAT_RX_MERGE_FRAGMENTS,
6262306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_OCTETS,
6362306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_UNICAST,
6462306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_MULTICAST,
6562306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_BROADCAST,
6662306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_SHORTS,
6762306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_FRAGMENTS,
6862306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_JABBERS,
6962306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS,
7062306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_SYM_ERRS,
7162306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_64,
7262306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_65_127,
7362306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_128_255,
7462306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_256_511,
7562306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_512_1023,
7662306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_1024_1526,
7762306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_1527_MAX,
7862306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_PAUSE,
7962306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_CONTROL,
8062306a36Sopenharmony_ci	OCELOT_STAT_RX_PMAC_LONGS,
8162306a36Sopenharmony_ci	OCELOT_STAT_TX_OCTETS,
8262306a36Sopenharmony_ci	OCELOT_STAT_TX_UNICAST,
8362306a36Sopenharmony_ci	OCELOT_STAT_TX_MULTICAST,
8462306a36Sopenharmony_ci	OCELOT_STAT_TX_BROADCAST,
8562306a36Sopenharmony_ci	OCELOT_STAT_TX_COLLISION,
8662306a36Sopenharmony_ci	OCELOT_STAT_TX_DROPS,
8762306a36Sopenharmony_ci	OCELOT_STAT_TX_PAUSE,
8862306a36Sopenharmony_ci	OCELOT_STAT_TX_64,
8962306a36Sopenharmony_ci	OCELOT_STAT_TX_65_127,
9062306a36Sopenharmony_ci	OCELOT_STAT_TX_128_255,
9162306a36Sopenharmony_ci	OCELOT_STAT_TX_256_511,
9262306a36Sopenharmony_ci	OCELOT_STAT_TX_512_1023,
9362306a36Sopenharmony_ci	OCELOT_STAT_TX_1024_1526,
9462306a36Sopenharmony_ci	OCELOT_STAT_TX_1527_MAX,
9562306a36Sopenharmony_ci	OCELOT_STAT_TX_YELLOW_PRIO_0,
9662306a36Sopenharmony_ci	OCELOT_STAT_TX_YELLOW_PRIO_1,
9762306a36Sopenharmony_ci	OCELOT_STAT_TX_YELLOW_PRIO_2,
9862306a36Sopenharmony_ci	OCELOT_STAT_TX_YELLOW_PRIO_3,
9962306a36Sopenharmony_ci	OCELOT_STAT_TX_YELLOW_PRIO_4,
10062306a36Sopenharmony_ci	OCELOT_STAT_TX_YELLOW_PRIO_5,
10162306a36Sopenharmony_ci	OCELOT_STAT_TX_YELLOW_PRIO_6,
10262306a36Sopenharmony_ci	OCELOT_STAT_TX_YELLOW_PRIO_7,
10362306a36Sopenharmony_ci	OCELOT_STAT_TX_GREEN_PRIO_0,
10462306a36Sopenharmony_ci	OCELOT_STAT_TX_GREEN_PRIO_1,
10562306a36Sopenharmony_ci	OCELOT_STAT_TX_GREEN_PRIO_2,
10662306a36Sopenharmony_ci	OCELOT_STAT_TX_GREEN_PRIO_3,
10762306a36Sopenharmony_ci	OCELOT_STAT_TX_GREEN_PRIO_4,
10862306a36Sopenharmony_ci	OCELOT_STAT_TX_GREEN_PRIO_5,
10962306a36Sopenharmony_ci	OCELOT_STAT_TX_GREEN_PRIO_6,
11062306a36Sopenharmony_ci	OCELOT_STAT_TX_GREEN_PRIO_7,
11162306a36Sopenharmony_ci	OCELOT_STAT_TX_AGED,
11262306a36Sopenharmony_ci	OCELOT_STAT_TX_MM_HOLD,
11362306a36Sopenharmony_ci	OCELOT_STAT_TX_MERGE_FRAGMENTS,
11462306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_OCTETS,
11562306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_UNICAST,
11662306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_MULTICAST,
11762306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_BROADCAST,
11862306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_PAUSE,
11962306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_64,
12062306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_65_127,
12162306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_128_255,
12262306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_256_511,
12362306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_512_1023,
12462306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_1024_1526,
12562306a36Sopenharmony_ci	OCELOT_STAT_TX_PMAC_1527_MAX,
12662306a36Sopenharmony_ci	OCELOT_STAT_DROP_LOCAL,
12762306a36Sopenharmony_ci	OCELOT_STAT_DROP_TAIL,
12862306a36Sopenharmony_ci	OCELOT_STAT_DROP_YELLOW_PRIO_0,
12962306a36Sopenharmony_ci	OCELOT_STAT_DROP_YELLOW_PRIO_1,
13062306a36Sopenharmony_ci	OCELOT_STAT_DROP_YELLOW_PRIO_2,
13162306a36Sopenharmony_ci	OCELOT_STAT_DROP_YELLOW_PRIO_3,
13262306a36Sopenharmony_ci	OCELOT_STAT_DROP_YELLOW_PRIO_4,
13362306a36Sopenharmony_ci	OCELOT_STAT_DROP_YELLOW_PRIO_5,
13462306a36Sopenharmony_ci	OCELOT_STAT_DROP_YELLOW_PRIO_6,
13562306a36Sopenharmony_ci	OCELOT_STAT_DROP_YELLOW_PRIO_7,
13662306a36Sopenharmony_ci	OCELOT_STAT_DROP_GREEN_PRIO_0,
13762306a36Sopenharmony_ci	OCELOT_STAT_DROP_GREEN_PRIO_1,
13862306a36Sopenharmony_ci	OCELOT_STAT_DROP_GREEN_PRIO_2,
13962306a36Sopenharmony_ci	OCELOT_STAT_DROP_GREEN_PRIO_3,
14062306a36Sopenharmony_ci	OCELOT_STAT_DROP_GREEN_PRIO_4,
14162306a36Sopenharmony_ci	OCELOT_STAT_DROP_GREEN_PRIO_5,
14262306a36Sopenharmony_ci	OCELOT_STAT_DROP_GREEN_PRIO_6,
14362306a36Sopenharmony_ci	OCELOT_STAT_DROP_GREEN_PRIO_7,
14462306a36Sopenharmony_ci	OCELOT_NUM_STATS,
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistruct ocelot_stat_layout {
14862306a36Sopenharmony_ci	enum ocelot_reg reg;
14962306a36Sopenharmony_ci	char name[ETH_GSTRING_LEN];
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* 32-bit counter checked for wraparound by ocelot_port_update_stats()
15362306a36Sopenharmony_ci * and copied to ocelot->stats.
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_ci#define OCELOT_STAT(kind) \
15662306a36Sopenharmony_ci	[OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind }
15762306a36Sopenharmony_ci/* Same as above, except also exported to ethtool -S. Standard counters should
15862306a36Sopenharmony_ci * only be exposed to more specific interfaces rather than by their string name.
15962306a36Sopenharmony_ci */
16062306a36Sopenharmony_ci#define OCELOT_STAT_ETHTOOL(kind, ethtool_name) \
16162306a36Sopenharmony_ci	[OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind, .name = ethtool_name }
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci#define OCELOT_COMMON_STATS \
16462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_OCTETS, "rx_octets"), \
16562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_UNICAST, "rx_unicast"), \
16662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_MULTICAST, "rx_multicast"), \
16762306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_BROADCAST, "rx_broadcast"), \
16862306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_SHORTS, "rx_shorts"), \
16962306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_FRAGMENTS, "rx_fragments"), \
17062306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_JABBERS, "rx_jabbers"), \
17162306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_CRC_ALIGN_ERRS, "rx_crc_align_errs"), \
17262306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_SYM_ERRS, "rx_sym_errs"), \
17362306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_64, "rx_frames_below_65_octets"), \
17462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_65_127, "rx_frames_65_to_127_octets"), \
17562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_128_255, "rx_frames_128_to_255_octets"), \
17662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_256_511, "rx_frames_256_to_511_octets"), \
17762306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_512_1023, "rx_frames_512_to_1023_octets"), \
17862306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_1024_1526, "rx_frames_1024_to_1526_octets"), \
17962306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_1527_MAX, "rx_frames_over_1526_octets"), \
18062306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_PAUSE, "rx_pause"), \
18162306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_CONTROL, "rx_control"), \
18262306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_LONGS, "rx_longs"), \
18362306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_CLASSIFIED_DROPS, "rx_classified_drops"), \
18462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_0, "rx_red_prio_0"), \
18562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_1, "rx_red_prio_1"), \
18662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_2, "rx_red_prio_2"), \
18762306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_3, "rx_red_prio_3"), \
18862306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_4, "rx_red_prio_4"), \
18962306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_5, "rx_red_prio_5"), \
19062306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_6, "rx_red_prio_6"), \
19162306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_7, "rx_red_prio_7"), \
19262306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_0, "rx_yellow_prio_0"), \
19362306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_1, "rx_yellow_prio_1"), \
19462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_2, "rx_yellow_prio_2"), \
19562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_3, "rx_yellow_prio_3"), \
19662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_4, "rx_yellow_prio_4"), \
19762306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_5, "rx_yellow_prio_5"), \
19862306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_6, "rx_yellow_prio_6"), \
19962306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_7, "rx_yellow_prio_7"), \
20062306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_0, "rx_green_prio_0"), \
20162306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_1, "rx_green_prio_1"), \
20262306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_2, "rx_green_prio_2"), \
20362306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_3, "rx_green_prio_3"), \
20462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_4, "rx_green_prio_4"), \
20562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_5, "rx_green_prio_5"), \
20662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_6, "rx_green_prio_6"), \
20762306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_7, "rx_green_prio_7"), \
20862306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_OCTETS, "tx_octets"), \
20962306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_UNICAST, "tx_unicast"), \
21062306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_MULTICAST, "tx_multicast"), \
21162306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_BROADCAST, "tx_broadcast"), \
21262306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_COLLISION, "tx_collision"), \
21362306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_DROPS, "tx_drops"), \
21462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_PAUSE, "tx_pause"), \
21562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_64, "tx_frames_below_65_octets"), \
21662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_65_127, "tx_frames_65_to_127_octets"), \
21762306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_128_255, "tx_frames_128_255_octets"), \
21862306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_256_511, "tx_frames_256_511_octets"), \
21962306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_512_1023, "tx_frames_512_1023_octets"), \
22062306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_1024_1526, "tx_frames_1024_1526_octets"), \
22162306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_1527_MAX, "tx_frames_over_1526_octets"), \
22262306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_0, "tx_yellow_prio_0"), \
22362306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_1, "tx_yellow_prio_1"), \
22462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_2, "tx_yellow_prio_2"), \
22562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_3, "tx_yellow_prio_3"), \
22662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_4, "tx_yellow_prio_4"), \
22762306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_5, "tx_yellow_prio_5"), \
22862306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_6, "tx_yellow_prio_6"), \
22962306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_7, "tx_yellow_prio_7"), \
23062306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_0, "tx_green_prio_0"), \
23162306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_1, "tx_green_prio_1"), \
23262306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_2, "tx_green_prio_2"), \
23362306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_3, "tx_green_prio_3"), \
23462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_4, "tx_green_prio_4"), \
23562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_5, "tx_green_prio_5"), \
23662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_6, "tx_green_prio_6"), \
23762306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_7, "tx_green_prio_7"), \
23862306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(TX_AGED, "tx_aged"), \
23962306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_LOCAL, "drop_local"), \
24062306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_TAIL, "drop_tail"), \
24162306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_0, "drop_yellow_prio_0"), \
24262306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_1, "drop_yellow_prio_1"), \
24362306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_2, "drop_yellow_prio_2"), \
24462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_3, "drop_yellow_prio_3"), \
24562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_4, "drop_yellow_prio_4"), \
24662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_5, "drop_yellow_prio_5"), \
24762306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_6, "drop_yellow_prio_6"), \
24862306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_7, "drop_yellow_prio_7"), \
24962306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_0, "drop_green_prio_0"), \
25062306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_1, "drop_green_prio_1"), \
25162306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_2, "drop_green_prio_2"), \
25262306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_3, "drop_green_prio_3"), \
25362306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_4, "drop_green_prio_4"), \
25462306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_5, "drop_green_prio_5"), \
25562306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_6, "drop_green_prio_6"), \
25662306a36Sopenharmony_ci	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_7, "drop_green_prio_7")
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistruct ocelot_stats_region {
25962306a36Sopenharmony_ci	struct list_head node;
26062306a36Sopenharmony_ci	enum ocelot_reg base;
26162306a36Sopenharmony_ci	enum ocelot_stat first_stat;
26262306a36Sopenharmony_ci	int count;
26362306a36Sopenharmony_ci	u32 *buf;
26462306a36Sopenharmony_ci};
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic const struct ocelot_stat_layout ocelot_stats_layout[OCELOT_NUM_STATS] = {
26762306a36Sopenharmony_ci	OCELOT_COMMON_STATS,
26862306a36Sopenharmony_ci};
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic const struct ocelot_stat_layout ocelot_mm_stats_layout[OCELOT_NUM_STATS] = {
27162306a36Sopenharmony_ci	OCELOT_COMMON_STATS,
27262306a36Sopenharmony_ci	OCELOT_STAT(RX_ASSEMBLY_ERRS),
27362306a36Sopenharmony_ci	OCELOT_STAT(RX_SMD_ERRS),
27462306a36Sopenharmony_ci	OCELOT_STAT(RX_ASSEMBLY_OK),
27562306a36Sopenharmony_ci	OCELOT_STAT(RX_MERGE_FRAGMENTS),
27662306a36Sopenharmony_ci	OCELOT_STAT(TX_MERGE_FRAGMENTS),
27762306a36Sopenharmony_ci	OCELOT_STAT(TX_MM_HOLD),
27862306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_OCTETS),
27962306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_UNICAST),
28062306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_MULTICAST),
28162306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_BROADCAST),
28262306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_SHORTS),
28362306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_FRAGMENTS),
28462306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_JABBERS),
28562306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_CRC_ALIGN_ERRS),
28662306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_SYM_ERRS),
28762306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_64),
28862306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_65_127),
28962306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_128_255),
29062306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_256_511),
29162306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_512_1023),
29262306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_1024_1526),
29362306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_1527_MAX),
29462306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_PAUSE),
29562306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_CONTROL),
29662306a36Sopenharmony_ci	OCELOT_STAT(RX_PMAC_LONGS),
29762306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_OCTETS),
29862306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_UNICAST),
29962306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_MULTICAST),
30062306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_BROADCAST),
30162306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_PAUSE),
30262306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_64),
30362306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_65_127),
30462306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_128_255),
30562306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_256_511),
30662306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_512_1023),
30762306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_1024_1526),
30862306a36Sopenharmony_ci	OCELOT_STAT(TX_PMAC_1527_MAX),
30962306a36Sopenharmony_ci};
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic const struct ocelot_stat_layout *
31262306a36Sopenharmony_ciocelot_get_stats_layout(struct ocelot *ocelot)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	if (ocelot->mm_supported)
31562306a36Sopenharmony_ci		return ocelot_mm_stats_layout;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return ocelot_stats_layout;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/* Read the counters from hardware and keep them in region->buf.
32162306a36Sopenharmony_ci * Caller must hold &ocelot->stat_view_lock.
32262306a36Sopenharmony_ci */
32362306a36Sopenharmony_cistatic int ocelot_port_update_stats(struct ocelot *ocelot, int port)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct ocelot_stats_region *region;
32662306a36Sopenharmony_ci	int err;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* Configure the port to read the stats from */
32962306a36Sopenharmony_ci	ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), SYS_STAT_CFG);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	list_for_each_entry(region, &ocelot->stats_regions, node) {
33262306a36Sopenharmony_ci		err = ocelot_bulk_read(ocelot, region->base, region->buf,
33362306a36Sopenharmony_ci				       region->count);
33462306a36Sopenharmony_ci		if (err)
33562306a36Sopenharmony_ci			return err;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	return 0;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci/* Transfer the counters from region->buf to ocelot->stats.
34262306a36Sopenharmony_ci * Caller must hold &ocelot->stat_view_lock and &ocelot->stats_lock.
34362306a36Sopenharmony_ci */
34462306a36Sopenharmony_cistatic void ocelot_port_transfer_stats(struct ocelot *ocelot, int port)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct ocelot_stats_region *region;
34762306a36Sopenharmony_ci	int j;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	list_for_each_entry(region, &ocelot->stats_regions, node) {
35062306a36Sopenharmony_ci		unsigned int idx = port * OCELOT_NUM_STATS + region->first_stat;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci		for (j = 0; j < region->count; j++) {
35362306a36Sopenharmony_ci			u64 *stat = &ocelot->stats[idx + j];
35462306a36Sopenharmony_ci			u64 val = region->buf[j];
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci			if (val < (*stat & U32_MAX))
35762306a36Sopenharmony_ci				*stat += (u64)1 << 32;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci			*stat = (*stat & ~(u64)U32_MAX) + val;
36062306a36Sopenharmony_ci		}
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic void ocelot_check_stats_work(struct work_struct *work)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct delayed_work *del_work = to_delayed_work(work);
36762306a36Sopenharmony_ci	struct ocelot *ocelot = container_of(del_work, struct ocelot,
36862306a36Sopenharmony_ci					     stats_work);
36962306a36Sopenharmony_ci	int port, err;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	mutex_lock(&ocelot->stat_view_lock);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	for (port = 0; port < ocelot->num_phys_ports; port++) {
37462306a36Sopenharmony_ci		err = ocelot_port_update_stats(ocelot, port);
37562306a36Sopenharmony_ci		if (err)
37662306a36Sopenharmony_ci			break;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		spin_lock(&ocelot->stats_lock);
37962306a36Sopenharmony_ci		ocelot_port_transfer_stats(ocelot, port);
38062306a36Sopenharmony_ci		spin_unlock(&ocelot->stats_lock);
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (!err && ocelot->ops->update_stats)
38462306a36Sopenharmony_ci		ocelot->ops->update_stats(ocelot);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	mutex_unlock(&ocelot->stat_view_lock);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (err)
38962306a36Sopenharmony_ci		dev_err(ocelot->dev, "Error %d updating ethtool stats\n",  err);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
39262306a36Sopenharmony_ci			   OCELOT_STATS_CHECK_DELAY);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_civoid ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	const struct ocelot_stat_layout *layout;
39862306a36Sopenharmony_ci	enum ocelot_stat i;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (sset != ETH_SS_STATS)
40162306a36Sopenharmony_ci		return;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	layout = ocelot_get_stats_layout(ocelot);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	for (i = 0; i < OCELOT_NUM_STATS; i++) {
40662306a36Sopenharmony_ci		if (layout[i].name[0] == '\0')
40762306a36Sopenharmony_ci			continue;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		memcpy(data, layout[i].name, ETH_GSTRING_LEN);
41062306a36Sopenharmony_ci		data += ETH_GSTRING_LEN;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ciEXPORT_SYMBOL(ocelot_get_strings);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/* Update ocelot->stats for the given port and run the given callback */
41662306a36Sopenharmony_cistatic void ocelot_port_stats_run(struct ocelot *ocelot, int port, void *priv,
41762306a36Sopenharmony_ci				  void (*cb)(struct ocelot *ocelot, int port,
41862306a36Sopenharmony_ci					     void *priv))
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	int err;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	mutex_lock(&ocelot->stat_view_lock);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	err = ocelot_port_update_stats(ocelot, port);
42562306a36Sopenharmony_ci	if (err) {
42662306a36Sopenharmony_ci		dev_err(ocelot->dev, "Failed to update port %d stats: %pe\n",
42762306a36Sopenharmony_ci			port, ERR_PTR(err));
42862306a36Sopenharmony_ci		goto out_unlock;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	spin_lock(&ocelot->stats_lock);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	ocelot_port_transfer_stats(ocelot, port);
43462306a36Sopenharmony_ci	cb(ocelot, port, priv);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	spin_unlock(&ocelot->stats_lock);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ciout_unlock:
43962306a36Sopenharmony_ci	mutex_unlock(&ocelot->stat_view_lock);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ciint ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	const struct ocelot_stat_layout *layout;
44562306a36Sopenharmony_ci	enum ocelot_stat i;
44662306a36Sopenharmony_ci	int num_stats = 0;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (sset != ETH_SS_STATS)
44962306a36Sopenharmony_ci		return -EOPNOTSUPP;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	layout = ocelot_get_stats_layout(ocelot);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	for (i = 0; i < OCELOT_NUM_STATS; i++)
45462306a36Sopenharmony_ci		if (layout[i].name[0] != '\0')
45562306a36Sopenharmony_ci			num_stats++;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	return num_stats;
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ciEXPORT_SYMBOL(ocelot_get_sset_count);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic void ocelot_port_ethtool_stats_cb(struct ocelot *ocelot, int port,
46262306a36Sopenharmony_ci					 void *priv)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	const struct ocelot_stat_layout *layout;
46562306a36Sopenharmony_ci	enum ocelot_stat i;
46662306a36Sopenharmony_ci	u64 *data = priv;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	layout = ocelot_get_stats_layout(ocelot);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* Copy all supported counters */
47162306a36Sopenharmony_ci	for (i = 0; i < OCELOT_NUM_STATS; i++) {
47262306a36Sopenharmony_ci		int index = port * OCELOT_NUM_STATS + i;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci		if (layout[i].name[0] == '\0')
47562306a36Sopenharmony_ci			continue;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		*data++ = ocelot->stats[index];
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_civoid ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	ocelot_port_stats_run(ocelot, port, data, ocelot_port_ethtool_stats_cb);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ciEXPORT_SYMBOL(ocelot_get_ethtool_stats);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic void ocelot_port_pause_stats_cb(struct ocelot *ocelot, int port, void *priv)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
49062306a36Sopenharmony_ci	struct ethtool_pause_stats *pause_stats = priv;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PAUSE];
49362306a36Sopenharmony_ci	pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PAUSE];
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic void ocelot_port_pmac_pause_stats_cb(struct ocelot *ocelot, int port,
49762306a36Sopenharmony_ci					    void *priv)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
50062306a36Sopenharmony_ci	struct ethtool_pause_stats *pause_stats = priv;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PMAC_PAUSE];
50362306a36Sopenharmony_ci	pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PMAC_PAUSE];
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic void ocelot_port_mm_stats_cb(struct ocelot *ocelot, int port,
50762306a36Sopenharmony_ci				    void *priv)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
51062306a36Sopenharmony_ci	struct ethtool_mm_stats *stats = priv;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	stats->MACMergeFrameAssErrorCount = s[OCELOT_STAT_RX_ASSEMBLY_ERRS];
51362306a36Sopenharmony_ci	stats->MACMergeFrameSmdErrorCount = s[OCELOT_STAT_RX_SMD_ERRS];
51462306a36Sopenharmony_ci	stats->MACMergeFrameAssOkCount = s[OCELOT_STAT_RX_ASSEMBLY_OK];
51562306a36Sopenharmony_ci	stats->MACMergeFragCountRx = s[OCELOT_STAT_RX_MERGE_FRAGMENTS];
51662306a36Sopenharmony_ci	stats->MACMergeFragCountTx = s[OCELOT_STAT_TX_MERGE_FRAGMENTS];
51762306a36Sopenharmony_ci	stats->MACMergeHoldCount = s[OCELOT_STAT_TX_MM_HOLD];
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_civoid ocelot_port_get_pause_stats(struct ocelot *ocelot, int port,
52162306a36Sopenharmony_ci				 struct ethtool_pause_stats *pause_stats)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct net_device *dev;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	switch (pause_stats->src) {
52662306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_EMAC:
52762306a36Sopenharmony_ci		ocelot_port_stats_run(ocelot, port, pause_stats,
52862306a36Sopenharmony_ci				      ocelot_port_pause_stats_cb);
52962306a36Sopenharmony_ci		break;
53062306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_PMAC:
53162306a36Sopenharmony_ci		if (ocelot->mm_supported)
53262306a36Sopenharmony_ci			ocelot_port_stats_run(ocelot, port, pause_stats,
53362306a36Sopenharmony_ci					      ocelot_port_pmac_pause_stats_cb);
53462306a36Sopenharmony_ci		break;
53562306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
53662306a36Sopenharmony_ci		dev = ocelot->ops->port_to_netdev(ocelot, port);
53762306a36Sopenharmony_ci		ethtool_aggregate_pause_stats(dev, pause_stats);
53862306a36Sopenharmony_ci		break;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_get_pause_stats);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_civoid ocelot_port_get_mm_stats(struct ocelot *ocelot, int port,
54462306a36Sopenharmony_ci			      struct ethtool_mm_stats *stats)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	if (!ocelot->mm_supported)
54762306a36Sopenharmony_ci		return;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	ocelot_port_stats_run(ocelot, port, stats, ocelot_port_mm_stats_cb);
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_get_mm_stats);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic const struct ethtool_rmon_hist_range ocelot_rmon_ranges[] = {
55462306a36Sopenharmony_ci	{   64,    64 },
55562306a36Sopenharmony_ci	{   65,   127 },
55662306a36Sopenharmony_ci	{  128,   255 },
55762306a36Sopenharmony_ci	{  256,   511 },
55862306a36Sopenharmony_ci	{  512,  1023 },
55962306a36Sopenharmony_ci	{ 1024,  1526 },
56062306a36Sopenharmony_ci	{ 1527, 65535 },
56162306a36Sopenharmony_ci	{},
56262306a36Sopenharmony_ci};
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic void ocelot_port_rmon_stats_cb(struct ocelot *ocelot, int port, void *priv)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
56762306a36Sopenharmony_ci	struct ethtool_rmon_stats *rmon_stats = priv;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_SHORTS];
57062306a36Sopenharmony_ci	rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_LONGS];
57162306a36Sopenharmony_ci	rmon_stats->fragments = s[OCELOT_STAT_RX_FRAGMENTS];
57262306a36Sopenharmony_ci	rmon_stats->jabbers = s[OCELOT_STAT_RX_JABBERS];
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	rmon_stats->hist[0] = s[OCELOT_STAT_RX_64];
57562306a36Sopenharmony_ci	rmon_stats->hist[1] = s[OCELOT_STAT_RX_65_127];
57662306a36Sopenharmony_ci	rmon_stats->hist[2] = s[OCELOT_STAT_RX_128_255];
57762306a36Sopenharmony_ci	rmon_stats->hist[3] = s[OCELOT_STAT_RX_256_511];
57862306a36Sopenharmony_ci	rmon_stats->hist[4] = s[OCELOT_STAT_RX_512_1023];
57962306a36Sopenharmony_ci	rmon_stats->hist[5] = s[OCELOT_STAT_RX_1024_1526];
58062306a36Sopenharmony_ci	rmon_stats->hist[6] = s[OCELOT_STAT_RX_1527_MAX];
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_64];
58362306a36Sopenharmony_ci	rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_65_127];
58462306a36Sopenharmony_ci	rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_128_255];
58562306a36Sopenharmony_ci	rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_256_511];
58662306a36Sopenharmony_ci	rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_512_1023];
58762306a36Sopenharmony_ci	rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_1024_1526];
58862306a36Sopenharmony_ci	rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_1527_MAX];
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic void ocelot_port_pmac_rmon_stats_cb(struct ocelot *ocelot, int port,
59262306a36Sopenharmony_ci					   void *priv)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
59562306a36Sopenharmony_ci	struct ethtool_rmon_stats *rmon_stats = priv;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_PMAC_SHORTS];
59862306a36Sopenharmony_ci	rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_PMAC_LONGS];
59962306a36Sopenharmony_ci	rmon_stats->fragments = s[OCELOT_STAT_RX_PMAC_FRAGMENTS];
60062306a36Sopenharmony_ci	rmon_stats->jabbers = s[OCELOT_STAT_RX_PMAC_JABBERS];
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	rmon_stats->hist[0] = s[OCELOT_STAT_RX_PMAC_64];
60362306a36Sopenharmony_ci	rmon_stats->hist[1] = s[OCELOT_STAT_RX_PMAC_65_127];
60462306a36Sopenharmony_ci	rmon_stats->hist[2] = s[OCELOT_STAT_RX_PMAC_128_255];
60562306a36Sopenharmony_ci	rmon_stats->hist[3] = s[OCELOT_STAT_RX_PMAC_256_511];
60662306a36Sopenharmony_ci	rmon_stats->hist[4] = s[OCELOT_STAT_RX_PMAC_512_1023];
60762306a36Sopenharmony_ci	rmon_stats->hist[5] = s[OCELOT_STAT_RX_PMAC_1024_1526];
60862306a36Sopenharmony_ci	rmon_stats->hist[6] = s[OCELOT_STAT_RX_PMAC_1527_MAX];
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_PMAC_64];
61162306a36Sopenharmony_ci	rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_PMAC_65_127];
61262306a36Sopenharmony_ci	rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_PMAC_128_255];
61362306a36Sopenharmony_ci	rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_PMAC_256_511];
61462306a36Sopenharmony_ci	rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_PMAC_512_1023];
61562306a36Sopenharmony_ci	rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_PMAC_1024_1526];
61662306a36Sopenharmony_ci	rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_PMAC_1527_MAX];
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_civoid ocelot_port_get_rmon_stats(struct ocelot *ocelot, int port,
62062306a36Sopenharmony_ci				struct ethtool_rmon_stats *rmon_stats,
62162306a36Sopenharmony_ci				const struct ethtool_rmon_hist_range **ranges)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	struct net_device *dev;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	*ranges = ocelot_rmon_ranges;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	switch (rmon_stats->src) {
62862306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_EMAC:
62962306a36Sopenharmony_ci		ocelot_port_stats_run(ocelot, port, rmon_stats,
63062306a36Sopenharmony_ci				      ocelot_port_rmon_stats_cb);
63162306a36Sopenharmony_ci		break;
63262306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_PMAC:
63362306a36Sopenharmony_ci		if (ocelot->mm_supported)
63462306a36Sopenharmony_ci			ocelot_port_stats_run(ocelot, port, rmon_stats,
63562306a36Sopenharmony_ci					      ocelot_port_pmac_rmon_stats_cb);
63662306a36Sopenharmony_ci		break;
63762306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
63862306a36Sopenharmony_ci		dev = ocelot->ops->port_to_netdev(ocelot, port);
63962306a36Sopenharmony_ci		ethtool_aggregate_rmon_stats(dev, rmon_stats);
64062306a36Sopenharmony_ci		break;
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_get_rmon_stats);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic void ocelot_port_ctrl_stats_cb(struct ocelot *ocelot, int port, void *priv)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
64862306a36Sopenharmony_ci	struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_CONTROL];
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic void ocelot_port_pmac_ctrl_stats_cb(struct ocelot *ocelot, int port,
65462306a36Sopenharmony_ci					   void *priv)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
65762306a36Sopenharmony_ci	struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_PMAC_CONTROL];
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_civoid ocelot_port_get_eth_ctrl_stats(struct ocelot *ocelot, int port,
66362306a36Sopenharmony_ci				    struct ethtool_eth_ctrl_stats *ctrl_stats)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	struct net_device *dev;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	switch (ctrl_stats->src) {
66862306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_EMAC:
66962306a36Sopenharmony_ci		ocelot_port_stats_run(ocelot, port, ctrl_stats,
67062306a36Sopenharmony_ci				      ocelot_port_ctrl_stats_cb);
67162306a36Sopenharmony_ci		break;
67262306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_PMAC:
67362306a36Sopenharmony_ci		if (ocelot->mm_supported)
67462306a36Sopenharmony_ci			ocelot_port_stats_run(ocelot, port, ctrl_stats,
67562306a36Sopenharmony_ci					      ocelot_port_pmac_ctrl_stats_cb);
67662306a36Sopenharmony_ci		break;
67762306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
67862306a36Sopenharmony_ci		dev = ocelot->ops->port_to_netdev(ocelot, port);
67962306a36Sopenharmony_ci		ethtool_aggregate_ctrl_stats(dev, ctrl_stats);
68062306a36Sopenharmony_ci		break;
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_get_eth_ctrl_stats);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic void ocelot_port_mac_stats_cb(struct ocelot *ocelot, int port, void *priv)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
68862306a36Sopenharmony_ci	struct ethtool_eth_mac_stats *mac_stats = priv;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_OCTETS];
69162306a36Sopenharmony_ci	mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_64] +
69262306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_65_127] +
69362306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_128_255] +
69462306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_256_511] +
69562306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_512_1023] +
69662306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_1024_1526] +
69762306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_1527_MAX];
69862306a36Sopenharmony_ci	mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_OCTETS];
69962306a36Sopenharmony_ci	mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_GREEN_PRIO_0] +
70062306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_GREEN_PRIO_1] +
70162306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_GREEN_PRIO_2] +
70262306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_GREEN_PRIO_3] +
70362306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_GREEN_PRIO_4] +
70462306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_GREEN_PRIO_5] +
70562306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_GREEN_PRIO_6] +
70662306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_GREEN_PRIO_7] +
70762306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_YELLOW_PRIO_0] +
70862306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_YELLOW_PRIO_1] +
70962306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_YELLOW_PRIO_2] +
71062306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_YELLOW_PRIO_3] +
71162306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_YELLOW_PRIO_4] +
71262306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_YELLOW_PRIO_5] +
71362306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_YELLOW_PRIO_6] +
71462306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_YELLOW_PRIO_7];
71562306a36Sopenharmony_ci	mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_MULTICAST];
71662306a36Sopenharmony_ci	mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_BROADCAST];
71762306a36Sopenharmony_ci	mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_MULTICAST];
71862306a36Sopenharmony_ci	mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_BROADCAST];
71962306a36Sopenharmony_ci	mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_LONGS];
72062306a36Sopenharmony_ci	/* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
72162306a36Sopenharmony_ci	 * counted individually.
72262306a36Sopenharmony_ci	 */
72362306a36Sopenharmony_ci	mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
72462306a36Sopenharmony_ci	mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic void ocelot_port_pmac_mac_stats_cb(struct ocelot *ocelot, int port,
72862306a36Sopenharmony_ci					  void *priv)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
73162306a36Sopenharmony_ci	struct ethtool_eth_mac_stats *mac_stats = priv;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_PMAC_OCTETS];
73462306a36Sopenharmony_ci	mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_PMAC_64] +
73562306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_PMAC_65_127] +
73662306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_PMAC_128_255] +
73762306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_PMAC_256_511] +
73862306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_PMAC_512_1023] +
73962306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_PMAC_1024_1526] +
74062306a36Sopenharmony_ci					 s[OCELOT_STAT_TX_PMAC_1527_MAX];
74162306a36Sopenharmony_ci	mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_PMAC_OCTETS];
74262306a36Sopenharmony_ci	mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_PMAC_64] +
74362306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_PMAC_65_127] +
74462306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_PMAC_128_255] +
74562306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_PMAC_256_511] +
74662306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_PMAC_512_1023] +
74762306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_PMAC_1024_1526] +
74862306a36Sopenharmony_ci				      s[OCELOT_STAT_RX_PMAC_1527_MAX];
74962306a36Sopenharmony_ci	mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_PMAC_MULTICAST];
75062306a36Sopenharmony_ci	mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_PMAC_BROADCAST];
75162306a36Sopenharmony_ci	mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_PMAC_MULTICAST];
75262306a36Sopenharmony_ci	mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_PMAC_BROADCAST];
75362306a36Sopenharmony_ci	mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_PMAC_LONGS];
75462306a36Sopenharmony_ci	/* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
75562306a36Sopenharmony_ci	 * counted individually.
75662306a36Sopenharmony_ci	 */
75762306a36Sopenharmony_ci	mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS];
75862306a36Sopenharmony_ci	mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS];
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_civoid ocelot_port_get_eth_mac_stats(struct ocelot *ocelot, int port,
76262306a36Sopenharmony_ci				   struct ethtool_eth_mac_stats *mac_stats)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	struct net_device *dev;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	switch (mac_stats->src) {
76762306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_EMAC:
76862306a36Sopenharmony_ci		ocelot_port_stats_run(ocelot, port, mac_stats,
76962306a36Sopenharmony_ci				      ocelot_port_mac_stats_cb);
77062306a36Sopenharmony_ci		break;
77162306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_PMAC:
77262306a36Sopenharmony_ci		if (ocelot->mm_supported)
77362306a36Sopenharmony_ci			ocelot_port_stats_run(ocelot, port, mac_stats,
77462306a36Sopenharmony_ci					      ocelot_port_pmac_mac_stats_cb);
77562306a36Sopenharmony_ci		break;
77662306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
77762306a36Sopenharmony_ci		dev = ocelot->ops->port_to_netdev(ocelot, port);
77862306a36Sopenharmony_ci		ethtool_aggregate_mac_stats(dev, mac_stats);
77962306a36Sopenharmony_ci		break;
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_get_eth_mac_stats);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistatic void ocelot_port_phy_stats_cb(struct ocelot *ocelot, int port, void *priv)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
78762306a36Sopenharmony_ci	struct ethtool_eth_phy_stats *phy_stats = priv;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_SYM_ERRS];
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic void ocelot_port_pmac_phy_stats_cb(struct ocelot *ocelot, int port,
79362306a36Sopenharmony_ci					  void *priv)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
79662306a36Sopenharmony_ci	struct ethtool_eth_phy_stats *phy_stats = priv;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_PMAC_SYM_ERRS];
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_civoid ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
80262306a36Sopenharmony_ci				   struct ethtool_eth_phy_stats *phy_stats)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	struct net_device *dev;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	switch (phy_stats->src) {
80762306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_EMAC:
80862306a36Sopenharmony_ci		ocelot_port_stats_run(ocelot, port, phy_stats,
80962306a36Sopenharmony_ci				      ocelot_port_phy_stats_cb);
81062306a36Sopenharmony_ci		break;
81162306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_PMAC:
81262306a36Sopenharmony_ci		if (ocelot->mm_supported)
81362306a36Sopenharmony_ci			ocelot_port_stats_run(ocelot, port, phy_stats,
81462306a36Sopenharmony_ci					      ocelot_port_pmac_phy_stats_cb);
81562306a36Sopenharmony_ci		break;
81662306a36Sopenharmony_ci	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
81762306a36Sopenharmony_ci		dev = ocelot->ops->port_to_netdev(ocelot, port);
81862306a36Sopenharmony_ci		ethtool_aggregate_phy_stats(dev, phy_stats);
81962306a36Sopenharmony_ci		break;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_civoid ocelot_port_get_stats64(struct ocelot *ocelot, int port,
82562306a36Sopenharmony_ci			     struct rtnl_link_stats64 *stats)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	spin_lock(&ocelot->stats_lock);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* Get Rx stats */
83262306a36Sopenharmony_ci	stats->rx_bytes = s[OCELOT_STAT_RX_OCTETS];
83362306a36Sopenharmony_ci	stats->rx_packets = s[OCELOT_STAT_RX_SHORTS] +
83462306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_FRAGMENTS] +
83562306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_JABBERS] +
83662306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_LONGS] +
83762306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_64] +
83862306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_65_127] +
83962306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_128_255] +
84062306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_256_511] +
84162306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_512_1023] +
84262306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_1024_1526] +
84362306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_1527_MAX];
84462306a36Sopenharmony_ci	stats->multicast = s[OCELOT_STAT_RX_MULTICAST];
84562306a36Sopenharmony_ci	stats->rx_missed_errors = s[OCELOT_STAT_DROP_TAIL];
84662306a36Sopenharmony_ci	stats->rx_dropped = s[OCELOT_STAT_RX_RED_PRIO_0] +
84762306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_RED_PRIO_1] +
84862306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_RED_PRIO_2] +
84962306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_RED_PRIO_3] +
85062306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_RED_PRIO_4] +
85162306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_RED_PRIO_5] +
85262306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_RED_PRIO_6] +
85362306a36Sopenharmony_ci			    s[OCELOT_STAT_RX_RED_PRIO_7] +
85462306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_LOCAL] +
85562306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_YELLOW_PRIO_0] +
85662306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_YELLOW_PRIO_1] +
85762306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_YELLOW_PRIO_2] +
85862306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_YELLOW_PRIO_3] +
85962306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_YELLOW_PRIO_4] +
86062306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_YELLOW_PRIO_5] +
86162306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_YELLOW_PRIO_6] +
86262306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_YELLOW_PRIO_7] +
86362306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_GREEN_PRIO_0] +
86462306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_GREEN_PRIO_1] +
86562306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_GREEN_PRIO_2] +
86662306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_GREEN_PRIO_3] +
86762306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_GREEN_PRIO_4] +
86862306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_GREEN_PRIO_5] +
86962306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_GREEN_PRIO_6] +
87062306a36Sopenharmony_ci			    s[OCELOT_STAT_DROP_GREEN_PRIO_7];
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	/* Get Tx stats */
87362306a36Sopenharmony_ci	stats->tx_bytes = s[OCELOT_STAT_TX_OCTETS];
87462306a36Sopenharmony_ci	stats->tx_packets = s[OCELOT_STAT_TX_64] +
87562306a36Sopenharmony_ci			    s[OCELOT_STAT_TX_65_127] +
87662306a36Sopenharmony_ci			    s[OCELOT_STAT_TX_128_255] +
87762306a36Sopenharmony_ci			    s[OCELOT_STAT_TX_256_511] +
87862306a36Sopenharmony_ci			    s[OCELOT_STAT_TX_512_1023] +
87962306a36Sopenharmony_ci			    s[OCELOT_STAT_TX_1024_1526] +
88062306a36Sopenharmony_ci			    s[OCELOT_STAT_TX_1527_MAX];
88162306a36Sopenharmony_ci	stats->tx_dropped = s[OCELOT_STAT_TX_DROPS] +
88262306a36Sopenharmony_ci			    s[OCELOT_STAT_TX_AGED];
88362306a36Sopenharmony_ci	stats->collisions = s[OCELOT_STAT_TX_COLLISION];
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	spin_unlock(&ocelot->stats_lock);
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ciEXPORT_SYMBOL(ocelot_port_get_stats64);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic int ocelot_prepare_stats_regions(struct ocelot *ocelot)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	struct ocelot_stats_region *region = NULL;
89262306a36Sopenharmony_ci	const struct ocelot_stat_layout *layout;
89362306a36Sopenharmony_ci	enum ocelot_reg last = 0;
89462306a36Sopenharmony_ci	enum ocelot_stat i;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	INIT_LIST_HEAD(&ocelot->stats_regions);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	layout = ocelot_get_stats_layout(ocelot);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	for (i = 0; i < OCELOT_NUM_STATS; i++) {
90162306a36Sopenharmony_ci		if (!layout[i].reg)
90262306a36Sopenharmony_ci			continue;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci		/* enum ocelot_stat must be kept sorted in the same order
90562306a36Sopenharmony_ci		 * as the addresses behind layout[i].reg in order to have
90662306a36Sopenharmony_ci		 * efficient bulking
90762306a36Sopenharmony_ci		 */
90862306a36Sopenharmony_ci		if (last) {
90962306a36Sopenharmony_ci			WARN(ocelot->map[SYS][last & REG_MASK] >= ocelot->map[SYS][layout[i].reg & REG_MASK],
91062306a36Sopenharmony_ci			     "reg 0x%x had address 0x%x but reg 0x%x has address 0x%x, bulking broken!",
91162306a36Sopenharmony_ci			     last, ocelot->map[SYS][last & REG_MASK],
91262306a36Sopenharmony_ci			     layout[i].reg, ocelot->map[SYS][layout[i].reg & REG_MASK]);
91362306a36Sopenharmony_ci		}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci		if (region && ocelot->map[SYS][layout[i].reg & REG_MASK] ==
91662306a36Sopenharmony_ci		    ocelot->map[SYS][last & REG_MASK] + 4) {
91762306a36Sopenharmony_ci			region->count++;
91862306a36Sopenharmony_ci		} else {
91962306a36Sopenharmony_ci			region = devm_kzalloc(ocelot->dev, sizeof(*region),
92062306a36Sopenharmony_ci					      GFP_KERNEL);
92162306a36Sopenharmony_ci			if (!region)
92262306a36Sopenharmony_ci				return -ENOMEM;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci			region->base = layout[i].reg;
92562306a36Sopenharmony_ci			region->first_stat = i;
92662306a36Sopenharmony_ci			region->count = 1;
92762306a36Sopenharmony_ci			list_add_tail(&region->node, &ocelot->stats_regions);
92862306a36Sopenharmony_ci		}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci		last = layout[i].reg;
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	list_for_each_entry(region, &ocelot->stats_regions, node) {
93462306a36Sopenharmony_ci		enum ocelot_target target;
93562306a36Sopenharmony_ci		u32 addr;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci		ocelot_reg_to_target_addr(ocelot, region->base, &target,
93862306a36Sopenharmony_ci					  &addr);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		dev_dbg(ocelot->dev,
94162306a36Sopenharmony_ci			"region of %d contiguous counters starting with SYS:STAT:CNT[0x%03x]\n",
94262306a36Sopenharmony_ci			region->count, addr / 4);
94362306a36Sopenharmony_ci		region->buf = devm_kcalloc(ocelot->dev, region->count,
94462306a36Sopenharmony_ci					   sizeof(*region->buf), GFP_KERNEL);
94562306a36Sopenharmony_ci		if (!region->buf)
94662306a36Sopenharmony_ci			return -ENOMEM;
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	return 0;
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ciint ocelot_stats_init(struct ocelot *ocelot)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	char queue_name[32];
95562306a36Sopenharmony_ci	int ret;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	ocelot->stats = devm_kcalloc(ocelot->dev,
95862306a36Sopenharmony_ci				     ocelot->num_phys_ports * OCELOT_NUM_STATS,
95962306a36Sopenharmony_ci				     sizeof(u64), GFP_KERNEL);
96062306a36Sopenharmony_ci	if (!ocelot->stats)
96162306a36Sopenharmony_ci		return -ENOMEM;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	snprintf(queue_name, sizeof(queue_name), "%s-stats",
96462306a36Sopenharmony_ci		 dev_name(ocelot->dev));
96562306a36Sopenharmony_ci	ocelot->stats_queue = create_singlethread_workqueue(queue_name);
96662306a36Sopenharmony_ci	if (!ocelot->stats_queue)
96762306a36Sopenharmony_ci		return -ENOMEM;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	spin_lock_init(&ocelot->stats_lock);
97062306a36Sopenharmony_ci	mutex_init(&ocelot->stat_view_lock);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	ret = ocelot_prepare_stats_regions(ocelot);
97362306a36Sopenharmony_ci	if (ret) {
97462306a36Sopenharmony_ci		destroy_workqueue(ocelot->stats_queue);
97562306a36Sopenharmony_ci		return ret;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
97962306a36Sopenharmony_ci	queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
98062306a36Sopenharmony_ci			   OCELOT_STATS_CHECK_DELAY);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	return 0;
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_civoid ocelot_stats_deinit(struct ocelot *ocelot)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	cancel_delayed_work(&ocelot->stats_work);
98862306a36Sopenharmony_ci	destroy_workqueue(ocelot->stats_queue);
98962306a36Sopenharmony_ci}
990