forked from mirrors/linux
		
	[S390] cleanup lowcore access from external interrupts
Read external interrupts parameters from the lowcore in the first level interrupt handler in entry[64].S. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
		
							parent
							
								
									1e54622e04
								
							
						
					
					
						commit
						f6649a7e5a
					
				
					 15 changed files with 57 additions and 49 deletions
				
			
		| 
						 | 
				
			
			@ -12,7 +12,7 @@
 | 
			
		|||
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
 | 
			
		||||
typedef void (*ext_int_handler_t)(__u16 code);
 | 
			
		||||
typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
 | 
			
		||||
 | 
			
		||||
typedef struct ext_int_info_t {
 | 
			
		||||
	struct ext_int_info_t *next;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -143,10 +143,8 @@ int main(void)
 | 
			
		|||
	DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area));
 | 
			
		||||
	DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
 | 
			
		||||
#ifdef CONFIG_32BIT
 | 
			
		||||
	DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params));
 | 
			
		||||
	DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
 | 
			
		||||
#else /* CONFIG_32BIT */
 | 
			
		||||
	DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params2));
 | 
			
		||||
	DEFINE(__LC_EXT_PARAMS2, offsetof(struct _lowcore, ext_params2));
 | 
			
		||||
	DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, floating_pt_save_area));
 | 
			
		||||
	DEFINE(__LC_PASTE, offsetof(struct _lowcore, paste));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -722,7 +722,8 @@ ext_no_vtime:
 | 
			
		|||
	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 | 
			
		||||
	TRACE_IRQS_OFF
 | 
			
		||||
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 | 
			
		||||
	lh	%r3,__LC_EXT_INT_CODE	# get interruption code
 | 
			
		||||
	l	%r3,__LC_CPU_ADDRESS	# get cpu address + interruption code
 | 
			
		||||
	l	%r4,__LC_EXT_PARAMS	# get external parameters
 | 
			
		||||
	l	%r1,BASED(.Ldo_extint)
 | 
			
		||||
	basr	%r14,%r1
 | 
			
		||||
	b	BASED(io_return)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ void do_signal(struct pt_regs *regs);
 | 
			
		|||
int handle_signal32(unsigned long sig, struct k_sigaction *ka,
 | 
			
		||||
		    siginfo_t *info, sigset_t *oldset, struct pt_regs *regs);
 | 
			
		||||
 | 
			
		||||
void do_extint(struct pt_regs *regs, unsigned short code);
 | 
			
		||||
void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long);
 | 
			
		||||
int __cpuinit start_secondary(void *cpuvoid);
 | 
			
		||||
void __init startup_init(void);
 | 
			
		||||
void die(const char * str, struct pt_regs * regs, long err);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -727,8 +727,11 @@ ext_int_handler:
 | 
			
		|||
ext_no_vtime:
 | 
			
		||||
	HANDLE_SIE_INTERCEPT
 | 
			
		||||
	TRACE_IRQS_OFF
 | 
			
		||||
	lghi	%r1,4096
 | 
			
		||||
	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 | 
			
		||||
	llgh	%r3,__LC_EXT_INT_CODE	# get interruption code
 | 
			
		||||
	llgf	%r3,__LC_CPU_ADDRESS	# 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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,12 +113,15 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
 | 
			
		||||
void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
 | 
			
		||||
			   unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	struct pt_regs *old_regs;
 | 
			
		||||
	unsigned short code;
 | 
			
		||||
        ext_int_info_t *p;
 | 
			
		||||
        int index;
 | 
			
		||||
	struct pt_regs *old_regs;
 | 
			
		||||
 | 
			
		||||
	code = (unsigned short) ext_int_code;
 | 
			
		||||
	old_regs = set_irq_regs(regs);
 | 
			
		||||
	s390_idle_check(regs, S390_lowcore.int_clock,
 | 
			
		||||
			S390_lowcore.async_enter_timer);
 | 
			
		||||
| 
						 | 
				
			
			@ -132,7 +135,7 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
 | 
			
		|||
        index = ext_hash(code);
 | 
			
		||||
	for (p = ext_int_hash[index]; p; p = p->next) {
 | 
			
		||||
		if (likely(p->code == code))
 | 
			
		||||
			p->handler(code);
 | 
			
		||||
			p->handler(ext_int_code, param32, param64);
 | 
			
		||||
	}
 | 
			
		||||
	irq_exit();
 | 
			
		||||
	set_irq_regs(old_regs);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -156,7 +156,8 @@ void smp_send_stop(void)
 | 
			
		|||
 * cpus are handled.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static void do_ext_call_interrupt(__u16 code)
 | 
			
		||||
static void do_ext_call_interrupt(unsigned int ext_int_code,
 | 
			
		||||
				  unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long bits;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,7 +155,9 @@ void init_cpu_timer(void)
 | 
			
		|||
	__ctl_set_bit(0, 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clock_comparator_interrupt(__u16 code)
 | 
			
		||||
static void clock_comparator_interrupt(unsigned int ext_int_code,
 | 
			
		||||
				       unsigned int param32,
 | 
			
		||||
				       unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	if (S390_lowcore.clock_comparator == -1ULL)
 | 
			
		||||
		set_clock_comparator(S390_lowcore.clock_comparator);
 | 
			
		||||
| 
						 | 
				
			
			@ -164,14 +166,13 @@ static void clock_comparator_interrupt(__u16 code)
 | 
			
		|||
static void etr_timing_alert(struct etr_irq_parm *);
 | 
			
		||||
static void stp_timing_alert(struct stp_irq_parm *);
 | 
			
		||||
 | 
			
		||||
static void timing_alert_interrupt(__u16 code)
 | 
			
		||||
static void timing_alert_interrupt(unsigned int ext_int_code,
 | 
			
		||||
				   unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	if (S390_lowcore.ext_params & 0x00c40000)
 | 
			
		||||
		etr_timing_alert((struct etr_irq_parm *)
 | 
			
		||||
				 &S390_lowcore.ext_params);
 | 
			
		||||
	if (S390_lowcore.ext_params & 0x00038000)
 | 
			
		||||
		stp_timing_alert((struct stp_irq_parm *)
 | 
			
		||||
				 &S390_lowcore.ext_params);
 | 
			
		||||
	if (param32 & 0x00c40000)
 | 
			
		||||
		etr_timing_alert((struct etr_irq_parm *) ¶m32);
 | 
			
		||||
	if (param32 & 0x00038000)
 | 
			
		||||
		stp_timing_alert((struct stp_irq_parm *) ¶m32);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void etr_reset(void);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -314,7 +314,8 @@ static void do_callbacks(struct list_head *cb_list)
 | 
			
		|||
/*
 | 
			
		||||
 * Handler for the virtual CPU timer.
 | 
			
		||||
 */
 | 
			
		||||
static void do_cpu_timer_interrupt(__u16 error_code)
 | 
			
		||||
static void do_cpu_timer_interrupt(unsigned int ext_int_code,
 | 
			
		||||
				   unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	struct vtimer_queue *vq;
 | 
			
		||||
	struct vtimer_list *event, *tmp;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -542,7 +542,8 @@ void pfault_fini(void)
 | 
			
		|||
		: : "a" (&refbk), "m" (refbk) : "cc");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pfault_interrupt(__u16 int_code)
 | 
			
		||||
static void pfault_interrupt(unsigned int ext_int_code,
 | 
			
		||||
			     unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	struct task_struct *tsk;
 | 
			
		||||
	__u16 subcode;
 | 
			
		||||
| 
						 | 
				
			
			@ -553,14 +554,18 @@ static void pfault_interrupt(__u16 int_code)
 | 
			
		|||
	 * in the 'cpu address' field associated with the
 | 
			
		||||
         * external interrupt. 
 | 
			
		||||
	 */
 | 
			
		||||
	subcode = S390_lowcore.cpu_addr;
 | 
			
		||||
	subcode = ext_int_code >> 16;
 | 
			
		||||
	if ((subcode & 0xff00) != __SUBCODE_MASK)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Get the token (= address of the task structure of the affected task).
 | 
			
		||||
	 */
 | 
			
		||||
	tsk = *(struct task_struct **) __LC_PFAULT_INTPARM;
 | 
			
		||||
#ifdef CONFIG_64BIT
 | 
			
		||||
	tsk = *(struct task_struct **) param64;
 | 
			
		||||
#else
 | 
			
		||||
	tsk = *(struct task_struct **) param32;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (subcode & 0x0080) {
 | 
			
		||||
		/* signal bit is set -> a page has been swapped in by VM */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -228,25 +228,22 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/* Handle external interruption. */
 | 
			
		||||
static void
 | 
			
		||||
dasd_ext_handler(__u16 code)
 | 
			
		||||
static void dasd_ext_handler(unsigned int ext_int_code,
 | 
			
		||||
			     unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	struct dasd_ccw_req *cqr, *next;
 | 
			
		||||
	struct dasd_device *device;
 | 
			
		||||
	unsigned long long expires;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	u8 int_code, status;
 | 
			
		||||
	addr_t ip;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
 | 
			
		||||
	status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
 | 
			
		||||
	switch (int_code) {
 | 
			
		||||
	switch (ext_int_code >> 24) {
 | 
			
		||||
	case DASD_DIAG_CODE_31BIT:
 | 
			
		||||
		ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
 | 
			
		||||
		ip = (addr_t) param32;
 | 
			
		||||
		break;
 | 
			
		||||
	case DASD_DIAG_CODE_64BIT:
 | 
			
		||||
		ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
 | 
			
		||||
		ip = (addr_t) param64;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +278,7 @@ dasd_ext_handler(__u16 code)
 | 
			
		|||
	cqr->stopclk = get_clock();
 | 
			
		||||
 | 
			
		||||
	expires = 0;
 | 
			
		||||
	if (status == 0) {
 | 
			
		||||
	if ((ext_int_code & 0xff0000) == 0) {
 | 
			
		||||
		cqr->status = DASD_CQR_SUCCESS;
 | 
			
		||||
		/* Start first request on queue if possible -> fast_io. */
 | 
			
		||||
		if (!list_empty(&device->ccw_queue)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -296,8 +293,8 @@ dasd_ext_handler(__u16 code)
 | 
			
		|||
	} else {
 | 
			
		||||
		cqr->status = DASD_CQR_QUEUED;
 | 
			
		||||
		DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "
 | 
			
		||||
			    "request %p was %d (%d retries left)", cqr, status,
 | 
			
		||||
			    cqr->retries);
 | 
			
		||||
			      "request %p was %d (%d retries left)", cqr,
 | 
			
		||||
			      (ext_int_code >> 16) & 0xff, cqr->retries);
 | 
			
		||||
		dasd_diag_erp(device);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,10 +18,6 @@
 | 
			
		|||
#define DEV_CLASS_FBA	0x01
 | 
			
		||||
#define DEV_CLASS_ECKD	0x04
 | 
			
		||||
 | 
			
		||||
#define DASD_DIAG_LC_INT_CODE		132
 | 
			
		||||
#define DASD_DIAG_LC_INT_STATUS		133
 | 
			
		||||
#define DASD_DIAG_LC_INT_PARM_31BIT	128
 | 
			
		||||
#define DASD_DIAG_LC_INT_PARM_64BIT	4536
 | 
			
		||||
#define DASD_DIAG_CODE_31BIT		0x03
 | 
			
		||||
#define DASD_DIAG_CODE_64BIT		0x07
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -395,16 +395,16 @@ __sclp_find_req(u32 sccb)
 | 
			
		|||
/* Handler for external interruption. Perform request post-processing.
 | 
			
		||||
 * Prepare read event data request if necessary. Start processing of next
 | 
			
		||||
 * request on queue. */
 | 
			
		||||
static void
 | 
			
		||||
sclp_interrupt_handler(__u16 code)
 | 
			
		||||
static void sclp_interrupt_handler(unsigned int ext_int_code,
 | 
			
		||||
				   unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	struct sclp_req *req;
 | 
			
		||||
	u32 finished_sccb;
 | 
			
		||||
	u32 evbuf_pending;
 | 
			
		||||
 | 
			
		||||
	spin_lock(&sclp_lock);
 | 
			
		||||
	finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
 | 
			
		||||
	evbuf_pending = S390_lowcore.ext_params & 0x3;
 | 
			
		||||
	finished_sccb = param32 & 0xfffffff8;
 | 
			
		||||
	evbuf_pending = param32 & 0x3;
 | 
			
		||||
	if (finished_sccb) {
 | 
			
		||||
		del_timer(&sclp_request_timer);
 | 
			
		||||
		sclp_running_state = sclp_running_state_reset_pending;
 | 
			
		||||
| 
						 | 
				
			
			@ -819,12 +819,12 @@ EXPORT_SYMBOL(sclp_reactivate);
 | 
			
		|||
 | 
			
		||||
/* Handler for external interruption used during initialization. Modify
 | 
			
		||||
 * request state to done. */
 | 
			
		||||
static void
 | 
			
		||||
sclp_check_handler(__u16 code)
 | 
			
		||||
static void sclp_check_handler(unsigned int ext_int_code,
 | 
			
		||||
			       unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	u32 finished_sccb;
 | 
			
		||||
 | 
			
		||||
	finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
 | 
			
		||||
	finished_sccb = param32 & 0xfffffff8;
 | 
			
		||||
	/* Is this the interrupt we are waiting for? */
 | 
			
		||||
	if (finished_sccb == 0)
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -372,21 +372,22 @@ static void hotplug_devices(struct work_struct *dummy)
 | 
			
		|||
/*
 | 
			
		||||
 * we emulate the request_irq behaviour on top of s390 extints
 | 
			
		||||
 */
 | 
			
		||||
static void kvm_extint_handler(u16 code)
 | 
			
		||||
static void kvm_extint_handler(unsigned int ext_int_code,
 | 
			
		||||
			       unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	struct virtqueue *vq;
 | 
			
		||||
	u16 subcode;
 | 
			
		||||
	u32 param;
 | 
			
		||||
 | 
			
		||||
	subcode = S390_lowcore.cpu_addr;
 | 
			
		||||
	subcode = ext_int_code >> 16;
 | 
			
		||||
	if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* The LSB might be overloaded, we have to mask it */
 | 
			
		||||
	vq = (struct virtqueue *)(S390_lowcore.ext_params2 & ~1UL);
 | 
			
		||||
	vq = (struct virtqueue *)(param64 & ~1UL);
 | 
			
		||||
 | 
			
		||||
	/* We use ext_params to decide what this interrupt means */
 | 
			
		||||
	param = S390_lowcore.ext_params & VIRTIO_PARAM_MASK;
 | 
			
		||||
	param = param32 & VIRTIO_PARAM_MASK;
 | 
			
		||||
 | 
			
		||||
	switch (param) {
 | 
			
		||||
	case VIRTIO_PARAM_CONFIG_CHANGED:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1798,7 +1798,8 @@ static void iucv_work_fn(struct work_struct *work)
 | 
			
		|||
 * Handles external interrupts coming in from CP.
 | 
			
		||||
 * Places the interrupt buffer on a queue and schedules iucv_tasklet_fn().
 | 
			
		||||
 */
 | 
			
		||||
static void iucv_external_interrupt(u16 code)
 | 
			
		||||
static void iucv_external_interrupt(unsigned int ext_int_code,
 | 
			
		||||
				    unsigned int param32, unsigned long param64)
 | 
			
		||||
{
 | 
			
		||||
	struct iucv_irq_data *p;
 | 
			
		||||
	struct iucv_irq_list *work;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue