[S390] cleanup lowcore access from external interrupts
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 25 Oct 2010 14:10:38 +0000 (16:10 +0200)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Mon, 25 Oct 2010 14:10:19 +0000 (16:10 +0200)
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>
15 files changed:
arch/s390/include/asm/s390_ext.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry.h
arch/s390/kernel/entry64.S
arch/s390/kernel/s390_ext.c
arch/s390/kernel/smp.c
arch/s390/kernel/time.c
arch/s390/kernel/vtime.c
arch/s390/mm/fault.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_diag.h
drivers/s390/char/sclp.c
drivers/s390/kvm/kvm_virtio.c
net/iucv/iucv.c

index 2afc060..1a9307e 100644 (file)
@@ -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;
index 76328de..f3c1b82 100644 (file)
@@ -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));
index adf2524..736d701 100644 (file)
@@ -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)
index 714ff2e..95c1dfc 100644 (file)
@@ -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);
index 2d205e4..e4038ea 100644 (file)
@@ -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
 
index 9ce641b..bd1db50 100644 (file)
@@ -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);
index 8127ebd..354589d 100644 (file)
@@ -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;
 
index 2896cac..f754a6d 100644 (file)
@@ -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 *) &param32);
+       if (param32 & 0x00038000)
+               stp_timing_alert((struct stp_irq_parm *) &param32);
 }
 
 static void etr_reset(void);
index 3479f1b..56c8687 100644 (file)
@@ -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;
index b657006..b4aad0c 100644 (file)
@@ -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 */
index 2b3bc3e..266b34b 100644 (file)
@@ -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);
        }
 
index b8c7826..4f71fbe 100644 (file)
 #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
 
index 5707a80..35cc468 100644 (file)
@@ -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;
index 5a46b8c..375aeea 100644 (file)
@@ -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:
index 499c045..f7db676 100644 (file)
@@ -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;