Commit fcd0157e authored by Ken Cox's avatar Ken Cox Committed by Greg Kroah-Hartman

Staging: unisys: detect s-Par firmware

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: default avatarFengguang Wu <fengguang.wu@intel.com>
Signed-off-by: default avatarKen Cox <jkc@redhat.com>
Tested by: Ken Cox <jkc@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7f03de97
...@@ -25,11 +25,14 @@ ...@@ -25,11 +25,14 @@
#include "channel.h" #include "channel.h"
#include "chanstub.h" #include "chanstub.h"
#include "timskmodutils.h"
#include "version.h" #include "version.h"
static __init int static __init int
channel_mod_init(void) channel_mod_init(void)
{ {
if (!unisys_spar_platform)
return -ENODEV;
return 0; return 0;
} }
......
...@@ -72,4 +72,6 @@ char *cyclesToSomethingsPerSecond(u64 cycles, u64 cyclesPerSecond, ...@@ -72,4 +72,6 @@ char *cyclesToSomethingsPerSecond(u64 cycles, u64 cyclesPerSecond,
struct seq_file *visor_seq_file_new_buffer(void *buf, size_t buf_size); struct seq_file *visor_seq_file_new_buffer(void *buf, size_t buf_size);
void visor_seq_file_done_buffer(struct seq_file *m); void visor_seq_file_done_buffer(struct seq_file *m);
extern int unisys_spar_platform;
#endif #endif
...@@ -2277,6 +2277,9 @@ static int __init ...@@ -2277,6 +2277,9 @@ static int __init
uislib_mod_init(void) uislib_mod_init(void)
{ {
if (!unisys_spar_platform)
return -ENODEV;
LOGINF("MONITORAPIS"); LOGINF("MONITORAPIS");
LOGINF("sizeof(struct uiscmdrsp):%lu bytes\n", LOGINF("sizeof(struct uiscmdrsp):%lu bytes\n",
......
...@@ -1699,6 +1699,9 @@ virthba_mod_init(void) ...@@ -1699,6 +1699,9 @@ virthba_mod_init(void)
int error; int error;
int i; int i;
if (!unisys_spar_platform)
return -ENODEV;
LOGINF("Entering virthba_mod_init...\n"); LOGINF("Entering virthba_mod_init...\n");
POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO); POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/version.h> #include <linux/version.h>
#include "version.h" #include "version.h"
#include "guestlinuxdebug.h" #include "guestlinuxdebug.h"
#include "timskmodutils.h"
struct driver_private { struct driver_private {
struct kobject kobj; struct kobject kobj;
...@@ -1687,6 +1688,9 @@ static int __init virtpci_mod_init(void) ...@@ -1687,6 +1688,9 @@ static int __init virtpci_mod_init(void)
int ret; int ret;
if (!unisys_spar_platform)
return -ENODEV;
LOGINF("Module build: Date:%s Time:%s...\n", __DATE__, __TIME__); LOGINF("Module build: Date:%s Time:%s...\n", __DATE__, __TIME__);
POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO); POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
static int __init static int __init
visorchannel_init(void) visorchannel_init(void)
{ {
if (!unisys_spar_platform)
return -ENODEV;
INFODRV("driver version %s loaded", VERSION); INFODRV("driver version %s loaded", VERSION);
return 0; return 0;
} }
......
...@@ -2699,6 +2699,9 @@ visorchipset_init(void) ...@@ -2699,6 +2699,9 @@ visorchipset_init(void)
struct proc_dir_entry *toolaction_file; struct proc_dir_entry *toolaction_file;
struct proc_dir_entry *bootToTool_file; struct proc_dir_entry *bootToTool_file;
if (!unisys_spar_platform)
return -ENODEV;
LOGINF("chipset driver version %s loaded", VERSION); LOGINF("chipset driver version %s loaded", VERSION);
/* process module options */ /* process module options */
POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO); POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO);
......
...@@ -20,6 +20,22 @@ ...@@ -20,6 +20,22 @@
#define MYDRVNAME "timskmodutils" #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 /** Callers to interfaces that set __GFP_NORETRY flag below
* must check for a NULL (error) result as we are telling the * must check for a NULL (error) result as we are telling the
* kernel interface that it is okay to fail. * kernel interface that it is okay to fail.
...@@ -69,3 +85,41 @@ void visor_seq_file_done_buffer(struct seq_file *m) ...@@ -69,3 +85,41 @@ void visor_seq_file_done_buffer(struct seq_file *m)
kfree(m); kfree(m);
} }
EXPORT_SYMBOL_GPL(visor_seq_file_done_buffer); 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment