summaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2013-06-17 14:54:02 +0200
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-06-26 21:10:23 +0200
commit48f6b00c6e3190b786c44731b25ac124c81c2247 (patch)
treec06d6ba767544eba04a2cd47db1c303f6a35d9f7 /drivers/s390
parent4bdb613ff45ef5f2848584b250f8a65f6d6c5755 (diff)
downloadlinux-stable-48f6b00c6e3190b786c44731b25ac124c81c2247.tar.gz
linux-stable-48f6b00c6e3190b786c44731b25ac124c81c2247.tar.bz2
linux-stable-48f6b00c6e3190b786c44731b25ac124c81c2247.zip
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')
-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:
*/
void __irq_entry do_IRQ(struct pt_regs *regs)
{
- struct tpi_info *tpi_info;
+ struct tpi_info *tpi_info = (struct tpi_info *) &regs->int_code;
struct subchannel *sch;
struct irb *irb;
struct pt_regs *old_regs;
@@ -579,46 +579,34 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
/* Serve timer interrupts first. */
clock_comparator_work();
- /*
- * Get interrupt information from lowcore
- */
- tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
- irb = (struct irb *)&S390_lowcore.irb;
- do {
- kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
- if (tpi_info->adapter_IO) {
- do_adapter_IO(tpi_info->isc);
- continue;
- }
- sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
- if (!sch) {
- /* Clear pending interrupt condition. */
- inc_irq_stat(IRQIO_CIO);
- tsch(tpi_info->schid, irb);
- continue;
- }
- spin_lock(sch->lock);
- /* Store interrupt response block to lowcore. */
- if (tsch(tpi_info->schid, irb) == 0) {
- /* Keep subchannel information word up to date. */
- memcpy (&sch->schib.scsw, &irb->scsw,
- sizeof (irb->scsw));
- /* Call interrupt handler if there is one. */
- if (sch->driver && sch->driver->irq)
- sch->driver->irq(sch);
- else
- inc_irq_stat(IRQIO_CIO);
- } else
+
+ kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
+ irb = (struct irb *) &S390_lowcore.irb;
+ if (tpi_info->adapter_IO) {
+ do_adapter_IO(tpi_info->isc);
+ goto out;
+ }
+ sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
+ if (!sch) {
+ /* Clear pending interrupt condition. */
+ inc_irq_stat(IRQIO_CIO);
+ tsch(tpi_info->schid, irb);
+ goto out;
+ }
+ spin_lock(sch->lock);
+ /* Store interrupt response block to lowcore. */
+ if (tsch(tpi_info->schid, irb) == 0) {
+ /* Keep subchannel information word up to date. */
+ memcpy (&sch->schib.scsw, &irb->scsw, sizeof (irb->scsw));
+ /* Call interrupt handler if there is one. */
+ if (sch->driver && sch->driver->irq)
+ sch->driver->irq(sch);
+ else
inc_irq_stat(IRQIO_CIO);
- spin_unlock(sch->lock);
- /*
- * Are more interrupts pending?
- * If so, the tpi instruction will update the lowcore
- * to hold the info for the next interrupt.
- * We don't do this for VM because a tpi drops the cpu
- * out of the sie which costs more cycles than it saves.
- */
- } while (MACHINE_IS_LPAR && tpi(NULL) != 0);
+ } else
+ inc_irq_stat(IRQIO_CIO);
+ spin_unlock(sch->lock);
+out:
irq_exit();
set_irq_regs(old_regs);
}