blob: 57c79953ffddccc81073e30fcc4276e995235ad6 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2020-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_vp.h"
#include "nss_ppe_vp_stats.h"
/*
* nss_ppe_vp_stats_cntrs
* PPE VP stats counters displayed using debugfs
*/
enum nss_ppe_vp_stats_cntrs {
NSS_PPE_VP_STATS_VP_NUM,
NSS_PPE_VP_STATS_NSS_IF,
NSS_PPE_VP_STATS_RX_PKTS,
NSS_PPE_VP_STATS_RX_BYTES,
NSS_PPE_VP_STATS_TX_PKTS,
NSS_PPE_VP_STATS_TX_BYTES,
NSS_PPE_VP_STATS_RX_INACTIVE,
NSS_PPE_VP_STATS_TX_INACTIVE,
NSS_PPE_VP_STATS_PACKET_BIG,
NSS_PPE_VP_STATS_TX_Q_0_DROP,
NSS_PPE_VP_STATS_TX_Q_1_DROP,
NSS_PPE_VP_STATS_TX_Q_2_DROP,
NSS_PPE_VP_STATS_TX_Q_3_DROP,
NSS_PPE_VP_STATS_MAX
};
/*
* nss_ppe_vp_stats_rx_cntrs
* PPE VP RX stats counters displayed using debugfs
*/
enum nss_ppe_vp_stats_rx_cntrs {
NSS_PPE_VP_STATS_RX_Q_0_DROP,
NSS_PPE_VP_STATS_RX_Q_1_DROP,
NSS_PPE_VP_STATS_RX_Q_2_DROP,
NSS_PPE_VP_STATS_RX_Q_3_DROP,
NSS_PPE_VP_STATS_RX_MAX
};
/*
* nss_ppe_vp_rx_stats_str
* PPE VP Rx statistics strings
*/
struct nss_stats_info nss_ppe_vp_stats_rx_str[NSS_PPE_VP_STATS_RX_MAX] = {
{"rx_queue_0_drop" , NSS_STATS_TYPE_DROP},
{"rx_queue_1_drop" , NSS_STATS_TYPE_DROP},
{"rx_queue_2_drop" , NSS_STATS_TYPE_DROP},
{"rx_queue_3_drop" , NSS_STATS_TYPE_DROP},
};
/*
* nss_ppe_vp_stats_str
* PPE VP statistics strings
*/
struct nss_stats_info nss_ppe_vp_stats_str[NSS_PPE_VP_STATS_MAX] = {
{"ppe_port_num" , NSS_STATS_TYPE_SPECIAL},
{"nss_if" , NSS_STATS_TYPE_SPECIAL},
{"rx_packets" , NSS_STATS_TYPE_COMMON},
{"rx_bytes" , NSS_STATS_TYPE_COMMON},
{"tx_packets" , NSS_STATS_TYPE_COMMON},
{"tx_bytes" , NSS_STATS_TYPE_COMMON},
{"rx_inactive" , NSS_STATS_TYPE_DROP},
{"tx_inactive" , NSS_STATS_TYPE_DROP},
{"packet_large_err" , NSS_STATS_TYPE_EXCEPTION},
{"tx_queue_0_drop" , NSS_STATS_TYPE_DROP},
{"tx_queue_1_drop" , NSS_STATS_TYPE_DROP},
{"tx_queue_2_drop" , NSS_STATS_TYPE_DROP},
{"tx_queue_3_drop" , NSS_STATS_TYPE_DROP},
};
/*
* nss_ppe_vp_stats_sync
* PPE VP sync statistics from NSS
*/
void nss_ppe_vp_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_ppe_vp_sync_stats_msg *stats_msg, uint16_t if_num)
{
uint16_t count = stats_msg->count;
uint16_t vp_index, i;
spin_lock_bh(&nss_ppe_vp_stats_lock);
/*
* Update general rx dropped stats.
*/
for (i = 0; i < NSS_MAX_NUM_PRI; i++) {
nss_ppe_vp_debug_stats.rx_dropped[i] += stats_msg->rx_dropped[i];
}
/*
* Update per VP tx and rx stats.
*/
while (count) {
count--;
/*
* Update stats in global array
*/
vp_index = stats_msg->vp_stats[count].ppe_port_num - NSS_PPE_VP_START;
nss_ppe_vp_debug_stats.vp_stats[vp_index].ppe_port_num = stats_msg->vp_stats[count].ppe_port_num;
nss_ppe_vp_debug_stats.vp_stats[vp_index].nss_if = stats_msg->vp_stats[count].nss_if;
nss_ppe_vp_debug_stats.vp_stats[vp_index].rx_packets += stats_msg->vp_stats[count].stats.rx_packets;
nss_ppe_vp_debug_stats.vp_stats[vp_index].rx_bytes += stats_msg->vp_stats[count].stats.rx_bytes;
nss_ppe_vp_debug_stats.vp_stats[vp_index].tx_packets += stats_msg->vp_stats[count].stats.tx_packets;
nss_ppe_vp_debug_stats.vp_stats[vp_index].tx_bytes += stats_msg->vp_stats[count].stats.tx_bytes;
nss_ppe_vp_debug_stats.vp_stats[vp_index].rx_inactive_drop += stats_msg->vp_stats[count].rx_drop;
nss_ppe_vp_debug_stats.vp_stats[vp_index].tx_inactive_drop += stats_msg->vp_stats[count].tx_drop;
nss_ppe_vp_debug_stats.vp_stats[vp_index].packet_big_err += stats_msg->vp_stats[count].packet_big_err;
for (i = 0; i < NSS_MAX_NUM_PRI; i++) {
nss_ppe_vp_debug_stats.vp_stats[vp_index].tx_dropped[i] += stats_msg->vp_stats[count].stats.rx_dropped[i];
}
nss_trace("sync count:%d ppe_port_num %d rx_packets %d tx_packets %d\n",
count, stats_msg->vp_stats[count].ppe_port_num,
stats_msg->vp_stats[count].stats.rx_packets,
stats_msg->vp_stats[count].stats.tx_packets);
}
spin_unlock_bh(&nss_ppe_vp_stats_lock);
}
/*
* nss_ppe_vp_stats_read()
* Read ppe vp statistics
*/
static ssize_t nss_ppe_vp_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_vp_stats_debug *ppe_vp_stats;
uint32_t max_output_lines = ((NSS_PPE_VP_STATS_RX_MAX + NSS_PPE_VP_STATS_MAX) * NSS_PPE_VP_MAX_NUM) + NSS_STATS_EXTRA_OUTPUT_LINES;
size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
size_t stats_sz = sizeof(struct nss_ppe_vp_stats_debug);
ppe_vp_stats = kzalloc(stats_sz, GFP_KERNEL);
if (!ppe_vp_stats) {
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(!lbuf)) {
kfree(ppe_vp_stats);
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
/*
* Get vp stats
*/
spin_lock_bh(&nss_ppe_vp_stats_lock);
memcpy(ppe_vp_stats, &nss_ppe_vp_debug_stats, stats_sz);
spin_unlock_bh(&nss_ppe_vp_stats_lock);
/*
* VP stats
*/
size_wr += nss_stats_banner(lbuf, size_wr, size_al, "ppe_vp", NSS_STATS_SINGLE_CORE);
/*
* Print Rx dropped.
*/
size_wr += nss_stats_print("ppe_vp", "ppe_vp rx dropped:"
, NSS_STATS_SINGLE_INSTANCE
, nss_ppe_vp_stats_rx_str
, ppe_vp_stats->rx_dropped
, NSS_PPE_VP_STATS_RX_MAX
, lbuf, size_wr, size_al);
/*
* Print individual VP stats
*/
for (i = 0; i < NSS_PPE_VP_MAX_NUM; i++) {
if (!ppe_vp_stats->vp_stats[i].nss_if) {
continue;
}
size_wr += nss_stats_print("ppe_vp", "ppe_vp stats"
, NSS_STATS_SINGLE_INSTANCE
, nss_ppe_vp_stats_str
, (uint64_t *) &ppe_vp_stats->vp_stats[i]
, NSS_PPE_VP_STATS_MAX
, lbuf, size_wr, size_al);
}
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, size_wr);
kfree(ppe_vp_stats);
kfree(lbuf);
return bytes_read;
}
/*
* nss_ppe_vp_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(ppe_vp)
/*
* nss_ppe_vp_stats_dentry_create()
* Create PPE statistics debug entry.
*/
struct dentry *nss_ppe_vp_stats_dentry_create(void)
{
struct dentry *ppe_vp_d = debugfs_create_file("ppe_vp", 0400, nss_top_main.stats_dentry,
&nss_top_main, &nss_ppe_vp_stats_ops);
if (unlikely(ppe_vp_d == NULL)) {
nss_warning("Failed to create qca-nss-drv/stats/ppe_vp file");
return NULL;
}
return ppe_vp_d;
}