File Index
Files and directories
Sign in
FILE

ocelot_stats.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mscc/ocelot_stats.c C
   1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2/* Statistics for Ocelot switch family
   3 *
   4 * Copyright (c) 2017 Microsemi Corporation
   5 * Copyright 2022 NXP
   6 */
   7#include <linux/ethtool_netlink.h>
   8#include <linux/spinlock.h>
   9#include <linux/mutex.h>
  10#include <linux/workqueue.h>
  11#include "ocelot.h"
  12
  13enum ocelot_stat {
  14	OCELOT_STAT_RX_OCTETS,
  15	OCELOT_STAT_RX_UNICAST,
  16	OCELOT_STAT_RX_MULTICAST,
  17	OCELOT_STAT_RX_BROADCAST,
  18	OCELOT_STAT_RX_SHORTS,
  19	OCELOT_STAT_RX_FRAGMENTS,
  20	OCELOT_STAT_RX_JABBERS,
  21	OCELOT_STAT_RX_CRC_ALIGN_ERRS,
  22	OCELOT_STAT_RX_SYM_ERRS,
  23	OCELOT_STAT_RX_64,
  24	OCELOT_STAT_RX_65_127,
  25	OCELOT_STAT_RX_128_255,
  26	OCELOT_STAT_RX_256_511,
  27	OCELOT_STAT_RX_512_1023,
  28	OCELOT_STAT_RX_1024_1526,
  29	OCELOT_STAT_RX_1527_MAX,
  30	OCELOT_STAT_RX_PAUSE,
  31	OCELOT_STAT_RX_CONTROL,
  32	OCELOT_STAT_RX_LONGS,
  33	OCELOT_STAT_RX_CLASSIFIED_DROPS,
  34	OCELOT_STAT_RX_RED_PRIO_0,
  35	OCELOT_STAT_RX_RED_PRIO_1,
  36	OCELOT_STAT_RX_RED_PRIO_2,
  37	OCELOT_STAT_RX_RED_PRIO_3,
  38	OCELOT_STAT_RX_RED_PRIO_4,
  39	OCELOT_STAT_RX_RED_PRIO_5,
  40	OCELOT_STAT_RX_RED_PRIO_6,
  41	OCELOT_STAT_RX_RED_PRIO_7,
  42	OCELOT_STAT_RX_YELLOW_PRIO_0,
  43	OCELOT_STAT_RX_YELLOW_PRIO_1,
  44	OCELOT_STAT_RX_YELLOW_PRIO_2,
  45	OCELOT_STAT_RX_YELLOW_PRIO_3,
  46	OCELOT_STAT_RX_YELLOW_PRIO_4,
  47	OCELOT_STAT_RX_YELLOW_PRIO_5,
  48	OCELOT_STAT_RX_YELLOW_PRIO_6,
  49	OCELOT_STAT_RX_YELLOW_PRIO_7,
  50	OCELOT_STAT_RX_GREEN_PRIO_0,
  51	OCELOT_STAT_RX_GREEN_PRIO_1,
  52	OCELOT_STAT_RX_GREEN_PRIO_2,
  53	OCELOT_STAT_RX_GREEN_PRIO_3,
  54	OCELOT_STAT_RX_GREEN_PRIO_4,
  55	OCELOT_STAT_RX_GREEN_PRIO_5,
  56	OCELOT_STAT_RX_GREEN_PRIO_6,
  57	OCELOT_STAT_RX_GREEN_PRIO_7,
  58	OCELOT_STAT_RX_ASSEMBLY_ERRS,
  59	OCELOT_STAT_RX_SMD_ERRS,
  60	OCELOT_STAT_RX_ASSEMBLY_OK,
  61	OCELOT_STAT_RX_MERGE_FRAGMENTS,
  62	OCELOT_STAT_RX_PMAC_OCTETS,
  63	OCELOT_STAT_RX_PMAC_UNICAST,
  64	OCELOT_STAT_RX_PMAC_MULTICAST,
  65	OCELOT_STAT_RX_PMAC_BROADCAST,
  66	OCELOT_STAT_RX_PMAC_SHORTS,
  67	OCELOT_STAT_RX_PMAC_FRAGMENTS,
  68	OCELOT_STAT_RX_PMAC_JABBERS,
  69	OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS,
  70	OCELOT_STAT_RX_PMAC_SYM_ERRS,
  71	OCELOT_STAT_RX_PMAC_64,
  72	OCELOT_STAT_RX_PMAC_65_127,
  73	OCELOT_STAT_RX_PMAC_128_255,
  74	OCELOT_STAT_RX_PMAC_256_511,
  75	OCELOT_STAT_RX_PMAC_512_1023,
  76	OCELOT_STAT_RX_PMAC_1024_1526,
  77	OCELOT_STAT_RX_PMAC_1527_MAX,
  78	OCELOT_STAT_RX_PMAC_PAUSE,
  79	OCELOT_STAT_RX_PMAC_CONTROL,
  80	OCELOT_STAT_RX_PMAC_LONGS,
  81	OCELOT_STAT_TX_OCTETS,
  82	OCELOT_STAT_TX_UNICAST,
  83	OCELOT_STAT_TX_MULTICAST,
  84	OCELOT_STAT_TX_BROADCAST,
  85	OCELOT_STAT_TX_COLLISION,
  86	OCELOT_STAT_TX_DROPS,
  87	OCELOT_STAT_TX_PAUSE,
  88	OCELOT_STAT_TX_64,
  89	OCELOT_STAT_TX_65_127,
  90	OCELOT_STAT_TX_128_255,
  91	OCELOT_STAT_TX_256_511,
  92	OCELOT_STAT_TX_512_1023,
  93	OCELOT_STAT_TX_1024_1526,
  94	OCELOT_STAT_TX_1527_MAX,
  95	OCELOT_STAT_TX_YELLOW_PRIO_0,
  96	OCELOT_STAT_TX_YELLOW_PRIO_1,
  97	OCELOT_STAT_TX_YELLOW_PRIO_2,
  98	OCELOT_STAT_TX_YELLOW_PRIO_3,
  99	OCELOT_STAT_TX_YELLOW_PRIO_4,
 100	OCELOT_STAT_TX_YELLOW_PRIO_5,
 101	OCELOT_STAT_TX_YELLOW_PRIO_6,
 102	OCELOT_STAT_TX_YELLOW_PRIO_7,
 103	OCELOT_STAT_TX_GREEN_PRIO_0,
 104	OCELOT_STAT_TX_GREEN_PRIO_1,
 105	OCELOT_STAT_TX_GREEN_PRIO_2,
 106	OCELOT_STAT_TX_GREEN_PRIO_3,
 107	OCELOT_STAT_TX_GREEN_PRIO_4,
 108	OCELOT_STAT_TX_GREEN_PRIO_5,
 109	OCELOT_STAT_TX_GREEN_PRIO_6,
 110	OCELOT_STAT_TX_GREEN_PRIO_7,
 111	OCELOT_STAT_TX_AGED,
 112	OCELOT_STAT_TX_MM_HOLD,
 113	OCELOT_STAT_TX_MERGE_FRAGMENTS,
 114	OCELOT_STAT_TX_PMAC_OCTETS,
 115	OCELOT_STAT_TX_PMAC_UNICAST,
 116	OCELOT_STAT_TX_PMAC_MULTICAST,
 117	OCELOT_STAT_TX_PMAC_BROADCAST,
 118	OCELOT_STAT_TX_PMAC_PAUSE,
 119	OCELOT_STAT_TX_PMAC_64,
 120	OCELOT_STAT_TX_PMAC_65_127,
 121	OCELOT_STAT_TX_PMAC_128_255,
 122	OCELOT_STAT_TX_PMAC_256_511,
 123	OCELOT_STAT_TX_PMAC_512_1023,
 124	OCELOT_STAT_TX_PMAC_1024_1526,
 125	OCELOT_STAT_TX_PMAC_1527_MAX,
 126	OCELOT_STAT_DROP_LOCAL,
 127	OCELOT_STAT_DROP_TAIL,
 128	OCELOT_STAT_DROP_YELLOW_PRIO_0,
 129	OCELOT_STAT_DROP_YELLOW_PRIO_1,
 130	OCELOT_STAT_DROP_YELLOW_PRIO_2,
 131	OCELOT_STAT_DROP_YELLOW_PRIO_3,
 132	OCELOT_STAT_DROP_YELLOW_PRIO_4,
 133	OCELOT_STAT_DROP_YELLOW_PRIO_5,
 134	OCELOT_STAT_DROP_YELLOW_PRIO_6,
 135	OCELOT_STAT_DROP_YELLOW_PRIO_7,
 136	OCELOT_STAT_DROP_GREEN_PRIO_0,
 137	OCELOT_STAT_DROP_GREEN_PRIO_1,
 138	OCELOT_STAT_DROP_GREEN_PRIO_2,
 139	OCELOT_STAT_DROP_GREEN_PRIO_3,
 140	OCELOT_STAT_DROP_GREEN_PRIO_4,
 141	OCELOT_STAT_DROP_GREEN_PRIO_5,
 142	OCELOT_STAT_DROP_GREEN_PRIO_6,
 143	OCELOT_STAT_DROP_GREEN_PRIO_7,
 144	OCELOT_NUM_STATS,
 145};
 146
 147struct ocelot_stat_layout {
 148	enum ocelot_reg reg;
 149	char name[ETH_GSTRING_LEN];
 150};
 151
 152/* 32-bit counter checked for wraparound by ocelot_port_update_stats()
 153 * and copied to ocelot->stats.
 154 */
 155#define OCELOT_STAT(kind) \
 156	[OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind }
 157/* Same as above, except also exported to ethtool -S. Standard counters should
 158 * only be exposed to more specific interfaces rather than by their string name.
 159 */
 160#define OCELOT_STAT_ETHTOOL(kind, ethtool_name) \
 161	[OCELOT_STAT_ ## kind] = { .reg = SYS_COUNT_ ## kind, .name = ethtool_name }
 162
 163#define OCELOT_COMMON_STATS \
 164	OCELOT_STAT_ETHTOOL(RX_OCTETS, "rx_octets"), \
 165	OCELOT_STAT_ETHTOOL(RX_UNICAST, "rx_unicast"), \
 166	OCELOT_STAT_ETHTOOL(RX_MULTICAST, "rx_multicast"), \
 167	OCELOT_STAT_ETHTOOL(RX_BROADCAST, "rx_broadcast"), \
 168	OCELOT_STAT_ETHTOOL(RX_SHORTS, "rx_shorts"), \
 169	OCELOT_STAT_ETHTOOL(RX_FRAGMENTS, "rx_fragments"), \
 170	OCELOT_STAT_ETHTOOL(RX_JABBERS, "rx_jabbers"), \
 171	OCELOT_STAT_ETHTOOL(RX_CRC_ALIGN_ERRS, "rx_crc_align_errs"), \
 172	OCELOT_STAT_ETHTOOL(RX_SYM_ERRS, "rx_sym_errs"), \
 173	OCELOT_STAT_ETHTOOL(RX_64, "rx_frames_below_65_octets"), \
 174	OCELOT_STAT_ETHTOOL(RX_65_127, "rx_frames_65_to_127_octets"), \
 175	OCELOT_STAT_ETHTOOL(RX_128_255, "rx_frames_128_to_255_octets"), \
 176	OCELOT_STAT_ETHTOOL(RX_256_511, "rx_frames_256_to_511_octets"), \
 177	OCELOT_STAT_ETHTOOL(RX_512_1023, "rx_frames_512_to_1023_octets"), \
 178	OCELOT_STAT_ETHTOOL(RX_1024_1526, "rx_frames_1024_to_1526_octets"), \
 179	OCELOT_STAT_ETHTOOL(RX_1527_MAX, "rx_frames_over_1526_octets"), \
 180	OCELOT_STAT_ETHTOOL(RX_PAUSE, "rx_pause"), \
 181	OCELOT_STAT_ETHTOOL(RX_CONTROL, "rx_control"), \
 182	OCELOT_STAT_ETHTOOL(RX_LONGS, "rx_longs"), \
 183	OCELOT_STAT_ETHTOOL(RX_CLASSIFIED_DROPS, "rx_classified_drops"), \
 184	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_0, "rx_red_prio_0"), \
 185	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_1, "rx_red_prio_1"), \
 186	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_2, "rx_red_prio_2"), \
 187	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_3, "rx_red_prio_3"), \
 188	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_4, "rx_red_prio_4"), \
 189	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_5, "rx_red_prio_5"), \
 190	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_6, "rx_red_prio_6"), \
 191	OCELOT_STAT_ETHTOOL(RX_RED_PRIO_7, "rx_red_prio_7"), \
 192	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_0, "rx_yellow_prio_0"), \
 193	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_1, "rx_yellow_prio_1"), \
 194	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_2, "rx_yellow_prio_2"), \
 195	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_3, "rx_yellow_prio_3"), \
 196	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_4, "rx_yellow_prio_4"), \
 197	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_5, "rx_yellow_prio_5"), \
 198	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_6, "rx_yellow_prio_6"), \
 199	OCELOT_STAT_ETHTOOL(RX_YELLOW_PRIO_7, "rx_yellow_prio_7"), \
 200	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_0, "rx_green_prio_0"), \
 201	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_1, "rx_green_prio_1"), \
 202	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_2, "rx_green_prio_2"), \
 203	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_3, "rx_green_prio_3"), \
 204	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_4, "rx_green_prio_4"), \
 205	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_5, "rx_green_prio_5"), \
 206	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_6, "rx_green_prio_6"), \
 207	OCELOT_STAT_ETHTOOL(RX_GREEN_PRIO_7, "rx_green_prio_7"), \
 208	OCELOT_STAT_ETHTOOL(TX_OCTETS, "tx_octets"), \
 209	OCELOT_STAT_ETHTOOL(TX_UNICAST, "tx_unicast"), \
 210	OCELOT_STAT_ETHTOOL(TX_MULTICAST, "tx_multicast"), \
 211	OCELOT_STAT_ETHTOOL(TX_BROADCAST, "tx_broadcast"), \
 212	OCELOT_STAT_ETHTOOL(TX_COLLISION, "tx_collision"), \
 213	OCELOT_STAT_ETHTOOL(TX_DROPS, "tx_drops"), \
 214	OCELOT_STAT_ETHTOOL(TX_PAUSE, "tx_pause"), \
 215	OCELOT_STAT_ETHTOOL(TX_64, "tx_frames_below_65_octets"), \
 216	OCELOT_STAT_ETHTOOL(TX_65_127, "tx_frames_65_to_127_octets"), \
 217	OCELOT_STAT_ETHTOOL(TX_128_255, "tx_frames_128_255_octets"), \
 218	OCELOT_STAT_ETHTOOL(TX_256_511, "tx_frames_256_511_octets"), \
 219	OCELOT_STAT_ETHTOOL(TX_512_1023, "tx_frames_512_1023_octets"), \
 220	OCELOT_STAT_ETHTOOL(TX_1024_1526, "tx_frames_1024_1526_octets"), \
 221	OCELOT_STAT_ETHTOOL(TX_1527_MAX, "tx_frames_over_1526_octets"), \
 222	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_0, "tx_yellow_prio_0"), \
 223	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_1, "tx_yellow_prio_1"), \
 224	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_2, "tx_yellow_prio_2"), \
 225	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_3, "tx_yellow_prio_3"), \
 226	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_4, "tx_yellow_prio_4"), \
 227	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_5, "tx_yellow_prio_5"), \
 228	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_6, "tx_yellow_prio_6"), \
 229	OCELOT_STAT_ETHTOOL(TX_YELLOW_PRIO_7, "tx_yellow_prio_7"), \
 230	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_0, "tx_green_prio_0"), \
 231	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_1, "tx_green_prio_1"), \
 232	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_2, "tx_green_prio_2"), \
 233	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_3, "tx_green_prio_3"), \
 234	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_4, "tx_green_prio_4"), \
 235	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_5, "tx_green_prio_5"), \
 236	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_6, "tx_green_prio_6"), \
 237	OCELOT_STAT_ETHTOOL(TX_GREEN_PRIO_7, "tx_green_prio_7"), \
 238	OCELOT_STAT_ETHTOOL(TX_AGED, "tx_aged"), \
 239	OCELOT_STAT_ETHTOOL(DROP_LOCAL, "drop_local"), \
 240	OCELOT_STAT_ETHTOOL(DROP_TAIL, "drop_tail"), \
 241	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_0, "drop_yellow_prio_0"), \
 242	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_1, "drop_yellow_prio_1"), \
 243	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_2, "drop_yellow_prio_2"), \
 244	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_3, "drop_yellow_prio_3"), \
 245	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_4, "drop_yellow_prio_4"), \
 246	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_5, "drop_yellow_prio_5"), \
 247	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_6, "drop_yellow_prio_6"), \
 248	OCELOT_STAT_ETHTOOL(DROP_YELLOW_PRIO_7, "drop_yellow_prio_7"), \
 249	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_0, "drop_green_prio_0"), \
 250	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_1, "drop_green_prio_1"), \
 251	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_2, "drop_green_prio_2"), \
 252	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_3, "drop_green_prio_3"), \
 253	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_4, "drop_green_prio_4"), \
 254	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_5, "drop_green_prio_5"), \
 255	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_6, "drop_green_prio_6"), \
 256	OCELOT_STAT_ETHTOOL(DROP_GREEN_PRIO_7, "drop_green_prio_7")
 257
 258struct ocelot_stats_region {
 259	struct list_head node;
 260	enum ocelot_reg base;
 261	enum ocelot_stat first_stat;
 262	int count;
 263	u32 *buf;
 264};
 265
 266static const struct ocelot_stat_layout ocelot_stats_layout[OCELOT_NUM_STATS] = {
 267	OCELOT_COMMON_STATS,
 268};
 269
 270static const struct ocelot_stat_layout ocelot_mm_stats_layout[OCELOT_NUM_STATS] = {
 271	OCELOT_COMMON_STATS,
 272	OCELOT_STAT(RX_ASSEMBLY_ERRS),
 273	OCELOT_STAT(RX_SMD_ERRS),
 274	OCELOT_STAT(RX_ASSEMBLY_OK),
 275	OCELOT_STAT(RX_MERGE_FRAGMENTS),
 276	OCELOT_STAT(TX_MERGE_FRAGMENTS),
 277	OCELOT_STAT(TX_MM_HOLD),
 278	OCELOT_STAT(RX_PMAC_OCTETS),
 279	OCELOT_STAT(RX_PMAC_UNICAST),
 280	OCELOT_STAT(RX_PMAC_MULTICAST),
 281	OCELOT_STAT(RX_PMAC_BROADCAST),
 282	OCELOT_STAT(RX_PMAC_SHORTS),
 283	OCELOT_STAT(RX_PMAC_FRAGMENTS),
 284	OCELOT_STAT(RX_PMAC_JABBERS),
 285	OCELOT_STAT(RX_PMAC_CRC_ALIGN_ERRS),
 286	OCELOT_STAT(RX_PMAC_SYM_ERRS),
 287	OCELOT_STAT(RX_PMAC_64),
 288	OCELOT_STAT(RX_PMAC_65_127),
 289	OCELOT_STAT(RX_PMAC_128_255),
 290	OCELOT_STAT(RX_PMAC_256_511),
 291	OCELOT_STAT(RX_PMAC_512_1023),
 292	OCELOT_STAT(RX_PMAC_1024_1526),
 293	OCELOT_STAT(RX_PMAC_1527_MAX),
 294	OCELOT_STAT(RX_PMAC_PAUSE),
 295	OCELOT_STAT(RX_PMAC_CONTROL),
 296	OCELOT_STAT(RX_PMAC_LONGS),
 297	OCELOT_STAT(TX_PMAC_OCTETS),
 298	OCELOT_STAT(TX_PMAC_UNICAST),
 299	OCELOT_STAT(TX_PMAC_MULTICAST),
 300	OCELOT_STAT(TX_PMAC_BROADCAST),
 301	OCELOT_STAT(TX_PMAC_PAUSE),
 302	OCELOT_STAT(TX_PMAC_64),
 303	OCELOT_STAT(TX_PMAC_65_127),
 304	OCELOT_STAT(TX_PMAC_128_255),
 305	OCELOT_STAT(TX_PMAC_256_511),
 306	OCELOT_STAT(TX_PMAC_512_1023),
 307	OCELOT_STAT(TX_PMAC_1024_1526),
 308	OCELOT_STAT(TX_PMAC_1527_MAX),
 309};
 310
 311static const struct ocelot_stat_layout *
 312ocelot_get_stats_layout(struct ocelot *ocelot)
 313{
 314	if (ocelot->mm_supported)
 315		return ocelot_mm_stats_layout;
 316
 317	return ocelot_stats_layout;
 318}
 319
 320/* Read the counters from hardware and keep them in region->buf.
 321 * Caller must hold &ocelot->stat_view_lock.
 322 */
 323static int ocelot_port_update_stats(struct ocelot *ocelot, int port)
 324{
 325	struct ocelot_stats_region *region;
 326	int err;
 327
 328	/* Configure the port to read the stats from */
 329	ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), SYS_STAT_CFG);
 330
 331	list_for_each_entry(region, &ocelot->stats_regions, node) {
 332		err = ocelot_bulk_read(ocelot, region->base, region->buf,
 333				       region->count);
 334		if (err)
 335			return err;
 336	}
 337
 338	return 0;
 339}
 340
 341/* Transfer the counters from region->buf to ocelot->stats.
 342 * Caller must hold &ocelot->stat_view_lock and &ocelot->stats_lock.
 343 */
 344static void ocelot_port_transfer_stats(struct ocelot *ocelot, int port)
 345{
 346	struct ocelot_stats_region *region;
 347	int j;
 348
 349	list_for_each_entry(region, &ocelot->stats_regions, node) {
 350		unsigned int idx = port * OCELOT_NUM_STATS + region->first_stat;
 351
 352		for (j = 0; j < region->count; j++) {
 353			u64 *stat = &ocelot->stats[idx + j];
 354			u64 val = region->buf[j];
 355
 356			if (val < (*stat & U32_MAX))
 357				*stat += (u64)1 << 32;
 358
 359			*stat = (*stat & ~(u64)U32_MAX) + val;
 360		}
 361	}
 362}
 363
 364static void ocelot_check_stats_work(struct work_struct *work)
 365{
 366	struct delayed_work *del_work = to_delayed_work(work);
 367	struct ocelot *ocelot = container_of(del_work, struct ocelot,
 368					     stats_work);
 369	int port, err;
 370
 371	mutex_lock(&ocelot->stat_view_lock);
 372
 373	for (port = 0; port < ocelot->num_phys_ports; port++) {
 374		err = ocelot_port_update_stats(ocelot, port);
 375		if (err)
 376			break;
 377
 378		spin_lock(&ocelot->stats_lock);
 379		ocelot_port_transfer_stats(ocelot, port);
 380		spin_unlock(&ocelot->stats_lock);
 381	}
 382
 383	if (!err && ocelot->ops->update_stats)
 384		ocelot->ops->update_stats(ocelot);
 385
 386	mutex_unlock(&ocelot->stat_view_lock);
 387
 388	if (err)
 389		dev_err(ocelot->dev, "Error %d updating ethtool stats\n",  err);
 390
 391	queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
 392			   OCELOT_STATS_CHECK_DELAY);
 393}
 394
 395void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
 396{
 397	const struct ocelot_stat_layout *layout;
 398	enum ocelot_stat i;
 399
 400	if (sset != ETH_SS_STATS)
 401		return;
 402
 403	layout = ocelot_get_stats_layout(ocelot);
 404
 405	for (i = 0; i < OCELOT_NUM_STATS; i++) {
 406		if (layout[i].name[0] == '\0')
 407			continue;
 408
 409		memcpy(data, layout[i].name, ETH_GSTRING_LEN);
 410		data += ETH_GSTRING_LEN;
 411	}
 412}
 413EXPORT_SYMBOL(ocelot_get_strings);
 414
 415/* Update ocelot->stats for the given port and run the given callback */
 416static void ocelot_port_stats_run(struct ocelot *ocelot, int port, void *priv,
 417				  void (*cb)(struct ocelot *ocelot, int port,
 418					     void *priv))
 419{
 420	int err;
 421
 422	mutex_lock(&ocelot->stat_view_lock);
 423
 424	err = ocelot_port_update_stats(ocelot, port);
 425	if (err) {
 426		dev_err(ocelot->dev, "Failed to update port %d stats: %pe\n",
 427			port, ERR_PTR(err));
 428		goto out_unlock;
 429	}
 430
 431	spin_lock(&ocelot->stats_lock);
 432
 433	ocelot_port_transfer_stats(ocelot, port);
 434	cb(ocelot, port, priv);
 435
 436	spin_unlock(&ocelot->stats_lock);
 437
 438out_unlock:
 439	mutex_unlock(&ocelot->stat_view_lock);
 440}
 441
 442int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset)
 443{
 444	const struct ocelot_stat_layout *layout;
 445	enum ocelot_stat i;
 446	int num_stats = 0;
 447
 448	if (sset != ETH_SS_STATS)
 449		return -EOPNOTSUPP;
 450
 451	layout = ocelot_get_stats_layout(ocelot);
 452
 453	for (i = 0; i < OCELOT_NUM_STATS; i++)
 454		if (layout[i].name[0] != '\0')
 455			num_stats++;
 456
 457	return num_stats;
 458}
 459EXPORT_SYMBOL(ocelot_get_sset_count);
 460
 461static void ocelot_port_ethtool_stats_cb(struct ocelot *ocelot, int port,
 462					 void *priv)
 463{
 464	const struct ocelot_stat_layout *layout;
 465	enum ocelot_stat i;
 466	u64 *data = priv;
 467
 468	layout = ocelot_get_stats_layout(ocelot);
 469
 470	/* Copy all supported counters */
 471	for (i = 0; i < OCELOT_NUM_STATS; i++) {
 472		int index = port * OCELOT_NUM_STATS + i;
 473
 474		if (layout[i].name[0] == '\0')
 475			continue;
 476
 477		*data++ = ocelot->stats[index];
 478	}
 479}
 480
 481void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
 482{
 483	ocelot_port_stats_run(ocelot, port, data, ocelot_port_ethtool_stats_cb);
 484}
 485EXPORT_SYMBOL(ocelot_get_ethtool_stats);
 486
 487static void ocelot_port_pause_stats_cb(struct ocelot *ocelot, int port, void *priv)
 488{
 489	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 490	struct ethtool_pause_stats *pause_stats = priv;
 491
 492	pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PAUSE];
 493	pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PAUSE];
 494}
 495
 496static void ocelot_port_pmac_pause_stats_cb(struct ocelot *ocelot, int port,
 497					    void *priv)
 498{
 499	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 500	struct ethtool_pause_stats *pause_stats = priv;
 501
 502	pause_stats->tx_pause_frames = s[OCELOT_STAT_TX_PMAC_PAUSE];
 503	pause_stats->rx_pause_frames = s[OCELOT_STAT_RX_PMAC_PAUSE];
 504}
 505
 506static void ocelot_port_mm_stats_cb(struct ocelot *ocelot, int port,
 507				    void *priv)
 508{
 509	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 510	struct ethtool_mm_stats *stats = priv;
 511
 512	stats->MACMergeFrameAssErrorCount = s[OCELOT_STAT_RX_ASSEMBLY_ERRS];
 513	stats->MACMergeFrameSmdErrorCount = s[OCELOT_STAT_RX_SMD_ERRS];
 514	stats->MACMergeFrameAssOkCount = s[OCELOT_STAT_RX_ASSEMBLY_OK];
 515	stats->MACMergeFragCountRx = s[OCELOT_STAT_RX_MERGE_FRAGMENTS];
 516	stats->MACMergeFragCountTx = s[OCELOT_STAT_TX_MERGE_FRAGMENTS];
 517	stats->MACMergeHoldCount = s[OCELOT_STAT_TX_MM_HOLD];
 518}
 519
 520void ocelot_port_get_pause_stats(struct ocelot *ocelot, int port,
 521				 struct ethtool_pause_stats *pause_stats)
 522{
 523	struct net_device *dev;
 524
 525	switch (pause_stats->src) {
 526	case ETHTOOL_MAC_STATS_SRC_EMAC:
 527		ocelot_port_stats_run(ocelot, port, pause_stats,
 528				      ocelot_port_pause_stats_cb);
 529		break;
 530	case ETHTOOL_MAC_STATS_SRC_PMAC:
 531		if (ocelot->mm_supported)
 532			ocelot_port_stats_run(ocelot, port, pause_stats,
 533					      ocelot_port_pmac_pause_stats_cb);
 534		break;
 535	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
 536		dev = ocelot->ops->port_to_netdev(ocelot, port);
 537		ethtool_aggregate_pause_stats(dev, pause_stats);
 538		break;
 539	}
 540}
 541EXPORT_SYMBOL_GPL(ocelot_port_get_pause_stats);
 542
 543void ocelot_port_get_mm_stats(struct ocelot *ocelot, int port,
 544			      struct ethtool_mm_stats *stats)
 545{
 546	if (!ocelot->mm_supported)
 547		return;
 548
 549	ocelot_port_stats_run(ocelot, port, stats, ocelot_port_mm_stats_cb);
 550}
 551EXPORT_SYMBOL_GPL(ocelot_port_get_mm_stats);
 552
 553static const struct ethtool_rmon_hist_range ocelot_rmon_ranges[] = {
 554	{   64,    64 },
 555	{   65,   127 },
 556	{  128,   255 },
 557	{  256,   511 },
 558	{  512,  1023 },
 559	{ 1024,  1526 },
 560	{ 1527, 65535 },
 561	{},
 562};
 563
 564static void ocelot_port_rmon_stats_cb(struct ocelot *ocelot, int port, void *priv)
 565{
 566	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 567	struct ethtool_rmon_stats *rmon_stats = priv;
 568
 569	rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_SHORTS];
 570	rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_LONGS];
 571	rmon_stats->fragments = s[OCELOT_STAT_RX_FRAGMENTS];
 572	rmon_stats->jabbers = s[OCELOT_STAT_RX_JABBERS];
 573
 574	rmon_stats->hist[0] = s[OCELOT_STAT_RX_64];
 575	rmon_stats->hist[1] = s[OCELOT_STAT_RX_65_127];
 576	rmon_stats->hist[2] = s[OCELOT_STAT_RX_128_255];
 577	rmon_stats->hist[3] = s[OCELOT_STAT_RX_256_511];
 578	rmon_stats->hist[4] = s[OCELOT_STAT_RX_512_1023];
 579	rmon_stats->hist[5] = s[OCELOT_STAT_RX_1024_1526];
 580	rmon_stats->hist[6] = s[OCELOT_STAT_RX_1527_MAX];
 581
 582	rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_64];
 583	rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_65_127];
 584	rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_128_255];
 585	rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_256_511];
 586	rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_512_1023];
 587	rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_1024_1526];
 588	rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_1527_MAX];
 589}
 590
 591static void ocelot_port_pmac_rmon_stats_cb(struct ocelot *ocelot, int port,
 592					   void *priv)
 593{
 594	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 595	struct ethtool_rmon_stats *rmon_stats = priv;
 596
 597	rmon_stats->undersize_pkts = s[OCELOT_STAT_RX_PMAC_SHORTS];
 598	rmon_stats->oversize_pkts = s[OCELOT_STAT_RX_PMAC_LONGS];
 599	rmon_stats->fragments = s[OCELOT_STAT_RX_PMAC_FRAGMENTS];
 600	rmon_stats->jabbers = s[OCELOT_STAT_RX_PMAC_JABBERS];
 601
 602	rmon_stats->hist[0] = s[OCELOT_STAT_RX_PMAC_64];
 603	rmon_stats->hist[1] = s[OCELOT_STAT_RX_PMAC_65_127];
 604	rmon_stats->hist[2] = s[OCELOT_STAT_RX_PMAC_128_255];
 605	rmon_stats->hist[3] = s[OCELOT_STAT_RX_PMAC_256_511];
 606	rmon_stats->hist[4] = s[OCELOT_STAT_RX_PMAC_512_1023];
 607	rmon_stats->hist[5] = s[OCELOT_STAT_RX_PMAC_1024_1526];
 608	rmon_stats->hist[6] = s[OCELOT_STAT_RX_PMAC_1527_MAX];
 609
 610	rmon_stats->hist_tx[0] = s[OCELOT_STAT_TX_PMAC_64];
 611	rmon_stats->hist_tx[1] = s[OCELOT_STAT_TX_PMAC_65_127];
 612	rmon_stats->hist_tx[2] = s[OCELOT_STAT_TX_PMAC_128_255];
 613	rmon_stats->hist_tx[3] = s[OCELOT_STAT_TX_PMAC_256_511];
 614	rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_PMAC_512_1023];
 615	rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_PMAC_1024_1526];
 616	rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_PMAC_1527_MAX];
 617}
 618
 619void ocelot_port_get_rmon_stats(struct ocelot *ocelot, int port,
 620				struct ethtool_rmon_stats *rmon_stats,
 621				const struct ethtool_rmon_hist_range **ranges)
 622{
 623	struct net_device *dev;
 624
 625	*ranges = ocelot_rmon_ranges;
 626
 627	switch (rmon_stats->src) {
 628	case ETHTOOL_MAC_STATS_SRC_EMAC:
 629		ocelot_port_stats_run(ocelot, port, rmon_stats,
 630				      ocelot_port_rmon_stats_cb);
 631		break;
 632	case ETHTOOL_MAC_STATS_SRC_PMAC:
 633		if (ocelot->mm_supported)
 634			ocelot_port_stats_run(ocelot, port, rmon_stats,
 635					      ocelot_port_pmac_rmon_stats_cb);
 636		break;
 637	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
 638		dev = ocelot->ops->port_to_netdev(ocelot, port);
 639		ethtool_aggregate_rmon_stats(dev, rmon_stats);
 640		break;
 641	}
 642}
 643EXPORT_SYMBOL_GPL(ocelot_port_get_rmon_stats);
 644
 645static void ocelot_port_ctrl_stats_cb(struct ocelot *ocelot, int port, void *priv)
 646{
 647	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 648	struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
 649
 650	ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_CONTROL];
 651}
 652
 653static void ocelot_port_pmac_ctrl_stats_cb(struct ocelot *ocelot, int port,
 654					   void *priv)
 655{
 656	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 657	struct ethtool_eth_ctrl_stats *ctrl_stats = priv;
 658
 659	ctrl_stats->MACControlFramesReceived = s[OCELOT_STAT_RX_PMAC_CONTROL];
 660}
 661
 662void ocelot_port_get_eth_ctrl_stats(struct ocelot *ocelot, int port,
 663				    struct ethtool_eth_ctrl_stats *ctrl_stats)
 664{
 665	struct net_device *dev;
 666
 667	switch (ctrl_stats->src) {
 668	case ETHTOOL_MAC_STATS_SRC_EMAC:
 669		ocelot_port_stats_run(ocelot, port, ctrl_stats,
 670				      ocelot_port_ctrl_stats_cb);
 671		break;
 672	case ETHTOOL_MAC_STATS_SRC_PMAC:
 673		if (ocelot->mm_supported)
 674			ocelot_port_stats_run(ocelot, port, ctrl_stats,
 675					      ocelot_port_pmac_ctrl_stats_cb);
 676		break;
 677	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
 678		dev = ocelot->ops->port_to_netdev(ocelot, port);
 679		ethtool_aggregate_ctrl_stats(dev, ctrl_stats);
 680		break;
 681	}
 682}
 683EXPORT_SYMBOL_GPL(ocelot_port_get_eth_ctrl_stats);
 684
 685static void ocelot_port_mac_stats_cb(struct ocelot *ocelot, int port, void *priv)
 686{
 687	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 688	struct ethtool_eth_mac_stats *mac_stats = priv;
 689
 690	mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_OCTETS];
 691	mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_64] +
 692					 s[OCELOT_STAT_TX_65_127] +
 693					 s[OCELOT_STAT_TX_128_255] +
 694					 s[OCELOT_STAT_TX_256_511] +
 695					 s[OCELOT_STAT_TX_512_1023] +
 696					 s[OCELOT_STAT_TX_1024_1526] +
 697					 s[OCELOT_STAT_TX_1527_MAX];
 698	mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_OCTETS];
 699	mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_GREEN_PRIO_0] +
 700				      s[OCELOT_STAT_RX_GREEN_PRIO_1] +
 701				      s[OCELOT_STAT_RX_GREEN_PRIO_2] +
 702				      s[OCELOT_STAT_RX_GREEN_PRIO_3] +
 703				      s[OCELOT_STAT_RX_GREEN_PRIO_4] +
 704				      s[OCELOT_STAT_RX_GREEN_PRIO_5] +
 705				      s[OCELOT_STAT_RX_GREEN_PRIO_6] +
 706				      s[OCELOT_STAT_RX_GREEN_PRIO_7] +
 707				      s[OCELOT_STAT_RX_YELLOW_PRIO_0] +
 708				      s[OCELOT_STAT_RX_YELLOW_PRIO_1] +
 709				      s[OCELOT_STAT_RX_YELLOW_PRIO_2] +
 710				      s[OCELOT_STAT_RX_YELLOW_PRIO_3] +
 711				      s[OCELOT_STAT_RX_YELLOW_PRIO_4] +
 712				      s[OCELOT_STAT_RX_YELLOW_PRIO_5] +
 713				      s[OCELOT_STAT_RX_YELLOW_PRIO_6] +
 714				      s[OCELOT_STAT_RX_YELLOW_PRIO_7];
 715	mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_MULTICAST];
 716	mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_BROADCAST];
 717	mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_MULTICAST];
 718	mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_BROADCAST];
 719	mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_LONGS];
 720	/* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
 721	 * counted individually.
 722	 */
 723	mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
 724	mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_CRC_ALIGN_ERRS];
 725}
 726
 727static void ocelot_port_pmac_mac_stats_cb(struct ocelot *ocelot, int port,
 728					  void *priv)
 729{
 730	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 731	struct ethtool_eth_mac_stats *mac_stats = priv;
 732
 733	mac_stats->OctetsTransmittedOK = s[OCELOT_STAT_TX_PMAC_OCTETS];
 734	mac_stats->FramesTransmittedOK = s[OCELOT_STAT_TX_PMAC_64] +
 735					 s[OCELOT_STAT_TX_PMAC_65_127] +
 736					 s[OCELOT_STAT_TX_PMAC_128_255] +
 737					 s[OCELOT_STAT_TX_PMAC_256_511] +
 738					 s[OCELOT_STAT_TX_PMAC_512_1023] +
 739					 s[OCELOT_STAT_TX_PMAC_1024_1526] +
 740					 s[OCELOT_STAT_TX_PMAC_1527_MAX];
 741	mac_stats->OctetsReceivedOK = s[OCELOT_STAT_RX_PMAC_OCTETS];
 742	mac_stats->FramesReceivedOK = s[OCELOT_STAT_RX_PMAC_64] +
 743				      s[OCELOT_STAT_RX_PMAC_65_127] +
 744				      s[OCELOT_STAT_RX_PMAC_128_255] +
 745				      s[OCELOT_STAT_RX_PMAC_256_511] +
 746				      s[OCELOT_STAT_RX_PMAC_512_1023] +
 747				      s[OCELOT_STAT_RX_PMAC_1024_1526] +
 748				      s[OCELOT_STAT_RX_PMAC_1527_MAX];
 749	mac_stats->MulticastFramesXmittedOK = s[OCELOT_STAT_TX_PMAC_MULTICAST];
 750	mac_stats->BroadcastFramesXmittedOK = s[OCELOT_STAT_TX_PMAC_BROADCAST];
 751	mac_stats->MulticastFramesReceivedOK = s[OCELOT_STAT_RX_PMAC_MULTICAST];
 752	mac_stats->BroadcastFramesReceivedOK = s[OCELOT_STAT_RX_PMAC_BROADCAST];
 753	mac_stats->FrameTooLongErrors = s[OCELOT_STAT_RX_PMAC_LONGS];
 754	/* Sadly, C_RX_CRC is the sum of FCS and alignment errors, they are not
 755	 * counted individually.
 756	 */
 757	mac_stats->FrameCheckSequenceErrors = s[OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS];
 758	mac_stats->AlignmentErrors = s[OCELOT_STAT_RX_PMAC_CRC_ALIGN_ERRS];
 759}
 760
 761void ocelot_port_get_eth_mac_stats(struct ocelot *ocelot, int port,
 762				   struct ethtool_eth_mac_stats *mac_stats)
 763{
 764	struct net_device *dev;
 765
 766	switch (mac_stats->src) {
 767	case ETHTOOL_MAC_STATS_SRC_EMAC:
 768		ocelot_port_stats_run(ocelot, port, mac_stats,
 769				      ocelot_port_mac_stats_cb);
 770		break;
 771	case ETHTOOL_MAC_STATS_SRC_PMAC:
 772		if (ocelot->mm_supported)
 773			ocelot_port_stats_run(ocelot, port, mac_stats,
 774					      ocelot_port_pmac_mac_stats_cb);
 775		break;
 776	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
 777		dev = ocelot->ops->port_to_netdev(ocelot, port);
 778		ethtool_aggregate_mac_stats(dev, mac_stats);
 779		break;
 780	}
 781}
 782EXPORT_SYMBOL_GPL(ocelot_port_get_eth_mac_stats);
 783
 784static void ocelot_port_phy_stats_cb(struct ocelot *ocelot, int port, void *priv)
 785{
 786	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 787	struct ethtool_eth_phy_stats *phy_stats = priv;
 788
 789	phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_SYM_ERRS];
 790}
 791
 792static void ocelot_port_pmac_phy_stats_cb(struct ocelot *ocelot, int port,
 793					  void *priv)
 794{
 795	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 796	struct ethtool_eth_phy_stats *phy_stats = priv;
 797
 798	phy_stats->SymbolErrorDuringCarrier = s[OCELOT_STAT_RX_PMAC_SYM_ERRS];
 799}
 800
 801void ocelot_port_get_eth_phy_stats(struct ocelot *ocelot, int port,
 802				   struct ethtool_eth_phy_stats *phy_stats)
 803{
 804	struct net_device *dev;
 805
 806	switch (phy_stats->src) {
 807	case ETHTOOL_MAC_STATS_SRC_EMAC:
 808		ocelot_port_stats_run(ocelot, port, phy_stats,
 809				      ocelot_port_phy_stats_cb);
 810		break;
 811	case ETHTOOL_MAC_STATS_SRC_PMAC:
 812		if (ocelot->mm_supported)
 813			ocelot_port_stats_run(ocelot, port, phy_stats,
 814					      ocelot_port_pmac_phy_stats_cb);
 815		break;
 816	case ETHTOOL_MAC_STATS_SRC_AGGREGATE:
 817		dev = ocelot->ops->port_to_netdev(ocelot, port);
 818		ethtool_aggregate_phy_stats(dev, phy_stats);
 819		break;
 820	}
 821}
 822EXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats);
 823
 824void ocelot_port_get_ts_stats(struct ocelot *ocelot, int port,
 825			      struct ethtool_ts_stats *ts_stats)
 826{
 827	struct ocelot_port *ocelot_port = ocelot->ports[port];
 828	struct ocelot_ts_stats *stats = ocelot_port->ts_stats;
 829	unsigned int start;
 830
 831	if (!ocelot->ptp)
 832		return;
 833
 834	do {
 835		start = u64_stats_fetch_begin(&stats->syncp);
 836		ts_stats->pkts = stats->pkts;
 837		ts_stats->onestep_pkts_unconfirmed = stats->onestep_pkts_unconfirmed;
 838		ts_stats->lost = stats->lost;
 839		ts_stats->err = stats->err;
 840	} while (u64_stats_fetch_retry(&stats->syncp, start));
 841}
 842EXPORT_SYMBOL_GPL(ocelot_port_get_ts_stats);
 843
 844void ocelot_port_get_stats64(struct ocelot *ocelot, int port,
 845			     struct rtnl_link_stats64 *stats)
 846{
 847	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];
 848
 849	spin_lock(&ocelot->stats_lock);
 850
 851	/* Get Rx stats */
 852	stats->rx_bytes = s[OCELOT_STAT_RX_OCTETS];
 853	stats->rx_packets = s[OCELOT_STAT_RX_SHORTS] +
 854			    s[OCELOT_STAT_RX_FRAGMENTS] +
 855			    s[OCELOT_STAT_RX_JABBERS] +
 856			    s[OCELOT_STAT_RX_LONGS] +
 857			    s[OCELOT_STAT_RX_64] +
 858			    s[OCELOT_STAT_RX_65_127] +
 859			    s[OCELOT_STAT_RX_128_255] +
 860			    s[OCELOT_STAT_RX_256_511] +
 861			    s[OCELOT_STAT_RX_512_1023] +
 862			    s[OCELOT_STAT_RX_1024_1526] +
 863			    s[OCELOT_STAT_RX_1527_MAX];
 864	stats->multicast = s[OCELOT_STAT_RX_MULTICAST];
 865	stats->rx_missed_errors = s[OCELOT_STAT_DROP_TAIL];
 866	stats->rx_dropped = s[OCELOT_STAT_RX_RED_PRIO_0] +
 867			    s[OCELOT_STAT_RX_RED_PRIO_1] +
 868			    s[OCELOT_STAT_RX_RED_PRIO_2] +
 869			    s[OCELOT_STAT_RX_RED_PRIO_3] +
 870			    s[OCELOT_STAT_RX_RED_PRIO_4] +
 871			    s[OCELOT_STAT_RX_RED_PRIO_5] +
 872			    s[OCELOT_STAT_RX_RED_PRIO_6] +
 873			    s[OCELOT_STAT_RX_RED_PRIO_7] +
 874			    s[OCELOT_STAT_DROP_LOCAL] +
 875			    s[OCELOT_STAT_DROP_YELLOW_PRIO_0] +
 876			    s[OCELOT_STAT_DROP_YELLOW_PRIO_1] +
 877			    s[OCELOT_STAT_DROP_YELLOW_PRIO_2] +
 878			    s[OCELOT_STAT_DROP_YELLOW_PRIO_3] +
 879			    s[OCELOT_STAT_DROP_YELLOW_PRIO_4] +
 880			    s[OCELOT_STAT_DROP_YELLOW_PRIO_5] +
 881			    s[OCELOT_STAT_DROP_YELLOW_PRIO_6] +
 882			    s[OCELOT_STAT_DROP_YELLOW_PRIO_7] +
 883			    s[OCELOT_STAT_DROP_GREEN_PRIO_0] +
 884			    s[OCELOT_STAT_DROP_GREEN_PRIO_1] +
 885			    s[OCELOT_STAT_DROP_GREEN_PRIO_2] +
 886			    s[OCELOT_STAT_DROP_GREEN_PRIO_3] +
 887			    s[OCELOT_STAT_DROP_GREEN_PRIO_4] +
 888			    s[OCELOT_STAT_DROP_GREEN_PRIO_5] +
 889			    s[OCELOT_STAT_DROP_GREEN_PRIO_6] +
 890			    s[OCELOT_STAT_DROP_GREEN_PRIO_7];
 891
 892	/* Get Tx stats */
 893	stats->tx_bytes = s[OCELOT_STAT_TX_OCTETS];
 894	stats->tx_packets = s[OCELOT_STAT_TX_64] +
 895			    s[OCELOT_STAT_TX_65_127] +
 896			    s[OCELOT_STAT_TX_128_255] +
 897			    s[OCELOT_STAT_TX_256_511] +
 898			    s[OCELOT_STAT_TX_512_1023] +
 899			    s[OCELOT_STAT_TX_1024_1526] +
 900			    s[OCELOT_STAT_TX_1527_MAX];
 901	stats->tx_dropped = s[OCELOT_STAT_TX_DROPS] +
 902			    s[OCELOT_STAT_TX_AGED];
 903	stats->collisions = s[OCELOT_STAT_TX_COLLISION];
 904
 905	spin_unlock(&ocelot->stats_lock);
 906}
 907EXPORT_SYMBOL(ocelot_port_get_stats64);
 908
 909static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
 910{
 911	struct ocelot_stats_region *region = NULL;
 912	const struct ocelot_stat_layout *layout;
 913	enum ocelot_reg last = 0;
 914	enum ocelot_stat i;
 915
 916	INIT_LIST_HEAD(&ocelot->stats_regions);
 917
 918	layout = ocelot_get_stats_layout(ocelot);
 919
 920	for (i = 0; i < OCELOT_NUM_STATS; i++) {
 921		if (!layout[i].reg)
 922			continue;
 923
 924		/* enum ocelot_stat must be kept sorted in the same order
 925		 * as the addresses behind layout[i].reg in order to have
 926		 * efficient bulking
 927		 */
 928		if (last) {
 929			WARN(ocelot->map[SYS][last & REG_MASK] >= ocelot->map[SYS][layout[i].reg & REG_MASK],
 930			     "reg 0x%x had address 0x%x but reg 0x%x has address 0x%x, bulking broken!",
 931			     last, ocelot->map[SYS][last & REG_MASK],
 932			     layout[i].reg, ocelot->map[SYS][layout[i].reg & REG_MASK]);
 933		}
 934
 935		if (region && ocelot->map[SYS][layout[i].reg & REG_MASK] ==
 936		    ocelot->map[SYS][last & REG_MASK] + 4) {
 937			region->count++;
 938		} else {
 939			region = devm_kzalloc(ocelot->dev, sizeof(*region),
 940					      GFP_KERNEL);
 941			if (!region)
 942				return -ENOMEM;
 943
 944			region->base = layout[i].reg;
 945			region->first_stat = i;
 946			region->count = 1;
 947			list_add_tail(&region->node, &ocelot->stats_regions);
 948		}
 949
 950		last = layout[i].reg;
 951	}
 952
 953	list_for_each_entry(region, &ocelot->stats_regions, node) {
 954		enum ocelot_target target;
 955		u32 addr;
 956
 957		ocelot_reg_to_target_addr(ocelot, region->base, &target,
 958					  &addr);
 959
 960		dev_dbg(ocelot->dev,
 961			"region of %d contiguous counters starting with SYS:STAT:CNT[0x%03x]\n",
 962			region->count, addr / 4);
 963		region->buf = devm_kcalloc(ocelot->dev, region->count,
 964					   sizeof(*region->buf), GFP_KERNEL);
 965		if (!region->buf)
 966			return -ENOMEM;
 967	}
 968
 969	return 0;
 970}
 971
 972int ocelot_stats_init(struct ocelot *ocelot)
 973{
 974	char queue_name[32];
 975	int ret;
 976
 977	ocelot->stats = devm_kcalloc(ocelot->dev,
 978				     ocelot->num_phys_ports * OCELOT_NUM_STATS,
 979				     sizeof(u64), GFP_KERNEL);
 980	if (!ocelot->stats)
 981		return -ENOMEM;
 982
 983	if (ocelot->ptp) {
 984		for (int port = 0; port < ocelot->num_phys_ports; port++) {
 985			struct ocelot_port *ocelot_port = ocelot->ports[port];
 986
 987			if (!ocelot_port)
 988				continue;
 989
 990			ocelot_port->ts_stats = devm_kzalloc(ocelot->dev,
 991							     sizeof(*ocelot_port->ts_stats),
 992							     GFP_KERNEL);
 993			if (!ocelot_port->ts_stats)
 994				return -ENOMEM;
 995
 996			u64_stats_init(&ocelot_port->ts_stats->syncp);
 997		}
 998	}
 999
1000	snprintf(queue_name, sizeof(queue_name), "%s-stats",
1001		 dev_name(ocelot->dev));
1002	ocelot->stats_queue = create_singlethread_workqueue(queue_name);
1003	if (!ocelot->stats_queue)
1004		return -ENOMEM;
1005
1006	spin_lock_init(&ocelot->stats_lock);
1007	mutex_init(&ocelot->stat_view_lock);
1008
1009	ret = ocelot_prepare_stats_regions(ocelot);
1010	if (ret) {
1011		destroy_workqueue(ocelot->stats_queue);
1012		return ret;
1013	}
1014
1015	INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);
1016	queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
1017			   OCELOT_STATS_CHECK_DELAY);
1018
1019	return 0;
1020}
1021
1022void ocelot_stats_deinit(struct ocelot *ocelot)
1023{
1024	disable_delayed_work_sync(&ocelot->stats_work);
1025	destroy_workqueue(ocelot->stats_queue);
1026}
~/ Read-only file preview.