Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3173

kernel-2.6.18-194.11.1.el5.src.rpm

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;