aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
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 /drivers/s390/cio
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>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/cio.c68
1 files changed, 28 insertions, 40 deletions
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}