PageRenderTime 35ms CodeModel.GetById 15ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/s390/cio/qdio_debug.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 302 lines | 260 code | 34 blank | 8 comment | 19 complexity | 7d434804dee4ffd317c4c70725355f28 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  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",
 60		   q->first_to_check, q->last_move);
 61	if (q->is_input_q) {
 62		seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
 63			   q->u.in.polling, q->u.in.ack_start,
 64			   q->u.in.ack_count);
 65		seq_printf(m, "IRQs disabled: %u\n",
 66			   test_bit(QDIO_QUEUE_IRQS_DISABLED,
 67			   &q->u.in.queue_irq_state));
 68	}
 69	seq_printf(m, "SBAL states:\n");
 70	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
 71
 72	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
 73		debug_get_buf_state(q, i, &state);
 74		switch (state) {
 75		case SLSB_P_INPUT_NOT_INIT:
 76		case SLSB_P_OUTPUT_NOT_INIT:
 77			seq_printf(m, "N");
 78			break;
 79		case SLSB_P_INPUT_PRIMED:
 80		case SLSB_CU_OUTPUT_PRIMED:
 81			seq_printf(m, "+");
 82			break;
 83		case SLSB_P_INPUT_ACK:
 84			seq_printf(m, "A");
 85			break;
 86		case SLSB_P_INPUT_ERROR:
 87		case SLSB_P_OUTPUT_ERROR:
 88			seq_printf(m, "x");
 89			break;
 90		case SLSB_CU_INPUT_EMPTY:
 91		case SLSB_P_OUTPUT_EMPTY:
 92			seq_printf(m, "-");
 93			break;
 94		case SLSB_P_INPUT_HALTED:
 95		case SLSB_P_OUTPUT_HALTED:
 96			seq_printf(m, ".");
 97			break;
 98		default:
 99			seq_printf(m, "?");
100		}
101		if (i == 63)
102			seq_printf(m, "\n");
103	}
104	seq_printf(m, "\n");
105	seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
106
107	seq_printf(m, "\nSBAL statistics:");
108	if (!q->irq_ptr->perf_stat_enabled) {
109		seq_printf(m, " disabled\n");
110		return 0;
111	}
112
113	seq_printf(m, "\n1          2..        4..        8..        "
114		   "16..       32..       64..       127\n");
115	for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
116		seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
117	seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
118		   q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
119		   q->q_stats.nr_sbal_total);
120	return 0;
121}
122
123static int qstat_seq_open(struct inode *inode, struct file *filp)
124{
125	return single_open(filp, qstat_show,
126			   filp->f_path.dentry->d_inode->i_private);
127}
128
129static const struct file_operations debugfs_fops = {
130	.owner	 = THIS_MODULE,
131	.open	 = qstat_seq_open,
132	.read	 = seq_read,
133	.llseek  = seq_lseek,
134	.release = single_release,
135};
136
137static char *qperf_names[] = {
138	"Assumed adapter interrupts",
139	"QDIO interrupts",
140	"Requested PCIs",
141	"Inbound tasklet runs",
142	"Inbound tasklet resched",
143	"Inbound tasklet resched2",
144	"Outbound tasklet runs",
145	"SIGA read",
146	"SIGA write",
147	"SIGA sync",
148	"Inbound calls",
149	"Inbound handler",
150	"Inbound stop_polling",
151	"Inbound queue full",
152	"Outbound calls",
153	"Outbound handler",
154	"Outbound queue full",
155	"Outbound fast_requeue",
156	"Outbound target_full",
157	"QEBSM eqbs",
158	"QEBSM eqbs partial",
159	"QEBSM sqbs",
160	"QEBSM sqbs partial",
161	"Discarded interrupts"
162};
163
164static int qperf_show(struct seq_file *m, void *v)
165{
166	struct qdio_irq *irq_ptr = m->private;
167	unsigned int *stat;
168	int i;
169
170	if (!irq_ptr)
171		return 0;
172	if (!irq_ptr->perf_stat_enabled) {
173		seq_printf(m, "disabled\n");
174		return 0;
175	}
176	stat = (unsigned int *)&irq_ptr->perf_stat;
177
178	for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
179		seq_printf(m, "%26s:\t%u\n",
180			   qperf_names[i], *(stat + i));
181	return 0;
182}
183
184static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
185			       size_t count, loff_t *off)
186{
187	struct seq_file *seq = file->private_data;
188	struct qdio_irq *irq_ptr = seq->private;
189	struct qdio_q *q;
190	unsigned long val;
191	int ret, i;
192
193	if (!irq_ptr)
194		return 0;
195
196	ret = kstrtoul_from_user(ubuf, count, 10, &val);
197	if (ret)
198		return ret;
199
200	switch (val) {
201	case 0:
202		irq_ptr->perf_stat_enabled = 0;
203		memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
204		for_each_input_queue(irq_ptr, q, i)
205			memset(&q->q_stats, 0, sizeof(q->q_stats));
206		for_each_output_queue(irq_ptr, q, i)
207			memset(&q->q_stats, 0, sizeof(q->q_stats));
208		break;
209	case 1:
210		irq_ptr->perf_stat_enabled = 1;
211		break;
212	}
213	return count;
214}
215
216static int qperf_seq_open(struct inode *inode, struct file *filp)
217{
218	return single_open(filp, qperf_show,
219			   filp->f_path.dentry->d_inode->i_private);
220}
221
222static struct file_operations debugfs_perf_fops = {
223	.owner	 = THIS_MODULE,
224	.open	 = qperf_seq_open,
225	.read	 = seq_read,
226	.write	 = qperf_seq_write,
227	.llseek  = seq_lseek,
228	.release = single_release,
229};
230static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
231{
232	char name[QDIO_DEBUGFS_NAME_LEN];
233
234	snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
235		 q->is_input_q ? "input" : "output",
236		 q->nr);
237	q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
238				q->irq_ptr->debugfs_dev, q, &debugfs_fops);
239	if (IS_ERR(q->debugfs_q))
240		q->debugfs_q = NULL;
241}
242
243void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
244{
245	struct qdio_q *q;
246	int i;
247
248	irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
249						  debugfs_root);
250	if (IS_ERR(irq_ptr->debugfs_dev))
251		irq_ptr->debugfs_dev = NULL;
252
253	irq_ptr->debugfs_perf = debugfs_create_file("statistics",
254				S_IFREG | S_IRUGO | S_IWUSR,
255				irq_ptr->debugfs_dev, irq_ptr,
256				&debugfs_perf_fops);
257	if (IS_ERR(irq_ptr->debugfs_perf))
258		irq_ptr->debugfs_perf = NULL;
259
260	for_each_input_queue(irq_ptr, q, i)
261		setup_debugfs_entry(q, cdev);
262	for_each_output_queue(irq_ptr, q, i)
263		setup_debugfs_entry(q, cdev);
264}
265
266void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
267{
268	struct qdio_q *q;
269	int i;
270
271	for_each_input_queue(irq_ptr, q, i)
272		debugfs_remove(q->debugfs_q);
273	for_each_output_queue(irq_ptr, q, i)
274		debugfs_remove(q->debugfs_q);
275	debugfs_remove(irq_ptr->debugfs_perf);
276	debugfs_remove(irq_ptr->debugfs_dev);
277}
278
279int __init qdio_debug_init(void)
280{
281	debugfs_root = debugfs_create_dir("qdio", NULL);
282
283	qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
284	debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
285	debug_set_level(qdio_dbf_setup, DBF_INFO);
286	DBF_EVENT("dbf created\n");
287
288	qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
289	debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
290	debug_set_level(qdio_dbf_error, DBF_INFO);
291	DBF_ERROR("dbf created\n");
292	return 0;
293}
294
295void qdio_debug_exit(void)
296{
297	debugfs_remove(debugfs_root);
298	if (qdio_dbf_setup)
299		debug_unregister(qdio_dbf_setup);
300	if (qdio_dbf_error)
301		debug_unregister(qdio_dbf_error);
302}