Loading drivers/platform/msm/ipa/ipa_v2/ipa.c +212 −64 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ #include <linux/delay.h> #include <linux/qcom_iommu.h> #include <linux/time.h> #include <linux/hashtable.h> #include <linux/hash.h> #include "ipa_i.h" #include "ipa_rm_i.h" Loading @@ -56,6 +58,13 @@ #define CLEANUP_TAG_PROCESS_TIMEOUT 150 #define IPA2_ACTIVE_CLIENTS_TABLE_BUF_SIZE 2048 #define IPA2_ACTIVE_CLIENT_LOG_TYPE_EP 0 #define IPA2_ACTIVE_CLIENT_LOG_TYPE_SIMPLE 1 #define IPA2_ACTIVE_CLIENT_LOG_TYPE_RESOURCE 2 #define IPA2_ACTIVE_CLIENT_LOG_TYPE_SPECIAL 3 #define IPA_AGGR_STR_IN_BYTES(str) \ (strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1) Loading Loading @@ -195,6 +204,8 @@ static bool smmu_present; static bool arm_smmu; static bool smmu_disable_htw; static char *active_clients_table_buf; const char *ipa2_clients_strings[IPA_CLIENT_MAX] = { __stringify(IPA_CLIENT_HSIC1_PROD), __stringify(IPA_CLIENT_WLAN1_PROD), Loading Loading @@ -267,23 +278,107 @@ const char *ipa2_clients_strings[IPA_CLIENT_MAX] = { __stringify(IPA_CLIENT_TEST4_CONS), }; int ipa2_active_clients_log_print_buffer(char *buf, int size) { int i; int nbytes; int cnt = 0; int start_idx; int end_idx; start_idx = (ipa_ctx->ipa2_active_clients_logging.log_tail + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; end_idx = ipa_ctx->ipa2_active_clients_logging.log_head; for (i = start_idx; i != end_idx; i = (i + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) { nbytes = scnprintf(buf + cnt, size - cnt, "%s\n", ipa_ctx->ipa2_active_clients_logging .log_buffer[i]); cnt += nbytes; } return cnt; } int ipa2_active_clients_log_print_table(char *buf, int size) { int i; struct ipa2_active_client_htable_entry *iterator; int cnt = 0; cnt = scnprintf(buf, size, "\n---- Active Clients Table ----\n"); hash_for_each(ipa_ctx->ipa2_active_clients_logging.htable, i, iterator, list) { switch (iterator->type) { case IPA2_ACTIVE_CLIENT_LOG_TYPE_EP: cnt += scnprintf(buf + cnt, size - cnt, "%-40s %-3d ENDPOINT\n", iterator->id_string, iterator->count); break; case IPA2_ACTIVE_CLIENT_LOG_TYPE_SIMPLE: cnt += scnprintf(buf + cnt, size - cnt, "%-40s %-3d SIMPLE\n", iterator->id_string, iterator->count); break; case IPA2_ACTIVE_CLIENT_LOG_TYPE_RESOURCE: cnt += scnprintf(buf + cnt, size - cnt, "%-40s %-3d RESOURCE\n", iterator->id_string, iterator->count); break; case IPA2_ACTIVE_CLIENT_LOG_TYPE_SPECIAL: cnt += scnprintf(buf + cnt, size - cnt, "%-40s %-3d SPECIAL\n", iterator->id_string, iterator->count); break; default: IPAERR("Trying to print illegal active_clients type"); break; } } cnt += scnprintf(buf + cnt, size - cnt, "\nTotal active clients count: %d\n", ipa_ctx->ipa_active_clients.cnt); return cnt; } static int ipa2_active_clients_panic_notifier(struct notifier_block *this, unsigned long event, void *ptr) { ipa_active_clients_lock(); ipa2_active_clients_log_print_table(active_clients_table_buf, IPA2_ACTIVE_CLIENTS_TABLE_BUF_SIZE); IPAERR("%s", active_clients_table_buf); ipa_active_clients_unlock(); return NOTIFY_DONE; } static struct notifier_block ipa2_active_clients_panic_blk = { .notifier_call = ipa2_active_clients_panic_notifier, }; static int ipa2_active_clients_log_insert(const char *string) { int head; int tail; head = ipa_ctx->ipa2_active_clients_logging.log_head; tail = ipa_ctx->ipa2_active_clients_logging.log_tail; if (!ipa_ctx->ipa2_active_clients_logging.log_rdy) return -EPERM; strlcpy(ipa_ctx->ipa2_active_clients_logging.log_buffer [ipa_ctx->ipa2_active_clients_logging.log_head], string, memset(ipa_ctx->ipa2_active_clients_logging.log_buffer[head], '_', IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN); strlcpy(ipa_ctx->ipa2_active_clients_logging.log_buffer[head], string, (size_t)IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN); ipa_ctx->ipa2_active_clients_logging.log_head = (ipa_ctx->ipa2_active_clients_logging.log_head + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; if (ipa_ctx->ipa2_active_clients_logging.log_tail == ipa_ctx->ipa2_active_clients_logging.log_head) { ipa_ctx->ipa2_active_clients_logging.log_tail = (ipa_ctx->ipa2_active_clients_logging.log_tail + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; } head = (head + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; if (tail == head) tail = (tail + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; ipa_ctx->ipa2_active_clients_logging.log_tail = tail; ipa_ctx->ipa2_active_clients_logging.log_head = head; return 0; } Loading @@ -295,6 +390,8 @@ static int ipa2_active_clients_log_init(void) IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES * sizeof(char[IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN]), GFP_KERNEL); active_clients_table_buf = kzalloc(sizeof( char[IPA2_ACTIVE_CLIENTS_TABLE_BUF_SIZE]), GFP_KERNEL); if (ipa_ctx->ipa2_active_clients_logging.log_buffer == NULL) { IPAERR("Active Clients Logging memory allocation failed"); goto bail; Loading @@ -307,6 +404,9 @@ static int ipa2_active_clients_log_init(void) ipa_ctx->ipa2_active_clients_logging.log_head = 0; ipa_ctx->ipa2_active_clients_logging.log_tail = IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1; hash_init(ipa_ctx->ipa2_active_clients_logging.htable); atomic_notifier_chain_register(&panic_notifier_list, &ipa2_active_clients_panic_blk); ipa_ctx->ipa2_active_clients_logging.log_rdy = 1; return 0; Loading @@ -333,22 +433,6 @@ static void ipa2_active_clients_log_destroy(void) IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1; } void ipa2_active_clients_log_print_buffer(void) { int i; ipa_active_clients_lock(); for (i = (ipa_ctx->ipa2_active_clients_logging.log_tail + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; i != ipa_ctx->ipa2_active_clients_logging.log_head; i = (i + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) { pr_err("%s\n", ipa_ctx->ipa2_active_clients_logging .log_buffer[i]); } ipa_active_clients_unlock(); } enum ipa_smmu_cb_type { IPA_SMMU_CB_AP, IPA_SMMU_CB_WLAN, Loading Loading @@ -2922,37 +3006,116 @@ static void ipa_start_tag_process(struct work_struct *work) if (res) IPAERR("ipa_tag_aggr_force_close failed %d\n", res); IPA2_ACTIVE_CLIENTS_DEC_SIMPLE(); IPA2_ACTIVE_CLIENTS_DEC_SPECIAL("TAG_PROCESS"); IPADBG("TAG process done\n"); } /** * ipa_inc_client_enable_clks() - Increase active clients counter, and * enable ipa clocks if necessary * ipa2_active_clients_log_mod() - Log a modification in the active clients * reference count * * Please do not use this API, use the wrapper macros instead (ipa_i.h) * IPA2_ACTIVE_CLIENTS_INC_XXXX(); * This method logs any modification in the active clients reference count: * It logs the modification in the circular history buffer * It logs the modification in the hash table - looking for an entry, * creating one if needed and deleting one if needed. * * Return codes: * None * @id: ipa2_active client logging info struct to hold the log information * @inc: a boolean variable to indicate whether the modification is an increase * or decrease * @int_ctx: a boolean variable to indicate whether this call is being made from * an interrupt context and therefore should allocate GFP_ATOMIC memory * * Method process: * - Hash the unique identifier string * - Find the hash in the table * 1)If found, increase or decrease the reference count * 2)If not found, allocate a new hash table entry struct and initialize it * - Remove and deallocate unneeded data structure * - Log the call in the circular history buffer (unless it is a simple call) */ void ipa2_inc_client_enable_clks(struct ipa2_active_client_logging_info *id) void ipa2_active_clients_log_mod(struct ipa2_active_client_logging_info *id, bool inc, bool int_ctx) { char temp_str[IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN]; unsigned long long t; unsigned long nanosec_rem; struct ipa2_active_client_htable_entry *hentry; struct ipa2_active_client_htable_entry *hfound; u32 hkey; char str_to_hash[IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN]; hfound = NULL; memset(str_to_hash, 0, IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN); strlcpy(str_to_hash, id->id_string, IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN); hkey = arch_fast_hash(str_to_hash, IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN, 0); hash_for_each_possible(ipa_ctx->ipa2_active_clients_logging.htable, hentry, list, hkey) { if (!strcmp(hentry->id_string, id->id_string)) { hentry->count = hentry->count + (inc ? 1 : -1); hfound = hentry; } } if (hfound == NULL) { hentry = NULL; hentry = kzalloc(sizeof( struct ipa2_active_client_htable_entry), int_ctx ? GFP_ATOMIC : GFP_KERNEL); if (hentry == NULL) { IPAERR("failed allocating active clients hash entry"); return; } hentry->type = id->type; strlcpy(hentry->id_string, id->id_string, IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN); INIT_HLIST_NODE(&hentry->list); hentry->count = inc ? 1 : -1; hash_add(ipa_ctx->ipa2_active_clients_logging.htable, &hentry->list, hkey); } else if (hfound->count == 0) { hash_del(&hfound->list); kfree(hfound); } ipa_active_clients_lock(); if (id->type != SIMPLE) { t = local_clock(); nanosec_rem = do_div(t, 1000000000) / 1000; snprintf(temp_str, IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN, "[%5lu.%06lu] ^ %s, %s: %d", inc ? "[%5lu.%06lu] ^ %s, %s: %d" : "[%5lu.%06lu] v %s, %s: %d", (unsigned long)t, nanosec_rem, id->id_string, id->file, id->line); ipa2_active_clients_log_insert(temp_str); } } void ipa2_active_clients_log_dec(struct ipa2_active_client_logging_info *id, bool int_ctx) { ipa2_active_clients_log_mod(id, false, int_ctx); } void ipa2_active_clients_log_inc(struct ipa2_active_client_logging_info *id, bool int_ctx) { ipa2_active_clients_log_mod(id, true, int_ctx); } /** * ipa_inc_client_enable_clks() - Increase active clients counter, and * enable ipa clocks if necessary * * Please do not use this API, use the wrapper macros instead (ipa_i.h) * IPA2_ACTIVE_CLIENTS_INC_XXXX(); * * Return codes: * None */ void ipa2_inc_client_enable_clks(struct ipa2_active_client_logging_info *id) { ipa_active_clients_lock(); ipa2_active_clients_log_inc(id, false); ipa_ctx->ipa_active_clients.cnt++; if (ipa_ctx->ipa_active_clients.cnt == 1) ipa_enable_clks(); Loading @@ -2976,9 +3139,6 @@ int ipa2_inc_client_enable_clks_no_block(struct ipa2_active_client_logging_info { int res = 0; unsigned long flags; char temp_str[IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN]; unsigned long long t; unsigned long nanosec_rem; if (ipa_active_clients_trylock(&flags) == 0) return -EPERM; Loading @@ -2988,15 +3148,7 @@ int ipa2_inc_client_enable_clks_no_block(struct ipa2_active_client_logging_info goto bail; } if (id->type != SIMPLE) { t = local_clock(); nanosec_rem = do_div(t, 1000000000) / 1000; snprintf(temp_str, IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN, "[%5lu.%06lu] ^ %s, %s: %d", (unsigned long)t, nanosec_rem, id->id_string, id->file, id->line); ipa2_active_clients_log_insert(temp_str); } ipa2_active_clients_log_inc(id, true); ipa_ctx->ipa_active_clients.cnt++; IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients.cnt); Loading @@ -3022,24 +3174,17 @@ bail: */ void ipa2_dec_client_disable_clks(struct ipa2_active_client_logging_info *id) { char temp_str[IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN]; unsigned long long t; unsigned long nanosec_rem; struct ipa2_active_client_logging_info log_info; ipa_active_clients_lock(); if (id->type != SIMPLE) { t = local_clock(); nanosec_rem = do_div(t, 1000000000) / 1000; snprintf(temp_str, IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN, "[%5lu.%06lu] v %s, %s: %d", (unsigned long)t, nanosec_rem, id->id_string, id->file, id->line); ipa2_active_clients_log_insert(temp_str); } ipa2_active_clients_log_dec(id, false); ipa_ctx->ipa_active_clients.cnt--; IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients.cnt); if (ipa_ctx->ipa_active_clients.cnt == 0) { if (ipa_ctx->tag_process_before_gating) { IPA2_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "TAG_PROCESS"); ipa2_active_clients_log_inc(&log_info, false); ipa_ctx->tag_process_before_gating = false; /* * When TAG process ends, active clients will be Loading Loading @@ -3464,6 +3609,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, struct sps_bam_props bam_props = { 0 }; struct ipa_flt_tbl *flt_tbl; struct ipa_rt_tbl_set *rset; struct ipa2_active_client_logging_info log_info; IPADBG("IPA Driver initialization started\n"); Loading Loading @@ -3587,6 +3733,8 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, mutex_init(&ipa_ctx->ipa_active_clients.mutex); spin_lock_init(&ipa_ctx->ipa_active_clients.spinlock); IPA2_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE"); ipa2_active_clients_log_inc(&log_info, false); ipa_ctx->ipa_active_clients.cnt = 1; /* Create workqueues for power management */ Loading drivers/platform/msm/ipa/ipa_v2/ipa_client.c +4 −4 Original line number Diff line number Diff line Loading @@ -539,6 +539,7 @@ int ipa2_disconnect(u32 clnt_hdl) struct iommu_domain *smmu_domain; struct ipa_disable_force_clear_datapath_req_msg_v01 req = {0}; int res; enum ipa_client_type client_type; if (unlikely(!ipa_ctx)) { IPAERR("IPA driver was not initialized\n"); Loading @@ -552,10 +553,9 @@ int ipa2_disconnect(u32 clnt_hdl) } ep = &ipa_ctx->ep[clnt_hdl]; client_type = ipa2_get_client_mapping(clnt_hdl); if (!ep->keep_ipa_awake) IPA2_ACTIVE_CLIENTS_INC_EP(ipa2_get_client_mapping(clnt_hdl)); IPA2_ACTIVE_CLIENTS_INC_EP(client_type); /* Set Disconnect in Progress flag. */ spin_lock(&ipa_ctx->disconnect_lock); Loading Loading @@ -662,7 +662,7 @@ int ipa2_disconnect(u32 clnt_hdl) memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context)); spin_unlock(&ipa_ctx->disconnect_lock); IPA2_ACTIVE_CLIENTS_DEC_EP(ipa2_get_client_mapping(clnt_hdl)); IPA2_ACTIVE_CLIENTS_DEC_EP(client_type); IPADBG("client (ep: %d) disconnected\n", clnt_hdl); Loading drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +33 −5 Original line number Diff line number Diff line Loading @@ -21,6 +21,9 @@ #define IPA_MAX_MSG_LEN 4096 #define IPA_DBG_CNTR_ON 127265 #define IPA_DBG_CNTR_OFF 127264 #define IPA_DBG_ACTIVE_CLIENTS_BUF_SIZE ((IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN \ * IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) \ + IPA_MAX_MSG_LEN) #define IPA_DUMP_STATUS_FIELD(f) \ pr_err(#f "=0x%x\n", status->f) Loading Loading @@ -108,6 +111,7 @@ static struct dentry *dfile_rm_stats; static struct dentry *dfile_status_stats; static struct dentry *dfile_active_clients; static char dbg_buff[IPA_MAX_MSG_LEN]; static char *active_clients_buf; static s8 ep_reg_idx; int _ipa_read_gen_reg_v1_1(char *buff, int max_len) Loading Loading @@ -1552,10 +1556,24 @@ static ssize_t ipa_status_stats_read(struct file *file, char __user *ubuf, static ssize_t ipa2_print_active_clients_log(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { ipa2_active_clients_log_print_buffer(); 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_CLIENTS_BUF_SIZE); ipa_active_clients_lock(); cnt = ipa2_active_clients_log_print_buffer(active_clients_buf, IPA_DBG_ACTIVE_CLIENTS_BUF_SIZE - IPA_MAX_MSG_LEN); table_size = ipa2_active_clients_log_print_table(active_clients_buf + cnt, IPA_MAX_MSG_LEN); ipa_active_clients_unlock(); return simple_read_from_buffer(ubuf, count, ppos, active_clients_buf, cnt + table_size); } static ssize_t ipa2_clear_active_clients_log(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) Loading Loading @@ -1682,13 +1700,19 @@ void ipa_debugfs_init(void) goto fail; } dfile_ep_reg = debugfs_create_file("active_clients", dfile_active_clients = debugfs_create_file("active_clients", read_write_mode, dent, 0, &ipa2_active_clients); if (!dfile_ep_reg || IS_ERR(dfile_active_clients)) { IPAERR("fail to create file for debug_fs ep_reg\n"); if (!dfile_active_clients || IS_ERR(dfile_active_clients)) { IPAERR("fail to create file for debug_fs active_clients\n"); goto fail; } active_clients_buf = NULL; active_clients_buf = kzalloc(IPA_DBG_ACTIVE_CLIENTS_BUF_SIZE, GFP_KERNEL); if (active_clients_buf == NULL) IPAERR("fail to allocate active clients memory buffer"); dfile_ep_reg = debugfs_create_file("ep_reg", read_write_mode, dent, 0, &ipa_ep_reg_ops); if (!dfile_ep_reg || IS_ERR(dfile_ep_reg)) { Loading Loading @@ -1843,6 +1867,10 @@ void ipa_debugfs_remove(void) IPAERR("ipa_debugfs_remove: folder was not created.\n"); return; } if (active_clients_buf != NULL) { kfree(active_clients_buf); active_clients_buf = NULL; } debugfs_remove_recursive(dent); } Loading drivers/platform/msm/ipa/ipa_v2/ipa_i.h +17 −2 Original line number Diff line number Diff line Loading @@ -235,7 +235,9 @@ } while (0) #define IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES 120 #define IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN 100 #define IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN 96 #define IPA2_ACTIVE_CLIENTS_LOG_HASHTABLE_SIZE 50 #define IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN 40 extern const char *ipa2_clients_strings[]; Loading @@ -254,11 +256,19 @@ struct ipa2_active_client_logging_info { enum ipa2_active_client_log_type type; }; struct ipa2_active_client_htable_entry { struct hlist_node list; char id_string[IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN]; int count; enum ipa2_active_client_log_type type; }; struct ipa2_active_clients_log_ctx { char *log_buffer[IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES]; int log_head; int log_tail; bool log_rdy; struct hlist_head htable[IPA2_ACTIVE_CLIENTS_LOG_HASHTABLE_SIZE]; }; Loading Loading @@ -1945,7 +1955,12 @@ void ipa2_inc_client_enable_clks(struct ipa2_active_client_logging_info *id); int ipa2_inc_client_enable_clks_no_block(struct ipa2_active_client_logging_info *id); void ipa2_dec_client_disable_clks(struct ipa2_active_client_logging_info *id); void ipa2_active_clients_log_print_buffer(void); void ipa2_active_clients_log_dec(struct ipa2_active_client_logging_info *id, bool int_ctx); void ipa2_active_clients_log_inc(struct ipa2_active_client_logging_info *id, bool int_ctx); int ipa2_active_clients_log_print_buffer(char *buf, int size); int ipa2_active_clients_log_print_table(char *buf, int size); void ipa2_active_clients_log_clear(void); int ipa_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev); int __ipa_del_rt_rule(u32 rule_hdl); Loading drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +4 −0 Original line number Diff line number Diff line Loading @@ -569,6 +569,7 @@ int ipa_suspend_resource_no_block(enum ipa_rm_resource_name resource) struct ipa_ep_cfg_ctrl suspend; int ipa_ep_idx; unsigned long flags; struct ipa2_active_client_logging_info log_info; if (ipa_active_clients_trylock(&flags) == 0) return -EPERM; Loading Loading @@ -606,6 +607,9 @@ int ipa_suspend_resource_no_block(enum ipa_rm_resource_name resource) } if (res == 0) { IPA2_ACTIVE_CLIENTS_PREP_RESOURCE(log_info, ipa_rm_resource_str(resource)); ipa2_active_clients_log_dec(&log_info, true); ipa_ctx->ipa_active_clients.cnt--; IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients.cnt); Loading Loading
drivers/platform/msm/ipa/ipa_v2/ipa.c +212 −64 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ #include <linux/delay.h> #include <linux/qcom_iommu.h> #include <linux/time.h> #include <linux/hashtable.h> #include <linux/hash.h> #include "ipa_i.h" #include "ipa_rm_i.h" Loading @@ -56,6 +58,13 @@ #define CLEANUP_TAG_PROCESS_TIMEOUT 150 #define IPA2_ACTIVE_CLIENTS_TABLE_BUF_SIZE 2048 #define IPA2_ACTIVE_CLIENT_LOG_TYPE_EP 0 #define IPA2_ACTIVE_CLIENT_LOG_TYPE_SIMPLE 1 #define IPA2_ACTIVE_CLIENT_LOG_TYPE_RESOURCE 2 #define IPA2_ACTIVE_CLIENT_LOG_TYPE_SPECIAL 3 #define IPA_AGGR_STR_IN_BYTES(str) \ (strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1) Loading Loading @@ -195,6 +204,8 @@ static bool smmu_present; static bool arm_smmu; static bool smmu_disable_htw; static char *active_clients_table_buf; const char *ipa2_clients_strings[IPA_CLIENT_MAX] = { __stringify(IPA_CLIENT_HSIC1_PROD), __stringify(IPA_CLIENT_WLAN1_PROD), Loading Loading @@ -267,23 +278,107 @@ const char *ipa2_clients_strings[IPA_CLIENT_MAX] = { __stringify(IPA_CLIENT_TEST4_CONS), }; int ipa2_active_clients_log_print_buffer(char *buf, int size) { int i; int nbytes; int cnt = 0; int start_idx; int end_idx; start_idx = (ipa_ctx->ipa2_active_clients_logging.log_tail + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; end_idx = ipa_ctx->ipa2_active_clients_logging.log_head; for (i = start_idx; i != end_idx; i = (i + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) { nbytes = scnprintf(buf + cnt, size - cnt, "%s\n", ipa_ctx->ipa2_active_clients_logging .log_buffer[i]); cnt += nbytes; } return cnt; } int ipa2_active_clients_log_print_table(char *buf, int size) { int i; struct ipa2_active_client_htable_entry *iterator; int cnt = 0; cnt = scnprintf(buf, size, "\n---- Active Clients Table ----\n"); hash_for_each(ipa_ctx->ipa2_active_clients_logging.htable, i, iterator, list) { switch (iterator->type) { case IPA2_ACTIVE_CLIENT_LOG_TYPE_EP: cnt += scnprintf(buf + cnt, size - cnt, "%-40s %-3d ENDPOINT\n", iterator->id_string, iterator->count); break; case IPA2_ACTIVE_CLIENT_LOG_TYPE_SIMPLE: cnt += scnprintf(buf + cnt, size - cnt, "%-40s %-3d SIMPLE\n", iterator->id_string, iterator->count); break; case IPA2_ACTIVE_CLIENT_LOG_TYPE_RESOURCE: cnt += scnprintf(buf + cnt, size - cnt, "%-40s %-3d RESOURCE\n", iterator->id_string, iterator->count); break; case IPA2_ACTIVE_CLIENT_LOG_TYPE_SPECIAL: cnt += scnprintf(buf + cnt, size - cnt, "%-40s %-3d SPECIAL\n", iterator->id_string, iterator->count); break; default: IPAERR("Trying to print illegal active_clients type"); break; } } cnt += scnprintf(buf + cnt, size - cnt, "\nTotal active clients count: %d\n", ipa_ctx->ipa_active_clients.cnt); return cnt; } static int ipa2_active_clients_panic_notifier(struct notifier_block *this, unsigned long event, void *ptr) { ipa_active_clients_lock(); ipa2_active_clients_log_print_table(active_clients_table_buf, IPA2_ACTIVE_CLIENTS_TABLE_BUF_SIZE); IPAERR("%s", active_clients_table_buf); ipa_active_clients_unlock(); return NOTIFY_DONE; } static struct notifier_block ipa2_active_clients_panic_blk = { .notifier_call = ipa2_active_clients_panic_notifier, }; static int ipa2_active_clients_log_insert(const char *string) { int head; int tail; head = ipa_ctx->ipa2_active_clients_logging.log_head; tail = ipa_ctx->ipa2_active_clients_logging.log_tail; if (!ipa_ctx->ipa2_active_clients_logging.log_rdy) return -EPERM; strlcpy(ipa_ctx->ipa2_active_clients_logging.log_buffer [ipa_ctx->ipa2_active_clients_logging.log_head], string, memset(ipa_ctx->ipa2_active_clients_logging.log_buffer[head], '_', IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN); strlcpy(ipa_ctx->ipa2_active_clients_logging.log_buffer[head], string, (size_t)IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN); ipa_ctx->ipa2_active_clients_logging.log_head = (ipa_ctx->ipa2_active_clients_logging.log_head + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; if (ipa_ctx->ipa2_active_clients_logging.log_tail == ipa_ctx->ipa2_active_clients_logging.log_head) { ipa_ctx->ipa2_active_clients_logging.log_tail = (ipa_ctx->ipa2_active_clients_logging.log_tail + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; } head = (head + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; if (tail == head) tail = (tail + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; ipa_ctx->ipa2_active_clients_logging.log_tail = tail; ipa_ctx->ipa2_active_clients_logging.log_head = head; return 0; } Loading @@ -295,6 +390,8 @@ static int ipa2_active_clients_log_init(void) IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES * sizeof(char[IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN]), GFP_KERNEL); active_clients_table_buf = kzalloc(sizeof( char[IPA2_ACTIVE_CLIENTS_TABLE_BUF_SIZE]), GFP_KERNEL); if (ipa_ctx->ipa2_active_clients_logging.log_buffer == NULL) { IPAERR("Active Clients Logging memory allocation failed"); goto bail; Loading @@ -307,6 +404,9 @@ static int ipa2_active_clients_log_init(void) ipa_ctx->ipa2_active_clients_logging.log_head = 0; ipa_ctx->ipa2_active_clients_logging.log_tail = IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1; hash_init(ipa_ctx->ipa2_active_clients_logging.htable); atomic_notifier_chain_register(&panic_notifier_list, &ipa2_active_clients_panic_blk); ipa_ctx->ipa2_active_clients_logging.log_rdy = 1; return 0; Loading @@ -333,22 +433,6 @@ static void ipa2_active_clients_log_destroy(void) IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES - 1; } void ipa2_active_clients_log_print_buffer(void) { int i; ipa_active_clients_lock(); for (i = (ipa_ctx->ipa2_active_clients_logging.log_tail + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES; i != ipa_ctx->ipa2_active_clients_logging.log_head; i = (i + 1) % IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) { pr_err("%s\n", ipa_ctx->ipa2_active_clients_logging .log_buffer[i]); } ipa_active_clients_unlock(); } enum ipa_smmu_cb_type { IPA_SMMU_CB_AP, IPA_SMMU_CB_WLAN, Loading Loading @@ -2922,37 +3006,116 @@ static void ipa_start_tag_process(struct work_struct *work) if (res) IPAERR("ipa_tag_aggr_force_close failed %d\n", res); IPA2_ACTIVE_CLIENTS_DEC_SIMPLE(); IPA2_ACTIVE_CLIENTS_DEC_SPECIAL("TAG_PROCESS"); IPADBG("TAG process done\n"); } /** * ipa_inc_client_enable_clks() - Increase active clients counter, and * enable ipa clocks if necessary * ipa2_active_clients_log_mod() - Log a modification in the active clients * reference count * * Please do not use this API, use the wrapper macros instead (ipa_i.h) * IPA2_ACTIVE_CLIENTS_INC_XXXX(); * This method logs any modification in the active clients reference count: * It logs the modification in the circular history buffer * It logs the modification in the hash table - looking for an entry, * creating one if needed and deleting one if needed. * * Return codes: * None * @id: ipa2_active client logging info struct to hold the log information * @inc: a boolean variable to indicate whether the modification is an increase * or decrease * @int_ctx: a boolean variable to indicate whether this call is being made from * an interrupt context and therefore should allocate GFP_ATOMIC memory * * Method process: * - Hash the unique identifier string * - Find the hash in the table * 1)If found, increase or decrease the reference count * 2)If not found, allocate a new hash table entry struct and initialize it * - Remove and deallocate unneeded data structure * - Log the call in the circular history buffer (unless it is a simple call) */ void ipa2_inc_client_enable_clks(struct ipa2_active_client_logging_info *id) void ipa2_active_clients_log_mod(struct ipa2_active_client_logging_info *id, bool inc, bool int_ctx) { char temp_str[IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN]; unsigned long long t; unsigned long nanosec_rem; struct ipa2_active_client_htable_entry *hentry; struct ipa2_active_client_htable_entry *hfound; u32 hkey; char str_to_hash[IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN]; hfound = NULL; memset(str_to_hash, 0, IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN); strlcpy(str_to_hash, id->id_string, IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN); hkey = arch_fast_hash(str_to_hash, IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN, 0); hash_for_each_possible(ipa_ctx->ipa2_active_clients_logging.htable, hentry, list, hkey) { if (!strcmp(hentry->id_string, id->id_string)) { hentry->count = hentry->count + (inc ? 1 : -1); hfound = hentry; } } if (hfound == NULL) { hentry = NULL; hentry = kzalloc(sizeof( struct ipa2_active_client_htable_entry), int_ctx ? GFP_ATOMIC : GFP_KERNEL); if (hentry == NULL) { IPAERR("failed allocating active clients hash entry"); return; } hentry->type = id->type; strlcpy(hentry->id_string, id->id_string, IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN); INIT_HLIST_NODE(&hentry->list); hentry->count = inc ? 1 : -1; hash_add(ipa_ctx->ipa2_active_clients_logging.htable, &hentry->list, hkey); } else if (hfound->count == 0) { hash_del(&hfound->list); kfree(hfound); } ipa_active_clients_lock(); if (id->type != SIMPLE) { t = local_clock(); nanosec_rem = do_div(t, 1000000000) / 1000; snprintf(temp_str, IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN, "[%5lu.%06lu] ^ %s, %s: %d", inc ? "[%5lu.%06lu] ^ %s, %s: %d" : "[%5lu.%06lu] v %s, %s: %d", (unsigned long)t, nanosec_rem, id->id_string, id->file, id->line); ipa2_active_clients_log_insert(temp_str); } } void ipa2_active_clients_log_dec(struct ipa2_active_client_logging_info *id, bool int_ctx) { ipa2_active_clients_log_mod(id, false, int_ctx); } void ipa2_active_clients_log_inc(struct ipa2_active_client_logging_info *id, bool int_ctx) { ipa2_active_clients_log_mod(id, true, int_ctx); } /** * ipa_inc_client_enable_clks() - Increase active clients counter, and * enable ipa clocks if necessary * * Please do not use this API, use the wrapper macros instead (ipa_i.h) * IPA2_ACTIVE_CLIENTS_INC_XXXX(); * * Return codes: * None */ void ipa2_inc_client_enable_clks(struct ipa2_active_client_logging_info *id) { ipa_active_clients_lock(); ipa2_active_clients_log_inc(id, false); ipa_ctx->ipa_active_clients.cnt++; if (ipa_ctx->ipa_active_clients.cnt == 1) ipa_enable_clks(); Loading @@ -2976,9 +3139,6 @@ int ipa2_inc_client_enable_clks_no_block(struct ipa2_active_client_logging_info { int res = 0; unsigned long flags; char temp_str[IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN]; unsigned long long t; unsigned long nanosec_rem; if (ipa_active_clients_trylock(&flags) == 0) return -EPERM; Loading @@ -2988,15 +3148,7 @@ int ipa2_inc_client_enable_clks_no_block(struct ipa2_active_client_logging_info goto bail; } if (id->type != SIMPLE) { t = local_clock(); nanosec_rem = do_div(t, 1000000000) / 1000; snprintf(temp_str, IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN, "[%5lu.%06lu] ^ %s, %s: %d", (unsigned long)t, nanosec_rem, id->id_string, id->file, id->line); ipa2_active_clients_log_insert(temp_str); } ipa2_active_clients_log_inc(id, true); ipa_ctx->ipa_active_clients.cnt++; IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients.cnt); Loading @@ -3022,24 +3174,17 @@ bail: */ void ipa2_dec_client_disable_clks(struct ipa2_active_client_logging_info *id) { char temp_str[IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN]; unsigned long long t; unsigned long nanosec_rem; struct ipa2_active_client_logging_info log_info; ipa_active_clients_lock(); if (id->type != SIMPLE) { t = local_clock(); nanosec_rem = do_div(t, 1000000000) / 1000; snprintf(temp_str, IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN, "[%5lu.%06lu] v %s, %s: %d", (unsigned long)t, nanosec_rem, id->id_string, id->file, id->line); ipa2_active_clients_log_insert(temp_str); } ipa2_active_clients_log_dec(id, false); ipa_ctx->ipa_active_clients.cnt--; IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients.cnt); if (ipa_ctx->ipa_active_clients.cnt == 0) { if (ipa_ctx->tag_process_before_gating) { IPA2_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "TAG_PROCESS"); ipa2_active_clients_log_inc(&log_info, false); ipa_ctx->tag_process_before_gating = false; /* * When TAG process ends, active clients will be Loading Loading @@ -3464,6 +3609,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, struct sps_bam_props bam_props = { 0 }; struct ipa_flt_tbl *flt_tbl; struct ipa_rt_tbl_set *rset; struct ipa2_active_client_logging_info log_info; IPADBG("IPA Driver initialization started\n"); Loading Loading @@ -3587,6 +3733,8 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, mutex_init(&ipa_ctx->ipa_active_clients.mutex); spin_lock_init(&ipa_ctx->ipa_active_clients.spinlock); IPA2_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE"); ipa2_active_clients_log_inc(&log_info, false); ipa_ctx->ipa_active_clients.cnt = 1; /* Create workqueues for power management */ Loading
drivers/platform/msm/ipa/ipa_v2/ipa_client.c +4 −4 Original line number Diff line number Diff line Loading @@ -539,6 +539,7 @@ int ipa2_disconnect(u32 clnt_hdl) struct iommu_domain *smmu_domain; struct ipa_disable_force_clear_datapath_req_msg_v01 req = {0}; int res; enum ipa_client_type client_type; if (unlikely(!ipa_ctx)) { IPAERR("IPA driver was not initialized\n"); Loading @@ -552,10 +553,9 @@ int ipa2_disconnect(u32 clnt_hdl) } ep = &ipa_ctx->ep[clnt_hdl]; client_type = ipa2_get_client_mapping(clnt_hdl); if (!ep->keep_ipa_awake) IPA2_ACTIVE_CLIENTS_INC_EP(ipa2_get_client_mapping(clnt_hdl)); IPA2_ACTIVE_CLIENTS_INC_EP(client_type); /* Set Disconnect in Progress flag. */ spin_lock(&ipa_ctx->disconnect_lock); Loading Loading @@ -662,7 +662,7 @@ int ipa2_disconnect(u32 clnt_hdl) memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context)); spin_unlock(&ipa_ctx->disconnect_lock); IPA2_ACTIVE_CLIENTS_DEC_EP(ipa2_get_client_mapping(clnt_hdl)); IPA2_ACTIVE_CLIENTS_DEC_EP(client_type); IPADBG("client (ep: %d) disconnected\n", clnt_hdl); Loading
drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +33 −5 Original line number Diff line number Diff line Loading @@ -21,6 +21,9 @@ #define IPA_MAX_MSG_LEN 4096 #define IPA_DBG_CNTR_ON 127265 #define IPA_DBG_CNTR_OFF 127264 #define IPA_DBG_ACTIVE_CLIENTS_BUF_SIZE ((IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN \ * IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) \ + IPA_MAX_MSG_LEN) #define IPA_DUMP_STATUS_FIELD(f) \ pr_err(#f "=0x%x\n", status->f) Loading Loading @@ -108,6 +111,7 @@ static struct dentry *dfile_rm_stats; static struct dentry *dfile_status_stats; static struct dentry *dfile_active_clients; static char dbg_buff[IPA_MAX_MSG_LEN]; static char *active_clients_buf; static s8 ep_reg_idx; int _ipa_read_gen_reg_v1_1(char *buff, int max_len) Loading Loading @@ -1552,10 +1556,24 @@ static ssize_t ipa_status_stats_read(struct file *file, char __user *ubuf, static ssize_t ipa2_print_active_clients_log(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { ipa2_active_clients_log_print_buffer(); 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_CLIENTS_BUF_SIZE); ipa_active_clients_lock(); cnt = ipa2_active_clients_log_print_buffer(active_clients_buf, IPA_DBG_ACTIVE_CLIENTS_BUF_SIZE - IPA_MAX_MSG_LEN); table_size = ipa2_active_clients_log_print_table(active_clients_buf + cnt, IPA_MAX_MSG_LEN); ipa_active_clients_unlock(); return simple_read_from_buffer(ubuf, count, ppos, active_clients_buf, cnt + table_size); } static ssize_t ipa2_clear_active_clients_log(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) Loading Loading @@ -1682,13 +1700,19 @@ void ipa_debugfs_init(void) goto fail; } dfile_ep_reg = debugfs_create_file("active_clients", dfile_active_clients = debugfs_create_file("active_clients", read_write_mode, dent, 0, &ipa2_active_clients); if (!dfile_ep_reg || IS_ERR(dfile_active_clients)) { IPAERR("fail to create file for debug_fs ep_reg\n"); if (!dfile_active_clients || IS_ERR(dfile_active_clients)) { IPAERR("fail to create file for debug_fs active_clients\n"); goto fail; } active_clients_buf = NULL; active_clients_buf = kzalloc(IPA_DBG_ACTIVE_CLIENTS_BUF_SIZE, GFP_KERNEL); if (active_clients_buf == NULL) IPAERR("fail to allocate active clients memory buffer"); dfile_ep_reg = debugfs_create_file("ep_reg", read_write_mode, dent, 0, &ipa_ep_reg_ops); if (!dfile_ep_reg || IS_ERR(dfile_ep_reg)) { Loading Loading @@ -1843,6 +1867,10 @@ void ipa_debugfs_remove(void) IPAERR("ipa_debugfs_remove: folder was not created.\n"); return; } if (active_clients_buf != NULL) { kfree(active_clients_buf); active_clients_buf = NULL; } debugfs_remove_recursive(dent); } Loading
drivers/platform/msm/ipa/ipa_v2/ipa_i.h +17 −2 Original line number Diff line number Diff line Loading @@ -235,7 +235,9 @@ } while (0) #define IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES 120 #define IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN 100 #define IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN 96 #define IPA2_ACTIVE_CLIENTS_LOG_HASHTABLE_SIZE 50 #define IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN 40 extern const char *ipa2_clients_strings[]; Loading @@ -254,11 +256,19 @@ struct ipa2_active_client_logging_info { enum ipa2_active_client_log_type type; }; struct ipa2_active_client_htable_entry { struct hlist_node list; char id_string[IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN]; int count; enum ipa2_active_client_log_type type; }; struct ipa2_active_clients_log_ctx { char *log_buffer[IPA2_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES]; int log_head; int log_tail; bool log_rdy; struct hlist_head htable[IPA2_ACTIVE_CLIENTS_LOG_HASHTABLE_SIZE]; }; Loading Loading @@ -1945,7 +1955,12 @@ void ipa2_inc_client_enable_clks(struct ipa2_active_client_logging_info *id); int ipa2_inc_client_enable_clks_no_block(struct ipa2_active_client_logging_info *id); void ipa2_dec_client_disable_clks(struct ipa2_active_client_logging_info *id); void ipa2_active_clients_log_print_buffer(void); void ipa2_active_clients_log_dec(struct ipa2_active_client_logging_info *id, bool int_ctx); void ipa2_active_clients_log_inc(struct ipa2_active_client_logging_info *id, bool int_ctx); int ipa2_active_clients_log_print_buffer(char *buf, int size); int ipa2_active_clients_log_print_table(char *buf, int size); void ipa2_active_clients_log_clear(void); int ipa_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev); int __ipa_del_rt_rule(u32 rule_hdl); Loading
drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +4 −0 Original line number Diff line number Diff line Loading @@ -569,6 +569,7 @@ int ipa_suspend_resource_no_block(enum ipa_rm_resource_name resource) struct ipa_ep_cfg_ctrl suspend; int ipa_ep_idx; unsigned long flags; struct ipa2_active_client_logging_info log_info; if (ipa_active_clients_trylock(&flags) == 0) return -EPERM; Loading Loading @@ -606,6 +607,9 @@ int ipa_suspend_resource_no_block(enum ipa_rm_resource_name resource) } if (res == 0) { IPA2_ACTIVE_CLIENTS_PREP_RESOURCE(log_info, ipa_rm_resource_str(resource)); ipa2_active_clients_log_dec(&log_info, true); ipa_ctx->ipa_active_clients.cnt--; IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients.cnt); Loading