162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/debugfs.h> 662306a36Sopenharmony_ci#include "mtk_eth_soc.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_cistruct mtk_flow_addr_info 962306a36Sopenharmony_ci{ 1062306a36Sopenharmony_ci void *src, *dest; 1162306a36Sopenharmony_ci u16 *src_port, *dest_port; 1262306a36Sopenharmony_ci bool ipv6; 1362306a36Sopenharmony_ci}; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic const char *mtk_foe_entry_state_str(int state) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci static const char * const state_str[] = { 1862306a36Sopenharmony_ci [MTK_FOE_STATE_INVALID] = "INV", 1962306a36Sopenharmony_ci [MTK_FOE_STATE_UNBIND] = "UNB", 2062306a36Sopenharmony_ci [MTK_FOE_STATE_BIND] = "BND", 2162306a36Sopenharmony_ci [MTK_FOE_STATE_FIN] = "FIN", 2262306a36Sopenharmony_ci }; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if (state >= ARRAY_SIZE(state_str) || !state_str[state]) 2562306a36Sopenharmony_ci return "UNK"; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci return state_str[state]; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const char *mtk_foe_pkt_type_str(int type) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci static const char * const type_str[] = { 3362306a36Sopenharmony_ci [MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T", 3462306a36Sopenharmony_ci [MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T", 3562306a36Sopenharmony_ci [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE", 3662306a36Sopenharmony_ci [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T", 3762306a36Sopenharmony_ci [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T", 3862306a36Sopenharmony_ci [MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD", 3962306a36Sopenharmony_ci }; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (type >= ARRAY_SIZE(type_str) || !type_str[type]) 4262306a36Sopenharmony_ci return "UNKNOWN"; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return type_str[type]; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic void 4862306a36Sopenharmony_cimtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci __be32 n_addr[4]; 5162306a36Sopenharmony_ci int i; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (!ipv6) { 5462306a36Sopenharmony_ci seq_printf(m, "%pI4h", addr); 5562306a36Sopenharmony_ci return; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(n_addr); i++) 5962306a36Sopenharmony_ci n_addr[i] = htonl(addr[i]); 6062306a36Sopenharmony_ci seq_printf(m, "%pI6", n_addr); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void 6462306a36Sopenharmony_cimtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci mtk_print_addr(m, ai->src, ai->ipv6); 6762306a36Sopenharmony_ci if (ai->src_port) 6862306a36Sopenharmony_ci seq_printf(m, ":%d", *ai->src_port); 6962306a36Sopenharmony_ci seq_printf(m, "->"); 7062306a36Sopenharmony_ci mtk_print_addr(m, ai->dest, ai->ipv6); 7162306a36Sopenharmony_ci if (ai->dest_port) 7262306a36Sopenharmony_ci seq_printf(m, ":%d", *ai->dest_port); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int 7662306a36Sopenharmony_cimtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct mtk_ppe *ppe = m->private; 7962306a36Sopenharmony_ci int i; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci for (i = 0; i < MTK_PPE_ENTRIES; i++) { 8262306a36Sopenharmony_ci struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i); 8362306a36Sopenharmony_ci struct mtk_foe_mac_info *l2; 8462306a36Sopenharmony_ci struct mtk_flow_addr_info ai = {}; 8562306a36Sopenharmony_ci struct mtk_foe_accounting *acct; 8662306a36Sopenharmony_ci unsigned char h_source[ETH_ALEN]; 8762306a36Sopenharmony_ci unsigned char h_dest[ETH_ALEN]; 8862306a36Sopenharmony_ci int type, state; 8962306a36Sopenharmony_ci u32 ib2; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1); 9362306a36Sopenharmony_ci if (!state) 9462306a36Sopenharmony_ci continue; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (bind && state != MTK_FOE_STATE_BIND) 9762306a36Sopenharmony_ci continue; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci acct = mtk_foe_entry_get_mib(ppe, i, NULL); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci type = mtk_get_ib1_pkt_type(ppe->eth, entry->ib1); 10262306a36Sopenharmony_ci seq_printf(m, "%05x %s %7s", i, 10362306a36Sopenharmony_ci mtk_foe_entry_state_str(state), 10462306a36Sopenharmony_ci mtk_foe_pkt_type_str(type)); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci switch (type) { 10762306a36Sopenharmony_ci case MTK_PPE_PKT_TYPE_IPV4_HNAPT: 10862306a36Sopenharmony_ci case MTK_PPE_PKT_TYPE_IPV4_DSLITE: 10962306a36Sopenharmony_ci ai.src_port = &entry->ipv4.orig.src_port; 11062306a36Sopenharmony_ci ai.dest_port = &entry->ipv4.orig.dest_port; 11162306a36Sopenharmony_ci fallthrough; 11262306a36Sopenharmony_ci case MTK_PPE_PKT_TYPE_IPV4_ROUTE: 11362306a36Sopenharmony_ci ai.src = &entry->ipv4.orig.src_ip; 11462306a36Sopenharmony_ci ai.dest = &entry->ipv4.orig.dest_ip; 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T: 11762306a36Sopenharmony_ci ai.src_port = &entry->ipv6.src_port; 11862306a36Sopenharmony_ci ai.dest_port = &entry->ipv6.dest_port; 11962306a36Sopenharmony_ci fallthrough; 12062306a36Sopenharmony_ci case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T: 12162306a36Sopenharmony_ci case MTK_PPE_PKT_TYPE_IPV6_6RD: 12262306a36Sopenharmony_ci ai.src = &entry->ipv6.src_ip; 12362306a36Sopenharmony_ci ai.dest = &entry->ipv6.dest_ip; 12462306a36Sopenharmony_ci ai.ipv6 = true; 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci seq_printf(m, " orig="); 12962306a36Sopenharmony_ci mtk_print_addr_info(m, &ai); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci switch (type) { 13262306a36Sopenharmony_ci case MTK_PPE_PKT_TYPE_IPV4_HNAPT: 13362306a36Sopenharmony_ci case MTK_PPE_PKT_TYPE_IPV4_DSLITE: 13462306a36Sopenharmony_ci ai.src_port = &entry->ipv4.new.src_port; 13562306a36Sopenharmony_ci ai.dest_port = &entry->ipv4.new.dest_port; 13662306a36Sopenharmony_ci fallthrough; 13762306a36Sopenharmony_ci case MTK_PPE_PKT_TYPE_IPV4_ROUTE: 13862306a36Sopenharmony_ci ai.src = &entry->ipv4.new.src_ip; 13962306a36Sopenharmony_ci ai.dest = &entry->ipv4.new.dest_ip; 14062306a36Sopenharmony_ci seq_printf(m, " new="); 14162306a36Sopenharmony_ci mtk_print_addr_info(m, &ai); 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { 14662306a36Sopenharmony_ci l2 = &entry->ipv6.l2; 14762306a36Sopenharmony_ci ib2 = entry->ipv6.ib2; 14862306a36Sopenharmony_ci } else { 14962306a36Sopenharmony_ci l2 = &entry->ipv4.l2; 15062306a36Sopenharmony_ci ib2 = entry->ipv4.ib2; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci *((__be32 *)h_source) = htonl(l2->src_mac_hi); 15462306a36Sopenharmony_ci *((__be16 *)&h_source[4]) = htons(l2->src_mac_lo); 15562306a36Sopenharmony_ci *((__be32 *)h_dest) = htonl(l2->dest_mac_hi); 15662306a36Sopenharmony_ci *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci seq_printf(m, " eth=%pM->%pM etype=%04x" 15962306a36Sopenharmony_ci " vlan=%d,%d ib1=%08x ib2=%08x" 16062306a36Sopenharmony_ci " packets=%llu bytes=%llu\n", 16162306a36Sopenharmony_ci h_source, h_dest, ntohs(l2->etype), 16262306a36Sopenharmony_ci l2->vlan1, l2->vlan2, entry->ib1, ib2, 16362306a36Sopenharmony_ci acct ? acct->packets : 0, acct ? acct->bytes : 0); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int 17062306a36Sopenharmony_cimtk_ppe_debugfs_foe_all_show(struct seq_file *m, void *private) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci return mtk_ppe_debugfs_foe_show(m, private, false); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_all); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic int 17762306a36Sopenharmony_cimtk_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci return mtk_ppe_debugfs_foe_show(m, private, true); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_bind); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ciint mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct dentry *root; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci snprintf(ppe->dirname, sizeof(ppe->dirname), "ppe%d", index); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci root = debugfs_create_dir(ppe->dirname, NULL); 19062306a36Sopenharmony_ci debugfs_create_file("entries", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_all_fops); 19162306a36Sopenharmony_ci debugfs_create_file("bind", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_bind_fops); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 195