1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */ 3 4 #include <linux/kernel.h> 5 #include <linux/debugfs.h> 6 #include "mtk_eth_soc.h" 7 8 struct mtk_flow_addr_info 9 { 10 void *src, *dest; 11 u16 *src_port, *dest_port; 12 bool ipv6; 13 }; 14 15 static const char *mtk_foe_entry_state_str(int state) 16 { 17 static const char * const state_str[] = { 18 [MTK_FOE_STATE_INVALID] = "INV", 19 [MTK_FOE_STATE_UNBIND] = "UNB", 20 [MTK_FOE_STATE_BIND] = "BND", 21 [MTK_FOE_STATE_FIN] = "FIN", 22 }; 23 24 if (state >= ARRAY_SIZE(state_str) || !state_str[state]) 25 return "UNK"; 26 27 return state_str[state]; 28 } 29 30 static const char *mtk_foe_pkt_type_str(int type) 31 { 32 static const char * const type_str[] = { 33 [MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T", 34 [MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T", 35 [MTK_PPE_PKT_TYPE_BRIDGE] = "L2", 36 [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE", 37 [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T", 38 [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T", 39 [MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD", 40 }; 41 42 if (type >= ARRAY_SIZE(type_str) || !type_str[type]) 43 return "UNKNOWN"; 44 45 return type_str[type]; 46 } 47 48 static void 49 mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6) 50 { 51 u32 n_addr[4]; 52 int i; 53 54 if (!ipv6) { 55 seq_printf(m, "%pI4h", addr); 56 return; 57 } 58 59 for (i = 0; i < ARRAY_SIZE(n_addr); i++) 60 n_addr[i] = htonl(addr[i]); 61 seq_printf(m, "%pI6", n_addr); 62 } 63 64 static void 65 mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai) 66 { 67 mtk_print_addr(m, ai->src, ai->ipv6); 68 if (ai->src_port) 69 seq_printf(m, ":%d", *ai->src_port); 70 seq_printf(m, "->"); 71 mtk_print_addr(m, ai->dest, ai->ipv6); 72 if (ai->dest_port) 73 seq_printf(m, ":%d", *ai->dest_port); 74 } 75 76 static int 77 mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) 78 { 79 struct mtk_ppe *ppe = m->private; 80 int i; 81 82 for (i = 0; i < MTK_PPE_ENTRIES; i++) { 83 struct mtk_foe_entry *entry = &ppe->foe_table[i]; 84 struct mtk_foe_mac_info *l2; 85 struct mtk_flow_addr_info ai = {}; 86 unsigned char h_source[ETH_ALEN]; 87 unsigned char h_dest[ETH_ALEN]; 88 int type, state; 89 u32 ib2; 90 91 92 state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1); 93 if (!state) 94 continue; 95 96 if (bind && state != MTK_FOE_STATE_BIND) 97 continue; 98 99 type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); 100 seq_printf(m, "%05x %s %7s", i, 101 mtk_foe_entry_state_str(state), 102 mtk_foe_pkt_type_str(type)); 103 104 switch (type) { 105 case MTK_PPE_PKT_TYPE_IPV4_HNAPT: 106 case MTK_PPE_PKT_TYPE_IPV4_DSLITE: 107 ai.src_port = &entry->ipv4.orig.src_port; 108 ai.dest_port = &entry->ipv4.orig.dest_port; 109 fallthrough; 110 case MTK_PPE_PKT_TYPE_IPV4_ROUTE: 111 ai.src = &entry->ipv4.orig.src_ip; 112 ai.dest = &entry->ipv4.orig.dest_ip; 113 break; 114 case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T: 115 ai.src_port = &entry->ipv6.src_port; 116 ai.dest_port = &entry->ipv6.dest_port; 117 fallthrough; 118 case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T: 119 case MTK_PPE_PKT_TYPE_IPV6_6RD: 120 ai.src = &entry->ipv6.src_ip; 121 ai.dest = &entry->ipv6.dest_ip; 122 ai.ipv6 = true; 123 break; 124 } 125 126 seq_printf(m, " orig="); 127 mtk_print_addr_info(m, &ai); 128 129 switch (type) { 130 case MTK_PPE_PKT_TYPE_IPV4_HNAPT: 131 case MTK_PPE_PKT_TYPE_IPV4_DSLITE: 132 ai.src_port = &entry->ipv4.new.src_port; 133 ai.dest_port = &entry->ipv4.new.dest_port; 134 fallthrough; 135 case MTK_PPE_PKT_TYPE_IPV4_ROUTE: 136 ai.src = &entry->ipv4.new.src_ip; 137 ai.dest = &entry->ipv4.new.dest_ip; 138 seq_printf(m, " new="); 139 mtk_print_addr_info(m, &ai); 140 break; 141 } 142 143 if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { 144 l2 = &entry->ipv6.l2; 145 ib2 = entry->ipv6.ib2; 146 } else { 147 l2 = &entry->ipv4.l2; 148 ib2 = entry->ipv4.ib2; 149 } 150 151 *((__be32 *)h_source) = htonl(l2->src_mac_hi); 152 *((__be16 *)&h_source[4]) = htons(l2->src_mac_lo); 153 *((__be32 *)h_dest) = htonl(l2->dest_mac_hi); 154 *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo); 155 156 seq_printf(m, " eth=%pM->%pM etype=%04x" 157 " vlan=%d,%d ib1=%08x ib2=%08x\n", 158 h_source, h_dest, ntohs(l2->etype), 159 l2->vlan1, l2->vlan2, entry->ib1, ib2); 160 } 161 162 return 0; 163 } 164 165 static int 166 mtk_ppe_debugfs_foe_show_all(struct seq_file *m, void *private) 167 { 168 return mtk_ppe_debugfs_foe_show(m, private, false); 169 } 170 171 static int 172 mtk_ppe_debugfs_foe_show_bind(struct seq_file *m, void *private) 173 { 174 return mtk_ppe_debugfs_foe_show(m, private, true); 175 } 176 177 static int 178 mtk_ppe_debugfs_foe_open_all(struct inode *inode, struct file *file) 179 { 180 return single_open(file, mtk_ppe_debugfs_foe_show_all, 181 inode->i_private); 182 } 183 184 static int 185 mtk_ppe_debugfs_foe_open_bind(struct inode *inode, struct file *file) 186 { 187 return single_open(file, mtk_ppe_debugfs_foe_show_bind, 188 inode->i_private); 189 } 190 191 int mtk_ppe_debugfs_init(struct mtk_ppe *ppe) 192 { 193 static const struct file_operations fops_all = { 194 .open = mtk_ppe_debugfs_foe_open_all, 195 .read = seq_read, 196 .llseek = seq_lseek, 197 .release = single_release, 198 }; 199 200 static const struct file_operations fops_bind = { 201 .open = mtk_ppe_debugfs_foe_open_bind, 202 .read = seq_read, 203 .llseek = seq_lseek, 204 .release = single_release, 205 }; 206 207 struct dentry *root; 208 209 root = debugfs_create_dir("mtk_ppe", NULL); 210 if (!root) 211 return -ENOMEM; 212 213 debugfs_create_file("entries", S_IRUGO, root, ppe, &fops_all); 214 debugfs_create_file("bind", S_IRUGO, root, ppe, &fops_bind); 215 216 return 0; 217 } 218