Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 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 | |
| 21 | int qdio_performance_stats; |
| 22 | struct qdio_perf_stats perf_stats; |
| 23 | |
| 24 | #ifdef CONFIG_PROC_FS |
| 25 | static struct proc_dir_entry *qdio_perf_pde; |
| 26 | #endif |
| 27 | |
Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 28 | /* |
| 29 | * procfs functions |
| 30 | */ |
| 31 | static 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)); |
Jan Glauber | 50f769d | 2008-12-25 13:38:47 +0100 | [diff] [blame] | 65 | seq_printf(m, "Number of outbound target full condition\t: %li\n", |
| 66 | (long)atomic_long_read(&perf_stats.outbound_target_full)); |
Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 67 | seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n", |
| 68 | (long)atomic_long_read(&perf_stats.debug_tl_out_timer)); |
| 69 | seq_printf(m, "Number of stop polling calls\t\t\t: %li\n", |
| 70 | (long)atomic_long_read(&perf_stats.debug_stop_polling)); |
| 71 | seq_printf(m, "AI inbound tasklet loops after stop polling\t: %li\n", |
| 72 | (long)atomic_long_read(&perf_stats.thinint_inbound_loop2)); |
Jan Glauber | 23589d0 | 2008-12-25 13:38:44 +0100 | [diff] [blame] | 73 | seq_printf(m, "QEBSM EQBS total/incomplete\t\t\t: %li/%li\n", |
| 74 | (long)atomic_long_read(&perf_stats.debug_eqbs_all), |
| 75 | (long)atomic_long_read(&perf_stats.debug_eqbs_incomplete)); |
| 76 | seq_printf(m, "QEBSM SQBS total/incomplete\t\t\t: %li/%li\n", |
| 77 | (long)atomic_long_read(&perf_stats.debug_sqbs_all), |
| 78 | (long)atomic_long_read(&perf_stats.debug_sqbs_incomplete)); |
Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 79 | seq_printf(m, "\n"); |
| 80 | return 0; |
| 81 | } |
| 82 | static int qdio_perf_seq_open(struct inode *inode, struct file *filp) |
| 83 | { |
| 84 | return single_open(filp, qdio_perf_proc_show, NULL); |
| 85 | } |
| 86 | |
| 87 | static struct file_operations qdio_perf_proc_fops = { |
| 88 | .owner = THIS_MODULE, |
| 89 | .open = qdio_perf_seq_open, |
| 90 | .read = seq_read, |
| 91 | .llseek = seq_lseek, |
| 92 | .release = single_release, |
| 93 | }; |
| 94 | |
| 95 | /* |
| 96 | * sysfs functions |
| 97 | */ |
| 98 | static ssize_t qdio_perf_stats_show(struct bus_type *bus, char *buf) |
| 99 | { |
| 100 | return sprintf(buf, "%i\n", qdio_performance_stats ? 1 : 0); |
| 101 | } |
| 102 | |
| 103 | static ssize_t qdio_perf_stats_store(struct bus_type *bus, |
| 104 | const char *buf, size_t count) |
| 105 | { |
| 106 | unsigned long i; |
| 107 | |
| 108 | if (strict_strtoul(buf, 16, &i) != 0) |
| 109 | return -EINVAL; |
| 110 | if ((i != 0) && (i != 1)) |
| 111 | return -EINVAL; |
| 112 | if (i == qdio_performance_stats) |
| 113 | return count; |
| 114 | |
| 115 | qdio_performance_stats = i; |
| 116 | /* reset performance statistics */ |
| 117 | if (i == 0) |
| 118 | memset(&perf_stats, 0, sizeof(struct qdio_perf_stats)); |
| 119 | return count; |
| 120 | } |
| 121 | |
| 122 | static BUS_ATTR(qdio_performance_stats, 0644, qdio_perf_stats_show, |
| 123 | qdio_perf_stats_store); |
| 124 | |
| 125 | int __init qdio_setup_perf_stats(void) |
| 126 | { |
| 127 | int rc; |
| 128 | |
| 129 | rc = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats); |
| 130 | if (rc) |
| 131 | return rc; |
| 132 | |
| 133 | #ifdef CONFIG_PROC_FS |
| 134 | memset(&perf_stats, 0, sizeof(struct qdio_perf_stats)); |
| 135 | qdio_perf_pde = proc_create("qdio_perf", S_IFREG | S_IRUGO, |
| 136 | NULL, &qdio_perf_proc_fops); |
| 137 | #endif |
| 138 | return 0; |
| 139 | } |
| 140 | |
Heiko Carstens | 3f1934b | 2008-08-01 16:39:20 +0200 | [diff] [blame] | 141 | void qdio_remove_perf_stats(void) |
Jan Glauber | 779e6e1 | 2008-07-17 17:16:48 +0200 | [diff] [blame] | 142 | { |
| 143 | #ifdef CONFIG_PROC_FS |
| 144 | remove_proc_entry("qdio_perf", NULL); |
| 145 | #endif |
| 146 | bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats); |
| 147 | } |