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_IPV4_DSLITE] = "DS-LITE", 36 [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T", 37 [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T", 38 [MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD", 39 }; 40 41 if (type >= ARRAY_SIZE(type_str) || !type_str[type]) 42 return "UNKNOWN"; 43 44 return type_str[type]; 45 } 46 47 static void 48 mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6) 49 { 50 __be32 n_addr[4]; 51 int i; 52 53 if (!ipv6) { 54 seq_printf(m, "%pI4h", addr); 55 return; 56 } 57 58 for (i = 0; i < ARRAY_SIZE(n_addr); i++) 59 n_addr[i] = htonl(addr[i]); 60 seq_printf(m, "%pI6", n_addr); 61 } 62 63 static void 64 mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai) 65 { 66 mtk_print_addr(m, ai->src, ai->ipv6); 67 if (ai->src_port) 68 seq_printf(m, ":%d", *ai->src_port); 69 seq_printf(m, "->"); 70 mtk_print_addr(m, ai->dest, ai->ipv6); 71 if (ai->dest_port) 72 seq_printf(m, ":%d", *ai->dest_port); 73 } 74 75 static int 76 mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) 77 { 78 struct mtk_ppe *ppe = m->private; 79 int i; 80 81 for (i = 0; i < MTK_PPE_ENTRIES; i++) { 82 struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i); 83 struct mtk_foe_mac_info *l2; 84 struct mtk_flow_addr_info ai = {}; 85 struct mtk_foe_accounting *acct; 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 acct = mtk_foe_entry_get_mib(ppe, i, NULL); 100 101 type = mtk_get_ib1_pkt_type(ppe->eth, entry->ib1); 102 seq_printf(m, "%05x %s %7s", i, 103 mtk_foe_entry_state_str(state), 104 mtk_foe_pkt_type_str(type)); 105 106 switch (type) { 107 case MTK_PPE_PKT_TYPE_IPV4_HNAPT: 108 case MTK_PPE_PKT_TYPE_IPV4_DSLITE: 109 ai.src_port = &entry->ipv4.orig.src_port; 110 ai.dest_port = &entry->ipv4.orig.dest_port; 111 fallthrough; 112 case MTK_PPE_PKT_TYPE_IPV4_ROUTE: 113 ai.src = &entry->ipv4.orig.src_ip; 114 ai.dest = &entry->ipv4.orig.dest_ip; 115 break; 116 case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T: 117 ai.src_port = &entry->ipv6.src_port; 118 ai.dest_port = &entry->ipv6.dest_port; 119 fallthrough; 120 case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T: 121 case MTK_PPE_PKT_TYPE_IPV6_6RD: 122 ai.src = &entry->ipv6.src_ip; 123 ai.dest = &entry->ipv6.dest_ip; 124 ai.ipv6 = true; 125 break; 126 } 127 128 seq_printf(m, " orig="); 129 mtk_print_addr_info(m, &ai); 130 131 switch (type) { 132 case MTK_PPE_PKT_TYPE_IPV4_HNAPT: 133 case MTK_PPE_PKT_TYPE_IPV4_DSLITE: 134 ai.src_port = &entry->ipv4.new.src_port; 135 ai.dest_port = &entry->ipv4.new.dest_port; 136 fallthrough; 137 case MTK_PPE_PKT_TYPE_IPV4_ROUTE: 138 ai.src = &entry->ipv4.new.src_ip; 139 ai.dest = &entry->ipv4.new.dest_ip; 140 seq_printf(m, " new="); 141 mtk_print_addr_info(m, &ai); 142 break; 143 } 144 145 if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { 146 l2 = &entry->ipv6.l2; 147 ib2 = entry->ipv6.ib2; 148 } else { 149 l2 = &entry->ipv4.l2; 150 ib2 = entry->ipv4.ib2; 151 } 152 153 *((__be32 *)h_source) = htonl(l2->src_mac_hi); 154 *((__be16 *)&h_source[4]) = htons(l2->src_mac_lo); 155 *((__be32 *)h_dest) = htonl(l2->dest_mac_hi); 156 *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo); 157 158 seq_printf(m, " eth=%pM->%pM etype=%04x" 159 " vlan=%d,%d ib1=%08x ib2=%08x" 160 " packets=%llu bytes=%llu\n", 161 h_source, h_dest, ntohs(l2->etype), 162 l2->vlan1, l2->vlan2, entry->ib1, ib2, 163 acct ? acct->packets : 0, acct ? acct->bytes : 0); 164 } 165 166 return 0; 167 } 168 169 static int 170 mtk_ppe_debugfs_foe_all_show(struct seq_file *m, void *private) 171 { 172 return mtk_ppe_debugfs_foe_show(m, private, false); 173 } 174 DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_all); 175 176 static int 177 mtk_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private) 178 { 179 return mtk_ppe_debugfs_foe_show(m, private, true); 180 } 181 DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_bind); 182 183 int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index) 184 { 185 struct dentry *root; 186 187 snprintf(ppe->dirname, sizeof(ppe->dirname), "ppe%d", index); 188 189 root = debugfs_create_dir(ppe->dirname, NULL); 190 debugfs_create_file("entries", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_all_fops); 191 debugfs_create_file("bind", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_bind_fops); 192 193 return 0; 194 } 195