diff options
author | Jan Glauber <jang@linux.vnet.ibm.com> | 2011-01-05 06:47:52 -0500 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2011-01-05 06:47:28 -0500 |
commit | 958c0ba403cb6a693b54be2389f9ef53377fa259 (patch) | |
tree | 7fb99145dc1254c136081cf492dcc75b11a8e723 /drivers/s390 | |
parent | 0195843bfda90a215f3b72c9aac2fd0bc9244b67 (diff) |
[S390] qdio: use proper QEBSM operand for SIGA-R and SIGA-S
If QIOASSIST is enabled for a qdio device the SIGA instruction requires
a modified function code. This function code modifier was missing for
SIGA-R and SIGA-S which can lead to a kernel panic caused by an
operand exception.
Cc: stable@kernel.org
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/qdio.h | 6 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 43 |
2 files changed, 34 insertions, 15 deletions
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 40ca0b9241e5..0a42da4beafa 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
@@ -91,6 +91,12 @@ enum qdio_irq_states { | |||
91 | #define AC1_SC_QEBSM_AVAILABLE 0x02 /* available for subchannel */ | 91 | #define AC1_SC_QEBSM_AVAILABLE 0x02 /* available for subchannel */ |
92 | #define AC1_SC_QEBSM_ENABLED 0x01 /* enabled for subchannel */ | 92 | #define AC1_SC_QEBSM_ENABLED 0x01 /* enabled for subchannel */ |
93 | 93 | ||
94 | /* SIGA flags */ | ||
95 | #define QDIO_SIGA_WRITE 0x00 | ||
96 | #define QDIO_SIGA_READ 0x01 | ||
97 | #define QDIO_SIGA_SYNC 0x02 | ||
98 | #define QDIO_SIGA_QEBSM_FLAG 0x80 | ||
99 | |||
94 | #ifdef CONFIG_64BIT | 100 | #ifdef CONFIG_64BIT |
95 | static inline int do_sqbs(u64 token, unsigned char state, int queue, | 101 | static inline int do_sqbs(u64 token, unsigned char state, int queue, |
96 | int *start, int *count) | 102 | int *start, int *count) |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index af86875bede4..99823477d57e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -30,11 +30,12 @@ MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>,"\ | |||
30 | MODULE_DESCRIPTION("QDIO base support"); | 30 | MODULE_DESCRIPTION("QDIO base support"); |
31 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
32 | 32 | ||
33 | static inline int do_siga_sync(struct subchannel_id schid, | 33 | static inline int do_siga_sync(unsigned long schid, |
34 | unsigned int out_mask, unsigned int in_mask) | 34 | unsigned int out_mask, unsigned int in_mask, |
35 | unsigned int fc) | ||
35 | { | 36 | { |
36 | register unsigned long __fc asm ("0") = 2; | 37 | register unsigned long __fc asm ("0") = fc; |
37 | register struct subchannel_id __schid asm ("1") = schid; | 38 | register unsigned long __schid asm ("1") = schid; |
38 | register unsigned long out asm ("2") = out_mask; | 39 | register unsigned long out asm ("2") = out_mask; |
39 | register unsigned long in asm ("3") = in_mask; | 40 | register unsigned long in asm ("3") = in_mask; |
40 | int cc; | 41 | int cc; |
@@ -48,10 +49,11 @@ static inline int do_siga_sync(struct subchannel_id schid, | |||
48 | return cc; | 49 | return cc; |
49 | } | 50 | } |
50 | 51 | ||
51 | static inline int do_siga_input(struct subchannel_id schid, unsigned int mask) | 52 | static inline int do_siga_input(unsigned long schid, unsigned int mask, |
53 | unsigned int fc) | ||
52 | { | 54 | { |
53 | register unsigned long __fc asm ("0") = 1; | 55 | register unsigned long __fc asm ("0") = fc; |
54 | register struct subchannel_id __schid asm ("1") = schid; | 56 | register unsigned long __schid asm ("1") = schid; |
55 | register unsigned long __mask asm ("2") = mask; | 57 | register unsigned long __mask asm ("2") = mask; |
56 | int cc; | 58 | int cc; |
57 | 59 | ||
@@ -280,6 +282,8 @@ void qdio_init_buf_states(struct qdio_irq *irq_ptr) | |||
280 | static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, | 282 | static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, |
281 | unsigned int input) | 283 | unsigned int input) |
282 | { | 284 | { |
285 | unsigned long schid = *((u32 *) &q->irq_ptr->schid); | ||
286 | unsigned int fc = QDIO_SIGA_SYNC; | ||
283 | int cc; | 287 | int cc; |
284 | 288 | ||
285 | if (!need_siga_sync(q)) | 289 | if (!need_siga_sync(q)) |
@@ -288,7 +292,12 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, | |||
288 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr); | 292 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr); |
289 | qperf_inc(q, siga_sync); | 293 | qperf_inc(q, siga_sync); |
290 | 294 | ||
291 | cc = do_siga_sync(q->irq_ptr->schid, output, input); | 295 | if (is_qebsm(q)) { |
296 | schid = q->irq_ptr->sch_token; | ||
297 | fc |= QDIO_SIGA_QEBSM_FLAG; | ||
298 | } | ||
299 | |||
300 | cc = do_siga_sync(schid, output, input, fc); | ||
292 | if (cc) | 301 | if (cc) |
293 | DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); | 302 | DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); |
294 | return cc; | 303 | return cc; |
@@ -314,8 +323,8 @@ static inline int qdio_siga_sync_all(struct qdio_q *q) | |||
314 | 323 | ||
315 | static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) | 324 | static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) |
316 | { | 325 | { |
317 | unsigned long schid; | 326 | unsigned long schid = *((u32 *) &q->irq_ptr->schid); |
318 | unsigned int fc = 0; | 327 | unsigned int fc = QDIO_SIGA_WRITE; |
319 | u64 start_time = 0; | 328 | u64 start_time = 0; |
320 | int cc; | 329 | int cc; |
321 | 330 | ||
@@ -324,11 +333,8 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) | |||
324 | 333 | ||
325 | if (is_qebsm(q)) { | 334 | if (is_qebsm(q)) { |
326 | schid = q->irq_ptr->sch_token; | 335 | schid = q->irq_ptr->sch_token; |
327 | fc |= 0x80; | 336 | fc |= QDIO_SIGA_QEBSM_FLAG; |
328 | } | 337 | } |
329 | else | ||
330 | schid = *((u32 *)&q->irq_ptr->schid); | ||
331 | |||
332 | again: | 338 | again: |
333 | cc = do_siga_output(schid, q->mask, busy_bit, fc); | 339 | cc = do_siga_output(schid, q->mask, busy_bit, fc); |
334 | 340 | ||
@@ -348,12 +354,19 @@ again: | |||
348 | 354 | ||
349 | static inline int qdio_siga_input(struct qdio_q *q) | 355 | static inline int qdio_siga_input(struct qdio_q *q) |
350 | { | 356 | { |
357 | unsigned long schid = *((u32 *) &q->irq_ptr->schid); | ||
358 | unsigned int fc = QDIO_SIGA_READ; | ||
351 | int cc; | 359 | int cc; |
352 | 360 | ||
353 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr); | 361 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr); |
354 | qperf_inc(q, siga_read); | 362 | qperf_inc(q, siga_read); |
355 | 363 | ||
356 | cc = do_siga_input(q->irq_ptr->schid, q->mask); | 364 | if (is_qebsm(q)) { |
365 | schid = q->irq_ptr->sch_token; | ||
366 | fc |= QDIO_SIGA_QEBSM_FLAG; | ||
367 | } | ||
368 | |||
369 | cc = do_siga_input(schid, q->mask, fc); | ||
357 | if (cc) | 370 | if (cc) |
358 | DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); | 371 | DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); |
359 | return cc; | 372 | return cc; |