patch-2.4.18 linux/arch/s390x/kernel/time.c

Next file: linux/arch/s390x/kernel/traps.c
Previous file: linux/arch/s390x/kernel/smp.c
Back to the patch index
Back to the overall index

diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/arch/s390x/kernel/time.c linux/arch/s390x/kernel/time.c
@@ -33,65 +33,33 @@
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
 
-
 /* change this if you have some constant time drift */
-#define USECS_PER_JIFFY ((signed long)1000000/HZ)
-#define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12)
+#define USECS_PER_JIFFY     ((unsigned long) 1000000/HZ)
+#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
 
 #define TICK_SIZE tick
 
-static uint64_t init_timer_cc, last_timer_cc;
+static uint64_t init_timer_cc;
 
 extern rwlock_t xtime_lock;
 extern unsigned long wall_jiffies;
 
-void tod_to_timeval(uint64_t todval, struct timeval *xtime)
+void tod_to_timeval(__u64 todval, struct timeval *xtime)
 {
-#if 0
-        const int high_bit = 0x80000000L;
-        const int c_f4240 = 0xf4240L;
-        const int c_7a120 = 0x7a120;
-	/* We have to divide the 64 bit value todval by 4096
-	 * (because the 2^12 bit is the one that changes every 
-         * microsecond) and then split it into seconds and
-         * microseconds. A value of max (2^52-1) divided by
-         * the value 0xF4240 can yield a max result of approx
-         * (2^32.068). Thats to big to fit into a signed int
-	 *   ... hacking time!
-         */
-	asm volatile ("L     2,%1\n\t"
-		      "LR    3,2\n\t"
-		      "SRL   2,12\n\t"
-		      "SLL   3,20\n\t"
-		      "L     4,%O1+4(%R1)\n\t"
-		      "SRL   4,12\n\t"
-		      "OR    3,4\n\t"  /* now R2/R3 contain (todval >> 12) */
-		      "SR    4,4\n\t"
-		      "CL    2,%2\n\t"
-		      "JL    .+12\n\t"
-		      "S     2,%2\n\t"
-		      "L     4,%3\n\t"
-                      "D     2,%4\n\t"
-		      "OR    3,4\n\t"
-		      "ST    2,%O0+4(%R0)\n\t"
-		      "ST    3,%0"
-		      : "=m" (*xtime) : "m" (todval),
-		        "m" (c_7a120), "m" (high_bit), "m" (c_f4240)
-		      : "cc", "memory", "2", "3", "4" );
-#else
-    todval >>= 12;
-    xtime->tv_sec = todval / 1000000;
-    xtime->tv_usec = todval % 1000000;
-#endif
+        todval >>= 12;
+        xtime->tv_sec = todval / 1000000;
+        xtime->tv_usec = todval % 1000000;
 }
 
-unsigned long do_gettimeoffset(void) 
+static inline unsigned long do_gettimeoffset(void) 
 {
-	__u64 timer_cc;
+	__u64 now;
 
-	asm volatile ("STCK %0" : "=m" (timer_cc));
-        /* We require the offset from the previous interrupt */
-        return ((unsigned long)((timer_cc - last_timer_cc)>>12));
+	asm ("STCK %0" : "=m" (now));
+        now = (now - init_timer_cc) >> 12;
+	/* We require the offset from the latest update of xtime */
+	now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
+	return (unsigned long) now;
 }
 
 /*
@@ -101,15 +69,10 @@
 {
 	unsigned long flags;
 	unsigned long usec, sec;
-	unsigned long lost_ticks;
 
 	read_lock_irqsave(&xtime_lock, flags);
-	lost_ticks = jiffies - wall_jiffies;
-	usec = do_gettimeoffset();
-	if (lost_ticks)
-		usec +=(USECS_PER_JIFFY*lost_ticks);
 	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
+	usec = xtime.tv_usec + do_gettimeoffset();
 	read_unlock_irqrestore(&xtime_lock, flags);
 
 	while (usec >= 1000000) {
@@ -155,51 +118,31 @@
 extern __u16 boot_cpu_addr;
 #endif
 
-void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
+static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
 {
 	int cpu = smp_processor_id();
 
 	irq_enter(cpu, 0);
 
-        /*
-         * reset timer to 10ms minus time already elapsed
-         * since timer-interrupt pending
-         */
+	/*
+	 * set clock comparator for next tick
+	 */
+        S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
+        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
+
 #ifdef CONFIG_SMP
-	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) {
+	if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr)
 		write_lock(&xtime_lock);
-		last_timer_cc = S390_lowcore.jiffy_timer_cc;
-	}
-#else
-        last_timer_cc = S390_lowcore.jiffy_timer_cc;
-#endif
-        /* set clock comparator */
-        S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
-        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
 
-/*
- * In the SMP case we use the local timer interrupt to do the
- * profiling, except when we simulate SMP mode on a uniprocessor
- * system, in that case we have to call the local interrupt handler.
- */
-#ifdef CONFIG_SMP
-        /* when SMP, do smp_local_timer_interrupt for *all* CPUs,
-           but only do the rest for the boot CPU */
-        smp_local_timer_interrupt(regs);
-#else
-        if (!user_mode(regs))
-                s390_do_profile(regs->psw.addr);
-#endif
+	update_process_times(user_mode(regs));
 
-#ifdef CONFIG_SMP
-	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr)
-#endif
-	{
+	if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) {
 		do_timer(regs);
-#ifdef CONFIG_SMP
 		write_unlock(&xtime_lock);
-#endif
 	}
+#else
+	do_timer(regs);
+#endif
 
 	irq_exit(cpu, 0);
 }
@@ -207,19 +150,17 @@
 /*
  * Start the clock comparator on the current CPU
  */
-static unsigned long cr0 __attribute__ ((aligned (8)));
-
-void init_100hz_timer(void)
+void init_cpu_timer(void)
 {
+	unsigned long cr0;
+
         /* allow clock comparator timer interrupt */
         asm volatile ("STCTG 0,0,%0" : "=m" (cr0) : : "memory");
         cr0 |= 0x800;
         asm volatile ("LCTLG 0,0,%0" : : "m" (cr0) : "memory");
-        /* set clock comparator */
-        /* read the TOD clock */
-        asm volatile ("STCK %0" : "=m" (S390_lowcore.jiffy_timer_cc));
-        S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
-        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
+	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
+	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
+	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
 }
 
 /*
@@ -228,6 +169,7 @@
  */
 void __init time_init(void)
 {
+        __u64 set_time_cc;
 	int cc;
 
         /* kick the TOD clock */
@@ -247,15 +189,16 @@
                 printk("time_init: TOD clock stopped/non-operational\n");
                 break;
         }
+
+	/* set xtime */
+        set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
+                      (0x3c26700LL*1000000*4096);
+        tod_to_timeval(set_time_cc, &xtime);
+
         /* request the 0x1004 external interrupt */
-        if (register_external_interrupt(0x1004, do_timer_interrupt) != 0)
-                panic("Couldn't request external interrupts 0x1004");
-        init_100hz_timer();
-        init_timer_cc = S390_lowcore.jiffy_timer_cc;
-        init_timer_cc -= 0x8126d60e46000000LL -
-                         (0x3c26700LL*1000000*4096);
-        tod_to_timeval(init_timer_cc, &xtime);
+        if (register_external_interrupt(0x1004, do_comparator_interrupt) != 0)
+                panic("Couldn't request external interrupt 0x1004");
 
-	/* Set do_get_fast_time function pointer.  */
-	do_get_fast_time = do_gettimeofday;
+        /* init CPU timer */
+        init_cpu_timer();
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)