calibrate_delay() must be __cpuinit
[pandora-kernel.git] / drivers / s390 / sysinfo.c
index 1e788e8..291ff62 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,76 @@ static __init int create_proc_sysinfo(void)
 
 __initcall(create_proc_sysinfo);
 
+int get_cpu_capability(unsigned int *capability)
+{
+       struct sysinfo_1_2_2 *info;
+       int rc;
+
+       info = (void *) get_zeroed_page(GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       rc = stsi(info, 1, 2, 2);
+       if (rc == -ENOSYS)
+               goto out;
+       rc = 0;
+       *capability = info->capability;
+out:
+       free_page((unsigned long) info);
+       return rc;
+}
+
+/*
+ * 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 __cpuinit 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);
+}