Staging: unisys: detect s-Par firmware
authorKen Cox <jkc@redhat.com>
Mon, 28 Apr 2014 17:23:13 +0000 (12:23 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 18 May 2014 16:44:17 +0000 (09:44 -0700)
This patch adds support for detection of s-Par firmware by checking for
the hypervisor bit in the CPU capabilities, and then querying the hypervisor
ID cpuid leaf.

This functionality will be used by the unisys drivers to determine if
they are being loaded on an s-Par platform and refuse to load if no
s-Par firmware is present.

This fixes a problem reported from upstream where a panic occurs if the
unisys drivers are loaded on a non s-Par system.

Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Ken Cox <jkc@redhat.com>
Tested by: Ken Cox <jkc@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/unisys/channels/chanstub.c
drivers/staging/unisys/include/timskmodutils.h
drivers/staging/unisys/uislib/uislib.c
drivers/staging/unisys/virthba/virthba.c
drivers/staging/unisys/virtpci/virtpci.c
drivers/staging/unisys/visorchannel/visorchannel_main.c
drivers/staging/unisys/visorchipset/visorchipset_main.c
drivers/staging/unisys/visorutil/visorkmodutils.c

index 45ac55d3fe1c93837b12e14ece58efaf0c3d6200..1e7d6a78602de9d00380de2ba2f828722a68fa01 100644 (file)
 
 #include "channel.h"
 #include "chanstub.h"
+#include "timskmodutils.h"
 #include "version.h"
 
 static __init int
 channel_mod_init(void)
 {
+       if (!unisys_spar_platform)
+               return -ENODEV;
        return 0;
 }
 
index 0045d559d1b9a16ba4f83d5cee1ca3ed8dfb18ca..c316c94ea1947cf4afae8390d1c4c1710cb47d5a 100644 (file)
@@ -72,4 +72,6 @@ char *cyclesToSomethingsPerSecond(u64 cycles, u64 cyclesPerSecond,
 struct seq_file *visor_seq_file_new_buffer(void *buf, size_t buf_size);
 void visor_seq_file_done_buffer(struct seq_file *m);
 
+extern int unisys_spar_platform;
+
 #endif
index 0e1a58ab28b10fd1f5293405969524dbb81983b3..fbdb19fc7891f4eb4c7a8324c5d7616e58daca44 100644 (file)
@@ -2277,6 +2277,9 @@ static int __init
 uislib_mod_init(void)
 {
 
+       if (!unisys_spar_platform)
+               return -ENODEV;
+
        LOGINF("MONITORAPIS");
 
        LOGINF("sizeof(struct uiscmdrsp):%lu bytes\n",
index a13e79e287f40025c08e79dd0b5d1058a695a608..d528388d596f71270b400dbb5780f7f4401808a0 100644 (file)
@@ -1699,6 +1699,9 @@ virthba_mod_init(void)
        int error;
        int i;
 
+       if (!unisys_spar_platform)
+               return -ENODEV;
+
        LOGINF("Entering virthba_mod_init...\n");
 
        POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
index 21f8bd5fdff94dd0a45a7ae88faae1e2776dae67..9a35dd2cd472fdc9f1072386279f5c050b6ab1d8 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/version.h>
 #include "version.h"
 #include "guestlinuxdebug.h"
+#include "timskmodutils.h"
 
 struct driver_private {
        struct kobject kobj;
@@ -1687,6 +1688,9 @@ static int __init virtpci_mod_init(void)
        int ret;
 
 
+       if (!unisys_spar_platform)
+               return -ENODEV;
+
        LOGINF("Module build: Date:%s Time:%s...\n", __DATE__, __TIME__);
 
        POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
index 1a092570602e7eb041355495f62c822f413bcf50..c8f89bd75e0c176ec7fb9ee9a7e02d2c860600b5 100644 (file)
@@ -29,6 +29,9 @@
 static int __init
 visorchannel_init(void)
 {
+       if (!unisys_spar_platform)
+               return -ENODEV;
+
        INFODRV("driver version %s loaded", VERSION);
        return 0;
 }
index 1895dc4596438939b39a41cf134ca5da41af0bef..5b955926f42dd47a69c80c7e2920348f33ea70f5 100644 (file)
@@ -2699,6 +2699,9 @@ visorchipset_init(void)
        struct proc_dir_entry *toolaction_file;
        struct proc_dir_entry *bootToTool_file;
 
+       if (!unisys_spar_platform)
+               return -ENODEV;
+
        LOGINF("chipset driver version %s loaded", VERSION);
        /* process module options */
        POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO);
index e802e75a46966b726e3349b166cfd6bc096d7fae..7521027c9368c45a68bd7d6243e393a538b2b84b 100644 (file)
 
 #define MYDRVNAME "timskmodutils"
 
+/* s-Par uses the Intel processor's VT-X features to separate groups of
+ * processors into partitions. The firmware sets the hypervisor bit and
+ * reports an ID in the HV capabilities leaf so that the partition's OS
+ * knows s-Par is present and managing the processors.
+ */
+
+#define UNISYS_SPAR_LEAF_ID 0x40000000
+
+/* The s-Par leaf ID returns "UnisysSpar64" encoded across ebx, ecx, edx */
+#define UNISYS_SPAR_ID_EBX 0x73696e55
+#define UNISYS_SPAR_ID_ECX 0x70537379
+#define UNISYS_SPAR_ID_EDX 0x34367261
+
+int unisys_spar_platform;
+EXPORT_SYMBOL_GPL(unisys_spar_platform);
+
 /** Callers to interfaces that set __GFP_NORETRY flag below
  *  must check for a NULL (error) result as we are telling the
  *  kernel interface that it is okay to fail.
@@ -69,3 +85,41 @@ void visor_seq_file_done_buffer(struct seq_file *m)
        kfree(m);
 }
 EXPORT_SYMBOL_GPL(visor_seq_file_done_buffer);
+
+static __init uint32_t
+visorutil_spar_detect(void)
+{
+       unsigned int eax, ebx, ecx, edx;
+
+       if (cpu_has_hypervisor) {
+               /* check the ID */
+               cpuid(UNISYS_SPAR_LEAF_ID, &eax, &ebx, &ecx, &edx);
+               return  (ebx == UNISYS_SPAR_ID_EBX) &&
+                       (ecx == UNISYS_SPAR_ID_ECX) &&
+                       (edx == UNISYS_SPAR_ID_EDX);
+       } else
+               return 0;
+
+}
+
+
+
+
+static __init int
+visorutil_mod_init(void)
+{
+       if (visorutil_spar_detect()) {
+               unisys_spar_platform = TRUE;
+               return 0;
+       } else
+               return -ENODEV;
+}
+
+static __exit void
+visorutil_mod_exit(void)
+{
+}
+
+module_init(visorutil_mod_init);
+module_exit(visorutil_mod_exit);
+