From: Hans-Joachim Picht <hpicht@redhat.com> Date: Tue, 20 Jan 2009 16:58:58 +0100 Subject: [s390] qdio: only 1 buffer in INPUT_PROCESSING state Message-id: 20090120155858.GF21694@redhat.com O-Subject: [RHEL5 U4 PATCH 6/8] s390 - qdio: not more than 1 buffer in INPUT_PROCESSING state Bugzilla: 479867 RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com> Description ============ Symptom: HiperSocket traffic failure with z/OS tcpip Problem: z/OS tcpip is configured with IQDMULTIWRITE (enhanced SIGA) for HiperSockets. A Linux dump shows that one inbound buffer is still in the INPUT_PROCESSING state, even though the two following buffers are already in INPUT_NOT_INIT state and qdio polling is off. That means interrupt for further incoming buffers is suppressed. Solution: While qdio is polling make sure a buffer previously set to INPUT_PROCESSING state is changed into INPUT_NOT_INIT state as soon as a following buffer is changed to INPUT_PROCESSING state. Bugzilla ========= BZ 479867 https://bugzilla.redhat.com/show_bug.cgi?id=479867 Upstream status of the patch: ============================= The patch has not been posted upstream since it is not applicable in the upstream code base due to a complete qdio driver rewrite which is upstream as of 2.6.27 and does not contain this problem Test status: ============ The patch has been tested and fixes the problem. The fix has been verified by the IBM test department. Please ACK. With best regards, --Hans diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index c10667e..6060304 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -651,9 +651,11 @@ qdio_qebsm_get_inbound_buffer_frontier(struct qdio_q *q) struct qdio_irq *irq; unsigned char state; int tmp, ftc, count, cnt; +#ifdef QDIO_USE_PROCESSING_STATE + int processed; +#endif char dbf_text[15]; - irq = (struct qdio_irq *) q->irq_ptr; ftc = q->first_to_check; count = qdio_min(atomic_read(&q->number_of_buffers_used), @@ -694,6 +696,13 @@ qdio_qebsm_get_inbound_buffer_frontier(struct qdio_q *q) cnt = 1; tmp += set_slsb(q, &ftc, SLSB_P_INPUT_PROCESSING, &cnt); + if (atomic_read(&q->polling)) { + /* change previous SLSB_P_INPUT_PROCESSING slsb */ + processed = (q->first_to_check + QDIO_MAX_BUFFERS_PER_Q - 1) & + (QDIO_MAX_BUFFERS_PER_Q - 1); + cnt = 1; + set_slsb(q, &processed, SLSB_P_INPUT_NOT_INIT, &cnt); + } atomic_set(&q->polling, 1); #else tmp = set_slsb(q, &ftc, SLSB_P_INPUT_NOT_INIT, &cnt); @@ -1040,6 +1049,8 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q) #endif /* CONFIG_QDIO_DEBUG */ #ifdef QDIO_USE_PROCESSING_STATE int last_position=-1; + int processed; + int was_polling; #endif /* QDIO_USE_PROCESSING_STATE */ QDIO_DBF_TEXT4(0,trace,"getibfro"); @@ -1057,6 +1068,9 @@ qdio_get_inbound_buffer_frontier(struct qdio_q *q) */ first_not_to_check=f+qdio_min(atomic_read(&q->number_of_buffers_used), (QDIO_MAX_BUFFERS_PER_Q-1)); +#ifdef QDIO_USE_PROCESSING_STATE + was_polling = atomic_read(&q->polling); +#endif /* * we don't use this one, as a PCI or we after a thin interrupt @@ -1146,13 +1160,21 @@ check_next: break; } out: - q->first_to_check=f_mod_no; #ifdef QDIO_USE_PROCESSING_STATE - if (last_position>=0) + if (last_position>=0) { set_slsb(q, &last_position, SLSB_P_INPUT_PROCESSING, &count); + if (was_polling) { + /* change previous SLSB_P_INPUT_PROCESSING slsb */ + processed = (q->first_to_check + QDIO_MAX_BUFFERS_PER_Q - 1) & + (QDIO_MAX_BUFFERS_PER_Q - 1); + if (q->slsb.acc.val[processed] == SLSB_P_INPUT_PROCESSING) + set_slsb(q, &processed, SLSB_P_INPUT_NOT_INIT, &count); + } + } #endif /* QDIO_USE_PROCESSING_STATE */ + q->first_to_check=f_mod_no; QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int)); return q->first_to_check;