1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include <linux/netdevice.h> 4 5 #include "lan966x_main.h" 6 7 /* Number of traffic classes */ 8 #define LAN966X_NUM_TC 8 9 #define LAN966X_STATS_CHECK_DELAY (2 * HZ) 10 11 static const struct lan966x_stat_layout lan966x_stats_layout[] = { 12 { .name = "rx_octets", .offset = 0x00, }, 13 { .name = "rx_unicast", .offset = 0x01, }, 14 { .name = "rx_multicast", .offset = 0x02 }, 15 { .name = "rx_broadcast", .offset = 0x03 }, 16 { .name = "rx_short", .offset = 0x04 }, 17 { .name = "rx_frag", .offset = 0x05 }, 18 { .name = "rx_jabber", .offset = 0x06 }, 19 { .name = "rx_crc", .offset = 0x07 }, 20 { .name = "rx_symbol_err", .offset = 0x08 }, 21 { .name = "rx_sz_64", .offset = 0x09 }, 22 { .name = "rx_sz_65_127", .offset = 0x0a}, 23 { .name = "rx_sz_128_255", .offset = 0x0b}, 24 { .name = "rx_sz_256_511", .offset = 0x0c }, 25 { .name = "rx_sz_512_1023", .offset = 0x0d }, 26 { .name = "rx_sz_1024_1526", .offset = 0x0e }, 27 { .name = "rx_sz_jumbo", .offset = 0x0f }, 28 { .name = "rx_pause", .offset = 0x10 }, 29 { .name = "rx_control", .offset = 0x11 }, 30 { .name = "rx_long", .offset = 0x12 }, 31 { .name = "rx_cat_drop", .offset = 0x13 }, 32 { .name = "rx_red_prio_0", .offset = 0x14 }, 33 { .name = "rx_red_prio_1", .offset = 0x15 }, 34 { .name = "rx_red_prio_2", .offset = 0x16 }, 35 { .name = "rx_red_prio_3", .offset = 0x17 }, 36 { .name = "rx_red_prio_4", .offset = 0x18 }, 37 { .name = "rx_red_prio_5", .offset = 0x19 }, 38 { .name = "rx_red_prio_6", .offset = 0x1a }, 39 { .name = "rx_red_prio_7", .offset = 0x1b }, 40 { .name = "rx_yellow_prio_0", .offset = 0x1c }, 41 { .name = "rx_yellow_prio_1", .offset = 0x1d }, 42 { .name = "rx_yellow_prio_2", .offset = 0x1e }, 43 { .name = "rx_yellow_prio_3", .offset = 0x1f }, 44 { .name = "rx_yellow_prio_4", .offset = 0x20 }, 45 { .name = "rx_yellow_prio_5", .offset = 0x21 }, 46 { .name = "rx_yellow_prio_6", .offset = 0x22 }, 47 { .name = "rx_yellow_prio_7", .offset = 0x23 }, 48 { .name = "rx_green_prio_0", .offset = 0x24 }, 49 { .name = "rx_green_prio_1", .offset = 0x25 }, 50 { .name = "rx_green_prio_2", .offset = 0x26 }, 51 { .name = "rx_green_prio_3", .offset = 0x27 }, 52 { .name = "rx_green_prio_4", .offset = 0x28 }, 53 { .name = "rx_green_prio_5", .offset = 0x29 }, 54 { .name = "rx_green_prio_6", .offset = 0x2a }, 55 { .name = "rx_green_prio_7", .offset = 0x2b }, 56 { .name = "rx_assembly_err", .offset = 0x2c }, 57 { .name = "rx_smd_err", .offset = 0x2d }, 58 { .name = "rx_assembly_ok", .offset = 0x2e }, 59 { .name = "rx_merge_frag", .offset = 0x2f }, 60 { .name = "rx_pmac_octets", .offset = 0x30, }, 61 { .name = "rx_pmac_unicast", .offset = 0x31, }, 62 { .name = "rx_pmac_multicast", .offset = 0x32 }, 63 { .name = "rx_pmac_broadcast", .offset = 0x33 }, 64 { .name = "rx_pmac_short", .offset = 0x34 }, 65 { .name = "rx_pmac_frag", .offset = 0x35 }, 66 { .name = "rx_pmac_jabber", .offset = 0x36 }, 67 { .name = "rx_pmac_crc", .offset = 0x37 }, 68 { .name = "rx_pmac_symbol_err", .offset = 0x38 }, 69 { .name = "rx_pmac_sz_64", .offset = 0x39 }, 70 { .name = "rx_pmac_sz_65_127", .offset = 0x3a }, 71 { .name = "rx_pmac_sz_128_255", .offset = 0x3b }, 72 { .name = "rx_pmac_sz_256_511", .offset = 0x3c }, 73 { .name = "rx_pmac_sz_512_1023", .offset = 0x3d }, 74 { .name = "rx_pmac_sz_1024_1526", .offset = 0x3e }, 75 { .name = "rx_pmac_sz_jumbo", .offset = 0x3f }, 76 { .name = "rx_pmac_pause", .offset = 0x40 }, 77 { .name = "rx_pmac_control", .offset = 0x41 }, 78 { .name = "rx_pmac_long", .offset = 0x42 }, 79 80 { .name = "tx_octets", .offset = 0x80, }, 81 { .name = "tx_unicast", .offset = 0x81, }, 82 { .name = "tx_multicast", .offset = 0x82 }, 83 { .name = "tx_broadcast", .offset = 0x83 }, 84 { .name = "tx_col", .offset = 0x84 }, 85 { .name = "tx_drop", .offset = 0x85 }, 86 { .name = "tx_pause", .offset = 0x86 }, 87 { .name = "tx_sz_64", .offset = 0x87 }, 88 { .name = "tx_sz_65_127", .offset = 0x88 }, 89 { .name = "tx_sz_128_255", .offset = 0x89 }, 90 { .name = "tx_sz_256_511", .offset = 0x8a }, 91 { .name = "tx_sz_512_1023", .offset = 0x8b }, 92 { .name = "tx_sz_1024_1526", .offset = 0x8c }, 93 { .name = "tx_sz_jumbo", .offset = 0x8d }, 94 { .name = "tx_yellow_prio_0", .offset = 0x8e }, 95 { .name = "tx_yellow_prio_1", .offset = 0x8f }, 96 { .name = "tx_yellow_prio_2", .offset = 0x90 }, 97 { .name = "tx_yellow_prio_3", .offset = 0x91 }, 98 { .name = "tx_yellow_prio_4", .offset = 0x92 }, 99 { .name = "tx_yellow_prio_5", .offset = 0x93 }, 100 { .name = "tx_yellow_prio_6", .offset = 0x94 }, 101 { .name = "tx_yellow_prio_7", .offset = 0x95 }, 102 { .name = "tx_green_prio_0", .offset = 0x96 }, 103 { .name = "tx_green_prio_1", .offset = 0x97 }, 104 { .name = "tx_green_prio_2", .offset = 0x98 }, 105 { .name = "tx_green_prio_3", .offset = 0x99 }, 106 { .name = "tx_green_prio_4", .offset = 0x9a }, 107 { .name = "tx_green_prio_5", .offset = 0x9b }, 108 { .name = "tx_green_prio_6", .offset = 0x9c }, 109 { .name = "tx_green_prio_7", .offset = 0x9d }, 110 { .name = "tx_aged", .offset = 0x9e }, 111 { .name = "tx_llct", .offset = 0x9f }, 112 { .name = "tx_ct", .offset = 0xa0 }, 113 { .name = "tx_mm_hold", .offset = 0xa1 }, 114 { .name = "tx_merge_frag", .offset = 0xa2 }, 115 { .name = "tx_pmac_octets", .offset = 0xa3, }, 116 { .name = "tx_pmac_unicast", .offset = 0xa4, }, 117 { .name = "tx_pmac_multicast", .offset = 0xa5 }, 118 { .name = "tx_pmac_broadcast", .offset = 0xa6 }, 119 { .name = "tx_pmac_pause", .offset = 0xa7 }, 120 { .name = "tx_pmac_sz_64", .offset = 0xa8 }, 121 { .name = "tx_pmac_sz_65_127", .offset = 0xa9 }, 122 { .name = "tx_pmac_sz_128_255", .offset = 0xaa }, 123 { .name = "tx_pmac_sz_256_511", .offset = 0xab }, 124 { .name = "tx_pmac_sz_512_1023", .offset = 0xac }, 125 { .name = "tx_pmac_sz_1024_1526", .offset = 0xad }, 126 { .name = "tx_pmac_sz_jumbo", .offset = 0xae }, 127 128 { .name = "dr_local", .offset = 0x100 }, 129 { .name = "dr_tail", .offset = 0x101 }, 130 { .name = "dr_yellow_prio_0", .offset = 0x102 }, 131 { .name = "dr_yellow_prio_1", .offset = 0x103 }, 132 { .name = "dr_yellow_prio_2", .offset = 0x104 }, 133 { .name = "dr_yellow_prio_3", .offset = 0x105 }, 134 { .name = "dr_yellow_prio_4", .offset = 0x106 }, 135 { .name = "dr_yellow_prio_5", .offset = 0x107 }, 136 { .name = "dr_yellow_prio_6", .offset = 0x108 }, 137 { .name = "dr_yellow_prio_7", .offset = 0x109 }, 138 { .name = "dr_green_prio_0", .offset = 0x10a }, 139 { .name = "dr_green_prio_1", .offset = 0x10b }, 140 { .name = "dr_green_prio_2", .offset = 0x10c }, 141 { .name = "dr_green_prio_3", .offset = 0x10d }, 142 { .name = "dr_green_prio_4", .offset = 0x10e }, 143 { .name = "dr_green_prio_5", .offset = 0x10f }, 144 { .name = "dr_green_prio_6", .offset = 0x110 }, 145 { .name = "dr_green_prio_7", .offset = 0x111 }, 146 }; 147 148 /* The following numbers are indexes into lan966x_stats_layout[] */ 149 #define SYS_COUNT_RX_OCT 0 150 #define SYS_COUNT_RX_UC 1 151 #define SYS_COUNT_RX_MC 2 152 #define SYS_COUNT_RX_BC 3 153 #define SYS_COUNT_RX_SHORT 4 154 #define SYS_COUNT_RX_FRAG 5 155 #define SYS_COUNT_RX_JABBER 6 156 #define SYS_COUNT_RX_CRC 7 157 #define SYS_COUNT_RX_SYMBOL_ERR 8 158 #define SYS_COUNT_RX_SZ_64 9 159 #define SYS_COUNT_RX_SZ_65_127 10 160 #define SYS_COUNT_RX_SZ_128_255 11 161 #define SYS_COUNT_RX_SZ_256_511 12 162 #define SYS_COUNT_RX_SZ_512_1023 13 163 #define SYS_COUNT_RX_SZ_1024_1526 14 164 #define SYS_COUNT_RX_SZ_JUMBO 15 165 #define SYS_COUNT_RX_PAUSE 16 166 #define SYS_COUNT_RX_CONTROL 17 167 #define SYS_COUNT_RX_LONG 18 168 #define SYS_COUNT_RX_CAT_DROP 19 169 #define SYS_COUNT_RX_RED_PRIO_0 20 170 #define SYS_COUNT_RX_RED_PRIO_1 21 171 #define SYS_COUNT_RX_RED_PRIO_2 22 172 #define SYS_COUNT_RX_RED_PRIO_3 23 173 #define SYS_COUNT_RX_RED_PRIO_4 24 174 #define SYS_COUNT_RX_RED_PRIO_5 25 175 #define SYS_COUNT_RX_RED_PRIO_6 26 176 #define SYS_COUNT_RX_RED_PRIO_7 27 177 #define SYS_COUNT_RX_YELLOW_PRIO_0 28 178 #define SYS_COUNT_RX_YELLOW_PRIO_1 29 179 #define SYS_COUNT_RX_YELLOW_PRIO_2 30 180 #define SYS_COUNT_RX_YELLOW_PRIO_3 31 181 #define SYS_COUNT_RX_YELLOW_PRIO_4 32 182 #define SYS_COUNT_RX_YELLOW_PRIO_5 33 183 #define SYS_COUNT_RX_YELLOW_PRIO_6 34 184 #define SYS_COUNT_RX_YELLOW_PRIO_7 35 185 #define SYS_COUNT_RX_GREEN_PRIO_0 36 186 #define SYS_COUNT_RX_GREEN_PRIO_1 37 187 #define SYS_COUNT_RX_GREEN_PRIO_2 38 188 #define SYS_COUNT_RX_GREEN_PRIO_3 39 189 #define SYS_COUNT_RX_GREEN_PRIO_4 40 190 #define SYS_COUNT_RX_GREEN_PRIO_5 41 191 #define SYS_COUNT_RX_GREEN_PRIO_6 42 192 #define SYS_COUNT_RX_GREEN_PRIO_7 43 193 #define SYS_COUNT_RX_ASSEMBLY_ERR 44 194 #define SYS_COUNT_RX_SMD_ERR 45 195 #define SYS_COUNT_RX_ASSEMBLY_OK 46 196 #define SYS_COUNT_RX_MERGE_FRAG 47 197 #define SYS_COUNT_RX_PMAC_OCT 48 198 #define SYS_COUNT_RX_PMAC_UC 49 199 #define SYS_COUNT_RX_PMAC_MC 50 200 #define SYS_COUNT_RX_PMAC_BC 51 201 #define SYS_COUNT_RX_PMAC_SHORT 52 202 #define SYS_COUNT_RX_PMAC_FRAG 53 203 #define SYS_COUNT_RX_PMAC_JABBER 54 204 #define SYS_COUNT_RX_PMAC_CRC 55 205 #define SYS_COUNT_RX_PMAC_SYMBOL_ERR 56 206 #define SYS_COUNT_RX_PMAC_SZ_64 57 207 #define SYS_COUNT_RX_PMAC_SZ_65_127 58 208 #define SYS_COUNT_RX_PMAC_SZ_128_255 59 209 #define SYS_COUNT_RX_PMAC_SZ_256_511 60 210 #define SYS_COUNT_RX_PMAC_SZ_512_1023 61 211 #define SYS_COUNT_RX_PMAC_SZ_1024_1526 62 212 #define SYS_COUNT_RX_PMAC_SZ_JUMBO 63 213 #define SYS_COUNT_RX_PMAC_PAUSE 64 214 #define SYS_COUNT_RX_PMAC_CONTROL 65 215 #define SYS_COUNT_RX_PMAC_LONG 66 216 217 #define SYS_COUNT_TX_OCT 67 218 #define SYS_COUNT_TX_UC 68 219 #define SYS_COUNT_TX_MC 69 220 #define SYS_COUNT_TX_BC 70 221 #define SYS_COUNT_TX_COL 71 222 #define SYS_COUNT_TX_DROP 72 223 #define SYS_COUNT_TX_PAUSE 73 224 #define SYS_COUNT_TX_SZ_64 74 225 #define SYS_COUNT_TX_SZ_65_127 75 226 #define SYS_COUNT_TX_SZ_128_255 76 227 #define SYS_COUNT_TX_SZ_256_511 77 228 #define SYS_COUNT_TX_SZ_512_1023 78 229 #define SYS_COUNT_TX_SZ_1024_1526 79 230 #define SYS_COUNT_TX_SZ_JUMBO 80 231 #define SYS_COUNT_TX_YELLOW_PRIO_0 81 232 #define SYS_COUNT_TX_YELLOW_PRIO_1 82 233 #define SYS_COUNT_TX_YELLOW_PRIO_2 83 234 #define SYS_COUNT_TX_YELLOW_PRIO_3 84 235 #define SYS_COUNT_TX_YELLOW_PRIO_4 85 236 #define SYS_COUNT_TX_YELLOW_PRIO_5 86 237 #define SYS_COUNT_TX_YELLOW_PRIO_6 87 238 #define SYS_COUNT_TX_YELLOW_PRIO_7 88 239 #define SYS_COUNT_TX_GREEN_PRIO_0 89 240 #define SYS_COUNT_TX_GREEN_PRIO_1 90 241 #define SYS_COUNT_TX_GREEN_PRIO_2 91 242 #define SYS_COUNT_TX_GREEN_PRIO_3 92 243 #define SYS_COUNT_TX_GREEN_PRIO_4 93 244 #define SYS_COUNT_TX_GREEN_PRIO_5 94 245 #define SYS_COUNT_TX_GREEN_PRIO_6 95 246 #define SYS_COUNT_TX_GREEN_PRIO_7 96 247 #define SYS_COUNT_TX_AGED 97 248 #define SYS_COUNT_TX_LLCT 98 249 #define SYS_COUNT_TX_CT 99 250 #define SYS_COUNT_TX_MM_HOLD 100 251 #define SYS_COUNT_TX_MERGE_FRAG 101 252 #define SYS_COUNT_TX_PMAC_OCT 102 253 #define SYS_COUNT_TX_PMAC_UC 103 254 #define SYS_COUNT_TX_PMAC_MC 104 255 #define SYS_COUNT_TX_PMAC_BC 105 256 #define SYS_COUNT_TX_PMAC_PAUSE 106 257 #define SYS_COUNT_TX_PMAC_SZ_64 107 258 #define SYS_COUNT_TX_PMAC_SZ_65_127 108 259 #define SYS_COUNT_TX_PMAC_SZ_128_255 109 260 #define SYS_COUNT_TX_PMAC_SZ_256_511 110 261 #define SYS_COUNT_TX_PMAC_SZ_512_1023 111 262 #define SYS_COUNT_TX_PMAC_SZ_1024_1526 112 263 #define SYS_COUNT_TX_PMAC_SZ_JUMBO 113 264 265 #define SYS_COUNT_DR_LOCAL 114 266 #define SYS_COUNT_DR_TAIL 115 267 #define SYS_COUNT_DR_YELLOW_PRIO_0 116 268 #define SYS_COUNT_DR_YELLOW_PRIO_1 117 269 #define SYS_COUNT_DR_YELLOW_PRIO_2 118 270 #define SYS_COUNT_DR_YELLOW_PRIO_3 119 271 #define SYS_COUNT_DR_YELLOW_PRIO_4 120 272 #define SYS_COUNT_DR_YELLOW_PRIO_5 121 273 #define SYS_COUNT_DR_YELLOW_PRIO_6 122 274 #define SYS_COUNT_DR_YELLOW_PRIO_7 123 275 #define SYS_COUNT_DR_GREEN_PRIO_0 124 276 #define SYS_COUNT_DR_GREEN_PRIO_1 125 277 #define SYS_COUNT_DR_GREEN_PRIO_2 126 278 #define SYS_COUNT_DR_GREEN_PRIO_3 127 279 #define SYS_COUNT_DR_GREEN_PRIO_4 128 280 #define SYS_COUNT_DR_GREEN_PRIO_5 129 281 #define SYS_COUNT_DR_GREEN_PRIO_6 130 282 #define SYS_COUNT_DR_GREEN_PRIO_7 131 283 284 /* Add a possibly wrapping 32 bit value to a 64 bit counter */ 285 static void lan966x_add_cnt(u64 *cnt, u32 val) 286 { 287 if (val < (*cnt & U32_MAX)) 288 *cnt += (u64)1 << 32; /* value has wrapped */ 289 290 *cnt = (*cnt & ~(u64)U32_MAX) + val; 291 } 292 293 static void lan966x_stats_update(struct lan966x *lan966x) 294 { 295 int i, j; 296 297 mutex_lock(&lan966x->stats_lock); 298 299 for (i = 0; i < lan966x->num_phys_ports; i++) { 300 uint idx = i * lan966x->num_stats; 301 302 lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(i), 303 lan966x, SYS_STAT_CFG); 304 305 for (j = 0; j < lan966x->num_stats; j++) { 306 u32 offset = lan966x->stats_layout[j].offset; 307 308 lan966x_add_cnt(&lan966x->stats[idx++], 309 lan_rd(lan966x, SYS_CNT(offset))); 310 } 311 } 312 313 mutex_unlock(&lan966x->stats_lock); 314 } 315 316 static int lan966x_get_sset_count(struct net_device *dev, int sset) 317 { 318 struct lan966x_port *port = netdev_priv(dev); 319 struct lan966x *lan966x = port->lan966x; 320 321 if (sset != ETH_SS_STATS) 322 return -EOPNOTSUPP; 323 324 return lan966x->num_stats; 325 } 326 327 static void lan966x_get_strings(struct net_device *netdev, u32 sset, u8 *data) 328 { 329 struct lan966x_port *port = netdev_priv(netdev); 330 struct lan966x *lan966x = port->lan966x; 331 int i; 332 333 if (sset != ETH_SS_STATS) 334 return; 335 336 for (i = 0; i < lan966x->num_stats; i++) 337 memcpy(data + i * ETH_GSTRING_LEN, 338 lan966x->stats_layout[i].name, ETH_GSTRING_LEN); 339 } 340 341 static void lan966x_get_ethtool_stats(struct net_device *dev, 342 struct ethtool_stats *stats, u64 *data) 343 { 344 struct lan966x_port *port = netdev_priv(dev); 345 struct lan966x *lan966x = port->lan966x; 346 int i; 347 348 /* check and update now */ 349 lan966x_stats_update(lan966x); 350 351 /* Copy all counters */ 352 for (i = 0; i < lan966x->num_stats; i++) 353 *data++ = lan966x->stats[port->chip_port * 354 lan966x->num_stats + i]; 355 } 356 357 static void lan966x_get_eth_mac_stats(struct net_device *dev, 358 struct ethtool_eth_mac_stats *mac_stats) 359 { 360 struct lan966x_port *port = netdev_priv(dev); 361 struct lan966x *lan966x = port->lan966x; 362 u32 idx; 363 364 lan966x_stats_update(lan966x); 365 366 idx = port->chip_port * lan966x->num_stats; 367 368 mutex_lock(&lan966x->stats_lock); 369 370 mac_stats->FramesTransmittedOK = 371 lan966x->stats[idx + SYS_COUNT_TX_UC] + 372 lan966x->stats[idx + SYS_COUNT_TX_MC] + 373 lan966x->stats[idx + SYS_COUNT_TX_BC] + 374 lan966x->stats[idx + SYS_COUNT_TX_PMAC_UC] + 375 lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC] + 376 lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC]; 377 mac_stats->SingleCollisionFrames = 378 lan966x->stats[idx + SYS_COUNT_TX_COL]; 379 mac_stats->MultipleCollisionFrames = 0; 380 mac_stats->FramesReceivedOK = 381 lan966x->stats[idx + SYS_COUNT_RX_UC] + 382 lan966x->stats[idx + SYS_COUNT_RX_MC] + 383 lan966x->stats[idx + SYS_COUNT_RX_BC]; 384 mac_stats->FrameCheckSequenceErrors = 385 lan966x->stats[idx + SYS_COUNT_RX_CRC] + 386 lan966x->stats[idx + SYS_COUNT_RX_CRC]; 387 mac_stats->AlignmentErrors = 0; 388 mac_stats->OctetsTransmittedOK = 389 lan966x->stats[idx + SYS_COUNT_TX_OCT] + 390 lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT]; 391 mac_stats->FramesWithDeferredXmissions = 392 lan966x->stats[idx + SYS_COUNT_TX_MM_HOLD]; 393 mac_stats->LateCollisions = 0; 394 mac_stats->FramesAbortedDueToXSColls = 0; 395 mac_stats->FramesLostDueToIntMACXmitError = 0; 396 mac_stats->CarrierSenseErrors = 0; 397 mac_stats->OctetsReceivedOK = 398 lan966x->stats[idx + SYS_COUNT_RX_OCT]; 399 mac_stats->FramesLostDueToIntMACRcvError = 0; 400 mac_stats->MulticastFramesXmittedOK = 401 lan966x->stats[idx + SYS_COUNT_TX_MC] + 402 lan966x->stats[idx + SYS_COUNT_TX_PMAC_MC]; 403 mac_stats->BroadcastFramesXmittedOK = 404 lan966x->stats[idx + SYS_COUNT_TX_BC] + 405 lan966x->stats[idx + SYS_COUNT_TX_PMAC_BC]; 406 mac_stats->FramesWithExcessiveDeferral = 0; 407 mac_stats->MulticastFramesReceivedOK = 408 lan966x->stats[idx + SYS_COUNT_RX_MC]; 409 mac_stats->BroadcastFramesReceivedOK = 410 lan966x->stats[idx + SYS_COUNT_RX_BC]; 411 mac_stats->InRangeLengthErrors = 412 lan966x->stats[idx + SYS_COUNT_RX_FRAG] + 413 lan966x->stats[idx + SYS_COUNT_RX_JABBER] + 414 lan966x->stats[idx + SYS_COUNT_RX_CRC] + 415 lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] + 416 lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] + 417 lan966x->stats[idx + SYS_COUNT_RX_PMAC_CRC]; 418 mac_stats->OutOfRangeLengthField = 419 lan966x->stats[idx + SYS_COUNT_RX_SHORT] + 420 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] + 421 lan966x->stats[idx + SYS_COUNT_RX_LONG] + 422 lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG]; 423 mac_stats->FrameTooLongErrors = 424 lan966x->stats[idx + SYS_COUNT_RX_LONG] + 425 lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG]; 426 427 mutex_unlock(&lan966x->stats_lock); 428 } 429 430 static const struct ethtool_rmon_hist_range lan966x_rmon_ranges[] = { 431 { 0, 64 }, 432 { 65, 127 }, 433 { 128, 255 }, 434 { 256, 511 }, 435 { 512, 1023 }, 436 { 1024, 1518 }, 437 { 1519, 10239 }, 438 {} 439 }; 440 441 static void lan966x_get_eth_rmon_stats(struct net_device *dev, 442 struct ethtool_rmon_stats *rmon_stats, 443 const struct ethtool_rmon_hist_range **ranges) 444 { 445 struct lan966x_port *port = netdev_priv(dev); 446 struct lan966x *lan966x = port->lan966x; 447 u32 idx; 448 449 lan966x_stats_update(lan966x); 450 451 idx = port->chip_port * lan966x->num_stats; 452 453 mutex_lock(&lan966x->stats_lock); 454 455 rmon_stats->undersize_pkts = 456 lan966x->stats[idx + SYS_COUNT_RX_SHORT] + 457 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT]; 458 rmon_stats->oversize_pkts = 459 lan966x->stats[idx + SYS_COUNT_RX_LONG] + 460 lan966x->stats[idx + SYS_COUNT_RX_PMAC_LONG]; 461 rmon_stats->fragments = 462 lan966x->stats[idx + SYS_COUNT_RX_FRAG] + 463 lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG]; 464 rmon_stats->jabbers = 465 lan966x->stats[idx + SYS_COUNT_RX_JABBER] + 466 lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER]; 467 rmon_stats->hist[0] = 468 lan966x->stats[idx + SYS_COUNT_RX_SZ_64] + 469 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64]; 470 rmon_stats->hist[1] = 471 lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] + 472 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127]; 473 rmon_stats->hist[2] = 474 lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] + 475 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255]; 476 rmon_stats->hist[3] = 477 lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] + 478 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511]; 479 rmon_stats->hist[4] = 480 lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] + 481 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023]; 482 rmon_stats->hist[5] = 483 lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] + 484 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526]; 485 rmon_stats->hist[6] = 486 lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] + 487 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526]; 488 489 rmon_stats->hist_tx[0] = 490 lan966x->stats[idx + SYS_COUNT_TX_SZ_64] + 491 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64]; 492 rmon_stats->hist_tx[1] = 493 lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] + 494 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127]; 495 rmon_stats->hist_tx[2] = 496 lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] + 497 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255]; 498 rmon_stats->hist_tx[3] = 499 lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] + 500 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511]; 501 rmon_stats->hist_tx[4] = 502 lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] + 503 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023]; 504 rmon_stats->hist_tx[5] = 505 lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] + 506 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526]; 507 rmon_stats->hist_tx[6] = 508 lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] + 509 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526]; 510 511 mutex_unlock(&lan966x->stats_lock); 512 513 *ranges = lan966x_rmon_ranges; 514 } 515 516 static int lan966x_get_link_ksettings(struct net_device *ndev, 517 struct ethtool_link_ksettings *cmd) 518 { 519 struct lan966x_port *port = netdev_priv(ndev); 520 521 return phylink_ethtool_ksettings_get(port->phylink, cmd); 522 } 523 524 static int lan966x_set_link_ksettings(struct net_device *ndev, 525 const struct ethtool_link_ksettings *cmd) 526 { 527 struct lan966x_port *port = netdev_priv(ndev); 528 529 return phylink_ethtool_ksettings_set(port->phylink, cmd); 530 } 531 532 static void lan966x_get_pauseparam(struct net_device *dev, 533 struct ethtool_pauseparam *pause) 534 { 535 struct lan966x_port *port = netdev_priv(dev); 536 537 phylink_ethtool_get_pauseparam(port->phylink, pause); 538 } 539 540 static int lan966x_set_pauseparam(struct net_device *dev, 541 struct ethtool_pauseparam *pause) 542 { 543 struct lan966x_port *port = netdev_priv(dev); 544 545 return phylink_ethtool_set_pauseparam(port->phylink, pause); 546 } 547 548 const struct ethtool_ops lan966x_ethtool_ops = { 549 .get_link_ksettings = lan966x_get_link_ksettings, 550 .set_link_ksettings = lan966x_set_link_ksettings, 551 .get_pauseparam = lan966x_get_pauseparam, 552 .set_pauseparam = lan966x_set_pauseparam, 553 .get_sset_count = lan966x_get_sset_count, 554 .get_strings = lan966x_get_strings, 555 .get_ethtool_stats = lan966x_get_ethtool_stats, 556 .get_eth_mac_stats = lan966x_get_eth_mac_stats, 557 .get_rmon_stats = lan966x_get_eth_rmon_stats, 558 .get_link = ethtool_op_get_link, 559 }; 560 561 static void lan966x_check_stats_work(struct work_struct *work) 562 { 563 struct delayed_work *del_work = to_delayed_work(work); 564 struct lan966x *lan966x = container_of(del_work, struct lan966x, 565 stats_work); 566 567 lan966x_stats_update(lan966x); 568 569 queue_delayed_work(lan966x->stats_queue, &lan966x->stats_work, 570 LAN966X_STATS_CHECK_DELAY); 571 } 572 573 void lan966x_stats_get(struct net_device *dev, 574 struct rtnl_link_stats64 *stats) 575 { 576 struct lan966x_port *port = netdev_priv(dev); 577 struct lan966x *lan966x = port->lan966x; 578 u32 idx; 579 int i; 580 581 idx = port->chip_port * lan966x->num_stats; 582 583 mutex_lock(&lan966x->stats_lock); 584 585 stats->rx_bytes = lan966x->stats[idx + SYS_COUNT_RX_OCT] + 586 lan966x->stats[idx + SYS_COUNT_RX_PMAC_OCT]; 587 588 stats->rx_packets = lan966x->stats[idx + SYS_COUNT_RX_SHORT] + 589 lan966x->stats[idx + SYS_COUNT_RX_FRAG] + 590 lan966x->stats[idx + SYS_COUNT_RX_JABBER] + 591 lan966x->stats[idx + SYS_COUNT_RX_CRC] + 592 lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] + 593 lan966x->stats[idx + SYS_COUNT_RX_SZ_64] + 594 lan966x->stats[idx + SYS_COUNT_RX_SZ_65_127] + 595 lan966x->stats[idx + SYS_COUNT_RX_SZ_128_255] + 596 lan966x->stats[idx + SYS_COUNT_RX_SZ_256_511] + 597 lan966x->stats[idx + SYS_COUNT_RX_SZ_512_1023] + 598 lan966x->stats[idx + SYS_COUNT_RX_SZ_1024_1526] + 599 lan966x->stats[idx + SYS_COUNT_RX_SZ_JUMBO] + 600 lan966x->stats[idx + SYS_COUNT_RX_LONG] + 601 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SHORT] + 602 lan966x->stats[idx + SYS_COUNT_RX_PMAC_FRAG] + 603 lan966x->stats[idx + SYS_COUNT_RX_PMAC_JABBER] + 604 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_64] + 605 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_65_127] + 606 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_128_255] + 607 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_256_511] + 608 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023] + 609 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526] + 610 lan966x->stats[idx + SYS_COUNT_RX_PMAC_SZ_JUMBO]; 611 612 stats->multicast = lan966x->stats[idx + SYS_COUNT_RX_MC] + 613 lan966x->stats[idx + SYS_COUNT_RX_PMAC_MC]; 614 615 stats->rx_errors = lan966x->stats[idx + SYS_COUNT_RX_SHORT] + 616 lan966x->stats[idx + SYS_COUNT_RX_FRAG] + 617 lan966x->stats[idx + SYS_COUNT_RX_JABBER] + 618 lan966x->stats[idx + SYS_COUNT_RX_CRC] + 619 lan966x->stats[idx + SYS_COUNT_RX_SYMBOL_ERR] + 620 lan966x->stats[idx + SYS_COUNT_RX_LONG]; 621 622 stats->rx_dropped = dev->stats.rx_dropped + 623 lan966x->stats[idx + SYS_COUNT_RX_LONG] + 624 lan966x->stats[idx + SYS_COUNT_DR_LOCAL] + 625 lan966x->stats[idx + SYS_COUNT_DR_TAIL]; 626 627 for (i = 0; i < LAN966X_NUM_TC; i++) { 628 stats->rx_dropped += 629 (lan966x->stats[idx + SYS_COUNT_DR_YELLOW_PRIO_0 + i] + 630 lan966x->stats[idx + SYS_COUNT_DR_GREEN_PRIO_0 + i]); 631 } 632 633 /* Get Tx stats */ 634 stats->tx_bytes = lan966x->stats[idx + SYS_COUNT_TX_OCT] + 635 lan966x->stats[idx + SYS_COUNT_TX_PMAC_OCT]; 636 637 stats->tx_packets = lan966x->stats[idx + SYS_COUNT_TX_SZ_64] + 638 lan966x->stats[idx + SYS_COUNT_TX_SZ_65_127] + 639 lan966x->stats[idx + SYS_COUNT_TX_SZ_128_255] + 640 lan966x->stats[idx + SYS_COUNT_TX_SZ_256_511] + 641 lan966x->stats[idx + SYS_COUNT_TX_SZ_512_1023] + 642 lan966x->stats[idx + SYS_COUNT_TX_SZ_1024_1526] + 643 lan966x->stats[idx + SYS_COUNT_TX_SZ_JUMBO] + 644 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_64] + 645 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_65_127] + 646 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_128_255] + 647 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_256_511] + 648 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023] + 649 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526] + 650 lan966x->stats[idx + SYS_COUNT_TX_PMAC_SZ_JUMBO]; 651 652 stats->tx_dropped = lan966x->stats[idx + SYS_COUNT_TX_DROP] + 653 lan966x->stats[idx + SYS_COUNT_TX_AGED]; 654 655 stats->collisions = lan966x->stats[idx + SYS_COUNT_TX_COL]; 656 657 mutex_unlock(&lan966x->stats_lock); 658 } 659 660 int lan966x_stats_init(struct lan966x *lan966x) 661 { 662 char queue_name[32]; 663 664 lan966x->stats_layout = lan966x_stats_layout; 665 lan966x->num_stats = ARRAY_SIZE(lan966x_stats_layout); 666 lan966x->stats = devm_kcalloc(lan966x->dev, lan966x->num_phys_ports * 667 lan966x->num_stats, 668 sizeof(u64), GFP_KERNEL); 669 if (!lan966x->stats) 670 return -ENOMEM; 671 672 /* Init stats worker */ 673 mutex_init(&lan966x->stats_lock); 674 snprintf(queue_name, sizeof(queue_name), "%s-stats", 675 dev_name(lan966x->dev)); 676 lan966x->stats_queue = create_singlethread_workqueue(queue_name); 677 INIT_DELAYED_WORK(&lan966x->stats_work, lan966x_check_stats_work); 678 queue_delayed_work(lan966x->stats_queue, &lan966x->stats_work, 679 LAN966X_STATS_CHECK_DELAY); 680 681 return 0; 682 } 683