aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2010-01-04 03:05:42 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-01-04 03:05:58 -0500
commit6486cda6c6b15368e2c925d89b4e9ed13e67b91b (patch)
treec4ca8e2b2b961adbc19733d1bcf3ebc6c5c6be32 /drivers/s390/cio
parent45d28b097280a78893ce25a5d0db41e6a2717853 (diff)
[S390] qdio: convert global statistics to per-device stats
Revamp the qdio performance statistics and move them from procfs to debugfs using the seq_file interface. Since the statistics are not intended for the general user the removal of /proc/qdio_perf should not surprise anyone. The per device statistics are disabled by default, writing 1 to /<debugfs mountpoint>/qdio/<device bus ID>/statistics enables the statistics for the given device. Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/Makefile2
-rw-r--r--drivers/s390/cio/qdio.h36
-rw-r--r--drivers/s390/cio/qdio_debug.c114
-rw-r--r--drivers/s390/cio/qdio_main.c71
-rw-r--r--drivers/s390/cio/qdio_perf.c149
-rw-r--r--drivers/s390/cio/qdio_perf.h62
-rw-r--r--drivers/s390/cio/qdio_thinint.c8
7 files changed, 177 insertions, 265 deletions
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index d033414f7599..e1b700a19648 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -10,5 +10,5 @@ obj-y += ccw_device.o cmf.o
10obj-$(CONFIG_CHSC_SCH) += chsc_sch.o 10obj-$(CONFIG_CHSC_SCH) += chsc_sch.o
11obj-$(CONFIG_CCWGROUP) += ccwgroup.o 11obj-$(CONFIG_CCWGROUP) += ccwgroup.o
12 12
13qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_perf.o qdio_setup.o 13qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o
14obj-$(CONFIG_QDIO) += qdio.o 14obj-$(CONFIG_QDIO) += qdio.o
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index ff7748a9199d..44f2f6a97f33 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -182,6 +182,34 @@ struct scssc_area {
182 u32:32; 182 u32:32;
183} __attribute__ ((packed)); 183} __attribute__ ((packed));
184 184
185struct qdio_dev_perf_stat {
186 unsigned int adapter_int;
187 unsigned int qdio_int;
188 unsigned int pci_request_int;
189
190 unsigned int tasklet_inbound;
191 unsigned int tasklet_inbound_resched;
192 unsigned int tasklet_inbound_resched2;
193 unsigned int tasklet_outbound;
194
195 unsigned int siga_read;
196 unsigned int siga_write;
197 unsigned int siga_sync;
198
199 unsigned int inbound_call;
200 unsigned int inbound_handler;
201 unsigned int stop_polling;
202 unsigned int inbound_queue_full;
203 unsigned int outbound_call;
204 unsigned int outbound_handler;
205 unsigned int fast_requeue;
206 unsigned int target_full;
207 unsigned int eqbs;
208 unsigned int eqbs_partial;
209 unsigned int sqbs;
210 unsigned int sqbs_partial;
211};
212
185struct qdio_input_q { 213struct qdio_input_q {
186 /* input buffer acknowledgement flag */ 214 /* input buffer acknowledgement flag */
187 int polling; 215 int polling;
@@ -269,6 +297,7 @@ struct qdio_irq {
269 u32 *dsci; /* address of device state change indicator */ 297 u32 *dsci; /* address of device state change indicator */
270 struct ccw_device *cdev; 298 struct ccw_device *cdev;
271 struct dentry *debugfs_dev; 299 struct dentry *debugfs_dev;
300 struct dentry *debugfs_perf;
272 301
273 unsigned long int_parm; 302 unsigned long int_parm;
274 struct subchannel_id schid; 303 struct subchannel_id schid;
@@ -286,9 +315,10 @@ struct qdio_irq {
286 struct ciw aqueue; 315 struct ciw aqueue;
287 316
288 struct qdio_ssqd_desc ssqd_desc; 317 struct qdio_ssqd_desc ssqd_desc;
289
290 void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *); 318 void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *);
291 319
320 struct qdio_dev_perf_stat perf_stat;
321 int perf_stat_enabled;
292 /* 322 /*
293 * Warning: Leave these members together at the end so they won't be 323 * Warning: Leave these members together at the end so they won't be
294 * cleared in qdio_setup_irq. 324 * cleared in qdio_setup_irq.
@@ -311,6 +341,10 @@ struct qdio_irq {
311 (irq->qib.qfmt == QDIO_IQDIO_QFMT || \ 341 (irq->qib.qfmt == QDIO_IQDIO_QFMT || \
312 css_general_characteristics.aif_osa) 342 css_general_characteristics.aif_osa)
313 343
344#define qperf(qdev,attr) qdev->perf_stat.attr
345#define qperf_inc(q,attr) if (q->irq_ptr->perf_stat_enabled) \
346 q->irq_ptr->perf_stat.attr++
347
314/* the highest iqdio queue is used for multicast */ 348/* the highest iqdio queue is used for multicast */
315static inline int multicast_outbound(struct qdio_q *q) 349static inline int multicast_outbound(struct qdio_q *q)
316{ 350{
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index 76769978285f..f49761ff9a00 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -55,13 +55,11 @@ static int qstat_show(struct seq_file *m, void *v)
55 if (!q) 55 if (!q)
56 return 0; 56 return 0;
57 57
58 seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci); 58 seq_printf(m, "DSCI: %d nr_used: %d\n",
59 seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used)); 59 *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used));
60 seq_printf(m, "ftc: %d\n", q->first_to_check); 60 seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move);
61 seq_printf(m, "last_move: %d\n", q->last_move); 61 seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
62 seq_printf(m, "polling: %d\n", q->u.in.polling); 62 q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
63 seq_printf(m, "ack start: %d\n", q->u.in.ack_start);
64 seq_printf(m, "ack count: %d\n", q->u.in.ack_count);
65 seq_printf(m, "slsb buffer states:\n"); 63 seq_printf(m, "slsb buffer states:\n");
66 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); 64 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
67 65
@@ -110,7 +108,6 @@ static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
110 108
111 if (!q) 109 if (!q)
112 return 0; 110 return 0;
113
114 if (q->is_input_q) 111 if (q->is_input_q)
115 xchg(q->irq_ptr->dsci, 1); 112 xchg(q->irq_ptr->dsci, 1);
116 local_bh_disable(); 113 local_bh_disable();
@@ -134,6 +131,98 @@ static const struct file_operations debugfs_fops = {
134 .release = single_release, 131 .release = single_release,
135}; 132};
136 133
134static char *qperf_names[] = {
135 "Assumed adapter interrupts",
136 "QDIO interrupts",
137 "Requested PCIs",
138 "Inbound tasklet runs",
139 "Inbound tasklet resched",
140 "Inbound tasklet resched2",
141 "Outbound tasklet runs",
142 "SIGA read",
143 "SIGA write",
144 "SIGA sync",
145 "Inbound calls",
146 "Inbound handler",
147 "Inbound stop_polling",
148 "Inbound queue full",
149 "Outbound calls",
150 "Outbound handler",
151 "Outbound fast_requeue",
152 "Outbound target_full",
153 "QEBSM eqbs",
154 "QEBSM eqbs partial",
155 "QEBSM sqbs",
156 "QEBSM sqbs partial"
157};
158
159static int qperf_show(struct seq_file *m, void *v)
160{
161 struct qdio_irq *irq_ptr = m->private;
162 unsigned int *stat;
163 int i;
164
165 if (!irq_ptr)
166 return 0;
167 if (!irq_ptr->perf_stat_enabled) {
168 seq_printf(m, "disabled\n");
169 return 0;
170 }
171 stat = (unsigned int *)&irq_ptr->perf_stat;
172
173 for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
174 seq_printf(m, "%26s:\t%u\n",
175 qperf_names[i], *(stat + i));
176 return 0;
177}
178
179static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
180 size_t count, loff_t *off)
181{
182 struct seq_file *seq = file->private_data;
183 struct qdio_irq *irq_ptr = seq->private;
184 unsigned long val;
185 char buf[8];
186 int ret;
187
188 if (!irq_ptr)
189 return 0;
190 if (count >= sizeof(buf))
191 return -EINVAL;
192 if (copy_from_user(&buf, ubuf, count))
193 return -EFAULT;
194 buf[count] = 0;
195
196 ret = strict_strtoul(buf, 10, &val);
197 if (ret < 0)
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 break;
205 case 1:
206 irq_ptr->perf_stat_enabled = 1;
207 break;
208 }
209 return count;
210}
211
212static int qperf_seq_open(struct inode *inode, struct file *filp)
213{
214 return single_open(filp, qperf_show,
215 filp->f_path.dentry->d_inode->i_private);
216}
217
218static struct file_operations debugfs_perf_fops = {
219 .owner = THIS_MODULE,
220 .open = qperf_seq_open,
221 .read = seq_read,
222 .write = qperf_seq_write,
223 .llseek = seq_lseek,
224 .release = single_release,
225};
137static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) 226static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
138{ 227{
139 char name[QDIO_DEBUGFS_NAME_LEN]; 228 char name[QDIO_DEBUGFS_NAME_LEN];
@@ -156,6 +245,14 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
156 debugfs_root); 245 debugfs_root);
157 if (IS_ERR(irq_ptr->debugfs_dev)) 246 if (IS_ERR(irq_ptr->debugfs_dev))
158 irq_ptr->debugfs_dev = NULL; 247 irq_ptr->debugfs_dev = NULL;
248
249 irq_ptr->debugfs_perf = debugfs_create_file("statistics",
250 S_IFREG | S_IRUGO | S_IWUSR,
251 irq_ptr->debugfs_dev, irq_ptr,
252 &debugfs_perf_fops);
253 if (IS_ERR(irq_ptr->debugfs_perf))
254 irq_ptr->debugfs_perf = NULL;
255
159 for_each_input_queue(irq_ptr, q, i) 256 for_each_input_queue(irq_ptr, q, i)
160 setup_debugfs_entry(q, cdev); 257 setup_debugfs_entry(q, cdev);
161 for_each_output_queue(irq_ptr, q, i) 258 for_each_output_queue(irq_ptr, q, i)
@@ -171,6 +268,7 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd
171 debugfs_remove(q->debugfs_q); 268 debugfs_remove(q->debugfs_q);
172 for_each_output_queue(irq_ptr, q, i) 269 for_each_output_queue(irq_ptr, q, i)
173 debugfs_remove(q->debugfs_q); 270 debugfs_remove(q->debugfs_q);
271 debugfs_remove(irq_ptr->debugfs_perf);
174 debugfs_remove(irq_ptr->debugfs_dev); 272 debugfs_remove(irq_ptr->debugfs_dev);
175} 273}
176 274
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index b2275c5000e7..999fe80c4051 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -22,7 +22,6 @@
22#include "device.h" 22#include "device.h"
23#include "qdio.h" 23#include "qdio.h"
24#include "qdio_debug.h" 24#include "qdio_debug.h"
25#include "qdio_perf.h"
26 25
27MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>,"\ 26MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>,"\
28 "Jan Glauber <jang@linux.vnet.ibm.com>"); 27 "Jan Glauber <jang@linux.vnet.ibm.com>");
@@ -126,7 +125,7 @@ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
126 int rc; 125 int rc;
127 126
128 BUG_ON(!q->irq_ptr->sch_token); 127 BUG_ON(!q->irq_ptr->sch_token);
129 qdio_perf_stat_inc(&perf_stats.debug_eqbs_all); 128 qperf_inc(q, eqbs);
130 129
131 if (!q->is_input_q) 130 if (!q->is_input_q)
132 nr += q->irq_ptr->nr_input_qs; 131 nr += q->irq_ptr->nr_input_qs;
@@ -139,7 +138,7 @@ again:
139 * buffers later. 138 * buffers later.
140 */ 139 */
141 if ((ccq == 96) && (count != tmp_count)) { 140 if ((ccq == 96) && (count != tmp_count)) {
142 qdio_perf_stat_inc(&perf_stats.debug_eqbs_incomplete); 141 qperf_inc(q, eqbs_partial);
143 return (count - tmp_count); 142 return (count - tmp_count);
144 } 143 }
145 144
@@ -182,7 +181,7 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start,
182 return 0; 181 return 0;
183 182
184 BUG_ON(!q->irq_ptr->sch_token); 183 BUG_ON(!q->irq_ptr->sch_token);
185 qdio_perf_stat_inc(&perf_stats.debug_sqbs_all); 184 qperf_inc(q, sqbs);
186 185
187 if (!q->is_input_q) 186 if (!q->is_input_q)
188 nr += q->irq_ptr->nr_input_qs; 187 nr += q->irq_ptr->nr_input_qs;
@@ -191,7 +190,7 @@ again:
191 rc = qdio_check_ccq(q, ccq); 190 rc = qdio_check_ccq(q, ccq);
192 if (rc == 1) { 191 if (rc == 1) {
193 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq); 192 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq);
194 qdio_perf_stat_inc(&perf_stats.debug_sqbs_incomplete); 193 qperf_inc(q, sqbs_partial);
195 goto again; 194 goto again;
196 } 195 }
197 if (rc < 0) { 196 if (rc < 0) {
@@ -285,7 +284,7 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output,
285 return 0; 284 return 0;
286 285
287 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr); 286 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr);
288 qdio_perf_stat_inc(&perf_stats.siga_sync); 287 qperf_inc(q, siga_sync);
289 288
290 cc = do_siga_sync(q->irq_ptr->schid, output, input); 289 cc = do_siga_sync(q->irq_ptr->schid, output, input);
291 if (cc) 290 if (cc)
@@ -350,7 +349,7 @@ static inline int qdio_siga_input(struct qdio_q *q)
350 int cc; 349 int cc;
351 350
352 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr); 351 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr);
353 qdio_perf_stat_inc(&perf_stats.siga_in); 352 qperf_inc(q, siga_read);
354 353
355 cc = do_siga_input(q->irq_ptr->schid, q->mask); 354 cc = do_siga_input(q->irq_ptr->schid, q->mask);
356 if (cc) 355 if (cc)
@@ -382,7 +381,7 @@ static inline void qdio_stop_polling(struct qdio_q *q)
382 return; 381 return;
383 382
384 q->u.in.polling = 0; 383 q->u.in.polling = 0;
385 qdio_perf_stat_inc(&perf_stats.debug_stop_polling); 384 qperf_inc(q, stop_polling);
386 385
387 /* show the card that we are not polling anymore */ 386 /* show the card that we are not polling anymore */
388 if (is_qebsm(q)) { 387 if (is_qebsm(q)) {
@@ -400,7 +399,7 @@ static void announce_buffer_error(struct qdio_q *q, int count)
400 /* special handling for no target buffer empty */ 399 /* special handling for no target buffer empty */
401 if ((!q->is_input_q && 400 if ((!q->is_input_q &&
402 (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) { 401 (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) {
403 qdio_perf_stat_inc(&perf_stats.outbound_target_full); 402 qperf_inc(q, target_full);
404 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%02x", 403 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%02x",
405 q->first_to_check); 404 q->first_to_check);
406 return; 405 return;
@@ -487,7 +486,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
487 inbound_primed(q, count); 486 inbound_primed(q, count);
488 q->first_to_check = add_buf(q->first_to_check, count); 487 q->first_to_check = add_buf(q->first_to_check, count);
489 if (atomic_sub(count, &q->nr_buf_used) == 0) 488 if (atomic_sub(count, &q->nr_buf_used) == 0)
490 qdio_perf_stat_inc(&perf_stats.inbound_queue_full); 489 qperf_inc(q, inbound_queue_full);
491 break; 490 break;
492 case SLSB_P_INPUT_ERROR: 491 case SLSB_P_INPUT_ERROR:
493 announce_buffer_error(q, count); 492 announce_buffer_error(q, count);
@@ -567,9 +566,10 @@ static void qdio_kick_handler(struct qdio_q *q)
567 count = sub_buf(end, start); 566 count = sub_buf(end, start);
568 567
569 if (q->is_input_q) { 568 if (q->is_input_q) {
570 qdio_perf_stat_inc(&perf_stats.inbound_handler); 569 qperf_inc(q, inbound_handler);
571 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count); 570 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count);
572 } else 571 } else
572 qperf_inc(q, outbound_handler);
573 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x", 573 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x",
574 start, count); 574 start, count);
575 575
@@ -583,24 +583,28 @@ static void qdio_kick_handler(struct qdio_q *q)
583 583
584static void __qdio_inbound_processing(struct qdio_q *q) 584static void __qdio_inbound_processing(struct qdio_q *q)
585{ 585{
586 qdio_perf_stat_inc(&perf_stats.tasklet_inbound); 586 qperf_inc(q, tasklet_inbound);
587again: 587again:
588 if (!qdio_inbound_q_moved(q)) 588 if (!qdio_inbound_q_moved(q))
589 return; 589 return;
590 590
591 qdio_kick_handler(q); 591 qdio_kick_handler(q);
592 592
593 if (!qdio_inbound_q_done(q)) 593 if (!qdio_inbound_q_done(q)) {
594 /* means poll time is not yet over */ 594 /* means poll time is not yet over */
595 qperf_inc(q, tasklet_inbound_resched);
595 goto again; 596 goto again;
597 }
596 598
597 qdio_stop_polling(q); 599 qdio_stop_polling(q);
598 /* 600 /*
599 * We need to check again to not lose initiative after 601 * We need to check again to not lose initiative after
600 * resetting the ACK state. 602 * resetting the ACK state.
601 */ 603 */
602 if (!qdio_inbound_q_done(q)) 604 if (!qdio_inbound_q_done(q)) {
605 qperf_inc(q, tasklet_inbound_resched2);
603 goto again; 606 goto again;
607 }
604} 608}
605 609
606void qdio_inbound_processing(unsigned long data) 610void qdio_inbound_processing(unsigned long data)
@@ -688,7 +692,7 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
688 return 0; 692 return 0;
689 693
690 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); 694 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
691 qdio_perf_stat_inc(&perf_stats.siga_out); 695 qperf_inc(q, siga_write);
692 696
693 cc = qdio_siga_output(q, &busy_bit); 697 cc = qdio_siga_output(q, &busy_bit);
694 switch (cc) { 698 switch (cc) {
@@ -711,7 +715,7 @@ static int qdio_kick_outbound_q(struct qdio_q *q)
711 715
712static void __qdio_outbound_processing(struct qdio_q *q) 716static void __qdio_outbound_processing(struct qdio_q *q)
713{ 717{
714 qdio_perf_stat_inc(&perf_stats.tasklet_outbound); 718 qperf_inc(q, tasklet_outbound);
715 BUG_ON(atomic_read(&q->nr_buf_used) < 0); 719 BUG_ON(atomic_read(&q->nr_buf_used) < 0);
716 720
717 if (qdio_outbound_q_moved(q)) 721 if (qdio_outbound_q_moved(q))
@@ -739,12 +743,9 @@ static void __qdio_outbound_processing(struct qdio_q *q)
739 */ 743 */
740 if (qdio_outbound_q_done(q)) 744 if (qdio_outbound_q_done(q))
741 del_timer(&q->u.out.timer); 745 del_timer(&q->u.out.timer);
742 else { 746 else
743 if (!timer_pending(&q->u.out.timer)) { 747 if (!timer_pending(&q->u.out.timer))
744 mod_timer(&q->u.out.timer, jiffies + 10 * HZ); 748 mod_timer(&q->u.out.timer, jiffies + 10 * HZ);
745 qdio_perf_stat_inc(&perf_stats.debug_tl_out_timer);
746 }
747 }
748 return; 749 return;
749 750
750sched: 751sched:
@@ -784,7 +785,7 @@ static inline void qdio_check_outbound_after_thinint(struct qdio_q *q)
784 785
785static void __tiqdio_inbound_processing(struct qdio_q *q) 786static void __tiqdio_inbound_processing(struct qdio_q *q)
786{ 787{
787 qdio_perf_stat_inc(&perf_stats.thinint_inbound); 788 qperf_inc(q, tasklet_inbound);
788 qdio_sync_after_thinint(q); 789 qdio_sync_after_thinint(q);
789 790
790 /* 791 /*
@@ -799,7 +800,7 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
799 qdio_kick_handler(q); 800 qdio_kick_handler(q);
800 801
801 if (!qdio_inbound_q_done(q)) { 802 if (!qdio_inbound_q_done(q)) {
802 qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); 803 qperf_inc(q, tasklet_inbound_resched);
803 if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) { 804 if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) {
804 tasklet_schedule(&q->tasklet); 805 tasklet_schedule(&q->tasklet);
805 return; 806 return;
@@ -812,7 +813,7 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
812 * resetting the ACK state. 813 * resetting the ACK state.
813 */ 814 */
814 if (!qdio_inbound_q_done(q)) { 815 if (!qdio_inbound_q_done(q)) {
815 qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2); 816 qperf_inc(q, tasklet_inbound_resched2);
816 if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) 817 if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
817 tasklet_schedule(&q->tasklet); 818 tasklet_schedule(&q->tasklet);
818 } 819 }
@@ -851,8 +852,6 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
851 if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) 852 if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
852 return; 853 return;
853 854
854 qdio_perf_stat_inc(&perf_stats.pci_int);
855
856 for_each_input_queue(irq_ptr, q, i) 855 for_each_input_queue(irq_ptr, q, i)
857 tasklet_schedule(&q->tasklet); 856 tasklet_schedule(&q->tasklet);
858 857
@@ -923,8 +922,6 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
923 struct qdio_irq *irq_ptr = cdev->private->qdio_data; 922 struct qdio_irq *irq_ptr = cdev->private->qdio_data;
924 int cstat, dstat; 923 int cstat, dstat;
925 924
926 qdio_perf_stat_inc(&perf_stats.qdio_int);
927
928 if (!intparm || !irq_ptr) { 925 if (!intparm || !irq_ptr) {
929 DBF_ERROR("qint:%4x", cdev->private->schid.sch_no); 926 DBF_ERROR("qint:%4x", cdev->private->schid.sch_no);
930 return; 927 return;
@@ -1383,6 +1380,8 @@ static int handle_inbound(struct qdio_q *q, unsigned int callflags,
1383{ 1380{
1384 int used, diff; 1381 int used, diff;
1385 1382
1383 qperf_inc(q, inbound_call);
1384
1386 if (!q->u.in.polling) 1385 if (!q->u.in.polling)
1387 goto set; 1386 goto set;
1388 1387
@@ -1438,14 +1437,16 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
1438 unsigned char state; 1437 unsigned char state;
1439 int used, rc = 0; 1438 int used, rc = 0;
1440 1439
1441 qdio_perf_stat_inc(&perf_stats.outbound_handler); 1440 qperf_inc(q, outbound_call);
1442 1441
1443 count = set_buf_states(q, bufnr, SLSB_CU_OUTPUT_PRIMED, count); 1442 count = set_buf_states(q, bufnr, SLSB_CU_OUTPUT_PRIMED, count);
1444 used = atomic_add_return(count, &q->nr_buf_used); 1443 used = atomic_add_return(count, &q->nr_buf_used);
1445 BUG_ON(used > QDIO_MAX_BUFFERS_PER_Q); 1444 BUG_ON(used > QDIO_MAX_BUFFERS_PER_Q);
1446 1445
1447 if (callflags & QDIO_FLAG_PCI_OUT) 1446 if (callflags & QDIO_FLAG_PCI_OUT) {
1448 q->u.out.pci_out_enabled = 1; 1447 q->u.out.pci_out_enabled = 1;
1448 qperf_inc(q, pci_request_int);
1449 }
1449 else 1450 else
1450 q->u.out.pci_out_enabled = 0; 1451 q->u.out.pci_out_enabled = 0;
1451 1452
@@ -1484,7 +1485,7 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
1484 if (state != SLSB_CU_OUTPUT_PRIMED) 1485 if (state != SLSB_CU_OUTPUT_PRIMED)
1485 rc = qdio_kick_outbound_q(q); 1486 rc = qdio_kick_outbound_q(q);
1486 else 1487 else
1487 qdio_perf_stat_inc(&perf_stats.fast_requeue); 1488 qperf_inc(q, fast_requeue);
1488 1489
1489out: 1490out:
1490 tasklet_schedule(&q->tasklet); 1491 tasklet_schedule(&q->tasklet);
@@ -1540,16 +1541,11 @@ static int __init init_QDIO(void)
1540 rc = qdio_debug_init(); 1541 rc = qdio_debug_init();
1541 if (rc) 1542 if (rc)
1542 goto out_ti; 1543 goto out_ti;
1543 rc = qdio_setup_perf_stats();
1544 if (rc)
1545 goto out_debug;
1546 rc = tiqdio_register_thinints(); 1544 rc = tiqdio_register_thinints();
1547 if (rc) 1545 if (rc)
1548 goto out_perf; 1546 goto out_debug;
1549 return 0; 1547 return 0;
1550 1548
1551out_perf:
1552 qdio_remove_perf_stats();
1553out_debug: 1549out_debug:
1554 qdio_debug_exit(); 1550 qdio_debug_exit();
1555out_ti: 1551out_ti:
@@ -1563,7 +1559,6 @@ static void __exit exit_QDIO(void)
1563{ 1559{
1564 tiqdio_unregister_thinints(); 1560 tiqdio_unregister_thinints();
1565 tiqdio_free_memory(); 1561 tiqdio_free_memory();
1566 qdio_remove_perf_stats();
1567 qdio_debug_exit(); 1562 qdio_debug_exit();
1568 qdio_setup_exit(); 1563 qdio_setup_exit();
1569} 1564}
diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c
deleted file mode 100644
index 54f7c325a3e6..000000000000
--- a/drivers/s390/cio/qdio_perf.c
+++ /dev/null
@@ -1,149 +0,0 @@
1/*
2 * drivers/s390/cio/qdio_perf.c
3 *
4 * Copyright IBM Corp. 2008
5 *
6 * Author: Jan Glauber (jang@linux.vnet.ibm.com)
7 */
8#include <linux/kernel.h>
9#include <linux/proc_fs.h>
10#include <linux/seq_file.h>
11#include <asm/ccwdev.h>
12
13#include "cio.h"
14#include "css.h"
15#include "device.h"
16#include "ioasm.h"
17#include "chsc.h"
18#include "qdio_debug.h"
19#include "qdio_perf.h"
20
21int qdio_performance_stats;
22struct qdio_perf_stats perf_stats;
23
24#ifdef CONFIG_PROC_FS
25static struct proc_dir_entry *qdio_perf_pde;
26#endif
27
28/*
29 * procfs functions
30 */
31static int qdio_perf_proc_show(struct seq_file *m, void *v)
32{
33 seq_printf(m, "Number of qdio interrupts\t\t\t: %li\n",
34 (long)atomic_long_read(&perf_stats.qdio_int));
35 seq_printf(m, "Number of PCI interrupts\t\t\t: %li\n",
36 (long)atomic_long_read(&perf_stats.pci_int));
37 seq_printf(m, "Number of adapter interrupts\t\t\t: %li\n",
38 (long)atomic_long_read(&perf_stats.thin_int));
39 seq_printf(m, "\n");
40 seq_printf(m, "Inbound tasklet runs\t\t\t\t: %li\n",
41 (long)atomic_long_read(&perf_stats.tasklet_inbound));
42 seq_printf(m, "Outbound tasklet runs\t\t\t\t: %li\n",
43 (long)atomic_long_read(&perf_stats.tasklet_outbound));
44 seq_printf(m, "Adapter interrupt tasklet runs/loops\t\t: %li/%li\n",
45 (long)atomic_long_read(&perf_stats.tasklet_thinint),
46 (long)atomic_long_read(&perf_stats.tasklet_thinint_loop));
47 seq_printf(m, "Adapter interrupt inbound tasklet runs/loops\t: %li/%li\n",
48 (long)atomic_long_read(&perf_stats.thinint_inbound),
49 (long)atomic_long_read(&perf_stats.thinint_inbound_loop));
50 seq_printf(m, "\n");
51 seq_printf(m, "Number of SIGA In issued\t\t\t: %li\n",
52 (long)atomic_long_read(&perf_stats.siga_in));
53 seq_printf(m, "Number of SIGA Out issued\t\t\t: %li\n",
54 (long)atomic_long_read(&perf_stats.siga_out));
55 seq_printf(m, "Number of SIGA Sync issued\t\t\t: %li\n",
56 (long)atomic_long_read(&perf_stats.siga_sync));
57 seq_printf(m, "\n");
58 seq_printf(m, "Number of inbound transfers\t\t\t: %li\n",
59 (long)atomic_long_read(&perf_stats.inbound_handler));
60 seq_printf(m, "Number of outbound transfers\t\t\t: %li\n",
61 (long)atomic_long_read(&perf_stats.outbound_handler));
62 seq_printf(m, "\n");
63 seq_printf(m, "Number of fast requeues (outg. SBAL w/o SIGA)\t: %li\n",
64 (long)atomic_long_read(&perf_stats.fast_requeue));
65 seq_printf(m, "Number of outbound target full condition\t: %li\n",
66 (long)atomic_long_read(&perf_stats.outbound_target_full));
67 seq_printf(m, "Number of inbound queue full condition\t\t: %li\n",
68 (long)atomic_long_read(&perf_stats.inbound_queue_full));
69 seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n",
70 (long)atomic_long_read(&perf_stats.debug_tl_out_timer));
71 seq_printf(m, "Number of stop polling calls\t\t\t: %li\n",
72 (long)atomic_long_read(&perf_stats.debug_stop_polling));
73 seq_printf(m, "AI inbound tasklet loops after stop polling\t: %li\n",
74 (long)atomic_long_read(&perf_stats.thinint_inbound_loop2));
75 seq_printf(m, "QEBSM EQBS total/incomplete\t\t\t: %li/%li\n",
76 (long)atomic_long_read(&perf_stats.debug_eqbs_all),
77 (long)atomic_long_read(&perf_stats.debug_eqbs_incomplete));
78 seq_printf(m, "QEBSM SQBS total/incomplete\t\t\t: %li/%li\n",
79 (long)atomic_long_read(&perf_stats.debug_sqbs_all),
80 (long)atomic_long_read(&perf_stats.debug_sqbs_incomplete));
81 seq_printf(m, "\n");
82 return 0;
83}
84static int qdio_perf_seq_open(struct inode *inode, struct file *filp)
85{
86 return single_open(filp, qdio_perf_proc_show, NULL);
87}
88
89static const struct file_operations qdio_perf_proc_fops = {
90 .owner = THIS_MODULE,
91 .open = qdio_perf_seq_open,
92 .read = seq_read,
93 .llseek = seq_lseek,
94 .release = single_release,
95};
96
97/*
98 * sysfs functions
99 */
100static ssize_t qdio_perf_stats_show(struct bus_type *bus, char *buf)
101{
102 return sprintf(buf, "%i\n", qdio_performance_stats ? 1 : 0);
103}
104
105static ssize_t qdio_perf_stats_store(struct bus_type *bus,
106 const char *buf, size_t count)
107{
108 unsigned long i;
109
110 if (strict_strtoul(buf, 16, &i) != 0)
111 return -EINVAL;
112 if ((i != 0) && (i != 1))
113 return -EINVAL;
114 if (i == qdio_performance_stats)
115 return count;
116
117 qdio_performance_stats = i;
118 /* reset performance statistics */
119 if (i == 0)
120 memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
121 return count;
122}
123
124static BUS_ATTR(qdio_performance_stats, 0644, qdio_perf_stats_show,
125 qdio_perf_stats_store);
126
127int __init qdio_setup_perf_stats(void)
128{
129 int rc;
130
131 rc = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
132 if (rc)
133 return rc;
134
135#ifdef CONFIG_PROC_FS
136 memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
137 qdio_perf_pde = proc_create("qdio_perf", S_IFREG | S_IRUGO,
138 NULL, &qdio_perf_proc_fops);
139#endif
140 return 0;
141}
142
143void qdio_remove_perf_stats(void)
144{
145#ifdef CONFIG_PROC_FS
146 remove_proc_entry("qdio_perf", NULL);
147#endif
148 bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
149}
diff --git a/drivers/s390/cio/qdio_perf.h b/drivers/s390/cio/qdio_perf.h
deleted file mode 100644
index 12454231dc8b..000000000000
--- a/drivers/s390/cio/qdio_perf.h
+++ /dev/null
@@ -1,62 +0,0 @@
1/*
2 * drivers/s390/cio/qdio_perf.h
3 *
4 * Copyright IBM Corp. 2008
5 *
6 * Author: Jan Glauber (jang@linux.vnet.ibm.com)
7 */
8#ifndef QDIO_PERF_H
9#define QDIO_PERF_H
10
11#include <linux/types.h>
12#include <asm/atomic.h>
13
14struct qdio_perf_stats {
15 /* interrupt handler calls */
16 atomic_long_t qdio_int;
17 atomic_long_t pci_int;
18 atomic_long_t thin_int;
19
20 /* tasklet runs */
21 atomic_long_t tasklet_inbound;
22 atomic_long_t tasklet_outbound;
23 atomic_long_t tasklet_thinint;
24 atomic_long_t tasklet_thinint_loop;
25 atomic_long_t thinint_inbound;
26 atomic_long_t thinint_inbound_loop;
27 atomic_long_t thinint_inbound_loop2;
28
29 /* signal adapter calls */
30 atomic_long_t siga_out;
31 atomic_long_t siga_in;
32 atomic_long_t siga_sync;
33
34 /* misc */
35 atomic_long_t inbound_handler;
36 atomic_long_t outbound_handler;
37 atomic_long_t fast_requeue;
38 atomic_long_t outbound_target_full;
39 atomic_long_t inbound_queue_full;
40
41 /* for debugging */
42 atomic_long_t debug_tl_out_timer;
43 atomic_long_t debug_stop_polling;
44 atomic_long_t debug_eqbs_all;
45 atomic_long_t debug_eqbs_incomplete;
46 atomic_long_t debug_sqbs_all;
47 atomic_long_t debug_sqbs_incomplete;
48};
49
50extern struct qdio_perf_stats perf_stats;
51extern int qdio_performance_stats;
52
53static inline void qdio_perf_stat_inc(atomic_long_t *count)
54{
55 if (qdio_performance_stats)
56 atomic_long_inc(count);
57}
58
59int qdio_setup_perf_stats(void);
60void qdio_remove_perf_stats(void);
61
62#endif
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 981a77ea7ee2..091d904d3182 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -1,9 +1,7 @@
1/* 1/*
2 * linux/drivers/s390/cio/thinint_qdio.c 2 * linux/drivers/s390/cio/thinint_qdio.c
3 * 3 *
4 * thin interrupt support for qdio 4 * Copyright 2000,2009 IBM Corp.
5 *
6 * Copyright 2000-2008 IBM Corp.
7 * Author(s): Utz Bacher <utz.bacher@de.ibm.com> 5 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
8 * Cornelia Huck <cornelia.huck@de.ibm.com> 6 * Cornelia Huck <cornelia.huck@de.ibm.com>
9 * Jan Glauber <jang@linux.vnet.ibm.com> 7 * Jan Glauber <jang@linux.vnet.ibm.com>
@@ -19,7 +17,6 @@
19#include "ioasm.h" 17#include "ioasm.h"
20#include "qdio.h" 18#include "qdio.h"
21#include "qdio_debug.h" 19#include "qdio_debug.h"
22#include "qdio_perf.h"
23 20
24/* 21/*
25 * Restriction: only 63 iqdio subchannels would have its own indicator, 22 * Restriction: only 63 iqdio subchannels would have its own indicator,
@@ -132,8 +129,6 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data)
132{ 129{
133 struct qdio_q *q; 130 struct qdio_q *q;
134 131
135 qdio_perf_stat_inc(&perf_stats.thin_int);
136
137 /* 132 /*
138 * SVS only when needed: issue SVS to benefit from iqdio interrupt 133 * SVS only when needed: issue SVS to benefit from iqdio interrupt
139 * avoidance (SVS clears adapter interrupt suppression overwrite) 134 * avoidance (SVS clears adapter interrupt suppression overwrite)
@@ -154,6 +149,7 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data)
154 list_for_each_entry_rcu(q, &tiq_list, entry) 149 list_for_each_entry_rcu(q, &tiq_list, entry)
155 /* only process queues from changed sets */ 150 /* only process queues from changed sets */
156 if (*q->irq_ptr->dsci) { 151 if (*q->irq_ptr->dsci) {
152 qperf_inc(q, adapter_int);
157 153
158 /* only clear it if the indicator is non-shared */ 154 /* only clear it if the indicator is non-shared */
159 if (!shared_ind(q->irq_ptr)) 155 if (!shared_ind(q->irq_ptr))