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