blob: e544856ed50fcee4d196bb9bceb00d2a6670cea3 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**************************************************************************
*/
#include "nss_core.h"
#include "nss_ppe.h"
#include "nss_ppe_stats.h"
#include "nss_ppe_strings.h"
/*
* Declare atomic notifier data structure for statistics.
*/
ATOMIC_NOTIFIER_HEAD(nss_ppe_stats_notifier);
static uint8_t ppe_cc_nonexception[NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX] = {
NSS_PPE_STATS_CPU_CODE_EXP_FAKE_L2_PROT_ERR,
NSS_PPE_STATS_CPU_CODE_EXP_FAKE_MAC_HEADER_ERR,
NSS_PPE_STATS_CPU_CODE_EXP_BITMAP_MAX,
NSS_PPE_STATS_CPU_CODE_L2_EXP_MRU_FAIL,
NSS_PPE_STATS_CPU_CODE_L2_EXP_MTU_FAIL,
NSS_PPE_STATS_CPU_CODE_L3_EXP_IP_PREFIX_BC,
NSS_PPE_STATS_CPU_CODE_L3_EXP_MTU_FAIL,
NSS_PPE_STATS_CPU_CODE_L3_EXP_MRU_FAIL,
NSS_PPE_STATS_CPU_CODE_L3_EXP_ICMP_RDT,
NSS_PPE_STATS_CPU_CODE_L3_EXP_IP_RT_TTL1_TO_ME,
NSS_PPE_STATS_CPU_CODE_L3_EXP_IP_RT_TTL_ZERO,
NSS_PPE_STATS_CPU_CODE_L3_FLOW_SERVICE_CODE_LOOP,
NSS_PPE_STATS_CPU_CODE_L3_FLOW_DE_ACCELERATE,
NSS_PPE_STATS_CPU_CODE_L3_EXP_FLOW_SRC_IF_CHK_FAIL,
NSS_PPE_STATS_CPU_CODE_L3_FLOW_SYNC_TOGGLE_MISMATCH,
NSS_PPE_STATS_CPU_CODE_L3_EXP_MTU_DF_FAIL,
NSS_PPE_STATS_CPU_CODE_L3_EXP_PPPOE_MULTICAST,
NSS_PPE_STATS_CPU_CODE_MGMT_OFFSET,
NSS_PPE_STATS_CPU_CODE_MGMT_EAPOL,
NSS_PPE_STATS_CPU_CODE_MGMT_PPPOE_DIS,
NSS_PPE_STATS_CPU_CODE_MGMT_IGMP,
NSS_PPE_STATS_CPU_CODE_MGMT_ARP_REQ,
NSS_PPE_STATS_CPU_CODE_MGMT_ARP_REP,
NSS_PPE_STATS_CPU_CODE_MGMT_DHCPv4,
NSS_PPE_STATS_CPU_CODE_MGMT_MLD,
NSS_PPE_STATS_CPU_CODE_MGMT_NS,
NSS_PPE_STATS_CPU_CODE_MGMT_NA,
NSS_PPE_STATS_CPU_CODE_MGMT_DHCPv6,
NSS_PPE_STATS_CPU_CODE_PTP_OFFSET,
NSS_PPE_STATS_CPU_CODE_PTP_SYNC,
NSS_PPE_STATS_CPU_CODE_PTP_FOLLOW_UP,
NSS_PPE_STATS_CPU_CODE_PTP_DELAY_REQ,
NSS_PPE_STATS_CPU_CODE_PTP_DELAY_RESP,
NSS_PPE_STATS_CPU_CODE_PTP_PDELAY_REQ,
NSS_PPE_STATS_CPU_CODE_PTP_PDELAY_RESP,
NSS_PPE_STATS_CPU_CODE_PTP_PDELAY_RESP_FOLLOW_UP,
NSS_PPE_STATS_CPU_CODE_PTP_ANNOUNCE,
NSS_PPE_STATS_CPU_CODE_PTP_MANAGEMENT,
NSS_PPE_STATS_CPU_CODE_PTP_SIGNALING,
NSS_PPE_STATS_CPU_CODE_PTP_PKT_RSV_MSG,
NSS_PPE_STATS_CPU_CODE_IPV4_SG_UNKNOWN,
NSS_PPE_STATS_CPU_CODE_IPV6_SG_UNKNOWN,
NSS_PPE_STATS_CPU_CODE_ARP_SG_UNKNOWN,
NSS_PPE_STATS_CPU_CODE_ND_SG_UNKNOWN,
NSS_PPE_STATS_CPU_CODE_IPV4_SG_VIO,
NSS_PPE_STATS_CPU_CODE_IPV6_SG_VIO,
NSS_PPE_STATS_CPU_CODE_ARP_SG_VIO,
NSS_PPE_STATS_CPU_CODE_ND_SG_VIO,
NSS_PPE_STATS_CPU_CODE_L3_ROUTING_IP_TO_ME,
NSS_PPE_STATS_CPU_CODE_L3_FLOW_SNAT_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_FLOW_DNAT_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_FLOW_RT_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_FLOW_BR_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_MC_BRIDGE_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_ROUTE_PREHEAD_RT_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_ROUTE_PREHEAD_SNAPT_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_ROUTE_PREHEAD_DNAPT_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_ROUTE_PREHEAD_SNAT_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_ROUTE_PREHEAD_DNAT_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_NO_ROUTE_PREHEAD_NAT_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_NO_ROUTE_PREHEAD_NAT_ERROR,
NSS_PPE_STATS_CPU_CODE_L3_ROUTE_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_NO_ROUTE_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_NO_ROUTE_NH_INVALID_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_NO_ROUTE_PREHEAD_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_BRIDGE_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_FLOW_ACTION,
NSS_PPE_STATS_CPU_CODE_L3_FLOW_MISS_ACTION,
NSS_PPE_STATS_CPU_CODE_L2_NEW_MAC_ADDRESS,
NSS_PPE_STATS_CPU_CODE_L2_HASH_COLLISION,
NSS_PPE_STATS_CPU_CODE_L2_STATION_MOVE,
NSS_PPE_STATS_CPU_CODE_L2_LEARN_LIMIT,
NSS_PPE_STATS_CPU_CODE_L2_SA_LOOKUP_ACTION,
NSS_PPE_STATS_CPU_CODE_L2_DA_LOOKUP_ACTION,
NSS_PPE_STATS_CPU_CODE_APP_CTRL_ACTION,
NSS_PPE_STATS_CPU_CODE_IN_VLAN_FILTER_ACTION,
NSS_PPE_STATS_CPU_CODE_IN_VLAN_XLT_MISS,
NSS_PPE_STATS_CPU_CODE_EG_VLAN_FILTER_DROP,
NSS_PPE_STATS_CPU_CODE_ACL_PRE_ACTION,
NSS_PPE_STATS_CPU_CODE_ACL_POST_ACTION,
NSS_PPE_STATS_CPU_CODE_SERVICE_CODE_ACTION,
};
/*
* nss_ppe_stats_str_sc_type
* PPE service-code stats type
*/
static int8_t *nss_ppe_stats_str_sc_type[NSS_PPE_SC_MAX] = {
"SC_NONE ",
"SC_BYPASS_ALL ",
"SC_ADV_QOS_BRIDGED",
"SC_BR_QOS ",
"SC_BNC_0 ",
"SC_BNC_CMPL_0 ",
"SC_ADV_QOS_ROUTED ",
"SC_IPSEC_PPE2EIP ",
"SC_IPSEC_EIP2PPE ",
"SC_PTP ",
"SC_VLAN_FILTER ",
"SC_L3_EXCEPT ",
};
/*
* nss_ppe_stats_sync
* PPE connection sync statistics from NSS
*/
void nss_ppe_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_ppe_sync_stats_msg *stats_msg, uint16_t if_num)
{
uint32_t sc;
spin_lock_bh(&nss_ppe_stats_lock);
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_L3_FLOWS] = stats_msg->stats.nss_ppe_v4_l3_flows;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_L2_FLOWS] = stats_msg->stats.nss_ppe_v4_l2_flows;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_CREATE_REQ] += stats_msg->stats.nss_ppe_v4_create_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_CREATE_FAIL] += stats_msg->stats.nss_ppe_v4_create_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_DESTROY_REQ] += stats_msg->stats.nss_ppe_v4_destroy_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_DESTROY_FAIL] += stats_msg->stats.nss_ppe_v4_destroy_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_MC_CREATE_REQ] += stats_msg->stats.nss_ppe_v4_mc_create_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_MC_CREATE_FAIL] += stats_msg->stats.nss_ppe_v4_mc_create_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_MC_UPDATE_REQ] += stats_msg->stats.nss_ppe_v4_mc_update_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_MC_UPDATE_FAIL] += stats_msg->stats.nss_ppe_v4_mc_update_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_MC_DESTROY_REQ] += stats_msg->stats.nss_ppe_v4_mc_destroy_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_MC_DESTROY_FAIL] += stats_msg->stats.nss_ppe_v4_mc_destroy_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V4_UNKNOWN_INTERFACE] += stats_msg->stats.nss_ppe_v4_unknown_interface;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_L3_FLOWS] = stats_msg->stats.nss_ppe_v6_l3_flows;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_L2_FLOWS] = stats_msg->stats.nss_ppe_v6_l2_flows;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_CREATE_REQ] += stats_msg->stats.nss_ppe_v6_create_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_CREATE_FAIL] += stats_msg->stats.nss_ppe_v6_create_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_DESTROY_REQ] += stats_msg->stats.nss_ppe_v6_destroy_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_DESTROY_FAIL] += stats_msg->stats.nss_ppe_v6_destroy_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_MC_CREATE_REQ] += stats_msg->stats.nss_ppe_v6_mc_create_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_MC_CREATE_FAIL] += stats_msg->stats.nss_ppe_v6_mc_create_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_MC_UPDATE_REQ] += stats_msg->stats.nss_ppe_v6_mc_update_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_MC_UPDATE_FAIL] += stats_msg->stats.nss_ppe_v6_mc_update_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_MC_DESTROY_REQ] += stats_msg->stats.nss_ppe_v6_mc_destroy_req;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_MC_DESTROY_FAIL] += stats_msg->stats.nss_ppe_v6_mc_destroy_fail;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_V6_UNKNOWN_INTERFACE] += stats_msg->stats.nss_ppe_v6_unknown_interface;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_VP_FULL] += stats_msg->stats.nss_ppe_fail_vp_full;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_NH_FULL] += stats_msg->stats.nss_ppe_fail_nh_full;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_FLOW_FULL] += stats_msg->stats.nss_ppe_fail_flow_full;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_HOST_FULL] += stats_msg->stats.nss_ppe_fail_host_full;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_PUBIP_FULL] += stats_msg->stats.nss_ppe_fail_pubip_full;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_PORT_SETUP] += stats_msg->stats.nss_ppe_fail_port_setup;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_RW_FIFO_FULL] += stats_msg->stats.nss_ppe_fail_rw_fifo_full;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_FLOW_COMMAND] += stats_msg->stats.nss_ppe_fail_flow_command;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_UNKNOWN_PROTO] += stats_msg->stats.nss_ppe_fail_unknown_proto;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_PPE_UNRESPONSIVE] += stats_msg->stats.nss_ppe_fail_ppe_unresponsive;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_CE_OPAQUE_INVALID] += stats_msg->stats.nss_ppe_ce_opaque_invalid;
nss_ppe_debug_stats.conn_stats[NSS_PPE_STATS_FAIL_FQG_FULL] += stats_msg->stats.nss_ppe_fail_fqg_full;
/*
* Update service-code stats.
*/
for (sc = 0; sc < NSS_PPE_SC_MAX; sc++) {
nss_ppe_debug_stats.sc_stats[sc].nss_ppe_sc_cb_unregister += stats_msg->sc_stats[sc].nss_ppe_sc_cb_unregister;
nss_ppe_debug_stats.sc_stats[sc].nss_ppe_sc_cb_success += stats_msg->sc_stats[sc].nss_ppe_sc_cb_success;
nss_ppe_debug_stats.sc_stats[sc].nss_ppe_sc_cb_failure += stats_msg->sc_stats[sc].nss_ppe_sc_cb_failure;
}
spin_unlock_bh(&nss_ppe_stats_lock);
}
/*
* nss_ppe_stats_conn_get()
* Get PPE connection statistics.
*/
static void nss_ppe_stats_conn_get(uint64_t *stats)
{
if (!stats) {
nss_warning("No memory to copy ppe connection stats");
return;
}
/*
* Get flow stats
*/
spin_lock_bh(&nss_ppe_stats_lock);
memcpy(stats, nss_ppe_debug_stats.conn_stats, (sizeof(uint64_t) * NSS_PPE_STATS_CONN_MAX));
spin_unlock_bh(&nss_ppe_stats_lock);
}
/*
* nss_ppe_stats_sc_get()
* Get PPE service-code statistics.
*/
static void nss_ppe_stats_sc_get(struct nss_ppe_sc_stats_debug *sc_stats)
{
if (!sc_stats) {
nss_warning("No memory to copy ppe service code stats");
return;
}
/*
* Get flow stats
*/
spin_lock_bh(&nss_ppe_stats_lock);
memcpy(sc_stats, nss_ppe_debug_stats.sc_stats, (sizeof(struct nss_ppe_sc_stats_debug) * NSS_PPE_SC_MAX));
spin_unlock_bh(&nss_ppe_stats_lock);
}
/*
* nss_ppe_stats_l3_get()
* Get PPE L3 debug statistics.
*/
static void nss_ppe_stats_l3_get(uint32_t *stats)
{
if (!stats) {
nss_warning("No memory to copy ppe l3 dbg stats\n");
return;
}
spin_lock_bh(&nss_ppe_stats_lock);
nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG0_OFFSET);
nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_PPE_STATS_L3_DBG_0]);
nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG1_OFFSET);
nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_PPE_STATS_L3_DBG_1]);
nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG2_OFFSET);
nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_PPE_STATS_L3_DBG_2]);
nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG3_OFFSET);
nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_PPE_STATS_L3_DBG_3]);
nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG4_OFFSET);
nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_PPE_STATS_L3_DBG_4]);
nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG_PORT_OFFSET);
nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_PPE_STATS_L3_DBG_PORT]);
spin_unlock_bh(&nss_ppe_stats_lock);
}
/*
* nss_ppe_stats_code_get()
* Get PPE CPU and DROP code for last packet processed.
*/
static void nss_ppe_stats_code_get(uint32_t *stats)
{
uint32_t drop_0, drop_1, cpu_code;
nss_trace("%s(%d) Start\n", __func__, __LINE__);
if (!stats) {
nss_warning("No memory to copy ppe code\n");
return;
}
spin_lock_bh(&nss_ppe_stats_lock);
nss_ppe_reg_write(PPE_PKT_CODE_WR_OFFSET, PPE_PKT_CODE_DROP0_OFFSET);
nss_ppe_reg_read(PPE_PKT_CODE_RD_OFFSET, &drop_0);
nss_ppe_reg_write(PPE_PKT_CODE_WR_OFFSET, PPE_PKT_CODE_DROP1_OFFSET);
nss_ppe_reg_read(PPE_PKT_CODE_RD_OFFSET, &drop_1);
stats[NSS_PPE_STATS_CODE_DROP] = PPE_PKT_CODE_DROP_GET(drop_0, drop_1);
nss_ppe_reg_write(PPE_PKT_CODE_WR_OFFSET, PPE_PKT_CODE_CPU_OFFSET);
nss_ppe_reg_read(PPE_PKT_CODE_RD_OFFSET, &cpu_code);
stats[NSS_PPE_STATS_CODE_CPU] = PPE_PKT_CODE_CPU_GET(cpu_code);
spin_unlock_bh(&nss_ppe_stats_lock);
}
/*
* nss_ppe_port_drop_code_get()
* Get ppe per port drop code.
*/
static void nss_ppe_port_drop_code_get(uint32_t *stats, uint8_t port_id)
{
uint8_t i;
nss_trace("%s(%d) Start\n", __func__, __LINE__);
if (!stats) {
nss_warning("No memory to copy ppe code\n");
return;
}
if (port_id > NSS_PPE_NUM_PHY_PORTS_MAX) {
nss_warning("Port id is out of range\n");
return;
}
spin_lock_bh(&nss_ppe_stats_lock);
for (i = 0; i < NSS_PPE_STATS_DROP_CODE_MAX; i++) {
nss_ppe_reg_read(PPE_DROP_CODE_OFFSET(i, port_id), &stats[i]);
}
spin_unlock_bh(&nss_ppe_stats_lock);
}
/*
* nss_ppe_cpu_code_exception_get()
* Get ppe cpu code specific for flow exceptions.
*/
static void nss_ppe_cpu_code_exception_get(uint32_t *stats)
{
uint8_t i;
nss_trace("%s(%d) Start\n", __func__, __LINE__);
if (!stats) {
nss_warning("No memory to copy ppe code\n");
return;
}
spin_lock_bh(&nss_ppe_stats_lock);
for (i = 0; i < NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX ; i++) {
nss_ppe_reg_read(PPE_CPU_CODE_OFFSET(i), &stats[i]);
}
spin_unlock_bh(&nss_ppe_stats_lock);
}
/*
* nss_ppe_cpu_code_nonexception_get()
* Get ppe cpu code specific for flow exceptions.
*/
static void nss_ppe_cpu_code_nonexception_get(uint32_t *stats)
{
uint8_t i;
nss_trace("%s(%d) Start\n", __func__, __LINE__);
if (!stats) {
nss_warning("No memory to copy ppe code\n");
return;
}
spin_lock_bh(&nss_ppe_stats_lock);
for (i = 0; i < NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX; i++) {
nss_ppe_reg_read(PPE_CPU_CODE_OFFSET(ppe_cc_nonexception[i]), &stats[i]);
}
spin_unlock_bh(&nss_ppe_stats_lock);
}
/*
* nss_ppe_conn_stats_read()
* Read ppe connection statistics
*/
static ssize_t nss_ppe_conn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
int i;
char *lbuf = NULL;
size_t size_wr = 0;
ssize_t bytes_read = 0;
uint64_t *stats_shadow;
uint64_t ppe_stats[NSS_PPE_STATS_CONN_MAX];
uint32_t max_output_lines = NSS_PPE_STATS_CONN_MAX + NSS_STATS_EXTRA_OUTPUT_LINES;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(lbuf == NULL)) {
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
stats_shadow = kzalloc(NSS_PPE_STATS_CONN_MAX * 8, GFP_KERNEL);
if (unlikely(!stats_shadow)) {
nss_warning("Could not allocate memory for local shadow buffer");
kfree(lbuf);
return 0;
}
memset(ppe_stats, 0, sizeof(uint64_t) * NSS_PPE_STATS_CONN_MAX);
/*
* Get all stats
*/
nss_ppe_stats_conn_get(ppe_stats);
/*
* flow stats
*/
spin_lock_bh(&nss_ppe_stats_lock);
for (i = 0; i < NSS_PPE_STATS_CONN_MAX; i++) {
stats_shadow[i] = ppe_stats[i];
}
spin_unlock_bh(&nss_ppe_stats_lock);
size_wr += nss_stats_print("ppe", "ppe flow counters", NSS_STATS_SINGLE_INSTANCE, nss_ppe_stats_str_conn, stats_shadow,
NSS_PPE_STATS_CONN_MAX, lbuf, size_wr, size_al);
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
kfree(lbuf);
kfree(stats_shadow);
return bytes_read;
}
/*
* nss_ppe_sc_stats_read()
* Read ppe service code statistics
*/
static ssize_t nss_ppe_sc_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
int i;
char *lbuf = NULL;
size_t size_wr = 0;
ssize_t bytes_read = 0;
struct nss_ppe_sc_stats_debug sc_stats[NSS_PPE_SC_MAX];
uint32_t max_output_lines = (NSS_PPE_SC_MAX * NSS_PPE_STATS_SERVICE_CODE_MAX) + NSS_STATS_EXTRA_OUTPUT_LINES;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(lbuf == NULL)) {
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
memset(sc_stats, 0, sizeof(sc_stats));
/*
* Get stats
*/
nss_ppe_stats_sc_get(sc_stats);
/*
* service code stats
*/
for (i = 0; i < NSS_PPE_SC_MAX; i++) {
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "ppe service code type: %s\n",
nss_ppe_stats_str_sc_type[i]);
size_wr += nss_stats_print("ppe", "ppe service code counters", NSS_STATS_SINGLE_INSTANCE,
nss_ppe_stats_str_sc, &sc_stats[i].nss_ppe_sc_cb_unregister,
NSS_PPE_STATS_SERVICE_CODE_MAX, lbuf, size_wr, size_al);
}
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
kfree(lbuf);
return bytes_read;
}
/*
* nss_ppe_l3_stats_read()
* Read PPE L3 debug statistics
*/
static ssize_t nss_ppe_l3_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
int i;
char *lbuf = NULL;
size_t size_wr = 0;
ssize_t bytes_read = 0;
uint64_t *stats_shadow;
uint32_t ppe_stats[NSS_PPE_STATS_L3_MAX];
uint32_t max_output_lines = NSS_PPE_STATS_L3_MAX + NSS_STATS_EXTRA_OUTPUT_LINES;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(!lbuf)) {
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
stats_shadow = kzalloc(NSS_PPE_STATS_L3_MAX * 8, GFP_KERNEL);
if (unlikely(!stats_shadow)) {
nss_warning("Could not allocate memory for local shadow buffer");
kfree(lbuf);
return 0;
}
memset(ppe_stats, 0, sizeof(uint32_t) * NSS_PPE_STATS_L3_MAX);
/*
* Get all stats
*/
nss_ppe_stats_l3_get(ppe_stats);
/*
* flow stats
*/
spin_lock_bh(&nss_ppe_stats_lock);
for (i = 0; i < NSS_PPE_STATS_L3_MAX; i++) {
stats_shadow[i] = ppe_stats[i];
}
spin_unlock_bh(&nss_ppe_stats_lock);
size_wr += nss_stats_print("ppe", "ppe l3 debug stats", NSS_STATS_SINGLE_INSTANCE, nss_ppe_stats_str_l3,
stats_shadow, NSS_PPE_STATS_L3_MAX, lbuf, size_wr, size_al);
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
kfree(lbuf);
kfree(stats_shadow);
return bytes_read;
}
/*
* nss_ppe_code_stats_read()
* Read ppe CPU & DROP code
*/
static ssize_t nss_ppe_code_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
int i;
char *lbuf = NULL;
size_t size_wr = 0;
ssize_t bytes_read = 0;
uint64_t *stats_shadow;
uint32_t ppe_stats[NSS_PPE_STATS_CODE_MAX];
uint32_t max_output_lines = NSS_PPE_STATS_CODE_MAX + NSS_STATS_EXTRA_OUTPUT_LINES;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(!lbuf)) {
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
stats_shadow = kzalloc(NSS_PPE_STATS_CODE_MAX * 8, GFP_KERNEL);
if (unlikely(!stats_shadow)) {
nss_warning("Could not allocate memory for local shadow buffer");
kfree(lbuf);
return 0;
}
memset(ppe_stats, 0, sizeof(uint32_t) * NSS_PPE_STATS_CODE_MAX);
/*
* Get all stats
*/
nss_ppe_stats_code_get(ppe_stats);
/*
* flow stats
*/
spin_lock_bh(&nss_ppe_stats_lock);
for (i = 0; i < NSS_PPE_STATS_CODE_MAX; i++) {
stats_shadow[i] = ppe_stats[i];
}
spin_unlock_bh(&nss_ppe_stats_lock);
size_wr += nss_stats_print("ppe", "ppe session stats", NSS_STATS_SINGLE_INSTANCE, nss_ppe_stats_str_code, stats_shadow,
NSS_PPE_STATS_CODE_MAX, lbuf, size_wr, size_al);
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
kfree(lbuf);
kfree(stats_shadow);
return bytes_read;
}
/*
* nss_ppe_port_dc_stats_read()
* Read PPE per port drop code stats
*/
static ssize_t nss_ppe_port_dc_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
int32_t i;
/*
* max output lines = #stats + few blank lines for future reference to add new stats.
*/
uint32_t max_output_lines = NSS_PPE_STATS_DROP_CODE_MAX + NSS_STATS_EXTRA_OUTPUT_LINES;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
size_t size_wr = 0;
ssize_t bytes_read = 0;
uint64_t *stats_shadow;
struct nss_stats_data *data = fp->private_data;
uint32_t *ppe_stats;
char *lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(lbuf == NULL)) {
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
ppe_stats = kzalloc(sizeof(uint32_t) * NSS_PPE_STATS_DROP_CODE_MAX, GFP_KERNEL);
if (unlikely(ppe_stats == NULL)) {
kfree(lbuf);
nss_warning("Could not allocate memory for ppe stats buffer");
return 0;
}
stats_shadow = kzalloc((NSS_PPE_STATS_DROP_CODE_MAX) * 8, GFP_KERNEL);
if (unlikely(!stats_shadow)) {
nss_warning("Could not allocate memory for local shadow buffer");
kfree(lbuf);
kfree(ppe_stats);
return 0;
}
/*
* Get drop code counters for specific port
*/
nss_ppe_port_drop_code_get(ppe_stats, data->edma_id);
/*
* Drop code stats
*/
spin_lock_bh(&nss_ppe_stats_lock);
for (i = 0; i < NSS_PPE_STATS_DROP_CODE_MAX; i++) {
stats_shadow[i] = ppe_stats[i];
}
spin_unlock_bh(&nss_ppe_stats_lock);
size_wr += nss_stats_print("ppe", "ppe drop code stats", NSS_STATS_SINGLE_INSTANCE, nss_ppe_stats_str_dc,
stats_shadow, NSS_PPE_STATS_DROP_CODE_MAX, lbuf, size_wr, size_al);
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
kfree(ppe_stats);
kfree(lbuf);
kfree(stats_shadow);
return bytes_read;
}
/*
* nss_ppe_exception_cc_stats_read()
* Read PPE CPU code stats specific to flow exceptions
*/
static ssize_t nss_ppe_exception_cc_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
int32_t i;
/*
* max output lines = #stats + few blank lines for future reference to add new stats.
*/
uint32_t max_output_lines = NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX + NSS_STATS_EXTRA_OUTPUT_LINES;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
size_t size_wr = 0;
ssize_t bytes_read = 0;
uint64_t *stats_shadow;
uint32_t *ppe_stats;
char *lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(lbuf == NULL)) {
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
ppe_stats = kzalloc(sizeof(uint32_t) * NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX, GFP_KERNEL);
if (unlikely(ppe_stats == NULL)) {
kfree(lbuf);
nss_warning("Could not allocate memory for ppe stats buffer");
return 0;
}
stats_shadow = kzalloc(NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX * 8, GFP_KERNEL);
if (unlikely(!stats_shadow)) {
nss_warning("Could not allocate memory for local shadow buffer");
kfree(lbuf);
kfree(ppe_stats);
return 0;
}
/*
* Get CPU code counters for flow specific exceptions
*/
nss_ppe_cpu_code_exception_get(ppe_stats);
/*
* CPU code stats
*/
spin_lock_bh(&nss_ppe_stats_lock);
for (i = 0; i < NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX; i++) {
stats_shadow[i] = ppe_stats[i];
}
spin_unlock_bh(&nss_ppe_stats_lock);
size_wr += nss_stats_print("ppe", "ppe cpu code flow-exception stats", NSS_STATS_SINGLE_INSTANCE,
nss_ppe_stats_str_cc, stats_shadow, NSS_PPE_STATS_CPU_CODE_EXCEPTION_MAX,
lbuf, size_wr, size_al);
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
kfree(ppe_stats);
kfree(lbuf);
kfree(stats_shadow);
return bytes_read;
}
/*
* nss_ppe_nonexception_cc_stats_read()
* Read PPE CPU code stats for other than flow exceptions
*/
static ssize_t nss_ppe_nonexception_cc_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
int32_t i;
/*
* max output lines = #stats + few blank lines for future reference to add new stats.
*/
uint32_t max_output_lines = NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX + NSS_STATS_EXTRA_OUTPUT_LINES;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
size_t size_wr = 0;
ssize_t bytes_read = 0;
uint64_t *stats_shadow;
uint32_t *ppe_stats;
char *lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(lbuf == NULL)) {
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
ppe_stats = kzalloc(sizeof(uint32_t) * NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX, GFP_KERNEL);
if (unlikely(ppe_stats == NULL)) {
kfree(lbuf);
nss_warning("Could not allocate memory for ppe stats buffer");
return 0;
}
stats_shadow = kzalloc(NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX * 8, GFP_KERNEL);
if (unlikely(!stats_shadow)) {
nss_warning("Could not allocate memory for local shadow buffer");
kfree(lbuf);
kfree(ppe_stats);
return 0;
}
/*
* Get CPU code counters for non flow exceptions
*/
nss_ppe_cpu_code_nonexception_get(ppe_stats);
/*
* CPU code stats
*/
spin_lock_bh(&nss_ppe_stats_lock);
for (i = 0; i < NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX; i++) {
stats_shadow[i] = ppe_stats[i];
}
spin_unlock_bh(&nss_ppe_stats_lock);
size_wr += nss_stats_print("ppe", "ppe cpu code non-flow exception stats", NSS_STATS_SINGLE_INSTANCE,
&nss_ppe_stats_str_cc[NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_START],
stats_shadow, NSS_PPE_STATS_CPU_CODE_NONEXCEPTION_MAX, lbuf, size_wr, size_al);
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
kfree(ppe_stats);
kfree(stats_shadow);
kfree(lbuf);
return bytes_read;
}
/*
* nss_ppe_conn_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(ppe_conn)
/*
* nss_ppe_l3_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(ppe_l3)
/*
* nss_ppe_code_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(ppe_code)
/*
* nss_ppe_port_dc_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(ppe_port_dc)
/*
* nss_ppe_exception_cc_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(ppe_exception_cc)
/*
* nss_ppe_nonexception_cc_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(ppe_nonexception_cc)
/*
* nss_ppe_sc_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(ppe_sc)
/*
* nss_ppe_stats_dentry_create()
* Create PPE statistics debug entry.
*/
void nss_ppe_stats_dentry_create(void)
{
int i;
struct dentry *ppe_dentry = NULL;
struct dentry *ppe_code_d = NULL;
struct dentry *ppe_drop_d = NULL;
struct dentry *ppe_cpu_d = NULL;
char file_name[10];
ppe_dentry = debugfs_create_dir("ppe", nss_top_main.stats_dentry);
if (!ppe_dentry) {
nss_warning("Failed to create qca-nss-drv/stats/ppe directory");
return;
}
if (!debugfs_create_file("connection", 0400, ppe_dentry, &nss_top_main, &nss_ppe_conn_stats_ops)) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/connection file");
debugfs_remove_recursive(ppe_dentry);
return;
}
if (!debugfs_create_file("sc_stats", 0400, ppe_dentry, &nss_top_main, &nss_ppe_sc_stats_ops)) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/sc_stats file");
debugfs_remove_recursive(ppe_dentry);
return;
}
if (!debugfs_create_file("l3", 0400, ppe_dentry, &nss_top_main, &nss_ppe_l3_stats_ops)) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/l3 file");
debugfs_remove_recursive(ppe_dentry);
return;
}
if (!debugfs_create_file("ppe_code", 0400, ppe_dentry, &nss_top_main, &nss_ppe_code_stats_ops)) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/ppe_code file");
debugfs_remove_recursive(ppe_dentry);
return;
}
/*
* ppe exception and drop code stats
*/
ppe_code_d = debugfs_create_dir("code", ppe_dentry);
if (!ppe_code_d) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/code directory");
return;
}
ppe_cpu_d = debugfs_create_dir("cpu", ppe_code_d);
if (!ppe_cpu_d) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/code/cpu directory");
return;
}
if (!debugfs_create_file("exception", 0400, ppe_cpu_d, &nss_top_main, &nss_ppe_exception_cc_stats_ops)) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/code/exception file");
debugfs_remove_recursive(ppe_cpu_d);
return;
}
if (!debugfs_create_file("non-exception", 0400, ppe_cpu_d, &nss_top_main, &nss_ppe_nonexception_cc_stats_ops)) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/code/non-exception file");
debugfs_remove_recursive(ppe_cpu_d);
return;
}
ppe_drop_d = debugfs_create_dir("drop", ppe_code_d);
if (!ppe_drop_d) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/code/drop directory");
return;
}
for (i = 0; i < NSS_PPE_NUM_PHY_PORTS_MAX; i++) {
if (i > 0) {
memset(file_name, 0, sizeof(file_name));
snprintf(file_name, sizeof(file_name), "%d", i);
}
if (!debugfs_create_file((i == 0) ? "cpu" : file_name, 0400, ppe_drop_d,
(void *)(nss_ptr_t)i, &nss_ppe_port_dc_stats_ops)) {
nss_warning("Failed to create qca-nss-drv/stats/ppe/code/drop/%d file", i);
debugfs_remove_recursive(ppe_drop_d);
return;
}
}
}
/*
* nss_ppe_stats_notify()
* Sends notifications to all the registered modules.
*
* Leverage NSS-FW statistics timing to update Netlink.
*/
void nss_ppe_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num)
{
struct nss_ppe_stats_notification ppe_stats;
spin_lock_bh(&nss_ppe_stats_lock);
ppe_stats.core_id = nss_ctx->id;
ppe_stats.if_num = if_num;
memcpy(ppe_stats.ppe_stats_conn, nss_ppe_debug_stats.conn_stats, sizeof(ppe_stats.ppe_stats_conn));
memcpy(ppe_stats.ppe_stats_sc, nss_ppe_debug_stats.sc_stats, sizeof(ppe_stats.ppe_stats_sc));
spin_unlock_bh(&nss_ppe_stats_lock);
atomic_notifier_call_chain(&nss_ppe_stats_notifier, NSS_STATS_EVENT_NOTIFY, &ppe_stats);
}
/*
* nss_ppe_stats_unregister_notifier()
* Deregisters statistics notifier.
*/
int nss_ppe_stats_unregister_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&nss_ppe_stats_notifier, nb);
}
EXPORT_SYMBOL(nss_ppe_stats_unregister_notifier);
/*
* nss_ppe_stats_register_notifier()
* Registers statistics notifier.
*/
int nss_ppe_stats_register_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&nss_ppe_stats_notifier, nb);
}
EXPORT_SYMBOL(nss_ppe_stats_register_notifier);