diff options
| author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-06-17 14:54:02 +0200 | 
|---|---|---|
| committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-06-26 21:10:23 +0200 | 
| commit | 48f6b00c6e3190b786c44731b25ac124c81c2247 (patch) | |
| tree | c06d6ba767544eba04a2cd47db1c303f6a35d9f7 | |
| parent | 4bdb613ff45ef5f2848584b250f8a65f6d6c5755 (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>
| -rw-r--r-- | arch/s390/include/asm/ptrace.h | 1 | ||||
| -rw-r--r-- | arch/s390/kernel/asm-offsets.c | 1 | ||||
| -rw-r--r-- | arch/s390/kernel/entry.S | 12 | ||||
| -rw-r--r-- | arch/s390/kernel/entry.h | 2 | ||||
| -rw-r--r-- | arch/s390/kernel/entry64.S | 16 | ||||
| -rw-r--r-- | arch/s390/kernel/irq.c | 8 | ||||
| -rw-r--r-- | drivers/s390/cio/cio.c | 68 | 
7 files changed, 58 insertions, 50 deletions
| diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 559512a455da..52b56533c57c 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -24,6 +24,7 @@ struct pt_regs  	unsigned long gprs[NUM_GPRS];  	unsigned long orig_gpr2;  	unsigned int int_code; +	unsigned int int_parm;  	unsigned long int_parm_long;  }; diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 7a82f9f70100..d6de844bc30a 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -47,6 +47,7 @@ int main(void)  	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(); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 4d5e6f8a7978..be7a408be7a1 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -429,11 +429,19 @@ io_skip:  	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 @@ -573,10 +581,10 @@ ext_skip:  	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 diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index aa0ab02e9595..3ddbc26d246e 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -54,7 +54,7 @@ void handle_signal32(unsigned long sig, struct k_sigaction *ka,  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); diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 4c17eece707e..bc5864c5148b 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -460,10 +460,18 @@ io_skip:  	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 @@ -605,13 +613,13 @@ ext_skip:  	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 diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index dd3c1994b8bd..54b0995514e8 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -234,9 +234,9 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler)  }  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; @@ -248,6 +248,7 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,  		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; @@ -255,7 +256,8 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,  	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); 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 *) ®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);  } | 
