1 /* 2 * drivers/s390/cio/qdio_debug.c 3 * 4 * Copyright IBM Corp. 2008 5 * 6 * Author: Jan Glauber (jang@linux.vnet.ibm.com) 7 */ 8 #include <linux/proc_fs.h> 9 #include <linux/seq_file.h> 10 #include <linux/debugfs.h> 11 #include <asm/qdio.h> 12 #include <asm/debug.h> 13 #include "qdio_debug.h" 14 #include "qdio.h" 15 16 debug_info_t *qdio_dbf_setup; 17 debug_info_t *qdio_dbf_trace; 18 19 static struct dentry *debugfs_root; 20 #define MAX_DEBUGFS_QUEUES 32 21 static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL }; 22 static DEFINE_MUTEX(debugfs_mutex); 23 #define QDIO_DEBUGFS_NAME_LEN 40 24 25 void qdio_allocate_do_dbf(struct qdio_initialize *init_data) 26 { 27 char dbf_text[20]; 28 29 sprintf(dbf_text, "qfmt:%x", init_data->q_format); 30 QDIO_DBF_TEXT0(0, setup, dbf_text); 31 QDIO_DBF_HEX0(0, setup, init_data->adapter_name, 8); 32 sprintf(dbf_text, "qpff%4x", init_data->qib_param_field_format); 33 QDIO_DBF_TEXT0(0, setup, dbf_text); 34 QDIO_DBF_HEX0(0, setup, &init_data->qib_param_field, sizeof(void *)); 35 QDIO_DBF_HEX0(0, setup, &init_data->input_slib_elements, sizeof(void *)); 36 QDIO_DBF_HEX0(0, setup, &init_data->output_slib_elements, sizeof(void *)); 37 sprintf(dbf_text, "niq:%4x", init_data->no_input_qs); 38 QDIO_DBF_TEXT0(0, setup, dbf_text); 39 sprintf(dbf_text, "noq:%4x", init_data->no_output_qs); 40 QDIO_DBF_TEXT0(0, setup, dbf_text); 41 QDIO_DBF_HEX0(0, setup, &init_data->input_handler, sizeof(void *)); 42 QDIO_DBF_HEX0(0, setup, &init_data->output_handler, sizeof(void *)); 43 QDIO_DBF_HEX0(0, setup, &init_data->int_parm, sizeof(long)); 44 QDIO_DBF_HEX0(0, setup, &init_data->flags, sizeof(long)); 45 QDIO_DBF_HEX0(0, setup, &init_data->input_sbal_addr_array, sizeof(void *)); 46 QDIO_DBF_HEX0(0, setup, &init_data->output_sbal_addr_array, sizeof(void *)); 47 } 48 49 static void qdio_unregister_dbf_views(void) 50 { 51 if (qdio_dbf_setup) 52 debug_unregister(qdio_dbf_setup); 53 if (qdio_dbf_trace) 54 debug_unregister(qdio_dbf_trace); 55 } 56 57 static int qdio_register_dbf_views(void) 58 { 59 qdio_dbf_setup = debug_register("qdio_setup", QDIO_DBF_SETUP_PAGES, 60 QDIO_DBF_SETUP_NR_AREAS, 61 QDIO_DBF_SETUP_LEN); 62 if (!qdio_dbf_setup) 63 goto oom; 64 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); 65 debug_set_level(qdio_dbf_setup, QDIO_DBF_SETUP_LEVEL); 66 67 qdio_dbf_trace = debug_register("qdio_trace", QDIO_DBF_TRACE_PAGES, 68 QDIO_DBF_TRACE_NR_AREAS, 69 QDIO_DBF_TRACE_LEN); 70 if (!qdio_dbf_trace) 71 goto oom; 72 debug_register_view(qdio_dbf_trace, &debug_hex_ascii_view); 73 debug_set_level(qdio_dbf_trace, QDIO_DBF_TRACE_LEVEL); 74 return 0; 75 oom: 76 qdio_unregister_dbf_views(); 77 return -ENOMEM; 78 } 79 80 static int qstat_show(struct seq_file *m, void *v) 81 { 82 unsigned char state; 83 struct qdio_q *q = m->private; 84 int i; 85 86 if (!q) 87 return 0; 88 89 seq_printf(m, "device state indicator: %d\n", *q->irq_ptr->dsci); 90 seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used)); 91 seq_printf(m, "ftc: %d\n", q->first_to_check); 92 seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc); 93 seq_printf(m, "polling: %d\n", q->u.in.polling); 94 seq_printf(m, "slsb buffer states:\n"); 95 96 qdio_siga_sync_q(q); 97 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { 98 get_buf_state(q, i, &state); 99 switch (state) { 100 case SLSB_P_INPUT_NOT_INIT: 101 case SLSB_P_OUTPUT_NOT_INIT: 102 seq_printf(m, "N"); 103 break; 104 case SLSB_P_INPUT_PRIMED: 105 case SLSB_CU_OUTPUT_PRIMED: 106 seq_printf(m, "+"); 107 break; 108 case SLSB_P_INPUT_ACK: 109 seq_printf(m, "A"); 110 break; 111 case SLSB_P_INPUT_ERROR: 112 case SLSB_P_OUTPUT_ERROR: 113 seq_printf(m, "x"); 114 break; 115 case SLSB_CU_INPUT_EMPTY: 116 case SLSB_P_OUTPUT_EMPTY: 117 seq_printf(m, "-"); 118 break; 119 case SLSB_P_INPUT_HALTED: 120 case SLSB_P_OUTPUT_HALTED: 121 seq_printf(m, "."); 122 break; 123 default: 124 seq_printf(m, "?"); 125 } 126 if (i == 63) 127 seq_printf(m, "\n"); 128 } 129 seq_printf(m, "\n"); 130 return 0; 131 } 132 133 static ssize_t qstat_seq_write(struct file *file, const char __user *buf, 134 size_t count, loff_t *off) 135 { 136 struct seq_file *seq = file->private_data; 137 struct qdio_q *q = seq->private; 138 139 if (!q) 140 return 0; 141 142 if (q->is_input_q) 143 xchg(q->irq_ptr->dsci, 1); 144 local_bh_disable(); 145 tasklet_schedule(&q->tasklet); 146 local_bh_enable(); 147 return count; 148 } 149 150 static int qstat_seq_open(struct inode *inode, struct file *filp) 151 { 152 return single_open(filp, qstat_show, 153 filp->f_path.dentry->d_inode->i_private); 154 } 155 156 static void remove_debugfs_entry(struct qdio_q *q) 157 { 158 int i; 159 160 for (i = 0; i < MAX_DEBUGFS_QUEUES; i++) { 161 if (!debugfs_queues[i]) 162 continue; 163 if (debugfs_queues[i]->d_inode->i_private == q) { 164 debugfs_remove(debugfs_queues[i]); 165 debugfs_queues[i] = NULL; 166 } 167 } 168 } 169 170 static struct file_operations debugfs_fops = { 171 .owner = THIS_MODULE, 172 .open = qstat_seq_open, 173 .read = seq_read, 174 .write = qstat_seq_write, 175 .llseek = seq_lseek, 176 .release = single_release, 177 }; 178 179 static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) 180 { 181 int i = 0; 182 char name[QDIO_DEBUGFS_NAME_LEN]; 183 184 while (debugfs_queues[i] != NULL) { 185 i++; 186 if (i >= MAX_DEBUGFS_QUEUES) 187 return; 188 } 189 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%s_%d", 190 dev_name(&cdev->dev), 191 q->is_input_q ? "input" : "output", 192 q->nr); 193 debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, 194 debugfs_root, q, &debugfs_fops); 195 } 196 197 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) 198 { 199 struct qdio_q *q; 200 int i; 201 202 mutex_lock(&debugfs_mutex); 203 for_each_input_queue(irq_ptr, q, i) 204 setup_debugfs_entry(q, cdev); 205 for_each_output_queue(irq_ptr, q, i) 206 setup_debugfs_entry(q, cdev); 207 mutex_unlock(&debugfs_mutex); 208 } 209 210 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) 211 { 212 struct qdio_q *q; 213 int i; 214 215 mutex_lock(&debugfs_mutex); 216 for_each_input_queue(irq_ptr, q, i) 217 remove_debugfs_entry(q); 218 for_each_output_queue(irq_ptr, q, i) 219 remove_debugfs_entry(q); 220 mutex_unlock(&debugfs_mutex); 221 } 222 223 int __init qdio_debug_init(void) 224 { 225 debugfs_root = debugfs_create_dir("qdio_queues", NULL); 226 return qdio_register_dbf_views(); 227 } 228 229 void qdio_debug_exit(void) 230 { 231 debugfs_remove(debugfs_root); 232 qdio_unregister_dbf_views(); 233 } 234