// SPDX-License-Identifier: GPL-2.0 #include "hwpa_ppe_internal.h" #include #include #if defined(CONFIG_DEBUG_FS) static void hwpa_ppe_show_brief(hwpa_ppe_fprintf fprintffunc, void *arg) { struct hwpa_ppe_context *ppe_ctx = hwpa_ppe_get_context(); int free_hws = 0, used_hws = 0; struct hwpa_ppe_session *hws; int hws_per_accelerator[HWPA_PPE_MAX_ACCELERATORS] = {0}; int undefined_accelerator_count = 0; struct hwpa_ppe_accelerator *accelerator; int i; int bkt; (*fprintffunc)(arg, "HWPA ppe summary:\n"); rcu_read_lock(); hash_for_each_rcu(ppe_ctx->used_hws_hlist, bkt, hws, node) { accelerator = hwpa_ppe_get_accelerator(hws); if (accelerator) hws_per_accelerator[hws->accel_type]++; else undefined_accelerator_count++; ++used_hws; } rcu_read_unlock(); hash_for_each_rcu(ppe_ctx->free_hws_hlist, bkt, hws, node) ++free_hws; (*fprintffunc)(arg, "used hws %d / %d\n", used_hws, ARRAY_SIZE(ppe_ctx->hws_storage)); (*fprintffunc)(arg, "free hws %d / %d\n\n", free_hws, ARRAY_SIZE(ppe_ctx->hws_storage)); (*fprintffunc)(arg, "Common PPE offload counter:\n"); for (i = 0; i < ppe_ctx->counter_count; ++i) (*fprintffunc)(arg, " %-16s: %d\n", ppe_ctx->counter_label[i], atomic_read(&ppe_ctx->counter[i])); (*fprintffunc)(arg, "\nCounter per accelerator:"); list_for_each_entry(accelerator, &ppe_ctx->accelerators, ctx_node) { (*fprintffunc)(arg, "\n%-16s =>\n %-16s: %d\n", accelerator->label, "sessions", hws_per_accelerator[accelerator->accel_type]); for (i = 0; i < accelerator->counter_count; ++i) { (*fprintffunc)(arg, " %-16s: %d\n", accelerator->counter_label[i], atomic_read(&accelerator->counter[i])); } } if (undefined_accelerator_count) (*fprintffunc)(arg, "hws with undefined accelerator %d\n", undefined_accelerator_count); (*fprintffunc)(arg, "\nWAN Egress Config:\n"); (*fprintffunc)(arg, " state: %d\n", ppe_ctx->wan_egress.state); (*fprintffunc)(arg, " fos_mac: %pM\n", ppe_ctx->wan_egress.fos_mac); (*fprintffunc)(arg, " ppe_if_mac: %pM\n", ppe_ctx->wan_egress.ppe_if_mac); (*fprintffunc)(arg, " ppe_ifnum: %d\n", ppe_ctx->wan_egress.ppe_ifnum); (*fprintffunc)(arg, " refcount: %d\n", ppe_ctx->wan_egress.refcount); } static int brief_show(struct seq_file *m, void *v) { hwpa_ppe_show_brief((hwpa_ppe_fprintf *)seq_printf, m); return 0; } static int brief_show_open(struct inode *inode, struct file *file) { return single_open(file, brief_show, NULL); } static const struct file_operations brief_show_fops = { .open = brief_show_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static void hwpa_ppe_show_interfaces(hwpa_ppe_fprintf fprintffunc, void *arg) { struct net_device *dev; struct net *net; int32_t if_index; int32_t port_num; bool rfs_support; struct net_device *vp_dev; struct hwpa_ppe_context *ppe_ctx = hwpa_ppe_get_context(); avm_pid_handle pid_handle; (*fprintffunc)(arg, "%-20s%-10s%-10s%-10s%-10s%-6s%-10s%-10s%-10s\n", "Netdev", "type", "avm_pid", "ppe_ifidx", "ppe_port", "rfs", "vp_dev", "hwpa_type", "mht_bmp"); rcu_read_lock(); for_each_net_rcu(net) { for_each_netdev_rcu(net, dev) { port_num = ppe_drv_port_num_from_dev(dev); if_index = ppe_drv_iface_idx_get_by_dev(dev); rfs_support = ppe_drv_port_check_rfs_support(dev); vp_dev = ppe_drv_port_get_vp_phys_dev(dev); pid_handle = AVM_PA_DEVINFO(dev)->pid_handle; (*fprintffunc)(arg, "%-20s%-10u%-10u%-10d%-10d%-6s%-10s%-10d%-10x\n", dev->name, (unsigned int)dev->type, (unsigned int)pid_handle, if_index, port_num, rfs_support ? "yes" : "no", vp_dev ? vp_dev->name : "NULL", hwpa_ppe_valid_pid_handle(pid_handle) ? ppe_ctx->pid_info[pid_handle].type : HWPA_PPE_PID_TYPE_UNDEFINED, hwpa_ppe_valid_pid_handle(pid_handle) ? ppe_ctx->pid_info[pid_handle].mht_port_bmp : HWPA_PPE_PID_TYPE_UNDEFINED ); } } rcu_read_unlock(); } static int interfaces_show(struct seq_file *m, void *v) { hwpa_ppe_show_interfaces((hwpa_ppe_fprintf *)seq_printf, m); return 0; } static int interfaces_show_open(struct inode *inode, struct file *file) { return single_open(file, interfaces_show, NULL); } static const struct file_operations interfaces_show_fops = { .open = interfaces_show_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; struct cap_table_entry { const char label[20]; uint32_t cap; }; static void hwpa_ppe_show_caps(hwpa_ppe_fprintf fprintffunc, void *arg) { fal_ppe_tbl_caps_t caps; uint32_t i; (*fprintffunc)(arg, "MAX AVM_PA Sessions: %d\n", CONFIG_AVM_PA_MAX_SESSION); (*fprintffunc)(arg, "MAX AVM_PA PIDs: %d\n", CONFIG_AVM_PA_MAX_PID); (*fprintffunc)(arg, "MAX HWPA PPE Sessions: %d\n", HWPA_PPE_MAX_HW_SESSIONS); if (fal_ppe_capacity_get(PPE_SWITCH_ID, &caps) != SW_OK) { pr_err("Could not obtain capabilities of internal ppe switch!\n"); return; } { struct cap_table_entry cap_table[] = { {.label = "flow_caps", .cap = caps.flow_caps}, {.label = "host_caps", .cap = caps.host_caps}, {.label = "nexthop_caps", .cap = caps.nexthop_caps}, {.label = "pub_ip_caps", .cap = caps.pub_ip_caps}, {.label = "vsi_caps", .cap = caps.vsi_caps}, {.label = "port_caps", .cap = caps.port_caps}, {.label = "l3_if_caps", .cap = caps.l3_if_caps}, {.label = "my_mac_caps", .cap = caps.my_mac_caps}, {.label = "queue_caps", .cap = caps.queue_caps}, {.label = "service_code_caps", .cap = caps.service_code_caps}, {.label = "pppoe_session_caps", .cap = caps.pppoe_session_caps}, }; for (i = 0; i < ARRAY_SIZE(cap_table); ++i) (*fprintffunc)(arg, "%-25s: %d\n", cap_table[i].label, cap_table[i].cap); } } static int caps_show(struct seq_file *m, void *v) { hwpa_ppe_show_caps((hwpa_ppe_fprintf *)seq_printf, m); return 0; } static int caps_show_open(struct inode *inode, struct file *file) { return single_open(file, caps_show, NULL); } static const struct file_operations caps_show_fops = { .open = caps_show_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static void hwpa_ppe_show_meminfo(hwpa_ppe_fprintf fprintffunc, void *arg) { struct hwpa_ppe_context *ppe_ctx = hwpa_ppe_get_context(); (*fprintffunc)(arg, "HW Sessions: %d bytes\n", sizeof(ppe_ctx->hws_storage)); } static int meminfo_show(struct seq_file *m, void *v) { hwpa_ppe_show_meminfo((hwpa_ppe_fprintf *)seq_printf, m); return 0; } static int meminfo_show_open(struct inode *inode, struct file *file) { return single_open(file, meminfo_show, NULL); } static const struct file_operations meminfo_show_fops = { .open = meminfo_show_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static void hwpa_ppe_show_synced_sessions(hwpa_ppe_fprintf fprintffunc, void *arg) { struct hwpa_ppe_context *ppe_ctx = hwpa_ppe_get_context(); struct hwpa_ppe_session *hws; struct hwpa_ppe_accelerator *accelerator; int bkt; (*fprintffunc)(arg, "HWPA synced sessions\n"); rcu_read_lock(); hash_for_each_rcu(ppe_ctx->used_hws_hlist, bkt, hws, node) { (*fprintffunc)(arg, "\nHWS: %p\n", hws); accelerator = hwpa_ppe_get_accelerator(hws); if (!accelerator) { (*fprintffunc)(arg, "\nNo accelerator\n", hws); continue; } (*fprintffunc)(arg, "accelerator: %s \n", accelerator->label); if (accelerator->set_flushed_session) (*fprintffunc)(arg, "flushed by hw: %s\n", hws->session_flushed ? "yes" : "no"); (*fprintffunc)(arg, "avm_pa uniq_id: %d ssdk flow_index: %d\n", hws->sess_pa->uniq_id, hws->flow_index); if (accelerator->dump_hws) accelerator->dump_hws(fprintffunc, arg, hws); (*fprintffunc)(arg, "stats: tx_bytes: %d tx_pkts %d total_tx_bytes %lu total_tx_pkts %lu\n", hws->stats.tx_bytes, hws->stats.tx_pkts, hws->stats.total_tx_bytes, hws->stats.total_tx_pkts); } rcu_read_unlock(); } static int synced_sessions_show(struct seq_file *m, void *v) { hwpa_ppe_show_synced_sessions((hwpa_ppe_fprintf *)seq_printf, m); return 0; } static int synced_sessions_show_open(struct inode *inode, struct file *file) { return single_open(file, synced_sessions_show, NULL); } static const struct file_operations synced_sessions_show_fops = { .open = synced_sessions_show_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static struct dentry *dir_entry; void hwpa_ppe_debugfs_init(void) { dir_entry = debugfs_create_dir("hwpa_ppe", NULL); debugfs_create_file("brief", 0444, dir_entry, NULL, &brief_show_fops); debugfs_create_file("interfaces", 0444, dir_entry, NULL, &interfaces_show_fops); debugfs_create_file("caps", 0444, dir_entry, NULL, &caps_show_fops); debugfs_create_file("meminfo", 0444, dir_entry, NULL, &meminfo_show_fops); debugfs_create_file("synced_sessions", 0444, dir_entry, NULL, &synced_sessions_show_fops); PR_DEVEL("Created debugfs entries!\n"); } void hwpa_ppe_debugfs_exit(void) { debugfs_remove_recursive(dir_entry); PR_DEVEL("Removed debugfs entries!\n"); } #else void hwpa_ppe_debugfs_init(void) { } void hwpa_ppe_debugfs_exit(void) { } #endif /* CONFIG_DEBUG_FS */