scc_pata: use ide_find_port()
[safe/jmp/linux-2.6] / drivers / s390 / sysinfo.c
index 1e788e8..c3e4ab0 100644 (file)
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/ebcdic.h>
+#include <asm/sysinfo.h>
 
-struct sysinfo_1_1_1 {
-       char reserved_0[32];
-       char manufacturer[16];
-       char type[4];
-       char reserved_1[12];
-       char model_capacity[16];
-       char sequence[16];
-       char plant[4];
-       char model[16];
-};
-
-struct sysinfo_1_2_1 {
-       char reserved_0[80];
-       char sequence[16];
-       char plant[4];
-       char reserved_1[2];
-       unsigned short cpu_address;
-};
-
-struct sysinfo_1_2_2 {
-       char format;
-       char reserved_0[1];
-       unsigned short acc_offset;
-       char reserved_1[24];
-       unsigned int secondary_capability;
-       unsigned int capability;
-       unsigned short cpus_total;
-       unsigned short cpus_configured;
-       unsigned short cpus_standby;
-       unsigned short cpus_reserved;
-       unsigned short adjustment[0];
-};
-
-struct sysinfo_1_2_2_extension {
-       unsigned int alt_capability;
-       unsigned short alt_adjustment[0];
-};
-
-struct sysinfo_2_2_1 {
-       char reserved_0[80];
-       char sequence[16];
-       char plant[4];
-       unsigned short cpu_id;
-       unsigned short cpu_address;
-};
-
-struct sysinfo_2_2_2 {
-       char reserved_0[32];
-       unsigned short lpar_number;
-       char reserved_1;
-       unsigned char characteristics;
-       unsigned short cpus_total;
-       unsigned short cpus_configured;
-       unsigned short cpus_standby;
-       unsigned short cpus_reserved;
-       char name[8];
-       unsigned int caf;
-       char reserved_2[16];
-       unsigned short cpus_dedicated;
-       unsigned short cpus_shared;
-};
-
-#define LPAR_CHAR_DEDICATED    (1 << 7)
-#define LPAR_CHAR_SHARED       (1 << 6)
-#define LPAR_CHAR_LIMITED      (1 << 5)
-
-struct sysinfo_3_2_2 {
-       char reserved_0[31];
-       unsigned char count;
-       struct {
-               char reserved_0[4];
-               unsigned short cpus_total;
-               unsigned short cpus_configured;
-               unsigned short cpus_standby;
-               unsigned short cpus_reserved;
-               char name[8];
-               unsigned int caf;
-               char cpi[16];
-               char reserved_1[24];
-
-       } vm[8];
-};
-
-static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
-{
-       register int r0 asm("0") = (fc << 28) | sel1;
-       register int r1 asm("1") = sel2;
-
-       asm volatile(
-               "   stsi 0(%2)\n"
-               "0: jz   2f\n"
-               "1: lhi  %0,%3\n"
-               "2:\n"
-               EX_TABLE(0b,1b)
-               : "+d" (r0) : "d" (r1), "a" (sysinfo), "K" (-ENOSYS)
-               : "cc", "memory" );
-       return r0;
-}
+/* Sigh, math-emu. Don't ask. */
+#include <asm/sfp-util.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
 
 static inline int stsi_0(void)
 {
@@ -127,6 +35,8 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
        EBCASC(info->sequence, sizeof(info->sequence));
        EBCASC(info->plant, sizeof(info->plant));
        EBCASC(info->model_capacity, sizeof(info->model_capacity));
+       EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap));
+       EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap));
        len += sprintf(page + len, "Manufacturer:         %-16.16s\n",
                       info->manufacturer);
        len += sprintf(page + len, "Type:                 %-4.4s\n",
@@ -149,8 +59,18 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
                       info->sequence);
        len += sprintf(page + len, "Plant:                %-4.4s\n",
                       info->plant);
-       len += sprintf(page + len, "Model Capacity:       %-16.16s\n",
-                      info->model_capacity);
+       len += sprintf(page + len, "Model Capacity:       %-16.16s %08u\n",
+                      info->model_capacity, *(u32 *) info->model_cap_rating);
+       if (info->model_perm_cap[0] != '\0')
+               len += sprintf(page + len,
+                              "Model Perm. Capacity: %-16.16s %08u\n",
+                              info->model_perm_cap,
+                              *(u32 *) info->model_perm_cap_rating);
+       if (info->model_temp_cap[0] != '\0')
+               len += sprintf(page + len,
+                              "Model Temp. Capacity: %-16.16s %08u\n",
+                              info->model_temp_cap,
+                              *(u32 *) info->model_temp_cap_rating);
        return len;
 }
 
@@ -198,7 +118,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 +271,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);
+}