[S390] Calibrate delay and bogomips.
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 5 Feb 2007 20:18:31 +0000 (21:18 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 5 Feb 2007 20:18:31 +0000 (21:18 +0100)
Preset the bogomips number to the cpu capacity value reported by
store system information in SYSIB 1.2.2. This value is constant
for a particular machine model and can be used to determine
relative performance differences between machines.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
12 files changed:
arch/s390/Kconfig
arch/s390/kernel/setup.c
arch/s390/lib/Makefile
arch/s390/lib/qrnnd.S [new file with mode: 0644]
arch/s390/math-emu/Makefile
arch/s390/math-emu/math.c
arch/s390/math-emu/qrnnd.S [deleted file]
arch/s390/math-emu/sfp-util.h [deleted file]
drivers/s390/Makefile
drivers/s390/sysinfo.c
include/asm-s390/processor.h
include/asm-s390/sfp-util.h [new file with mode: 0644]

index 5c7e981c115b1c427d15236910b8166972ee0021..eaed402ad3460a758872ccf271971a36f6042add 100644 (file)
@@ -34,10 +34,6 @@ config GENERIC_HWEIGHT
        bool
        default y
 
-config GENERIC_CALIBRATE_DELAY
-       bool
-       default y
-
 config GENERIC_TIME
        def_bool y
 
index 2569aafcc5438a8a21989a24a537e2682f327f66..2fa866f6f7116b45c33986bb0abbfc7aede84f38 100644 (file)
@@ -938,6 +938,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
         struct cpuinfo_S390 *cpuinfo;
        unsigned long n = (unsigned long) v - 1;
 
+       s390_adjust_jiffies();
        preempt_disable();
        if (!n) {
                seq_printf(m, "vendor_id       : IBM/S390\n"
index b5f94cf3bde8d190d09c66fec8bfcc289d5f3292..7a44fed21b35cb39f1beb1991991ab48bcb3d0a7 100644 (file)
@@ -4,7 +4,7 @@
 
 EXTRA_AFLAGS := -traditional
 
-lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
+lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o
 lib-$(CONFIG_32BIT) += div64.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/qrnnd.S b/arch/s390/lib/qrnnd.S
new file mode 100644 (file)
index 0000000..eb1df63
--- /dev/null
@@ -0,0 +1,77 @@
+# S/390 __udiv_qrnnd
+
+# r2 : &__r
+# r3 : upper half of 64 bit word n
+# r4 : lower half of 64 bit word n
+# r5 : divisor d
+# the reminder r of the division is to be stored to &__r and
+# the quotient q is to be returned
+
+       .text
+       .globl __udiv_qrnnd
+__udiv_qrnnd:
+       st    %r2,24(%r15)        # store pointer to reminder for later
+       lr    %r0,%r3             # reload n
+       lr    %r1,%r4
+       ltr   %r2,%r5             # reload and test divisor
+       jp    5f
+       # divisor >= 0x80000000
+       srdl  %r0,2               # n/4
+       srl   %r2,1               # d/2
+       slr   %r1,%r2             # special case if last bit of d is set
+       brc   3,0f                #  (n/4) div (n/2) can overflow by 1
+       ahi   %r0,-1              #  trick: subtract n/2, then divide
+0:     dr    %r0,%r2             # signed division
+       ahi   %r1,1               #  trick part 2: add 1 to the quotient
+       # now (n >> 2) = (d >> 1) * %r1 + %r0
+       lhi   %r3,1
+       nr    %r3,%r1             # test last bit of q
+       jz    1f
+       alr   %r0,%r2             # add (d>>1) to r
+1:     srl   %r1,1               # q >>= 1
+       # now (n >> 2) = (d&-2) * %r1 + %r0
+       lhi   %r3,1
+       nr    %r3,%r5             # test last bit of d
+       jz    2f
+       slr   %r0,%r1             # r -= q
+       brc   3,2f                # borrow ?
+       alr   %r0,%r5             # r += d
+       ahi   %r1,-1
+2:     # now (n >> 2) = d * %r1 + %r0
+       alr   %r1,%r1             # q <<= 1
+       alr   %r0,%r0             # r <<= 1
+       brc   12,3f               # overflow on r ?
+       slr   %r0,%r5             # r -= d
+       ahi   %r1,1               # q += 1
+3:     lhi   %r3,2
+       nr    %r3,%r4             # test next to last bit of n
+       jz    4f
+       ahi   %r0,1               # r += 1
+4:     clr   %r0,%r5             # r >= d ?
+       jl    6f
+       slr   %r0,%r5             # r -= d
+       ahi   %r1,1               # q += 1
+       # now (n >> 1) = d * %r1 + %r0
+       j     6f
+5:     # divisor < 0x80000000
+       srdl  %r0,1
+       dr    %r0,%r2             # signed division
+       # now (n >> 1) = d * %r1 + %r0
+6:     alr   %r1,%r1             # q <<= 1
+       alr   %r0,%r0             # r <<= 1
+       brc   12,7f               # overflow on r ?
+       slr   %r0,%r5             # r -= d
+       ahi   %r1,1               # q += 1
+7:     lhi   %r3,1
+       nr    %r3,%r4             # isolate last bit of n
+       alr   %r0,%r3             # r += (n & 1)
+       clr   %r0,%r5             # r >= d ?
+       jl    8f
+       slr   %r0,%r5             # r -= d
+       ahi   %r1,1               # q += 1
+8:     # now n = d * %r1 + %r0
+       l     %r2,24(%r15)
+       st    %r0,0(%r2)
+       lr    %r2,%r1
+       br    %r14
+       .end    __udiv_qrnnd
index c10df144f2ab44fe298b60ab1192ad08d8edd115..73b3e72efc46a460cc62a31c59400dbae232dedf 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the FPU instruction emulation.
 #
 
-obj-$(CONFIG_MATHEMU) := math.o qrnnd.o
+obj-$(CONFIG_MATHEMU) := math.o
 
 EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
 EXTRA_AFLAGS := -traditional
index 6b9aec5a2c18dae0283d61904b37b6018691e36c..3ee78ccb617da4783430e79aa67efefec0ceda8c 100644 (file)
@@ -15,7 +15,7 @@
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
 
-#include "sfp-util.h"
+#include <asm/sfp-util.h>
 #include <math-emu/soft-fp.h>
 #include <math-emu/single.h>
 #include <math-emu/double.h>
diff --git a/arch/s390/math-emu/qrnnd.S b/arch/s390/math-emu/qrnnd.S
deleted file mode 100644 (file)
index b01c2b6..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-# S/390 __udiv_qrnnd
-
-# r2 : &__r
-# r3 : upper half of 64 bit word n
-# r4 : lower half of 64 bit word n
-# r5 : divisor d
-# the reminder r of the division is to be stored to &__r and
-# the quotient q is to be returned
-
-        .text
-        .globl __udiv_qrnnd
-__udiv_qrnnd:
-        st    %r2,24(%r15)        # store pointer to reminder for later
-        lr    %r0,%r3             # reload n
-       lr    %r1,%r4
-       ltr   %r2,%r5             # reload and test divisor
-        jp    5f
-        # divisor >= 0x80000000
-       srdl  %r0,2               # n/4
-        srl   %r2,1               # d/2
-        slr   %r1,%r2             # special case if last bit of d is set
-        brc   3,0f                #  (n/4) div (n/2) can overflow by 1
-        ahi   %r0,-1              #  trick: subtract n/2, then divide
-0:      dr    %r0,%r2             # signed division
-        ahi   %r1,1               #  trick part 2: add 1 to the quotient
-        # now (n >> 2) = (d >> 1) * %r1 + %r0
-       lhi   %r3,1
-        nr    %r3,%r1             # test last bit of q
-        jz    1f
-        alr   %r0,%r2             # add (d>>1) to r
-1:      srl   %r1,1               # q >>= 1
-        # now (n >> 2) = (d&-2) * %r1 + %r0
-        lhi   %r3,1
-        nr    %r3,%r5             # test last bit of d
-        jz    2f
-        slr   %r0,%r1             # r -= q
-       brc   3,2f                # borrow ?
-       alr   %r0,%r5             # r += d
-       ahi   %r1,-1
-2:      # now (n >> 2) = d * %r1 + %r0
-        alr   %r1,%r1             # q <<= 1
-        alr   %r0,%r0             # r <<= 1
-        brc   12,3f               # overflow on r ?
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-3:      lhi   %r3,2
-        nr    %r3,%r4             # test next to last bit of n
-        jz    4f
-        ahi   %r0,1               # r += 1
-4:      clr   %r0,%r5             # r >= d ?
-        jl    6f
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-        # now (n >> 1) = d * %r1 + %r0
-        j     6f
-5:      # divisor < 0x80000000
-       srdl  %r0,1
-        dr    %r0,%r2             # signed division
-        # now (n >> 1) = d * %r1 + %r0
-6:      alr   %r1,%r1             # q <<= 1
-        alr   %r0,%r0             # r <<= 1
-        brc   12,7f               # overflow on r ?
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-7:      lhi   %r3,1
-        nr    %r3,%r4             # isolate last bit of n
-        alr   %r0,%r3             # r += (n & 1)
-        clr   %r0,%r5             # r >= d ?
-        jl    8f
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-8:      # now n = d * %r1 + %r0
-       l     %r2,24(%r15)
-        st    %r0,0(%r2)
-        lr    %r2,%r1
-        br    %r14
-       .end    __udiv_qrnnd
diff --git a/arch/s390/math-emu/sfp-util.h b/arch/s390/math-emu/sfp-util.h
deleted file mode 100644 (file)
index 5b6ca45..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({          \
-       unsigned int __sh = (ah);                       \
-       unsigned int __sl = (al);                       \
-       asm volatile(                                   \
-               "       alr     %1,%3\n"                \
-               "       brc     12,0f\n"                \
-               "       ahi     %0,1\n"                 \
-               "0:     alr  %0,%2"                     \
-               : "+&d" (__sh), "+d" (__sl)             \
-               : "d" (bh), "d" (bl) : "cc");           \
-       (sh) = __sh;                                    \
-       (sl) = __sl;                                    \
-})
-
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({          \
-       unsigned int __sh = (ah);                       \
-       unsigned int __sl = (al);                       \
-       asm volatile(                                   \
-               "       slr     %1,%3\n"                \
-               "       brc     3,0f\n"                 \
-               "       ahi     %0,-1\n"                \
-               "0:     slr     %0,%2"                  \
-               : "+&d" (__sh), "+d" (__sl)             \
-               : "d" (bh), "d" (bl) : "cc");           \
-       (sh) = __sh;                                    \
-       (sl) = __sl;                                    \
-})
-
-/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */
-#define umul_ppmm(wh, wl, u, v) ({                     \
-       unsigned int __wh = u;                          \
-       unsigned int __wl = v;                          \
-       asm volatile(                                   \
-               "       ltr     1,%0\n"                 \
-               "       mr      0,%1\n"                 \
-               "       jnm     0f\n"                           \
-               "       alr     0,%1\n"                 \
-               "0:     ltr     %1,%1\n"                        \
-               "       jnm     1f\n"                           \
-               "       alr     0,%0\n"                 \
-               "1:     lr      %0,0\n"                 \
-               "       lr      %1,1\n"                 \
-               : "+d" (__wh), "+d" (__wl)              \
-               : : "0", "1", "cc");                    \
-       wh = __wh;                                      \
-       wl = __wl;                                      \
-})
-
-#define udiv_qrnnd(q, r, n1, n0, d)                    \
-  do { unsigned long __r;                              \
-    (q) = __udiv_qrnnd (&__r, (n1), (n0), (d));                \
-    (r) = __r;                                         \
-  } while (0)
-extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
-                                  unsigned long , unsigned long);
-
-#define UDIV_NEEDS_NORMALIZATION 0
-
-#define abort() return 0
-
-#define __BYTE_ORDER __BIG_ENDIAN
index 9803c9352d78e8e88bffbd49b82794e6c06444c3..5a888704a8d002ca0d846308f51e052ec4a3301b 100644 (file)
@@ -2,6 +2,8 @@
 # Makefile for the S/390 specific device drivers
 #
 
+CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
+
 obj-y += s390mach.o sysinfo.o s390_rdev.o
 obj-y += cio/ block/ char/ crypto/ net/ scsi/
 
index 1e788e815ce7f872f629a91d75936f446f1835c8..090743d2f914aec39990cdca66f40455df512450 100644 (file)
@@ -9,8 +9,14 @@
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/ebcdic.h>
 
+/* Sigh, math-emu. Don't ask. */
+#include <asm/sfp-util.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+
 struct sysinfo_1_1_1 {
        char reserved_0[32];
        char manufacturer[16];
@@ -198,7 +204,7 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
                 * if the higher order 8 bits are not zero. Printing
                 * a floating point number in the kernel is a no-no,
                 * always print the number as 32 bit unsigned integer.
-                * The user-space needs to know about the stange
+                * The user-space needs to know about the strange
                 * encoding of the alternate cpu capability.
                 */
                len += sprintf(page + len, "Capability:           %u %u\n",
@@ -351,3 +357,58 @@ static __init int create_proc_sysinfo(void)
 
 __initcall(create_proc_sysinfo);
 
+/*
+ * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
+ */
+void s390_adjust_jiffies(void)
+{
+       struct sysinfo_1_2_2 *info;
+       const unsigned int fmil = 0x4b189680;   /* 1e7 as 32-bit float. */
+       FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+       FP_DECL_EX;
+       unsigned int capability;
+
+       info = (void *) get_zeroed_page(GFP_KERNEL);
+       if (!info)
+               return;
+
+       if (stsi(info, 1, 2, 2) != -ENOSYS) {
+               /*
+                * Major sigh. The cpu capability encoding is "special".
+                * If the first 9 bits of info->capability are 0 then it
+                * is a 32 bit unsigned integer in the range 0 .. 2^23.
+                * If the first 9 bits are != 0 then it is a 32 bit float.
+                * In addition a lower value indicates a proportionally
+                * higher cpu capacity. Bogomips are the other way round.
+                * To get to a halfway suitable number we divide 1e7
+                * by the cpu capability number. Yes, that means a floating
+                * point division .. math-emu here we come :-)
+                */
+               FP_UNPACK_SP(SA, &fmil);
+               if ((info->capability >> 23) == 0)
+                       FP_FROM_INT_S(SB, info->capability, 32, int);
+               else
+                       FP_UNPACK_SP(SB, &info->capability);
+               FP_DIV_S(SR, SA, SB);
+               FP_TO_INT_S(capability, SR, 32, 0);
+       } else
+               /*
+                * Really old machine without stsi block for basic
+                * cpu information. Report 42.0 bogomips.
+                */
+               capability = 42;
+       loops_per_jiffy = capability * (500000/HZ);
+       free_page((unsigned long) info);
+}
+
+/*
+ * calibrate the delay loop
+ */
+void __init calibrate_delay(void)
+{
+       s390_adjust_jiffies();
+       /* Print the good old Bogomips line .. */
+       printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
+              "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
+              (loops_per_jiffy/(5000/HZ)) % 100);
+}
index 5af853576cbdce7b3f673e2fc9d79c529a6aebcc..cf71c5449240bfc5a053f3be94be9867d35f872a 100644 (file)
@@ -50,6 +50,7 @@ struct cpuinfo_S390
         unsigned long pgtable_cache_sz;
 };
 
+extern void s390_adjust_jiffies(void);
 extern void print_cpu_info(struct cpuinfo_S390 *);
 
 /* Lazy FPU handling on uni-processor */
diff --git a/include/asm-s390/sfp-util.h b/include/asm-s390/sfp-util.h
new file mode 100644 (file)
index 0000000..8cabcd2
--- /dev/null
@@ -0,0 +1,66 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({          \
+       unsigned int __sh = (ah);                       \
+       unsigned int __sl = (al);                       \
+       asm volatile(                                   \
+               "       alr     %1,%3\n"                \
+               "       brc     12,0f\n"                \
+               "       ahi     %0,1\n"                 \
+               "0:     alr  %0,%2"                     \
+               : "+&d" (__sh), "+d" (__sl)             \
+               : "d" (bh), "d" (bl) : "cc");           \
+       (sh) = __sh;                                    \
+       (sl) = __sl;                                    \
+})
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({          \
+       unsigned int __sh = (ah);                       \
+       unsigned int __sl = (al);                       \
+       asm volatile(                                   \
+               "       slr     %1,%3\n"                \
+               "       brc     3,0f\n"                 \
+               "       ahi     %0,-1\n"                \
+               "0:     slr     %0,%2"                  \
+               : "+&d" (__sh), "+d" (__sl)             \
+               : "d" (bh), "d" (bl) : "cc");           \
+       (sh) = __sh;                                    \
+       (sl) = __sl;                                    \
+})
+
+/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */
+#define umul_ppmm(wh, wl, u, v) ({                     \
+       unsigned int __wh = u;                          \
+       unsigned int __wl = v;                          \
+       asm volatile(                                   \
+               "       ltr     1,%0\n"                 \
+               "       mr      0,%1\n"                 \
+               "       jnm     0f\n"                           \
+               "       alr     0,%1\n"                 \
+               "0:     ltr     %1,%1\n"                        \
+               "       jnm     1f\n"                           \
+               "       alr     0,%0\n"                 \
+               "1:     lr      %0,0\n"                 \
+               "       lr      %1,1\n"                 \
+               : "+d" (__wh), "+d" (__wl)              \
+               : : "0", "1", "cc");                    \
+       wh = __wh;                                      \
+       wl = __wl;                                      \
+})
+
+#define udiv_qrnnd(q, r, n1, n0, d)                    \
+  do { unsigned int __r;                               \
+    (q) = __udiv_qrnnd (&__r, (n1), (n0), (d));                \
+    (r) = __r;                                         \
+  } while (0)
+extern unsigned long __udiv_qrnnd (unsigned int *, unsigned int,
+                                  unsigned int , unsigned int);
+
+#define UDIV_NEEDS_NORMALIZATION 0
+
+#define abort() return 0
+
+#define __BYTE_ORDER __BIG_ENDIAN