]> git.hungrycats.org Git - linux/commitdiff
[PATCH] s390: system tick misaccounting.
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 26 Sep 2003 01:01:37 +0000 (18:01 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Fri, 26 Sep 2003 01:01:37 +0000 (18:01 -0700)
Fix system tick misaccounting problem.

arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/s390_ext.c
arch/s390/kernel/time.c
drivers/s390/block/dasd_diag.c
drivers/s390/char/sclp.c
drivers/s390/cio/cio.c
include/asm-s390/hardirq.h
include/asm-s390/lowcore.h

index 1d06b3258cb41c41edad14631a237b2734aa25e5..5c2e6861c5c3bc84b8dc6c5391ccd4ad04386d1d 100644 (file)
@@ -515,12 +515,9 @@ io_int_handler:
        SAVE_ALL_BASE
         SAVE_ALL __LC_IO_OLD_PSW,0
         GET_THREAD_INFO           # load pointer to task_struct to R9
+       stck    __LC_INT_CLOCK
         l       %r1,BASED(.Ldo_IRQ)        # load address of do_IRQ
         la      %r2,SP_PTREGS(%r15) # address of register-save area
-        sr      %r3,%r3
-        icm     %r3,3,__LC_SUBCHANNEL_NR   # load subchannel nr & extend to int
-        l       %r4,__LC_IO_INT_PARM       # load interruption parm
-       l       %r5,__LC_IO_INT_WORD       # load interruption word
         basr    %r14,%r1          # branch to standard irq handler
 
 io_return:
@@ -609,26 +606,11 @@ ext_int_handler:
        SAVE_ALL_BASE
         SAVE_ALL __LC_EXT_OLD_PSW,0
         GET_THREAD_INFO                # load pointer to task_struct to R9
+       stck    __LC_INT_CLOCK
+       la      %r2,SP_PTREGS(%r15)    # address of register-save area
+       lh      %r3,__LC_EXT_INT_CODE  # get interruption code
        l       %r1,BASED(.Ldo_extint)
        basr    %r14,%r1
-       lh      %r6,__LC_EXT_INT_CODE  # get interruption code
-       lr      %r1,%r6                # calculate index = code & 0xff
-       n       %r1,BASED(.Lc0xff)
-       sll     %r1,2
-       l       %r7,BASED(.Lext_hash)
-       l       %r7,0(%r1,%r7)         # get first list entry for hash value
-       ltr     %r7,%r7                # == NULL ?
-       bz      BASED(io_return)       # yes, nothing to do, exit
-ext_int_loop:
-       ch      %r6,8(%r7)             # compare external interrupt code
-       bne     BASED(ext_int_next)
-       l       %r1,4(%r7)             # get handler address
-       la      %r2,SP_PTREGS(%r15)    # address of register-save area
-       lr      %r3,%r6                # interruption code
-       basr    %r14,%r1               # call handler
-ext_int_next:
-       icm     %r7,15,0(%r7)          # next list entry
-       bnz     BASED(ext_int_loop)
        b       BASED(io_return)
 
 /*
index c1e99b1f4f25d2f95ec7dd9824668a5aed368e62..8140fdf2a9844ab5b8e6527457b2a1dfba85088c 100644 (file)
@@ -552,10 +552,8 @@ pgm_svc_nogo:
 io_int_handler:
         SAVE_ALL __LC_IO_OLD_PSW,0
         GET_THREAD_INFO                # load pointer to task_struct to R9
+       stck    __LC_INT_CLOCK
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
-       llgh    %r3,__LC_SUBCHANNEL_NR # load subchannel number
-        llgf    %r4,__LC_IO_INT_PARM   # load interruption parm
-        llgf    %r5,__LC_IO_INT_WORD   # load interruption word
        brasl   %r14,do_IRQ            # call standard irq handler
 
 io_return:
@@ -640,26 +638,10 @@ io_sigpending:
 ext_int_handler:
         SAVE_ALL __LC_EXT_OLD_PSW,0
         GET_THREAD_INFO                # load pointer to task_struct to R9
-       brasl   %r14,do_extint
-       llgh    %r6,__LC_EXT_INT_CODE  # get interruption code
-       lgr     %r1,%r6                # calculate index = code & 0xff
-       nill    %r1,0xff
-       sll     %r1,3
-       larl    %r7,ext_int_hash
-       lg      %r7,0(%r1,%r7)         # get first list entry for hash value
-       ltgr    %r7,%r7                # == NULL ?
-       jz      io_return              # yes, nothing to do, exit
-ext_int_loop:
-       ch      %r6,16(%r7)            # compare external interrupt code
-       jne     ext_int_next
-       lg      %r1,8(%r7)             # get handler address
+       stck    __LC_INT_CLOCK
        la      %r2,SP_PTREGS(%r15)    # address of register-save area
-       lgr     %r3,%r6                # interruption code
-       basr    %r14,%r1               # call handler
-ext_int_next:
-       lg      %r7,0(%r7)             # next list entry
-       ltgr    %r7,%r7
-       jnz     ext_int_loop
+       llgh    %r3,__LC_EXT_INT_CODE  # get interruption code
+       brasl   %r14,do_extint
        j       io_return
 
 /*
index afc5cb5018d786fbf169d8b7b6c01491cdef0a32..2337751b3c78536efbcbd94da83fa133877eec5a 100644 (file)
@@ -26,7 +26,8 @@
  */
 ext_int_info_t *ext_int_hash[256] = { 0, };
 
-int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
+int register_external_interrupt(__u16 code, ext_int_handler_t handler)
+{
         ext_int_info_t *p;
         int index;
 
@@ -42,7 +43,8 @@ int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
 }
 
 int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
-                                     ext_int_info_t *p) {
+                                     ext_int_info_t *p)
+{
         int index;
 
         if (p == NULL)
@@ -55,7 +57,8 @@ int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
         return 0;
 }
 
-int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
+int unregister_external_interrupt(__u16 code, ext_int_handler_t handler)
+{
         ext_int_info_t *p, *q;
         int index;
 
@@ -79,7 +82,8 @@ int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
 }
 
 int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
-                                       ext_int_info_t *p) {
+                                       ext_int_info_t *p)
+{
        ext_int_info_t *q;
        int index;
 
@@ -101,9 +105,23 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
        return 0;
 }
 
-void do_extint(void)
+void do_extint(struct pt_regs *regs, unsigned short code)
 {
+        ext_int_info_t *p;
+        int index;
+
+       irq_enter();
+       if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
+               account_ticks(regs);
        kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
+        index = code & 0xff;
+       for (p = ext_int_hash[index]; p; p = p->next) {
+               if (likely(p->code == code)) {
+                       if (likely(p->handler))
+                               p->handler(regs, code);
+               }
+       }
+       irq_exit();
 }
 
 EXPORT_SYMBOL(register_external_interrupt);
index 4fe6d7e5fe22a7498ab1f9b7e23614c2220fee40..2b48351814551744c85a9ef333e0e8947a486eda 100644 (file)
@@ -166,28 +166,29 @@ __calculate_ticks(__u64 elapsed)
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
+void account_ticks(struct pt_regs *regs)
 {
        __u64 tmp;
        __u32 ticks;
 
        /* Calculate how many ticks have passed. */
-       tmp = get_clock() - S390_lowcore.jiffy_timer;
-       if (tmp >= 2*CLK_TICKS_PER_JIFFY) {  /* more than one tick ? */
-               ticks = __calculate_ticks(tmp);
+       tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
+       if (tmp >= 2*CLK_TICKS_PER_JIFFY) {  /* more than two ticks ? */
+               ticks = __calculate_ticks(tmp) + 1;
                S390_lowcore.jiffy_timer +=
                        CLK_TICKS_PER_JIFFY * (__u64) ticks;
+       } else if (tmp >= CLK_TICKS_PER_JIFFY) {
+               ticks = 2;
+               S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY;
        } else {
                ticks = 1;
                S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
        }
 
        /* set clock comparator for next tick */
-       tmp = S390_lowcore.jiffy_timer + CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
+       tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
         asm volatile ("SCKC %0" : : "m" (tmp));
 
-       irq_enter();
-
 #ifdef CONFIG_SMP
        /*
         * Do not rely on the boot cpu to do the calls to do_timer.
@@ -215,8 +216,6 @@ static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
        while (ticks--)
                do_timer(regs);
 #endif
-
-       irq_exit();
 }
 
 /*
@@ -228,7 +227,7 @@ void init_cpu_timer(void)
        __u64 timer;
 
        timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY;
-       S390_lowcore.jiffy_timer = timer;
+       S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY;
        timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
        asm volatile ("SCKC %0" : : "m" (timer));
         /* allow clock comparator timer interrupt */
@@ -275,7 +274,7 @@ void __init time_init(void)
                                 -xtime.tv_sec, -xtime.tv_nsec);
 
         /* request the 0x1004 external interrupt */
-        if (register_early_external_interrupt(0x1004, do_comparator_interrupt,
+        if (register_early_external_interrupt(0x1004, 0,
                                              &ext_int_info_timer) != 0)
                 panic("Couldn't request external interrupt 0x1004");
 
index 1897ccdacd2145e87c79af3853513485f2dadadc..ac0bb86863653b0c00fb92aee9b8a05e5e174ba2 100644 (file)
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.31 $
+ * $Revision: 1.32 $
  */
 
 #include <linux/config.h>
@@ -170,7 +170,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
        ip = S390_lowcore.ext_params;
 
        cpu = smp_processor_id();
-       irq_enter();
 
        if (!ip) {              /* no intparm: unsolicited interrupt */
                MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
@@ -218,7 +217,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
        dasd_schedule_bh(device);
 
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-       irq_exit();
 }
 
 static int
index 2b9c8dbe2a6a8afd86249bc30972eaa4e7325155..2aaf356845aceb2b419690cb40bf210d8189c538 100644 (file)
@@ -293,7 +293,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
        finished_sccb = ext_int_param & EXT_INT_SCCB_MASK;
        evbuf_pending = ext_int_param & (EXT_INT_EVBUF_PENDING |
                                         EXT_INT_STATECHANGE_PENDING);
-       irq_enter();
        req = NULL;
        if (finished_sccb != 0U) {
                list_for_each(l, &sclp_req_queue) {
@@ -321,7 +320,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
        spin_unlock(&sclp_lock);
        /* and start next request on the queue */
        sclp_start_request();
-       irq_exit();
 }
 
 /*
index 4e840d087ef133e43249cec9f5b4e6a498ae0dc8..cd426d64a645de6703e98365d419cd4f9eb11dcf 100644 (file)
@@ -588,13 +588,15 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
  *
  */
 void
-do_IRQ (struct pt_regs regs)
+do_IRQ (struct pt_regs *regs)
 {
        struct tpi_info *tpi_info;
        struct subchannel *sch;
        struct irb *irb;
 
        irq_enter ();
+       if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
+               account_ticks(regs);
        /*
         * Get interrupt information from lowcore
         */
@@ -663,7 +665,7 @@ wait_cons_dev (void)
        do {
                spin_unlock(&console_subchannel.lock);
                if (!cio_tpi())
-                       udelay (100);
+                       cpu_relax();
                spin_lock(&console_subchannel.lock);
        } while (console_subchannel.schib.scsw.actl != 0);
        /*
index 4858d62d872444be2b5554ce776f4a975c3ddfb1..e7bd21c229b787b2beab56f40bdd266bbd3bbc00 100644 (file)
@@ -87,6 +87,7 @@ do {                                                                  \
        
 
 extern void do_call_softirq(void);
+extern void account_ticks(struct pt_regs *);
 
 #define invoke_softirq() do_call_softirq()
 
index cc3c82e8d20fe7dd44b781526ca7ba2474cd6456..217c0a613dcdb98d82b7555ad12f2b84d1f782ea 100644 (file)
@@ -66,6 +66,7 @@
 #define __LC_IPLDEV                     0xC7C
 #define __LC_JIFFY_TIMER               0xC80
 #define __LC_CURRENT                   0xC90
+#define __LC_INT_CLOCK                 0xC98
 #else /* __s390x__ */
 #define __LC_KERNEL_STACK               0xD40
 #define __LC_ASYNC_STACK                0xD48
@@ -74,6 +75,7 @@
 #define __LC_IPLDEV                     0xDB8
 #define __LC_JIFFY_TIMER               0xDC0
 #define __LC_CURRENT                   0xDD8
+#define __LC_INT_CLOCK                 0xDE8
 #endif /* __s390x__ */
 
 #define __LC_PANIC_MAGIC                0xE00
@@ -174,7 +176,8 @@ struct _lowcore
        __u32        percpu_offset;            /* 0xc8c */
        __u32        current_task;             /* 0xc90 */
        __u32        softirq_pending;          /* 0xc94 */
-        __u8         pad11[0xe00-0xc98];       /* 0xc98 */
+       __u64        int_clock;                /* 0xc98 */
+        __u8         pad11[0xe00-0xca0];       /* 0xca0 */
 
         /* 0xe00 is used as indicator for dump tools */
         /* whether the kernel died with panic() or not */
@@ -252,7 +255,8 @@ struct _lowcore
        __u64        percpu_offset;            /* 0xdd0 */
        __u64        current_task;             /* 0xdd8 */
        __u64        softirq_pending;          /* 0xde0 */
-        __u8         pad12[0xe00-0xde8];       /* 0xde8 */
+       __u64        int_clock;                /* 0xde8 */
+        __u8         pad12[0xe00-0xdf0];       /* 0xdf0 */
 
         /* 0xe00 is used as indicator for dump tools */
         /* whether the kernel died with panic() or not */