blob: a493cbeac254dbd9438ea4be1ef9d72c82f008d1 [file] [log] [blame]
Eric Holmberg6275b602012-11-19 13:05:04 -07001/* arch/arm/mach-msm/smp2p_debug.c
2 *
3 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include <linux/ctype.h>
15#include <linux/list.h>
16#include <linux/debugfs.h>
17#include "smp2p_private.h"
18
19#if defined(CONFIG_DEBUG_FS)
20
21/**
22 * Dump interrupt statistics.
23 *
24 * @s: pointer to output file
25 */
26static void smp2p_int_stats(struct seq_file *s)
27{
28 struct smp2p_interrupt_config *int_cfg;
29 int pid;
30
31 int_cfg = smp2p_get_interrupt_config();
32 if (!int_cfg)
33 return;
34
35 seq_printf(s, "| Processor | Incoming Id | Incoming # |");
36 seq_printf(s, " Outgoing # | Base Ptr | Mask |\n");
37
38 for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid) {
39 if (!int_cfg[pid].is_configured &&
40 pid != SMP2P_REMOTE_MOCK_PROC)
41 continue;
42
43 seq_printf(s,
44 "| %5s (%d) | %11u | %10u | %10u | %p | %08x |\n",
45 int_cfg[pid].name,
46 pid, int_cfg[pid].in_int_id,
47 int_cfg[pid].in_interrupt_count,
48 int_cfg[pid].out_interrupt_count,
49 int_cfg[pid].out_int_ptr,
50 int_cfg[pid].out_int_mask);
51 }
52}
53
54/**
55 * Dump item header line 1.
56 *
57 * @buf: output buffer
58 * @max: length of output buffer
59 * @item_ptr: SMEM item pointer
60 * @state: item state
61 * @returns: Number of bytes written to output buffer
62 */
63static int smp2p_item_header1(char *buf, int max, struct smp2p_smem *item_ptr,
64 enum msm_smp2p_edge_state state)
65{
66 int i = 0;
67 const char *state_text;
68
69 if (!item_ptr) {
70 i += scnprintf(buf + i, max - i, "None");
71 return i;
72 }
73
74 switch (state) {
75 case SMP2P_EDGE_STATE_CLOSED:
76 state_text = "State: Closed";
77 break;
78 case SMP2P_EDGE_STATE_OPENING:
79 state_text = "State: Opening";
80 break;
81 case SMP2P_EDGE_STATE_OPENED:
82 state_text = "State: Opened";
83 break;
84 default:
85 state_text = "";
86 break;
87 }
88
89 i += scnprintf(buf + i, max - i,
90 "%-14s LPID %d RPID %d",
91 state_text,
92 SMP2P_GET_LOCAL_PID(item_ptr->rem_loc_proc_id),
93 SMP2P_GET_REMOTE_PID(item_ptr->rem_loc_proc_id)
94 );
95
96 return i;
97}
98
99/**
100 * Dump item header line 2.
101 *
102 * @buf: output buffer
103 * @max: length of output buffer
104 * @item_ptr: SMEM item pointer
105 * @returns: Number of bytes written to output buffer
106 */
107static int smp2p_item_header2(char *buf, int max, struct smp2p_smem *item_ptr)
108{
109 int i = 0;
110
111 if (!item_ptr) {
112 i += scnprintf(buf + i, max - i, "None");
113 return i;
114 }
115
116 i += scnprintf(buf + i, max - i,
117 "Version: %08x Features: %08x",
118 SMP2P_GET_VERSION(item_ptr->feature_version),
119 SMP2P_GET_FEATURES(item_ptr->feature_version)
120 );
121
122 return i;
123}
124
125/**
126 * Dump item header line 3.
127 *
128 * @buf: output buffer
129 * @max: length of output buffer
130 * @item_ptr: SMEM item pointer
131 * @state: item state
132 * @returns: Number of bytes written to output buffer
133 */
134static int smp2p_item_header3(char *buf, int max, struct smp2p_smem *item_ptr)
135{
136 int i = 0;
137
138 if (!item_ptr) {
139 i += scnprintf(buf + i, max - i, "None");
140 return i;
141 }
142
143 i += scnprintf(buf + i, max - i,
144 "Entries Valid/Max: %d/%d",
145 SMP2P_GET_ENT_VALID(item_ptr->valid_total_ent),
146 SMP2P_GET_ENT_TOTAL(item_ptr->valid_total_ent)
147 );
148
149 return i;
150}
151
152/**
153 * Dump individual input/output item pair.
154 *
155 * @s: pointer to output file
156 */
157static void smp2p_item(struct seq_file *s, int remote_pid)
158{
159 struct smp2p_smem *out_ptr;
160 struct smp2p_smem *in_ptr;
161 struct smp2p_interrupt_config *int_cfg;
162 char tmp_buff[64];
163 int state;
164 int entry;
165 struct smp2p_entry_v1 *out_entries = NULL;
166 struct smp2p_entry_v1 *in_entries = NULL;
167 int out_valid = 0;
168 int in_valid = 0;
169
170 int_cfg = smp2p_get_interrupt_config();
171 if (!int_cfg)
172 return;
173 if (!int_cfg[remote_pid].is_configured &&
174 remote_pid != SMP2P_REMOTE_MOCK_PROC)
175 return;
176
177 out_ptr = smp2p_get_out_item(remote_pid, &state);
178 in_ptr = smp2p_get_in_item(remote_pid);
179
180 if (!out_ptr && !in_ptr)
181 return;
182
183 /* print item headers */
184 seq_printf(s, "%s%s\n",
185 " ====================================== ",
186 "======================================");
187 scnprintf(tmp_buff, sizeof(tmp_buff),
188 "Apps(%d)->%s(%d)",
189 SMP2P_APPS_PROC, int_cfg[remote_pid].name, remote_pid);
190 seq_printf(s, "| %-37s", tmp_buff);
191
192 scnprintf(tmp_buff, sizeof(tmp_buff),
193 "%s(%d)->Apps(%d)",
194 int_cfg[remote_pid].name, remote_pid, SMP2P_APPS_PROC);
195 seq_printf(s, "| %-37s|\n", tmp_buff);
196 seq_printf(s, "%s%s\n",
197 " ====================================== ",
198 "======================================");
199
200 smp2p_item_header1(tmp_buff, sizeof(tmp_buff), out_ptr, state);
201 seq_printf(s, "| %-37s", tmp_buff);
202 smp2p_item_header1(tmp_buff, sizeof(tmp_buff), in_ptr, -1);
203 seq_printf(s, "| %-37s|\n", tmp_buff);
204
205 smp2p_item_header2(tmp_buff, sizeof(tmp_buff), out_ptr);
206 seq_printf(s, "| %-37s", tmp_buff);
207 smp2p_item_header2(tmp_buff, sizeof(tmp_buff), in_ptr);
208 seq_printf(s, "| %-37s|\n", tmp_buff);
209
210 smp2p_item_header3(tmp_buff, sizeof(tmp_buff), out_ptr);
211 seq_printf(s, "| %-37s", tmp_buff);
212 smp2p_item_header3(tmp_buff, sizeof(tmp_buff), in_ptr);
213 seq_printf(s, "| %-37s|\n", tmp_buff);
214
215 seq_printf(s, " %s%s\n",
216 "-------------------------------------- ",
217 "--------------------------------------");
218 seq_printf(s, "| %-37s",
219 "Entry Name Value");
220 seq_printf(s, "| %-37s|\n",
221 "Entry Name Value");
222 seq_printf(s, " %s%s\n",
223 "-------------------------------------- ",
224 "--------------------------------------");
225
226 /* print entries */
227 if (out_ptr) {
228 out_entries = (struct smp2p_entry_v1 *)((void *)out_ptr +
229 sizeof(struct smp2p_smem));
230 out_valid = SMP2P_GET_ENT_VALID(out_ptr->valid_total_ent);
231 }
232
233 if (in_ptr) {
234 in_entries = (struct smp2p_entry_v1 *)((void *)in_ptr +
235 sizeof(struct smp2p_smem));
Eric Holmberg07c667a2013-02-28 17:53:50 -0700236 in_valid = SMP2P_GET_ENT_VALID(in_ptr->valid_total_ent);
Eric Holmberg6275b602012-11-19 13:05:04 -0700237 }
238
239 for (entry = 0; out_entries || in_entries; ++entry) {
240 if (out_entries && entry < out_valid) {
241 scnprintf(tmp_buff, sizeof(tmp_buff),
242 "%-16s 0x%08x",
243 out_entries->name,
244 out_entries->entry);
245 ++out_entries;
246 } else {
247 out_entries = NULL;
248 scnprintf(tmp_buff, sizeof(tmp_buff), "None");
249 }
250 seq_printf(s, "| %-37s", tmp_buff);
251
252 if (in_entries && entry < in_valid) {
253 scnprintf(tmp_buff, sizeof(tmp_buff),
254 "%-16s 0x%08x",
255 in_entries->name,
256 in_entries->entry);
257 ++in_entries;
258 } else {
259 in_entries = NULL;
260 scnprintf(tmp_buff, sizeof(tmp_buff), "None");
261 }
262 seq_printf(s, "| %-37s|\n", tmp_buff);
263 }
264 seq_printf(s, " %s%s\n\n",
265 "-------------------------------------- ",
266 "--------------------------------------");
267}
268
269/**
270 * Dump item state.
271 *
272 * @s: pointer to output file
273 */
274static void smp2p_items(struct seq_file *s)
275{
276 int pid;
277
278 for (pid = 0; pid < SMP2P_NUM_PROCS; ++pid)
279 smp2p_item(s, pid);
280}
281
282static struct dentry *dent;
283
284static int debugfs_show(struct seq_file *s, void *data)
285{
286 void (*show)(struct seq_file *) = s->private;
287
288 show(s);
289
290 return 0;
291}
292
293static int debug_open(struct inode *inode, struct file *file)
294{
295 return single_open(file, debugfs_show, inode->i_private);
296}
297
298static const struct file_operations debug_ops = {
299 .open = debug_open,
300 .release = single_release,
301 .read = seq_read,
302 .llseek = seq_lseek,
303};
304
305void debug_create(const char *name,
306 void (*show)(struct seq_file *))
307{
308 struct dentry *file;
309
310 file = debugfs_create_file(name, 0444, dent, show, &debug_ops);
311 if (!file)
312 pr_err("%s: unable to create file '%s'\n", __func__, name);
313}
314
315static int __init smp2p_debugfs_init(void)
316{
317 dent = debugfs_create_dir("smp2p", 0);
318 if (IS_ERR(dent))
319 return PTR_ERR(dent);
320
321 debug_create("int_stats", smp2p_int_stats);
322 debug_create("items", smp2p_items);
323
324 return 0;
325}
326
327late_initcall(smp2p_debugfs_init);
328#endif /* CONFIG_DEBUG_FS */