diff options
author | Frank Pavlic <pavlic@de.ibm.com> | 2006-01-06 03:19:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:51 -0500 |
commit | 8129ee164267dc030b8e1d541ee3643c0b9f2fa1 (patch) | |
tree | ca477e575a9098e637411332a8d354477143eff4 /drivers/s390/cio/qdio.h | |
parent | 05f29fcdb0c6c99484c8bea5e244fe2f4edc9337 (diff) |
[PATCH] s390: qdio V=V pass-through
New feature V=V qdio pass-through.
QDIO and HiperSockets processing in z/VM V=V guest environments (as well as
V=R with z/VM running in LPAR mode) requires shadowing of all QDIO
architecture queue elements. Especially the shadowing of SBALs and SLSBs
structures in the hypervisor, and the need to issue SIGA SYNC operations to
observe state changes, eventually causes significant CPU processing overhead
in the hypervisor.
The QDIO pass-through support for V=V guests avoids the shadowing of SBALs and
SLSBs. This significantly reduces the hypervisor overhead for QDIO based I/O.
Signed-off-by: Frank Pavlic <pavlic@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/s390/cio/qdio.h')
-rw-r--r-- | drivers/s390/cio/qdio.h | 104 |
1 files changed, 70 insertions, 34 deletions
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 328e31cc6854..b5d303e79a24 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
@@ -3,14 +3,13 @@ | |||
3 | 3 | ||
4 | #include <asm/page.h> | 4 | #include <asm/page.h> |
5 | 5 | ||
6 | #define VERSION_CIO_QDIO_H "$Revision: 1.33 $" | 6 | #define VERSION_CIO_QDIO_H "$Revision: 1.37 $" |
7 | 7 | ||
8 | #ifdef CONFIG_QDIO_DEBUG | 8 | #ifdef CONFIG_QDIO_DEBUG |
9 | #define QDIO_VERBOSE_LEVEL 9 | 9 | #define QDIO_VERBOSE_LEVEL 9 |
10 | #else /* CONFIG_QDIO_DEBUG */ | 10 | #else /* CONFIG_QDIO_DEBUG */ |
11 | #define QDIO_VERBOSE_LEVEL 5 | 11 | #define QDIO_VERBOSE_LEVEL 5 |
12 | #endif /* CONFIG_QDIO_DEBUG */ | 12 | #endif /* CONFIG_QDIO_DEBUG */ |
13 | |||
14 | #define QDIO_USE_PROCESSING_STATE | 13 | #define QDIO_USE_PROCESSING_STATE |
15 | 14 | ||
16 | #ifdef CONFIG_QDIO_PERF_STATS | 15 | #ifdef CONFIG_QDIO_PERF_STATS |
@@ -265,6 +264,58 @@ QDIO_PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | |||
265 | /* | 264 | /* |
266 | * Some instructions as assembly | 265 | * Some instructions as assembly |
267 | */ | 266 | */ |
267 | |||
268 | static inline int | ||
269 | do_sqbs(unsigned long sch, unsigned char state, int queue, | ||
270 | unsigned int *start, unsigned int *count) | ||
271 | { | ||
272 | #ifdef CONFIG_ARCH_S390X | ||
273 | register unsigned long _ccq asm ("0") = *count; | ||
274 | register unsigned long _sch asm ("1") = sch; | ||
275 | unsigned long _queuestart = ((unsigned long)queue << 32) | *start; | ||
276 | |||
277 | asm volatile ( | ||
278 | " .insn rsy,0xeb000000008A,%1,0,0(%2)\n\t" | ||
279 | : "+d" (_ccq), "+d" (_queuestart) | ||
280 | : "d" ((unsigned long)state), "d" (_sch) | ||
281 | : "memory", "cc" | ||
282 | ); | ||
283 | *count = _ccq & 0xff; | ||
284 | *start = _queuestart & 0xff; | ||
285 | |||
286 | return (_ccq >> 32) & 0xff; | ||
287 | #else | ||
288 | return 0; | ||
289 | #endif | ||
290 | } | ||
291 | |||
292 | static inline int | ||
293 | do_eqbs(unsigned long sch, unsigned char *state, int queue, | ||
294 | unsigned int *start, unsigned int *count) | ||
295 | { | ||
296 | #ifdef CONFIG_ARCH_S390X | ||
297 | register unsigned long _ccq asm ("0") = *count; | ||
298 | register unsigned long _sch asm ("1") = sch; | ||
299 | unsigned long _queuestart = ((unsigned long)queue << 32) | *start; | ||
300 | unsigned long _state = 0; | ||
301 | |||
302 | asm volatile ( | ||
303 | " .insn rrf,0xB99c0000,%1,%2,0,0 \n\t" | ||
304 | : "+d" (_ccq), "+d" (_queuestart), "+d" (_state) | ||
305 | : "d" (_sch) | ||
306 | : "memory", "cc" | ||
307 | ); | ||
308 | *count = _ccq & 0xff; | ||
309 | *start = _queuestart & 0xff; | ||
310 | *state = _state & 0xff; | ||
311 | |||
312 | return (_ccq >> 32) & 0xff; | ||
313 | #else | ||
314 | return 0; | ||
315 | #endif | ||
316 | } | ||
317 | |||
318 | |||
268 | static inline int | 319 | static inline int |
269 | do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2) | 320 | do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2) |
270 | { | 321 | { |
@@ -280,7 +331,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2) | |||
280 | "ipm %0 \n\t" | 331 | "ipm %0 \n\t" |
281 | "srl %0,28 \n\t" | 332 | "srl %0,28 \n\t" |
282 | : "=d" (cc) | 333 | : "=d" (cc) |
283 | : "d" (0x10000|irq), "d" (mask1), "d" (mask2) | 334 | : "d" (irq), "d" (mask1), "d" (mask2) |
284 | : "cc", "0", "1", "2", "3" | 335 | : "cc", "0", "1", "2", "3" |
285 | ); | 336 | ); |
286 | #else /* CONFIG_ARCH_S390X */ | 337 | #else /* CONFIG_ARCH_S390X */ |
@@ -293,7 +344,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2) | |||
293 | "ipm %0 \n\t" | 344 | "ipm %0 \n\t" |
294 | "srl %0,28 \n\t" | 345 | "srl %0,28 \n\t" |
295 | : "=d" (cc) | 346 | : "=d" (cc) |
296 | : "d" (0x10000|irq), "d" (mask1), "d" (mask2) | 347 | : "d" (irq), "d" (mask1), "d" (mask2) |
297 | : "cc", "0", "1", "2", "3" | 348 | : "cc", "0", "1", "2", "3" |
298 | ); | 349 | ); |
299 | #endif /* CONFIG_ARCH_S390X */ | 350 | #endif /* CONFIG_ARCH_S390X */ |
@@ -314,7 +365,7 @@ do_siga_input(unsigned int irq, unsigned int mask) | |||
314 | "ipm %0 \n\t" | 365 | "ipm %0 \n\t" |
315 | "srl %0,28 \n\t" | 366 | "srl %0,28 \n\t" |
316 | : "=d" (cc) | 367 | : "=d" (cc) |
317 | : "d" (0x10000|irq), "d" (mask) | 368 | : "d" (irq), "d" (mask) |
318 | : "cc", "0", "1", "2", "memory" | 369 | : "cc", "0", "1", "2", "memory" |
319 | ); | 370 | ); |
320 | #else /* CONFIG_ARCH_S390X */ | 371 | #else /* CONFIG_ARCH_S390X */ |
@@ -326,7 +377,7 @@ do_siga_input(unsigned int irq, unsigned int mask) | |||
326 | "ipm %0 \n\t" | 377 | "ipm %0 \n\t" |
327 | "srl %0,28 \n\t" | 378 | "srl %0,28 \n\t" |
328 | : "=d" (cc) | 379 | : "=d" (cc) |
329 | : "d" (0x10000|irq), "d" (mask) | 380 | : "d" (irq), "d" (mask) |
330 | : "cc", "0", "1", "2", "memory" | 381 | : "cc", "0", "1", "2", "memory" |
331 | ); | 382 | ); |
332 | #endif /* CONFIG_ARCH_S390X */ | 383 | #endif /* CONFIG_ARCH_S390X */ |
@@ -335,7 +386,8 @@ do_siga_input(unsigned int irq, unsigned int mask) | |||
335 | } | 386 | } |
336 | 387 | ||
337 | static inline int | 388 | static inline int |
338 | do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb) | 389 | do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb, |
390 | unsigned int fc) | ||
339 | { | 391 | { |
340 | int cc; | 392 | int cc; |
341 | __u32 busy_bit; | 393 | __u32 busy_bit; |
@@ -366,14 +418,14 @@ do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb) | |||
366 | ".long 0b,2b \n\t" | 418 | ".long 0b,2b \n\t" |
367 | ".previous \n\t" | 419 | ".previous \n\t" |
368 | : "=d" (cc), "=d" (busy_bit) | 420 | : "=d" (cc), "=d" (busy_bit) |
369 | : "d" (0x10000|irq), "d" (mask), | 421 | : "d" (irq), "d" (mask), |
370 | "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION) | 422 | "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION) |
371 | : "cc", "0", "1", "2", "memory" | 423 | : "cc", "0", "1", "2", "memory" |
372 | ); | 424 | ); |
373 | #else /* CONFIG_ARCH_S390X */ | 425 | #else /* CONFIG_ARCH_S390X */ |
374 | asm volatile ( | 426 | asm volatile ( |
375 | "lghi 0,0 \n\t" | 427 | "llgfr 0,%5 \n\t" |
376 | "llgfr 1,%2 \n\t" | 428 | "lgr 1,%2 \n\t" |
377 | "llgfr 2,%3 \n\t" | 429 | "llgfr 2,%3 \n\t" |
378 | "siga 0 \n\t" | 430 | "siga 0 \n\t" |
379 | "0:" | 431 | "0:" |
@@ -391,8 +443,8 @@ do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb) | |||
391 | ".quad 0b,1b \n\t" | 443 | ".quad 0b,1b \n\t" |
392 | ".previous \n\t" | 444 | ".previous \n\t" |
393 | : "=d" (cc), "=d" (busy_bit) | 445 | : "=d" (cc), "=d" (busy_bit) |
394 | : "d" (0x10000|irq), "d" (mask), | 446 | : "d" (irq), "d" (mask), |
395 | "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION) | 447 | "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION), "d" (fc) |
396 | : "cc", "0", "1", "2", "memory" | 448 | : "cc", "0", "1", "2", "memory" |
397 | ); | 449 | ); |
398 | #endif /* CONFIG_ARCH_S390X */ | 450 | #endif /* CONFIG_ARCH_S390X */ |
@@ -494,33 +546,12 @@ struct qdio_perf_stats { | |||
494 | #define QDIO_GET_ADDR(x) ((__u32)(long)x) | 546 | #define QDIO_GET_ADDR(x) ((__u32)(long)x) |
495 | #endif /* CONFIG_ARCH_S390X */ | 547 | #endif /* CONFIG_ARCH_S390X */ |
496 | 548 | ||
497 | #ifdef CONFIG_QDIO_DEBUG | ||
498 | #define set_slsb(x,y) \ | ||
499 | if(q->queue_type==QDIO_TRACE_QTYPE) { \ | ||
500 | if(q->is_input_q) { \ | ||
501 | QDIO_DBF_HEX2(0,slsb_in,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \ | ||
502 | } else { \ | ||
503 | QDIO_DBF_HEX2(0,slsb_out,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \ | ||
504 | } \ | ||
505 | } \ | ||
506 | qdio_set_slsb(x,y); \ | ||
507 | if(q->queue_type==QDIO_TRACE_QTYPE) { \ | ||
508 | if(q->is_input_q) { \ | ||
509 | QDIO_DBF_HEX2(0,slsb_in,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \ | ||
510 | } else { \ | ||
511 | QDIO_DBF_HEX2(0,slsb_out,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \ | ||
512 | } \ | ||
513 | } | ||
514 | #else /* CONFIG_QDIO_DEBUG */ | ||
515 | #define set_slsb(x,y) qdio_set_slsb(x,y) | ||
516 | #endif /* CONFIG_QDIO_DEBUG */ | ||
517 | |||
518 | struct qdio_q { | 549 | struct qdio_q { |
519 | volatile struct slsb slsb; | 550 | volatile struct slsb slsb; |
520 | 551 | ||
521 | char unused[QDIO_MAX_BUFFERS_PER_Q]; | 552 | char unused[QDIO_MAX_BUFFERS_PER_Q]; |
522 | 553 | ||
523 | __u32 * volatile dev_st_chg_ind; | 554 | __u32 * dev_st_chg_ind; |
524 | 555 | ||
525 | int is_input_q; | 556 | int is_input_q; |
526 | int irq; | 557 | int irq; |
@@ -568,6 +599,7 @@ struct qdio_q { | |||
568 | struct tasklet_struct tasklet; | 599 | struct tasklet_struct tasklet; |
569 | #endif /* QDIO_USE_TIMERS_FOR_POLLING */ | 600 | #endif /* QDIO_USE_TIMERS_FOR_POLLING */ |
570 | 601 | ||
602 | |||
571 | enum qdio_irq_states state; | 603 | enum qdio_irq_states state; |
572 | 604 | ||
573 | /* used to store the error condition during a data transfer */ | 605 | /* used to store the error condition during a data transfer */ |
@@ -624,6 +656,10 @@ struct qdio_irq { | |||
624 | unsigned int hydra_gives_outbound_pcis; | 656 | unsigned int hydra_gives_outbound_pcis; |
625 | unsigned int sync_done_on_outb_pcis; | 657 | unsigned int sync_done_on_outb_pcis; |
626 | 658 | ||
659 | /* QEBSM facility */ | ||
660 | unsigned int is_qebsm; | ||
661 | unsigned long sch_token; | ||
662 | |||
627 | enum qdio_irq_states state; | 663 | enum qdio_irq_states state; |
628 | 664 | ||
629 | unsigned int no_input_qs; | 665 | unsigned int no_input_qs; |