sja1105_ethtool.c (10599B)
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> 3 */ 4#include "sja1105.h" 5 6enum sja1105_counter_index { 7 __SJA1105_COUNTER_UNUSED, 8 /* MAC */ 9 N_RUNT, 10 N_SOFERR, 11 N_ALIGNERR, 12 N_MIIERR, 13 TYPEERR, 14 SIZEERR, 15 TCTIMEOUT, 16 PRIORERR, 17 NOMASTER, 18 MEMOV, 19 MEMERR, 20 INVTYP, 21 INTCYOV, 22 DOMERR, 23 PCFBAGDROP, 24 SPCPRIOR, 25 AGEPRIOR, 26 PORTDROP, 27 LENDROP, 28 BAGDROP, 29 POLICEERR, 30 DRPNONA664ERR, 31 SPCERR, 32 AGEDRP, 33 /* HL1 */ 34 N_N664ERR, 35 N_VLANERR, 36 N_UNRELEASED, 37 N_SIZEERR, 38 N_CRCERR, 39 N_VLNOTFOUND, 40 N_CTPOLERR, 41 N_POLERR, 42 N_RXFRM, 43 N_RXBYTE, 44 N_TXFRM, 45 N_TXBYTE, 46 /* HL2 */ 47 N_QFULL, 48 N_PART_DROP, 49 N_EGR_DISABLED, 50 N_NOT_REACH, 51 __MAX_SJA1105ET_PORT_COUNTER, 52 /* P/Q/R/S only */ 53 /* ETHER */ 54 N_DROPS_NOLEARN = __MAX_SJA1105ET_PORT_COUNTER, 55 N_DROPS_NOROUTE, 56 N_DROPS_ILL_DTAG, 57 N_DROPS_DTAG, 58 N_DROPS_SOTAG, 59 N_DROPS_SITAG, 60 N_DROPS_UTAG, 61 N_TX_BYTES_1024_2047, 62 N_TX_BYTES_512_1023, 63 N_TX_BYTES_256_511, 64 N_TX_BYTES_128_255, 65 N_TX_BYTES_65_127, 66 N_TX_BYTES_64, 67 N_TX_MCAST, 68 N_TX_BCAST, 69 N_RX_BYTES_1024_2047, 70 N_RX_BYTES_512_1023, 71 N_RX_BYTES_256_511, 72 N_RX_BYTES_128_255, 73 N_RX_BYTES_65_127, 74 N_RX_BYTES_64, 75 N_RX_MCAST, 76 N_RX_BCAST, 77 __MAX_SJA1105PQRS_PORT_COUNTER, 78}; 79 80struct sja1105_port_counter { 81 enum sja1105_stats_area area; 82 const char name[ETH_GSTRING_LEN]; 83 int offset; 84 int start; 85 int end; 86 bool is_64bit; 87}; 88 89static const struct sja1105_port_counter sja1105_port_counters[] = { 90 /* MAC-Level Diagnostic Counters */ 91 [N_RUNT] = { 92 .area = MAC, 93 .name = "n_runt", 94 .offset = 0, 95 .start = 31, 96 .end = 24, 97 }, 98 [N_SOFERR] = { 99 .area = MAC, 100 .name = "n_soferr", 101 .offset = 0x0, 102 .start = 23, 103 .end = 16, 104 }, 105 [N_ALIGNERR] = { 106 .area = MAC, 107 .name = "n_alignerr", 108 .offset = 0x0, 109 .start = 15, 110 .end = 8, 111 }, 112 [N_MIIERR] = { 113 .area = MAC, 114 .name = "n_miierr", 115 .offset = 0x0, 116 .start = 7, 117 .end = 0, 118 }, 119 /* MAC-Level Diagnostic Flags */ 120 [TYPEERR] = { 121 .area = MAC, 122 .name = "typeerr", 123 .offset = 0x1, 124 .start = 27, 125 .end = 27, 126 }, 127 [SIZEERR] = { 128 .area = MAC, 129 .name = "sizeerr", 130 .offset = 0x1, 131 .start = 26, 132 .end = 26, 133 }, 134 [TCTIMEOUT] = { 135 .area = MAC, 136 .name = "tctimeout", 137 .offset = 0x1, 138 .start = 25, 139 .end = 25, 140 }, 141 [PRIORERR] = { 142 .area = MAC, 143 .name = "priorerr", 144 .offset = 0x1, 145 .start = 24, 146 .end = 24, 147 }, 148 [NOMASTER] = { 149 .area = MAC, 150 .name = "nomaster", 151 .offset = 0x1, 152 .start = 23, 153 .end = 23, 154 }, 155 [MEMOV] = { 156 .area = MAC, 157 .name = "memov", 158 .offset = 0x1, 159 .start = 22, 160 .end = 22, 161 }, 162 [MEMERR] = { 163 .area = MAC, 164 .name = "memerr", 165 .offset = 0x1, 166 .start = 21, 167 .end = 21, 168 }, 169 [INVTYP] = { 170 .area = MAC, 171 .name = "invtyp", 172 .offset = 0x1, 173 .start = 19, 174 .end = 19, 175 }, 176 [INTCYOV] = { 177 .area = MAC, 178 .name = "intcyov", 179 .offset = 0x1, 180 .start = 18, 181 .end = 18, 182 }, 183 [DOMERR] = { 184 .area = MAC, 185 .name = "domerr", 186 .offset = 0x1, 187 .start = 17, 188 .end = 17, 189 }, 190 [PCFBAGDROP] = { 191 .area = MAC, 192 .name = "pcfbagdrop", 193 .offset = 0x1, 194 .start = 16, 195 .end = 16, 196 }, 197 [SPCPRIOR] = { 198 .area = MAC, 199 .name = "spcprior", 200 .offset = 0x1, 201 .start = 15, 202 .end = 12, 203 }, 204 [AGEPRIOR] = { 205 .area = MAC, 206 .name = "ageprior", 207 .offset = 0x1, 208 .start = 11, 209 .end = 8, 210 }, 211 [PORTDROP] = { 212 .area = MAC, 213 .name = "portdrop", 214 .offset = 0x1, 215 .start = 6, 216 .end = 6, 217 }, 218 [LENDROP] = { 219 .area = MAC, 220 .name = "lendrop", 221 .offset = 0x1, 222 .start = 5, 223 .end = 5, 224 }, 225 [BAGDROP] = { 226 .area = MAC, 227 .name = "bagdrop", 228 .offset = 0x1, 229 .start = 4, 230 .end = 4, 231 }, 232 [POLICEERR] = { 233 .area = MAC, 234 .name = "policeerr", 235 .offset = 0x1, 236 .start = 3, 237 .end = 3, 238 }, 239 [DRPNONA664ERR] = { 240 .area = MAC, 241 .name = "drpnona664err", 242 .offset = 0x1, 243 .start = 2, 244 .end = 2, 245 }, 246 [SPCERR] = { 247 .area = MAC, 248 .name = "spcerr", 249 .offset = 0x1, 250 .start = 1, 251 .end = 1, 252 }, 253 [AGEDRP] = { 254 .area = MAC, 255 .name = "agedrp", 256 .offset = 0x1, 257 .start = 0, 258 .end = 0, 259 }, 260 /* High-Level Diagnostic Counters */ 261 [N_N664ERR] = { 262 .area = HL1, 263 .name = "n_n664err", 264 .offset = 0xF, 265 .start = 31, 266 .end = 0, 267 }, 268 [N_VLANERR] = { 269 .area = HL1, 270 .name = "n_vlanerr", 271 .offset = 0xE, 272 .start = 31, 273 .end = 0, 274 }, 275 [N_UNRELEASED] = { 276 .area = HL1, 277 .name = "n_unreleased", 278 .offset = 0xD, 279 .start = 31, 280 .end = 0, 281 }, 282 [N_SIZEERR] = { 283 .area = HL1, 284 .name = "n_sizeerr", 285 .offset = 0xC, 286 .start = 31, 287 .end = 0, 288 }, 289 [N_CRCERR] = { 290 .area = HL1, 291 .name = "n_crcerr", 292 .offset = 0xB, 293 .start = 31, 294 .end = 0, 295 }, 296 [N_VLNOTFOUND] = { 297 .area = HL1, 298 .name = "n_vlnotfound", 299 .offset = 0xA, 300 .start = 31, 301 .end = 0, 302 }, 303 [N_CTPOLERR] = { 304 .area = HL1, 305 .name = "n_ctpolerr", 306 .offset = 0x9, 307 .start = 31, 308 .end = 0, 309 }, 310 [N_POLERR] = { 311 .area = HL1, 312 .name = "n_polerr", 313 .offset = 0x8, 314 .start = 31, 315 .end = 0, 316 }, 317 [N_RXFRM] = { 318 .area = HL1, 319 .name = "n_rxfrm", 320 .offset = 0x6, 321 .start = 31, 322 .end = 0, 323 .is_64bit = true, 324 }, 325 [N_RXBYTE] = { 326 .area = HL1, 327 .name = "n_rxbyte", 328 .offset = 0x4, 329 .start = 31, 330 .end = 0, 331 .is_64bit = true, 332 }, 333 [N_TXFRM] = { 334 .area = HL1, 335 .name = "n_txfrm", 336 .offset = 0x2, 337 .start = 31, 338 .end = 0, 339 .is_64bit = true, 340 }, 341 [N_TXBYTE] = { 342 .area = HL1, 343 .name = "n_txbyte", 344 .offset = 0x0, 345 .start = 31, 346 .end = 0, 347 .is_64bit = true, 348 }, 349 [N_QFULL] = { 350 .area = HL2, 351 .name = "n_qfull", 352 .offset = 0x3, 353 .start = 31, 354 .end = 0, 355 }, 356 [N_PART_DROP] = { 357 .area = HL2, 358 .name = "n_part_drop", 359 .offset = 0x2, 360 .start = 31, 361 .end = 0, 362 }, 363 [N_EGR_DISABLED] = { 364 .area = HL2, 365 .name = "n_egr_disabled", 366 .offset = 0x1, 367 .start = 31, 368 .end = 0, 369 }, 370 [N_NOT_REACH] = { 371 .area = HL2, 372 .name = "n_not_reach", 373 .offset = 0x0, 374 .start = 31, 375 .end = 0, 376 }, 377 /* Ether Stats */ 378 [N_DROPS_NOLEARN] = { 379 .area = ETHER, 380 .name = "n_drops_nolearn", 381 .offset = 0x16, 382 .start = 31, 383 .end = 0, 384 }, 385 [N_DROPS_NOROUTE] = { 386 .area = ETHER, 387 .name = "n_drops_noroute", 388 .offset = 0x15, 389 .start = 31, 390 .end = 0, 391 }, 392 [N_DROPS_ILL_DTAG] = { 393 .area = ETHER, 394 .name = "n_drops_ill_dtag", 395 .offset = 0x14, 396 .start = 31, 397 .end = 0, 398 }, 399 [N_DROPS_DTAG] = { 400 .area = ETHER, 401 .name = "n_drops_dtag", 402 .offset = 0x13, 403 .start = 31, 404 .end = 0, 405 }, 406 [N_DROPS_SOTAG] = { 407 .area = ETHER, 408 .name = "n_drops_sotag", 409 .offset = 0x12, 410 .start = 31, 411 .end = 0, 412 }, 413 [N_DROPS_SITAG] = { 414 .area = ETHER, 415 .name = "n_drops_sitag", 416 .offset = 0x11, 417 .start = 31, 418 .end = 0, 419 }, 420 [N_DROPS_UTAG] = { 421 .area = ETHER, 422 .name = "n_drops_utag", 423 .offset = 0x10, 424 .start = 31, 425 .end = 0, 426 }, 427 [N_TX_BYTES_1024_2047] = { 428 .area = ETHER, 429 .name = "n_tx_bytes_1024_2047", 430 .offset = 0x0F, 431 .start = 31, 432 .end = 0, 433 }, 434 [N_TX_BYTES_512_1023] = { 435 .area = ETHER, 436 .name = "n_tx_bytes_512_1023", 437 .offset = 0x0E, 438 .start = 31, 439 .end = 0, 440 }, 441 [N_TX_BYTES_256_511] = { 442 .area = ETHER, 443 .name = "n_tx_bytes_256_511", 444 .offset = 0x0D, 445 .start = 31, 446 .end = 0, 447 }, 448 [N_TX_BYTES_128_255] = { 449 .area = ETHER, 450 .name = "n_tx_bytes_128_255", 451 .offset = 0x0C, 452 .start = 31, 453 .end = 0, 454 }, 455 [N_TX_BYTES_65_127] = { 456 .area = ETHER, 457 .name = "n_tx_bytes_65_127", 458 .offset = 0x0B, 459 .start = 31, 460 .end = 0, 461 }, 462 [N_TX_BYTES_64] = { 463 .area = ETHER, 464 .name = "n_tx_bytes_64", 465 .offset = 0x0A, 466 .start = 31, 467 .end = 0, 468 }, 469 [N_TX_MCAST] = { 470 .area = ETHER, 471 .name = "n_tx_mcast", 472 .offset = 0x09, 473 .start = 31, 474 .end = 0, 475 }, 476 [N_TX_BCAST] = { 477 .area = ETHER, 478 .name = "n_tx_bcast", 479 .offset = 0x08, 480 .start = 31, 481 .end = 0, 482 }, 483 [N_RX_BYTES_1024_2047] = { 484 .area = ETHER, 485 .name = "n_rx_bytes_1024_2047", 486 .offset = 0x07, 487 .start = 31, 488 .end = 0, 489 }, 490 [N_RX_BYTES_512_1023] = { 491 .area = ETHER, 492 .name = "n_rx_bytes_512_1023", 493 .offset = 0x06, 494 .start = 31, 495 .end = 0, 496 }, 497 [N_RX_BYTES_256_511] = { 498 .area = ETHER, 499 .name = "n_rx_bytes_256_511", 500 .offset = 0x05, 501 .start = 31, 502 .end = 0, 503 }, 504 [N_RX_BYTES_128_255] = { 505 .area = ETHER, 506 .name = "n_rx_bytes_128_255", 507 .offset = 0x04, 508 .start = 31, 509 .end = 0, 510 }, 511 [N_RX_BYTES_65_127] = { 512 .area = ETHER, 513 .name = "n_rx_bytes_65_127", 514 .offset = 0x03, 515 .start = 31, 516 .end = 0, 517 }, 518 [N_RX_BYTES_64] = { 519 .area = ETHER, 520 .name = "n_rx_bytes_64", 521 .offset = 0x02, 522 .start = 31, 523 .end = 0, 524 }, 525 [N_RX_MCAST] = { 526 .area = ETHER, 527 .name = "n_rx_mcast", 528 .offset = 0x01, 529 .start = 31, 530 .end = 0, 531 }, 532 [N_RX_BCAST] = { 533 .area = ETHER, 534 .name = "n_rx_bcast", 535 .offset = 0x00, 536 .start = 31, 537 .end = 0, 538 }, 539}; 540 541static int sja1105_port_counter_read(struct sja1105_private *priv, int port, 542 enum sja1105_counter_index idx, u64 *ctr) 543{ 544 const struct sja1105_port_counter *c = &sja1105_port_counters[idx]; 545 size_t size = c->is_64bit ? 8 : 4; 546 u8 buf[8] = {0}; 547 u64 regs; 548 int rc; 549 550 regs = priv->info->regs->stats[c->area][port]; 551 552 rc = sja1105_xfer_buf(priv, SPI_READ, regs + c->offset, buf, size); 553 if (rc) 554 return rc; 555 556 sja1105_unpack(buf, ctr, c->start, c->end, size); 557 558 return 0; 559} 560 561void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 562{ 563 struct sja1105_private *priv = ds->priv; 564 enum sja1105_counter_index max_ctr, i; 565 int rc, k = 0; 566 567 if (priv->info->device_id == SJA1105E_DEVICE_ID || 568 priv->info->device_id == SJA1105T_DEVICE_ID) 569 max_ctr = __MAX_SJA1105ET_PORT_COUNTER; 570 else 571 max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER; 572 573 for (i = 0; i < max_ctr; i++) { 574 rc = sja1105_port_counter_read(priv, port, i, &data[k++]); 575 if (rc) { 576 dev_err(ds->dev, 577 "Failed to read port %d counters: %d\n", 578 port, rc); 579 break; 580 } 581 } 582} 583 584void sja1105_get_strings(struct dsa_switch *ds, int port, 585 u32 stringset, u8 *data) 586{ 587 struct sja1105_private *priv = ds->priv; 588 enum sja1105_counter_index max_ctr, i; 589 char *p = data; 590 591 if (stringset != ETH_SS_STATS) 592 return; 593 594 if (priv->info->device_id == SJA1105E_DEVICE_ID || 595 priv->info->device_id == SJA1105T_DEVICE_ID) 596 max_ctr = __MAX_SJA1105ET_PORT_COUNTER; 597 else 598 max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER; 599 600 for (i = 0; i < max_ctr; i++) { 601 strscpy(p, sja1105_port_counters[i].name, ETH_GSTRING_LEN); 602 p += ETH_GSTRING_LEN; 603 } 604} 605 606int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset) 607{ 608 struct sja1105_private *priv = ds->priv; 609 enum sja1105_counter_index max_ctr, i; 610 int sset_count = 0; 611 612 if (sset != ETH_SS_STATS) 613 return -EOPNOTSUPP; 614 615 if (priv->info->device_id == SJA1105E_DEVICE_ID || 616 priv->info->device_id == SJA1105T_DEVICE_ID) 617 max_ctr = __MAX_SJA1105ET_PORT_COUNTER; 618 else 619 max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER; 620 621 for (i = 0; i < max_ctr; i++) { 622 if (!strlen(sja1105_port_counters[i].name)) 623 continue; 624 625 sset_count++; 626 } 627 628 return sset_count; 629}