| /* 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) { |
| ofst = entry->proc_ctx->offset_entry->offset; |
| ofst_words = |
| (ofst + |
| ipa3_ctx->hdr_proc_ctx_tbl.start_offset) |
| >> 5; |
| |
| 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) |
| ofst = entry->hdr->offset_entry->offset; |
| else |
| ofst = 0; |
| |
| 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 |