1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com> 3 */ 4 #include "sja1105.h" 5 6 #define SJA1105_SIZE_MAC_AREA (0x02 * 4) 7 #define SJA1105_SIZE_HL1_AREA (0x10 * 4) 8 #define SJA1105_SIZE_HL2_AREA (0x4 * 4) 9 #define SJA1105_SIZE_QLEVEL_AREA (0x8 * 4) /* 0x4 to 0xB */ 10 #define SJA1105_SIZE_ETHER_AREA (0x17 * 4) 11 12 struct sja1105_port_status_mac { 13 u64 n_runt; 14 u64 n_soferr; 15 u64 n_alignerr; 16 u64 n_miierr; 17 u64 typeerr; 18 u64 sizeerr; 19 u64 tctimeout; 20 u64 priorerr; 21 u64 nomaster; 22 u64 memov; 23 u64 memerr; 24 u64 invtyp; 25 u64 intcyov; 26 u64 domerr; 27 u64 pcfbagdrop; 28 u64 spcprior; 29 u64 ageprior; 30 u64 portdrop; 31 u64 lendrop; 32 u64 bagdrop; 33 u64 policeerr; 34 u64 drpnona664err; 35 u64 spcerr; 36 u64 agedrp; 37 }; 38 39 struct sja1105_port_status_hl1 { 40 u64 n_n664err; 41 u64 n_vlanerr; 42 u64 n_unreleased; 43 u64 n_sizeerr; 44 u64 n_crcerr; 45 u64 n_vlnotfound; 46 u64 n_ctpolerr; 47 u64 n_polerr; 48 u64 n_rxfrmsh; 49 u64 n_rxfrm; 50 u64 n_rxbytesh; 51 u64 n_rxbyte; 52 u64 n_txfrmsh; 53 u64 n_txfrm; 54 u64 n_txbytesh; 55 u64 n_txbyte; 56 }; 57 58 struct sja1105_port_status_hl2 { 59 u64 n_qfull; 60 u64 n_part_drop; 61 u64 n_egr_disabled; 62 u64 n_not_reach; 63 u64 qlevel_hwm[8]; /* Only for P/Q/R/S */ 64 u64 qlevel[8]; /* Only for P/Q/R/S */ 65 }; 66 67 struct sja1105_port_status_ether { 68 u64 n_drops_nolearn; 69 u64 n_drops_noroute; 70 u64 n_drops_ill_dtag; 71 u64 n_drops_dtag; 72 u64 n_drops_sotag; 73 u64 n_drops_sitag; 74 u64 n_drops_utag; 75 u64 n_tx_bytes_1024_2047; 76 u64 n_tx_bytes_512_1023; 77 u64 n_tx_bytes_256_511; 78 u64 n_tx_bytes_128_255; 79 u64 n_tx_bytes_65_127; 80 u64 n_tx_bytes_64; 81 u64 n_tx_mcast; 82 u64 n_tx_bcast; 83 u64 n_rx_bytes_1024_2047; 84 u64 n_rx_bytes_512_1023; 85 u64 n_rx_bytes_256_511; 86 u64 n_rx_bytes_128_255; 87 u64 n_rx_bytes_65_127; 88 u64 n_rx_bytes_64; 89 u64 n_rx_mcast; 90 u64 n_rx_bcast; 91 }; 92 93 struct sja1105_port_status { 94 struct sja1105_port_status_mac mac; 95 struct sja1105_port_status_hl1 hl1; 96 struct sja1105_port_status_hl2 hl2; 97 struct sja1105_port_status_ether ether; 98 }; 99 100 static void 101 sja1105_port_status_mac_unpack(void *buf, 102 struct sja1105_port_status_mac *status) 103 { 104 /* Make pointer arithmetic work on 4 bytes */ 105 u32 *p = buf; 106 107 sja1105_unpack(p + 0x0, &status->n_runt, 31, 24, 4); 108 sja1105_unpack(p + 0x0, &status->n_soferr, 23, 16, 4); 109 sja1105_unpack(p + 0x0, &status->n_alignerr, 15, 8, 4); 110 sja1105_unpack(p + 0x0, &status->n_miierr, 7, 0, 4); 111 sja1105_unpack(p + 0x1, &status->typeerr, 27, 27, 4); 112 sja1105_unpack(p + 0x1, &status->sizeerr, 26, 26, 4); 113 sja1105_unpack(p + 0x1, &status->tctimeout, 25, 25, 4); 114 sja1105_unpack(p + 0x1, &status->priorerr, 24, 24, 4); 115 sja1105_unpack(p + 0x1, &status->nomaster, 23, 23, 4); 116 sja1105_unpack(p + 0x1, &status->memov, 22, 22, 4); 117 sja1105_unpack(p + 0x1, &status->memerr, 21, 21, 4); 118 sja1105_unpack(p + 0x1, &status->invtyp, 19, 19, 4); 119 sja1105_unpack(p + 0x1, &status->intcyov, 18, 18, 4); 120 sja1105_unpack(p + 0x1, &status->domerr, 17, 17, 4); 121 sja1105_unpack(p + 0x1, &status->pcfbagdrop, 16, 16, 4); 122 sja1105_unpack(p + 0x1, &status->spcprior, 15, 12, 4); 123 sja1105_unpack(p + 0x1, &status->ageprior, 11, 8, 4); 124 sja1105_unpack(p + 0x1, &status->portdrop, 6, 6, 4); 125 sja1105_unpack(p + 0x1, &status->lendrop, 5, 5, 4); 126 sja1105_unpack(p + 0x1, &status->bagdrop, 4, 4, 4); 127 sja1105_unpack(p + 0x1, &status->policeerr, 3, 3, 4); 128 sja1105_unpack(p + 0x1, &status->drpnona664err, 2, 2, 4); 129 sja1105_unpack(p + 0x1, &status->spcerr, 1, 1, 4); 130 sja1105_unpack(p + 0x1, &status->agedrp, 0, 0, 4); 131 } 132 133 static void 134 sja1105_port_status_hl1_unpack(void *buf, 135 struct sja1105_port_status_hl1 *status) 136 { 137 /* Make pointer arithmetic work on 4 bytes */ 138 u32 *p = buf; 139 140 sja1105_unpack(p + 0xF, &status->n_n664err, 31, 0, 4); 141 sja1105_unpack(p + 0xE, &status->n_vlanerr, 31, 0, 4); 142 sja1105_unpack(p + 0xD, &status->n_unreleased, 31, 0, 4); 143 sja1105_unpack(p + 0xC, &status->n_sizeerr, 31, 0, 4); 144 sja1105_unpack(p + 0xB, &status->n_crcerr, 31, 0, 4); 145 sja1105_unpack(p + 0xA, &status->n_vlnotfound, 31, 0, 4); 146 sja1105_unpack(p + 0x9, &status->n_ctpolerr, 31, 0, 4); 147 sja1105_unpack(p + 0x8, &status->n_polerr, 31, 0, 4); 148 sja1105_unpack(p + 0x7, &status->n_rxfrmsh, 31, 0, 4); 149 sja1105_unpack(p + 0x6, &status->n_rxfrm, 31, 0, 4); 150 sja1105_unpack(p + 0x5, &status->n_rxbytesh, 31, 0, 4); 151 sja1105_unpack(p + 0x4, &status->n_rxbyte, 31, 0, 4); 152 sja1105_unpack(p + 0x3, &status->n_txfrmsh, 31, 0, 4); 153 sja1105_unpack(p + 0x2, &status->n_txfrm, 31, 0, 4); 154 sja1105_unpack(p + 0x1, &status->n_txbytesh, 31, 0, 4); 155 sja1105_unpack(p + 0x0, &status->n_txbyte, 31, 0, 4); 156 status->n_rxfrm += status->n_rxfrmsh << 32; 157 status->n_rxbyte += status->n_rxbytesh << 32; 158 status->n_txfrm += status->n_txfrmsh << 32; 159 status->n_txbyte += status->n_txbytesh << 32; 160 } 161 162 static void 163 sja1105_port_status_hl2_unpack(void *buf, 164 struct sja1105_port_status_hl2 *status) 165 { 166 /* Make pointer arithmetic work on 4 bytes */ 167 u32 *p = buf; 168 169 sja1105_unpack(p + 0x3, &status->n_qfull, 31, 0, 4); 170 sja1105_unpack(p + 0x2, &status->n_part_drop, 31, 0, 4); 171 sja1105_unpack(p + 0x1, &status->n_egr_disabled, 31, 0, 4); 172 sja1105_unpack(p + 0x0, &status->n_not_reach, 31, 0, 4); 173 } 174 175 static void 176 sja1105pqrs_port_status_qlevel_unpack(void *buf, 177 struct sja1105_port_status_hl2 *status) 178 { 179 /* Make pointer arithmetic work on 4 bytes */ 180 u32 *p = buf; 181 int i; 182 183 for (i = 0; i < 8; i++) { 184 sja1105_unpack(p + i, &status->qlevel_hwm[i], 24, 16, 4); 185 sja1105_unpack(p + i, &status->qlevel[i], 8, 0, 4); 186 } 187 } 188 189 static void 190 sja1105pqrs_port_status_ether_unpack(void *buf, 191 struct sja1105_port_status_ether *status) 192 { 193 /* Make pointer arithmetic work on 4 bytes */ 194 u32 *p = buf; 195 196 sja1105_unpack(p + 0x16, &status->n_drops_nolearn, 31, 0, 4); 197 sja1105_unpack(p + 0x15, &status->n_drops_noroute, 31, 0, 4); 198 sja1105_unpack(p + 0x14, &status->n_drops_ill_dtag, 31, 0, 4); 199 sja1105_unpack(p + 0x13, &status->n_drops_dtag, 31, 0, 4); 200 sja1105_unpack(p + 0x12, &status->n_drops_sotag, 31, 0, 4); 201 sja1105_unpack(p + 0x11, &status->n_drops_sitag, 31, 0, 4); 202 sja1105_unpack(p + 0x10, &status->n_drops_utag, 31, 0, 4); 203 sja1105_unpack(p + 0x0F, &status->n_tx_bytes_1024_2047, 31, 0, 4); 204 sja1105_unpack(p + 0x0E, &status->n_tx_bytes_512_1023, 31, 0, 4); 205 sja1105_unpack(p + 0x0D, &status->n_tx_bytes_256_511, 31, 0, 4); 206 sja1105_unpack(p + 0x0C, &status->n_tx_bytes_128_255, 31, 0, 4); 207 sja1105_unpack(p + 0x0B, &status->n_tx_bytes_65_127, 31, 0, 4); 208 sja1105_unpack(p + 0x0A, &status->n_tx_bytes_64, 31, 0, 4); 209 sja1105_unpack(p + 0x09, &status->n_tx_mcast, 31, 0, 4); 210 sja1105_unpack(p + 0x08, &status->n_tx_bcast, 31, 0, 4); 211 sja1105_unpack(p + 0x07, &status->n_rx_bytes_1024_2047, 31, 0, 4); 212 sja1105_unpack(p + 0x06, &status->n_rx_bytes_512_1023, 31, 0, 4); 213 sja1105_unpack(p + 0x05, &status->n_rx_bytes_256_511, 31, 0, 4); 214 sja1105_unpack(p + 0x04, &status->n_rx_bytes_128_255, 31, 0, 4); 215 sja1105_unpack(p + 0x03, &status->n_rx_bytes_65_127, 31, 0, 4); 216 sja1105_unpack(p + 0x02, &status->n_rx_bytes_64, 31, 0, 4); 217 sja1105_unpack(p + 0x01, &status->n_rx_mcast, 31, 0, 4); 218 sja1105_unpack(p + 0x00, &status->n_rx_bcast, 31, 0, 4); 219 } 220 221 static int 222 sja1105pqrs_port_status_get_ether(struct sja1105_private *priv, 223 struct sja1105_port_status_ether *ether, 224 int port) 225 { 226 const struct sja1105_regs *regs = priv->info->regs; 227 u8 packed_buf[SJA1105_SIZE_ETHER_AREA] = {0}; 228 int rc; 229 230 /* Ethernet statistics area */ 231 rc = sja1105_xfer_buf(priv, SPI_READ, regs->ether_stats[port], 232 packed_buf, SJA1105_SIZE_ETHER_AREA); 233 if (rc < 0) 234 return rc; 235 236 sja1105pqrs_port_status_ether_unpack(packed_buf, ether); 237 238 return 0; 239 } 240 241 static int sja1105_port_status_get_mac(struct sja1105_private *priv, 242 struct sja1105_port_status_mac *status, 243 int port) 244 { 245 const struct sja1105_regs *regs = priv->info->regs; 246 u8 packed_buf[SJA1105_SIZE_MAC_AREA] = {0}; 247 int rc; 248 249 /* MAC area */ 250 rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac[port], packed_buf, 251 SJA1105_SIZE_MAC_AREA); 252 if (rc < 0) 253 return rc; 254 255 sja1105_port_status_mac_unpack(packed_buf, status); 256 257 return 0; 258 } 259 260 static int sja1105_port_status_get_hl1(struct sja1105_private *priv, 261 struct sja1105_port_status_hl1 *status, 262 int port) 263 { 264 const struct sja1105_regs *regs = priv->info->regs; 265 u8 packed_buf[SJA1105_SIZE_HL1_AREA] = {0}; 266 int rc; 267 268 rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac_hl1[port], packed_buf, 269 SJA1105_SIZE_HL1_AREA); 270 if (rc < 0) 271 return rc; 272 273 sja1105_port_status_hl1_unpack(packed_buf, status); 274 275 return 0; 276 } 277 278 static int sja1105_port_status_get_hl2(struct sja1105_private *priv, 279 struct sja1105_port_status_hl2 *status, 280 int port) 281 { 282 const struct sja1105_regs *regs = priv->info->regs; 283 u8 packed_buf[SJA1105_SIZE_QLEVEL_AREA] = {0}; 284 int rc; 285 286 rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac_hl2[port], packed_buf, 287 SJA1105_SIZE_HL2_AREA); 288 if (rc < 0) 289 return rc; 290 291 sja1105_port_status_hl2_unpack(packed_buf, status); 292 293 /* Code below is strictly P/Q/R/S specific. */ 294 if (priv->info->device_id == SJA1105E_DEVICE_ID || 295 priv->info->device_id == SJA1105T_DEVICE_ID) 296 return 0; 297 298 rc = sja1105_xfer_buf(priv, SPI_READ, regs->qlevel[port], packed_buf, 299 SJA1105_SIZE_QLEVEL_AREA); 300 if (rc < 0) 301 return rc; 302 303 sja1105pqrs_port_status_qlevel_unpack(packed_buf, status); 304 305 return 0; 306 } 307 308 static int sja1105_port_status_get(struct sja1105_private *priv, 309 struct sja1105_port_status *status, 310 int port) 311 { 312 int rc; 313 314 rc = sja1105_port_status_get_mac(priv, &status->mac, port); 315 if (rc < 0) 316 return rc; 317 rc = sja1105_port_status_get_hl1(priv, &status->hl1, port); 318 if (rc < 0) 319 return rc; 320 rc = sja1105_port_status_get_hl2(priv, &status->hl2, port); 321 if (rc < 0) 322 return rc; 323 324 if (priv->info->device_id == SJA1105E_DEVICE_ID || 325 priv->info->device_id == SJA1105T_DEVICE_ID) 326 return 0; 327 328 return sja1105pqrs_port_status_get_ether(priv, &status->ether, port); 329 } 330 331 static char sja1105_port_stats[][ETH_GSTRING_LEN] = { 332 /* MAC-Level Diagnostic Counters */ 333 "n_runt", 334 "n_soferr", 335 "n_alignerr", 336 "n_miierr", 337 /* MAC-Level Diagnostic Flags */ 338 "typeerr", 339 "sizeerr", 340 "tctimeout", 341 "priorerr", 342 "nomaster", 343 "memov", 344 "memerr", 345 "invtyp", 346 "intcyov", 347 "domerr", 348 "pcfbagdrop", 349 "spcprior", 350 "ageprior", 351 "portdrop", 352 "lendrop", 353 "bagdrop", 354 "policeerr", 355 "drpnona664err", 356 "spcerr", 357 "agedrp", 358 /* High-Level Diagnostic Counters */ 359 "n_n664err", 360 "n_vlanerr", 361 "n_unreleased", 362 "n_sizeerr", 363 "n_crcerr", 364 "n_vlnotfound", 365 "n_ctpolerr", 366 "n_polerr", 367 "n_rxfrm", 368 "n_rxbyte", 369 "n_txfrm", 370 "n_txbyte", 371 "n_qfull", 372 "n_part_drop", 373 "n_egr_disabled", 374 "n_not_reach", 375 }; 376 377 static char sja1105pqrs_extra_port_stats[][ETH_GSTRING_LEN] = { 378 /* Queue Levels */ 379 "qlevel_hwm_0", 380 "qlevel_hwm_1", 381 "qlevel_hwm_2", 382 "qlevel_hwm_3", 383 "qlevel_hwm_4", 384 "qlevel_hwm_5", 385 "qlevel_hwm_6", 386 "qlevel_hwm_7", 387 "qlevel_0", 388 "qlevel_1", 389 "qlevel_2", 390 "qlevel_3", 391 "qlevel_4", 392 "qlevel_5", 393 "qlevel_6", 394 "qlevel_7", 395 /* Ether Stats */ 396 "n_drops_nolearn", 397 "n_drops_noroute", 398 "n_drops_ill_dtag", 399 "n_drops_dtag", 400 "n_drops_sotag", 401 "n_drops_sitag", 402 "n_drops_utag", 403 "n_tx_bytes_1024_2047", 404 "n_tx_bytes_512_1023", 405 "n_tx_bytes_256_511", 406 "n_tx_bytes_128_255", 407 "n_tx_bytes_65_127", 408 "n_tx_bytes_64", 409 "n_tx_mcast", 410 "n_tx_bcast", 411 "n_rx_bytes_1024_2047", 412 "n_rx_bytes_512_1023", 413 "n_rx_bytes_256_511", 414 "n_rx_bytes_128_255", 415 "n_rx_bytes_65_127", 416 "n_rx_bytes_64", 417 "n_rx_mcast", 418 "n_rx_bcast", 419 }; 420 421 void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) 422 { 423 struct sja1105_private *priv = ds->priv; 424 struct sja1105_port_status status; 425 int rc, i, k = 0; 426 427 memset(&status, 0, sizeof(status)); 428 429 rc = sja1105_port_status_get(priv, &status, port); 430 if (rc < 0) { 431 dev_err(ds->dev, "Failed to read port %d counters: %d\n", 432 port, rc); 433 return; 434 } 435 memset(data, 0, ARRAY_SIZE(sja1105_port_stats) * sizeof(u64)); 436 data[k++] = status.mac.n_runt; 437 data[k++] = status.mac.n_soferr; 438 data[k++] = status.mac.n_alignerr; 439 data[k++] = status.mac.n_miierr; 440 data[k++] = status.mac.typeerr; 441 data[k++] = status.mac.sizeerr; 442 data[k++] = status.mac.tctimeout; 443 data[k++] = status.mac.priorerr; 444 data[k++] = status.mac.nomaster; 445 data[k++] = status.mac.memov; 446 data[k++] = status.mac.memerr; 447 data[k++] = status.mac.invtyp; 448 data[k++] = status.mac.intcyov; 449 data[k++] = status.mac.domerr; 450 data[k++] = status.mac.pcfbagdrop; 451 data[k++] = status.mac.spcprior; 452 data[k++] = status.mac.ageprior; 453 data[k++] = status.mac.portdrop; 454 data[k++] = status.mac.lendrop; 455 data[k++] = status.mac.bagdrop; 456 data[k++] = status.mac.policeerr; 457 data[k++] = status.mac.drpnona664err; 458 data[k++] = status.mac.spcerr; 459 data[k++] = status.mac.agedrp; 460 data[k++] = status.hl1.n_n664err; 461 data[k++] = status.hl1.n_vlanerr; 462 data[k++] = status.hl1.n_unreleased; 463 data[k++] = status.hl1.n_sizeerr; 464 data[k++] = status.hl1.n_crcerr; 465 data[k++] = status.hl1.n_vlnotfound; 466 data[k++] = status.hl1.n_ctpolerr; 467 data[k++] = status.hl1.n_polerr; 468 data[k++] = status.hl1.n_rxfrm; 469 data[k++] = status.hl1.n_rxbyte; 470 data[k++] = status.hl1.n_txfrm; 471 data[k++] = status.hl1.n_txbyte; 472 data[k++] = status.hl2.n_qfull; 473 data[k++] = status.hl2.n_part_drop; 474 data[k++] = status.hl2.n_egr_disabled; 475 data[k++] = status.hl2.n_not_reach; 476 477 if (priv->info->device_id == SJA1105E_DEVICE_ID || 478 priv->info->device_id == SJA1105T_DEVICE_ID) 479 return; 480 481 memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) * 482 sizeof(u64)); 483 for (i = 0; i < 8; i++) { 484 data[k++] = status.hl2.qlevel_hwm[i]; 485 data[k++] = status.hl2.qlevel[i]; 486 } 487 data[k++] = status.ether.n_drops_nolearn; 488 data[k++] = status.ether.n_drops_noroute; 489 data[k++] = status.ether.n_drops_ill_dtag; 490 data[k++] = status.ether.n_drops_dtag; 491 data[k++] = status.ether.n_drops_sotag; 492 data[k++] = status.ether.n_drops_sitag; 493 data[k++] = status.ether.n_drops_utag; 494 data[k++] = status.ether.n_tx_bytes_1024_2047; 495 data[k++] = status.ether.n_tx_bytes_512_1023; 496 data[k++] = status.ether.n_tx_bytes_256_511; 497 data[k++] = status.ether.n_tx_bytes_128_255; 498 data[k++] = status.ether.n_tx_bytes_65_127; 499 data[k++] = status.ether.n_tx_bytes_64; 500 data[k++] = status.ether.n_tx_mcast; 501 data[k++] = status.ether.n_tx_bcast; 502 data[k++] = status.ether.n_rx_bytes_1024_2047; 503 data[k++] = status.ether.n_rx_bytes_512_1023; 504 data[k++] = status.ether.n_rx_bytes_256_511; 505 data[k++] = status.ether.n_rx_bytes_128_255; 506 data[k++] = status.ether.n_rx_bytes_65_127; 507 data[k++] = status.ether.n_rx_bytes_64; 508 data[k++] = status.ether.n_rx_mcast; 509 data[k++] = status.ether.n_rx_bcast; 510 } 511 512 void sja1105_get_strings(struct dsa_switch *ds, int port, 513 u32 stringset, u8 *data) 514 { 515 struct sja1105_private *priv = ds->priv; 516 u8 *p = data; 517 int i; 518 519 switch (stringset) { 520 case ETH_SS_STATS: 521 for (i = 0; i < ARRAY_SIZE(sja1105_port_stats); i++) { 522 strlcpy(p, sja1105_port_stats[i], ETH_GSTRING_LEN); 523 p += ETH_GSTRING_LEN; 524 } 525 if (priv->info->device_id == SJA1105E_DEVICE_ID || 526 priv->info->device_id == SJA1105T_DEVICE_ID) 527 return; 528 for (i = 0; i < ARRAY_SIZE(sja1105pqrs_extra_port_stats); i++) { 529 strlcpy(p, sja1105pqrs_extra_port_stats[i], 530 ETH_GSTRING_LEN); 531 p += ETH_GSTRING_LEN; 532 } 533 break; 534 } 535 } 536 537 int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset) 538 { 539 int count = ARRAY_SIZE(sja1105_port_stats); 540 struct sja1105_private *priv = ds->priv; 541 542 if (sset != ETH_SS_STATS) 543 return -EOPNOTSUPP; 544 545 if (priv->info->device_id == SJA1105PR_DEVICE_ID || 546 priv->info->device_id == SJA1105QS_DEVICE_ID) 547 count += ARRAY_SIZE(sja1105pqrs_extra_port_stats); 548 549 return count; 550 } 551