diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index cba64e4cfcd470492cdf9235c0a86ac2f1ba30a2..f770018fe1d5c02c691686b32115b59bf1d6472e 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -996,18 +996,25 @@ __qdio_outbound_processing(struct qdio_q *q) if (qdio_has_outbound_q_moved(q)) qdio_kick_outbound_handler(q); - if (q->is_iqdio_q) { + if (q->queue_type == QDIO_ZFCP_QFMT) { + if ((!q->hydra_gives_outbound_pcis) && + (!qdio_is_outbound_q_done(q))) + qdio_mark_q(q); + } + else if (((!q->is_iqdio_q) && (!q->is_pci_out)) || + (q->queue_type == QDIO_IQDIO_QFMT_ASYNCH)) { /* - * for asynchronous queues, we better check, if the sent - * buffer is already switched from PRIMED to EMPTY. + * make sure buffer switch from PRIMED to EMPTY is noticed + * and outbound_handler is called */ - if ((q->queue_type == QDIO_IQDIO_QFMT_ASYNCH) && - !qdio_is_outbound_q_done(q)) - qdio_mark_q(q); - - } else if (!q->hydra_gives_outbound_pcis) - if (!qdio_is_outbound_q_done(q)) - qdio_mark_q(q); + if (qdio_is_outbound_q_done(q)) { + del_timer(&q->timer); + } else { + if (!timer_pending(&q->timer)) + mod_timer(&q->timer, jiffies + + QDIO_FORCE_CHECK_TIMEOUT); + } + } qdio_release_q(q); } @@ -1826,6 +1833,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->queue_type = QDIO_IQDIO_QFMT_ASYNCH; q->int_parm=int_parm; q->is_input_q=0; + q->is_pci_out = 0; q->schid = irq_ptr->schid; q->cdev = cdev; q->irq_ptr = irq_ptr; @@ -1838,6 +1846,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev, q->tasklet.data=(unsigned long)q; q->tasklet.func=(void(*)(unsigned long)) &qdio_outbound_processing; + q->timer.function=(void(*)(unsigned long)) + &qdio_outbound_processing; + q->timer.data = (long)q; + init_timer(&q->timer); atomic_set(&q->busy_siga_counter,0); q->timing.busy_start=0; @@ -2635,6 +2647,7 @@ qdio_shutdown(struct ccw_device *cdev, int how) for (i=0;ino_output_qs;i++) { tasklet_kill(&irq_ptr->output_qs[i]->tasklet); + del_timer(&irq_ptr->output_qs[i]->timer); wait_event_interruptible_timeout(cdev->private->wait_q, !atomic_read(&irq_ptr-> output_qs[i]-> @@ -3458,6 +3471,10 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, qdio_perf_stat_inc(&perf_stats.outbound_cnt); return; } + if (callflags & QDIO_FLAG_PCI_OUT) + q->is_pci_out = 1; + else + q->is_pci_out = 0; if (q->is_iqdio_q) { /* one siga for every sbal */ while (count--) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 2895392eaae4392a5d9be226ca18c1a267367d50..6d7aad18f6f0132fa24d5b10b9c5d9f88638347a 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -60,6 +60,7 @@ #define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10) #define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ) #define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ) +#define QDIO_FORCE_CHECK_TIMEOUT (10*HZ) enum qdio_irq_states { QDIO_IRQ_STATE_INACTIVE, @@ -511,8 +512,8 @@ struct qdio_q { void *irq_ptr; -#ifdef QDIO_USE_TIMERS_FOR_POLLING struct timer_list timer; +#ifdef QDIO_USE_TIMERS_FOR_POLLING atomic_t timer_already_set; spinlock_t timer_lock; #else /* QDIO_USE_TIMERS_FOR_POLLING */ @@ -558,6 +559,7 @@ struct qdio_q { } timing; atomic_t busy_siga_counter; unsigned int queue_type; + unsigned int is_pci_out; /* leave this member at the end. won't be cleared in qdio_fill_qs */ struct slib *slib; /* a page is allocated under this pointer, diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 0324835130278f6b9494037871d53e5f836b73b4..134f08c200d25579e0536be69c5cc6dff9d2faa8 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -2816,6 +2816,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, struct qeth_qdio_out_buffer *buf; int rc; int i; + unsigned int qdio_flags; QETH_DBF_TEXT(trace, 6, "flushbuf"); @@ -2859,13 +2860,13 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, queue->card->perf_stats.outbound_do_qdio_start_time = qeth_get_micros(); } + qdio_flags = QDIO_FLAG_SYNC_OUTPUT; if (under_int) - rc = do_QDIO(CARD_DDEV(queue->card), - QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT, - queue->queue_no, index, count, NULL); - else - rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT, - queue->queue_no, index, count, NULL); + qdio_flags |= QDIO_FLAG_UNDER_INTERRUPT; + if (atomic_read(&queue->set_pci_flags_count)) + qdio_flags |= QDIO_FLAG_PCI_OUT; + rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags, + queue->queue_no, index, count, NULL); if (queue->card->options.performance_stats) queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - @@ -8498,6 +8499,7 @@ __qeth_reboot_event_card(struct device *dev, void *data) card = (struct qeth_card *) dev->driver_data; qeth_clear_ip_list(card, 0, 0); qeth_qdio_clear_card(card, 0); + qeth_clear_qdio_buffers(card); return 0; } diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h index 127f72e774197d9bdccb02029b9e01e443cb8c26..74db1dc10a7d60043a182333a5c815a3187a9000 100644 --- a/include/asm-s390/qdio.h +++ b/include/asm-s390/qdio.h @@ -120,6 +120,7 @@ extern unsigned long qdio_get_status(int irq); #define QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT 0x08 /* no effect on adapter interrupts */ #define QDIO_FLAG_DONT_SIGA 0x10 +#define QDIO_FLAG_PCI_OUT 0x20 extern int do_QDIO(struct ccw_device*, unsigned int flags, unsigned int queue_number,