1/*
2 *  Copyright IBM Corp. 2008, 2009
3 *
4 *  Author: Jan Glauber (jang@linux.vnet.ibm.com)
5 */
6#include <linux/seq_file.h>
7#include <linux/debugfs.h>
8#include <linux/uaccess.h>
9#include <linux/export.h>
10#include <linux/slab.h>
11#include <asm/debug.h>
12#include "qdio_debug.h"
13#include "qdio.h"
14
15debug_info_t *qdio_dbf_setup;
16debug_info_t *qdio_dbf_error;
17
18static struct dentry *debugfs_root;
19#define QDIO_DEBUGFS_NAME_LEN	10
20#define QDIO_DBF_NAME_LEN	20
21
22struct qdio_dbf_entry {
23	char dbf_name[QDIO_DBF_NAME_LEN];
24	debug_info_t *dbf_info;
25	struct list_head dbf_list;
26};
27
28static LIST_HEAD(qdio_dbf_list);
29static DEFINE_MUTEX(qdio_dbf_list_mutex);
30
31static debug_info_t *qdio_get_dbf_entry(char *name)
32{
33	struct qdio_dbf_entry *entry;
34	debug_info_t *rc = NULL;
35
36	mutex_lock(&qdio_dbf_list_mutex);
37	list_for_each_entry(entry, &qdio_dbf_list, dbf_list) {
38		if (strcmp(entry->dbf_name, name) == 0) {
39			rc = entry->dbf_info;
40			break;
41		}
42	}
43	mutex_unlock(&qdio_dbf_list_mutex);
44	return rc;
45}
46
47static void qdio_clear_dbf_list(void)
48{
49	struct qdio_dbf_entry *entry, *tmp;
50
51	mutex_lock(&qdio_dbf_list_mutex);
52	list_for_each_entry_safe(entry, tmp, &qdio_dbf_list, dbf_list) {
53		list_del(&entry->dbf_list);
54		debug_unregister(entry->dbf_info);
55		kfree(entry);
56	}
57	mutex_unlock(&qdio_dbf_list_mutex);
58}
59
60int qdio_allocate_dbf(struct qdio_initialize *init_data,
61		       struct qdio_irq *irq_ptr)
62{
63	char text[QDIO_DBF_NAME_LEN];
64	struct qdio_dbf_entry *new_entry;
65
66	DBF_EVENT("qfmt:%1d", init_data->q_format);
67	DBF_HEX(init_data->adapter_name, 8);
68	DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
69	DBF_HEX(&init_data->qib_param_field, sizeof(void *));
70	DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
71	DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
72	DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
73		  init_data->no_output_qs);
74	DBF_HEX(&init_data->input_handler, sizeof(void *));
75	DBF_HEX(&init_data->output_handler, sizeof(void *));
76	DBF_HEX(&init_data->int_parm, sizeof(long));
77	DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
78	DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
79	DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
80
81	/* allocate trace view for the interface */
82	snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s",
83					dev_name(&init_data->cdev->dev));
84	irq_ptr->debug_area = qdio_get_dbf_entry(text);
85	if (irq_ptr->debug_area)
86		DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused");
87	else {
88		irq_ptr->debug_area = debug_register(text, 2, 1, 16);
89		if (!irq_ptr->debug_area)
90			return -ENOMEM;
91		if (debug_register_view(irq_ptr->debug_area,
92						&debug_hex_ascii_view)) {
93			debug_unregister(irq_ptr->debug_area);
94			return -ENOMEM;
95		}
96		debug_set_level(irq_ptr->debug_area, DBF_WARN);
97		DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
98		new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL);
99		if (!new_entry) {
100			debug_unregister(irq_ptr->debug_area);
101			return -ENOMEM;
102		}
103		strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN);
104		new_entry->dbf_info = irq_ptr->debug_area;
105		mutex_lock(&qdio_dbf_list_mutex);
106		list_add(&new_entry->dbf_list, &qdio_dbf_list);
107		mutex_unlock(&qdio_dbf_list_mutex);
108	}
109	return 0;
110}
111
112static int qstat_show(struct seq_file *m, void *v)
113{
114	unsigned char state;
115	struct qdio_q *q = m->private;
116	int i;
117
118	if (!q)
119		return 0;
120
121	seq_printf(m, "Timestamp: %Lx  Last AI: %Lx\n",
122		   q->timestamp, last_ai_time);
123	seq_printf(m, "nr_used: %d  ftc: %d  last_move: %d\n",
124		   atomic_read(&q->nr_buf_used),
125		   q->first_to_check, q->last_move);
126	if (q->is_input_q) {
127		seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
128			   q->u.in.polling, q->u.in.ack_start,
129			   q->u.in.ack_count);
130		seq_printf(m, "DSCI: %d   IRQs disabled: %u\n",
131			   *(u32 *)q->irq_ptr->dsci,
132			   test_bit(QDIO_QUEUE_IRQS_DISABLED,
133			   &q->u.in.queue_irq_state));
134	}
135	seq_printf(m, "SBAL states:\n");
136	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
137
138	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
139		debug_get_buf_state(q, i, &state);
140		switch (state) {
141		case SLSB_P_INPUT_NOT_INIT:
142		case SLSB_P_OUTPUT_NOT_INIT:
143			seq_printf(m, "N");
144			break;
145		case SLSB_P_OUTPUT_PENDING:
146			seq_printf(m, "P");
147			break;
148		case SLSB_P_INPUT_PRIMED:
149		case SLSB_CU_OUTPUT_PRIMED:
150			seq_printf(m, "+");
151			break;
152		case SLSB_P_INPUT_ACK:
153			seq_printf(m, "A");
154			break;
155		case SLSB_P_INPUT_ERROR:
156		case SLSB_P_OUTPUT_ERROR:
157			seq_printf(m, "x");
158			break;
159		case SLSB_CU_INPUT_EMPTY:
160		case SLSB_P_OUTPUT_EMPTY:
161			seq_printf(m, "-");
162			break;
163		case SLSB_P_INPUT_HALTED:
164		case SLSB_P_OUTPUT_HALTED:
165			seq_printf(m, ".");
166			break;
167		default:
168			seq_printf(m, "?");
169		}
170		if (i == 63)
171			seq_printf(m, "\n");
172	}
173	seq_printf(m, "\n");
174	seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
175
176	seq_printf(m, "\nSBAL statistics:");
177	if (!q->irq_ptr->perf_stat_enabled) {
178		seq_printf(m, " disabled\n");
179		return 0;
180	}
181
182	seq_printf(m, "\n1          2..        4..        8..        "
183		   "16..       32..       64..       127\n");
184	for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
185		seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
186	seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
187		   q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
188		   q->q_stats.nr_sbal_total);
189	return 0;
190}
191
192static int qstat_seq_open(struct inode *inode, struct file *filp)
193{
194	return single_open(filp, qstat_show,
195			   file_inode(filp)->i_private);
196}
197
198static const struct file_operations debugfs_fops = {
199	.owner	 = THIS_MODULE,
200	.open	 = qstat_seq_open,
201	.read	 = seq_read,
202	.llseek  = seq_lseek,
203	.release = single_release,
204};
205
206static char *qperf_names[] = {
207	"Assumed adapter interrupts",
208	"QDIO interrupts",
209	"Requested PCIs",
210	"Inbound tasklet runs",
211	"Inbound tasklet resched",
212	"Inbound tasklet resched2",
213	"Outbound tasklet runs",
214	"SIGA read",
215	"SIGA write",
216	"SIGA sync",
217	"Inbound calls",
218	"Inbound handler",
219	"Inbound stop_polling",
220	"Inbound queue full",
221	"Outbound calls",
222	"Outbound handler",
223	"Outbound queue full",
224	"Outbound fast_requeue",
225	"Outbound target_full",
226	"QEBSM eqbs",
227	"QEBSM eqbs partial",
228	"QEBSM sqbs",
229	"QEBSM sqbs partial",
230	"Discarded interrupts"
231};
232
233static int qperf_show(struct seq_file *m, void *v)
234{
235	struct qdio_irq *irq_ptr = m->private;
236	unsigned int *stat;
237	int i;
238
239	if (!irq_ptr)
240		return 0;
241	if (!irq_ptr->perf_stat_enabled) {
242		seq_printf(m, "disabled\n");
243		return 0;
244	}
245	stat = (unsigned int *)&irq_ptr->perf_stat;
246
247	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
248		seq_printf(m, "%26s:\t%u\n",
249			   qperf_names[i], *(stat + i));
250	return 0;
251}
252
253static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
254			       size_t count, loff_t *off)
255{
256	struct seq_file *seq = file->private_data;
257	struct qdio_irq *irq_ptr = seq->private;
258	struct qdio_q *q;
259	unsigned long val;
260	int ret, i;
261
262	if (!irq_ptr)
263		return 0;
264
265	ret = kstrtoul_from_user(ubuf, count, 10, &val);
266	if (ret)
267		return ret;
268
269	switch (val) {
270	case 0:
271		irq_ptr->perf_stat_enabled = 0;
272		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
273		for_each_input_queue(irq_ptr, q, i)
274			memset(&q->q_stats, 0, sizeof(q->q_stats));
275		for_each_output_queue(irq_ptr, q, i)
276			memset(&q->q_stats, 0, sizeof(q->q_stats));
277		break;
278	case 1:
279		irq_ptr->perf_stat_enabled = 1;
280		break;
281	}
282	return count;
283}
284
285static int qperf_seq_open(struct inode *inode, struct file *filp)
286{
287	return single_open(filp, qperf_show,
288			   file_inode(filp)->i_private);
289}
290
291static const struct file_operations debugfs_perf_fops = {
292	.owner	 = THIS_MODULE,
293	.open	 = qperf_seq_open,
294	.read	 = seq_read,
295	.write	 = qperf_seq_write,
296	.llseek  = seq_lseek,
297	.release = single_release,
298};
299
300static void setup_debugfs_entry(struct qdio_q *q)
301{
302	char name[QDIO_DEBUGFS_NAME_LEN];
303
304	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
305		 q->is_input_q ? "input" : "output",
306		 q->nr);
307	q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
308				q->irq_ptr->debugfs_dev, q, &debugfs_fops);
309	if (IS_ERR(q->debugfs_q))
310		q->debugfs_q = NULL;
311}
312
313void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
314{
315	struct qdio_q *q;
316	int i;
317
318	irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
319						  debugfs_root);
320	if (IS_ERR(irq_ptr->debugfs_dev))
321		irq_ptr->debugfs_dev = NULL;
322
323	irq_ptr->debugfs_perf = debugfs_create_file("statistics",
324				S_IFREG | S_IRUGO | S_IWUSR,
325				irq_ptr->debugfs_dev, irq_ptr,
326				&debugfs_perf_fops);
327	if (IS_ERR(irq_ptr->debugfs_perf))
328		irq_ptr->debugfs_perf = NULL;
329
330	for_each_input_queue(irq_ptr, q, i)
331		setup_debugfs_entry(q);
332	for_each_output_queue(irq_ptr, q, i)
333		setup_debugfs_entry(q);
334}
335
336void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
337{
338	struct qdio_q *q;
339	int i;
340
341	for_each_input_queue(irq_ptr, q, i)
342		debugfs_remove(q->debugfs_q);
343	for_each_output_queue(irq_ptr, q, i)
344		debugfs_remove(q->debugfs_q);
345	debugfs_remove(irq_ptr->debugfs_perf);
346	debugfs_remove(irq_ptr->debugfs_dev);
347}
348
349int __init qdio_debug_init(void)
350{
351	debugfs_root = debugfs_create_dir("qdio", NULL);
352
353	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
354	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
355	debug_set_level(qdio_dbf_setup, DBF_INFO);
356	DBF_EVENT("dbf created\n");
357
358	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
359	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
360	debug_set_level(qdio_dbf_error, DBF_INFO);
361	DBF_ERROR("dbf created\n");
362	return 0;
363}
364
365void qdio_debug_exit(void)
366{
367	qdio_clear_dbf_list();
368	debugfs_remove(debugfs_root);
369	if (qdio_dbf_setup)
370		debug_unregister(qdio_dbf_setup);
371	if (qdio_dbf_error)
372		debug_unregister(qdio_dbf_error);
373}
374