sja1105_ethtool.c 10 KB

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