blob: 55281f06dca25840146508f8adda8558f509df4a [file] [log] [blame]
/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/stringify.h>
#include "ipa_i.h"
#include "../ipa_rm_i.h"
#include "ipahal/ipahal_nat.h"
#include "ipa_odl.h"
#include "ipa_qmi_service.h"
#define IPA_MAX_ENTRY_STRING_LEN 500
#define IPA_MAX_MSG_LEN 4096
#define IPA_DBG_MAX_RULE_IN_TBL 128
#define IPA_DBG_ACTIVE_CLIENT_BUF_SIZE ((IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN \
* IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) + IPA_MAX_MSG_LEN)
#define IPA_DUMP_STATUS_FIELD(f) \
pr_err(#f "=0x%x\n", status->f)
#define IPA_READ_ONLY_MODE 0444
#define IPA_READ_WRITE_MODE 0664
#define IPA_WRITE_ONLY_MODE 0220
struct ipa3_debugfs_file {
const char *name;
umode_t mode;
void *data;
const struct file_operations fops;
};
const char *ipa3_event_name[] = {
__stringify(WLAN_CLIENT_CONNECT),
__stringify(WLAN_CLIENT_DISCONNECT),
__stringify(WLAN_CLIENT_POWER_SAVE_MODE),
__stringify(WLAN_CLIENT_NORMAL_MODE),
__stringify(SW_ROUTING_ENABLE),
__stringify(SW_ROUTING_DISABLE),
__stringify(WLAN_AP_CONNECT),
__stringify(WLAN_AP_DISCONNECT),
__stringify(WLAN_STA_CONNECT),
__stringify(WLAN_STA_DISCONNECT),
__stringify(WLAN_CLIENT_CONNECT_EX),
__stringify(WLAN_SWITCH_TO_SCC),
__stringify(WLAN_SWITCH_TO_MCC),
__stringify(WLAN_WDI_ENABLE),
__stringify(WLAN_WDI_DISABLE),
__stringify(WAN_UPSTREAM_ROUTE_ADD),
__stringify(WAN_UPSTREAM_ROUTE_DEL),
__stringify(WAN_EMBMS_CONNECT),
__stringify(WAN_XLAT_CONNECT),
__stringify(ECM_CONNECT),
__stringify(ECM_DISCONNECT),
__stringify(IPA_TETHERING_STATS_UPDATE_STATS),
__stringify(IPA_TETHERING_STATS_UPDATE_NETWORK_STATS),
__stringify(IPA_QUOTA_REACH),
__stringify(IPA_SSR_BEFORE_SHUTDOWN),
__stringify(IPA_SSR_AFTER_POWERUP),
__stringify(ADD_VLAN_IFACE),
__stringify(DEL_VLAN_IFACE),
__stringify(ADD_L2TP_VLAN_MAPPING),
__stringify(DEL_L2TP_VLAN_MAPPING),
__stringify(IPA_PER_CLIENT_STATS_CONNECT_EVENT),
__stringify(IPA_PER_CLIENT_STATS_DISCONNECT_EVENT),
__stringify(ADD_BRIDGE_VLAN_MAPPING),
__stringify(DEL_BRIDGE_VLAN_MAPPING),
__stringify(WLAN_FWR_SSR_BEFORE_SHUTDOWN),
__stringify(IPA_GSB_CONNECT),
__stringify(IPA_GSB_DISCONNECT),
__stringify(IPA_COALESCE_ENABLE),
__stringify(IPA_COALESCE_DISABLE),
__stringify(WIGIG_CLIENT_CONNECT),
__stringify(WIGIG_FST_SWITCH),
__stringify(IPA_SOCKV5_ADD),
__stringify(IPA_SOCKV5_DEL),
__stringify(IPA_PDN_DEFAULT_MODE_CONFIG),
__stringify(IPA_PDN_IP_COLLISION_MODE_CONFIG),
__stringify(IPA_PDN_IP_PASSTHROUGH_MODE_CONFIG),
__stringify(IPA_MAC_FLT_EVENT),
};
const char *ipa3_hdr_l2_type_name[] = {
__stringify(IPA_HDR_L2_NONE),
__stringify(IPA_HDR_L2_ETHERNET_II),
__stringify(IPA_HDR_L2_802_3),
__stringify(IPA_HDR_L2_802_1Q),
};
const char *ipa3_hdr_proc_type_name[] = {
__stringify(IPA_HDR_PROC_NONE),
__stringify(IPA_HDR_PROC_ETHII_TO_ETHII),
__stringify(IPA_HDR_PROC_ETHII_TO_802_3),
__stringify(IPA_HDR_PROC_802_3_TO_ETHII),
__stringify(IPA_HDR_PROC_802_3_TO_802_3),
__stringify(IPA_HDR_PROC_L2TP_HEADER_ADD),
__stringify(IPA_HDR_PROC_L2TP_HEADER_REMOVE),
__stringify(IPA_HDR_PROC_ETHII_TO_ETHII_EX),
__stringify(IPA_HDR_PROC_L2TP_UDP_HEADER_ADD),
__stringify(IPA_HDR_PROC_L2TP_UDP_HEADER_REMOVE),
__stringify(IPA_HDR_PROC_SET_DSCP),
};
static struct dentry *dent;
static char dbg_buff[IPA_MAX_MSG_LEN + 1];
static char *active_clients_buf;
static s8 ep_reg_idx;
static void *ipa_ipc_low_buff;
#define IPA_MAX_DEBUG_MSG_LEN (IPA_MAX_MSG_LEN * 8)
#define IPA_DEBUG_MSG_DUMP_HW 0 /*1: enable, 0: disable*/
static int ipa_msg_buff_count;
static char *ipa_msg_buff;
static ssize_t ipa3_read_dump_debug_msg(struct file*,
char __user*, size_t, loff_t*);
static ssize_t ipa3_read_gen_reg(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int nbytes;
struct ipahal_reg_shared_mem_size smem_sz;
memset(&smem_sz, 0, sizeof(smem_sz));
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
ipahal_read_reg_fields(IPA_SHARED_MEM_SIZE, &smem_sz);
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"IPA_VERSION=0x%x\n"
"IPA_COMP_HW_VERSION=0x%x\n"
"IPA_ROUTE=0x%x\n"
"IPA_SHARED_MEM_RESTRICTED=0x%x\n"
"IPA_SHARED_MEM_SIZE=0x%x\n"
"IPA_QTIME_TIMESTAMP_CFG=0x%x\n"
"IPA_TIMERS_PULSE_GRAN_CFG=0x%x\n"
"IPA_TIMERS_XO_CLK_DIV_CFG=0x%x\n",
ipahal_read_reg(IPA_VERSION),
ipahal_read_reg(IPA_COMP_HW_VERSION),
ipahal_read_reg(IPA_ROUTE),
smem_sz.shared_mem_baddr,
smem_sz.shared_mem_sz,
ipahal_read_reg(IPA_QTIME_TIMESTAMP_CFG),
ipahal_read_reg(IPA_TIMERS_PULSE_GRAN_CFG),
ipahal_read_reg(IPA_TIMERS_XO_CLK_DIV_CFG));
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
}
static ssize_t ipa3_write_ep_holb(struct file *file,
const char __user *buf, size_t count, loff_t *ppos)
{
struct ipa_ep_cfg_holb holb;
u32 en;
u32 tmr_val;
u32 ep_idx;
unsigned long missing;
char *sptr, *token;
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, min(sizeof(dbg_buff), count));
if (missing)
return -EFAULT;
dbg_buff[count] = '\0';
sptr = dbg_buff;
token = strsep(&sptr, " ");
if (!token)
return -EINVAL;
if (kstrtou32(token, 0, &ep_idx))
return -EINVAL;
token = strsep(&sptr, " ");
if (!token)
return -EINVAL;
if (kstrtou32(token, 0, &en))
return -EINVAL;
token = strsep(&sptr, " ");
if (!token)
return -EINVAL;
if (kstrtou32(token, 0, &tmr_val))
return -EINVAL;
holb.en = en;
holb.tmr_val = tmr_val;
ipa3_cfg_ep_holb(ep_idx, &holb);
return count;
}
static ssize_t ipa3_write_ep_reg(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long missing;
s8 option = 0;
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, min(sizeof(dbg_buff), count));
if (missing)
return -EFAULT;
dbg_buff[count] = '\0';
if (kstrtos8(dbg_buff, 0, &option))
return -EFAULT;
if (option >= ipa3_ctx->ipa_num_pipes) {
IPAERR("bad pipe specified %u\n", option);
return count;
}
ep_reg_idx = option;
return count;
}
/**
* _ipa_read_ep_reg_v3_0() - Reads and prints endpoint configuration registers
*
* Returns the number of characters printed
*/
int _ipa_read_ep_reg_v3_0(char *buf, int max_len, int pipe)
{
return scnprintf(
dbg_buff, IPA_MAX_MSG_LEN,
"IPA_ENDP_INIT_NAT_%u=0x%x\n"
"IPA_ENDP_INIT_HDR_%u=0x%x\n"
"IPA_ENDP_INIT_HDR_EXT_%u=0x%x\n"
"IPA_ENDP_INIT_MODE_%u=0x%x\n"
"IPA_ENDP_INIT_AGGR_%u=0x%x\n"
"IPA_ENDP_INIT_ROUTE_%u=0x%x\n"
"IPA_ENDP_INIT_CTRL_%u=0x%x\n"
"IPA_ENDP_INIT_HOL_EN_%u=0x%x\n"
"IPA_ENDP_INIT_HOL_TIMER_%u=0x%x\n"
"IPA_ENDP_INIT_DEAGGR_%u=0x%x\n"
"IPA_ENDP_INIT_CFG_%u=0x%x\n",
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_NAT_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_HDR_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_HDR_EXT_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_MODE_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_AGGR_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_ROUTE_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_CTRL_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_HOL_BLOCK_EN_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_DEAGGR_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_CFG_n, pipe));
}
/**
* _ipa_read_ep_reg_v4_0() - Reads and prints endpoint configuration registers
*
* Returns the number of characters printed
* Removed IPA_ENDP_INIT_ROUTE_n from v3
*/
int _ipa_read_ep_reg_v4_0(char *buf, int max_len, int pipe)
{
return scnprintf(
dbg_buff, IPA_MAX_MSG_LEN,
"IPA_ENDP_INIT_NAT_%u=0x%x\n"
"IPA_ENDP_INIT_CONN_TRACK_n%u=0x%x\n"
"IPA_ENDP_INIT_HDR_%u=0x%x\n"
"IPA_ENDP_INIT_HDR_EXT_%u=0x%x\n"
"IPA_ENDP_INIT_MODE_%u=0x%x\n"
"IPA_ENDP_INIT_AGGR_%u=0x%x\n"
"IPA_ENDP_INIT_CTRL_%u=0x%x\n"
"IPA_ENDP_INIT_HOL_EN_%u=0x%x\n"
"IPA_ENDP_INIT_HOL_TIMER_%u=0x%x\n"
"IPA_ENDP_INIT_DEAGGR_%u=0x%x\n"
"IPA_ENDP_INIT_CFG_%u=0x%x\n",
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_NAT_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_CONN_TRACK_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_HDR_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_HDR_EXT_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_MODE_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_AGGR_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_CTRL_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_HOL_BLOCK_EN_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_DEAGGR_n, pipe),
pipe, ipahal_read_reg_n(IPA_ENDP_INIT_CFG_n, pipe));
}
static ssize_t ipa3_read_ep_reg(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int nbytes;
int i;
int start_idx;
int end_idx;
int size = 0;
int ret;
loff_t pos;
/* negative ep_reg_idx means all registers */
if (ep_reg_idx < 0) {
start_idx = 0;
end_idx = ipa3_ctx->ipa_num_pipes;
} else {
start_idx = ep_reg_idx;
end_idx = start_idx + 1;
}
pos = *ppos;
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
for (i = start_idx; i < end_idx; i++) {
nbytes = ipa3_ctx->ctrl->ipa3_read_ep_reg(dbg_buff,
IPA_MAX_MSG_LEN, i);
*ppos = pos;
ret = simple_read_from_buffer(ubuf, count, ppos, dbg_buff,
nbytes);
if (ret < 0) {
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return ret;
}
size += ret;
ubuf += nbytes;
count -= nbytes;
}
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
*ppos = pos + size;
return size;
}
static ssize_t ipa3_write_keep_awake(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long missing;
s8 option = 0;
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, min(sizeof(dbg_buff), count));
if (missing)
return -EFAULT;
dbg_buff[count] = '\0';
if (kstrtos8(dbg_buff, 0, &option))
return -EFAULT;
if (option == 0) {
if (ipa_pm_remove_dummy_clients()) {
pr_err("Failed to remove dummy clients\n");
return -EFAULT;
}
} else {
if (ipa_pm_add_dummy_clients(option - 1)) {
pr_err("Failed to add dummy clients\n");
return -EFAULT;
}
}
return count;
}
static ssize_t ipa3_read_keep_awake(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int nbytes;
mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt))
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"IPA APPS power state is ON\n");
else
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"IPA APPS power state is OFF\n");
mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
}
static ssize_t ipa3_read_hdr(struct file *file, char __user *ubuf, size_t count,
loff_t *ppos)
{
int nbytes = 0;
int i = 0;
struct ipa3_hdr_entry *entry;
mutex_lock(&ipa3_ctx->lock);
if (ipa3_ctx->hdr_tbl_lcl)
pr_err("Table resides on local memory\n");
else
pr_err("Table resides on system (ddr) memory\n");
list_for_each_entry(entry, &ipa3_ctx->hdr_tbl.head_hdr_entry_list,
link) {
if (entry->cookie != IPA_HDR_COOKIE)
continue;
nbytes = scnprintf(
dbg_buff,
IPA_MAX_MSG_LEN,
"name:%s len=%d ref=%d partial=%d type=%s ",
entry->name,
entry->hdr_len,
entry->ref_cnt,
entry->is_partial,
ipa3_hdr_l2_type_name[entry->type]);
if (entry->is_hdr_proc_ctx) {
nbytes += scnprintf(
dbg_buff + nbytes,
IPA_MAX_MSG_LEN - nbytes,
"phys_base=0x%pa ",
&entry->phys_base);
} else {
nbytes += scnprintf(
dbg_buff + nbytes,
IPA_MAX_MSG_LEN - nbytes,
"ofst=%u ",
entry->offset_entry->offset >> 2);
}
for (i = 0; i < entry->hdr_len; i++) {
scnprintf(dbg_buff + nbytes + i * 2,
IPA_MAX_MSG_LEN - nbytes - i * 2,
"%02x", entry->hdr[i]);
}
scnprintf(dbg_buff + nbytes + entry->hdr_len * 2,
IPA_MAX_MSG_LEN - nbytes - entry->hdr_len * 2,
"\n");
pr_err("%s", dbg_buff);
}
mutex_unlock(&ipa3_ctx->lock);
return 0;
}
static int ipa3_attrib_dump(struct ipa_rule_attrib *attrib,
enum ipa_ip_type ip)
{
uint32_t addr[4];
uint32_t mask[4];
int i;
if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK)
pr_err("is_pure_ack ");
if (attrib->attrib_mask & IPA_FLT_TOS)
pr_cont("tos:%d ", attrib->u.v4.tos);
if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
pr_cont("tos_value:%d ", attrib->tos_value);
pr_cont("tos_mask:%d ", attrib->tos_mask);
}
if (attrib->attrib_mask & IPA_FLT_PROTOCOL)
pr_err("protocol:%d ", attrib->u.v4.protocol);
if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) {
if (ip == IPA_IP_v4) {
addr[0] = htonl(attrib->u.v4.src_addr);
mask[0] = htonl(attrib->u.v4.src_addr_mask);
pr_err(
"src_addr:%pI4 src_addr_mask:%pI4 ",
addr + 0, mask + 0);
} else if (ip == IPA_IP_v6) {
for (i = 0; i < 4; i++) {
addr[i] = htonl(attrib->u.v6.src_addr[i]);
mask[i] = htonl(attrib->u.v6.src_addr_mask[i]);
}
pr_err(
"src_addr:%pI6 src_addr_mask:%pI6 ",
addr + 0, mask + 0);
}
}
if (attrib->attrib_mask & IPA_FLT_DST_ADDR) {
if (ip == IPA_IP_v4) {
addr[0] = htonl(attrib->u.v4.dst_addr);
mask[0] = htonl(attrib->u.v4.dst_addr_mask);
pr_err(
"dst_addr:%pI4 dst_addr_mask:%pI4 ",
addr + 0, mask + 0);
} else if (ip == IPA_IP_v6) {
for (i = 0; i < 4; i++) {
addr[i] = htonl(attrib->u.v6.dst_addr[i]);
mask[i] = htonl(attrib->u.v6.dst_addr_mask[i]);
}
pr_err(
"dst_addr:%pI6 dst_addr_mask:%pI6 ",
addr + 0, mask + 0);
}
}
if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) {
pr_err("src_port_range:%u %u ",
attrib->src_port_lo,
attrib->src_port_hi);
}
if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) {
pr_err("dst_port_range:%u %u ",
attrib->dst_port_lo,
attrib->dst_port_hi);
}
if (attrib->attrib_mask & IPA_FLT_TYPE)
pr_err("type:%d ", attrib->type);
if (attrib->attrib_mask & IPA_FLT_CODE)
pr_err("code:%d ", attrib->code);
if (attrib->attrib_mask & IPA_FLT_SPI)
pr_err("spi:%x ", attrib->spi);
if (attrib->attrib_mask & IPA_FLT_SRC_PORT)
pr_err("src_port:%u ", attrib->src_port);
if (attrib->attrib_mask & IPA_FLT_DST_PORT)
pr_err("dst_port:%u ", attrib->dst_port);
if (attrib->attrib_mask & IPA_FLT_TC)
pr_err("tc:%d ", attrib->u.v6.tc);
if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL)
pr_err("flow_label:%x ", attrib->u.v6.flow_label);
if (attrib->attrib_mask & IPA_FLT_NEXT_HDR)
pr_err("next_hdr:%d ", attrib->u.v6.next_hdr);
if (attrib->ext_attrib_mask & IPA_FLT_EXT_NEXT_HDR)
pr_err("next_hdr:%d ", attrib->u.v6.next_hdr);
if (attrib->attrib_mask & IPA_FLT_META_DATA) {
pr_err(
"metadata:%x metadata_mask:%x ",
attrib->meta_data, attrib->meta_data_mask);
}
if (attrib->attrib_mask & IPA_FLT_FRAGMENT)
pr_err("frg ");
if ((attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_ETHER_II) ||
(attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_3) ||
(attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_1Q)) {
pr_err("src_mac_addr:%pM ", attrib->src_mac_addr);
}
if ((attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_ETHER_II) ||
(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_3) ||
(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_L2TP) ||
(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_1Q) ||
(attrib->attrib_mask & IPA_FLT_L2TP_UDP_INNER_MAC_DST_ADDR)) {
pr_err("dst_mac_addr:%pM ", attrib->dst_mac_addr);
}
if (attrib->ext_attrib_mask & IPA_FLT_EXT_MTU)
pr_err("Payload Length:%d ", attrib->payload_length);
if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE ||
attrib->ext_attrib_mask & IPA_FLT_EXT_L2TP_UDP_INNER_ETHER_TYPE)
pr_err("ether_type:%x ", attrib->ether_type);
if (attrib->attrib_mask & IPA_FLT_VLAN_ID)
pr_err("vlan_id:%x ", attrib->vlan_id);
if (attrib->attrib_mask & IPA_FLT_TCP_SYN)
pr_err("tcp syn ");
if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP ||
attrib->ext_attrib_mask & IPA_FLT_EXT_L2TP_UDP_TCP_SYN)
pr_err("tcp syn l2tp ");
if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE)
pr_err("l2tp inner ip type: %d ", attrib->type);
if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) {
addr[0] = htonl(attrib->u.v4.dst_addr);
mask[0] = htonl(attrib->u.v4.dst_addr_mask);
pr_err("dst_addr:%pI4 dst_addr_mask:%pI4 ", addr, mask);
}
pr_err("\n");
return 0;
}
static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib)
{
uint8_t addr[16];
uint8_t mask[16];
int i;
int j;
if (attrib->tos_eq_present) {
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5)
pr_err("pure_ack ");
else
pr_err("tos:%d ", attrib->tos_eq);
}
if (attrib->protocol_eq_present)
pr_err("protocol:%d ", attrib->protocol_eq);
if (attrib->tc_eq_present)
pr_err("tc:%d ", attrib->tc_eq);
if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) {
IPAERR_RL("num_offset_meq_128 Max %d passed value %d\n",
IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128);
return -EPERM;
}
for (i = 0; i < attrib->num_offset_meq_128; i++) {
for (j = 0; j < 16; j++) {
addr[j] = attrib->offset_meq_128[i].value[j];
mask[j] = attrib->offset_meq_128[i].mask[j];
}
pr_err(
"(ofst_meq128: ofst:%d mask:%pI6 val:%pI6) ",
attrib->offset_meq_128[i].offset,
mask, addr);
}
if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) {
IPAERR_RL("num_offset_meq_32 Max %d passed value %d\n",
IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32);
return -EPERM;
}
for (i = 0; i < attrib->num_offset_meq_32; i++)
pr_err(
"(ofst_meq32: ofst:%u mask:0x%x val:0x%x) ",
attrib->offset_meq_32[i].offset,
attrib->offset_meq_32[i].mask,
attrib->offset_meq_32[i].value);
if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) {
IPAERR_RL("num_ihl_offset_meq_32 Max %d passed value %d\n",
IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, attrib->num_ihl_offset_meq_32);
return -EPERM;
}
for (i = 0; i < attrib->num_ihl_offset_meq_32; i++)
pr_err(
"(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x) ",
attrib->ihl_offset_meq_32[i].offset,
attrib->ihl_offset_meq_32[i].mask,
attrib->ihl_offset_meq_32[i].value);
if (attrib->metadata_meq32_present)
pr_err(
"(metadata: ofst:%u mask:0x%x val:0x%x) ",
attrib->metadata_meq32.offset,
attrib->metadata_meq32.mask,
attrib->metadata_meq32.value);
if (attrib->num_ihl_offset_range_16 >
IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) {
IPAERR_RL("num_ihl_offset_range_16 Max %d passed value %d\n",
IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS,
attrib->num_ihl_offset_range_16);
return -EPERM;
}
for (i = 0; i < attrib->num_ihl_offset_range_16; i++)
pr_err(
"(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ",
attrib->ihl_offset_range_16[i].offset,
attrib->ihl_offset_range_16[i].range_low,
attrib->ihl_offset_range_16[i].range_high);
if (attrib->ihl_offset_eq_32_present)
pr_err(
"(ihl_ofst_eq32:%d val:0x%x) ",
attrib->ihl_offset_eq_32.offset,
attrib->ihl_offset_eq_32.value);
if (attrib->ihl_offset_eq_16_present)
pr_err(
"(ihl_ofst_eq16:%d val:0x%x) ",
attrib->ihl_offset_eq_16.offset,
attrib->ihl_offset_eq_16.value);
if (attrib->fl_eq_present)
pr_err("flow_label:%d ", attrib->fl_eq);
if (attrib->ipv4_frag_eq_present)
pr_err("frag ");
pr_err("\n");
return 0;
}
static int ipa3_open_dbg(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t ipa3_read_rt(struct file *file, char __user *ubuf, size_t count,
loff_t *ppos)
{
int i = 0;
struct ipa3_rt_tbl *tbl;
struct ipa3_rt_entry *entry;
struct ipa3_rt_tbl_set *set;
enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data;
u32 ofst;
u32 ofst_words;
set = &ipa3_ctx->rt_tbl_set[ip];
mutex_lock(&ipa3_ctx->lock);
if (ip == IPA_IP_v6) {
if (ipa3_ctx->ip6_rt_tbl_hash_lcl)
pr_err("Hashable table resides on local memory\n");
else
pr_err("Hashable table resides on system (ddr) memory\n");
if (ipa3_ctx->ip6_rt_tbl_nhash_lcl)
pr_err("Non-Hashable table resides on local memory\n");
else
pr_err("Non-Hashable table resides on system (ddr) memory\n");
} else if (ip == IPA_IP_v4) {
if (ipa3_ctx->ip4_rt_tbl_hash_lcl)
pr_err("Hashable table resides on local memory\n");
else
pr_err("Hashable table resides on system (ddr) memory\n");
if (ipa3_ctx->ip4_rt_tbl_nhash_lcl)
pr_err("Non-Hashable table resides on local memory\n");
else
pr_err("Non-Hashable table resides on system (ddr) memory\n");
}
list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
i = 0;
list_for_each_entry(entry, &tbl->head_rt_rule_list, link) {
if (entry->proc_ctx) {
ofst = entry->proc_ctx->offset_entry->offset;
ofst_words =
(ofst +
ipa3_ctx->hdr_proc_ctx_tbl.start_offset)
>> 5;
pr_err("tbl_idx:%d tbl_name:%s tbl_ref:%u ",
entry->tbl->idx, entry->tbl->name,
entry->tbl->ref_cnt);
pr_err("rule_idx:%d dst:%d ep:%d S:%u ",
i, entry->rule.dst,
ipa3_get_ep_mapping(entry->rule.dst),
!ipa3_ctx->hdr_proc_ctx_tbl_lcl);
pr_err("proc_ctx[32B]:%u attrib_mask:%08x ",
ofst_words,
entry->rule.attrib.attrib_mask);
pr_err("rule_id:%u max_prio:%u prio:%u ",
entry->rule_id, entry->rule.max_prio,
entry->prio);
pr_err("enable_stats:%u counter_id:%u ",
entry->rule.enable_stats,
entry->rule.cnt_idx);
pr_err("hashable:%u retain_hdr:%u ",
entry->rule.hashable,
entry->rule.retain_hdr);
} else {
if (entry->hdr)
ofst = entry->hdr->offset_entry->offset;
else
ofst = 0;
pr_err("tbl_idx:%d tbl_name:%s tbl_ref:%u ",
entry->tbl->idx, entry->tbl->name,
entry->tbl->ref_cnt);
pr_err("rule_idx:%d dst:%d ep:%d S:%u ",
i, entry->rule.dst,
ipa3_get_ep_mapping(entry->rule.dst),
!ipa3_ctx->hdr_tbl_lcl);
pr_err("hdr_ofst[words]:%u attrib_mask:%08x ",
ofst >> 2,
entry->rule.attrib.attrib_mask);
pr_err("rule_id:%u max_prio:%u prio:%u ",
entry->rule_id, entry->rule.max_prio,
entry->prio);
pr_err("enable_stats:%u counter_id:%u ",
entry->rule.enable_stats,
entry->rule.cnt_idx);
pr_err("hashable:%u retain_hdr:%u ",
entry->rule.hashable,
entry->rule.retain_hdr);
}
ipa3_attrib_dump(&entry->rule.attrib, ip);
i++;
}
}
mutex_unlock(&ipa3_ctx->lock);
return 0;
}
static ssize_t ipa3_read_rt_hw(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data;
int tbls_num;
int rules_num;
int tbl;
int rl;
int res = 0;
struct ipahal_rt_rule_entry *rules = NULL;
switch (ip) {
case IPA_IP_v4:
tbls_num = IPA_MEM_PART(v4_rt_num_index);
break;
case IPA_IP_v6:
tbls_num = IPA_MEM_PART(v6_rt_num_index);
break;
default:
IPAERR("ip type error %d\n", ip);
return -EINVAL;
};
IPADBG("Tring to parse %d H/W routing tables - IP=%d\n", tbls_num, ip);
rules = kzalloc(sizeof(*rules) * IPA_DBG_MAX_RULE_IN_TBL, GFP_KERNEL);
if (!rules) {
IPAERR("failed to allocate mem for tbl rules\n");
return -ENOMEM;
}
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
mutex_lock(&ipa3_ctx->lock);
for (tbl = 0 ; tbl < tbls_num ; tbl++) {
pr_err("=== Routing Table %d = Hashable Rules ===\n", tbl);
rules_num = IPA_DBG_MAX_RULE_IN_TBL;
res = ipa3_rt_read_tbl_from_hw(tbl, ip, true, rules,
&rules_num);
if (res) {
pr_err("ERROR - Check the logs\n");
IPAERR("failed reading tbl from hw\n");
goto bail;
}
if (!rules_num)
pr_err("-->No rules. Empty tbl or modem system table\n");
for (rl = 0 ; rl < rules_num ; rl++) {
pr_err("rule_idx:%d dst ep:%d L:%u ",
rl, rules[rl].dst_pipe_idx, rules[rl].hdr_lcl);
if (rules[rl].hdr_type == IPAHAL_RT_RULE_HDR_PROC_CTX)
pr_err("proc_ctx:%u attrib_mask:%08x ",
rules[rl].hdr_ofst,
rules[rl].eq_attrib.rule_eq_bitmap);
else
pr_err("hdr_ofst:%u attrib_mask:%08x ",
rules[rl].hdr_ofst,
rules[rl].eq_attrib.rule_eq_bitmap);
pr_err("rule_id:%u cnt_id:%hhu prio:%u retain_hdr:%u ",
rules[rl].id, rules[rl].cnt_idx,
rules[rl].priority, rules[rl].retain_hdr);
res = ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
if (res) {
IPAERR_RL("failed read attrib eq\n");
goto bail;
}
}
pr_err("=== Routing Table %d = Non-Hashable Rules ===\n", tbl);
rules_num = IPA_DBG_MAX_RULE_IN_TBL;
res = ipa3_rt_read_tbl_from_hw(tbl, ip, false, rules,
&rules_num);
if (res) {
pr_err("ERROR - Check the logs\n");
IPAERR("failed reading tbl from hw\n");
goto bail;
}
if (!rules_num)
pr_err("-->No rules. Empty tbl or modem system table\n");
for (rl = 0 ; rl < rules_num ; rl++) {
pr_err("rule_idx:%d dst ep:%d L:%u ",
rl, rules[rl].dst_pipe_idx, rules[rl].hdr_lcl);
if (rules[rl].hdr_type == IPAHAL_RT_RULE_HDR_PROC_CTX)
pr_err("proc_ctx:%u attrib_mask:%08x ",
rules[rl].hdr_ofst,
rules[rl].eq_attrib.rule_eq_bitmap);
else
pr_err("hdr_ofst:%u attrib_mask:%08x ",
rules[rl].hdr_ofst,
rules[rl].eq_attrib.rule_eq_bitmap);
pr_err("rule_id:%u cnt_id:%hhu prio:%u retain_hdr:%u ",
rules[rl].id, rules[rl].cnt_idx,
rules[rl].priority, rules[rl].retain_hdr);
res = ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
if (res) {
IPAERR_RL("failed read attrib eq\n");
goto bail;
}
}
pr_err("\n");
}
bail:
mutex_unlock(&ipa3_ctx->lock);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
kfree(rules);
return res;
}
static ssize_t ipa3_read_proc_ctx(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int nbytes = 0;
struct ipa3_hdr_proc_ctx_tbl *tbl;
struct ipa3_hdr_proc_ctx_entry *entry;
u32 ofst_words;
tbl = &ipa3_ctx->hdr_proc_ctx_tbl;
mutex_lock(&ipa3_ctx->lock);
if (ipa3_ctx->hdr_proc_ctx_tbl_lcl)
pr_info("Table resides on local memory\n");
else
pr_info("Table resides on system(ddr) memory\n");
list_for_each_entry(entry, &tbl->head_proc_ctx_entry_list, link) {
ofst_words = (entry->offset_entry->offset +
ipa3_ctx->hdr_proc_ctx_tbl.start_offset)
>> 5;
if (entry->hdr->is_hdr_proc_ctx) {
nbytes += scnprintf(dbg_buff + nbytes,
IPA_MAX_MSG_LEN - nbytes,
"id:%u hdr_proc_type:%s proc_ctx[32B]:%u ",
entry->id,
ipa3_hdr_proc_type_name[entry->type],
ofst_words);
nbytes += scnprintf(dbg_buff + nbytes,
IPA_MAX_MSG_LEN - nbytes,
"hdr_phys_base:0x%pa\n",
&entry->hdr->phys_base);
} else {
nbytes += scnprintf(dbg_buff + nbytes,
IPA_MAX_MSG_LEN - nbytes,
"id:%u hdr_proc_type:%s proc_ctx[32B]:%u ",
entry->id,
ipa3_hdr_proc_type_name[entry->type],
ofst_words);
nbytes += scnprintf(dbg_buff + nbytes,
IPA_MAX_MSG_LEN - nbytes,
"hdr[words]:%u\n",
entry->hdr->offset_entry->offset >> 2);
}
}
mutex_unlock(&ipa3_ctx->lock);
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
}
static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count,
loff_t *ppos)
{
int i;
int j;
struct ipa3_flt_tbl *tbl;
struct ipa3_flt_entry *entry;
enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data;
struct ipa3_rt_tbl *rt_tbl;
u32 rt_tbl_idx;
u32 bitmap;
bool eq;
int res = 0;
mutex_lock(&ipa3_ctx->lock);
for (j = 0; j < ipa3_ctx->ipa_num_pipes; j++) {
if (!ipa_is_ep_support_flt(j))
continue;
tbl = &ipa3_ctx->flt_tbl[j][ip];
i = 0;
list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
if (entry->cookie != IPA_FLT_COOKIE)
continue;
if (entry->rule.eq_attrib_type) {
rt_tbl_idx = entry->rule.rt_tbl_idx;
bitmap = entry->rule.eq_attrib.rule_eq_bitmap;
eq = true;
} else {
rt_tbl = ipa3_id_find(entry->rule.rt_tbl_hdl);
if (rt_tbl == NULL ||
rt_tbl->cookie != IPA_RT_TBL_COOKIE)
rt_tbl_idx = ~0;
else
rt_tbl_idx = rt_tbl->idx;
bitmap = entry->rule.attrib.attrib_mask;
eq = false;
}
pr_err("ep_idx:%d rule_idx:%d act:%d rt_tbl_idx:%d ",
j, i, entry->rule.action, rt_tbl_idx);
pr_err("attrib_mask:%08x retain_hdr:%d eq:%d ",
bitmap, entry->rule.retain_hdr, eq);
pr_err("hashable:%u rule_id:%u max_prio:%u prio:%u ",
entry->rule.hashable, entry->rule_id,
entry->rule.max_prio, entry->prio);
pr_err("enable_stats:%u counter_id:%u ",
entry->rule.enable_stats,
entry->rule.cnt_idx);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
pr_err("pdn index %d, set metadata %d ",
entry->rule.pdn_idx,
entry->rule.set_metadata);
if (eq) {
res = ipa3_attrib_dump_eq(
&entry->rule.eq_attrib);
if (res) {
IPAERR_RL("failed read attrib eq\n");
goto bail;
}
} else
ipa3_attrib_dump(
&entry->rule.attrib, ip);
i++;
}
}
bail:
mutex_unlock(&ipa3_ctx->lock);
return res;
}
static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int pipe;
int rl;
int rules_num;
struct ipahal_flt_rule_entry *rules;
enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data;
u32 rt_tbl_idx;
u32 bitmap;
int res = 0;
IPADBG("Tring to parse %d H/W filtering tables - IP=%d\n",
ipa3_ctx->ep_flt_num, ip);
rules = kzalloc(sizeof(*rules) * IPA_DBG_MAX_RULE_IN_TBL, GFP_KERNEL);
if (!rules)
return -ENOMEM;
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
mutex_lock(&ipa3_ctx->lock);
for (pipe = 0; pipe < ipa3_ctx->ipa_num_pipes; pipe++) {
if (!ipa_is_ep_support_flt(pipe))
continue;
pr_err("=== Filtering Table ep:%d = Hashable Rules ===\n",
pipe);
rules_num = IPA_DBG_MAX_RULE_IN_TBL;
res = ipa3_flt_read_tbl_from_hw(pipe, ip, true, rules,
&rules_num);
if (res) {
pr_err("ERROR - Check the logs\n");
IPAERR("failed reading tbl from hw\n");
goto bail;
}
if (!rules_num)
pr_err("-->No rules. Empty tbl or modem sys table\n");
for (rl = 0; rl < rules_num; rl++) {
rt_tbl_idx = rules[rl].rule.rt_tbl_idx;
bitmap = rules[rl].rule.eq_attrib.rule_eq_bitmap;
pr_err("ep_idx:%d rule_idx:%d act:%d rt_tbl_idx:%d ",
pipe, rl, rules[rl].rule.action, rt_tbl_idx);
pr_err("attrib_mask:%08x retain_hdr:%d ",
bitmap, rules[rl].rule.retain_hdr);
pr_err("rule_id:%u cnt_id:%hhu prio:%u ",
rules[rl].id, rules[rl].cnt_idx,
rules[rl].priority);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
pr_err("pdn: %u, set_metadata: %u ",
rules[rl].rule.pdn_idx,
rules[rl].rule.set_metadata);
res = ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
if (res) {
IPAERR_RL("failed read attrib eq\n");
goto bail;
}
}
pr_err("=== Filtering Table ep:%d = Non-Hashable Rules ===\n",
pipe);
rules_num = IPA_DBG_MAX_RULE_IN_TBL;
res = ipa3_flt_read_tbl_from_hw(pipe, ip, false, rules,
&rules_num);
if (res) {
IPAERR("failed reading tbl from hw\n");
goto bail;
}
if (!rules_num)
pr_err("-->No rules. Empty tbl or modem sys table\n");
for (rl = 0; rl < rules_num; rl++) {
rt_tbl_idx = rules[rl].rule.rt_tbl_idx;
bitmap = rules[rl].rule.eq_attrib.rule_eq_bitmap;
pr_err("ep_idx:%d rule_idx:%d act:%d rt_tbl_idx:%d ",
pipe, rl, rules[rl].rule.action, rt_tbl_idx);
pr_err("attrib_mask:%08x retain_hdr:%d ",
bitmap, rules[rl].rule.retain_hdr);
pr_err("rule_id:%u cnt_id:%hhu prio:%u ",
rules[rl].id, rules[rl].cnt_idx,
rules[rl].priority);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
pr_err("pdn: %u, set_metadata: %u ",
rules[rl].rule.pdn_idx,
rules[rl].rule.set_metadata);
res = ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
if (res) {
IPAERR_RL("failed read attrib eq\n");
goto bail;
}
}
pr_err("\n");
}
bail:
mutex_unlock(&ipa3_ctx->lock);
kfree(rules);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return res;
}
static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int nbytes;
int i;
int cnt = 0;
uint connect = 0;
for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++)
connect |= (ipa3_ctx->ep[i].valid << i);
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"sw_tx=%u\n"
"hw_tx=%u\n"
"tx_non_linear=%u\n"
"tx_compl=%u\n"
"wan_rx=%u\n"
"stat_compl=%u\n"
"lan_aggr_close=%u\n"
"wan_aggr_close=%u\n"
"act_clnt=%u\n"
"con_clnt_bmap=0x%x\n"
"wan_rx_empty=%u\n"
"wan_repl_rx_empty=%u\n"
"lan_rx_empty=%u\n"
"lan_repl_rx_empty=%u\n"
"flow_enable=%u\n"
"flow_disable=%u\n",
"rx_page_drop_cnt=%u\n",
ipa3_ctx->stats.tx_sw_pkts,
ipa3_ctx->stats.tx_hw_pkts,
ipa3_ctx->stats.tx_non_linear,
ipa3_ctx->stats.tx_pkts_compl,
ipa3_ctx->stats.rx_pkts,
ipa3_ctx->stats.stat_compl,
ipa3_ctx->stats.aggr_close,
ipa3_ctx->stats.wan_aggr_close,
atomic_read(&ipa3_ctx->ipa3_active_clients.cnt),
connect,
ipa3_ctx->stats.wan_rx_empty,
ipa3_ctx->stats.wan_repl_rx_empty,
ipa3_ctx->stats.lan_rx_empty,
ipa3_ctx->stats.lan_repl_rx_empty,
ipa3_ctx->stats.flow_enable,
ipa3_ctx->stats.flow_disable,
ipa3_ctx->stats.rx_page_drop_cnt);
cnt += nbytes;
for (i = 0; i < IPAHAL_PKT_STATUS_EXCEPTION_MAX; i++) {
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt,
"lan_rx_excp[%u:%20s]=%u\n", i,
ipahal_pkt_status_exception_str(i),
ipa3_ctx->stats.rx_excp_pkts[i]);
cnt += nbytes;
}
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_odlstats(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int nbytes;
int cnt = 0;
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"ODL received pkt =%u\n"
"ODL processed pkt to DIAG=%u\n"
"ODL dropped pkt =%u\n"
"ODL packet in queue =%u\n",
ipa3_odl_ctx->stats.odl_rx_pkt,
ipa3_odl_ctx->stats.odl_tx_diag_pkt,
ipa3_odl_ctx->stats.odl_drop_pkt,
atomic_read(&ipa3_odl_ctx->stats.numer_in_queue));
cnt += nbytes;
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_page_recycle_stats(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
int nbytes;
int cnt = 0;
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"COAL : Total number of packets replenished =%llu\n"
"COAL : Number of tmp alloc packets =%llu\n"
"DEF : Total number of packets replenished =%llu\n"
"DEF : Number of tmp alloc packets =%llu\n",
ipa3_ctx->stats.page_recycle_stats[0].total_replenished,
ipa3_ctx->stats.page_recycle_stats[0].tmp_alloc,
ipa3_ctx->stats.page_recycle_stats[1].total_replenished,
ipa3_ctx->stats.page_recycle_stats[1].tmp_alloc);
cnt += nbytes;
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_wstats(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
#define HEAD_FRMT_STR "%25s\n"
#define FRMT_STR "%25s %10u\n"
#define FRMT_STR1 "%25s %10u\n\n"
int cnt = 0;
int nbytes;
int ipa_ep_idx;
enum ipa_client_type client = IPA_CLIENT_WLAN1_PROD;
struct ipa3_ep_context *ep;
do {
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
HEAD_FRMT_STR, "Client IPA_CLIENT_WLAN1_PROD Stats:");
cnt += nbytes;
ipa_ep_idx = ipa3_get_ep_mapping(client);
if (ipa_ep_idx == -1) {
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt, HEAD_FRMT_STR, "Not up");
cnt += nbytes;
break;
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (ep->valid != 1) {
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt, HEAD_FRMT_STR, "Not up");
cnt += nbytes;
break;
}
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR, "Avail Fifo Desc:",
atomic_read(&ep->avail_fifo_desc));
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR, "Rx Pkts Rcvd:", ep->wstats.rx_pkts_rcvd);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR, "Rx Pkts Status Rcvd:",
ep->wstats.rx_pkts_status_rcvd);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR, "Rx DH Rcvd:", ep->wstats.rx_hd_rcvd);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR, "Rx DH Processed:",
ep->wstats.rx_hd_processed);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR, "Rx DH Sent Back:", ep->wstats.rx_hd_reply);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR, "Rx Pkt Leak:", ep->wstats.rx_pkt_leak);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR1, "Rx DP Fail:", ep->wstats.rx_dp_fail);
cnt += nbytes;
} while (0);
client = IPA_CLIENT_WLAN1_CONS;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, HEAD_FRMT_STR,
"Client IPA_CLIENT_WLAN1_CONS Stats:");
cnt += nbytes;
while (1) {
ipa_ep_idx = ipa3_get_ep_mapping(client);
if (ipa_ep_idx == -1) {
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt, HEAD_FRMT_STR, "Not up");
cnt += nbytes;
goto nxt_clnt_cons;
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (ep->valid != 1) {
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt, HEAD_FRMT_STR, "Not up");
cnt += nbytes;
goto nxt_clnt_cons;
}
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR, "Tx Pkts Received:", ep->wstats.tx_pkts_rcvd);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR, "Tx Pkts Sent:", ep->wstats.tx_pkts_sent);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
FRMT_STR1, "Tx Pkts Dropped:",
ep->wstats.tx_pkts_dropped);
cnt += nbytes;
nxt_clnt_cons:
switch (client) {
case IPA_CLIENT_WLAN1_CONS:
client = IPA_CLIENT_WLAN2_CONS;
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt, HEAD_FRMT_STR,
"Client IPA_CLIENT_WLAN2_CONS Stats:");
cnt += nbytes;
continue;
case IPA_CLIENT_WLAN2_CONS:
client = IPA_CLIENT_WLAN3_CONS;
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt, HEAD_FRMT_STR,
"Client IPA_CLIENT_WLAN3_CONS Stats:");
cnt += nbytes;
continue;
case IPA_CLIENT_WLAN3_CONS:
client = IPA_CLIENT_WLAN4_CONS;
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt, HEAD_FRMT_STR,
"Client IPA_CLIENT_WLAN4_CONS Stats:");
cnt += nbytes;
continue;
case IPA_CLIENT_WLAN4_CONS:
default:
break;
}
break;
}
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"\n"HEAD_FRMT_STR, "All Wlan Consumer pipes stats:");
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR,
"Tx Comm Buff Allocated:",
ipa3_ctx->wc_memb.wlan_comm_total_cnt);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR,
"Tx Comm Buff Avail:", ipa3_ctx->wc_memb.wlan_comm_free_cnt);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt, FRMT_STR1,
"Total Tx Pkts Freed:", ipa3_ctx->wc_memb.total_tx_pkts_freed);
cnt += nbytes;
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_ntn(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
#define TX_STATS(x, y) \
stats.tx_ch_stats[x].y
#define RX_STATS(x, y) \
stats.rx_ch_stats[x].y
struct Ipa3HwStatsNTNInfoData_t stats;
int nbytes;
int cnt = 0, i = 0;
if (!ipa3_get_ntn_stats(&stats)) {
for (i = 0; i < IPA_UC_MAX_NTN_TX_CHANNELS; i++) {
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt,
"TX%d num_pkts_psr=%u\n"
"TX%d ringFull=%u\n"
"TX%d ringEmpty=%u\n"
"TX%d ringUsageHigh=%u\n"
"TX%d ringUsageLow=%u\n"
"TX%d RingUtilCount=%u\n"
"TX%d bamFifoFull=%u\n"
"TX%d bamFifoEmpty=%u\n"
"TX%d bamFifoUsageHigh=%u\n"
"TX%d bamFifoUsageLow=%u\n"
"TX%d bamUtilCount=%u\n"
"TX%d num_db=%u\n"
"TX%d num_qmb_int_handled=%u\n"
"TX%d ipa_pipe_number=%u\n",
i, TX_STATS(i, num_pkts_processed),
i, TX_STATS(i, ring_stats.ringFull),
i, TX_STATS(i, ring_stats.ringEmpty),
i, TX_STATS(i, ring_stats.ringUsageHigh),
i, TX_STATS(i, ring_stats.ringUsageLow),
i, TX_STATS(i, ring_stats.RingUtilCount),
i, TX_STATS(i, gsi_stats.bamFifoFull),
i, TX_STATS(i, gsi_stats.bamFifoEmpty),
i, TX_STATS(i, gsi_stats.bamFifoUsageHigh),
i, TX_STATS(i, gsi_stats.bamFifoUsageLow),
i, TX_STATS(i, gsi_stats.bamUtilCount),
i, TX_STATS(i, num_db),
i, TX_STATS(i, num_qmb_int_handled),
i, TX_STATS(i, ipa_pipe_number));
cnt += nbytes;
}
for (i = 0; i < IPA_UC_MAX_NTN_RX_CHANNELS; i++) {
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt,
"RX%d num_pkts_psr=%u\n"
"RX%d ringFull=%u\n"
"RX%d ringEmpty=%u\n"
"RX%d ringUsageHigh=%u\n"
"RX%d ringUsageLow=%u\n"
"RX%d RingUtilCount=%u\n"
"RX%d bamFifoFull=%u\n"
"RX%d bamFifoEmpty=%u\n"
"RX%d bamFifoUsageHigh=%u\n"
"RX%d bamFifoUsageLow=%u\n"
"RX%d bamUtilCount=%u\n"
"RX%d num_db=%u\n"
"RX%d num_qmb_int_handled=%u\n"
"RX%d ipa_pipe_number=%u\n",
i, RX_STATS(i, num_pkts_processed),
i, RX_STATS(i, ring_stats.ringFull),
i, RX_STATS(i, ring_stats.ringEmpty),
i, RX_STATS(i, ring_stats.ringUsageHigh),
i, RX_STATS(i, ring_stats.ringUsageLow),
i, RX_STATS(i, ring_stats.RingUtilCount),
i, RX_STATS(i, gsi_stats.bamFifoFull),
i, RX_STATS(i, gsi_stats.bamFifoEmpty),
i, RX_STATS(i, gsi_stats.bamFifoUsageHigh),
i, RX_STATS(i, gsi_stats.bamFifoUsageLow),
i, RX_STATS(i, gsi_stats.bamUtilCount),
i, RX_STATS(i, num_db),
i, RX_STATS(i, num_qmb_int_handled),
i, RX_STATS(i, ipa_pipe_number));
cnt += nbytes;
}
} else {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"Fail to read NTN stats\n");
cnt += nbytes;
}
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_wdi(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
struct IpaHwStatsWDIInfoData_t stats;
int nbytes;
int cnt = 0;
struct IpaHwStatsWDITxInfoData_t *tx_ch_ptr;
if (!ipa3_get_wdi_stats(&stats)) {
tx_ch_ptr = &stats.tx_ch_stats;
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"TX num_pkts_processed=%u\n"
"TX copy_engine_doorbell_value=%u\n"
"TX num_db_fired=%u\n"
"TX ringFull=%u\n"
"TX ringEmpty=%u\n"
"TX ringUsageHigh=%u\n"
"TX ringUsageLow=%u\n"
"TX RingUtilCount=%u\n"
"TX bamFifoFull=%u\n"
"TX bamFifoEmpty=%u\n"
"TX bamFifoUsageHigh=%u\n"
"TX bamFifoUsageLow=%u\n"
"TX bamUtilCount=%u\n"
"TX num_db=%u\n"
"TX num_unexpected_db=%u\n"
"TX num_bam_int_handled=%u\n"
"TX num_bam_int_in_non_running_state=%u\n"
"TX num_qmb_int_handled=%u\n"
"TX num_bam_int_handled_while_wait_for_bam=%u\n",
tx_ch_ptr->num_pkts_processed,
tx_ch_ptr->copy_engine_doorbell_value,
tx_ch_ptr->num_db_fired,
tx_ch_ptr->tx_comp_ring_stats.ringFull,
tx_ch_ptr->tx_comp_ring_stats.ringEmpty,
tx_ch_ptr->tx_comp_ring_stats.ringUsageHigh,
tx_ch_ptr->tx_comp_ring_stats.ringUsageLow,
tx_ch_ptr->tx_comp_ring_stats.RingUtilCount,
tx_ch_ptr->bam_stats.bamFifoFull,
tx_ch_ptr->bam_stats.bamFifoEmpty,
tx_ch_ptr->bam_stats.bamFifoUsageHigh,
tx_ch_ptr->bam_stats.bamFifoUsageLow,
tx_ch_ptr->bam_stats.bamUtilCount,
tx_ch_ptr->num_db,
tx_ch_ptr->num_unexpected_db,
tx_ch_ptr->num_bam_int_handled,
tx_ch_ptr->num_bam_int_in_non_running_state,
tx_ch_ptr->num_qmb_int_handled,
tx_ch_ptr->num_bam_int_handled_while_wait_for_bam);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"RX max_outstanding_pkts=%u\n"
"RX num_pkts_processed=%u\n"
"RX rx_ring_rp_value=%u\n"
"RX ringFull=%u\n"
"RX ringEmpty=%u\n"
"RX ringUsageHigh=%u\n"
"RX ringUsageLow=%u\n"
"RX RingUtilCount=%u\n"
"RX bamFifoFull=%u\n"
"RX bamFifoEmpty=%u\n"
"RX bamFifoUsageHigh=%u\n"
"RX bamFifoUsageLow=%u\n"
"RX bamUtilCount=%u\n"
"RX num_bam_int_handled=%u\n"
"RX num_db=%u\n"
"RX num_unexpected_db=%u\n"
"RX num_pkts_in_dis_uninit_state=%u\n"
"RX num_ic_inj_vdev_change=%u\n"
"RX num_ic_inj_fw_desc_change=%u\n"
"RX num_qmb_int_handled=%u\n"
"RX reserved1=%u\n"
"RX reserved2=%u\n",
stats.rx_ch_stats.max_outstanding_pkts,
stats.rx_ch_stats.num_pkts_processed,
stats.rx_ch_stats.rx_ring_rp_value,
stats.rx_ch_stats.rx_ind_ring_stats.ringFull,
stats.rx_ch_stats.rx_ind_ring_stats.ringEmpty,
stats.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh,
stats.rx_ch_stats.rx_ind_ring_stats.ringUsageLow,
stats.rx_ch_stats.rx_ind_ring_stats.RingUtilCount,
stats.rx_ch_stats.bam_stats.bamFifoFull,
stats.rx_ch_stats.bam_stats.bamFifoEmpty,
stats.rx_ch_stats.bam_stats.bamFifoUsageHigh,
stats.rx_ch_stats.bam_stats.bamFifoUsageLow,
stats.rx_ch_stats.bam_stats.bamUtilCount,
stats.rx_ch_stats.num_bam_int_handled,
stats.rx_ch_stats.num_db,
stats.rx_ch_stats.num_unexpected_db,
stats.rx_ch_stats.num_pkts_in_dis_uninit_state,
stats.rx_ch_stats.num_ic_inj_vdev_change,
stats.rx_ch_stats.num_ic_inj_fw_desc_change,
stats.rx_ch_stats.num_qmb_int_handled,
stats.rx_ch_stats.reserved1,
stats.rx_ch_stats.reserved2);
cnt += nbytes;
} else {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"Fail to read WDI stats\n");
cnt += nbytes;
}
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_write_dbg_cnt(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long missing;
u32 option = 0;
struct ipahal_reg_debug_cnt_ctrl dbg_cnt_ctrl;
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
IPAERR("IPA_DEBUG_CNT_CTRL is not supported in IPA 4.0\n");
return -EPERM;
}
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, buf, min(sizeof(dbg_buff), count));
if (missing)
return -EFAULT;
dbg_buff[count] = '\0';
if (kstrtou32(dbg_buff, 0, &option))
return -EFAULT;
memset(&dbg_cnt_ctrl, 0, sizeof(dbg_cnt_ctrl));
dbg_cnt_ctrl.type = DBG_CNT_TYPE_GENERAL;
dbg_cnt_ctrl.product = true;
dbg_cnt_ctrl.src_pipe = 0xff;
dbg_cnt_ctrl.rule_idx_pipe_rule = false;
dbg_cnt_ctrl.rule_idx = 0;
if (option == 1)
dbg_cnt_ctrl.en = true;
else
dbg_cnt_ctrl.en = false;
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
ipahal_write_reg_n_fields(IPA_DEBUG_CNT_CTRL_n, 0, &dbg_cnt_ctrl);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return count;
}
static ssize_t ipa3_read_dbg_cnt(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int nbytes;
u32 regval;
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
IPAERR("IPA_DEBUG_CNT_REG is not supported in IPA 4.0\n");
return -EPERM;
}
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
regval =
ipahal_read_reg_n(IPA_DEBUG_CNT_REG_n, 0);
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"IPA_DEBUG_CNT_REG_0=0x%x\n", regval);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
}
static ssize_t ipa3_read_msg(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int nbytes;
int cnt = 0;
int i;
for (i = 0; i < ARRAY_SIZE(ipa3_event_name); i++) {
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"msg[%u:%27s] W:%u R:%u\n", i,
ipa3_event_name[i],
ipa3_ctx->stats.msg_w[i],
ipa3_ctx->stats.msg_r[i]);
cnt += nbytes;
}
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static void ipa3_read_table(
char *table_addr,
u32 table_size,
u32 *total_num_entries,
u32 *rule_id,
enum ipahal_nat_type nat_type)
{
int result;
char *entry;
size_t entry_size;
bool entry_zeroed;
bool entry_valid;
u32 i, num_entries = 0, id = *rule_id;
char *buff;
size_t buff_size = 2 * IPA_MAX_ENTRY_STRING_LEN;
IPADBG("In\n");
if (table_addr == NULL) {
pr_err("NULL NAT table\n");
goto bail;
}
result = ipahal_nat_entry_size(nat_type, &entry_size);
if (result) {
IPAERR("Failed to retrieve size of %s entry\n",
ipahal_nat_type_str(nat_type));
goto bail;
}
buff = kzalloc(buff_size, GFP_KERNEL);
if (!buff) {
IPAERR("Out of memory\n");
goto bail;
}
for (i = 0, entry = table_addr;
i < table_size;
++i, ++id, entry += entry_size) {
result = ipahal_nat_is_entry_zeroed(nat_type, entry,
&entry_zeroed);
if (result) {
IPAERR("Undefined if %s entry is zero\n",
ipahal_nat_type_str(nat_type));
goto free_buf;
}
if (entry_zeroed)
continue;
result = ipahal_nat_is_entry_valid(nat_type, entry,
&entry_valid);
if (result) {
IPAERR("Undefined if %s entry is valid\n",
ipahal_nat_type_str(nat_type));
goto free_buf;
}
if (entry_valid) {
++num_entries;
pr_err("\tEntry_Index=%d\n", id);
} else
pr_err("\tEntry_Index=%d - Invalid Entry\n", id);
ipahal_nat_stringify_entry(nat_type, entry,
buff, buff_size);
pr_err("%s\n", buff);
memset(buff, 0, buff_size);
}
if (num_entries)
pr_err("\n");
else
pr_err("\tEmpty\n\n");
free_buf:
kfree(buff);
*rule_id = id;
*total_num_entries += num_entries;
bail:
IPADBG("Out\n");
}
static void ipa3_start_read_memory_device(
struct ipa3_nat_ipv6ct_common_mem *dev,
enum ipahal_nat_type nat_type,
u32 *num_ddr_ent_ptr,
u32 *num_sram_ent_ptr)
{
u32 rule_id = 0;
if (dev->is_ipv6ct_mem) {
IPADBG("In: v6\n");
pr_err("%s_Table_Size=%d\n",
dev->name, dev->table_entries + 1);
pr_err("%s_Expansion_Table_Size=%d\n",
dev->name, dev->expn_table_entries);
pr_err("\n%s Base Table:\n", dev->name);
if (dev->base_table_addr)
ipa3_read_table(
dev->base_table_addr,
dev->table_entries + 1,
num_ddr_ent_ptr,
&rule_id,
nat_type);
pr_err("%s Expansion Table:\n", dev->name);
if (dev->expansion_table_addr)
ipa3_read_table(
dev->expansion_table_addr,
dev->expn_table_entries,
num_ddr_ent_ptr,
&rule_id,
nat_type);
}
if (dev->is_nat_mem) {
struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
struct ipa3_nat_mem_loc_data *mld_ptr = NULL;
u32 *num_ent_ptr;
const char *type_ptr;
IPADBG("In: v4\n");
if (nm_ptr->active_table == IPA_NAT_MEM_IN_DDR &&
nm_ptr->ddr_in_use) {
mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_DDR];
num_ent_ptr = num_ddr_ent_ptr;
type_ptr = "DDR based table";
}
if (nm_ptr->active_table == IPA_NAT_MEM_IN_SRAM &&
nm_ptr->sram_in_use) {
mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_SRAM];
num_ent_ptr = num_sram_ent_ptr;
type_ptr = "SRAM based table";
}
if (mld_ptr) {
pr_err("(%s) %s_Table_Size=%d\n",
type_ptr,
dev->name,
mld_ptr->table_entries + 1);
pr_err("(%s) %s_Expansion_Table_Size=%d\n",
type_ptr,
dev->name,
mld_ptr->expn_table_entries);
pr_err("\n(%s) %s_Base Table:\n",
type_ptr,
dev->name);
if (mld_ptr->base_table_addr)
ipa3_read_table(
mld_ptr->base_table_addr,
mld_ptr->table_entries + 1,
num_ent_ptr,
&rule_id,
nat_type);
pr_err("(%s) %s_Expansion Table:\n",
type_ptr,
dev->name);
if (mld_ptr->expansion_table_addr)
ipa3_read_table(
mld_ptr->expansion_table_addr,
mld_ptr->expn_table_entries,
num_ent_ptr,
&rule_id,
nat_type);
}
}
IPADBG("Out\n");
}
static void ipa3_finish_read_memory_device(
struct ipa3_nat_ipv6ct_common_mem *dev,
u32 num_ddr_entries,
u32 num_sram_entries)
{
IPADBG("In\n");
if (dev->is_ipv6ct_mem) {
pr_err("Overall number %s entries: %u\n\n",
dev->name,
num_ddr_entries);
} else {
struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
if (num_ddr_entries)
pr_err("%s: Overall number of DDR entries: %u\n\n",
dev->name,
num_ddr_entries);
if (num_sram_entries)
pr_err("%s: Overall number of SRAM entries: %u\n\n",
dev->name,
num_sram_entries);
pr_err("%s: Driver focus changes to DDR(%u) to SRAM(%u)\n",
dev->name,
nm_ptr->switch2ddr_cnt,
nm_ptr->switch2sram_cnt);
}
IPADBG("Out\n");
}
static void ipa3_read_pdn_table(void)
{
int i, result;
char *pdn_entry;
size_t pdn_entry_size;
bool entry_zeroed;
bool entry_valid;
char *buff;
size_t buff_size = 128;
IPADBG("In\n");
if (ipa3_ctx->nat_mem.pdn_mem.base) {
result = ipahal_nat_entry_size(
IPAHAL_NAT_IPV4_PDN, &pdn_entry_size);
if (result) {
IPAERR("Failed to retrieve size of PDN entry");
goto bail;
}
buff = kzalloc(buff_size, GFP_KERNEL);
if (!buff) {
IPAERR("Out of memory\n");
goto bail;
}
for (i = 0, pdn_entry = ipa3_ctx->nat_mem.pdn_mem.base;
i < IPA_MAX_PDN_NUM;
++i, pdn_entry += pdn_entry_size) {
result = ipahal_nat_is_entry_zeroed(
IPAHAL_NAT_IPV4_PDN,
pdn_entry, &entry_zeroed);
if (result) {
IPAERR("ipahal_nat_is_entry_zeroed() fail\n");
goto free;
}
if (entry_zeroed)
continue;
result = ipahal_nat_is_entry_valid(
IPAHAL_NAT_IPV4_PDN,
pdn_entry, &entry_valid);
if (result) {
IPAERR(
"Failed to determine whether the PDN entry is valid\n");
goto free;
}
if (entry_valid)
pr_err("PDN %d: ", i);
else
pr_err("PDN %d - Invalid: ", i);
ipahal_nat_stringify_entry(
IPAHAL_NAT_IPV4_PDN,
pdn_entry, buff, buff_size);
pr_err("%s\n", buff);
memset(buff, 0, buff_size);
}
pr_err("\n");
free:
kfree(buff);
}
bail:
IPADBG("Out\n");
}
static ssize_t ipa3_read_nat4(
struct file *file,
char __user *ubuf,
size_t count,
loff_t *ppos)
{
struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->nat_mem.dev;
struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
struct ipa3_nat_mem_loc_data *mld_ptr = NULL;
u32 rule_id = 0;
u32 *num_ents_ptr;
u32 num_ddr_ents = 0;
u32 num_sram_ents = 0;
u32 *num_index_ents_ptr;
u32 num_ddr_index_ents = 0;
u32 num_sram_index_ents = 0;
const char *type_ptr;
bool any_table_active = (nm_ptr->ddr_in_use || nm_ptr->sram_in_use);
pr_err("IPA3 NAT stats\n");
if (!dev->is_dev_init) {
pr_err("NAT hasn't been initialized or not supported\n");
goto ret;
}
mutex_lock(&dev->lock);
if (!dev->is_hw_init || !any_table_active) {
pr_err("NAT H/W and/or S/W not initialized\n");
goto bail;
}
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
ipa3_read_pdn_table();
} else {
pr_err("NAT Table IP Address=%pI4h\n\n",
&ipa3_ctx->nat_mem.public_ip_addr);
}
ipa3_start_read_memory_device(
dev,
IPAHAL_NAT_IPV4,
&num_ddr_ents,
&num_sram_ents);
if (nm_ptr->active_table == IPA_NAT_MEM_IN_DDR &&
nm_ptr->ddr_in_use) {
mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_DDR];
num_ents_ptr = &num_ddr_ents;
num_index_ents_ptr = &num_ddr_index_ents;
type_ptr = "DDR based table";
}
if (nm_ptr->active_table == IPA_NAT_MEM_IN_SRAM &&
nm_ptr->sram_in_use) {
mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_SRAM];
num_ents_ptr = &num_sram_ents;
num_index_ents_ptr = &num_sram_index_ents;
type_ptr = "SRAM based table";
}
if (mld_ptr) {
/* Print Index tables */
pr_err("(%s) ipaNatTable Index Table:\n", type_ptr);
ipa3_read_table(
mld_ptr->index_table_addr,
mld_ptr->table_entries + 1,
num_index_ents_ptr,
&rule_id,
IPAHAL_NAT_IPV4_INDEX);
pr_err("(%s) ipaNatTable Expansion Index Table:\n", type_ptr);
ipa3_read_table(
mld_ptr->index_table_expansion_addr,
mld_ptr->expn_table_entries,
num_index_ents_ptr,
&rule_id,
IPAHAL_NAT_IPV4_INDEX);
if (*num_ents_ptr != *num_index_ents_ptr)
IPAERR(
"(%s) Base Table vs Index Table entry count differs (%u vs %u)\n",
type_ptr, *num_ents_ptr, *num_index_ents_ptr);
}
ipa3_finish_read_memory_device(
dev,
num_ddr_ents,
num_sram_ents);
bail:
mutex_unlock(&dev->lock);
ret:
IPADBG("Out\n");
return 0;
}
static ssize_t ipa3_read_ipv6ct(
struct file *file,
char __user *ubuf,
size_t count,
loff_t *ppos)
{
struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->ipv6ct_mem.dev;
u32 num_ddr_ents, num_sram_ents;
num_ddr_ents = num_sram_ents = 0;
IPADBG("In\n");
pr_err("\n");
if (!dev->is_dev_init) {
pr_err("IPv6 Conntrack not initialized or not supported\n");
goto bail;
}
if (!dev->is_hw_init) {
pr_err("IPv6 connection tracking H/W hasn't been initialized\n");
goto bail;
}
mutex_lock(&dev->lock);
ipa3_start_read_memory_device(
dev,
IPAHAL_NAT_IPV6CT,
&num_ddr_ents,
&num_sram_ents);
ipa3_finish_read_memory_device(
dev,
num_ddr_ents,
num_sram_ents);
mutex_unlock(&dev->lock);
bail:
IPADBG("Out\n");
return 0;
}
static ssize_t ipa3_rm_read_stats(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int result, cnt = 0;
/* deprecate if IPA PM is used */
if (ipa3_ctx->use_ipa_pm) {
cnt += scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"IPA RM is disabled\n");
goto ret;
}
result = ipa_rm_stat(dbg_buff, IPA_MAX_MSG_LEN);
if (result < 0) {
cnt += scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"Error in printing RM stat %d\n", result);
goto ret;
}
cnt += result;
ret:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_pm_read_stats(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int result, cnt = 0;
if (!ipa3_ctx->use_ipa_pm) {
cnt += scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"IPA PM is disabled\n");
goto ret;
}
result = ipa_pm_stat(dbg_buff, IPA_MAX_MSG_LEN);
if (result < 0) {
cnt += scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"Error in printing PM stat %d\n", result);
goto ret;
}
cnt += result;
ret:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_pm_ex_read_stats(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
int result, cnt = 0;
if (!ipa3_ctx->use_ipa_pm) {
cnt += scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"IPA PM is disabled\n");
goto ret;
}
result = ipa_pm_exceptions_stat(dbg_buff, IPA_MAX_MSG_LEN);
if (result < 0) {
cnt += scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"Error in printing PM stat %d\n", result);
goto ret;
}
cnt += result;
ret:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_ipahal_regs(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
ipahal_print_all_regs(true);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return 0;
}
static ssize_t ipa3_read_wdi_gsi_stats(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
struct ipa_uc_dbg_ring_stats stats;
int nbytes;
int cnt = 0;
if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5
&& (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1
|| ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"This feature only support on IPA4.5+\n");
cnt += nbytes;
goto done;
}
if (!ipa3_get_wdi_gsi_stats(&stats)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"TX ringFull=%u\n"
"TX ringEmpty=%u\n"
"TX ringUsageHigh=%u\n"
"TX ringUsageLow=%u\n"
"TX RingUtilCount=%u\n",
stats.ring[1].ringFull,
stats.ring[1].ringEmpty,
stats.ring[1].ringUsageHigh,
stats.ring[1].ringUsageLow,
stats.ring[1].RingUtilCount);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"RX ringFull=%u\n"
"RX ringEmpty=%u\n"
"RX ringUsageHigh=%u\n"
"RX ringUsageLow=%u\n"
"RX RingUtilCount=%u\n",
stats.ring[0].ringFull,
stats.ring[0].ringEmpty,
stats.ring[0].ringUsageHigh,
stats.ring[0].ringUsageLow,
stats.ring[0].RingUtilCount);
cnt += nbytes;
} else {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"Fail to read WDI GSI stats\n");
cnt += nbytes;
}
done:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_wdi3_gsi_stats(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
struct ipa_uc_dbg_ring_stats stats;
int nbytes;
int cnt = 0;
if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5
&& (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1
|| ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"This feature only support on IPA4.5+\n");
cnt += nbytes;
goto done;
}
if (!ipa3_get_wdi3_gsi_stats(&stats)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"TX ringFull=%u\n"
"TX ringEmpty=%u\n"
"TX ringUsageHigh=%u\n"
"TX ringUsageLow=%u\n"
"TX RingUtilCount=%u\n",
stats.ring[1].ringFull,
stats.ring[1].ringEmpty,
stats.ring[1].ringUsageHigh,
stats.ring[1].ringUsageLow,
stats.ring[1].RingUtilCount);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"RX ringFull=%u\n"
"RX ringEmpty=%u\n"
"RX ringUsageHigh=%u\n"
"RX ringUsageLow=%u\n"
"RX RingUtilCount=%u\n",
stats.ring[0].ringFull,
stats.ring[0].ringEmpty,
stats.ring[0].ringUsageHigh,
stats.ring[0].ringUsageLow,
stats.ring[0].RingUtilCount);
cnt += nbytes;
} else {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"Fail to read WDI GSI stats\n");
cnt += nbytes;
}
done:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_11ad_gsi_stats(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
int nbytes;
int cnt = 0;
if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5
&& (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1
|| ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"This feature only support on IPA4.5+\n");
cnt += nbytes;
goto done;
}
return 0;
done:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_aqc_gsi_stats(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
struct ipa_uc_dbg_ring_stats stats;
int nbytes;
int cnt = 0;
if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5
&& (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1
|| ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"This feature only support on IPA4.5+\n");
cnt += nbytes;
goto done;
}
if (!ipa3_get_aqc_gsi_stats(&stats)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"TX ringFull=%u\n"
"TX ringEmpty=%u\n"
"TX ringUsageHigh=%u\n"
"TX ringUsageLow=%u\n"
"TX RingUtilCount=%u\n",
stats.ring[1].ringFull,
stats.ring[1].ringEmpty,
stats.ring[1].ringUsageHigh,
stats.ring[1].ringUsageLow,
stats.ring[1].RingUtilCount);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"RX ringFull=%u\n"
"RX ringEmpty=%u\n"
"RX ringUsageHigh=%u\n"
"RX ringUsageLow=%u\n"
"RX RingUtilCount=%u\n",
stats.ring[0].ringFull,
stats.ring[0].ringEmpty,
stats.ring[0].ringUsageHigh,
stats.ring[0].ringUsageLow,
stats.ring[0].RingUtilCount);
cnt += nbytes;
} else {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"Fail to read AQC GSI stats\n");
cnt += nbytes;
}
done:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_mhip_gsi_stats(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
struct ipa_uc_dbg_ring_stats stats;
int nbytes;
int cnt = 0;
if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5
&& (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1
|| ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"This feature only support on IPA4.5+\n");
cnt += nbytes;
goto done;
}
if (!ipa3_get_mhip_gsi_stats(&stats)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"IPA_CLIENT_MHI_PRIME_TETH_CONS ringFull=%u\n"
"IPA_CLIENT_MHI_PRIME_TETH_CONS ringEmpty=%u\n"
"IPA_CLIENT_MHI_PRIME_TETH_CONS ringUsageHigh=%u\n"
"IPA_CLIENT_MHI_PRIME_TETH_CONS ringUsageLow=%u\n"
"IPA_CLIENT_MHI_PRIME_TETH_CONS RingUtilCount=%u\n",
stats.ring[1].ringFull,
stats.ring[1].ringEmpty,
stats.ring[1].ringUsageHigh,
stats.ring[1].ringUsageLow,
stats.ring[1].RingUtilCount);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"IPA_CLIENT_MHI_PRIME_TETH_PROD ringFull=%u\n"
"IPA_CLIENT_MHI_PRIME_TETH_PROD ringEmpty=%u\n"
"IPA_CLIENT_MHI_PRIME_TETH_PROD ringUsageHigh=%u\n"
"IPA_CLIENT_MHI_PRIME_TETH_PROD ringUsageLow=%u\n"
"IPA_CLIENT_MHI_PRIME_TETH_PROD RingUtilCount=%u\n",
stats.ring[0].ringFull,
stats.ring[0].ringEmpty,
stats.ring[0].ringUsageHigh,
stats.ring[0].ringUsageLow,
stats.ring[0].RingUtilCount);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"IPA_CLIENT_MHI_PRIME_RMNET_CONS ringFull=%u\n"
"IPA_CLIENT_MHI_PRIME_RMNET_CONS ringEmpty=%u\n"
"IPA_CLIENT_MHI_PRIME_RMNET_CONS ringUsageHigh=%u\n"
"IPA_CLIENT_MHI_PRIME_RMNET_CONS ringUsageLow=%u\n"
"IPA_CLIENT_MHI_PRIME_RMNET_CONS RingUtilCount=%u\n",
stats.ring[3].ringFull,
stats.ring[3].ringEmpty,
stats.ring[3].ringUsageHigh,
stats.ring[3].ringUsageLow,
stats.ring[3].RingUtilCount);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"IPA_CLIENT_MHI_PRIME_RMNET_PROD ringFull=%u\n"
"IPA_CLIENT_MHI_PRIME_RMNET_PROD ringEmpty=%u\n"
"IPA_CLIENT_MHI_PRIME_RMNET_PROD ringUsageHigh=%u\n"
"IPA_CLIENT_MHI_PRIME_RMNET_PROD ringUsageLow=%u\n"
"IPA_CLIENT_MHI_PRIME_RMNET_PROD RingUtilCount=%u\n",
stats.ring[2].ringFull,
stats.ring[2].ringEmpty,
stats.ring[2].ringUsageHigh,
stats.ring[2].ringUsageLow,
stats.ring[2].RingUtilCount);
cnt += nbytes;
} else {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"Fail to read WDI GSI stats\n");
cnt += nbytes;
}
done:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_usb_gsi_stats(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
struct ipa_uc_dbg_ring_stats stats;
int nbytes;
int cnt = 0;
if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5
&& (ipa3_ctx->ipa_hw_type != IPA_HW_v4_1
|| ipa3_ctx->platform_type != IPA_PLAT_TYPE_APQ)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"This feature only support on IPA4.5+\n");
cnt += nbytes;
goto done;
}
if (!ipa3_get_usb_gsi_stats(&stats)) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"TX ringFull=%u\n"
"TX ringEmpty=%u\n"
"TX ringUsageHigh=%u\n"
"TX ringUsageLow=%u\n"
"TX RingUtilCount=%u\n",
stats.ring[1].ringFull,
stats.ring[1].ringEmpty,
stats.ring[1].ringUsageHigh,
stats.ring[1].ringUsageLow,
stats.ring[1].RingUtilCount);
cnt += nbytes;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"RX ringFull=%u\n"
"RX ringEmpty=%u\n"
"RX ringUsageHigh=%u\n"
"RX ringUsageLow=%u\n"
"RX RingUtilCount=%u\n",
stats.ring[0].ringFull,
stats.ring[0].ringEmpty,
stats.ring[0].ringUsageHigh,
stats.ring[0].ringUsageLow,
stats.ring[0].RingUtilCount);
cnt += nbytes;
} else {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"Fail to read WDI GSI stats\n");
cnt += nbytes;
}
done:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static ssize_t ipa3_read_app_clk_vote(
struct file *file,
char __user *ubuf,
size_t count,
loff_t *ppos)
{
int cnt =
scnprintf(
dbg_buff,
IPA_MAX_MSG_LEN,
"%u\n",
ipa3_ctx->app_clock_vote.cnt);
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static void ipa_dump_status(struct ipahal_pkt_status *status)
{
IPA_DUMP_STATUS_FIELD(status_opcode);
IPA_DUMP_STATUS_FIELD(exception);
IPA_DUMP_STATUS_FIELD(status_mask);
IPA_DUMP_STATUS_FIELD(pkt_len);
IPA_DUMP_STATUS_FIELD(endp_src_idx);
IPA_DUMP_STATUS_FIELD(endp_dest_idx);
IPA_DUMP_STATUS_FIELD(metadata);
IPA_DUMP_STATUS_FIELD(flt_local);
IPA_DUMP_STATUS_FIELD(flt_hash);
IPA_DUMP_STATUS_FIELD(flt_global);
IPA_DUMP_STATUS_FIELD(flt_ret_hdr);
IPA_DUMP_STATUS_FIELD(flt_miss);
IPA_DUMP_STATUS_FIELD(flt_rule_id);
IPA_DUMP_STATUS_FIELD(rt_local);
IPA_DUMP_STATUS_FIELD(rt_hash);
IPA_DUMP_STATUS_FIELD(ucp);
IPA_DUMP_STATUS_FIELD(rt_tbl_idx);
IPA_DUMP_STATUS_FIELD(rt_miss);
IPA_DUMP_STATUS_FIELD(rt_rule_id);
IPA_DUMP_STATUS_FIELD(nat_hit);
IPA_DUMP_STATUS_FIELD(nat_entry_idx);
IPA_DUMP_STATUS_FIELD(nat_type);
pr_err("tag = 0x%llx\n", (u64)status->tag_info & 0xFFFFFFFFFFFF);
IPA_DUMP_STATUS_FIELD(seq_num);
IPA_DUMP_STATUS_FIELD(time_of_day_ctr);
IPA_DUMP_STATUS_FIELD(hdr_local);
IPA_DUMP_STATUS_FIELD(hdr_offset);
IPA_DUMP_STATUS_FIELD(frag_hit);
IPA_DUMP_STATUS_FIELD(frag_rule);
}
static ssize_t ipa_status_stats_read(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
struct ipa3_status_stats *stats;
int i, j;
stats = kzalloc(sizeof(*stats), GFP_KERNEL);
if (!stats)
return -EFAULT;
for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
if (!ipa3_ctx->ep[i].sys || !ipa3_ctx->ep[i].sys->status_stat)
continue;
memcpy(stats, ipa3_ctx->ep[i].sys->status_stat, sizeof(*stats));
pr_err("Statuses for pipe %d\n", i);
for (j = 0; j < IPA_MAX_STATUS_STAT_NUM; j++) {
pr_err("curr=%d\n", stats->curr);
ipa_dump_status(&stats->status[stats->curr]);
pr_err("\n\n\n");
stats->curr = (stats->curr + 1) %
IPA_MAX_STATUS_STAT_NUM;
}
}
kfree(stats);
return 0;
}
static ssize_t ipa3_print_active_clients_log(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
int cnt;
int table_size;
if (active_clients_buf == NULL) {
IPAERR("Active Clients buffer is not allocated");
return 0;
}
memset(active_clients_buf, 0, IPA_DBG_ACTIVE_CLIENT_BUF_SIZE);
mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
cnt = ipa3_active_clients_log_print_buffer(active_clients_buf,
IPA_DBG_ACTIVE_CLIENT_BUF_SIZE - IPA_MAX_MSG_LEN);
table_size = ipa3_active_clients_log_print_table(active_clients_buf
+ cnt, IPA_MAX_MSG_LEN);
mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
return simple_read_from_buffer(ubuf, count, ppos,
active_clients_buf, cnt + table_size);
}
static ssize_t ipa3_clear_active_clients_log(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
{
unsigned long missing;
s8 option = 0;
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
if (missing)
return -EFAULT;
dbg_buff[count] = '\0';
if (kstrtos8(dbg_buff, 0, &option))
return -EFAULT;
ipa3_active_clients_log_clear();
return count;
}
static ssize_t ipa3_enable_ipc_low(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
{
unsigned long missing;
s8 option = 0;
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
missing = copy_from_user(dbg_buff, ubuf, min(sizeof(dbg_buff), count));
if (missing)
return -EFAULT;
dbg_buff[count] = '\0';
if (kstrtos8(dbg_buff, 0, &option))
return -EFAULT;
mutex_lock(&ipa3_ctx->lock);
if (option) {
if (!ipa_ipc_low_buff) {
ipa_ipc_low_buff =
ipc_log_context_create(IPA_IPC_LOG_PAGES,
"ipa_low", 0);
}
if (ipa_ipc_low_buff == NULL)
IPADBG("failed to get logbuf_low\n");
ipa3_ctx->logbuf_low = ipa_ipc_low_buff;
} else {
ipa3_ctx->logbuf_low = NULL;
}
mutex_unlock(&ipa3_ctx->lock);
return count;
}
static ssize_t ipa3_read_uc_act_tbl(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos)
{
int nbytes;
int cnt = 0;
int i;
struct ipa_ipv6_nat_uc_tmpl *uc_entry_nat;
struct ipa_socksv5_uc_tmpl *uc_entry_socks;
struct iphdr_rsv *socks_iphdr;
struct ipv6hdr *socks_ipv6hdr;
/* IPA version check */
if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"This feature only support on IPA4.5+\n");
cnt += nbytes;
goto done;
}
if (!ipa3_ctx->uc_act_tbl_valid) {
IPAERR("uC act tbl wasn't allocated\n");
return -ENOENT;
}
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
dbg_buff[count] = '\0';
mutex_lock(&ipa3_ctx->act_tbl_lock);
uc_entry_nat = (struct ipa_ipv6_nat_uc_tmpl *)
(ipa3_ctx->uc_act_tbl.base);
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
"uc_act_tbl_total %d, uc_act_tbl_ipv6_nat_total %d uc_act_tbl_socksv5_total %d, uc_act_tbl_next_index %d\n"
"uC activation entries:"
, ipa3_ctx->uc_act_tbl_total,
ipa3_ctx->uc_act_tbl_ipv6_nat_total,
ipa3_ctx->uc_act_tbl_socksv5_total,
ipa3_ctx->uc_act_tbl_next_index);
cnt += nbytes;
for (i = 0; i < IPA_UC_ACT_TBL_SIZE; i++) {
if (uc_entry_nat[i].cmd_id == IPA_IPv6_NAT_COM_ID) {
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
"\nentry %d:\n"
"cmd_id = IPV6_NAT\n"
"private_address_msb 0x%llX\n"
"private_address_lsb 0x%llX\n"
"private_port %u\n"
"public_address_msb 0x%llX\n"
"public_address_lsb 0x%llX\n"
"public_port %u\n",
i,
uc_entry_nat[i].private_address_msb,
uc_entry_nat[i].private_address_lsb,
uc_entry_nat[i].private_port,
uc_entry_nat[i].public_address_msb,
uc_entry_nat[i].public_address_lsb,
uc_entry_nat[i].public_port);
cnt += nbytes;
} else if (uc_entry_nat[i].cmd_id == IPA_SOCKSV5_ADD_COM_ID) {
uc_entry_socks = (struct ipa_socksv5_uc_tmpl *)
(uc_entry_nat);
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
"\nentry %d:\n"
"cmd_id = SOCKSv5\n"
"cmd_param: %u\n"
"source_port: %u\n"
"dest_port: %u\n"
"ipa_socksv5_mask: %x\n",
i,
uc_entry_socks[i].cmd_param,
uc_entry_socks[i].src_port,
uc_entry_socks[i].dst_port,
uc_entry_socks[i].ipa_sockv5_mask);
cnt += nbytes;
if (uc_entry_socks[i].cmd_param ==
IPA_SOCKsv5_ADD_V6_V4_COM_PM) {
socks_iphdr =
&uc_entry_socks[i].ip_hdr.ipv4_rsv;
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN,
"ipv4_src_addr: 0x%X\n"
"ipv4_dst_addr: 0x%X\n",
socks_iphdr->ipv4_temp.saddr,
socks_iphdr->ipv4_temp.daddr);
cnt += nbytes;
} else {
socks_ipv6hdr =
&uc_entry_socks[i].ip_hdr.ipv6_temp;
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN,
"ipv6_src_addr[0]: 0x%X\n"
"ipv6_src_addr[1]: 0x%X\n"
"ipv6_src_addr[2]: 0x%X\n"
"ipv6_src_addr[3]: 0x%X\n"
"ipv6_dts_addr[0]: 0x%X\n"
"ipv6_dts_addr[1]: 0x%X\n"
"ipv6_dts_addr[2]: 0x%X\n"
"ipv6_dts_addr[3]: 0x%X\n",
socks_ipv6hdr->saddr.s6_addr32[0],
socks_ipv6hdr->saddr.s6_addr32[1],
socks_ipv6hdr->saddr.s6_addr32[2],
socks_ipv6hdr->saddr.s6_addr32[3],
socks_ipv6hdr->daddr.s6_addr32[0],
socks_ipv6hdr->daddr.s6_addr32[1],
socks_ipv6hdr->daddr.s6_addr32[2],
socks_ipv6hdr->daddr.s6_addr32[3]);
cnt += nbytes;
}
}
}
mutex_unlock(&ipa3_ctx->act_tbl_lock);
done:
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
static const struct ipa3_debugfs_file debugfs_files[] = {
{
"gen_reg", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_gen_reg
}
}, {
"active_clients", IPA_READ_WRITE_MODE, NULL, {
.read = ipa3_print_active_clients_log,
.write = ipa3_clear_active_clients_log
}
}, {
"ep_reg", IPA_READ_WRITE_MODE, NULL, {
.read = ipa3_read_ep_reg,
.write = ipa3_write_ep_reg,
}
}, {
"keep_awake", IPA_READ_WRITE_MODE, NULL, {
.read = ipa3_read_keep_awake,
.write = ipa3_write_keep_awake,
}
}, {
"holb", IPA_WRITE_ONLY_MODE, NULL, {
.write = ipa3_write_ep_holb,
}
}, {
"hdr", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_hdr,
}
}, {
"proc_ctx", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_proc_ctx,
}
}, {
"ip4_rt", IPA_READ_ONLY_MODE, (void *)IPA_IP_v4, {
.read = ipa3_read_rt,
.open = ipa3_open_dbg,
}
}, {
"ip4_rt_hw", IPA_READ_ONLY_MODE, (void *)IPA_IP_v4, {
.read = ipa3_read_rt_hw,
.open = ipa3_open_dbg,
}
}, {
"ip6_rt", IPA_READ_ONLY_MODE, (void *)IPA_IP_v6, {
.read = ipa3_read_rt,
.open = ipa3_open_dbg,
}
}, {
"ip6_rt_hw", IPA_READ_ONLY_MODE, (void *)IPA_IP_v6, {
.read = ipa3_read_rt_hw,
.open = ipa3_open_dbg,
}
}, {
"ip4_flt", IPA_READ_ONLY_MODE, (void *)IPA_IP_v4, {
.read = ipa3_read_flt,
.open = ipa3_open_dbg,
}
}, {
"ip4_flt_hw", IPA_READ_ONLY_MODE, (void *)IPA_IP_v4, {
.read = ipa3_read_flt_hw,
.open = ipa3_open_dbg,
}
}, {
"ip6_flt", IPA_READ_ONLY_MODE, (void *)IPA_IP_v6, {
.read = ipa3_read_flt,
.open = ipa3_open_dbg,
}
}, {
"ip6_flt_hw", IPA_READ_ONLY_MODE, (void *)IPA_IP_v6, {
.read = ipa3_read_flt_hw,
.open = ipa3_open_dbg,
}
}, {
"stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_stats,
}
}, {
"wstats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_wstats,
}
}, {
"odlstats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_odlstats,
}
}, {
"page_recycle_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_page_recycle_stats,
}
}, {
"wdi", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_wdi,
}
}, {
"ntn", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_ntn,
}
}, {
"dbg_cnt", IPA_READ_WRITE_MODE, NULL, {
.read = ipa3_read_dbg_cnt,
.write = ipa3_write_dbg_cnt,
}
}, {
"msg", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_msg,
}
}, {
"ip4_nat", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_nat4,
}
}, {
"ipv6ct", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_ipv6ct,
}
}, {
"rm_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_rm_read_stats,
}
}, {
"pm_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_pm_read_stats,
}
}, {
"pm_ex_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_pm_ex_read_stats,
}
}, {
"status_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa_status_stats_read,
}
}, {
"enable_low_prio_print", IPA_WRITE_ONLY_MODE, NULL, {
.write = ipa3_enable_ipc_low,
}
}, {
"ipa_dump_regs", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_ipahal_regs,
}
}, {
"wdi_gsi_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_wdi_gsi_stats,
}
}, {
"wdi3_gsi_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_wdi3_gsi_stats,
}
}, {
"11ad_gsi_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_11ad_gsi_stats,
}
}, {
"aqc_gsi_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_aqc_gsi_stats,
}
}, {
"mhip_gsi_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_mhip_gsi_stats,
}
}, {
"usb_gsi_stats", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_usb_gsi_stats,
}
}, {
"ipa_statistics_msg", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_dump_debug_msg,
}
}, {
"app_clk_vote_cnt", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_app_clk_vote,
}
}, {
"uc_act_table", IPA_READ_ONLY_MODE, NULL, {
.read = ipa3_read_uc_act_tbl,
}
}
};
void ipa3_debugfs_pre_init(void)
{
dent = debugfs_create_dir("ipa", 0);
if (IS_ERR_OR_NULL(dent)) {
IPAERR("fail to create folder in debug_fs.\n");
dent = NULL;
}
}
void ipa3_debugfs_post_init(void)
{
const size_t debugfs_files_num =
sizeof(debugfs_files) / sizeof(struct ipa3_debugfs_file);
size_t i;
struct dentry *file;
if (IS_ERR_OR_NULL(dent)) {
IPAERR("debugs root not created\n");
return;
}
file = debugfs_create_u32("hw_type", IPA_READ_ONLY_MODE,
dent, &ipa3_ctx->ipa_hw_type);
if (!file) {
IPAERR("could not create hw_type file\n");
goto fail;
}
for (i = 0; i < debugfs_files_num; ++i) {
const struct ipa3_debugfs_file *curr = &debugfs_files[i];
file = debugfs_create_file(curr->name, curr->mode, dent,
curr->data, &curr->fops);
if (!file || IS_ERR(file)) {
IPAERR("fail to create file for debug_fs %s\n",
curr->name);
goto fail;
}
}
active_clients_buf = NULL;
active_clients_buf = kzalloc(IPA_DBG_ACTIVE_CLIENT_BUF_SIZE,
GFP_KERNEL);
if (active_clients_buf == NULL)
goto fail;
file = debugfs_create_u32("enable_clock_scaling", IPA_READ_WRITE_MODE,
dent, &ipa3_ctx->enable_clock_scaling);
if (!file) {
IPAERR("could not create enable_clock_scaling file\n");
goto fail;
}
file = debugfs_create_u32("enable_napi_chain", IPA_READ_WRITE_MODE,
dent, &ipa3_ctx->enable_napi_chain);
if (!file) {
IPAERR("could not create enable_napi_chain file\n");
goto fail;
}
file = debugfs_create_u32("clock_scaling_bw_threshold_nominal_mbps",
IPA_READ_WRITE_MODE, dent,
&ipa3_ctx->ctrl->clock_scaling_bw_threshold_nominal);
if (!file) {
IPAERR("could not create bw_threshold_nominal_mbps\n");
goto fail;
}
file = debugfs_create_u32("clock_scaling_bw_threshold_turbo_mbps",
IPA_READ_WRITE_MODE, dent,
&ipa3_ctx->ctrl->clock_scaling_bw_threshold_turbo);
if (!file) {
IPAERR("could not create bw_threshold_turbo_mbps\n");
goto fail;
}
file = debugfs_create_u32("clk_rate", IPA_READ_ONLY_MODE,
dent, &ipa3_ctx->curr_ipa_clk_rate);
if (!file) {
IPAERR("could not create clk_rate file\n");
goto fail;
}
ipa_debugfs_init_stats(dent);
return;
fail:
debugfs_remove_recursive(dent);
}
void ipa3_debugfs_remove(void)
{
if (dent == NULL) {
IPAERR("Debugfs:folder was not created.\n");
return;
}
if (active_clients_buf != NULL) {
kfree(active_clients_buf);
active_clients_buf = NULL;
}
debugfs_remove_recursive(dent);
}
struct dentry *ipa_debugfs_get_root(void)
{
return dent;
}
EXPORT_SYMBOL(ipa_debugfs_get_root);
static int ipa3_collect_gen_reg(char *msg_buff, int max_buff_len)
{
int nbytes = 0;
struct ipahal_reg_shared_mem_size smem_sz = { 0 };
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
ipahal_read_reg_fields(IPA_SHARED_MEM_SIZE, &smem_sz);
nbytes = scnprintf(msg_buff, max_buff_len,
"IPA_VERSION=0x%x\n"
"IPA_COMP_HW_VERSION=0x%x\n"
"IPA_ROUTE=0x%x\n"
"IPA_SHARED_MEM_RESTRICTED=0x%x\n"
"IPA_SHARED_MEM_SIZE=0x%x\n"
"IPA_QTIME_TIMESTAMP_CFG=0x%x\n"
"IPA_TIMERS_PULSE_GRAN_CFG=0x%x\n"
"IPA_TIMERS_XO_CLK_DIV_CFG=0x%x\n",
ipahal_read_reg(IPA_VERSION),
ipahal_read_reg(IPA_COMP_HW_VERSION),
ipahal_read_reg(IPA_ROUTE),
smem_sz.shared_mem_baddr,
smem_sz.shared_mem_sz,
ipahal_read_reg(IPA_QTIME_TIMESTAMP_CFG),
ipahal_read_reg(IPA_TIMERS_PULSE_GRAN_CFG),
ipahal_read_reg(IPA_TIMERS_XO_CLK_DIV_CFG));
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return nbytes;
}
static int ipa3_collect_active_clients(char *msg_buff, int max_buff_len)
{
int nbytes = 0;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
mutex_lock(&ipa3_ctx->ipa3_active_clients.mutex);
nbytes = ipa3_active_clients_log_print_buffer(
msg_buff, max_buff_len);
nbytes += ipa3_active_clients_log_print_table(
msg_buff + nbytes, max_buff_len - nbytes);
mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
return nbytes;
}
static int ipa3_collect_ep_reg(char *msg_buff, int max_buff_len)
{
int start_idx = 0, end_idx = 0;
int nbytes = 0, i = 0;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
/* negative ep_reg_idx means all registers */
if (ep_reg_idx < 0) {
start_idx = 0;
end_idx = ipa3_ctx->ipa_num_pipes;
} else {
start_idx = ep_reg_idx;
end_idx = start_idx + 1;
}
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
for (i = start_idx; i < end_idx; i++) {
nbytes += scnprintf(
msg_buff + nbytes, max_buff_len - nbytes,
"IPA_ENDP_INIT_NAT_%u=0x%x\n"
"IPA_ENDP_INIT_CONN_TRACK_n%u=0x%x\n"
"IPA_ENDP_INIT_HDR_%u=0x%x\n"
"IPA_ENDP_INIT_HDR_EXT_%u=0x%x\n"
"IPA_ENDP_INIT_MODE_%u=0x%x\n"
"IPA_ENDP_INIT_AGGR_%u=0x%x\n"
"IPA_ENDP_INIT_CTRL_%u=0x%x\n"
"IPA_ENDP_INIT_HOL_EN_%u=0x%x\n"
"IPA_ENDP_INIT_HOL_TIMER_%u=0x%x\n"
"IPA_ENDP_INIT_DEAGGR_%u=0x%x\n"
"IPA_ENDP_INIT_CFG_%u=0x%x\n",
i, ipahal_read_reg_n(IPA_ENDP_INIT_NAT_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_CONN_TRACK_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_HDR_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_HDR_EXT_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_MODE_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_AGGR_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_CTRL_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_HOL_BLOCK_EN_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_DEAGGR_n, i),
i, ipahal_read_reg_n(IPA_ENDP_INIT_CFG_n, i));
}
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return nbytes;
}
static int ipa3_collect_attrib(
char *msg_buff,
int max_buff_len,
struct ipa_rule_attrib *attrib,
enum ipa_ip_type ip)
{
uint32_t addr[4] = { 0 };
uint32_t mask[4] = { 0 };
int i = 0, nbytes = 0;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"is_pure_ack\n");
if (attrib->attrib_mask & IPA_FLT_TOS)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"tos:%d ", attrib->u.v4.tos);
if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"tos_value:%d ", attrib->tos_value);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"tos_mask:%d ", attrib->tos_mask);
}
if (attrib->attrib_mask & IPA_FLT_PROTOCOL)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"protocol:%d\n", attrib->u.v4.protocol);
if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) {
if (ip == IPA_IP_v4) {
addr[0] = htonl(attrib->u.v4.src_addr);
mask[0] = htonl(attrib->u.v4.src_addr_mask);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"src_addr:%pI4 src_addr_mask:%pI4\n",
addr + 0, mask + 0);
} else if (ip == IPA_IP_v6) {
for (i = 0; i < 4; i++) {
addr[i] = htonl(attrib->u.v6.src_addr[i]);
mask[i] = htonl(attrib->u.v6.src_addr_mask[i]);
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"src_addr:%pI6 src_addr_mask:%pI6\n",
addr + 0, mask + 0);
}
}
if (attrib->attrib_mask & IPA_FLT_DST_ADDR) {
if (ip == IPA_IP_v4) {
addr[0] = htonl(attrib->u.v4.dst_addr);
mask[0] = htonl(attrib->u.v4.dst_addr_mask);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"dst_addr:%pI4 dst_addr_mask:%pI4\n",
addr + 0, mask + 0);
} else if (ip == IPA_IP_v6) {
for (i = 0; i < 4; i++) {
addr[i] = htonl(attrib->u.v6.dst_addr[i]);
mask[i] = htonl(attrib->u.v6.dst_addr_mask[i]);
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"dst_addr:%pI6 dst_addr_mask:%pI6\n",
addr + 0, mask + 0);
}
}
if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"src_port_range:%u %u\n",
attrib->src_port_lo,
attrib->src_port_hi);
}
if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"dst_port_range:%u %u\n",
attrib->dst_port_lo,
attrib->dst_port_hi);
}
if (attrib->attrib_mask & IPA_FLT_TYPE)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"type:%d\n", attrib->type);
if (attrib->attrib_mask & IPA_FLT_CODE)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"code:%d\n", attrib->code);
if (attrib->attrib_mask & IPA_FLT_SPI)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"spi:%x\n", attrib->spi);
if (attrib->attrib_mask & IPA_FLT_SRC_PORT)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"src_port:%u\n", attrib->src_port);
if (attrib->attrib_mask & IPA_FLT_DST_PORT)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"dst_port:%u\n", attrib->dst_port);
if (attrib->attrib_mask & IPA_FLT_TC)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"tc:%d\n", attrib->u.v6.tc);
if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"flow_label:%x\n",
attrib->u.v6.flow_label);
if (attrib->attrib_mask & IPA_FLT_NEXT_HDR)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"next_hdr:%d\n",
attrib->u.v6.next_hdr);
if (attrib->attrib_mask & IPA_FLT_META_DATA) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"metadata:%x metadata_mask:%x\n",
attrib->meta_data,
attrib->meta_data_mask);
}
if (attrib->attrib_mask & IPA_FLT_FRAGMENT)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"frg\n");
if ((attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_ETHER_II) ||
(attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_3) ||
(attrib->attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_1Q)) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"src_mac_addr:%pM\n",
attrib->src_mac_addr);
}
if ((attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_ETHER_II) ||
(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_3) ||
(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_L2TP) ||
(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_1Q)) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"dst_mac_addr:%pM\n",
attrib->dst_mac_addr);
}
if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"ether_type:%x\n",
attrib->ether_type);
if (attrib->attrib_mask & IPA_FLT_VLAN_ID)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"vlan_id:%x\n",
attrib->vlan_id);
if (attrib->attrib_mask & IPA_FLT_TCP_SYN)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"tcp syn\n");
if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"tcp syn l2tp\n");
if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"l2tp inner ip type: %d\n",
attrib->type);
if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) {
addr[0] = htonl(attrib->u.v4.dst_addr);
mask[0] = htonl(attrib->u.v4.dst_addr_mask);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"dst_addr:%pI4 dst_addr_mask:%pI4\n",
addr, mask);
}
return nbytes;
}
static int ipa3_collect_rt(
char *msg_buff,
int max_buff_len,
enum ipa_ip_type ip)
{
char *temp_buff = NULL;
int nbytes = 0, i = 0;
u32 ofst = 0, ofst_words = 0;
struct ipa3_rt_tbl *tbl;
struct ipa3_rt_entry *entry;
struct ipa3_rt_tbl_set *set;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
if (ip != IPA_IP_v6 && ip != IPA_IP_v4) {
IPAERR("ip type error %d\n", ip);
return 0;
}
memset(msg_buff, 0, max_buff_len);
set = &ipa3_ctx->rt_tbl_set[ip];
mutex_lock(&ipa3_ctx->lock);
temp_buff = kzalloc(IPA_MAX_ENTRY_STRING_LEN, GFP_KERNEL);
if (temp_buff == NULL) {
IPAERR("temp buffer is not allocated");
goto fail;
}
if (ip == IPA_IP_v6) {
if (ipa3_ctx->ip6_rt_tbl_hash_lcl)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"Hashable table resides on local memory\n");
else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"Hashable table resides on system (ddr) memory\n");
if (ipa3_ctx->ip6_rt_tbl_nhash_lcl)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"Non-Hashable table resides on local memory\n");
else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"Non-Hashable table resides on system (ddr) memory\n");
} else if (ip == IPA_IP_v4) {
if (ipa3_ctx->ip4_rt_tbl_hash_lcl)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"Hashable table resides on local memory\n");
else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"Hashable table resides on system (ddr) memory\n");
if (ipa3_ctx->ip4_rt_tbl_nhash_lcl)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"Non-Hashable table resides on local memory\n");
else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"Non-Hashable table resides on system (ddr) memory\n");
}
list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
i = 0;
list_for_each_entry(entry, &tbl->head_rt_rule_list, link) {
if (entry->proc_ctx && entry->proc_ctx->offset_entry) {
ofst = entry->proc_ctx->offset_entry->offset;
ofst_words =
(ofst +
ipa3_ctx->hdr_proc_ctx_tbl.start_offset)
>> 5;
if (entry->tbl) {
nbytes += scnprintf(
msg_buff + nbytes,
max_buff_len - nbytes,
"tbl_idx:%d tbl_name:%s tbl_ref:%u\n",
entry->tbl->idx,
entry->tbl->name,
entry->tbl->ref_cnt);
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_idx:%d dst:%d ep:%d S:%u\n",
i, entry->rule.dst,
ipa3_get_ep_mapping(entry->rule.dst),
!ipa3_ctx->hdr_proc_ctx_tbl_lcl);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"proc_ctx[32B]:%u attrib_mask:%08x\n",
ofst_words,
entry->rule.attrib.attrib_mask);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_id:%u max_prio:%u prio:%u\n",
entry->rule_id, entry->rule.max_prio,
entry->prio);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"enable_stats:%u counter_id:%u\n",
entry->rule.enable_stats,
entry->rule.cnt_idx);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"hashable:%u retain_hdr:%u\n",
entry->rule.hashable,
entry->rule.retain_hdr);
} else {
if (entry->hdr && entry->hdr->offset_entry)
ofst = entry->hdr->offset_entry->offset;
else
ofst = 0;
if (entry->tbl) {
nbytes += scnprintf(
msg_buff + nbytes,
max_buff_len - nbytes,
"tbl_idx:%d tbl_name:%s tbl_ref:%u\n",
entry->tbl->idx,
entry->tbl->name,
entry->tbl->ref_cnt);
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_idx:%d dst:%d ep:%d S:%u\n",
i, entry->rule.dst,
ipa3_get_ep_mapping(entry->rule.dst),
!ipa3_ctx->hdr_tbl_lcl);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"hdr_ofst[words]:%u attrib_mask:%08x\n",
ofst >> 2,
entry->rule.attrib.attrib_mask);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_id:%u max_prio:%u prio:%u\n",
entry->rule_id, entry->rule.max_prio,
entry->prio);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"enable_stats:%u counter_id:%u\n",
entry->rule.enable_stats,
entry->rule.cnt_idx);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"hashable:%u retain_hdr:%u\n",
entry->rule.hashable,
entry->rule.retain_hdr);
}
ipa3_collect_attrib(
temp_buff,
IPA_MAX_ENTRY_STRING_LEN,
&entry->rule.attrib,
ip);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s\n",
temp_buff);
i++;
}
}
if (temp_buff != NULL) {
kfree(temp_buff);
temp_buff = NULL;
}
fail:
mutex_unlock(&ipa3_ctx->lock);
return nbytes;
}
static int ipa3_attrib_collect_eq(
char *msg_buff,
int max_buff_len,
struct ipa_ipfltri_rule_eq *attrib)
{
uint8_t addr[16] = { 0 };
uint8_t mask[16] = { 0 };
int i = 0, j = 0, nbytes = 0;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
if (attrib->tos_eq_present) {
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"pure_ack\n");
else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"tos:%d\n", attrib->tos_eq);
}
if (attrib->protocol_eq_present)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"protocol:%d\n", attrib->protocol_eq);
if (attrib->tc_eq_present)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"tc:%d\n", attrib->tc_eq);
if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) {
IPAERR_RL("num_offset_meq_128 Max %d passed value %d\n",
IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128);
return nbytes;
}
for (i = 0; i < attrib->num_offset_meq_128; i++) {
for (j = 0; j < 16; j++) {
addr[j] = attrib->offset_meq_128[i].value[j];
mask[j] = attrib->offset_meq_128[i].mask[j];
}
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"(ofst_meq128: ofst:%d mask:%pI6 val:%pI6)\n",
attrib->offset_meq_128[i].offset,
mask, addr);
}
if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) {
IPAERR_RL("num_offset_meq_32 Max %d passed value %d\n",
IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32);
return nbytes;
}
for (i = 0; i < attrib->num_offset_meq_32; i++)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"(ofst_meq32: ofst:%u mask:0x%x val:0x%x)\n",
attrib->offset_meq_32[i].offset,
attrib->offset_meq_32[i].mask,
attrib->offset_meq_32[i].value);
if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) {
IPAERR_RL("num_ihl_offset_meq_32 Max %d passed value %d\n",
IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, attrib->num_ihl_offset_meq_32);
return nbytes;
}
for (i = 0; i < attrib->num_ihl_offset_meq_32; i++)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x)\n",
attrib->ihl_offset_meq_32[i].offset,
attrib->ihl_offset_meq_32[i].mask,
attrib->ihl_offset_meq_32[i].value);
if (attrib->metadata_meq32_present)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"(metadata: ofst:%u mask:0x%x val:0x%x)\n",
attrib->metadata_meq32.offset,
attrib->metadata_meq32.mask,
attrib->metadata_meq32.value);
if (attrib->num_ihl_offset_range_16 >
IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) {
IPAERR_RL("num_ihl_offset_range_16 Max %d passed value %d\n",
IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS,
attrib->num_ihl_offset_range_16);
return nbytes;
}
for (i = 0; i < attrib->num_ihl_offset_range_16; i++)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"(ihl_ofst_range16: ofst:%u lo:%u hi:%u)\n",
attrib->ihl_offset_range_16[i].offset,
attrib->ihl_offset_range_16[i].range_low,
attrib->ihl_offset_range_16[i].range_high);
if (attrib->ihl_offset_eq_32_present)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"(ihl_ofst_eq32:%d val:0x%x)\n",
attrib->ihl_offset_eq_32.offset,
attrib->ihl_offset_eq_32.value);
if (attrib->ihl_offset_eq_16_present)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"(ihl_ofst_eq16:%d val:0x%x)\n",
attrib->ihl_offset_eq_16.offset,
attrib->ihl_offset_eq_16.value);
if (attrib->fl_eq_present)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"flow_label:%d\n", attrib->fl_eq);
if (attrib->ipv4_frag_eq_present)
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"frag\n");
return nbytes;
}
static int ipa3_collect_rt_hw(
char *msg_buff,
int max_buff_len,
enum ipa_ip_type ip)
{
char *temp_buff = NULL;
int tbls_num = 0, rules_num = 0;
int tbl = 0, rl = 0;
int res = 0;
int nbytes = 0;
struct ipahal_rt_rule_entry *rules = NULL;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
switch (ip) {
case IPA_IP_v4:
tbls_num = IPA_MEM_PART(v4_rt_num_index);
break;
case IPA_IP_v6:
tbls_num = IPA_MEM_PART(v6_rt_num_index);
break;
default:
IPAERR("ip type error %d\n", ip);
return 0;
};
memset(msg_buff, 0, max_buff_len);
IPADBG("Tring to parse %d H/W routing tables - IP=%d\n", tbls_num, ip);
rules = kzalloc(sizeof(*rules) * IPA_DBG_MAX_RULE_IN_TBL, GFP_KERNEL);
if (!rules) {
IPAERR("failed to allocate mem for tbl rules\n");
return 0;
}
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
mutex_lock(&ipa3_ctx->lock);
temp_buff = kzalloc(IPA_MAX_ENTRY_STRING_LEN, GFP_KERNEL);
if (temp_buff == NULL) {
IPAERR("temp buffer is not allocated");
goto fail;
}
for (tbl = 0 ; tbl < tbls_num ; tbl++) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"=== Routing Table %d = Hashable Rules ===\n",
tbl);
rules_num = IPA_DBG_MAX_RULE_IN_TBL;
res = ipa3_rt_read_tbl_from_hw(tbl, ip, true, rules,
&rules_num);
if (res) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"ERROR - Check the logs\n");
IPAERR("failed reading tbl from hw\n");
goto fail;
}
if (!rules_num)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"-->No rules. Empty tbl or modem system table\n");
for (rl = 0 ; rl < rules_num ; rl++) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_idx:%d dst ep:%d L:%u\n",
rl, rules[rl].dst_pipe_idx,
rules[rl].hdr_lcl);
if (rules[rl].hdr_type == IPAHAL_RT_RULE_HDR_PROC_CTX)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"proc_ctx:%u attrib_mask:%08x\n",
rules[rl].hdr_ofst,
rules[rl].eq_attrib.rule_eq_bitmap
);
else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"hdr_ofst:%u attrib_mask:%08x\n",
rules[rl].hdr_ofst,
rules[rl].eq_attrib.rule_eq_bitmap);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_id:%u cnt_id:%hhu prio:%u retain_hdr:%u\n",
rules[rl].id, rules[rl].cnt_idx,
rules[rl].priority, rules[rl].retain_hdr);
ipa3_attrib_collect_eq(
temp_buff,
IPA_MAX_ENTRY_STRING_LEN,
&rules[rl].eq_attrib);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s\n",
temp_buff);
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"=== Routing Table %d = Non-Hashable Rules ===\n",
tbl);
rules_num = IPA_DBG_MAX_RULE_IN_TBL;
res = ipa3_rt_read_tbl_from_hw(tbl, ip, false, rules,
&rules_num);
if (res) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"ERROR - Check the logs\n");
IPAERR("failed reading tbl from hw\n");
goto fail;
}
if (!rules_num)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"-->No rules. Empty tbl or modem system table\n");
for (rl = 0 ; rl < rules_num ; rl++) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_idx:%d dst ep:%d L:%u\n",
rl, rules[rl].dst_pipe_idx,
rules[rl].hdr_lcl);
if (rules[rl].hdr_type == IPAHAL_RT_RULE_HDR_PROC_CTX)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"proc_ctx:%u attrib_mask:%08x\n",
rules[rl].hdr_ofst,
rules[rl].eq_attrib.rule_eq_bitmap);
else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"hdr_ofst:%u attrib_mask:%08x\n",
rules[rl].hdr_ofst,
rules[rl].eq_attrib.rule_eq_bitmap);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_id:%u cnt_id:%hhu prio:%u retain_hdr:%u\n",
rules[rl].id, rules[rl].cnt_idx,
rules[rl].priority, rules[rl].retain_hdr);
ipa3_attrib_collect_eq(
temp_buff,
IPA_MAX_ENTRY_STRING_LEN,
&rules[rl].eq_attrib);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s\n",
temp_buff);
}
}
fail:
if (temp_buff != NULL) {
kfree(temp_buff);
temp_buff = NULL;
}
mutex_unlock(&ipa3_ctx->lock);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
kfree(rules);
return nbytes;
}
static int ipa3_collect_flt(
char *msg_buff,
int max_buff_len,
enum ipa_ip_type ip)
{
char *temp_buff = NULL;
int i = 0, j = 0, nbytes = 0;
u32 rt_tbl_idx = 0, bitmap = 0;
bool eq = false;
struct ipa3_flt_tbl *tbl;
struct ipa3_flt_entry *entry;
struct ipa3_rt_tbl *rt_tbl;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
if (ip != IPA_IP_v6 && ip != IPA_IP_v4) {
IPAERR("ip type error %d\n", ip);
return 0;
}
memset(msg_buff, 0, max_buff_len);
mutex_lock(&ipa3_ctx->lock);
temp_buff = kzalloc(IPA_MAX_ENTRY_STRING_LEN, GFP_KERNEL);
if (temp_buff == NULL) {
IPAERR("temp buffer is not allocated");
goto fail;
}
for (j = 0; j < ipa3_ctx->ipa_num_pipes; j++) {
if (!ipa_is_ep_support_flt(j))
continue;
tbl = &ipa3_ctx->flt_tbl[j][ip];
i = 0;
list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
if (entry->cookie != IPA_FLT_COOKIE)
continue;
if (entry->rule.eq_attrib_type) {
rt_tbl_idx = entry->rule.rt_tbl_idx;
bitmap = entry->rule.eq_attrib.rule_eq_bitmap;
eq = true;
} else {
rt_tbl = ipa3_id_find(entry->rule.rt_tbl_hdl);
if (rt_tbl == NULL ||
rt_tbl->cookie != IPA_RT_TBL_COOKIE)
rt_tbl_idx = ~0;
else
rt_tbl_idx = rt_tbl->idx;
bitmap = entry->rule.attrib.attrib_mask;
eq = false;
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"ep_idx:%d rule_idx:%d act:%d rt_tbl_idx:%d ",
j, i, entry->rule.action, rt_tbl_idx);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"attrib_mask:%08x retain_hdr:%d eq:%d ",
bitmap, entry->rule.retain_hdr, eq);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"hashable:%u rule_id:%u max_prio:%u prio:%u ",
entry->rule.hashable, entry->rule_id,
entry->rule.max_prio, entry->prio);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"enable_stats:%u counter_id:%u ",
entry->rule.enable_stats,
entry->rule.cnt_idx);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"pdn index %d, set metadata %d ",
entry->rule.pdn_idx,
entry->rule.set_metadata);
if (eq) {
ipa3_attrib_collect_eq(
temp_buff,
IPA_MAX_ENTRY_STRING_LEN,
&entry->rule.eq_attrib);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s\n",
temp_buff);
} else {
ipa3_collect_attrib(
temp_buff,
IPA_MAX_ENTRY_STRING_LEN,
&entry->rule.attrib, ip);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s\n",
temp_buff);
}
i++;
}
}
if (temp_buff != NULL) {
kfree(temp_buff);
temp_buff = NULL;
}
fail:
mutex_unlock(&ipa3_ctx->lock);
return nbytes;
}
static int ipa3_collect_pdn_table(
char *msg_buff,
int max_buff_len)
{
char *pdn_entry = NULL;
char *buff = NULL;
int i = 0, result = 0, nbytes = 0;
bool entry_zeroed = false, entry_valid = false;
size_t pdn_entry_size = 0, buff_size = 128;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
buff = kzalloc(buff_size, GFP_KERNEL);
if (!buff) {
IPAERR("Out of memory\n");
return 0;
}
memset(buff, 0, buff_size);
if (ipa3_ctx->nat_mem.pdn_mem.base) {
result = ipahal_nat_entry_size(
IPAHAL_NAT_IPV4_PDN, &pdn_entry_size);
if (result) {
IPAERR("Failed to retrieve size of PDN entry");
goto fail;
}
for (i = 0, pdn_entry = ipa3_ctx->nat_mem.pdn_mem.base;
i < IPA_MAX_PDN_NUM;
++i, pdn_entry += pdn_entry_size) {
result = ipahal_nat_is_entry_zeroed(
IPAHAL_NAT_IPV4_PDN,
pdn_entry, &entry_zeroed);
if (result) {
IPAERR("ipahal_nat_is_entry_zeroed() fail\n");
goto fail;
}
if (entry_zeroed)
continue;
result = ipahal_nat_is_entry_valid(
IPAHAL_NAT_IPV4_PDN,
pdn_entry, &entry_valid);
if (result) {
IPAERR("Failed to determine whether "
"the PDN entry is valid\n");
goto fail;
}
if (entry_valid)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"PDN %d: ", i);
else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"PDN %d - Invalid: ", i);
ipahal_nat_stringify_entry(
IPAHAL_NAT_IPV4_PDN,
pdn_entry, buff, buff_size);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes, "%s\n", buff);
memset(buff, 0, buff_size);
}
}
fail:
if (buff != NULL) {
kfree(buff);
buff = NULL;
}
return nbytes;
}
static int ipa3_collect_table(
char *msg_buff, int max_buff_len,
char *table_addr, u32 table_size,
u32 *total_num_entries,
u32 *rule_id,
enum ipahal_nat_type nat_type)
{
char *entry = NULL;
char *buff = NULL;
int nbytes = 0, result = 0;
bool entry_zeroed = false, entry_valid = false;
u32 i = 0, num_entries = 0, id = *rule_id;
size_t entry_size = 0, buff_size = 2 * IPA_MAX_ENTRY_STRING_LEN;
if (table_addr == NULL) {
pr_err("NULL NAT table\n");
return 0;
}
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
result = ipahal_nat_entry_size(nat_type, &entry_size);
if (result) {
IPAERR("Failed to retrieve size of %s entry\n",
ipahal_nat_type_str(nat_type));
return 0;
}
buff = kzalloc(buff_size, GFP_KERNEL);
if (!buff) {
IPAERR("Out of memory\n");
return 0;
}
for (i = 0, entry = table_addr;
i < table_size;
++i, ++id, entry += entry_size) {
result = ipahal_nat_is_entry_zeroed(nat_type, entry,
&entry_zeroed);
if (result) {
IPAERR(
"Undefined if %s entry is zero\n",
ipahal_nat_type_str(nat_type));
goto fail;
}
if (entry_zeroed)
continue;
result = ipahal_nat_is_entry_valid(nat_type, entry,
&entry_valid);
if (result) {
IPAERR(
"Undefined if %s entry is valid\n",
ipahal_nat_type_str(nat_type));
goto fail;
}
if (entry_valid) {
++num_entries;
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"\tEntry_Index=%d\n", id);
} else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"\tEntry_Index=%d - Invalid Entry\n", id);
ipahal_nat_stringify_entry(nat_type, entry,
buff, buff_size);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes, "%s\n", buff);
memset(buff, 0, buff_size);
}
if (num_entries)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes, "\n");
else
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes, "\tEmpty\n\n");
fail:
if ( buff != NULL ) {
kfree(buff);
buff = NULL;
}
*rule_id = id;
*total_num_entries += num_entries;
return nbytes;
}
static int ipa3_start_collect_memory_device(
char *msg_buff, int max_buff_len,
struct ipa3_nat_ipv6ct_common_mem *dev,
enum ipahal_nat_type nat_type,
u32 *num_ddr_ent_ptr,
u32 *num_sram_ent_ptr)
{
char *temp_buff = NULL;
size_t temp_buff_size = 2 * IPA_MAX_ENTRY_STRING_LEN;
u32 rule_id = 0;
int nbytes = 0;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
temp_buff = kzalloc(temp_buff_size, GFP_KERNEL);
if (!temp_buff) {
IPAERR("Out of memory\n");
return 0;
}
if (dev->is_ipv6ct_mem) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"In: v6\n");
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"%s_Table_Size=%d\n",
dev->name, dev->table_entries + 1);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"%s_Expansion_Table_Size=%d\n",
dev->name, dev->expn_table_entries);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"\n%s Base Table:\n", dev->name);
if (dev->base_table_addr) {
ipa3_collect_table(
temp_buff,
temp_buff_size,
dev->base_table_addr,
dev->table_entries + 1,
num_ddr_ent_ptr,
&rule_id,
nat_type);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s\n", temp_buff);
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s Expansion Table:\n", dev->name);
if (dev->expansion_table_addr) {
ipa3_collect_table(
temp_buff, temp_buff_size,
dev->expansion_table_addr,
dev->expn_table_entries,
num_ddr_ent_ptr,
&rule_id,
nat_type);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s\n", temp_buff);
}
}
if (dev->is_nat_mem) {
struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
struct ipa3_nat_mem_loc_data *mld_ptr = NULL;
u32 *num_ent_ptr;
const char *type_ptr;
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"In: v4\n");
if (nm_ptr->active_table == IPA_NAT_MEM_IN_DDR &&
nm_ptr->ddr_in_use) {
mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_DDR];
num_ent_ptr = num_ddr_ent_ptr;
type_ptr = "DDR based table";
}
if (nm_ptr->active_table == IPA_NAT_MEM_IN_SRAM &&
nm_ptr->sram_in_use) {
mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_SRAM];
num_ent_ptr = num_sram_ent_ptr;
type_ptr = "SRAM based table";
}
if (mld_ptr) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"(%s) %s_Table_Size=%d\n",
type_ptr,
dev->name,
dev->table_entries + 1);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"(%s) %s_Expansion_Table_Size=%d\n",
type_ptr,
dev->name,
dev->expn_table_entries);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"\n(%s) %s_Base Table:\n",
type_ptr,
dev->name);
if (mld_ptr->base_table_addr) {
ipa3_collect_table(
temp_buff,
temp_buff_size,
mld_ptr->base_table_addr,
mld_ptr->table_entries + 1,
num_ent_ptr,
&rule_id,
nat_type);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s\n", temp_buff);
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"(%s) %s_Expansion Table:\n",
type_ptr,
dev->name);
if (mld_ptr->expansion_table_addr) {
ipa3_collect_table(
temp_buff, temp_buff_size,
mld_ptr->expansion_table_addr,
mld_ptr->expn_table_entries,
num_ent_ptr,
&rule_id,
nat_type);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s\n", temp_buff);
}
}
}
if (temp_buff != NULL) {
kfree(temp_buff);
temp_buff = NULL;
}
return nbytes;
}
static int ipa3_finish_collect_memory_device(
char *msg_buff, int max_buff_len,
struct ipa3_nat_ipv6ct_common_mem *dev,
u32 num_ddr_entries,
u32 num_sram_entries)
{
int nbytes = 0;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
if (dev->is_ipv6ct_mem) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"Overall number %s entries: %u\n\n",
dev->name,
num_ddr_entries);
} else {
struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
if (num_ddr_entries)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s: Overall number of DDR entries: %u\n\n",
dev->name,
num_ddr_entries);
if (num_sram_entries)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s: Overall number of SRAM entries: %u\n\n",
dev->name,
num_sram_entries);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"%s: Driver focus changes to DDR(%u) to SRAM(%u)\n",
dev->name,
nm_ptr->switch2ddr_cnt,
nm_ptr->switch2sram_cnt);
}
return nbytes;
}
static int ipa3_collect_nat4(char *msg_buff, int max_buff_len)
{
char *temp_buff = NULL;
size_t temp_buff_size = 3 * IPA_MAX_ENTRY_STRING_LEN;
int nbytes = 0;
struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->nat_mem.dev;
struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
struct ipa3_nat_mem_loc_data *mld_ptr = NULL;
u32 rule_id = 0;
u32 *num_ents_ptr;
u32 num_ddr_ents = 0;
u32 num_sram_ents = 0;
u32 *num_index_ents_ptr;
u32 num_ddr_index_ents = 0;
u32 num_sram_index_ents = 0;
const char *type_ptr;
bool any_table_active = (nm_ptr->ddr_in_use || nm_ptr->sram_in_use);
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
temp_buff = kzalloc(temp_buff_size, GFP_KERNEL);
if (temp_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"IPA3 NAT stats\n");
if (!dev->is_dev_init) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"NAT hasn't been initialized or not supported\n");
goto ret;
}
mutex_lock(&dev->lock);
if (!dev->is_hw_init || !any_table_active) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"NAT H/W and/or S/W not initialized\n");
goto fail;
}
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
ipa3_collect_pdn_table(temp_buff, temp_buff_size);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"%s\n",
temp_buff);
} else {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"NAT Table IP Address=%pI4h\n\n",
&ipa3_ctx->nat_mem.public_ip_addr);
}
ipa3_start_collect_memory_device(temp_buff, temp_buff_size,
dev,
IPAHAL_NAT_IPV4,
&num_ddr_ents,
&num_sram_ents);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"%s\n",
temp_buff);
if (nm_ptr->active_table == IPA_NAT_MEM_IN_DDR &&
nm_ptr->ddr_in_use) {
mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_DDR];
num_ents_ptr = &num_ddr_ents;
num_index_ents_ptr = &num_ddr_index_ents;
type_ptr = "DDR based table";
}
if (nm_ptr->active_table == IPA_NAT_MEM_IN_SRAM &&
nm_ptr->sram_in_use) {
mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_SRAM];
num_ents_ptr = &num_sram_ents;
num_index_ents_ptr = &num_sram_index_ents;
type_ptr = "SRAM based table";
}
if (mld_ptr) {
/* Print Index tables */
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"(%s) ipaNatTable Index Table:\n", type_ptr);
ipa3_collect_table(
temp_buff, temp_buff_size,
mld_ptr->index_table_addr,
mld_ptr->table_entries + 1,
num_index_ents_ptr,
&rule_id,
IPAHAL_NAT_IPV4_INDEX);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"%s\n",
temp_buff);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"(%s) ipaNatTable Expansion Index Table:\n", type_ptr);
ipa3_collect_table(
temp_buff, temp_buff_size,
mld_ptr->index_table_expansion_addr,
mld_ptr->expn_table_entries,
num_index_ents_ptr,
&rule_id,
IPAHAL_NAT_IPV4_INDEX);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"%s\n",
temp_buff);
if (*num_ents_ptr != *num_index_ents_ptr)
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"(%s) Base Table vs Index Table entry count differs (%u vs %u)\n",
type_ptr, *num_ents_ptr, *num_index_ents_ptr);
}
ipa3_finish_collect_memory_device(
temp_buff, temp_buff_size,
dev,
num_ddr_ents,
num_sram_ents);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"%s\n",
temp_buff);
fail:
mutex_unlock(&dev->lock);
ret:
if (temp_buff != NULL) {
kfree(temp_buff);
temp_buff = NULL;
}
return nbytes;
}
static int ipa3_collect_stats(char *msg_buff, int max_buff_len)
{
int i = 0, nbytes = 0;
uint connect = 0;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++)
connect |= (ipa3_ctx->ep[i].valid << i);
nbytes = scnprintf(msg_buff, max_buff_len,
"sw_tx=%u\n"
"hw_tx=%u\n"
"tx_non_linear=%u\n"
"tx_compl=%u\n"
"wan_rx=%u\n"
"stat_compl=%u\n"
"lan_aggr_close=%u\n"
"wan_aggr_close=%u\n"
"act_clnt=%u\n"
"con_clnt_bmap=0x%x\n"
"wan_rx_empty=%u\n"
"wan_repl_rx_empty=%u\n"
"lan_rx_empty=%u\n"
"lan_repl_rx_empty=%u\n"
"flow_enable=%u\n"
"flow_disable=%u\n",
ipa3_ctx->stats.tx_sw_pkts,
ipa3_ctx->stats.tx_hw_pkts,
ipa3_ctx->stats.tx_non_linear,
ipa3_ctx->stats.tx_pkts_compl,
ipa3_ctx->stats.rx_pkts,
ipa3_ctx->stats.stat_compl,
ipa3_ctx->stats.aggr_close,
ipa3_ctx->stats.wan_aggr_close,
atomic_read(&ipa3_ctx->ipa3_active_clients.cnt),
connect,
ipa3_ctx->stats.wan_rx_empty,
ipa3_ctx->stats.wan_repl_rx_empty,
ipa3_ctx->stats.lan_rx_empty,
ipa3_ctx->stats.lan_repl_rx_empty,
ipa3_ctx->stats.flow_enable,
ipa3_ctx->stats.flow_disable);
for (i = 0; i < IPAHAL_PKT_STATUS_EXCEPTION_MAX; i++) {
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"lan_rx_excp[%u:%20s]=%u\n", i,
ipahal_pkt_status_exception_str(i),
ipa3_ctx->stats.rx_excp_pkts[i]);
}
return nbytes;
}
static int ipa3_collect_wstats(char *msg_buff, int max_buff_len)
{
#define HEAD_FRMT_STR "%25s\n"
#define FRMT_STR "%25s %10u\n"
#define FRMT_STR1 "%25s %10u\n\n"
int nbytes = 0;
int ipa_ep_idx = 0;
enum ipa_client_type client = IPA_CLIENT_WLAN1_PROD;
struct ipa3_ep_context *ep;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
do {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
HEAD_FRMT_STR, "Client IPA_CLIENT_WLAN1_PROD Stats:");
ipa_ep_idx = ipa3_get_ep_mapping(client);
if (ipa_ep_idx == -1) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
HEAD_FRMT_STR, "Not up");
break;
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (ep->valid != 1) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
HEAD_FRMT_STR, "Not up");
break;
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR, "Avail Fifo Desc:",
atomic_read(&ep->avail_fifo_desc));
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR, "Rx Pkts Rcvd:", ep->wstats.rx_pkts_rcvd);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR, "Rx Pkts Status Rcvd:",
ep->wstats.rx_pkts_status_rcvd);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR, "Rx DH Rcvd:", ep->wstats.rx_hd_rcvd);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR, "Rx DH Processed:",
ep->wstats.rx_hd_processed);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR, "Rx DH Sent Back:", ep->wstats.rx_hd_reply);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR, "Rx Pkt Leak:", ep->wstats.rx_pkt_leak);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR1, "Rx DP Fail:", ep->wstats.rx_dp_fail);
} while (0);
client = IPA_CLIENT_WLAN1_CONS;
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
HEAD_FRMT_STR,
"Client IPA_CLIENT_WLAN1_CONS Stats:");
while (1) {
ipa_ep_idx = ipa3_get_ep_mapping(client);
if (ipa_ep_idx == -1) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
HEAD_FRMT_STR, "Not up");
goto nxt_clnt_cons;
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
if (ep->valid != 1) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
HEAD_FRMT_STR, "Not up");
goto nxt_clnt_cons;
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR,
"Tx Pkts Received:",
ep->wstats.tx_pkts_rcvd);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR,
"Tx Pkts Sent:",
ep->wstats.tx_pkts_sent);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR1,
"Tx Pkts Dropped:",
ep->wstats.tx_pkts_dropped);
nxt_clnt_cons:
switch (client) {
case IPA_CLIENT_WLAN1_CONS:
client = IPA_CLIENT_WLAN2_CONS;
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
HEAD_FRMT_STR,
"Client IPA_CLIENT_WLAN2_CONS Stats:");
continue;
case IPA_CLIENT_WLAN2_CONS:
client = IPA_CLIENT_WLAN3_CONS;
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
HEAD_FRMT_STR,
"Client IPA_CLIENT_WLAN3_CONS Stats:");
continue;
case IPA_CLIENT_WLAN3_CONS:
client = IPA_CLIENT_WLAN4_CONS;
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
HEAD_FRMT_STR,
"Client IPA_CLIENT_WLAN4_CONS Stats:");
continue;
case IPA_CLIENT_WLAN4_CONS:
default:
break;
}
break;
}
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"\n"HEAD_FRMT_STR,
"All Wlan Consumer pipes stats:");
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR,
"Tx Comm Buff Allocated:",
ipa3_ctx->wc_memb.wlan_comm_total_cnt);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR,
"Tx Comm Buff Avail:",
ipa3_ctx->wc_memb.wlan_comm_free_cnt);
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
FRMT_STR1,
"Total Tx Pkts Freed:",
ipa3_ctx->wc_memb.total_tx_pkts_freed);
return nbytes;
}
static int ipa3_collect_msg(char *msg_buff, int max_buff_len)
{
int nbytes = 0, i = 0;
if (msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
memset(msg_buff, 0, max_buff_len);
for (i = 0; i < ARRAY_SIZE(ipa3_event_name); i++) {
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"msg[%u:%27s] W:%u R:%u\n", i,
ipa3_event_name[i],
ipa3_ctx->stats.msg_w[i],
ipa3_ctx->stats.msg_r[i]);
}
return nbytes;
}
static int ipa3_collect_debug_msg(char *msg_buff, int max_buff_len)
{
char *temp_buff = NULL;
int max_temp_len = IPA_MAX_MSG_LEN;
int nbytes = 0;
if (msg_buff == NULL) {
IPAERR("msg_buff is NULL\n");
return 0;
}
memset(msg_buff, 0, max_buff_len);
temp_buff = kzalloc(max_temp_len, GFP_KERNEL);
if (!temp_buff) {
IPAERR("temp_buff is NULL\n");
return 0;
}
//Start
nbytes += scnprintf(msg_buff, max_buff_len,
"===== IPA debug message start =====\n\n");
//gen_reg
ipa3_collect_gen_reg(temp_buff, max_temp_len);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA register ====\n"
"%s\n\n",
temp_buff);
//active_clients
ipa3_collect_active_clients(temp_buff, max_temp_len);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA active clients ====\n"
"%s\n\n",
temp_buff);
//ep_reg
ipa3_collect_ep_reg(temp_buff, max_temp_len);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA ep reg ====\n"
"%s\n\n",
temp_buff);
//ip4_rt
ipa3_collect_rt(temp_buff, max_temp_len, IPA_IP_v4);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA ip4 rt ====\n"
"%s\n\n",
temp_buff);
if(IPA_DEBUG_MSG_DUMP_HW) {
//ip4_rt_hw
ipa3_collect_rt_hw(temp_buff, max_temp_len, IPA_IP_v4);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA ip4 rt hw ====\n"
"%s\n\n",
temp_buff);
}
//ip4_flt
ipa3_collect_flt(temp_buff, max_temp_len, IPA_IP_v4);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA ip4 flt ====\n"
"%s\n\n",
temp_buff);
//ip4_nat
ipa3_collect_nat4(temp_buff, max_temp_len);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA ip4 nat ====\n"
"%s\n\n",
temp_buff);
//ip6_rt
ipa3_collect_rt(temp_buff, max_temp_len, IPA_IP_v6);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA ip6 rt ====\n"
"%s\n\n",
temp_buff);
if(IPA_DEBUG_MSG_DUMP_HW) {
//ip6_rt_hw
ipa3_collect_rt_hw(temp_buff, max_temp_len, IPA_IP_v6);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA ip6 rt hw ====\n"
"%s\n\n",
temp_buff);
}
//ip6_flt
ipa3_collect_flt(temp_buff, max_temp_len, IPA_IP_v6);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA ip6 flt ====\n"
"%s\n\n",
temp_buff);
//stats
ipa3_collect_stats(temp_buff, max_temp_len);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA stats ====\n"
"%s\n\n",
temp_buff);
//wstats
ipa3_collect_wstats(temp_buff, max_temp_len);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA wstats ====\n"
"%s\n\n",
temp_buff);
//msg
ipa3_collect_msg(temp_buff, max_temp_len);
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"==== IPA msg ====\n"
"%s\n\n",
temp_buff);
//End
nbytes += scnprintf(msg_buff + nbytes, max_buff_len - nbytes,
"===== IPA debug message end =====\n\r");
if (temp_buff != NULL) {
kfree(temp_buff);
temp_buff = NULL;
}
return nbytes;
}
static ssize_t ipa3_read_dump_debug_msg(
struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
ssize_t ret = 0;
if (*ppos == 0) {
//alloc buffer
ipa_msg_buff_count = 0;
if (ipa_msg_buff == NULL) {
ipa_msg_buff =
kzalloc(IPA_MAX_DEBUG_MSG_LEN, GFP_KERNEL);
}
if ( ipa_msg_buff )
memset(ipa_msg_buff, 0, IPA_MAX_DEBUG_MSG_LEN);
else {
IPAERR("buffer is not allocated");
return 0;
}
//collect data
ipa_msg_buff_count =
ipa3_collect_debug_msg(
ipa_msg_buff,
IPA_MAX_DEBUG_MSG_LEN);
pr_info("ipa_msg_buff_count=[%d]", ipa_msg_buff_count);
} else if (*ppos == ipa_msg_buff_count) {
ipa_msg_buff_count = 0;
if (ipa_msg_buff != NULL) {
kfree(ipa_msg_buff);
ipa_msg_buff = NULL;
}
return 0;
}
//check buffer before print
if (ipa_msg_buff == NULL) {
IPAERR("buffer is not allocated");
return 0;
}
//Check buffer size and ipa_msg_buff_count
if ( strlen(ipa_msg_buff) != ipa_msg_buff_count ) {
ipa_msg_buff_count = 0;
if (ipa_msg_buff != NULL) {
kfree(ipa_msg_buff);
ipa_msg_buff = NULL;
}
IPAERR("ipa_msg_buff size is incorrect\n");
return 0;
}
ret = simple_read_from_buffer(
ubuf, count, ppos,
ipa_msg_buff,
ipa_msg_buff_count);
return ret;
}
#else /* !CONFIG_DEBUG_FS */
#define INVALID_NO_OF_CHAR (-1)
void ipa3_debugfs_pre_init(void) {}
void ipa3_debugfs_post_init(void) {}
void ipa3_debugfs_remove(void) {}
int _ipa_read_ep_reg_v3_0(char *buf, int max_len, int pipe)
{
return INVALID_NO_OF_CHAR;
}
int _ipa_read_ep_reg_v4_0(char *buf, int max_len, int pipe)
{
return INVALID_NO_OF_CHAR;
}
#endif