aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/qdio_main.c
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2011-10-30 10:17:06 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2011-10-30 10:16:45 -0400
commit25f269f17316549e026c5dd0db7526411a504de6 (patch)
tree05897a8a28ff4cd6e81cc7ef12da405ab820c4f3 /drivers/s390/cio/qdio_main.c
parenta2b86019826cb97fd964fbaf101410c64cd78681 (diff)
[S390] qdio: EQBS retry after CCQ 96
Running under z/VM with QIOASSIST enabled, qdio queues could stall if EQBS did not extract all SBAL states. Add an instant retry for EQBS and, if the retry fails, set up a timer to ensure outstanding SBALs are processed later. While at it, optimize qdio_do_eqbs and qdio_do_sqbs to eliminate 3 jumps on the hot path. Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/qdio_main.c')
-rw-r--r--drivers/s390/cio/qdio_main.c81
1 files changed, 41 insertions, 40 deletions
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index a76d6764ce67..7c567b2268a7 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -104,9 +104,12 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
104 /* all done or next buffer state different */ 104 /* all done or next buffer state different */
105 if (ccq == 0 || ccq == 32) 105 if (ccq == 0 || ccq == 32)
106 return 0; 106 return 0;
107 /* not all buffers processed */ 107 /* no buffer processed */
108 if (ccq == 96 || ccq == 97) 108 if (ccq == 97)
109 return 1; 109 return 1;
110 /* not all buffers processed */
111 if (ccq == 96)
112 return 2;
110 /* notify devices immediately */ 113 /* notify devices immediately */
111 DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq); 114 DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq);
112 return -EIO; 115 return -EIO;
@@ -126,10 +129,8 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
126static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, 129static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
127 int start, int count, int auto_ack) 130 int start, int count, int auto_ack)
128{ 131{
132 int rc, tmp_count = count, tmp_start = start, nr = q->nr, retried = 0;
129 unsigned int ccq = 0; 133 unsigned int ccq = 0;
130 int tmp_count = count, tmp_start = start;
131 int nr = q->nr;
132 int rc;
133 134
134 BUG_ON(!q->irq_ptr->sch_token); 135 BUG_ON(!q->irq_ptr->sch_token);
135 qperf_inc(q, eqbs); 136 qperf_inc(q, eqbs);
@@ -140,30 +141,34 @@ again:
140 ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count, 141 ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count,
141 auto_ack); 142 auto_ack);
142 rc = qdio_check_ccq(q, ccq); 143 rc = qdio_check_ccq(q, ccq);
143 144 if (!rc)
144 /* At least one buffer was processed, return and extract the remaining 145 return count - tmp_count;
145 * buffers later.
146 */
147 if ((ccq == 96) && (count != tmp_count)) {
148 qperf_inc(q, eqbs_partial);
149 return (count - tmp_count);
150 }
151 146
152 if (rc == 1) { 147 if (rc == 1) {
153 DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq); 148 DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq);
154 goto again; 149 goto again;
155 } 150 }
156 151
157 if (rc < 0) { 152 if (rc == 2) {
158 DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); 153 BUG_ON(tmp_count == count);
159 DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); 154 qperf_inc(q, eqbs_partial);
160 q->handler(q->irq_ptr->cdev, 155 DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x",
161 QDIO_ERROR_ACTIVATE_CHECK_CONDITION, 156 tmp_count);
162 q->nr, q->first_to_kick, count, 157 /*
163 q->irq_ptr->int_parm); 158 * Retry once, if that fails bail out and process the
164 return 0; 159 * extracted buffers before trying again.
160 */
161 if (!retried++)
162 goto again;
163 else
164 return count - tmp_count;
165 } 165 }
166 return count - tmp_count; 166
167 DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
168 DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
169 q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
170 0, -1, -1, q->irq_ptr->int_parm);
171 return 0;
167} 172}
168 173
169/** 174/**
@@ -196,22 +201,22 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start,
196again: 201again:
197 ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); 202 ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count);
198 rc = qdio_check_ccq(q, ccq); 203 rc = qdio_check_ccq(q, ccq);
199 if (rc == 1) { 204 if (!rc) {
205 WARN_ON(tmp_count);
206 return count - tmp_count;
207 }
208
209 if (rc == 1 || rc == 2) {
200 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq); 210 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq);
201 qperf_inc(q, sqbs_partial); 211 qperf_inc(q, sqbs_partial);
202 goto again; 212 goto again;
203 } 213 }
204 if (rc < 0) { 214
205 DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); 215 DBF_ERROR("%4x SQBS ERROR", SCH_NO(q));
206 DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); 216 DBF_ERROR("%3d%3d%2d", count, tmp_count, nr);
207 q->handler(q->irq_ptr->cdev, 217 q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION,
208 QDIO_ERROR_ACTIVATE_CHECK_CONDITION, 218 0, -1, -1, q->irq_ptr->int_parm);
209 q->nr, q->first_to_kick, count, 219 return 0;
210 q->irq_ptr->int_parm);
211 return 0;
212 }
213 WARN_ON(tmp_count);
214 return count - tmp_count;
215} 220}
216 221
217/* returns number of examined buffers and their common state in *state */ 222/* returns number of examined buffers and their common state in *state */
@@ -915,10 +920,6 @@ static void __qdio_outbound_processing(struct qdio_q *q)
915 if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) 920 if (!pci_out_supported(q) && !qdio_outbound_q_done(q))
916 goto sched; 921 goto sched;
917 922
918 /* bail out for HiperSockets unicast queues */
919 if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q))
920 return;
921
922 if ((queue_type(q) == QDIO_IQDIO_QFMT) && 923 if ((queue_type(q) == QDIO_IQDIO_QFMT) &&
923 (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) 924 (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL)
924 goto sched; 925 goto sched;
@@ -928,8 +929,8 @@ static void __qdio_outbound_processing(struct qdio_q *q)
928 929
929 /* 930 /*
930 * Now we know that queue type is either qeth without pci enabled 931 * Now we know that queue type is either qeth without pci enabled
931 * or HiperSockets multicast. Make sure buffer switch from PRIMED to 932 * or HiperSockets. Make sure buffer switch from PRIMED to EMPTY
932 * EMPTY is noticed and outbound_handler is called after some time. 933 * is noticed and outbound_handler is called after some time.
933 */ 934 */
934 if (qdio_outbound_q_done(q)) 935 if (qdio_outbound_q_done(q))
935 del_timer(&q->u.out.timer); 936 del_timer(&q->u.out.timer);