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 13 enum 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 147 struct 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 258 struct 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 266 static const struct ocelot_stat_layout ocelot_stats_layout[OCELOT_NUM_STATS] = { 267 OCELOT_COMMON_STATS, 268 }; 269 270 static 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 311 static const struct ocelot_stat_layout * 312 ocelot_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 */ 323 static 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 */ 344 static 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 364 static 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 395 void 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 } 413 EXPORT_SYMBOL(ocelot_get_strings); 414 415 /* Update ocelot->stats for the given port and run the given callback */ 416 static 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 438 out_unlock: 439 mutex_unlock(&ocelot->stat_view_lock); 440 } 441 442 int 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 } 459 EXPORT_SYMBOL(ocelot_get_sset_count); 460 461 static 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 481 void 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 } 485 EXPORT_SYMBOL(ocelot_get_ethtool_stats); 486 487 static 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 496 static 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 506 static 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 520 void 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 } 541 EXPORT_SYMBOL_GPL(ocelot_port_get_pause_stats); 542 543 void 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 } 551 EXPORT_SYMBOL_GPL(ocelot_port_get_mm_stats); 552 553 static 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 564 static 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_128_255]; 586 rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_256_511]; 587 rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_512_1023]; 588 rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_1024_1526]; 589 } 590 591 static 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_128_255]; 614 rmon_stats->hist_tx[4] = s[OCELOT_STAT_TX_PMAC_256_511]; 615 rmon_stats->hist_tx[5] = s[OCELOT_STAT_TX_PMAC_512_1023]; 616 rmon_stats->hist_tx[6] = s[OCELOT_STAT_TX_PMAC_1024_1526]; 617 } 618 619 void 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 } 643 EXPORT_SYMBOL_GPL(ocelot_port_get_rmon_stats); 644 645 static 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 653 static 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 662 void 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 } 683 EXPORT_SYMBOL_GPL(ocelot_port_get_eth_ctrl_stats); 684 685 static 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 727 static 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 761 void 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 } 782 EXPORT_SYMBOL_GPL(ocelot_port_get_eth_mac_stats); 783 784 static 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 792 static 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 801 void 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 } 822 EXPORT_SYMBOL_GPL(ocelot_port_get_eth_phy_stats); 823 824 void 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 } 887 EXPORT_SYMBOL(ocelot_port_get_stats64); 888 889 static 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 order 905 * as the addresses behind layout[i].reg in order to have 906 * efficient bulking 907 */ 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 952 int 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 985 void ocelot_stats_deinit(struct ocelot *ocelot) 986 { 987 cancel_delayed_work(&ocelot->stats_work); 988 destroy_workqueue(ocelot->stats_queue); 989 } 990