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