summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/smp2p_debug.c
diff options
context:
space:
mode:
authorKarthikeyan Ramasubramanian <kramasub@codeaurora.org>2016-01-22 16:27:03 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:02:10 -0700
commitd4516a3652da25020efa5aad5a9eee0cf96a74e4 (patch)
tree68035093d2747170de7617519a3b57cc9c0a9ac2 /drivers/soc/qcom/smp2p_debug.c
parent180a1bcbe0a7516286ceecba6adb8e548ac366bc (diff)
soc: qcom: Add snapshot of SMP2P Driver
This snapshot is taken as of msm-3.18 commit e70ad0cd (Promotion of kernel.lnx.3.18-151201.) Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
Diffstat (limited to 'drivers/soc/qcom/smp2p_debug.c')
-rw-r--r--drivers/soc/qcom/smp2p_debug.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/drivers/soc/qcom/smp2p_debug.c b/drivers/soc/qcom/smp2p_debug.c
new file mode 100644
index 000000000000..4deb05a08139
--- /dev/null
+++ b/drivers/soc/qcom/smp2p_debug.c
@@ -0,0 +1,335 @@
+/* drivers/soc/qcom/smp2p_debug.c
+ *
+ * Copyright (c) 2013-2014, 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.
+ */
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include "smp2p_private.h"
+
+#if defined(CONFIG_DEBUG_FS)
+
+/**
+ * Dump interrupt statistics.
+ *
+ * @s: pointer to output file
+ */
+static void smp2p_int_stats(struct seq_file *s)
+{
+ struct smp2p_interrupt_config *int_cfg;
+ int pid;
+
+ int_cfg = smp2p_get_interrupt_config();
+ if (!int_cfg)
+ return;
+
+ seq_puts(s, "| Processor | Incoming Id | Incoming # |");
+ seq_puts(s, " Outgoing # | Base Ptr | Mask |\n");
+
+ for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
+ if (!int_cfg[pid].is_configured &&
+ pid != SMP2P_REMOTE_MOCK_PROC)
+ continue;
+
+ seq_printf(s, "| %5s (%d) | %11u | %10u | %10u | %p | %08x |\n",
+ int_cfg[pid].name,
+ pid, int_cfg[pid].in_int_id,
+ int_cfg[pid].in_interrupt_count,
+ int_cfg[pid].out_interrupt_count,
+ int_cfg[pid].out_int_ptr,
+ int_cfg[pid].out_int_mask);
+ }
+}
+
+/**
+ * Dump item header line 1.
+ *
+ * @buf: output buffer
+ * @max: length of output buffer
+ * @item_ptr: SMEM item pointer
+ * @state: item state
+ * @returns: Number of bytes written to output buffer
+ */
+static int smp2p_item_header1(char *buf, int max, struct smp2p_smem *item_ptr,
+ enum msm_smp2p_edge_state state)
+{
+ int i = 0;
+ const char *state_text;
+
+ if (!item_ptr) {
+ i += scnprintf(buf + i, max - i, "None");
+ return i;
+ }
+
+ switch (state) {
+ case SMP2P_EDGE_STATE_CLOSED:
+ state_text = "State: Closed";
+ break;
+ case SMP2P_EDGE_STATE_OPENING:
+ state_text = "State: Opening";
+ break;
+ case SMP2P_EDGE_STATE_OPENED:
+ state_text = "State: Opened";
+ break;
+ default:
+ state_text = "";
+ break;
+ }
+
+ i += scnprintf(buf + i, max - i,
+ "%-14s LPID %d RPID %d",
+ state_text,
+ SMP2P_GET_LOCAL_PID(item_ptr->rem_loc_proc_id),
+ SMP2P_GET_REMOTE_PID(item_ptr->rem_loc_proc_id)
+ );
+
+ return i;
+}
+
+/**
+ * Dump item header line 2.
+ *
+ * @buf: output buffer
+ * @max: length of output buffer
+ * @item_ptr: SMEM item pointer
+ * @returns: Number of bytes written to output buffer
+ */
+static int smp2p_item_header2(char *buf, int max, struct smp2p_smem *item_ptr)
+{
+ int i = 0;
+
+ if (!item_ptr) {
+ i += scnprintf(buf + i, max - i, "None");
+ return i;
+ }
+
+ i += scnprintf(buf + i, max - i,
+ "Version: %08x Features: %08x",
+ SMP2P_GET_VERSION(item_ptr->feature_version),
+ SMP2P_GET_FEATURES(item_ptr->feature_version)
+ );
+
+ return i;
+}
+
+/**
+ * Dump item header line 3.
+ *
+ * @buf: output buffer
+ * @max: length of output buffer
+ * @item_ptr: SMEM item pointer
+ * @state: item state
+ * @returns: Number of bytes written to output buffer
+ */
+static int smp2p_item_header3(char *buf, int max, struct smp2p_smem *item_ptr)
+{
+ int i = 0;
+
+ if (!item_ptr) {
+ i += scnprintf(buf + i, max - i, "None");
+ return i;
+ }
+
+ i += scnprintf(buf + i, max - i,
+ "Entries #/Max: %d/%d Flags: %c%c",
+ SMP2P_GET_ENT_VALID(item_ptr->valid_total_ent),
+ SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent),
+ item_ptr->flags & SMP2P_FLAGS_RESTART_ACK_MASK ? 'A' : 'a',
+ item_ptr->flags & SMP2P_FLAGS_RESTART_DONE_MASK ? 'D' : 'd'
+ );
+
+ return i;
+}
+
+/**
+ * Dump individual input/output item pair.
+ *
+ * @s: pointer to output file
+ */
+static void smp2p_item(struct seq_file *s, int remote_pid)
+{
+ struct smp2p_smem *out_ptr;
+ struct smp2p_smem *in_ptr;
+ struct smp2p_interrupt_config *int_cfg;
+ char tmp_buff[64];
+ int state;
+ int entry;
+ struct smp2p_entry_v1 *out_entries = NULL;
+ struct smp2p_entry_v1 *in_entries = NULL;
+ int out_valid = 0;
+ int in_valid = 0;
+ char entry_name[SMP2P_MAX_ENTRY_NAME];
+
+ int_cfg = smp2p_get_interrupt_config();
+ if (!int_cfg)
+ return;
+ if (!int_cfg[remote_pid].is_configured &&
+ remote_pid != SMP2P_REMOTE_MOCK_PROC)
+ return;
+
+ out_ptr = smp2p_get_out_item(remote_pid, &state);
+ in_ptr = smp2p_get_in_item(remote_pid);
+
+ if (!out_ptr && !in_ptr)
+ return;
+
+ /* print item headers */
+ seq_printf(s, "%s%s\n",
+ " ====================================== ",
+ "======================================");
+ scnprintf(tmp_buff, sizeof(tmp_buff),
+ "Apps(%d)->%s(%d)",
+ SMP2P_APPS_PROC, int_cfg[remote_pid].name, remote_pid);
+ seq_printf(s, "| %-37s", tmp_buff);
+
+ scnprintf(tmp_buff, sizeof(tmp_buff),
+ "%s(%d)->Apps(%d)",
+ int_cfg[remote_pid].name, remote_pid, SMP2P_APPS_PROC);
+ seq_printf(s, "| %-37s|\n", tmp_buff);
+ seq_printf(s, "%s%s\n",
+ " ====================================== ",
+ "======================================");
+
+ smp2p_item_header1(tmp_buff, sizeof(tmp_buff), out_ptr, state);
+ seq_printf(s, "| %-37s", tmp_buff);
+ smp2p_item_header1(tmp_buff, sizeof(tmp_buff), in_ptr, -1);
+ seq_printf(s, "| %-37s|\n", tmp_buff);
+
+ smp2p_item_header2(tmp_buff, sizeof(tmp_buff), out_ptr);
+ seq_printf(s, "| %-37s", tmp_buff);
+ smp2p_item_header2(tmp_buff, sizeof(tmp_buff), in_ptr);
+ seq_printf(s, "| %-37s|\n", tmp_buff);
+
+ smp2p_item_header3(tmp_buff, sizeof(tmp_buff), out_ptr);
+ seq_printf(s, "| %-37s", tmp_buff);
+ smp2p_item_header3(tmp_buff, sizeof(tmp_buff), in_ptr);
+ seq_printf(s, "| %-37s|\n", tmp_buff);
+
+ seq_printf(s, " %s%s\n",
+ "-------------------------------------- ",
+ "--------------------------------------");
+ seq_printf(s, "| %-37s",
+ "Entry Name Value");
+ seq_printf(s, "| %-37s|\n",
+ "Entry Name Value");
+ seq_printf(s, " %s%s\n",
+ "-------------------------------------- ",
+ "--------------------------------------");
+
+ /* print entries */
+ if (out_ptr) {
+ out_entries = (struct smp2p_entry_v1 *)((void *)out_ptr +
+ sizeof(struct smp2p_smem));
+ out_valid = SMP2P_GET_ENT_VALID(out_ptr->valid_total_ent);
+ }
+
+ if (in_ptr) {
+ in_entries = (struct smp2p_entry_v1 *)((void *)in_ptr +
+ sizeof(struct smp2p_smem));
+ in_valid = SMP2P_GET_ENT_VALID(in_ptr->valid_total_ent);
+ }
+
+ for (entry = 0; out_entries || in_entries; ++entry) {
+ if (out_entries && entry < out_valid) {
+ memcpy_fromio(entry_name, out_entries->name,
+ SMP2P_MAX_ENTRY_NAME);
+ scnprintf(tmp_buff, sizeof(tmp_buff),
+ "%-16s 0x%08x",
+ entry_name,
+ out_entries->entry);
+ ++out_entries;
+ } else {
+ out_entries = NULL;
+ scnprintf(tmp_buff, sizeof(tmp_buff), "None");
+ }
+ seq_printf(s, "| %-37s", tmp_buff);
+
+ if (in_entries && entry < in_valid) {
+ memcpy_fromio(entry_name, in_entries->name,
+ SMP2P_MAX_ENTRY_NAME);
+ scnprintf(tmp_buff, sizeof(tmp_buff),
+ "%-16s 0x%08x",
+ entry_name,
+ in_entries->entry);
+ ++in_entries;
+ } else {
+ in_entries = NULL;
+ scnprintf(tmp_buff, sizeof(tmp_buff), "None");
+ }
+ seq_printf(s, "| %-37s|\n", tmp_buff);
+ }
+ seq_printf(s, " %s%s\n\n",
+ "-------------------------------------- ",
+ "--------------------------------------");
+}
+
+/**
+ * Dump item state.
+ *
+ * @s: pointer to output file
+ */
+static void smp2p_items(struct seq_file *s)
+{
+ int pid;
+
+ for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid)
+ smp2p_item(s, pid);
+}
+
+static struct dentry *dent;
+
+static int debugfs_show(struct seq_file *s, void *data)
+{
+ void (*show)(struct seq_file *) = s->private;
+
+ show(s);
+
+ return 0;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, debugfs_show, inode->i_private);
+}
+
+static const struct file_operations debug_ops = {
+ .open = debug_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek,
+};
+
+void debug_create(const char *name,
+ void (*show)(struct seq_file *))
+{
+ struct dentry *file;
+
+ file = debugfs_create_file(name, 0444, dent, show, &debug_ops);
+ if (!file)
+ pr_err("%s: unable to create file '%s'\n", __func__, name);
+}
+
+static int __init smp2p_debugfs_init(void)
+{
+ dent = debugfs_create_dir("smp2p", 0);
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ debug_create("int_stats", smp2p_int_stats);
+ debug_create("items", smp2p_items);
+
+ return 0;
+}
+
+late_initcall(smp2p_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */