diff options
Diffstat (limited to 'drivers/s390/cio/qdio_setup.c')
-rw-r--r-- | drivers/s390/cio/qdio_setup.c | 99 |
1 files changed, 15 insertions, 84 deletions
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 16ecd35b8e5..89107d0938c 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c | |||
@@ -1,12 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * driver/s390/cio/qdio_setup.c | ||
3 | * | ||
2 | * qdio queue initialization | 4 | * qdio queue initialization |
3 | * | 5 | * |
4 | * Copyright IBM Corp. 2008 | 6 | * Copyright (C) IBM Corp. 2008 |
5 | * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> | 7 | * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> |
6 | */ | 8 | */ |
7 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
8 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
9 | #include <linux/export.h> | ||
10 | #include <asm/qdio.h> | 11 | #include <asm/qdio.h> |
11 | 12 | ||
12 | #include "cio.h" | 13 | #include "cio.h" |
@@ -18,19 +19,6 @@ | |||
18 | #include "qdio_debug.h" | 19 | #include "qdio_debug.h" |
19 | 20 | ||
20 | static struct kmem_cache *qdio_q_cache; | 21 | static struct kmem_cache *qdio_q_cache; |
21 | static struct kmem_cache *qdio_aob_cache; | ||
22 | |||
23 | struct qaob *qdio_allocate_aob(void) | ||
24 | { | ||
25 | return kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC); | ||
26 | } | ||
27 | EXPORT_SYMBOL_GPL(qdio_allocate_aob); | ||
28 | |||
29 | void qdio_release_aob(struct qaob *aob) | ||
30 | { | ||
31 | kmem_cache_free(qdio_aob_cache, aob); | ||
32 | } | ||
33 | EXPORT_SYMBOL_GPL(qdio_release_aob); | ||
34 | 22 | ||
35 | /* | 23 | /* |
36 | * qebsm is only available under 64bit but the adapter sets the feature | 24 | * qebsm is only available under 64bit but the adapter sets the feature |
@@ -140,8 +128,10 @@ static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, | |||
140 | q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2); | 128 | q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2); |
141 | 129 | ||
142 | /* fill in sbal */ | 130 | /* fill in sbal */ |
143 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) | 131 | for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) { |
144 | q->sbal[j] = *sbals_array++; | 132 | q->sbal[j] = *sbals_array++; |
133 | BUG_ON((unsigned long)q->sbal[j] & 0xff); | ||
134 | } | ||
145 | 135 | ||
146 | /* fill in slib */ | 136 | /* fill in slib */ |
147 | if (i > 0) { | 137 | if (i > 0) { |
@@ -164,37 +154,29 @@ static void setup_queues(struct qdio_irq *irq_ptr, | |||
164 | struct qdio_q *q; | 154 | struct qdio_q *q; |
165 | void **input_sbal_array = qdio_init->input_sbal_addr_array; | 155 | void **input_sbal_array = qdio_init->input_sbal_addr_array; |
166 | void **output_sbal_array = qdio_init->output_sbal_addr_array; | 156 | void **output_sbal_array = qdio_init->output_sbal_addr_array; |
167 | struct qdio_outbuf_state *output_sbal_state_array = | ||
168 | qdio_init->output_sbal_state_array; | ||
169 | int i; | 157 | int i; |
170 | 158 | ||
171 | for_each_input_queue(irq_ptr, q, i) { | 159 | for_each_input_queue(irq_ptr, q, i) { |
172 | DBF_EVENT("inq:%1d", i); | 160 | DBF_EVENT("in-q:%1d", i); |
173 | setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); | 161 | setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); |
174 | 162 | ||
175 | q->is_input_q = 1; | 163 | q->is_input_q = 1; |
176 | q->u.in.queue_start_poll = qdio_init->queue_start_poll_array ? | 164 | q->u.in.queue_start_poll = qdio_init->queue_start_poll; |
177 | qdio_init->queue_start_poll_array[i] : NULL; | ||
178 | |||
179 | setup_storage_lists(q, irq_ptr, input_sbal_array, i); | 165 | setup_storage_lists(q, irq_ptr, input_sbal_array, i); |
180 | input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; | 166 | input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; |
181 | 167 | ||
182 | if (is_thinint_irq(irq_ptr)) { | 168 | if (is_thinint_irq(irq_ptr)) |
183 | tasklet_init(&q->tasklet, tiqdio_inbound_processing, | 169 | tasklet_init(&q->tasklet, tiqdio_inbound_processing, |
184 | (unsigned long) q); | 170 | (unsigned long) q); |
185 | } else { | 171 | else |
186 | tasklet_init(&q->tasklet, qdio_inbound_processing, | 172 | tasklet_init(&q->tasklet, qdio_inbound_processing, |
187 | (unsigned long) q); | 173 | (unsigned long) q); |
188 | } | ||
189 | } | 174 | } |
190 | 175 | ||
191 | for_each_output_queue(irq_ptr, q, i) { | 176 | for_each_output_queue(irq_ptr, q, i) { |
192 | DBF_EVENT("outq:%1d", i); | 177 | DBF_EVENT("outq:%1d", i); |
193 | setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i); | 178 | setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i); |
194 | 179 | ||
195 | q->u.out.sbal_state = output_sbal_state_array; | ||
196 | output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q; | ||
197 | |||
198 | q->is_input_q = 0; | 180 | q->is_input_q = 0; |
199 | q->u.out.scan_threshold = qdio_init->scan_threshold; | 181 | q->u.out.scan_threshold = qdio_init->scan_threshold; |
200 | setup_storage_lists(q, irq_ptr, output_sbal_array, i); | 182 | setup_storage_lists(q, irq_ptr, output_sbal_array, i); |
@@ -307,8 +289,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | |||
307 | 289 | ||
308 | check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token); | 290 | check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token); |
309 | process_ac_flags(irq_ptr, qdioac); | 291 | process_ac_flags(irq_ptr, qdioac); |
310 | DBF_EVENT("ac 1:%2x 2:%4x", qdioac, irq_ptr->ssqd_desc.qdioac2); | 292 | DBF_EVENT("qdioac:%4x", qdioac); |
311 | DBF_EVENT("3:%4x qib:%4x", irq_ptr->ssqd_desc.qdioac3, irq_ptr->qib.ac); | ||
312 | } | 293 | } |
313 | 294 | ||
314 | void qdio_release_memory(struct qdio_irq *irq_ptr) | 295 | void qdio_release_memory(struct qdio_irq *irq_ptr) |
@@ -330,19 +311,6 @@ void qdio_release_memory(struct qdio_irq *irq_ptr) | |||
330 | for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) { | 311 | for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) { |
331 | q = irq_ptr->output_qs[i]; | 312 | q = irq_ptr->output_qs[i]; |
332 | if (q) { | 313 | if (q) { |
333 | if (q->u.out.use_cq) { | ||
334 | int n; | ||
335 | |||
336 | for (n = 0; n < QDIO_MAX_BUFFERS_PER_Q; ++n) { | ||
337 | struct qaob *aob = q->u.out.aobs[n]; | ||
338 | if (aob) { | ||
339 | qdio_release_aob(aob); | ||
340 | q->u.out.aobs[n] = NULL; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | qdio_disable_async_operation(&q->u.out); | ||
345 | } | ||
346 | free_page((unsigned long) q->slib); | 314 | free_page((unsigned long) q->slib); |
347 | kmem_cache_free(qdio_q_cache, q); | 315 | kmem_cache_free(qdio_q_cache, q); |
348 | } | 316 | } |
@@ -377,7 +345,6 @@ static void setup_qdr(struct qdio_irq *irq_ptr, | |||
377 | int i; | 345 | int i; |
378 | 346 | ||
379 | irq_ptr->qdr->qfmt = qdio_init->q_format; | 347 | irq_ptr->qdr->qfmt = qdio_init->q_format; |
380 | irq_ptr->qdr->ac = qdio_init->qdr_ac; | ||
381 | irq_ptr->qdr->iqdcnt = qdio_init->no_input_qs; | 348 | irq_ptr->qdr->iqdcnt = qdio_init->no_input_qs; |
382 | irq_ptr->qdr->oqdcnt = qdio_init->no_output_qs; | 349 | irq_ptr->qdr->oqdcnt = qdio_init->no_output_qs; |
383 | irq_ptr->qdr->iqdsz = sizeof(struct qdesfmt0) / 4; /* size in words */ | 350 | irq_ptr->qdr->iqdsz = sizeof(struct qdesfmt0) / 4; /* size in words */ |
@@ -432,8 +399,9 @@ int qdio_setup_irq(struct qdio_initialize *init_data) | |||
432 | irq_ptr->int_parm = init_data->int_parm; | 399 | irq_ptr->int_parm = init_data->int_parm; |
433 | irq_ptr->nr_input_qs = init_data->no_input_qs; | 400 | irq_ptr->nr_input_qs = init_data->no_input_qs; |
434 | irq_ptr->nr_output_qs = init_data->no_output_qs; | 401 | irq_ptr->nr_output_qs = init_data->no_output_qs; |
402 | |||
403 | irq_ptr->schid = ccw_device_get_subchannel_id(init_data->cdev); | ||
435 | irq_ptr->cdev = init_data->cdev; | 404 | irq_ptr->cdev = init_data->cdev; |
436 | ccw_device_get_schid(irq_ptr->cdev, &irq_ptr->schid); | ||
437 | setup_queues(irq_ptr, init_data); | 405 | setup_queues(irq_ptr, init_data); |
438 | 406 | ||
439 | setup_qib(irq_ptr, init_data); | 407 | setup_qib(irq_ptr, init_data); |
@@ -480,7 +448,7 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, | |||
480 | char s[80]; | 448 | char s[80]; |
481 | 449 | ||
482 | snprintf(s, 80, "qdio: %s %s on SC %x using " | 450 | snprintf(s, 80, "qdio: %s %s on SC %x using " |
483 | "AI:%d QEBSM:%d PRI:%d TDD:%d SIGA:%s%s%s%s%s\n", | 451 | "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s\n", |
484 | dev_name(&cdev->dev), | 452 | dev_name(&cdev->dev), |
485 | (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : | 453 | (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : |
486 | ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), | 454 | ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), |
@@ -497,60 +465,23 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, | |||
497 | printk(KERN_INFO "%s", s); | 465 | printk(KERN_INFO "%s", s); |
498 | } | 466 | } |
499 | 467 | ||
500 | int qdio_enable_async_operation(struct qdio_output_q *outq) | ||
501 | { | ||
502 | outq->aobs = kzalloc(sizeof(struct qaob *) * QDIO_MAX_BUFFERS_PER_Q, | ||
503 | GFP_ATOMIC); | ||
504 | if (!outq->aobs) { | ||
505 | outq->use_cq = 0; | ||
506 | return -ENOMEM; | ||
507 | } | ||
508 | outq->use_cq = 1; | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | void qdio_disable_async_operation(struct qdio_output_q *q) | ||
513 | { | ||
514 | kfree(q->aobs); | ||
515 | q->aobs = NULL; | ||
516 | q->use_cq = 0; | ||
517 | } | ||
518 | |||
519 | int __init qdio_setup_init(void) | 468 | int __init qdio_setup_init(void) |
520 | { | 469 | { |
521 | int rc; | ||
522 | |||
523 | qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), | 470 | qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), |
524 | 256, 0, NULL); | 471 | 256, 0, NULL); |
525 | if (!qdio_q_cache) | 472 | if (!qdio_q_cache) |
526 | return -ENOMEM; | 473 | return -ENOMEM; |
527 | 474 | ||
528 | qdio_aob_cache = kmem_cache_create("qdio_aob", | ||
529 | sizeof(struct qaob), | ||
530 | sizeof(struct qaob), | ||
531 | 0, | ||
532 | NULL); | ||
533 | if (!qdio_aob_cache) { | ||
534 | rc = -ENOMEM; | ||
535 | goto free_qdio_q_cache; | ||
536 | } | ||
537 | |||
538 | /* Check for OSA/FCP thin interrupts (bit 67). */ | 475 | /* Check for OSA/FCP thin interrupts (bit 67). */ |
539 | DBF_EVENT("thinint:%1d", | 476 | DBF_EVENT("thinint:%1d", |
540 | (css_general_characteristics.aif_osa) ? 1 : 0); | 477 | (css_general_characteristics.aif_osa) ? 1 : 0); |
541 | 478 | ||
542 | /* Check for QEBSM support in general (bit 58). */ | 479 | /* Check for QEBSM support in general (bit 58). */ |
543 | DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0); | 480 | DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0); |
544 | rc = 0; | 481 | return 0; |
545 | out: | ||
546 | return rc; | ||
547 | free_qdio_q_cache: | ||
548 | kmem_cache_destroy(qdio_q_cache); | ||
549 | goto out; | ||
550 | } | 482 | } |
551 | 483 | ||
552 | void qdio_setup_exit(void) | 484 | void qdio_setup_exit(void) |
553 | { | 485 | { |
554 | kmem_cache_destroy(qdio_aob_cache); | ||
555 | kmem_cache_destroy(qdio_q_cache); | 486 | kmem_cache_destroy(qdio_q_cache); |
556 | } | 487 | } |