|
@@ -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 *) ®s->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);
|
|
|
}
|