airoha_ppe_debugfs.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2025 AIROHA Inc
  4. * Author: Lorenzo Bianconi <lorenzo@kernel.org>
  5. */
  6. #include "airoha_eth.h"
  7. static void airoha_debugfs_ppe_print_tuple(struct seq_file *m,
  8. void *src_addr, void *dest_addr,
  9. u16 *src_port, u16 *dest_port,
  10. bool ipv6)
  11. {
  12. __be32 n_addr[IPV6_ADDR_WORDS];
  13. if (ipv6) {
  14. ipv6_addr_cpu_to_be32(n_addr, src_addr);
  15. seq_printf(m, "%pI6", n_addr);
  16. } else {
  17. seq_printf(m, "%pI4h", src_addr);
  18. }
  19. if (src_port)
  20. seq_printf(m, ":%d", *src_port);
  21. seq_puts(m, "->");
  22. if (ipv6) {
  23. ipv6_addr_cpu_to_be32(n_addr, dest_addr);
  24. seq_printf(m, "%pI6", n_addr);
  25. } else {
  26. seq_printf(m, "%pI4h", dest_addr);
  27. }
  28. if (dest_port)
  29. seq_printf(m, ":%d", *dest_port);
  30. }
  31. static int airoha_ppe_debugfs_foe_show(struct seq_file *m, void *private,
  32. bool bind)
  33. {
  34. static const char *const ppe_type_str[] = {
  35. [PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
  36. [PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
  37. [PPE_PKT_TYPE_BRIDGE] = "L2B",
  38. [PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
  39. [PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
  40. [PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
  41. [PPE_PKT_TYPE_IPV6_6RD] = "6RD",
  42. };
  43. static const char *const ppe_state_str[] = {
  44. [AIROHA_FOE_STATE_INVALID] = "INV",
  45. [AIROHA_FOE_STATE_UNBIND] = "UNB",
  46. [AIROHA_FOE_STATE_BIND] = "BND",
  47. [AIROHA_FOE_STATE_FIN] = "FIN",
  48. };
  49. struct airoha_ppe *ppe = m->private;
  50. u32 ppe_num_entries = airoha_ppe_get_total_num_entries(ppe);
  51. int i;
  52. for (i = 0; i < ppe_num_entries; i++) {
  53. const char *state_str, *type_str = "UNKNOWN";
  54. void *src_addr = NULL, *dest_addr = NULL;
  55. u16 *src_port = NULL, *dest_port = NULL;
  56. struct airoha_foe_mac_info_common *l2;
  57. unsigned char h_source[ETH_ALEN] = {};
  58. struct airoha_foe_stats64 stats = {};
  59. unsigned char h_dest[ETH_ALEN];
  60. struct airoha_foe_entry *hwe;
  61. u32 type, state, ib2, data;
  62. bool ipv6 = false;
  63. hwe = airoha_ppe_foe_get_entry(ppe, i);
  64. if (!hwe)
  65. continue;
  66. state = FIELD_GET(AIROHA_FOE_IB1_BIND_STATE, hwe->ib1);
  67. if (!state)
  68. continue;
  69. if (bind && state != AIROHA_FOE_STATE_BIND)
  70. continue;
  71. state_str = ppe_state_str[state % ARRAY_SIZE(ppe_state_str)];
  72. type = FIELD_GET(AIROHA_FOE_IB1_BIND_PACKET_TYPE, hwe->ib1);
  73. if (type < ARRAY_SIZE(ppe_type_str) && ppe_type_str[type])
  74. type_str = ppe_type_str[type];
  75. seq_printf(m, "%05x %s %7s", i, state_str, type_str);
  76. switch (type) {
  77. case PPE_PKT_TYPE_IPV4_HNAPT:
  78. case PPE_PKT_TYPE_IPV4_DSLITE:
  79. src_port = &hwe->ipv4.orig_tuple.src_port;
  80. dest_port = &hwe->ipv4.orig_tuple.dest_port;
  81. fallthrough;
  82. case PPE_PKT_TYPE_IPV4_ROUTE:
  83. src_addr = &hwe->ipv4.orig_tuple.src_ip;
  84. dest_addr = &hwe->ipv4.orig_tuple.dest_ip;
  85. break;
  86. case PPE_PKT_TYPE_IPV6_ROUTE_5T:
  87. src_port = &hwe->ipv6.src_port;
  88. dest_port = &hwe->ipv6.dest_port;
  89. fallthrough;
  90. case PPE_PKT_TYPE_IPV6_ROUTE_3T:
  91. case PPE_PKT_TYPE_IPV6_6RD:
  92. src_addr = &hwe->ipv6.src_ip;
  93. dest_addr = &hwe->ipv6.dest_ip;
  94. ipv6 = true;
  95. break;
  96. default:
  97. break;
  98. }
  99. if (src_addr && dest_addr) {
  100. seq_puts(m, " orig=");
  101. airoha_debugfs_ppe_print_tuple(m, src_addr, dest_addr,
  102. src_port, dest_port, ipv6);
  103. }
  104. switch (type) {
  105. case PPE_PKT_TYPE_IPV4_HNAPT:
  106. case PPE_PKT_TYPE_IPV4_DSLITE:
  107. src_port = &hwe->ipv4.new_tuple.src_port;
  108. dest_port = &hwe->ipv4.new_tuple.dest_port;
  109. fallthrough;
  110. case PPE_PKT_TYPE_IPV4_ROUTE:
  111. src_addr = &hwe->ipv4.new_tuple.src_ip;
  112. dest_addr = &hwe->ipv4.new_tuple.dest_ip;
  113. seq_puts(m, " new=");
  114. airoha_debugfs_ppe_print_tuple(m, src_addr, dest_addr,
  115. src_port, dest_port,
  116. ipv6);
  117. break;
  118. default:
  119. break;
  120. }
  121. if (type >= PPE_PKT_TYPE_IPV6_ROUTE_3T) {
  122. data = hwe->ipv6.data;
  123. ib2 = hwe->ipv6.ib2;
  124. l2 = &hwe->ipv6.l2;
  125. } else {
  126. data = hwe->ipv4.data;
  127. ib2 = hwe->ipv4.ib2;
  128. l2 = &hwe->ipv4.l2.common;
  129. *((__be16 *)&h_source[4]) =
  130. cpu_to_be16(hwe->ipv4.l2.src_mac_lo);
  131. }
  132. airoha_ppe_foe_entry_get_stats(ppe, i, &stats);
  133. *((__be32 *)h_dest) = cpu_to_be32(l2->dest_mac_hi);
  134. *((__be16 *)&h_dest[4]) = cpu_to_be16(l2->dest_mac_lo);
  135. *((__be32 *)h_source) = cpu_to_be32(l2->src_mac_hi);
  136. seq_printf(m, " eth=%pM->%pM etype=%04x data=%08x"
  137. " vlan=%d,%d ib1=%08x ib2=%08x"
  138. " packets=%llu bytes=%llu\n",
  139. h_source, h_dest, l2->etype, data,
  140. l2->vlan1, l2->vlan2, hwe->ib1, ib2,
  141. stats.packets, stats.bytes);
  142. }
  143. return 0;
  144. }
  145. static int airoha_ppe_debugfs_foe_all_show(struct seq_file *m, void *private)
  146. {
  147. return airoha_ppe_debugfs_foe_show(m, private, false);
  148. }
  149. DEFINE_SHOW_ATTRIBUTE(airoha_ppe_debugfs_foe_all);
  150. static int airoha_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private)
  151. {
  152. return airoha_ppe_debugfs_foe_show(m, private, true);
  153. }
  154. DEFINE_SHOW_ATTRIBUTE(airoha_ppe_debugfs_foe_bind);
  155. int airoha_ppe_debugfs_init(struct airoha_ppe *ppe)
  156. {
  157. ppe->debugfs_dir = debugfs_create_dir("ppe", NULL);
  158. debugfs_create_file("entries", 0444, ppe->debugfs_dir, ppe,
  159. &airoha_ppe_debugfs_foe_all_fops);
  160. debugfs_create_file("bind", 0444, ppe->debugfs_dir, ppe,
  161. &airoha_ppe_debugfs_foe_bind_fops);
  162. return 0;
  163. }