brintos

brintos / linux-shallow public Read only

0
0
Text · 32.1 KiB · c018783 Raw
990 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/* Statistics for Ocelot switch family3 *4 * Copyright (c) 2017 Microsemi Corporation5 * Copyright 2022 NXP6 */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 should158 * 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 not721	 * 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 not755	 * 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_stats64(struct ocelot *ocelot, int port,825			     struct rtnl_link_stats64 *stats)826{827	u64 *s = &ocelot->stats[port * OCELOT_NUM_STATS];828 829	spin_lock(&ocelot->stats_lock);830 831	/* Get Rx stats */832	stats->rx_bytes = s[OCELOT_STAT_RX_OCTETS];833	stats->rx_packets = s[OCELOT_STAT_RX_SHORTS] +834			    s[OCELOT_STAT_RX_FRAGMENTS] +835			    s[OCELOT_STAT_RX_JABBERS] +836			    s[OCELOT_STAT_RX_LONGS] +837			    s[OCELOT_STAT_RX_64] +838			    s[OCELOT_STAT_RX_65_127] +839			    s[OCELOT_STAT_RX_128_255] +840			    s[OCELOT_STAT_RX_256_511] +841			    s[OCELOT_STAT_RX_512_1023] +842			    s[OCELOT_STAT_RX_1024_1526] +843			    s[OCELOT_STAT_RX_1527_MAX];844	stats->multicast = s[OCELOT_STAT_RX_MULTICAST];845	stats->rx_missed_errors = s[OCELOT_STAT_DROP_TAIL];846	stats->rx_dropped = s[OCELOT_STAT_RX_RED_PRIO_0] +847			    s[OCELOT_STAT_RX_RED_PRIO_1] +848			    s[OCELOT_STAT_RX_RED_PRIO_2] +849			    s[OCELOT_STAT_RX_RED_PRIO_3] +850			    s[OCELOT_STAT_RX_RED_PRIO_4] +851			    s[OCELOT_STAT_RX_RED_PRIO_5] +852			    s[OCELOT_STAT_RX_RED_PRIO_6] +853			    s[OCELOT_STAT_RX_RED_PRIO_7] +854			    s[OCELOT_STAT_DROP_LOCAL] +855			    s[OCELOT_STAT_DROP_YELLOW_PRIO_0] +856			    s[OCELOT_STAT_DROP_YELLOW_PRIO_1] +857			    s[OCELOT_STAT_DROP_YELLOW_PRIO_2] +858			    s[OCELOT_STAT_DROP_YELLOW_PRIO_3] +859			    s[OCELOT_STAT_DROP_YELLOW_PRIO_4] +860			    s[OCELOT_STAT_DROP_YELLOW_PRIO_5] +861			    s[OCELOT_STAT_DROP_YELLOW_PRIO_6] +862			    s[OCELOT_STAT_DROP_YELLOW_PRIO_7] +863			    s[OCELOT_STAT_DROP_GREEN_PRIO_0] +864			    s[OCELOT_STAT_DROP_GREEN_PRIO_1] +865			    s[OCELOT_STAT_DROP_GREEN_PRIO_2] +866			    s[OCELOT_STAT_DROP_GREEN_PRIO_3] +867			    s[OCELOT_STAT_DROP_GREEN_PRIO_4] +868			    s[OCELOT_STAT_DROP_GREEN_PRIO_5] +869			    s[OCELOT_STAT_DROP_GREEN_PRIO_6] +870			    s[OCELOT_STAT_DROP_GREEN_PRIO_7];871 872	/* Get Tx stats */873	stats->tx_bytes = s[OCELOT_STAT_TX_OCTETS];874	stats->tx_packets = s[OCELOT_STAT_TX_64] +875			    s[OCELOT_STAT_TX_65_127] +876			    s[OCELOT_STAT_TX_128_255] +877			    s[OCELOT_STAT_TX_256_511] +878			    s[OCELOT_STAT_TX_512_1023] +879			    s[OCELOT_STAT_TX_1024_1526] +880			    s[OCELOT_STAT_TX_1527_MAX];881	stats->tx_dropped = s[OCELOT_STAT_TX_DROPS] +882			    s[OCELOT_STAT_TX_AGED];883	stats->collisions = s[OCELOT_STAT_TX_COLLISION];884 885	spin_unlock(&ocelot->stats_lock);886}887EXPORT_SYMBOL(ocelot_port_get_stats64);888 889static int ocelot_prepare_stats_regions(struct ocelot *ocelot)890{891	struct ocelot_stats_region *region = NULL;892	const struct ocelot_stat_layout *layout;893	enum ocelot_reg last = 0;894	enum ocelot_stat i;895 896	INIT_LIST_HEAD(&ocelot->stats_regions);897 898	layout = ocelot_get_stats_layout(ocelot);899 900	for (i = 0; i < OCELOT_NUM_STATS; i++) {901		if (!layout[i].reg)902			continue;903 904		/* enum ocelot_stat must be kept sorted in the same order905		 * as the addresses behind layout[i].reg in order to have906		 * efficient bulking907		 */908		if (last) {909			WARN(ocelot->map[SYS][last & REG_MASK] >= ocelot->map[SYS][layout[i].reg & REG_MASK],910			     "reg 0x%x had address 0x%x but reg 0x%x has address 0x%x, bulking broken!",911			     last, ocelot->map[SYS][last & REG_MASK],912			     layout[i].reg, ocelot->map[SYS][layout[i].reg & REG_MASK]);913		}914 915		if (region && ocelot->map[SYS][layout[i].reg & REG_MASK] ==916		    ocelot->map[SYS][last & REG_MASK] + 4) {917			region->count++;918		} else {919			region = devm_kzalloc(ocelot->dev, sizeof(*region),920					      GFP_KERNEL);921			if (!region)922				return -ENOMEM;923 924			region->base = layout[i].reg;925			region->first_stat = i;926			region->count = 1;927			list_add_tail(&region->node, &ocelot->stats_regions);928		}929 930		last = layout[i].reg;931	}932 933	list_for_each_entry(region, &ocelot->stats_regions, node) {934		enum ocelot_target target;935		u32 addr;936 937		ocelot_reg_to_target_addr(ocelot, region->base, &target,938					  &addr);939 940		dev_dbg(ocelot->dev,941			"region of %d contiguous counters starting with SYS:STAT:CNT[0x%03x]\n",942			region->count, addr / 4);943		region->buf = devm_kcalloc(ocelot->dev, region->count,944					   sizeof(*region->buf), GFP_KERNEL);945		if (!region->buf)946			return -ENOMEM;947	}948 949	return 0;950}951 952int ocelot_stats_init(struct ocelot *ocelot)953{954	char queue_name[32];955	int ret;956 957	ocelot->stats = devm_kcalloc(ocelot->dev,958				     ocelot->num_phys_ports * OCELOT_NUM_STATS,959				     sizeof(u64), GFP_KERNEL);960	if (!ocelot->stats)961		return -ENOMEM;962 963	snprintf(queue_name, sizeof(queue_name), "%s-stats",964		 dev_name(ocelot->dev));965	ocelot->stats_queue = create_singlethread_workqueue(queue_name);966	if (!ocelot->stats_queue)967		return -ENOMEM;968 969	spin_lock_init(&ocelot->stats_lock);970	mutex_init(&ocelot->stat_view_lock);971 972	ret = ocelot_prepare_stats_regions(ocelot);973	if (ret) {974		destroy_workqueue(ocelot->stats_queue);975		return ret;976	}977 978	INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work);979	queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,980			   OCELOT_STATS_CHECK_DELAY);981 982	return 0;983}984 985void ocelot_stats_deinit(struct ocelot *ocelot)986{987	cancel_delayed_work(&ocelot->stats_work);988	destroy_workqueue(ocelot->stats_queue);989}990