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 int i; 57 58 for (i = 0; i < PPE_NUM_ENTRIES; i++) { 59 const char *state_str, *type_str = "UNKNOWN"; 60 void *src_addr = NULL, *dest_addr = NULL; 61 u16 *src_port = NULL, *dest_port = NULL; 62 struct airoha_foe_mac_info_common *l2; 63 unsigned char h_source[ETH_ALEN] = {}; 64 unsigned char h_dest[ETH_ALEN]; 65 struct airoha_foe_entry *hwe; 66 u32 type, state, ib2, data; 67 bool ipv6 = false; 68 69 hwe = airoha_ppe_foe_get_entry(ppe, i); 70 if (!hwe) 71 continue; 72 73 state = FIELD_GET(AIROHA_FOE_IB1_BIND_STATE, hwe->ib1); 74 if (!state) 75 continue; 76 77 if (bind && state != AIROHA_FOE_STATE_BIND) 78 continue; 79 80 state_str = ppe_state_str[state % ARRAY_SIZE(ppe_state_str)]; 81 type = FIELD_GET(AIROHA_FOE_IB1_BIND_PACKET_TYPE, hwe->ib1); 82 if (type < ARRAY_SIZE(ppe_type_str) && ppe_type_str[type]) 83 type_str = ppe_type_str[type]; 84 85 seq_printf(m, "%05x %s %7s", i, state_str, type_str); 86 87 switch (type) { 88 case PPE_PKT_TYPE_IPV4_HNAPT: 89 case PPE_PKT_TYPE_IPV4_DSLITE: 90 src_port = &hwe->ipv4.orig_tuple.src_port; 91 dest_port = &hwe->ipv4.orig_tuple.dest_port; 92 fallthrough; 93 case PPE_PKT_TYPE_IPV4_ROUTE: 94 src_addr = &hwe->ipv4.orig_tuple.src_ip; 95 dest_addr = &hwe->ipv4.orig_tuple.dest_ip; 96 break; 97 case PPE_PKT_TYPE_IPV6_ROUTE_5T: 98 src_port = &hwe->ipv6.src_port; 99 dest_port = &hwe->ipv6.dest_port; 100 fallthrough; 101 case PPE_PKT_TYPE_IPV6_ROUTE_3T: 102 case PPE_PKT_TYPE_IPV6_6RD: 103 src_addr = &hwe->ipv6.src_ip; 104 dest_addr = &hwe->ipv6.dest_ip; 105 ipv6 = true; 106 break; 107 default: 108 break; 109 } 110 111 if (src_addr && dest_addr) { 112 seq_puts(m, " orig="); 113 airoha_debugfs_ppe_print_tuple(m, src_addr, dest_addr, 114 src_port, dest_port, ipv6); 115 } 116 117 switch (type) { 118 case PPE_PKT_TYPE_IPV4_HNAPT: 119 case PPE_PKT_TYPE_IPV4_DSLITE: 120 src_port = &hwe->ipv4.new_tuple.src_port; 121 dest_port = &hwe->ipv4.new_tuple.dest_port; 122 fallthrough; 123 case PPE_PKT_TYPE_IPV4_ROUTE: 124 src_addr = &hwe->ipv4.new_tuple.src_ip; 125 dest_addr = &hwe->ipv4.new_tuple.dest_ip; 126 seq_puts(m, " new="); 127 airoha_debugfs_ppe_print_tuple(m, src_addr, dest_addr, 128 src_port, dest_port, 129 ipv6); 130 break; 131 default: 132 break; 133 } 134 135 if (type >= PPE_PKT_TYPE_IPV6_ROUTE_3T) { 136 data = hwe->ipv6.data; 137 ib2 = hwe->ipv6.ib2; 138 l2 = &hwe->ipv6.l2; 139 } else { 140 data = hwe->ipv4.data; 141 ib2 = hwe->ipv4.ib2; 142 l2 = &hwe->ipv4.l2.common; 143 *((__be16 *)&h_source[4]) = 144 cpu_to_be16(hwe->ipv4.l2.src_mac_lo); 145 } 146 147 *((__be32 *)h_dest) = cpu_to_be32(l2->dest_mac_hi); 148 *((__be16 *)&h_dest[4]) = cpu_to_be16(l2->dest_mac_lo); 149 *((__be32 *)h_source) = cpu_to_be32(l2->src_mac_hi); 150 151 seq_printf(m, " eth=%pM->%pM etype=%04x data=%08x" 152 " vlan=%d,%d ib1=%08x ib2=%08x\n", 153 h_source, h_dest, l2->etype, data, 154 l2->vlan1, l2->vlan2, hwe->ib1, ib2); 155 } 156 157 return 0; 158 } 159 160 static int airoha_ppe_debugfs_foe_all_show(struct seq_file *m, void *private) 161 { 162 return airoha_ppe_debugfs_foe_show(m, private, false); 163 } 164 DEFINE_SHOW_ATTRIBUTE(airoha_ppe_debugfs_foe_all); 165 166 static int airoha_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private) 167 { 168 return airoha_ppe_debugfs_foe_show(m, private, true); 169 } 170 DEFINE_SHOW_ATTRIBUTE(airoha_ppe_debugfs_foe_bind); 171 172 int airoha_ppe_debugfs_init(struct airoha_ppe *ppe) 173 { 174 ppe->debugfs_dir = debugfs_create_dir("ppe", NULL); 175 debugfs_create_file("entries", 0444, ppe->debugfs_dir, ppe, 176 &airoha_ppe_debugfs_foe_all_fops); 177 debugfs_create_file("bind", 0444, ppe->debugfs_dir, ppe, 178 &airoha_ppe_debugfs_foe_bind_fops); 179 180 return 0; 181 } 182