/* * Description: PP session manager debugfs interface * * SPDX-License-Identifier: GPL-2.0-only * Copyright (C) 2018-2020 Intel Corporation */ #define pr_fmt(fmt) "[PP_SESS_MGR_DBG]:%s:%d: " fmt, __func__, __LINE__ #include #include #include #include #include #include #include #include #include #include #include #include "classifier.h" #include "pp_common.h" #include "pp_debugfs_common.h" #include "pp_si.h" #include "checker.h" #include "modifier.h" #include "uc.h" #include "pp_session_mgr.h" #include "pp_session_mgr_internal.h" /** * @brief Session manager debugfs dir */ static struct dentry *dbgfs; static u32 dbg_sess_id; static unsigned long req_id; static u16 mirroring_orig_q = U16_MAX; static u16 mirroring_sess_id = U16_MAX; static void __smgr_dbg_inactive_cb(struct pp_inactive_list_cb_args *args) { u32 i, sz, n; char *buf; ulong scan_time; scan_time = get_jiffies_64() - args->base.req_id; sz = 100; /* 100 chars for misc stuff */ sz += args->n_sessions * 10; /* need 10 char to print session id */ sz += args->n_sessions * 1; /* space or new line after each session */ buf = kzalloc(sz, GFP_KERNEL); if (unlikely(!buf)) { pr_err("failed to allocate %u memory\n", sz); goto free_inact; } if (args->n_sessions == 0) { pr_buf(buf, sz, n, "No inactive Sessions - Scan time %u ms\n", jiffies_to_msecs(scan_time)); goto done; } pr_buf(buf, sz, n, "\n"); pr_buf_cat(buf, sz, n, " %u PP Inactive Sessions Found - Scan time %u ms\n", args->n_sessions, jiffies_to_msecs(scan_time)); pr_buf_cat(buf, sz, n, "===================================================\n"); for (i = 1; i <= args->n_sessions; i++) { pr_buf_cat(buf, sz, n, "%u ", args->inact_sess[i - 1]); if (!(i % 10)) pr_buf_cat(buf, sz, n, "\n"); } done: pr_info("%s", buf); kfree(buf); free_inact: kfree(args->inact_sess); } /** * @brief Debug callback for accepting session manager events * @param args event arguments */ static void __smgr_dbg_cb(struct pp_cb_args *args) { if (unlikely(ptr_is_null(args))) return; if (unlikely(!__pp_is_event_valid(args->ev))) return; pr_info("PP event %s(%u): args %p, req_id %lu, ret %d\n", PP_EVENT_STR(args->ev), args->ev, args, args->req_id, args->ret); switch (args->ev) { case PP_SESS_CREATE: { struct pp_sess_create_cb_args *cr_args; cr_args = container_of(args, struct pp_sess_create_cb_args, base); if (cr_args->base.ret == -EEXIST) { pr_info("Session exist, id %u\n", cr_args->sess_id); } else if (!cr_args->base.ret) { pr_info("Session %u created\n", cr_args->sess_id); dbg_sess_id = cr_args->sess_id; } else { pr_info("Failed to create session\n"); } break; } case PP_SESS_DELETE: { struct pp_sess_delete_cb_args *del_args; del_args = container_of(args, struct pp_sess_delete_cb_args, base); if (del_args->base.ret == -ENOENT) pr_info("Session %u not exist\n", del_args->sess_id); else if (!del_args->base.ret) pr_info("Session %u deleted\n", del_args->sess_id); else pr_info("Failed to delete session %u\n", del_args->sess_id); break; } case PP_INACTIVE_LIST: { struct pp_inactive_list_cb_args *inact_args; inact_args = container_of(args, struct pp_inactive_list_cb_args, base); if (inact_args->base.ret) pr_err("failed to get inactive sessions list\n"); else __smgr_dbg_inactive_cb(inact_args); break; } default: pr_err("Event %s not supported\n", PP_EVENT_STR(args->ev)); break; } } /** * @brief Dump all PP opened sessions */ void __smgr_dbg_sessions_dump(struct seq_file *f) { unsigned long *bmap; u32 n_sessions; s32 ret; ret = smgr_sessions_bmap_alloc(&bmap, &n_sessions); if (unlikely(ret)) return; ret = smgr_open_sessions_bmap_get(bmap, n_sessions); if (unlikely(ret)) goto done; seq_printf(f, "%*pbl\n", n_sessions, bmap); done: kfree(bmap); } PP_DEFINE_DEBUGFS(sessions, __smgr_dbg_sessions_dump, NULL); /** * @brief Set session ID to use for dumping the session info */ void __smgr_dbg_sessions_scan_state_set(char *cmd_buf, void *data) { bool en; if (kstrtobool(cmd_buf, &en)) pr_info("failed to parse '%s'\n", cmd_buf); smgr_sessions_scan_state_set(en); } /** * @brief Dump all PP inactive sessions */ void __smgr_dbg_inact_sessions_dump(struct seq_file *f) { struct pp_request req; u32 *sessions, n_sessions; s32 ret; ret = smgr_sessions_arr_alloc(&sessions, &n_sessions); if (unlikely(ret)) return; req.cb = __smgr_dbg_cb; req.req_prio = 0; req.req_id = get_jiffies_64(); ret = pp_inactive_sessions_get(&req, sessions, n_sessions); } PP_DEFINE_DEBUGFS(inact_sessions, __smgr_dbg_inact_sessions_dump, __smgr_dbg_sessions_scan_state_set); /** * @brief Set session ID to use for dumping the session info */ void __smgr_dbg_session_set(char *cmd_buf, void *data) { if (kstrtou32(cmd_buf, 10, &dbg_sess_id)) pr_info("failed to parse '%s'\n", cmd_buf); } /** * @brief Dump specific session si top data, uses session ID * that was set by xsession file */ void __smgr_dbg_si_top_dump(struct seq_file *f, struct pp_si *si) { s32 i; seq_printf(f, "\n Session %u SI Info\n", dbg_sess_id); seq_puts(f, " ==============================\n"); seq_printf(f, " %-20s: %u\n", "sess_id ", si->sess_id); seq_printf(f, " %-20s: %u\n", "recipe_idx ", si->recipe_idx); seq_printf(f, " %-20s: %#x\n", "dpu_start ", si->dpu_start); seq_printf(f, " %-20s: %#x\n", "sce_start ", si->sce_start); seq_printf(f, " %-20s: %u\n", "fv_sz ", si->fv_sz); seq_printf(f, " %-20s: %#x\n", "bce_start ", si->bce_start); seq_printf(f, " %-20s: %u\n", "bce_sz ", si->bce_sz); seq_printf(f, " %-20s: %u\n", "bce_ext ", si->bce_ext); seq_printf(f, " %-20s: %u\n", "si_ps_sz ", si->si_ps_sz); seq_printf(f, " %-20s: %u\n", "si_ud_sz ", si->si_ud_sz); seq_printf(f, " %-20s: %u\n", "ext_reassembly", si->ext_reassembly); seq_printf(f, " %-20s: %u\n", "int_reassembly", si->int_reassembly); seq_printf(f, " %-20s: %u\n", "ps_off ", si->ps_off); seq_printf(f, " %-20s: %u\n", "base_policy ", si->base_policy); seq_printf(f, " %-20s: %u\n", "color ", si->color); seq_printf(f, " %-20s: %u\n", "tdox_flow ", si->tdox_flow); seq_printf(f, " %-20s: %u\n", "dst_q ", si->dst_q); seq_printf(f, " %-20s: %u\n", "eg_port ", si->eg_port); seq_printf(f, " %-20s: %u\n", "trim_l3_id ", si->trim_l3_id); seq_printf(f, " %-20s: %#x\n", "chck_flags ", si->chck_flags); seq_printf(f, " %-20s: %u\n", "pl2p ", si->pl2p); seq_printf(f, " %-20s: %u\n", "tmpl_ud_sz ", si->tmpl_ud_sz); seq_printf(f, " %-20s: %u\n", "ps_copy ", si->ps_copy); seq_printf(f, " %-20s: %d\n", "pkt_len_diff", si->pkt_len_diff); seq_printf(f, " %-20s: %#lx\n", "sgc_en_map ", si->sgc_en_map); for_each_set_bit (i, &si->sgc_en_map, PP_SI_SGC_MAX) seq_printf(f, " sgc[%u]%-14s: %u\n", i, " ", si->sgc[i]); seq_printf(f, " %-20s: %#lx\n", "tbm_en_map ", si->tbm_en_map); for_each_set_bit (i, &si->tbm_en_map, PP_SI_TBM_MAX) seq_printf(f, " tbm[%u]%-14s: %u\n", i, " ", si->tbm[i]); seq_printf(f, " %-20s: %#x\n", "policies_map ", si->policies_map); seq_printf(f, " %-20s: %s\n", "ext_df_mask", BOOL2STR(si->ext_df_mask)); seq_printf(f, " %-20s: %s\n", "int_df_mask", BOOL2STR(si->int_df_mask)); seq_printf(f, " %-20s: %s\n", "seg_en ", BOOL2STR(si->seg_en)); seq_printf(f, " %-20s: %u\n", "fsqm_prio ", si->fsqm_prio); } /** * @brief Dump specific session si data, uses session ID * that was set by xsession file */ void __smgr_dbg_session_si_dump(struct seq_file *f) { struct pp_dsi dsi; struct pp_si si; char buf[256]; s32 i; struct sess_db_info *info; struct si_ud_frag_info *frag_info; memset(&si, 0, sizeof(si)); if (smgr_session_si_get(dbg_sess_id, &si)) return; /* Dump SI */ __smgr_dbg_si_top_dump(f, &si); if (SI_IS_DPU_EXIST(&si)) { seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_NAT_SZ), si.dpu.nat_sz); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_NHDR_SZ), si.dpu.nhdr_sz); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_NHDR_L3_OFF), si.dpu.nhdr_l3_off); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_LYR_FLD_OFF), si.dpu.lyr_fld_off); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_PPPOE_OFF), si.dpu.pppoe_off); } if (SI_IS_SCE_EXIST(&si)) { seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_L3_CSUM), si.sce.l3_csum_delta); seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_L4_CSUM), si.sce.l4_csum_delta); seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_L4_CSUM_ZERO), si.sce.l4_csum_zero); seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_NHDR_CSUM), si.sce.nhdr_csum); seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_DSCP), si.sce.dscp); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_SCE_IP_LEN_DIFF), si.sce.tot_len_diff); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_DST_PORT), si.sce.new_dst_port, si.sce.new_dst_port); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_SRC_PORT), si.sce.new_src_port, si.sce.new_src_port); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_TTL_DIFF), si.sce.ttl_diff, si.sce.ttl_diff); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_PPPOE_DIFF), si.sce.pppoe_diff, si.sce.pppoe_diff); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_L2_ORG_VAL), si.sce.l2_org_val, si.sce.l2_org_val); } if (SI_IS_BCE_EXIST(&si)) { if (si.dpu.nat_sz == sizeof(si.bce.nat.v4)) { seq_printf(f, " %-20s: %pI4b\n", "bce.nat.saddr", &si.bce.nat.v4.saddr); seq_printf(f, " %-20s: %pI4b\n", "bce.nat.daddr", &si.bce.nat.v4.daddr); } else if (si.dpu.nat_sz == sizeof(si.bce.nat.v6)) { seq_printf(f, " %-20s: %pI6\n", "bce.nat.saddr", &si.bce.nat.v6.saddr); seq_printf(f, " %-20s: %pI6\n", "bce.nat.daddr", &si.bce.nat.v6.daddr); } hex_dump_to_buffer(si.bce.nhdr, si.dpu.nhdr_sz, 32, 1, buf, sizeof(buf), false); (void)strreplace(buf, '\n', ' '); seq_printf(f, " %-20s: %s\n", "New Header", buf); } if (si.si_ud_sz || si.si_ps_sz) { hex_dump_to_buffer(si.ud, max_t(u8, si.si_ud_sz, si.si_ps_sz), 16, 1, buf, sizeof(buf), false); (void)strreplace(buf, '\n', ' '); seq_printf(f, " %-20s: %s\n", "UD", buf); info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return; if (smgr_session_info_get(dbg_sess_id, info)) { kfree(info); return; } if (test_bit(SESS_FLAG_MTU_CHCK, &info->flags)) { frag_info = (struct si_ud_frag_info *)&si.ud[PP_PS_REGION_SZ]; seq_printf(f, " %-20s: %u (INT_DF %d (IGNORE %d), EXT_DF %d (IGNORE %d), FRAG_EXT %d, IPV4 %d, PPPOE %d)\n", "frag.flags", frag_info->flags, !!(frag_info->flags & FRAG_INFO_FLAG_INT_DF), !!(frag_info->flags & FRAG_INFO_FLAG_IGNORE_INT_DF), !!(frag_info->flags & FRAG_INFO_FLAG_EXT_DF), !!(frag_info->flags & FRAG_INFO_FLAG_IGNORE_EXT_DF), !!(frag_info->flags & FRAG_INFO_FLAG_FRAG_EXT), !!(frag_info->flags & FRAG_INFO_FLAG_IPV4), !!(frag_info->flags & FRAG_INFO_FLAG_PPPOE)); seq_printf(f, " %-20s: %u\n", "frag.l3_off", frag_info->l3_off); seq_printf(f, " %-20s: %u\n", "frag.dst_q", frag_info->dst_q); seq_printf(f, " %-20s: %u\n", "frag.max_pkt_size", frag_info->max_pkt_size); kfree(info); } } for (i = 0; i < (sizeof(si.fv) / sizeof(u32)); i++) seq_printf(f, " FV WORD%-13u: %#010x\n", i, ((u32 *)(&si.fv))[i]); if (smgr_session_dsi_get(dbg_sess_id, &dsi)) return; seq_printf(f, "\n Session %u DSI Info\n", dbg_sess_id); seq_puts(f, " ==============================\n"); seq_printf(f, " %-20s: %s\n", "valid", BOOL2STR(dsi.valid)); seq_printf(f, " %-20s: %s\n", "active", BOOL2STR(dsi.active)); seq_printf(f, " %-20s: %s\n", "stale", BOOL2STR(dsi.stale)); seq_printf(f, " %-20s: %s\n", "divert", BOOL2STR(dsi.divert)); seq_printf(f, " %-20s: %u\n", "dst_q", dsi.dst_q); seq_printf(f, " %-20s: %llu\n", "bytes", dsi.bytes_cnt); seq_printf(f, " %-20s: %llu\n", "packets", dsi.pkts_cnt); seq_puts(f, "\n"); } PP_DEFINE_DEBUGFS(session_si, __smgr_dbg_session_si_dump, NULL); /** * @brief Dump specific exception session si data, uses session * ID that was set by xsession file */ void __smgr_dbg_exception_session_si_dump(struct seq_file *f) { struct pp_si si; s32 ret; memset(&si, 0, sizeof(si)); ret = chk_exception_session_si_get(dbg_sess_id, &si); if (unlikely(ret)) { pr_err("Failed fetching SI for exception %u\n", dbg_sess_id); return; } /* Dump SI */ __smgr_dbg_si_top_dump(f, &si); } PP_DEFINE_DEBUGFS(exception_session_si, __smgr_dbg_exception_session_si_dump, NULL); /** * @brief Dump fragmentation stats */ void __smgr_dbg_frag_stats(struct seq_file *f) { struct frag_stats stats[UC_CPUS_MAX], *it; s32 ret; u32 cid, i; char **str; static const char *const cntrs_str[] = { "rx_pkt", "tx_pkt", "total_drops", "bmgr_drops", "df_drops", "max_frags_drops", }; for (cid = 0; cid < UC_CPUS_MAX; cid++) { ret = uc_frag_cpu_stats_get(cid, &stats[cid]); if (unlikely(ret)) { pr_err("failed to get frag uc cpu %u counters\n", cid); return; } } seq_puts(f, "\n"); seq_puts(f, "|=====================================================================|\n"); seq_puts(f, "| Fragmentation UC Statistics |\n"); seq_puts(f, "|=====================================================================|\n"); seq_printf(f, "| %-15s ", "Counter"); for (cid = 0; cid < UC_CPUS_MAX; cid++) seq_printf(f, "| CPU%u ", cid); seq_puts(f, "|\n"); seq_puts(f, "|-----------------+------------+------------+------------+------------|\n"); i = 0; for_each_arr_entry(str, cntrs_str, ARRAY_SIZE(cntrs_str), i++) { seq_printf(f, "| %-15s ", *str); for_each_arr_entry(it, stats, ARRAY_SIZE(stats)) { seq_printf(f, "| %10llu ", *(((u64 *)it) + i)); } seq_puts(f, "|\n"); } seq_puts(f, "|---------------------------------------------------------------------|\n\n"); } PP_DEFINE_DEBUGFS(frag_stats, __smgr_dbg_frag_stats, NULL); /** * @brief Dump fragmentation stats */ void __smgr_dbg_tdox_stats(struct seq_file *f) { struct smgr_tdox_stats tdox_stats; s32 ret; ret = smgr_tdox_stats_get(&tdox_stats); if (ret) return; seq_puts(f, "\n"); seq_puts(f, "|==============================|\n"); seq_puts(f, "| Tdox Statistics |\n"); seq_puts(f, "|==============================|\n"); seq_printf(f, "| %-15s ", "uC Stats"); seq_puts(f, "|\n"); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", " uC Rx "); seq_printf(f, "| %10u |\n", tdox_stats.uc_rx_pkt); seq_printf(f, "| %-15s ", " uC Tx "); seq_printf(f, "| %10u |\n", tdox_stats.uc_tx_pkt); seq_puts(f, "|------------------------------|\n"); seq_printf(f, "| %-15s ", "Entry Stats"); seq_puts(f, "|\n"); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", " Free Entries "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_sess_free); seq_printf(f, "| %-15s ", " Free Cand "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_free_candidates); seq_puts(f, "|------------------------------|\n"); seq_printf(f, "| %-15s ", "Session Stats"); seq_puts(f, "|\n"); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", " Tdox Full "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_sess_full_fail); seq_printf(f, "| %-15s ", " TdoxCand Full "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_candidate_full_fail); seq_printf(f, "| %-15s ", " Create Fail "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_create_args_err); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", "Lists Stats"); seq_puts(f, "|\n"); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", " free "); seq_printf(f, "| %10u |\n", tdox_stats.free_list_cnt); seq_printf(f, "| %-15s ", " busy "); seq_printf(f, "| %10u |\n", tdox_stats.busy_list_cnt); seq_printf(f, "| %-15s ", " obsolete "); seq_printf(f, "| %10u |\n", tdox_stats.obsolete_list_cnt); seq_printf(f, "| %-15s ", " cand_free "); seq_printf(f, "| %10u |\n", tdox_stats.cand_free_list_cnt); seq_printf(f, "| %-15s ", " cand_busy "); seq_printf(f, "| %10u |\n", tdox_stats.cand_busy_list_cnt); seq_printf(f, "| %-15s ", " update_free "); seq_printf(f, "| %10u |\n", tdox_stats.sess_update_free_list_cnt); seq_printf(f, "| %-15s ", " update_busy "); seq_printf(f, "| %10u |\n", tdox_stats.sess_update_busy_list_cnt); seq_puts(f, "|------------------------------|\n"); } PP_DEFINE_DEBUGFS(tdox_stats, __smgr_dbg_tdox_stats, NULL); static int __smgr_dbg_tdox_en_set(void *data, u64 val) { smgr_tdox_enable_set(val); return 0; } static int __smgr_dbg_tdox_en_get(void *data, u64 *val) { u32 tout; tout = smgr_tdox_enable_get(); *val = (u64)tout; return 0; } PP_DEFINE_DBGFS_ATT(tdox_en_fops, __smgr_dbg_tdox_en_get, __smgr_dbg_tdox_en_set); /** * @brief Dump specific session si and dsi raw data, uses session ID * that was set by xsession file */ void __smgr_dbg_session_si_raw_dump(struct seq_file *f) { struct pp_hw_dsi hw_dsi; struct pp_hw_si hw_si; u32 sess_id; s32 ret, i; memset(&hw_si, 0, sizeof(hw_si)); memset(&hw_dsi, 0, sizeof(hw_dsi)); ret = cls_session_si_get(dbg_sess_id, &hw_si); if (ret) return; ret = chk_session_dsi_get(dbg_sess_id, &hw_dsi); if (ret) return; ret = pp_si_fld_get(&hw_si, SI_FLD_SESS_ID, (s32 *)&sess_id); if (ret) return; seq_printf(f, "\n Session %u SI Info\n", sess_id); seq_puts(f, " =========================\n"); for (i = 0; i < ARRAY_SIZE(hw_si.word); i++) seq_printf(f, " SI WORD%-4u(%#4x): %#010x\n", i, i * (u32)sizeof(u32), hw_si.word[i]); for (i = 0; i < ARRAY_SIZE(hw_dsi.word); i++) seq_printf(f, " DSI WORD%-3u(%#4x): %#010x\n", i, i * (u32)sizeof(u32), hw_dsi.word[i]); seq_puts(f, "\n"); } PP_DEFINE_DEBUGFS(session_si_raw, __smgr_dbg_session_si_raw_dump, NULL); static void __smgr_pr_session_flags(struct seq_file *f, ulong flags) { const char *flags_str[SMGR_FLAGS_NUM] = { "ROUTED", "SYNCQ", "MTU_CHECK", "MCAST_GRP", "MCAST_DST", "SESS_FLAG_TDOX", "SESS_FLAG_TDOX_SUPP", }; u32 flag; if (!flags) return; seq_printf(f, " %-20s = %#lx ", "Flags", flags); for_each_set_bit (flag, &flags, SMGR_FLAGS_NUM) seq_printf(f, "[%s]", flags_str[flag]); seq_puts(f, "\n"); } static void __smgr_pr_si_chck_flags(struct seq_file *f, ulong flags) { u32 flag; if (!flags) return; seq_printf(f, " %-20s = %#lx ", "Checker Flags", flags); for_each_set_bit (flag, &flags, SI_CHCK_FLAGS_NUM) seq_printf(f, "[%s]", pp_si_chck_flag_to_str(flag)); seq_puts(f, "\n"); } static void __smgr_pr_mac(struct seq_file *f, struct pktprs_hdr *h, u8 lvl) { if (unlikely(!h)) return; if (PKTPRS_IS_MAC(h, lvl)) { seq_printf(f, " %-20s = %u\n", "ETH header Off", pktprs_hdr_off(h, PKTPRS_PROTO_MAC, lvl)); seq_printf(f, " %-20s = %pM\n", "Source MAC", pktprs_eth_hdr(h, lvl)->h_source); seq_printf(f, " %-20s = %pM\n", "Dest MAC", pktprs_eth_hdr(h, lvl)->h_dest); seq_printf(f, " %-20s = %s %u[%#x]\n", "Ether Type", PP_FV_ETHTYPE_STR(pktprs_eth_hdr(h, lvl)->h_proto), ntohs(pktprs_eth_hdr(h, lvl)->h_proto), ntohs(pktprs_eth_hdr(h, lvl)->h_proto)); } if (PKTPRS_IS_VLAN0(h, lvl)) { seq_printf(f, " %-20s = %u\n", "VLAN header Off", pktprs_hdr_off(h, PKTPRS_PROTO_VLAN0, lvl)); seq_printf(f, " %-20s = %u[%#x]\n", "External VLAN", ntohs(pktprs_vlan_hdr(h, lvl, 0)->h_vlan_TCI), ntohs(pktprs_vlan_hdr(h, lvl, 0)->h_vlan_TCI)); } if (PKTPRS_IS_VLAN1(h, lvl)) { seq_printf(f, " %-20s = %u\n", "VLAN header Off", pktprs_hdr_off(h, PKTPRS_PROTO_VLAN1, lvl)); seq_printf(f, " %-20s = %u[%#x]\n", "Internal VLAN", ntohs(pktprs_vlan_hdr(h, lvl, 1)->h_vlan_TCI), ntohs(pktprs_vlan_hdr(h, lvl, 1)->h_vlan_TCI)); } if (PKTPRS_IS_PPPOE(h, lvl)) { seq_printf(f, " %-20s = %u\n", "PPPOE header Off", pktprs_hdr_off(h, PKTPRS_PROTO_PPPOE, lvl)); seq_printf(f, " %-20s = %u[%#x]\n", "PPPoE ID", ntohs(pktprs_pppoe_hdr(h, lvl)->sid), ntohs(pktprs_pppoe_hdr(h, lvl)->sid)); } } static void __smgr_pr_ipv4(struct seq_file *f, struct pktprs_hdr *h, u8 lvl) { struct iphdr *v4 = pktprs_ipv4_hdr(h, lvl); if (unlikely(!v4)) return; seq_printf(f, " %-20s = %u\n", "IPV4 header Off", pktprs_hdr_off(h, PKTPRS_PROTO_IPV4, lvl)); seq_printf(f, " %-20s = %pI4b[%#x]\n", "Source IP", &v4->saddr, ntohl(v4->saddr)); seq_printf(f, " %-20s = %pI4b[%#x]\n", "Dest IP", &v4->daddr, ntohl(v4->daddr)); seq_printf(f, " %-20s = %s %u[%#x]\n", "L4 Protocol", PP_FV_L3_PROTOCOL_STR(v4->protocol), v4->protocol, v4->protocol); seq_printf(f, " %-20s = %u[%#x]\n", "TOS", v4->tos, v4->tos); if (pktprs_ipv4_first_frag(h, lvl)) seq_printf(f, " %-20s = %s\n", "Frag", "First"); else if (ip_is_fragment(v4)) seq_printf(f, " %-20s = %s\n", "Frag", "None-First"); } static void __smgr_pr_ipv6(struct seq_file *f, struct pktprs_hdr *h, u8 lvl) { struct ipv6hdr *v6 = pktprs_ipv6_hdr(h, lvl); u32 flow = 0; u8 tc = 0; if (unlikely(!v6)) return; tc = PP_FIELD_GET(GENMASK(7, 4), v6->flow_lbl[0]); tc = PP_FIELD_MOD(GENMASK(7, 4), v6->priority, tc); flow = PP_FIELD_MOD(GENMASK(19, 16), v6->flow_lbl[0] & 0x0f, flow); flow = PP_FIELD_MOD(GENMASK(15, 8), v6->flow_lbl[1], flow); flow = PP_FIELD_MOD(GENMASK(7, 0), v6->flow_lbl[2], flow); seq_printf(f, " %-20s = %u\n", "IPV6 header Off", pktprs_hdr_off(h, PKTPRS_PROTO_IPV6, lvl)); seq_printf(f, " %-20s = %pI6\n", "Source IP", &v6->saddr); seq_printf(f, " %-20s = %pI6\n", "Dest IP", &v6->daddr); seq_printf(f, " %-20s = %s %u[%#x]\n", "Next Header", PP_FV_L3_PROTOCOL_STR(v6->nexthdr), v6->nexthdr, v6->nexthdr); seq_printf(f, " %-20s = %u[%#x]\n", "TC", tc, tc); seq_printf(f, " %-20s = %u[%#x]\n", "Flow Label", flow, flow); if (PKTPRS_IS_FRAG_OPT(h, lvl)) { seq_printf(f, " %-20s = %u\n", "IPV6 FRAG header Off", pktprs_hdr_off(h, PKTPRS_PROTO_FRAG_OPT, lvl)); if (pktprs_ipv6_first_frag(h, lvl)) seq_printf(f, " %-20s = %s\n", "Frag", "First"); else if (pktprs_frag_opt_hdr(h, lvl)->frag_off & htons(IP6_OFFSET)) seq_printf(f, " %-20s = %s\n", "Frag", "None-First"); } } static void __smgr_pr_l3(struct seq_file *f, struct pktprs_hdr *h, u8 lvl) { if (unlikely(!h)) return; if (PKTPRS_IS_IPV4(h, lvl)) __smgr_pr_ipv4(f, h, lvl); else if (PKTPRS_IS_IPV6(h, lvl)) __smgr_pr_ipv6(f, h, lvl); } static void __smgr_pr_l4(struct seq_file *f, struct pktprs_hdr *h, u8 lvl) { union proto_ptr p; if (unlikely(!h)) return; if (PKTPRS_IS_TCP(h, lvl)) { seq_printf(f, " %-20s = %u\n", "TCP header Off", pktprs_hdr_off(h, PKTPRS_PROTO_TCP, lvl)); p.tcp = pktprs_tcp_hdr(h, lvl); seq_printf(f, " %-20s = %u[%#x]\n", "TCP Source Port", ntohs(p.tcp->source), ntohs(p.tcp->source)); seq_printf(f, " %-20s = %u[%#x]\n", "TCP Dest Port", ntohs(p.tcp->dest), ntohs(p.tcp->dest)); } else if (PKTPRS_IS_UDP(h, lvl)) { seq_printf(f, " %-20s = %u\n", "UDP header Off", pktprs_hdr_off(h, PKTPRS_PROTO_UDP, lvl)); p.udp = pktprs_udp_hdr(h, lvl); seq_printf(f, " %-20s = %u[%#x]\n", "UDP Source Port", ntohs(p.udp->source), ntohs(p.udp->source)); seq_printf(f, " %-20s = %u[%#x]\n", "UDP Dest Port", ntohs(p.udp->dest), ntohs(p.udp->dest)); } else if (PKTPRS_IS_SCTP(h, lvl)) { seq_printf(f, " %-20s = %u\n", "SCTP header Off", pktprs_hdr_off(h, PKTPRS_PROTO_SCTP, lvl)); p.sctp = pktprs_sctp_hdr(h, lvl); seq_printf(f, " %-20s = %u[%#x]\n", "SCTP Source Port", ntohs(p.sctp->source), ntohs(p.sctp->source)); seq_printf(f, " %-20s = %u[%#x]\n", "SCTP Dest Port", ntohs(p.sctp->dest), ntohs(p.sctp->dest)); } else if (PKTPRS_IS_ICMP(h, lvl)) { seq_printf(f, " %-20s = %u\n", "ICMP header Off", pktprs_hdr_off(h, PKTPRS_PROTO_ICMP, lvl)); p.icmp = pktprs_icmp_hdr(h, lvl); seq_printf(f, " %-20s = %u[%#x]\n", "ICMP ID", ntohs(p.icmp->un.echo.id), ntohs(p.icmp->un.echo.id)); seq_printf(f, " %-20s = %u[%#x]\n", "ICMP Type", p.icmp->type, p.icmp->type); } else if (PKTPRS_IS_ICMP6(h, lvl)) { seq_printf(f, " %-20s = %u\n", "ICMP6 header Off", pktprs_hdr_off(h, PKTPRS_PROTO_ICMP6, lvl)); p.icmp6 = pktprs_icmp6_hdr(h, lvl); seq_printf(f, " %-20s = %u[%#x]\n", "ICMP6 ID", ntohs(p.icmp6->icmp6_dataun.u_echo.identifier), ntohs(p.icmp6->icmp6_dataun.u_echo.identifier)); seq_printf(f, " %-20s = %u[%#x]\n", "ICMP6 Type", pktprs_icmp6_hdr(h, lvl)->icmp6_type, pktprs_icmp6_hdr(h, lvl)->icmp6_type); } else if (PKTPRS_IS_ESP(h, lvl)) { seq_printf(f, " %-20s = %u\n", "ESP header Off", pktprs_hdr_off(h, PKTPRS_PROTO_ESP, lvl)); p.esp = pktprs_esp_hdr(h, lvl); seq_printf(f, " %-20s = %u[%#x]\n", "ESP SPI", ntohl(p.esp->spi), ntohl(p.esp->spi)); } } static void __smgr_pr_tunn(struct seq_file *f, struct pktprs_hdr *h, u8 lvl) { union proto_ptr p; if (unlikely(!h)) return; seq_printf(f, " %-20s = ", "Tunnel Type"); if (PKTPRS_IS_PPPOE(h, lvl)) seq_puts(f, "[PPPoE]"); if (PKTPRS_IS_L2TP_OUDP(h, lvl)) seq_puts(f, "[UDP][L2TP]"); if (PKTPRS_IS_VXLAN(h, lvl)) seq_puts(f, "[UDP][VXLAN]"); if (PKTPRS_IS_GENEVE(h, lvl)) seq_puts(f, "[UDP][GENEVE]"); if (PKTPRS_IS_SCTP(h, lvl)) seq_puts(f, "[SCTP]"); if (PKTPRS_IS_L2TP_OIP(h, lvl)) seq_puts(f, "[L2TPIP]"); if (PKTPRS_IS_IP_GRE(h)) seq_puts(f, "[IPoGRE]"); if (PKTPRS_IS_L2_GRE(h)) seq_puts(f, "[EoGRE]"); if (PKTPRS_IS_DSLITE(h)) seq_puts(f, "[DSLITE]"); if (PKTPRS_IS_SIXRD(h)) seq_puts(f, "[SIXRD]"); seq_puts(f, "\n"); if (PKTPRS_IS_VXLAN(h, lvl)) { seq_printf(f, " %-20s = %u\n", "VXLAN header Off", pktprs_hdr_off(h, PKTPRS_PROTO_VXLAN, lvl)); p.vxlan = pktprs_vxlan_hdr(h, lvl); seq_printf(f, " %-20s = %u[%#x]\n", "VNI", ntohl(p.vxlan->vx_flags), ntohl(p.vxlan->vx_flags)); } else if (PKTPRS_IS_GENEVE(h, lvl)) { seq_printf(f, " %-20s = %u\n", "GENEVE header Off", pktprs_hdr_off(h, PKTPRS_PROTO_GENEVE, lvl)); p.geneve = pktprs_geneve_hdr(h, lvl); seq_printf(f, " %-20s = %#02x%02x%02x\n", "VNI", p.geneve->vni[2], p.geneve->vni[1], p.geneve->vni[0]); } else if (PKTPRS_IS_L2TP_OIP(h, lvl)) { seq_printf(f, " %-20s = %u\n", "L2TP_OIP header Off", pktprs_hdr_off(h, PKTPRS_PROTO_L2TP_OIP, lvl)); p.l2tp = pktprs_l2tp_oip_hdr(h, lvl); seq_printf(f, " %-20s = %u[%#x]\n", "Session ID", ntohl(p.l2tp->v3_oip.sess_id), ntohl(p.l2tp->v3_oip.sess_id)); } else if (PKTPRS_IS_L2TP_OUDP(h, lvl)) { seq_printf(f, " %-20s = %u\n", "L2TP_OUDP header Off", pktprs_hdr_off(h, PKTPRS_PROTO_L2TP_OUDP, lvl)); p.l2tp = pktprs_l2tp_oudp_hdr(h, lvl); if ((p.l2tp->v2.flags & L2TP_HDR_VER_MASK) == L2TP_HDR_VER_2) { if (p.l2tp->v3_oudp.flags & L2TP_HDRFLAG_L) { seq_printf(f, " %-20s = %u[%#x]\n", "Session ID", p.l2tp->v2_len.sess_id, p.l2tp->v2_len.sess_id); seq_printf(f, " %-20s = %u[%#x]\n", "Tunnel ID", p.l2tp->v2_len.tunnel, p.l2tp->v2_len.tunnel); } else { seq_printf(f, " %-20s = %u[%#x]\n", "Session ID", p.l2tp->v2.sess_id, p.l2tp->v2.sess_id); seq_printf(f, " %-20s = %u[%#x]\n", "Tunnel ID", p.l2tp->v2.tunnel, p.l2tp->v2.tunnel); } } else { seq_printf(f, " %-20s = %u[%#x]\n", "Session ID", p.l2tp->v3_oudp.sess_id, p.l2tp->v3_oudp.sess_id); } } } static void __smgr_pr_pkt(struct seq_file *f, struct pktprs_hdr *h) { if (unlikely(!h)) return; seq_printf(f, " %-20s = %u\n", "Header Length", h->buf_sz); __smgr_pr_mac(f, h, HDR_OUTER); __smgr_pr_l3(f, h, HDR_OUTER); __smgr_pr_l4(f, h, HDR_OUTER); __smgr_pr_tunn(f, h, HDR_OUTER); __smgr_pr_mac(f, h, HDR_INNER); __smgr_pr_l3(f, h, HDR_INNER); __smgr_pr_l4(f, h, HDR_INNER); } static void __smgr_pr_sess_mod(struct seq_file *f, ulong mod_flags, struct pp_si *si) { char buf[256]; u32 flag; if (unlikely(!si)) return; if (!(SI_IS_SCE_EXIST(si) || SI_IS_DPU_EXIST(si))) return; seq_puts(f, " Modification Record\n"); seq_puts(f, "=====================\n"); seq_printf(f, " %-20s = %#lx ", "Modification Flags", mod_flags); for_each_set_bit (flag, &mod_flags, MOD_FLAG_NUM) seq_printf(f, "[%s]", mod_flag_to_str(flag)); seq_puts(f, "\n"); if (SI_IS_DPU_EXIST(si)) { seq_printf(f, " %-20s = %u[%#x]\n", "NAT Size", si->dpu.nat_sz, si->dpu.nat_sz); seq_printf(f, " %-20s = %u[%#x]\n", "New Header Size", si->dpu.nhdr_sz, si->dpu.nhdr_sz); seq_printf(f, " %-20s = %u[%#x]\n", "New Header L3 Offset", si->dpu.nhdr_l3_off, si->dpu.nhdr_l3_off); seq_printf(f, " %-20s = %u[%#x]\n", "Layer Field Offset", si->dpu.lyr_fld_off, si->dpu.lyr_fld_off); seq_printf(f, " %-20s = %u[%#x]\n", "PPPoE Offset", si->dpu.pppoe_off, si->dpu.pppoe_off); } if (si->dpu.nhdr_sz) { hex_dump_to_buffer(si->bce.nhdr, si->dpu.nhdr_sz, 32, 4, buf, sizeof(buf), false); (void)strreplace(buf, '\n', ' '); seq_printf(f, " %-20s = %s\n", "New Header", buf); } if (si->dpu.nat_sz == sizeof(si->bce.nat.v4)) { seq_printf(f, " %-20s = %pI4b[%#x]\n", "Source IP", &si->bce.nat.v4.saddr, si->bce.nat.v4.saddr); seq_printf(f, " %-20s = %pI4b[%#x]\n", "Dest IP", &si->bce.nat.v4.daddr, si->bce.nat.v4.daddr); } else if (si->dpu.nat_sz == sizeof(si->bce.nat.v6)) { seq_printf(f, " %-20s = %pI6\n", "Source IP", &si->bce.nat.v6.saddr); seq_printf(f, " %-20s = %pI6\n", "Dest IP", &si->bce.nat.v6.daddr); } if (SI_IS_SCE_EXIST(si)) { seq_printf(f, " %-20s = %u[%#x]\n", "Source Port", si->sce.new_src_port, si->sce.new_src_port); seq_printf(f, " %-20s = %u[%#x]\n", "Dest Port", si->sce.new_dst_port, si->sce.new_dst_port); seq_printf(f, " %-20s = %#x\n", "L3 Checksum Delta", si->sce.l3_csum_delta); seq_printf(f, " %-20s = %#x\n", "L4 Checksum Delta", si->sce.l4_csum_delta); seq_printf(f, " %-20s = %#x\n", "New Header Checksum", si->sce.nhdr_csum); seq_printf(f, " %-20s = %#x\n", "TOS", si->sce.dscp); seq_printf(f, " %-20s = %d\n", "Packet Length Diff", si->pkt_len_diff); seq_printf(f, " %-20s = %d\n", "IP Length Diff", si->sce.tot_len_diff); seq_printf(f, " %-20s = %u\n", "TTL/Hop Limit Diff", si->sce.ttl_diff); seq_printf(f, " %-20s = %u\n", "PPPoE Diff", si->sce.pppoe_diff); } } /** * @brief Dump specific session info including packets and bytes * counters */ void __smgr_dbg_session_dump(struct seq_file *f) { struct sess_db_info *info; struct pp_dsi dsi; struct pp_si si; char buf[128]; s32 n; memset(&si, 0, sizeof(si)); memset(&dsi, 0, sizeof(dsi)); info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return; if (smgr_session_info_get(dbg_sess_id, info)) goto done; if (smgr_session_si_get(dbg_sess_id, &si)) goto done; if (smgr_session_dsi_get(dbg_sess_id, &dsi)) goto done; pr_buf(buf, sizeof(buf), n, "Session %u Info", info->sess_id); seq_puts(f, "##############################\n"); seq_printf(f, "## %-22s ##\n", buf); seq_puts(f, "##############################\n"); seq_printf(f, " %-20s = %s\n", "Valid", BOOL2STR(dsi.valid)); seq_printf(f, " %-20s = %s\n", "Active", BOOL2STR(dsi.active)); seq_printf(f, " %-20s = %s\n", "Stale", BOOL2STR(dsi.stale)); seq_printf(f, " %-20s = %s\n", "Type", smgr_is_sess_routed(info) ? "Routed" : "Bridge"); seq_printf(f, " %-20s = %s\n", "Divert", BOOL2STR(dsi.divert)); __smgr_pr_session_flags(f, info->flags); seq_printf(f, " %-20s = %u - %s\n", "Recipe", si.recipe_idx, mod_rcp_to_str(si.recipe_idx)); seq_printf(f, " %-20s = %u - %s\n", "Color", si.color, PP_COLOR_TO_STR(si.color)); seq_printf(f, " %-20s = %u\n", "FV Size", si.fv_sz); seq_printf(f, " %-20s = %u\n", "TDOX Flow/LRO Info", si.tdox_flow); __smgr_pr_si_chck_flags(f, si.chck_flags); seq_puts(f, "\n"); seq_puts(f, " Stats\n"); seq_puts(f, "=======\n"); seq_printf(f, " %-20s = %llu\n", "Packets", dsi.pkts_cnt); seq_printf(f, " %-20s = %llu\n", "Bytes", dsi.bytes_cnt); seq_puts(f, "\n"); seq_puts(f, " Ingress Packet\n"); seq_puts(f, "================\n"); seq_printf(f, " %-20s = %u\n", "Port", info->in_port); __smgr_pr_pkt(f, &info->rx); seq_puts(f, "\n"); seq_puts(f, " Egress Packet\n"); seq_puts(f, "===============\n"); seq_printf(f, " %-20s = %u\n", "Port", si.eg_port); seq_printf(f, " %-20s = %u\n", "Dest Q", si.dst_q); seq_printf(f, " %-20s = %u\n", "Dynamic Dest Q", dsi.dst_q); __smgr_pr_pkt(f, &info->tx); seq_puts(f, "\n"); __smgr_pr_sess_mod(f, info->mod_flags, &si); seq_puts(f, "\n"); seq_puts(f, " Hash\n"); seq_puts(f, "======\n"); seq_printf(f, " %-20s = %#x\n", "H1", info->hash.h1); seq_printf(f, " %-20s = %#x\n", "H2", info->hash.h2); seq_printf(f, " %-20s = %#x\n", "Signature", info->hash.sig); seq_puts(f, "\n"); if (smgr_is_sess_mcast_dst(info) || smgr_is_sess_mcast_grp(info)) { seq_puts(f, " Multicast\n"); seq_puts(f, "==========\n"); seq_printf(f, " %-20s = %#x\n", "Group-ID", info->mcast.grp_idx); if (smgr_is_sess_mcast_dst(info)) { seq_printf(f, " %-20s = %#x\n", "Dest-ID", info->mcast.dst_idx); } seq_puts(f, "\n"); } done: kfree(info); } PP_DEFINE_DEBUGFS(session, __smgr_dbg_session_dump, __smgr_dbg_session_set); void __smgr_dbg_stats_dump(struct seq_file *f) { struct smgr_stats stats; u32 n_sessions; if (pp_max_sessions_get(&n_sessions)) return; memset(&stats, 0, sizeof(stats)); if (pp_smgr_stats_get(&stats)) return; seq_puts(f, " +---------------------------------------------------------------------------------------+\n"); seq_puts(f, " | Session Manager Statistics |\n"); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Max Supported Sessions", n_sessions, "Free Sessions", atomic_read(&stats.sess_free)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Open Sessions", atomic_read(&stats.sess_open), "Open Sessions High Watermark", atomic_read(&stats.sess_open_hi_wm)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Session Create Requests", atomic_read(&stats.sess_create_req), "Sessions Created", atomic_read(&stats.sess_created)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Session Delete Requests", atomic_read(&stats.sess_delete_req), "Deleted Sessions", atomic_read(&stats.sess_deleted)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Port Flush Requests", atomic_read(&stats.port_flush_req), "Ports Flushed", atomic_read(&stats.port_flushed)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Flush All Requests", atomic_read(&stats.flush_all_req), "Flush All Done", atomic_read(&stats.flush_all_done)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Inactive Sessions Request", atomic_read(&stats.inactive_req), "Inactive Sessions Req Done", atomic_read(&stats.inactive_done)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Lookup Success", atomic_read(&stats.sess_lu_succ), "Lookup Fail", atomic_read(&stats.sess_lu_fail)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10s |\n", "Wait for Crawler Idle", atomic_read(&stats.crwlr_idle_wait), "", ""); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_puts(f, " | Errors |\n"); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Session Create Fail", atomic_read(&stats.sess_create_fail), "Session Delete Fail", atomic_read(&stats.sess_delete_fail)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Port Flush Fail", atomic_read(&stats.port_flush_fail), "Flush All Fail", atomic_read(&stats.flush_all_fail)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10s |\n", "Inactive Sessions Req Fail", atomic_read(&stats.inactive_fail), "", ""); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_puts(f, " | Error Cause |\n"); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Invalid Arguments", atomic_read(&stats.invalid_args), "Lookup Error", atomic_read(&stats.sess_lookup_err)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Unsupported Protocols", atomic_read(&stats.sess_not_supported), "SI Error", atomic_read(&stats.sess_si_create_err)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Cache Error", atomic_read(&stats.work_args_cache_err), "HW Error", atomic_read(&stats.hw_err)); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_puts(f, "\n"); } void __smgr_dbg_stats_reset(char *cmd_buf, void *data) { if (!strncmp(cmd_buf, "0", strlen("0"))) pp_smgr_stats_reset(); } PP_DEFINE_DEBUGFS(stats, __smgr_dbg_stats_dump, __smgr_dbg_stats_reset); enum sess_del_opts { sess_del_opt_help = 1, sess_del_opt_id, sess_del_opt_prio, sess_del_opt_async, }; static const match_table_t sess_del_tokens = { { sess_del_opt_help, "help" }, { sess_del_opt_id, "id=%u" }, { sess_del_opt_prio, "prio=%u" }, { sess_del_opt_async, "async" }, }; /** * @brief Session delete help */ static void __smgr_dbg_sess_del_help(void) { pr_info("\n"); pr_info(" Usage: echo