unsigned long gprs[NUM_GPRS];
unsigned long orig_gpr2;
unsigned int int_code;
+ unsigned int int_parm;
unsigned long int_parm_long;
};
DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code));
+ DEFINE(__PT_INT_PARM, offsetof(struct pt_regs, int_parm));
DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long));
DEFINE(__PT_SIZE, sizeof(struct pt_regs));
BLANK();
stm %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
stm %r8,%r9,__PT_PSW(%r11)
+ mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
TRACE_IRQS_OFF
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
+io_loop:
l %r1,BASED(.Ldo_IRQ)
lr %r2,%r11 # pass pointer to pt_regs
basr %r14,%r1 # call do_IRQ
+ tm __LC_MACHINE_FLAGS+2,0x10 # MACHINE_FLAG_LPAR
+ jz io_return
+ tpi 0
+ jz io_return
+ mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
+ j io_loop
io_return:
LOCKDEP_SYS_EXIT
TRACE_IRQS_ON
stm %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
stm %r8,%r9,__PT_PSW(%r11)
+ mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
+ mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
TRACE_IRQS_OFF
lr %r2,%r11 # pass pointer to pt_regs
- l %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code
- l %r4,__LC_EXT_PARAMS # get external parameters
l %r1,BASED(.Ldo_extint)
basr %r14,%r1 # call do_extint
j io_return
void do_notify_resume(struct pt_regs *regs);
struct ext_code;
-void do_extint(struct pt_regs *regs, struct ext_code, unsigned int, unsigned long);
+void do_extint(struct pt_regs *regs);
void do_restart(void);
void __init startup_init(void);
void die(struct pt_regs *regs, const char *str);
stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
stmg %r8,%r9,__PT_PSW(%r11)
+ mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
TRACE_IRQS_OFF
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
+io_loop:
lgr %r2,%r11 # pass pointer to pt_regs
brasl %r14,do_IRQ
+ tm __LC_MACHINE_FLAGS+6,0x10 # MACHINE_FLAG_LPAR
+ jz io_return
+ tpi 0
+ jz io_return
+ mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
+ j io_loop
io_return:
LOCKDEP_SYS_EXIT
TRACE_IRQS_ON
stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
stmg %r8,%r9,__PT_PSW(%r11)
+ lghi %r1,__LC_EXT_PARAMS2
+ mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
+ mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
+ mvc __PT_INT_PARM_LONG(8,%r11),0(%r1)
TRACE_IRQS_OFF
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
- lghi %r1,4096
lgr %r2,%r11 # pass pointer to pt_regs
- llgf %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code
- llgf %r4,__LC_EXT_PARAMS # get external parameter
- lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter
brasl %r14,do_extint
j io_return
}
EXPORT_SYMBOL(unregister_external_interrupt);
-void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
- unsigned int param32, unsigned long param64)
+void __irq_entry do_extint(struct pt_regs *regs)
{
+ struct ext_code ext_code;
struct pt_regs *old_regs;
struct ext_int_info *p;
int index;
clock_comparator_work();
}
kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);
+ ext_code = *(struct ext_code *) ®s->int_code;
if (ext_code.code != 0x1004)
__get_cpu_var(s390_idle).nohz_delay = 1;
rcu_read_lock();
list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
if (likely(p->code == ext_code.code))
- p->handler(ext_code, param32, param64);
+ p->handler(ext_code, regs->int_parm,
+ regs->int_parm_long);
rcu_read_unlock();
irq_exit();
set_irq_regs(old_regs);
*/
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;
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);
}