aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2010-02-26 16:37:36 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-02-26 16:37:30 -0500
commitd307297f73077b4dc8110eb998108ffc467e8e6c (patch)
treeda1ca8c5e39018149cfe77cbdc5d8dd50d826f29 /drivers
parenta93b8ec1df1f0ad75d036dbc0fdef2e0ccb7be02 (diff)
[S390] qdio: account processed SBAL during queue scan
Add counters for the number of processed SBALs. The numbers summarize how many SBALs were processed at each queue scan and indicate the utilization of the queue. Furthermore the number of unsuccessfull queue scans, SBAL errors and the total number of processed SBALs are accounted. Also regroup struct qdio_q to move read-mostly and write-mostly data into different cachelines. Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/s390/cio/qdio.h85
-rw-r--r--drivers/s390/cio/qdio_debug.c23
-rw-r--r--drivers/s390/cio/qdio_main.c26
3 files changed, 101 insertions, 33 deletions
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 44f2f6a97f33..9a5283e16e38 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -210,16 +210,25 @@ struct qdio_dev_perf_stat {
210 unsigned int sqbs_partial; 210 unsigned int sqbs_partial;
211}; 211};
212 212
213struct qdio_queue_perf_stat {
214 /*
215 * Sorted into order-2 buckets: 1, 2-3, 4-7, ... 64-127, 128.
216 * Since max. 127 SBALs are scanned reuse entry for 128 as queue full
217 * aka 127 SBALs found.
218 */
219 unsigned int nr_sbals[8];
220 unsigned int nr_sbal_error;
221 unsigned int nr_sbal_nop;
222 unsigned int nr_sbal_total;
223};
224
213struct qdio_input_q { 225struct qdio_input_q {
214 /* input buffer acknowledgement flag */ 226 /* input buffer acknowledgement flag */
215 int polling; 227 int polling;
216
217 /* first ACK'ed buffer */ 228 /* first ACK'ed buffer */
218 int ack_start; 229 int ack_start;
219
220 /* how much sbals are acknowledged with qebsm */ 230 /* how much sbals are acknowledged with qebsm */
221 int ack_count; 231 int ack_count;
222
223 /* last time of noticing incoming data */ 232 /* last time of noticing incoming data */
224 u64 timestamp; 233 u64 timestamp;
225}; 234};
@@ -227,40 +236,27 @@ struct qdio_input_q {
227struct qdio_output_q { 236struct qdio_output_q {
228 /* PCIs are enabled for the queue */ 237 /* PCIs are enabled for the queue */
229 int pci_out_enabled; 238 int pci_out_enabled;
230
231 /* IQDIO: output multiple buffers (enhanced SIGA) */ 239 /* IQDIO: output multiple buffers (enhanced SIGA) */
232 int use_enh_siga; 240 int use_enh_siga;
233
234 /* timer to check for more outbound work */ 241 /* timer to check for more outbound work */
235 struct timer_list timer; 242 struct timer_list timer;
236}; 243};
237 244
245/*
246 * Note on cache alignment: grouped slsb and write mostly data at the beginning
247 * sbal[] is read-only and starts on a new cacheline followed by read mostly.
248 */
238struct qdio_q { 249struct qdio_q {
239 struct slsb slsb; 250 struct slsb slsb;
251
240 union { 252 union {
241 struct qdio_input_q in; 253 struct qdio_input_q in;
242 struct qdio_output_q out; 254 struct qdio_output_q out;
243 } u; 255 } u;
244 256
245 /* queue number */
246 int nr;
247
248 /* bitmask of queue number */
249 int mask;
250
251 /* input or output queue */
252 int is_input_q;
253
254 /* list of thinint input queues */
255 struct list_head entry;
256
257 /* upper-layer program handler */
258 qdio_handler_t (*handler);
259
260 /* 257 /*
261 * inbound: next buffer the program should check for 258 * inbound: next buffer the program should check for
262 * outbound: next buffer to check for having been processed 259 * outbound: next buffer to check if adapter processed it
263 * by the card
264 */ 260 */
265 int first_to_check; 261 int first_to_check;
266 262
@@ -273,16 +269,32 @@ struct qdio_q {
273 /* number of buffers in use by the adapter */ 269 /* number of buffers in use by the adapter */
274 atomic_t nr_buf_used; 270 atomic_t nr_buf_used;
275 271
276 struct qdio_irq *irq_ptr;
277 struct dentry *debugfs_q;
278 struct tasklet_struct tasklet;
279
280 /* error condition during a data transfer */ 272 /* error condition during a data transfer */
281 unsigned int qdio_error; 273 unsigned int qdio_error;
282 274
283 struct sl *sl; 275 struct tasklet_struct tasklet;
284 struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; 276 struct qdio_queue_perf_stat q_stats;
277
278 struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q] ____cacheline_aligned;
279
280 /* queue number */
281 int nr;
282
283 /* bitmask of queue number */
284 int mask;
285
286 /* input or output queue */
287 int is_input_q;
288
289 /* list of thinint input queues */
290 struct list_head entry;
291
292 /* upper-layer program handler */
293 qdio_handler_t (*handler);
285 294
295 struct dentry *debugfs_q;
296 struct qdio_irq *irq_ptr;
297 struct sl *sl;
286 /* 298 /*
287 * Warning: Leave this member at the end so it won't be cleared in 299 * Warning: Leave this member at the end so it won't be cleared in
288 * qdio_fill_qs. A page is allocated under this pointer and used for 300 * qdio_fill_qs. A page is allocated under this pointer and used for
@@ -341,9 +353,20 @@ struct qdio_irq {
341 (irq->qib.qfmt == QDIO_IQDIO_QFMT || \ 353 (irq->qib.qfmt == QDIO_IQDIO_QFMT || \
342 css_general_characteristics.aif_osa) 354 css_general_characteristics.aif_osa)
343 355
344#define qperf(qdev,attr) qdev->perf_stat.attr 356#define qperf(__qdev, __attr) ((__qdev)->perf_stat.(__attr))
345#define qperf_inc(q,attr) if (q->irq_ptr->perf_stat_enabled) \ 357
346 q->irq_ptr->perf_stat.attr++ 358#define qperf_inc(__q, __attr) \
359({ \
360 struct qdio_irq *qdev = (__q)->irq_ptr; \
361 if (qdev->perf_stat_enabled) \
362 (qdev->perf_stat.__attr)++; \
363})
364
365static inline void account_sbals_error(struct qdio_q *q, int count)
366{
367 q->q_stats.nr_sbal_error += count;
368 q->q_stats.nr_sbal_total += count;
369}
347 370
348/* the highest iqdio queue is used for multicast */ 371/* the highest iqdio queue is used for multicast */
349static inline int multicast_outbound(struct qdio_q *q) 372static inline int multicast_outbound(struct qdio_q *q)
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index f49761ff9a00..c94eb2a0fa2e 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -60,7 +60,7 @@ static int qstat_show(struct seq_file *m, void *v)
60 seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move); 60 seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move);
61 seq_printf(m, "polling: %d ack start: %d ack count: %d\n", 61 seq_printf(m, "polling: %d ack start: %d ack count: %d\n",
62 q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count); 62 q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
63 seq_printf(m, "slsb buffer states:\n"); 63 seq_printf(m, "SBAL states:\n");
64 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");
65 65
66 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { 66 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
@@ -97,6 +97,20 @@ static int qstat_show(struct seq_file *m, void *v)
97 } 97 }
98 seq_printf(m, "\n"); 98 seq_printf(m, "\n");
99 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n"); 99 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n");
100
101 seq_printf(m, "\nSBAL statistics:");
102 if (!q->irq_ptr->perf_stat_enabled) {
103 seq_printf(m, " disabled\n");
104 return 0;
105 }
106
107 seq_printf(m, "\n1 2.. 4.. 8.. "
108 "16.. 32.. 64.. 127\n");
109 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
110 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
111 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n",
112 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
113 q->q_stats.nr_sbal_total);
100 return 0; 114 return 0;
101} 115}
102 116
@@ -181,9 +195,10 @@ static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
181{ 195{
182 struct seq_file *seq = file->private_data; 196 struct seq_file *seq = file->private_data;
183 struct qdio_irq *irq_ptr = seq->private; 197 struct qdio_irq *irq_ptr = seq->private;
198 struct qdio_q *q;
184 unsigned long val; 199 unsigned long val;
185 char buf[8]; 200 char buf[8];
186 int ret; 201 int ret, i;
187 202
188 if (!irq_ptr) 203 if (!irq_ptr)
189 return 0; 204 return 0;
@@ -201,6 +216,10 @@ static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
201 case 0: 216 case 0:
202 irq_ptr->perf_stat_enabled = 0; 217 irq_ptr->perf_stat_enabled = 0;
203 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); 218 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
219 for_each_input_queue(irq_ptr, q, i)
220 memset(&q->q_stats, 0, sizeof(q->q_stats));
221 for_each_output_queue(irq_ptr, q, i)
222 memset(&q->q_stats, 0, sizeof(q->q_stats));
204 break; 223 break;
205 case 1: 224 case 1:
206 irq_ptr->perf_stat_enabled = 1; 225 irq_ptr->perf_stat_enabled = 1;
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 62b654af9237..35dfc3cb2aae 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -392,6 +392,20 @@ static inline void qdio_stop_polling(struct qdio_q *q)
392 set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); 392 set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT);
393} 393}
394 394
395static inline void account_sbals(struct qdio_q *q, int count)
396{
397 int pos = 0;
398
399 q->q_stats.nr_sbal_total += count;
400 if (count == QDIO_MAX_BUFFERS_MASK) {
401 q->q_stats.nr_sbals[7]++;
402 return;
403 }
404 while (count >>= 1)
405 pos++;
406 q->q_stats.nr_sbals[pos]++;
407}
408
395static void announce_buffer_error(struct qdio_q *q, int count) 409static void announce_buffer_error(struct qdio_q *q, int count)
396{ 410{
397 q->qdio_error |= QDIO_ERROR_SLSB_STATE; 411 q->qdio_error |= QDIO_ERROR_SLSB_STATE;
@@ -487,16 +501,22 @@ static int get_inbound_buffer_frontier(struct qdio_q *q)
487 q->first_to_check = add_buf(q->first_to_check, count); 501 q->first_to_check = add_buf(q->first_to_check, count);
488 if (atomic_sub(count, &q->nr_buf_used) == 0) 502 if (atomic_sub(count, &q->nr_buf_used) == 0)
489 qperf_inc(q, inbound_queue_full); 503 qperf_inc(q, inbound_queue_full);
504 if (q->irq_ptr->perf_stat_enabled)
505 account_sbals(q, count);
490 break; 506 break;
491 case SLSB_P_INPUT_ERROR: 507 case SLSB_P_INPUT_ERROR:
492 announce_buffer_error(q, count); 508 announce_buffer_error(q, count);
493 /* process the buffer, the upper layer will take care of it */ 509 /* process the buffer, the upper layer will take care of it */
494 q->first_to_check = add_buf(q->first_to_check, count); 510 q->first_to_check = add_buf(q->first_to_check, count);
495 atomic_sub(count, &q->nr_buf_used); 511 atomic_sub(count, &q->nr_buf_used);
512 if (q->irq_ptr->perf_stat_enabled)
513 account_sbals_error(q, count);
496 break; 514 break;
497 case SLSB_CU_INPUT_EMPTY: 515 case SLSB_CU_INPUT_EMPTY:
498 case SLSB_P_INPUT_NOT_INIT: 516 case SLSB_P_INPUT_NOT_INIT:
499 case SLSB_P_INPUT_ACK: 517 case SLSB_P_INPUT_ACK:
518 if (q->irq_ptr->perf_stat_enabled)
519 q->q_stats.nr_sbal_nop++;
500 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop"); 520 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop");
501 break; 521 break;
502 default: 522 default:
@@ -643,15 +663,21 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
643 663
644 atomic_sub(count, &q->nr_buf_used); 664 atomic_sub(count, &q->nr_buf_used);
645 q->first_to_check = add_buf(q->first_to_check, count); 665 q->first_to_check = add_buf(q->first_to_check, count);
666 if (q->irq_ptr->perf_stat_enabled)
667 account_sbals(q, count);
646 break; 668 break;
647 case SLSB_P_OUTPUT_ERROR: 669 case SLSB_P_OUTPUT_ERROR:
648 announce_buffer_error(q, count); 670 announce_buffer_error(q, count);
649 /* process the buffer, the upper layer will take care of it */ 671 /* process the buffer, the upper layer will take care of it */
650 q->first_to_check = add_buf(q->first_to_check, count); 672 q->first_to_check = add_buf(q->first_to_check, count);
651 atomic_sub(count, &q->nr_buf_used); 673 atomic_sub(count, &q->nr_buf_used);
674 if (q->irq_ptr->perf_stat_enabled)
675 account_sbals_error(q, count);
652 break; 676 break;
653 case SLSB_CU_OUTPUT_PRIMED: 677 case SLSB_CU_OUTPUT_PRIMED:
654 /* the adapter has not fetched the output yet */ 678 /* the adapter has not fetched the output yet */
679 if (q->irq_ptr->perf_stat_enabled)
680 q->q_stats.nr_sbal_nop++;
655 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out primed:%1d", q->nr); 681 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out primed:%1d", q->nr);
656 break; 682 break;
657 case SLSB_P_OUTPUT_NOT_INIT: 683 case SLSB_P_OUTPUT_NOT_INIT: