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(®ion->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