diff options
Diffstat (limited to 'drivers/s390/cio/qdio_main.c')
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 222 |
1 files changed, 99 insertions, 123 deletions
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 10cb0f8726e5..9e8a2914259b 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -380,11 +380,11 @@ inline void qdio_stop_polling(struct qdio_q *q) | |||
380 | 380 | ||
381 | /* show the card that we are not polling anymore */ | 381 | /* show the card that we are not polling anymore */ |
382 | if (is_qebsm(q)) { | 382 | if (is_qebsm(q)) { |
383 | set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, | 383 | set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT, |
384 | q->u.in.ack_count); | 384 | q->u.in.ack_count); |
385 | q->u.in.ack_count = 0; | 385 | q->u.in.ack_count = 0; |
386 | } else | 386 | } else |
387 | set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); | 387 | set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); |
388 | } | 388 | } |
389 | 389 | ||
390 | static void announce_buffer_error(struct qdio_q *q, int count) | 390 | static void announce_buffer_error(struct qdio_q *q, int count) |
@@ -419,15 +419,15 @@ static inline void inbound_primed(struct qdio_q *q, int count) | |||
419 | if (!q->u.in.polling) { | 419 | if (!q->u.in.polling) { |
420 | q->u.in.polling = 1; | 420 | q->u.in.polling = 1; |
421 | q->u.in.ack_count = count; | 421 | q->u.in.ack_count = count; |
422 | q->last_move_ftc = q->first_to_check; | 422 | q->u.in.ack_start = q->first_to_check; |
423 | return; | 423 | return; |
424 | } | 424 | } |
425 | 425 | ||
426 | /* delete the previous ACK's */ | 426 | /* delete the previous ACK's */ |
427 | set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, | 427 | set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT, |
428 | q->u.in.ack_count); | 428 | q->u.in.ack_count); |
429 | q->u.in.ack_count = count; | 429 | q->u.in.ack_count = count; |
430 | q->last_move_ftc = q->first_to_check; | 430 | q->u.in.ack_start = q->first_to_check; |
431 | return; | 431 | return; |
432 | } | 432 | } |
433 | 433 | ||
@@ -439,14 +439,13 @@ static inline void inbound_primed(struct qdio_q *q, int count) | |||
439 | if (q->u.in.polling) { | 439 | if (q->u.in.polling) { |
440 | /* reset the previous ACK but first set the new one */ | 440 | /* reset the previous ACK but first set the new one */ |
441 | set_buf_state(q, new, SLSB_P_INPUT_ACK); | 441 | set_buf_state(q, new, SLSB_P_INPUT_ACK); |
442 | set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); | 442 | set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); |
443 | } | 443 | } else { |
444 | else { | ||
445 | q->u.in.polling = 1; | 444 | q->u.in.polling = 1; |
446 | set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK); | 445 | set_buf_state(q, new, SLSB_P_INPUT_ACK); |
447 | } | 446 | } |
448 | 447 | ||
449 | q->last_move_ftc = new; | 448 | q->u.in.ack_start = new; |
450 | count--; | 449 | count--; |
451 | if (!count) | 450 | if (!count) |
452 | return; | 451 | return; |
@@ -455,7 +454,7 @@ static inline void inbound_primed(struct qdio_q *q, int count) | |||
455 | * Need to change all PRIMED buffers to NOT_INIT, otherwise | 454 | * Need to change all PRIMED buffers to NOT_INIT, otherwise |
456 | * we're loosing initiative in the thinint code. | 455 | * we're loosing initiative in the thinint code. |
457 | */ | 456 | */ |
458 | set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT, | 457 | set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT, |
459 | count); | 458 | count); |
460 | } | 459 | } |
461 | 460 | ||
@@ -523,7 +522,8 @@ int qdio_inbound_q_moved(struct qdio_q *q) | |||
523 | 522 | ||
524 | bufnr = get_inbound_buffer_frontier(q); | 523 | bufnr = get_inbound_buffer_frontier(q); |
525 | 524 | ||
526 | if ((bufnr != q->last_move_ftc) || q->qdio_error) { | 525 | if ((bufnr != q->last_move) || q->qdio_error) { |
526 | q->last_move = bufnr; | ||
527 | if (!need_siga_sync(q) && !pci_out_supported(q)) | 527 | if (!need_siga_sync(q) && !pci_out_supported(q)) |
528 | q->u.in.timestamp = get_usecs(); | 528 | q->u.in.timestamp = get_usecs(); |
529 | 529 | ||
@@ -570,29 +570,30 @@ static int qdio_inbound_q_done(struct qdio_q *q) | |||
570 | } | 570 | } |
571 | } | 571 | } |
572 | 572 | ||
573 | void qdio_kick_inbound_handler(struct qdio_q *q) | 573 | void qdio_kick_handler(struct qdio_q *q) |
574 | { | 574 | { |
575 | int count, start, end; | 575 | int start = q->first_to_kick; |
576 | 576 | int end = q->first_to_check; | |
577 | qdio_perf_stat_inc(&perf_stats.inbound_handler); | 577 | int count; |
578 | |||
579 | start = q->first_to_kick; | ||
580 | end = q->first_to_check; | ||
581 | if (end >= start) | ||
582 | count = end - start; | ||
583 | else | ||
584 | count = end + QDIO_MAX_BUFFERS_PER_Q - start; | ||
585 | |||
586 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); | ||
587 | 578 | ||
588 | if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) | 579 | if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) |
589 | return; | 580 | return; |
590 | 581 | ||
591 | q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, | 582 | count = sub_buf(end, start); |
592 | start, count, q->irq_ptr->int_parm); | 583 | |
584 | if (q->is_input_q) { | ||
585 | qdio_perf_stat_inc(&perf_stats.inbound_handler); | ||
586 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); | ||
587 | } else { | ||
588 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: nr:%1d", q->nr); | ||
589 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); | ||
590 | } | ||
591 | |||
592 | q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, | ||
593 | q->irq_ptr->int_parm); | ||
593 | 594 | ||
594 | /* for the next time */ | 595 | /* for the next time */ |
595 | q->first_to_kick = q->first_to_check; | 596 | q->first_to_kick = end; |
596 | q->qdio_error = 0; | 597 | q->qdio_error = 0; |
597 | } | 598 | } |
598 | 599 | ||
@@ -603,7 +604,7 @@ again: | |||
603 | if (!qdio_inbound_q_moved(q)) | 604 | if (!qdio_inbound_q_moved(q)) |
604 | return; | 605 | return; |
605 | 606 | ||
606 | qdio_kick_inbound_handler(q); | 607 | qdio_kick_handler(q); |
607 | 608 | ||
608 | if (!qdio_inbound_q_done(q)) | 609 | if (!qdio_inbound_q_done(q)) |
609 | /* means poll time is not yet over */ | 610 | /* means poll time is not yet over */ |
@@ -698,21 +699,21 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) | |||
698 | 699 | ||
699 | bufnr = get_outbound_buffer_frontier(q); | 700 | bufnr = get_outbound_buffer_frontier(q); |
700 | 701 | ||
701 | if ((bufnr != q->last_move_ftc) || q->qdio_error) { | 702 | if ((bufnr != q->last_move) || q->qdio_error) { |
702 | q->last_move_ftc = bufnr; | 703 | q->last_move = bufnr; |
703 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); | 704 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); |
704 | return 1; | 705 | return 1; |
705 | } else | 706 | } else |
706 | return 0; | 707 | return 0; |
707 | } | 708 | } |
708 | 709 | ||
709 | static void qdio_kick_outbound_q(struct qdio_q *q) | 710 | static int qdio_kick_outbound_q(struct qdio_q *q) |
710 | { | 711 | { |
711 | unsigned int busy_bit; | 712 | unsigned int busy_bit; |
712 | int cc; | 713 | int cc; |
713 | 714 | ||
714 | if (!need_siga_out(q)) | 715 | if (!need_siga_out(q)) |
715 | return; | 716 | return 0; |
716 | 717 | ||
717 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); | 718 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); |
718 | qdio_perf_stat_inc(&perf_stats.siga_out); | 719 | qdio_perf_stat_inc(&perf_stats.siga_out); |
@@ -724,75 +725,37 @@ static void qdio_kick_outbound_q(struct qdio_q *q) | |||
724 | case 2: | 725 | case 2: |
725 | if (busy_bit) { | 726 | if (busy_bit) { |
726 | DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); | 727 | DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); |
727 | q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY; | 728 | cc |= QDIO_ERROR_SIGA_BUSY; |
728 | } else { | 729 | } else |
729 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", | 730 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); |
730 | q->nr); | ||
731 | q->qdio_error = cc; | ||
732 | } | ||
733 | break; | 731 | break; |
734 | case 1: | 732 | case 1: |
735 | case 3: | 733 | case 3: |
736 | DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); | 734 | DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); |
737 | q->qdio_error = cc; | ||
738 | break; | 735 | break; |
739 | } | 736 | } |
740 | } | 737 | return cc; |
741 | |||
742 | static void qdio_kick_outbound_handler(struct qdio_q *q) | ||
743 | { | ||
744 | int start, end, count; | ||
745 | |||
746 | start = q->first_to_kick; | ||
747 | end = q->last_move_ftc; | ||
748 | if (end >= start) | ||
749 | count = end - start; | ||
750 | else | ||
751 | count = end + QDIO_MAX_BUFFERS_PER_Q - start; | ||
752 | |||
753 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickouth: %1d", q->nr); | ||
754 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); | ||
755 | |||
756 | if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) | ||
757 | return; | ||
758 | |||
759 | q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, | ||
760 | q->irq_ptr->int_parm); | ||
761 | |||
762 | /* for the next time: */ | ||
763 | q->first_to_kick = q->last_move_ftc; | ||
764 | q->qdio_error = 0; | ||
765 | } | 738 | } |
766 | 739 | ||
767 | static void __qdio_outbound_processing(struct qdio_q *q) | 740 | static void __qdio_outbound_processing(struct qdio_q *q) |
768 | { | 741 | { |
769 | unsigned long flags; | ||
770 | |||
771 | qdio_perf_stat_inc(&perf_stats.tasklet_outbound); | 742 | qdio_perf_stat_inc(&perf_stats.tasklet_outbound); |
772 | spin_lock_irqsave(&q->lock, flags); | ||
773 | |||
774 | BUG_ON(atomic_read(&q->nr_buf_used) < 0); | 743 | BUG_ON(atomic_read(&q->nr_buf_used) < 0); |
775 | 744 | ||
776 | if (qdio_outbound_q_moved(q)) | 745 | if (qdio_outbound_q_moved(q)) |
777 | qdio_kick_outbound_handler(q); | 746 | qdio_kick_handler(q); |
778 | |||
779 | spin_unlock_irqrestore(&q->lock, flags); | ||
780 | 747 | ||
781 | if (queue_type(q) == QDIO_ZFCP_QFMT) { | 748 | if (queue_type(q) == QDIO_ZFCP_QFMT) |
782 | if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) | 749 | if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) |
783 | tasklet_schedule(&q->tasklet); | 750 | goto sched; |
784 | return; | ||
785 | } | ||
786 | 751 | ||
787 | /* bail out for HiperSockets unicast queues */ | 752 | /* bail out for HiperSockets unicast queues */ |
788 | if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q)) | 753 | if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q)) |
789 | return; | 754 | return; |
790 | 755 | ||
791 | if ((queue_type(q) == QDIO_IQDIO_QFMT) && | 756 | if ((queue_type(q) == QDIO_IQDIO_QFMT) && |
792 | (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) { | 757 | (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) |
793 | tasklet_schedule(&q->tasklet); | 758 | goto sched; |
794 | return; | ||
795 | } | ||
796 | 759 | ||
797 | if (q->u.out.pci_out_enabled) | 760 | if (q->u.out.pci_out_enabled) |
798 | return; | 761 | return; |
@@ -810,6 +773,12 @@ static void __qdio_outbound_processing(struct qdio_q *q) | |||
810 | qdio_perf_stat_inc(&perf_stats.debug_tl_out_timer); | 773 | qdio_perf_stat_inc(&perf_stats.debug_tl_out_timer); |
811 | } | 774 | } |
812 | } | 775 | } |
776 | return; | ||
777 | |||
778 | sched: | ||
779 | if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) | ||
780 | return; | ||
781 | tasklet_schedule(&q->tasklet); | ||
813 | } | 782 | } |
814 | 783 | ||
815 | /* outbound tasklet */ | 784 | /* outbound tasklet */ |
@@ -822,6 +791,9 @@ void qdio_outbound_processing(unsigned long data) | |||
822 | void qdio_outbound_timer(unsigned long data) | 791 | void qdio_outbound_timer(unsigned long data) |
823 | { | 792 | { |
824 | struct qdio_q *q = (struct qdio_q *)data; | 793 | struct qdio_q *q = (struct qdio_q *)data; |
794 | |||
795 | if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) | ||
796 | return; | ||
825 | tasklet_schedule(&q->tasklet); | 797 | tasklet_schedule(&q->tasklet); |
826 | } | 798 | } |
827 | 799 | ||
@@ -863,6 +835,9 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) | |||
863 | int i; | 835 | int i; |
864 | struct qdio_q *q; | 836 | struct qdio_q *q; |
865 | 837 | ||
838 | if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) | ||
839 | return; | ||
840 | |||
866 | qdio_perf_stat_inc(&perf_stats.pci_int); | 841 | qdio_perf_stat_inc(&perf_stats.pci_int); |
867 | 842 | ||
868 | for_each_input_queue(irq_ptr, q, i) | 843 | for_each_input_queue(irq_ptr, q, i) |
@@ -1065,8 +1040,9 @@ EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); | |||
1065 | * @cdev: associated ccw device | 1040 | * @cdev: associated ccw device |
1066 | * @how: use halt or clear to shutdown | 1041 | * @how: use halt or clear to shutdown |
1067 | * | 1042 | * |
1068 | * This function calls qdio_shutdown() for @cdev with method @how | 1043 | * This function calls qdio_shutdown() for @cdev with method @how. |
1069 | * and on success qdio_free() for @cdev. | 1044 | * and qdio_free(). The qdio_free() return value is ignored since |
1045 | * !irq_ptr is already checked. | ||
1070 | */ | 1046 | */ |
1071 | int qdio_cleanup(struct ccw_device *cdev, int how) | 1047 | int qdio_cleanup(struct ccw_device *cdev, int how) |
1072 | { | 1048 | { |
@@ -1077,8 +1053,8 @@ int qdio_cleanup(struct ccw_device *cdev, int how) | |||
1077 | return -ENODEV; | 1053 | return -ENODEV; |
1078 | 1054 | ||
1079 | rc = qdio_shutdown(cdev, how); | 1055 | rc = qdio_shutdown(cdev, how); |
1080 | if (rc == 0) | 1056 | |
1081 | rc = qdio_free(cdev); | 1057 | qdio_free(cdev); |
1082 | return rc; | 1058 | return rc; |
1083 | } | 1059 | } |
1084 | EXPORT_SYMBOL_GPL(qdio_cleanup); | 1060 | EXPORT_SYMBOL_GPL(qdio_cleanup); |
@@ -1090,11 +1066,11 @@ static void qdio_shutdown_queues(struct ccw_device *cdev) | |||
1090 | int i; | 1066 | int i; |
1091 | 1067 | ||
1092 | for_each_input_queue(irq_ptr, q, i) | 1068 | for_each_input_queue(irq_ptr, q, i) |
1093 | tasklet_disable(&q->tasklet); | 1069 | tasklet_kill(&q->tasklet); |
1094 | 1070 | ||
1095 | for_each_output_queue(irq_ptr, q, i) { | 1071 | for_each_output_queue(irq_ptr, q, i) { |
1096 | tasklet_disable(&q->tasklet); | ||
1097 | del_timer(&q->u.out.timer); | 1072 | del_timer(&q->u.out.timer); |
1073 | tasklet_kill(&q->tasklet); | ||
1098 | } | 1074 | } |
1099 | } | 1075 | } |
1100 | 1076 | ||
@@ -1112,6 +1088,7 @@ int qdio_shutdown(struct ccw_device *cdev, int how) | |||
1112 | if (!irq_ptr) | 1088 | if (!irq_ptr) |
1113 | return -ENODEV; | 1089 | return -ENODEV; |
1114 | 1090 | ||
1091 | BUG_ON(irqs_disabled()); | ||
1115 | DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no); | 1092 | DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no); |
1116 | 1093 | ||
1117 | mutex_lock(&irq_ptr->setup_mutex); | 1094 | mutex_lock(&irq_ptr->setup_mutex); |
@@ -1124,6 +1101,12 @@ int qdio_shutdown(struct ccw_device *cdev, int how) | |||
1124 | return 0; | 1101 | return 0; |
1125 | } | 1102 | } |
1126 | 1103 | ||
1104 | /* | ||
1105 | * Indicate that the device is going down. Scheduling the queue | ||
1106 | * tasklets is forbidden from here on. | ||
1107 | */ | ||
1108 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); | ||
1109 | |||
1127 | tiqdio_remove_input_queues(irq_ptr); | 1110 | tiqdio_remove_input_queues(irq_ptr); |
1128 | qdio_shutdown_queues(cdev); | 1111 | qdio_shutdown_queues(cdev); |
1129 | qdio_shutdown_debug_entries(irq_ptr, cdev); | 1112 | qdio_shutdown_debug_entries(irq_ptr, cdev); |
@@ -1403,9 +1386,8 @@ int qdio_activate(struct ccw_device *cdev) | |||
1403 | switch (irq_ptr->state) { | 1386 | switch (irq_ptr->state) { |
1404 | case QDIO_IRQ_STATE_STOPPED: | 1387 | case QDIO_IRQ_STATE_STOPPED: |
1405 | case QDIO_IRQ_STATE_ERR: | 1388 | case QDIO_IRQ_STATE_ERR: |
1406 | mutex_unlock(&irq_ptr->setup_mutex); | 1389 | rc = -EIO; |
1407 | qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); | 1390 | break; |
1408 | return -EIO; | ||
1409 | default: | 1391 | default: |
1410 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE); | 1392 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE); |
1411 | rc = 0; | 1393 | rc = 0; |
@@ -1442,10 +1424,10 @@ static inline int buf_in_between(int bufnr, int start, int count) | |||
1442 | * @bufnr: first buffer to process | 1424 | * @bufnr: first buffer to process |
1443 | * @count: how many buffers are emptied | 1425 | * @count: how many buffers are emptied |
1444 | */ | 1426 | */ |
1445 | static void handle_inbound(struct qdio_q *q, unsigned int callflags, | 1427 | static int handle_inbound(struct qdio_q *q, unsigned int callflags, |
1446 | int bufnr, int count) | 1428 | int bufnr, int count) |
1447 | { | 1429 | { |
1448 | int used, cc, diff; | 1430 | int used, diff; |
1449 | 1431 | ||
1450 | if (!q->u.in.polling) | 1432 | if (!q->u.in.polling) |
1451 | goto set; | 1433 | goto set; |
@@ -1456,19 +1438,18 @@ static void handle_inbound(struct qdio_q *q, unsigned int callflags, | |||
1456 | q->u.in.polling = 0; | 1438 | q->u.in.polling = 0; |
1457 | q->u.in.ack_count = 0; | 1439 | q->u.in.ack_count = 0; |
1458 | goto set; | 1440 | goto set; |
1459 | } else if (buf_in_between(q->last_move_ftc, bufnr, count)) { | 1441 | } else if (buf_in_between(q->u.in.ack_start, bufnr, count)) { |
1460 | if (is_qebsm(q)) { | 1442 | if (is_qebsm(q)) { |
1461 | /* partial overwrite, just update last_move_ftc */ | 1443 | /* partial overwrite, just update ack_start */ |
1462 | diff = add_buf(bufnr, count); | 1444 | diff = add_buf(bufnr, count); |
1463 | diff = sub_buf(diff, q->last_move_ftc); | 1445 | diff = sub_buf(diff, q->u.in.ack_start); |
1464 | q->u.in.ack_count -= diff; | 1446 | q->u.in.ack_count -= diff; |
1465 | if (q->u.in.ack_count <= 0) { | 1447 | if (q->u.in.ack_count <= 0) { |
1466 | q->u.in.polling = 0; | 1448 | q->u.in.polling = 0; |
1467 | q->u.in.ack_count = 0; | 1449 | q->u.in.ack_count = 0; |
1468 | /* TODO: must we set last_move_ftc to something meaningful? */ | ||
1469 | goto set; | 1450 | goto set; |
1470 | } | 1451 | } |
1471 | q->last_move_ftc = add_buf(q->last_move_ftc, diff); | 1452 | q->u.in.ack_start = add_buf(q->u.in.ack_start, diff); |
1472 | } | 1453 | } |
1473 | else | 1454 | else |
1474 | /* the only ACK will be deleted, so stop polling */ | 1455 | /* the only ACK will be deleted, so stop polling */ |
@@ -1483,13 +1464,11 @@ set: | |||
1483 | 1464 | ||
1484 | /* no need to signal as long as the adapter had free buffers */ | 1465 | /* no need to signal as long as the adapter had free buffers */ |
1485 | if (used) | 1466 | if (used) |
1486 | return; | 1467 | return 0; |
1487 | 1468 | ||
1488 | if (need_siga_in(q)) { | 1469 | if (need_siga_in(q)) |
1489 | cc = qdio_siga_input(q); | 1470 | return qdio_siga_input(q); |
1490 | if (cc) | 1471 | return 0; |
1491 | q->qdio_error = cc; | ||
1492 | } | ||
1493 | } | 1472 | } |
1494 | 1473 | ||
1495 | /** | 1474 | /** |
@@ -1499,11 +1478,11 @@ set: | |||
1499 | * @bufnr: first buffer to process | 1478 | * @bufnr: first buffer to process |
1500 | * @count: how many buffers are filled | 1479 | * @count: how many buffers are filled |
1501 | */ | 1480 | */ |
1502 | static void handle_outbound(struct qdio_q *q, unsigned int callflags, | 1481 | static int handle_outbound(struct qdio_q *q, unsigned int callflags, |
1503 | int bufnr, int count) | 1482 | int bufnr, int count) |
1504 | { | 1483 | { |
1505 | unsigned char state; | 1484 | unsigned char state; |
1506 | int used; | 1485 | int used, rc = 0; |
1507 | 1486 | ||
1508 | qdio_perf_stat_inc(&perf_stats.outbound_handler); | 1487 | qdio_perf_stat_inc(&perf_stats.outbound_handler); |
1509 | 1488 | ||
@@ -1518,27 +1497,26 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, | |||
1518 | 1497 | ||
1519 | if (queue_type(q) == QDIO_IQDIO_QFMT) { | 1498 | if (queue_type(q) == QDIO_IQDIO_QFMT) { |
1520 | if (multicast_outbound(q)) | 1499 | if (multicast_outbound(q)) |
1521 | qdio_kick_outbound_q(q); | 1500 | rc = qdio_kick_outbound_q(q); |
1522 | else | 1501 | else |
1523 | if ((q->irq_ptr->ssqd_desc.mmwc > 1) && | 1502 | if ((q->irq_ptr->ssqd_desc.mmwc > 1) && |
1524 | (count > 1) && | 1503 | (count > 1) && |
1525 | (count <= q->irq_ptr->ssqd_desc.mmwc)) { | 1504 | (count <= q->irq_ptr->ssqd_desc.mmwc)) { |
1526 | /* exploit enhanced SIGA */ | 1505 | /* exploit enhanced SIGA */ |
1527 | q->u.out.use_enh_siga = 1; | 1506 | q->u.out.use_enh_siga = 1; |
1528 | qdio_kick_outbound_q(q); | 1507 | rc = qdio_kick_outbound_q(q); |
1529 | } else { | 1508 | } else { |
1530 | /* | 1509 | /* |
1531 | * One siga-w per buffer required for unicast | 1510 | * One siga-w per buffer required for unicast |
1532 | * HiperSockets. | 1511 | * HiperSockets. |
1533 | */ | 1512 | */ |
1534 | q->u.out.use_enh_siga = 0; | 1513 | q->u.out.use_enh_siga = 0; |
1535 | while (count--) | 1514 | while (count--) { |
1536 | qdio_kick_outbound_q(q); | 1515 | rc = qdio_kick_outbound_q(q); |
1516 | if (rc) | ||
1517 | goto out; | ||
1518 | } | ||
1537 | } | 1519 | } |
1538 | |||
1539 | /* report CC=2 conditions synchronously */ | ||
1540 | if (q->qdio_error) | ||
1541 | __qdio_outbound_processing(q); | ||
1542 | goto out; | 1520 | goto out; |
1543 | } | 1521 | } |
1544 | 1522 | ||
@@ -1550,14 +1528,14 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, | |||
1550 | /* try to fast requeue buffers */ | 1528 | /* try to fast requeue buffers */ |
1551 | get_buf_state(q, prev_buf(bufnr), &state, 0); | 1529 | get_buf_state(q, prev_buf(bufnr), &state, 0); |
1552 | if (state != SLSB_CU_OUTPUT_PRIMED) | 1530 | if (state != SLSB_CU_OUTPUT_PRIMED) |
1553 | qdio_kick_outbound_q(q); | 1531 | rc = qdio_kick_outbound_q(q); |
1554 | else { | 1532 | else { |
1555 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); | 1533 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); |
1556 | qdio_perf_stat_inc(&perf_stats.fast_requeue); | 1534 | qdio_perf_stat_inc(&perf_stats.fast_requeue); |
1557 | } | 1535 | } |
1558 | out: | 1536 | out: |
1559 | /* Fixme: could wait forever if called from process context */ | ||
1560 | tasklet_schedule(&q->tasklet); | 1537 | tasklet_schedule(&q->tasklet); |
1538 | return rc; | ||
1561 | } | 1539 | } |
1562 | 1540 | ||
1563 | /** | 1541 | /** |
@@ -1596,14 +1574,12 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, | |||
1596 | return -EBUSY; | 1574 | return -EBUSY; |
1597 | 1575 | ||
1598 | if (callflags & QDIO_FLAG_SYNC_INPUT) | 1576 | if (callflags & QDIO_FLAG_SYNC_INPUT) |
1599 | handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr, | 1577 | return handle_inbound(irq_ptr->input_qs[q_nr], |
1600 | count); | 1578 | callflags, bufnr, count); |
1601 | else if (callflags & QDIO_FLAG_SYNC_OUTPUT) | 1579 | else if (callflags & QDIO_FLAG_SYNC_OUTPUT) |
1602 | handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr, | 1580 | return handle_outbound(irq_ptr->output_qs[q_nr], |
1603 | count); | 1581 | callflags, bufnr, count); |
1604 | else | 1582 | return -EINVAL; |
1605 | return -EINVAL; | ||
1606 | return 0; | ||
1607 | } | 1583 | } |
1608 | EXPORT_SYMBOL_GPL(do_QDIO); | 1584 | EXPORT_SYMBOL_GPL(do_QDIO); |
1609 | 1585 | ||