aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2013-06-17 08:54:02 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-06-26 15:10:23 -0400
commit48f6b00c6e3190b786c44731b25ac124c81c2247 (patch)
treec06d6ba767544eba04a2cd47db1c303f6a35d9f7
parent4bdb613ff45ef5f2848584b250f8a65f6d6c5755 (diff)
s390/irq: store interrupt information in pt_regs
Copy the interrupt parameters from the lowcore to the pt_regs structure in entry[64].S and reduce the arguments of the low level interrupt handler to the pt_regs pointer only. In addition move the test-pending-interrupt loop from do_IRQ to entry[64].S to make sure that interrupt information is always delivered via pt_regs. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/ptrace.h1
-rw-r--r--arch/s390/kernel/asm-offsets.c1
-rw-r--r--arch/s390/kernel/entry.S12
-rw-r--r--arch/s390/kernel/entry.h2
-rw-r--r--arch/s390/kernel/entry64.S16
-rw-r--r--arch/s390/kernel/irq.c8
-rw-r--r--drivers/s390/cio/cio.c68
7 files changed, 58 insertions, 50 deletions
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 559512a455da..52b56533c57c 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -24,6 +24,7 @@ struct pt_regs
24 unsigned long gprs[NUM_GPRS]; 24 unsigned long gprs[NUM_GPRS];
25 unsigned long orig_gpr2; 25 unsigned long orig_gpr2;
26 unsigned int int_code; 26 unsigned int int_code;
27 unsigned int int_parm;
27 unsigned long int_parm_long; 28 unsigned long int_parm_long;
28}; 29};
29 30
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 7a82f9f70100..d6de844bc30a 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -47,6 +47,7 @@ int main(void)
47 DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); 47 DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
48 DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); 48 DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
49 DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code)); 49 DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code));
50 DEFINE(__PT_INT_PARM, offsetof(struct pt_regs, int_parm));
50 DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long)); 51 DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long));
51 DEFINE(__PT_SIZE, sizeof(struct pt_regs)); 52 DEFINE(__PT_SIZE, sizeof(struct pt_regs));
52 BLANK(); 53 BLANK();
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 4d5e6f8a7978..be7a408be7a1 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -429,11 +429,19 @@ io_skip:
429 stm %r0,%r7,__PT_R0(%r11) 429 stm %r0,%r7,__PT_R0(%r11)
430 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC 430 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
431 stm %r8,%r9,__PT_PSW(%r11) 431 stm %r8,%r9,__PT_PSW(%r11)
432 mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
432 TRACE_IRQS_OFF 433 TRACE_IRQS_OFF
433 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) 434 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
435io_loop:
434 l %r1,BASED(.Ldo_IRQ) 436 l %r1,BASED(.Ldo_IRQ)
435 lr %r2,%r11 # pass pointer to pt_regs 437 lr %r2,%r11 # pass pointer to pt_regs
436 basr %r14,%r1 # call do_IRQ 438 basr %r14,%r1 # call do_IRQ
439 tm __LC_MACHINE_FLAGS+2,0x10 # MACHINE_FLAG_LPAR
440 jz io_return
441 tpi 0
442 jz io_return
443 mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
444 j io_loop
437io_return: 445io_return:
438 LOCKDEP_SYS_EXIT 446 LOCKDEP_SYS_EXIT
439 TRACE_IRQS_ON 447 TRACE_IRQS_ON
@@ -573,10 +581,10 @@ ext_skip:
573 stm %r0,%r7,__PT_R0(%r11) 581 stm %r0,%r7,__PT_R0(%r11)
574 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC 582 mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
575 stm %r8,%r9,__PT_PSW(%r11) 583 stm %r8,%r9,__PT_PSW(%r11)
584 mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
585 mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
576 TRACE_IRQS_OFF 586 TRACE_IRQS_OFF
577 lr %r2,%r11 # pass pointer to pt_regs 587 lr %r2,%r11 # pass pointer to pt_regs
578 l %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code
579 l %r4,__LC_EXT_PARAMS # get external parameters
580 l %r1,BASED(.Ldo_extint) 588 l %r1,BASED(.Ldo_extint)
581 basr %r14,%r1 # call do_extint 589 basr %r14,%r1 # call do_extint
582 j io_return 590 j io_return
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index aa0ab02e9595..3ddbc26d246e 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -54,7 +54,7 @@ void handle_signal32(unsigned long sig, struct k_sigaction *ka,
54void do_notify_resume(struct pt_regs *regs); 54void do_notify_resume(struct pt_regs *regs);
55 55
56struct ext_code; 56struct ext_code;
57void do_extint(struct pt_regs *regs, struct ext_code, unsigned int, unsigned long); 57void do_extint(struct pt_regs *regs);
58void do_restart(void); 58void do_restart(void);
59void __init startup_init(void); 59void __init startup_init(void);
60void die(struct pt_regs *regs, const char *str); 60void die(struct pt_regs *regs, const char *str);
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 4c17eece707e..bc5864c5148b 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -460,10 +460,18 @@ io_skip:
460 stmg %r0,%r7,__PT_R0(%r11) 460 stmg %r0,%r7,__PT_R0(%r11)
461 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC 461 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
462 stmg %r8,%r9,__PT_PSW(%r11) 462 stmg %r8,%r9,__PT_PSW(%r11)
463 mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
463 TRACE_IRQS_OFF 464 TRACE_IRQS_OFF
464 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) 465 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
466io_loop:
465 lgr %r2,%r11 # pass pointer to pt_regs 467 lgr %r2,%r11 # pass pointer to pt_regs
466 brasl %r14,do_IRQ 468 brasl %r14,do_IRQ
469 tm __LC_MACHINE_FLAGS+6,0x10 # MACHINE_FLAG_LPAR
470 jz io_return
471 tpi 0
472 jz io_return
473 mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
474 j io_loop
467io_return: 475io_return:
468 LOCKDEP_SYS_EXIT 476 LOCKDEP_SYS_EXIT
469 TRACE_IRQS_ON 477 TRACE_IRQS_ON
@@ -605,13 +613,13 @@ ext_skip:
605 stmg %r0,%r7,__PT_R0(%r11) 613 stmg %r0,%r7,__PT_R0(%r11)
606 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC 614 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
607 stmg %r8,%r9,__PT_PSW(%r11) 615 stmg %r8,%r9,__PT_PSW(%r11)
616 lghi %r1,__LC_EXT_PARAMS2
617 mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
618 mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
619 mvc __PT_INT_PARM_LONG(8,%r11),0(%r1)
608 TRACE_IRQS_OFF 620 TRACE_IRQS_OFF
609 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) 621 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
610 lghi %r1,4096
611 lgr %r2,%r11 # pass pointer to pt_regs 622 lgr %r2,%r11 # pass pointer to pt_regs
612 llgf %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code
613 llgf %r4,__LC_EXT_PARAMS # get external parameter
614 lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter
615 brasl %r14,do_extint 623 brasl %r14,do_extint
616 j io_return 624 j io_return
617 625
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index dd3c1994b8bd..54b0995514e8 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -234,9 +234,9 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
234} 234}
235EXPORT_SYMBOL(unregister_external_interrupt); 235EXPORT_SYMBOL(unregister_external_interrupt);
236 236
237void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code, 237void __irq_entry do_extint(struct pt_regs *regs)
238 unsigned int param32, unsigned long param64)
239{ 238{
239 struct ext_code ext_code;
240 struct pt_regs *old_regs; 240 struct pt_regs *old_regs;
241 struct ext_int_info *p; 241 struct ext_int_info *p;
242 int index; 242 int index;
@@ -248,6 +248,7 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
248 clock_comparator_work(); 248 clock_comparator_work();
249 } 249 }
250 kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL); 250 kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);
251 ext_code = *(struct ext_code *) &regs->int_code;
251 if (ext_code.code != 0x1004) 252 if (ext_code.code != 0x1004)
252 __get_cpu_var(s390_idle).nohz_delay = 1; 253 __get_cpu_var(s390_idle).nohz_delay = 1;
253 254
@@ -255,7 +256,8 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
255 rcu_read_lock(); 256 rcu_read_lock();
256 list_for_each_entry_rcu(p, &ext_int_hash[index], entry) 257 list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
257 if (likely(p->code == ext_code.code)) 258 if (likely(p->code == ext_code.code))
258 p->handler(ext_code, param32, param64); 259 p->handler(ext_code, regs->int_parm,
260 regs->int_parm_long);
259 rcu_read_unlock(); 261 rcu_read_unlock();
260 irq_exit(); 262 irq_exit();
261 set_irq_regs(old_regs); 263 set_irq_regs(old_regs);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 935d80b4e9ce..4eeb4a6bf207 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -568,7 +568,7 @@ out:
568 */ 568 */
569void __irq_entry do_IRQ(struct pt_regs *regs) 569void __irq_entry do_IRQ(struct pt_regs *regs)
570{ 570{
571 struct tpi_info *tpi_info; 571 struct tpi_info *tpi_info = (struct tpi_info *) &regs->int_code;
572 struct subchannel *sch; 572 struct subchannel *sch;
573 struct irb *irb; 573 struct irb *irb;
574 struct pt_regs *old_regs; 574 struct pt_regs *old_regs;
@@ -579,46 +579,34 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
579 if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) 579 if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
580 /* Serve timer interrupts first. */ 580 /* Serve timer interrupts first. */
581 clock_comparator_work(); 581 clock_comparator_work();
582 /* 582
583 * Get interrupt information from lowcore 583 kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
584 */ 584 irb = (struct irb *) &S390_lowcore.irb;
585 tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; 585 if (tpi_info->adapter_IO) {
586 irb = (struct irb *)&S390_lowcore.irb; 586 do_adapter_IO(tpi_info->isc);
587 do { 587 goto out;
588 kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL); 588 }
589 if (tpi_info->adapter_IO) { 589 sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
590 do_adapter_IO(tpi_info->isc); 590 if (!sch) {
591 continue; 591 /* Clear pending interrupt condition. */
592 } 592 inc_irq_stat(IRQIO_CIO);
593 sch = (struct subchannel *)(unsigned long)tpi_info->intparm; 593 tsch(tpi_info->schid, irb);
594 if (!sch) { 594 goto out;
595 /* Clear pending interrupt condition. */ 595 }
596 inc_irq_stat(IRQIO_CIO); 596 spin_lock(sch->lock);
597 tsch(tpi_info->schid, irb); 597 /* Store interrupt response block to lowcore. */
598 continue; 598 if (tsch(tpi_info->schid, irb) == 0) {
599 } 599 /* Keep subchannel information word up to date. */
600 spin_lock(sch->lock); 600 memcpy (&sch->schib.scsw, &irb->scsw, sizeof (irb->scsw));
601 /* Store interrupt response block to lowcore. */ 601 /* Call interrupt handler if there is one. */
602 if (tsch(tpi_info->schid, irb) == 0) { 602 if (sch->driver && sch->driver->irq)
603 /* Keep subchannel information word up to date. */ 603 sch->driver->irq(sch);
604 memcpy (&sch->schib.scsw, &irb->scsw, 604 else
605 sizeof (irb->scsw));
606 /* Call interrupt handler if there is one. */
607 if (sch->driver && sch->driver->irq)
608 sch->driver->irq(sch);
609 else
610 inc_irq_stat(IRQIO_CIO);
611 } else
612 inc_irq_stat(IRQIO_CIO); 605 inc_irq_stat(IRQIO_CIO);
613 spin_unlock(sch->lock); 606 } else
614 /* 607 inc_irq_stat(IRQIO_CIO);
615 * Are more interrupts pending? 608 spin_unlock(sch->lock);
616 * If so, the tpi instruction will update the lowcore 609out:
617 * to hold the info for the next interrupt.
618 * We don't do this for VM because a tpi drops the cpu
619 * out of the sie which costs more cycles than it saves.
620 */
621 } while (MACHINE_IS_LPAR && tpi(NULL) != 0);
622 irq_exit(); 610 irq_exit();
623 set_irq_regs(old_regs); 611 set_irq_regs(old_regs);
624} 612}