aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2011-01-05 06:47:52 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2011-01-05 06:47:28 -0500
commit958c0ba403cb6a693b54be2389f9ef53377fa259 (patch)
tree7fb99145dc1254c136081cf492dcc75b11a8e723 /drivers/s390
parent0195843bfda90a215f3b72c9aac2fd0bc9244b67 (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.h6
-rw-r--r--drivers/s390/cio/qdio_main.c43
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
95static inline int do_sqbs(u64 token, unsigned char state, int queue, 101static 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>,"\
30MODULE_DESCRIPTION("QDIO base support"); 30MODULE_DESCRIPTION("QDIO base support");
31MODULE_LICENSE("GPL"); 31MODULE_LICENSE("GPL");
32 32
33static inline int do_siga_sync(struct subchannel_id schid, 33static 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
51static inline int do_siga_input(struct subchannel_id schid, unsigned int mask) 52static 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)
280static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, 282static 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
315static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) 324static 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
332again: 338again:
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
349static inline int qdio_siga_input(struct qdio_q *q) 355static 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;