1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 4 */ 5 6 /* PPE debugfs routines for display of PPE counters useful for debug. */ 7 8 #include <linux/bitfield.h> 9 #include <linux/debugfs.h> 10 #include <linux/dev_printk.h> 11 #include <linux/device.h> 12 #include <linux/regmap.h> 13 #include <linux/seq_file.h> 14 15 #include "ppe.h" 16 #include "ppe_config.h" 17 #include "ppe_debugfs.h" 18 #include "ppe_regs.h" 19 20 #define PPE_PKT_CNT_TBL_SIZE 3 21 #define PPE_DROP_PKT_CNT_TBL_SIZE 5 22 23 #define PPE_W0_PKT_CNT GENMASK(31, 0) 24 #define PPE_W2_DROP_PKT_CNT_LOW GENMASK(31, 8) 25 #define PPE_W3_DROP_PKT_CNT_HIGH GENMASK(7, 0) 26 27 #define PPE_GET_PKT_CNT(tbl_cnt) \ 28 FIELD_GET(PPE_W0_PKT_CNT, *(tbl_cnt)) 29 #define PPE_GET_DROP_PKT_CNT_LOW(tbl_cnt) \ 30 FIELD_GET(PPE_W2_DROP_PKT_CNT_LOW, *((tbl_cnt) + 0x2)) 31 #define PPE_GET_DROP_PKT_CNT_HIGH(tbl_cnt) \ 32 FIELD_GET(PPE_W3_DROP_PKT_CNT_HIGH, *((tbl_cnt) + 0x3)) 33 34 /** 35 * enum ppe_cnt_size_type - PPE counter size type 36 * @PPE_PKT_CNT_SIZE_1WORD: Counter size with single register 37 * @PPE_PKT_CNT_SIZE_3WORD: Counter size with table of 3 words 38 * @PPE_PKT_CNT_SIZE_5WORD: Counter size with table of 5 words 39 * 40 * PPE takes the different register size to record the packet counters. 41 * It uses single register, or register table with 3 words or 5 words. 42 * The counter with table size 5 words also records the drop counter. 43 * There are also some other counter types occupying sizes less than 32 44 * bits, which is not covered by this enumeration type. 45 */ 46 enum ppe_cnt_size_type { 47 PPE_PKT_CNT_SIZE_1WORD, 48 PPE_PKT_CNT_SIZE_3WORD, 49 PPE_PKT_CNT_SIZE_5WORD, 50 }; 51 52 /** 53 * enum ppe_cnt_type - PPE counter type. 54 * @PPE_CNT_BM: Packet counter processed by BM. 55 * @PPE_CNT_PARSE: Packet counter parsed on ingress. 56 * @PPE_CNT_PORT_RX: Packet counter on the ingress port. 57 * @PPE_CNT_VLAN_RX: VLAN packet counter received. 58 * @PPE_CNT_L2_FWD: Packet counter processed by L2 forwarding. 59 * @PPE_CNT_CPU_CODE: Packet counter marked with various CPU codes. 60 * @PPE_CNT_VLAN_TX: VLAN packet counter transmitted. 61 * @PPE_CNT_PORT_TX: Packet counter on the egress port. 62 * @PPE_CNT_QM: Packet counter processed by QM. 63 */ 64 enum ppe_cnt_type { 65 PPE_CNT_BM, 66 PPE_CNT_PARSE, 67 PPE_CNT_PORT_RX, 68 PPE_CNT_VLAN_RX, 69 PPE_CNT_L2_FWD, 70 PPE_CNT_CPU_CODE, 71 PPE_CNT_VLAN_TX, 72 PPE_CNT_PORT_TX, 73 PPE_CNT_QM, 74 }; 75 76 /** 77 * struct ppe_debugfs_entry - PPE debugfs entry. 78 * @name: Debugfs file name. 79 * @counter_type: PPE packet counter type. 80 * @ppe: PPE device. 81 * 82 * The PPE debugfs entry is used to create the debugfs file and passed 83 * to debugfs_create_file() as private data. 84 */ 85 struct ppe_debugfs_entry { 86 const char *name; 87 enum ppe_cnt_type counter_type; 88 struct ppe_device *ppe; 89 }; 90 91 static const struct ppe_debugfs_entry debugfs_files[] = { 92 { 93 .name = "bm", 94 .counter_type = PPE_CNT_BM, 95 }, 96 { 97 .name = "parse", 98 .counter_type = PPE_CNT_PARSE, 99 }, 100 { 101 .name = "port_rx", 102 .counter_type = PPE_CNT_PORT_RX, 103 }, 104 { 105 .name = "vlan_rx", 106 .counter_type = PPE_CNT_VLAN_RX, 107 }, 108 { 109 .name = "l2_forward", 110 .counter_type = PPE_CNT_L2_FWD, 111 }, 112 { 113 .name = "cpu_code", 114 .counter_type = PPE_CNT_CPU_CODE, 115 }, 116 { 117 .name = "vlan_tx", 118 .counter_type = PPE_CNT_VLAN_TX, 119 }, 120 { 121 .name = "port_tx", 122 .counter_type = PPE_CNT_PORT_TX, 123 }, 124 { 125 .name = "qm", 126 .counter_type = PPE_CNT_QM, 127 }, 128 }; 129 130 static int ppe_pkt_cnt_get(struct ppe_device *ppe_dev, u32 reg, 131 enum ppe_cnt_size_type cnt_type, 132 u32 *cnt, u32 *drop_cnt) 133 { 134 u32 drop_pkt_cnt[PPE_DROP_PKT_CNT_TBL_SIZE]; 135 u32 pkt_cnt[PPE_PKT_CNT_TBL_SIZE]; 136 u32 value; 137 int ret; 138 139 switch (cnt_type) { 140 case PPE_PKT_CNT_SIZE_1WORD: 141 ret = regmap_read(ppe_dev->regmap, reg, &value); 142 if (ret) 143 return ret; 144 145 *cnt = value; 146 break; 147 case PPE_PKT_CNT_SIZE_3WORD: 148 ret = regmap_bulk_read(ppe_dev->regmap, reg, 149 pkt_cnt, ARRAY_SIZE(pkt_cnt)); 150 if (ret) 151 return ret; 152 153 *cnt = PPE_GET_PKT_CNT(pkt_cnt); 154 break; 155 case PPE_PKT_CNT_SIZE_5WORD: 156 ret = regmap_bulk_read(ppe_dev->regmap, reg, 157 drop_pkt_cnt, ARRAY_SIZE(drop_pkt_cnt)); 158 if (ret) 159 return ret; 160 161 *cnt = PPE_GET_PKT_CNT(drop_pkt_cnt); 162 163 /* Drop counter with low 24 bits. */ 164 value = PPE_GET_DROP_PKT_CNT_LOW(drop_pkt_cnt); 165 *drop_cnt = FIELD_PREP(GENMASK(23, 0), value); 166 167 /* Drop counter with high 8 bits. */ 168 value = PPE_GET_DROP_PKT_CNT_HIGH(drop_pkt_cnt); 169 *drop_cnt |= FIELD_PREP(GENMASK(31, 24), value); 170 break; 171 } 172 173 return 0; 174 } 175 176 static void ppe_tbl_pkt_cnt_clear(struct ppe_device *ppe_dev, u32 reg, 177 enum ppe_cnt_size_type cnt_type) 178 { 179 u32 drop_pkt_cnt[PPE_DROP_PKT_CNT_TBL_SIZE] = {}; 180 u32 pkt_cnt[PPE_PKT_CNT_TBL_SIZE] = {}; 181 182 switch (cnt_type) { 183 case PPE_PKT_CNT_SIZE_1WORD: 184 regmap_write(ppe_dev->regmap, reg, 0); 185 break; 186 case PPE_PKT_CNT_SIZE_3WORD: 187 regmap_bulk_write(ppe_dev->regmap, reg, 188 pkt_cnt, ARRAY_SIZE(pkt_cnt)); 189 break; 190 case PPE_PKT_CNT_SIZE_5WORD: 191 regmap_bulk_write(ppe_dev->regmap, reg, 192 drop_pkt_cnt, ARRAY_SIZE(drop_pkt_cnt)); 193 break; 194 } 195 } 196 197 static int ppe_bm_counter_get(struct ppe_device *ppe_dev, struct seq_file *seq) 198 { 199 u32 reg, val, pkt_cnt, pkt_cnt1; 200 int ret, i, tag; 201 202 seq_printf(seq, "%-24s", "BM SILENT_DROP:"); 203 tag = 0; 204 for (i = 0; i < PPE_DROP_CNT_TBL_ENTRIES; i++) { 205 reg = PPE_DROP_CNT_TBL_ADDR + i * PPE_DROP_CNT_TBL_INC; 206 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD, 207 &pkt_cnt, NULL); 208 if (ret) { 209 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 210 return ret; 211 } 212 213 if (pkt_cnt > 0) { 214 if (!((++tag) % 4)) 215 seq_printf(seq, "\n%-24s", ""); 216 217 seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "port", i); 218 } 219 } 220 221 seq_putc(seq, '\n'); 222 223 /* The number of packets dropped because hardware buffers were 224 * available only partially for the packet. 225 */ 226 seq_printf(seq, "%-24s", "BM OVERFLOW_DROP:"); 227 tag = 0; 228 for (i = 0; i < PPE_DROP_STAT_TBL_ENTRIES; i++) { 229 reg = PPE_DROP_STAT_TBL_ADDR + PPE_DROP_STAT_TBL_INC * i; 230 231 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 232 &pkt_cnt, NULL); 233 if (ret) { 234 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 235 return ret; 236 } 237 238 if (pkt_cnt > 0) { 239 if (!((++tag) % 4)) 240 seq_printf(seq, "\n%-24s", ""); 241 242 seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "port", i); 243 } 244 } 245 246 seq_putc(seq, '\n'); 247 248 /* The number of currently occupied buffers, that can't be flushed. */ 249 seq_printf(seq, "%-24s", "BM USED/REACT:"); 250 tag = 0; 251 for (i = 0; i < PPE_BM_USED_CNT_TBL_ENTRIES; i++) { 252 reg = PPE_BM_USED_CNT_TBL_ADDR + i * PPE_BM_USED_CNT_TBL_INC; 253 ret = regmap_read(ppe_dev->regmap, reg, &val); 254 if (ret) { 255 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 256 return ret; 257 } 258 259 /* The number of PPE buffers used for caching the received 260 * packets before the pause frame sent. 261 */ 262 pkt_cnt = FIELD_GET(PPE_BM_USED_CNT_VAL, val); 263 264 reg = PPE_BM_REACT_CNT_TBL_ADDR + i * PPE_BM_REACT_CNT_TBL_INC; 265 ret = regmap_read(ppe_dev->regmap, reg, &val); 266 if (ret) { 267 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 268 return ret; 269 } 270 271 /* The number of PPE buffers used for caching the received 272 * packets after pause frame sent out. 273 */ 274 pkt_cnt1 = FIELD_GET(PPE_BM_REACT_CNT_VAL, val); 275 276 if (pkt_cnt > 0 || pkt_cnt1 > 0) { 277 if (!((++tag) % 4)) 278 seq_printf(seq, "\n%-24s", ""); 279 280 seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, pkt_cnt1, 281 "port", i); 282 } 283 } 284 285 seq_putc(seq, '\n'); 286 287 return 0; 288 } 289 290 /* The number of packets processed by the ingress parser module of PPE. */ 291 static int ppe_parse_pkt_counter_get(struct ppe_device *ppe_dev, 292 struct seq_file *seq) 293 { 294 u32 reg, cnt = 0, tunnel_cnt = 0; 295 int i, ret, tag = 0; 296 297 seq_printf(seq, "%-24s", "PARSE TPRX/IPRX:"); 298 for (i = 0; i < PPE_IPR_PKT_CNT_TBL_ENTRIES; i++) { 299 reg = PPE_TPR_PKT_CNT_TBL_ADDR + i * PPE_TPR_PKT_CNT_TBL_INC; 300 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD, 301 &tunnel_cnt, NULL); 302 if (ret) { 303 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 304 return ret; 305 } 306 307 reg = PPE_IPR_PKT_CNT_TBL_ADDR + i * PPE_IPR_PKT_CNT_TBL_INC; 308 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD, 309 &cnt, NULL); 310 if (ret) { 311 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 312 return ret; 313 } 314 315 if (tunnel_cnt > 0 || cnt > 0) { 316 if (!((++tag) % 4)) 317 seq_printf(seq, "\n%-24s", ""); 318 319 seq_printf(seq, "%10u/%u(%s=%04d)", tunnel_cnt, cnt, 320 "port", i); 321 } 322 } 323 324 seq_putc(seq, '\n'); 325 326 return 0; 327 } 328 329 /* The number of packets received or dropped on the ingress port. */ 330 static int ppe_port_rx_counter_get(struct ppe_device *ppe_dev, 331 struct seq_file *seq) 332 { 333 u32 reg, pkt_cnt = 0, drop_cnt = 0; 334 int ret, i, tag; 335 336 seq_printf(seq, "%-24s", "PORT RX/RX_DROP:"); 337 tag = 0; 338 for (i = 0; i < PPE_PHY_PORT_RX_CNT_TBL_ENTRIES; i++) { 339 reg = PPE_PHY_PORT_RX_CNT_TBL_ADDR + PPE_PHY_PORT_RX_CNT_TBL_INC * i; 340 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD, 341 &pkt_cnt, &drop_cnt); 342 if (ret) { 343 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 344 return ret; 345 } 346 347 if (pkt_cnt > 0) { 348 if (!((++tag) % 4)) 349 seq_printf(seq, "\n%-24s", ""); 350 351 seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt, 352 "port", i); 353 } 354 } 355 356 seq_putc(seq, '\n'); 357 358 seq_printf(seq, "%-24s", "VPORT RX/RX_DROP:"); 359 tag = 0; 360 for (i = 0; i < PPE_PORT_RX_CNT_TBL_ENTRIES; i++) { 361 reg = PPE_PORT_RX_CNT_TBL_ADDR + PPE_PORT_RX_CNT_TBL_INC * i; 362 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD, 363 &pkt_cnt, &drop_cnt); 364 if (ret) { 365 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 366 return ret; 367 } 368 369 if (pkt_cnt > 0) { 370 if (!((++tag) % 4)) 371 seq_printf(seq, "\n%-24s", ""); 372 373 seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt, 374 "port", i); 375 } 376 } 377 378 seq_putc(seq, '\n'); 379 380 return 0; 381 } 382 383 /* The number of packets received or dropped by layer 2 processing. */ 384 static int ppe_l2_counter_get(struct ppe_device *ppe_dev, 385 struct seq_file *seq) 386 { 387 u32 reg, pkt_cnt = 0, drop_cnt = 0; 388 int ret, i, tag = 0; 389 390 seq_printf(seq, "%-24s", "L2 RX/RX_DROP:"); 391 for (i = 0; i < PPE_PRE_L2_CNT_TBL_ENTRIES; i++) { 392 reg = PPE_PRE_L2_CNT_TBL_ADDR + PPE_PRE_L2_CNT_TBL_INC * i; 393 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD, 394 &pkt_cnt, &drop_cnt); 395 if (ret) { 396 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 397 return ret; 398 } 399 400 if (pkt_cnt > 0) { 401 if (!((++tag) % 4)) 402 seq_printf(seq, "\n%-24s", ""); 403 404 seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt, 405 "vsi", i); 406 } 407 } 408 409 seq_putc(seq, '\n'); 410 411 return 0; 412 } 413 414 /* The number of VLAN packets received by PPE. */ 415 static int ppe_vlan_rx_counter_get(struct ppe_device *ppe_dev, 416 struct seq_file *seq) 417 { 418 u32 reg, pkt_cnt = 0; 419 int ret, i, tag = 0; 420 421 seq_printf(seq, "%-24s", "VLAN RX:"); 422 for (i = 0; i < PPE_VLAN_CNT_TBL_ENTRIES; i++) { 423 reg = PPE_VLAN_CNT_TBL_ADDR + PPE_VLAN_CNT_TBL_INC * i; 424 425 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 426 &pkt_cnt, NULL); 427 if (ret) { 428 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 429 return ret; 430 } 431 432 if (pkt_cnt > 0) { 433 if (!((++tag) % 4)) 434 seq_printf(seq, "\n%-24s", ""); 435 436 seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "vsi", i); 437 } 438 } 439 440 seq_putc(seq, '\n'); 441 442 return 0; 443 } 444 445 /* The number of packets handed to CPU by PPE. */ 446 static int ppe_cpu_code_counter_get(struct ppe_device *ppe_dev, 447 struct seq_file *seq) 448 { 449 u32 reg, pkt_cnt = 0; 450 int ret, i; 451 452 seq_printf(seq, "%-24s", "CPU CODE:"); 453 for (i = 0; i < PPE_DROP_CPU_CNT_TBL_ENTRIES; i++) { 454 reg = PPE_DROP_CPU_CNT_TBL_ADDR + PPE_DROP_CPU_CNT_TBL_INC * i; 455 456 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 457 &pkt_cnt, NULL); 458 if (ret) { 459 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 460 return ret; 461 } 462 463 if (!pkt_cnt) 464 continue; 465 466 /* There are 256 CPU codes saved in the first 256 entries 467 * of register table, and 128 drop codes for each PPE port 468 * (0-7), the total entries is 256 + 8 * 128. 469 */ 470 if (i < 256) 471 seq_printf(seq, "%10u(cpucode:%d)", pkt_cnt, i); 472 else 473 seq_printf(seq, "%10u(port=%04d),dropcode:%d", pkt_cnt, 474 (i - 256) % 8, (i - 256) / 8); 475 seq_putc(seq, '\n'); 476 seq_printf(seq, "%-24s", ""); 477 } 478 479 seq_putc(seq, '\n'); 480 481 return 0; 482 } 483 484 /* The number of packets forwarded by VLAN on the egress direction. */ 485 static int ppe_vlan_tx_counter_get(struct ppe_device *ppe_dev, 486 struct seq_file *seq) 487 { 488 u32 reg, pkt_cnt = 0; 489 int ret, i, tag = 0; 490 491 seq_printf(seq, "%-24s", "VLAN TX:"); 492 for (i = 0; i < PPE_EG_VSI_COUNTER_TBL_ENTRIES; i++) { 493 reg = PPE_EG_VSI_COUNTER_TBL_ADDR + PPE_EG_VSI_COUNTER_TBL_INC * i; 494 495 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 496 &pkt_cnt, NULL); 497 if (ret) { 498 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 499 return ret; 500 } 501 502 if (pkt_cnt > 0) { 503 if (!((++tag) % 4)) 504 seq_printf(seq, "\n%-24s", ""); 505 506 seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "vsi", i); 507 } 508 } 509 510 seq_putc(seq, '\n'); 511 512 return 0; 513 } 514 515 /* The number of packets transmitted or dropped on the egress port. */ 516 static int ppe_port_tx_counter_get(struct ppe_device *ppe_dev, 517 struct seq_file *seq) 518 { 519 u32 reg, pkt_cnt = 0, drop_cnt = 0; 520 int ret, i, tag; 521 522 seq_printf(seq, "%-24s", "VPORT TX/TX_DROP:"); 523 tag = 0; 524 for (i = 0; i < PPE_VPORT_TX_COUNTER_TBL_ENTRIES; i++) { 525 reg = PPE_VPORT_TX_COUNTER_TBL_ADDR + PPE_VPORT_TX_COUNTER_TBL_INC * i; 526 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 527 &pkt_cnt, NULL); 528 if (ret) { 529 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 530 return ret; 531 } 532 533 reg = PPE_VPORT_TX_DROP_CNT_TBL_ADDR + PPE_VPORT_TX_DROP_CNT_TBL_INC * i; 534 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 535 &drop_cnt, NULL); 536 if (ret) { 537 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 538 return ret; 539 } 540 541 if (pkt_cnt > 0 || drop_cnt > 0) { 542 if (!((++tag) % 4)) 543 seq_printf(seq, "\n%-24s", ""); 544 545 seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt, 546 "port", i); 547 } 548 } 549 550 seq_putc(seq, '\n'); 551 552 seq_printf(seq, "%-24s", "PORT TX/TX_DROP:"); 553 tag = 0; 554 for (i = 0; i < PPE_PORT_TX_COUNTER_TBL_ENTRIES; i++) { 555 reg = PPE_PORT_TX_COUNTER_TBL_ADDR + PPE_PORT_TX_COUNTER_TBL_INC * i; 556 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 557 &pkt_cnt, NULL); 558 if (ret) { 559 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 560 return ret; 561 } 562 563 reg = PPE_PORT_TX_DROP_CNT_TBL_ADDR + PPE_PORT_TX_DROP_CNT_TBL_INC * i; 564 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 565 &drop_cnt, NULL); 566 if (ret) { 567 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 568 return ret; 569 } 570 571 if (pkt_cnt > 0 || drop_cnt > 0) { 572 if (!((++tag) % 4)) 573 seq_printf(seq, "\n%-24s", ""); 574 575 seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt, 576 "port", i); 577 } 578 } 579 580 seq_putc(seq, '\n'); 581 582 return 0; 583 } 584 585 /* The number of packets transmitted or pending by the PPE queue. */ 586 static int ppe_queue_counter_get(struct ppe_device *ppe_dev, 587 struct seq_file *seq) 588 { 589 u32 reg, val, pkt_cnt = 0, pend_cnt = 0, drop_cnt = 0; 590 int ret, i, tag = 0; 591 592 seq_printf(seq, "%-24s", "QUEUE TX/PEND/DROP:"); 593 for (i = 0; i < PPE_QUEUE_TX_COUNTER_TBL_ENTRIES; i++) { 594 reg = PPE_QUEUE_TX_COUNTER_TBL_ADDR + PPE_QUEUE_TX_COUNTER_TBL_INC * i; 595 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 596 &pkt_cnt, NULL); 597 if (ret) { 598 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 599 return ret; 600 } 601 602 if (i < PPE_AC_UNICAST_QUEUE_CFG_TBL_ENTRIES) { 603 reg = PPE_AC_UNICAST_QUEUE_CNT_TBL_ADDR + 604 PPE_AC_UNICAST_QUEUE_CNT_TBL_INC * i; 605 ret = regmap_read(ppe_dev->regmap, reg, &val); 606 if (ret) { 607 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 608 return ret; 609 } 610 611 pend_cnt = FIELD_GET(PPE_AC_UNICAST_QUEUE_CNT_TBL_PEND_CNT, val); 612 613 reg = PPE_UNICAST_DROP_CNT_TBL_ADDR + 614 PPE_AC_UNICAST_QUEUE_CNT_TBL_INC * 615 (i * PPE_UNICAST_DROP_TYPES + PPE_UNICAST_DROP_FORCE_OFFSET); 616 617 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 618 &drop_cnt, NULL); 619 if (ret) { 620 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 621 return ret; 622 } 623 } else { 624 int mq_offset = i - PPE_AC_UNICAST_QUEUE_CFG_TBL_ENTRIES; 625 626 reg = PPE_AC_MULTICAST_QUEUE_CNT_TBL_ADDR + 627 PPE_AC_MULTICAST_QUEUE_CNT_TBL_INC * mq_offset; 628 ret = regmap_read(ppe_dev->regmap, reg, &val); 629 if (ret) { 630 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 631 return ret; 632 } 633 634 pend_cnt = FIELD_GET(PPE_AC_MULTICAST_QUEUE_CNT_TBL_PEND_CNT, val); 635 636 if (mq_offset < PPE_P0_MULTICAST_QUEUE_NUM) { 637 reg = PPE_CPU_PORT_MULTICAST_FORCE_DROP_CNT_TBL_ADDR(mq_offset); 638 } else { 639 mq_offset -= PPE_P0_MULTICAST_QUEUE_NUM; 640 641 reg = PPE_P1_MULTICAST_DROP_CNT_TBL_ADDR; 642 reg += (mq_offset / PPE_MULTICAST_QUEUE_NUM) * 643 PPE_MULTICAST_QUEUE_PORT_ADDR_INC; 644 reg += (mq_offset % PPE_MULTICAST_QUEUE_NUM) * 645 PPE_MULTICAST_DROP_CNT_TBL_INC * 646 PPE_MULTICAST_DROP_TYPES; 647 } 648 649 ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD, 650 &drop_cnt, NULL); 651 if (ret) { 652 dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret); 653 return ret; 654 } 655 } 656 657 if (pkt_cnt > 0 || pend_cnt > 0 || drop_cnt > 0) { 658 if (!((++tag) % 4)) 659 seq_printf(seq, "\n%-24s", ""); 660 661 seq_printf(seq, "%10u/%u/%u(%s=%04d)", 662 pkt_cnt, pend_cnt, drop_cnt, "queue", i); 663 } 664 } 665 666 seq_putc(seq, '\n'); 667 668 return 0; 669 } 670 671 /* Display the various packet counters of PPE. */ 672 static int ppe_packet_counter_show(struct seq_file *seq, void *v) 673 { 674 struct ppe_debugfs_entry *entry = seq->private; 675 struct ppe_device *ppe_dev = entry->ppe; 676 int ret; 677 678 switch (entry->counter_type) { 679 case PPE_CNT_BM: 680 ret = ppe_bm_counter_get(ppe_dev, seq); 681 break; 682 case PPE_CNT_PARSE: 683 ret = ppe_parse_pkt_counter_get(ppe_dev, seq); 684 break; 685 case PPE_CNT_PORT_RX: 686 ret = ppe_port_rx_counter_get(ppe_dev, seq); 687 break; 688 case PPE_CNT_VLAN_RX: 689 ret = ppe_vlan_rx_counter_get(ppe_dev, seq); 690 break; 691 case PPE_CNT_L2_FWD: 692 ret = ppe_l2_counter_get(ppe_dev, seq); 693 break; 694 case PPE_CNT_CPU_CODE: 695 ret = ppe_cpu_code_counter_get(ppe_dev, seq); 696 break; 697 case PPE_CNT_VLAN_TX: 698 ret = ppe_vlan_tx_counter_get(ppe_dev, seq); 699 break; 700 case PPE_CNT_PORT_TX: 701 ret = ppe_port_tx_counter_get(ppe_dev, seq); 702 break; 703 case PPE_CNT_QM: 704 ret = ppe_queue_counter_get(ppe_dev, seq); 705 break; 706 default: 707 ret = -EINVAL; 708 break; 709 } 710 711 return ret; 712 } 713 714 /* Flush the various packet counters of PPE. */ 715 static ssize_t ppe_packet_counter_write(struct file *file, 716 const char __user *buf, 717 size_t count, loff_t *pos) 718 { 719 struct ppe_debugfs_entry *entry = file_inode(file)->i_private; 720 struct ppe_device *ppe_dev = entry->ppe; 721 u32 reg; 722 int i; 723 724 switch (entry->counter_type) { 725 case PPE_CNT_BM: 726 for (i = 0; i < PPE_DROP_CNT_TBL_ENTRIES; i++) { 727 reg = PPE_DROP_CNT_TBL_ADDR + i * PPE_DROP_CNT_TBL_INC; 728 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD); 729 } 730 731 for (i = 0; i < PPE_DROP_STAT_TBL_ENTRIES; i++) { 732 reg = PPE_DROP_STAT_TBL_ADDR + PPE_DROP_STAT_TBL_INC * i; 733 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD); 734 } 735 736 break; 737 case PPE_CNT_PARSE: 738 for (i = 0; i < PPE_IPR_PKT_CNT_TBL_ENTRIES; i++) { 739 reg = PPE_IPR_PKT_CNT_TBL_ADDR + i * PPE_IPR_PKT_CNT_TBL_INC; 740 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD); 741 742 reg = PPE_TPR_PKT_CNT_TBL_ADDR + i * PPE_TPR_PKT_CNT_TBL_INC; 743 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD); 744 } 745 746 break; 747 case PPE_CNT_PORT_RX: 748 for (i = 0; i < PPE_PORT_RX_CNT_TBL_ENTRIES; i++) { 749 reg = PPE_PORT_RX_CNT_TBL_ADDR + PPE_PORT_RX_CNT_TBL_INC * i; 750 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD); 751 } 752 753 for (i = 0; i < PPE_PHY_PORT_RX_CNT_TBL_ENTRIES; i++) { 754 reg = PPE_PHY_PORT_RX_CNT_TBL_ADDR + PPE_PHY_PORT_RX_CNT_TBL_INC * i; 755 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD); 756 } 757 758 break; 759 case PPE_CNT_VLAN_RX: 760 for (i = 0; i < PPE_VLAN_CNT_TBL_ENTRIES; i++) { 761 reg = PPE_VLAN_CNT_TBL_ADDR + PPE_VLAN_CNT_TBL_INC * i; 762 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD); 763 } 764 765 break; 766 case PPE_CNT_L2_FWD: 767 for (i = 0; i < PPE_PRE_L2_CNT_TBL_ENTRIES; i++) { 768 reg = PPE_PRE_L2_CNT_TBL_ADDR + PPE_PRE_L2_CNT_TBL_INC * i; 769 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD); 770 } 771 772 break; 773 case PPE_CNT_CPU_CODE: 774 for (i = 0; i < PPE_DROP_CPU_CNT_TBL_ENTRIES; i++) { 775 reg = PPE_DROP_CPU_CNT_TBL_ADDR + PPE_DROP_CPU_CNT_TBL_INC * i; 776 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD); 777 } 778 779 break; 780 case PPE_CNT_VLAN_TX: 781 for (i = 0; i < PPE_EG_VSI_COUNTER_TBL_ENTRIES; i++) { 782 reg = PPE_EG_VSI_COUNTER_TBL_ADDR + PPE_EG_VSI_COUNTER_TBL_INC * i; 783 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD); 784 } 785 786 break; 787 case PPE_CNT_PORT_TX: 788 for (i = 0; i < PPE_PORT_TX_COUNTER_TBL_ENTRIES; i++) { 789 reg = PPE_PORT_TX_DROP_CNT_TBL_ADDR + PPE_PORT_TX_DROP_CNT_TBL_INC * i; 790 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD); 791 792 reg = PPE_PORT_TX_COUNTER_TBL_ADDR + PPE_PORT_TX_COUNTER_TBL_INC * i; 793 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD); 794 } 795 796 for (i = 0; i < PPE_VPORT_TX_COUNTER_TBL_ENTRIES; i++) { 797 reg = PPE_VPORT_TX_COUNTER_TBL_ADDR + PPE_VPORT_TX_COUNTER_TBL_INC * i; 798 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD); 799 800 reg = PPE_VPORT_TX_DROP_CNT_TBL_ADDR + PPE_VPORT_TX_DROP_CNT_TBL_INC * i; 801 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD); 802 } 803 804 break; 805 case PPE_CNT_QM: 806 for (i = 0; i < PPE_QUEUE_TX_COUNTER_TBL_ENTRIES; i++) { 807 reg = PPE_QUEUE_TX_COUNTER_TBL_ADDR + PPE_QUEUE_TX_COUNTER_TBL_INC * i; 808 ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD); 809 } 810 811 break; 812 default: 813 break; 814 } 815 816 return count; 817 } 818 DEFINE_SHOW_STORE_ATTRIBUTE(ppe_packet_counter); 819 820 void ppe_debugfs_setup(struct ppe_device *ppe_dev) 821 { 822 struct ppe_debugfs_entry *entry; 823 int i; 824 825 ppe_dev->debugfs_root = debugfs_create_dir("ppe", NULL); 826 if (IS_ERR(ppe_dev->debugfs_root)) 827 return; 828 829 for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) { 830 entry = devm_kzalloc(ppe_dev->dev, sizeof(*entry), GFP_KERNEL); 831 if (!entry) 832 return; 833 834 entry->ppe = ppe_dev; 835 entry->counter_type = debugfs_files[i].counter_type; 836 837 debugfs_create_file(debugfs_files[i].name, 0444, 838 ppe_dev->debugfs_root, entry, 839 &ppe_packet_counter_fops); 840 } 841 } 842 843 void ppe_debugfs_teardown(struct ppe_device *ppe_dev) 844 { 845 debugfs_remove_recursive(ppe_dev->debugfs_root); 846 ppe_dev->debugfs_root = NULL; 847 } 848