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>
This commit is contained in:
parent
4bdb613ff4
commit
48f6b00c6e
@ -24,6 +24,7 @@ struct pt_regs
|
|||||||
unsigned long gprs[NUM_GPRS];
|
unsigned long gprs[NUM_GPRS];
|
||||||
unsigned long orig_gpr2;
|
unsigned long orig_gpr2;
|
||||||
unsigned int int_code;
|
unsigned int int_code;
|
||||||
|
unsigned int int_parm;
|
||||||
unsigned long int_parm_long;
|
unsigned long int_parm_long;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ int main(void)
|
|||||||
DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
|
DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
|
||||||
DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
|
DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
|
||||||
DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code));
|
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_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long));
|
||||||
DEFINE(__PT_SIZE, sizeof(struct pt_regs));
|
DEFINE(__PT_SIZE, sizeof(struct pt_regs));
|
||||||
BLANK();
|
BLANK();
|
||||||
|
@ -429,11 +429,19 @@ io_skip:
|
|||||||
stm %r0,%r7,__PT_R0(%r11)
|
stm %r0,%r7,__PT_R0(%r11)
|
||||||
mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
|
mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
|
||||||
stm %r8,%r9,__PT_PSW(%r11)
|
stm %r8,%r9,__PT_PSW(%r11)
|
||||||
|
mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
|
||||||
TRACE_IRQS_OFF
|
TRACE_IRQS_OFF
|
||||||
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
|
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
|
||||||
|
io_loop:
|
||||||
l %r1,BASED(.Ldo_IRQ)
|
l %r1,BASED(.Ldo_IRQ)
|
||||||
lr %r2,%r11 # pass pointer to pt_regs
|
lr %r2,%r11 # pass pointer to pt_regs
|
||||||
basr %r14,%r1 # call do_IRQ
|
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:
|
io_return:
|
||||||
LOCKDEP_SYS_EXIT
|
LOCKDEP_SYS_EXIT
|
||||||
TRACE_IRQS_ON
|
TRACE_IRQS_ON
|
||||||
@ -573,10 +581,10 @@ ext_skip:
|
|||||||
stm %r0,%r7,__PT_R0(%r11)
|
stm %r0,%r7,__PT_R0(%r11)
|
||||||
mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
|
mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
|
||||||
stm %r8,%r9,__PT_PSW(%r11)
|
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
|
TRACE_IRQS_OFF
|
||||||
lr %r2,%r11 # pass pointer to pt_regs
|
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)
|
l %r1,BASED(.Ldo_extint)
|
||||||
basr %r14,%r1 # call do_extint
|
basr %r14,%r1 # call do_extint
|
||||||
j io_return
|
j io_return
|
||||||
|
@ -54,7 +54,7 @@ void handle_signal32(unsigned long sig, struct k_sigaction *ka,
|
|||||||
void do_notify_resume(struct pt_regs *regs);
|
void do_notify_resume(struct pt_regs *regs);
|
||||||
|
|
||||||
struct ext_code;
|
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 do_restart(void);
|
||||||
void __init startup_init(void);
|
void __init startup_init(void);
|
||||||
void die(struct pt_regs *regs, const char *str);
|
void die(struct pt_regs *regs, const char *str);
|
||||||
|
@ -460,10 +460,18 @@ io_skip:
|
|||||||
stmg %r0,%r7,__PT_R0(%r11)
|
stmg %r0,%r7,__PT_R0(%r11)
|
||||||
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
|
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
|
||||||
stmg %r8,%r9,__PT_PSW(%r11)
|
stmg %r8,%r9,__PT_PSW(%r11)
|
||||||
|
mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
|
||||||
TRACE_IRQS_OFF
|
TRACE_IRQS_OFF
|
||||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||||
|
io_loop:
|
||||||
lgr %r2,%r11 # pass pointer to pt_regs
|
lgr %r2,%r11 # pass pointer to pt_regs
|
||||||
brasl %r14,do_IRQ
|
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:
|
io_return:
|
||||||
LOCKDEP_SYS_EXIT
|
LOCKDEP_SYS_EXIT
|
||||||
TRACE_IRQS_ON
|
TRACE_IRQS_ON
|
||||||
@ -605,13 +613,13 @@ ext_skip:
|
|||||||
stmg %r0,%r7,__PT_R0(%r11)
|
stmg %r0,%r7,__PT_R0(%r11)
|
||||||
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
|
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
|
||||||
stmg %r8,%r9,__PT_PSW(%r11)
|
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
|
TRACE_IRQS_OFF
|
||||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||||
lghi %r1,4096
|
|
||||||
lgr %r2,%r11 # pass pointer to pt_regs
|
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
|
brasl %r14,do_extint
|
||||||
j io_return
|
j io_return
|
||||||
|
|
||||||
|
@ -234,9 +234,9 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(unregister_external_interrupt);
|
EXPORT_SYMBOL(unregister_external_interrupt);
|
||||||
|
|
||||||
void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
|
void __irq_entry do_extint(struct pt_regs *regs)
|
||||||
unsigned int param32, unsigned long param64)
|
|
||||||
{
|
{
|
||||||
|
struct ext_code ext_code;
|
||||||
struct pt_regs *old_regs;
|
struct pt_regs *old_regs;
|
||||||
struct ext_int_info *p;
|
struct ext_int_info *p;
|
||||||
int index;
|
int index;
|
||||||
@ -248,6 +248,7 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
|
|||||||
clock_comparator_work();
|
clock_comparator_work();
|
||||||
}
|
}
|
||||||
kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);
|
kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);
|
||||||
|
ext_code = *(struct ext_code *) ®s->int_code;
|
||||||
if (ext_code.code != 0x1004)
|
if (ext_code.code != 0x1004)
|
||||||
__get_cpu_var(s390_idle).nohz_delay = 1;
|
__get_cpu_var(s390_idle).nohz_delay = 1;
|
||||||
|
|
||||||
@ -255,7 +256,8 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
|
|||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
|
list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
|
||||||
if (likely(p->code == ext_code.code))
|
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();
|
rcu_read_unlock();
|
||||||
irq_exit();
|
irq_exit();
|
||||||
set_irq_regs(old_regs);
|
set_irq_regs(old_regs);
|
||||||
|
@ -568,7 +568,7 @@ out:
|
|||||||
*/
|
*/
|
||||||
void __irq_entry do_IRQ(struct pt_regs *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 subchannel *sch;
|
||||||
struct irb *irb;
|
struct irb *irb;
|
||||||
struct pt_regs *old_regs;
|
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)
|
if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
|
||||||
/* Serve timer interrupts first. */
|
/* Serve timer interrupts first. */
|
||||||
clock_comparator_work();
|
clock_comparator_work();
|
||||||
/*
|
|
||||||
* Get interrupt information from lowcore
|
kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
|
||||||
*/
|
irb = (struct irb *) &S390_lowcore.irb;
|
||||||
tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
|
if (tpi_info->adapter_IO) {
|
||||||
irb = (struct irb *)&S390_lowcore.irb;
|
do_adapter_IO(tpi_info->isc);
|
||||||
do {
|
goto out;
|
||||||
kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
|
}
|
||||||
if (tpi_info->adapter_IO) {
|
sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
|
||||||
do_adapter_IO(tpi_info->isc);
|
if (!sch) {
|
||||||
continue;
|
/* Clear pending interrupt condition. */
|
||||||
}
|
inc_irq_stat(IRQIO_CIO);
|
||||||
sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
|
tsch(tpi_info->schid, irb);
|
||||||
if (!sch) {
|
goto out;
|
||||||
/* Clear pending interrupt condition. */
|
}
|
||||||
|
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);
|
inc_irq_stat(IRQIO_CIO);
|
||||||
tsch(tpi_info->schid, irb);
|
} else
|
||||||
continue;
|
inc_irq_stat(IRQIO_CIO);
|
||||||
}
|
spin_unlock(sch->lock);
|
||||||
spin_lock(sch->lock);
|
out:
|
||||||
/* 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
|
|
||||||
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);
|
|
||||||
irq_exit();
|
irq_exit();
|
||||||
set_irq_regs(old_regs);
|
set_irq_regs(old_regs);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user