Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 platform updates from Ingo Molnar: "UV platform updates (with a 'hubless' variant) and Jailhouse updates for better UART support" * 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/jailhouse: Only enable platform UARTs if available x86/jailhouse: Improve setup data version comparison x86/platform/uv: Account for UV Hubless in is_uvX_hub Ops x86/platform/uv: Check EFI Boot to set reboot type x86/platform/uv: Decode UVsystab Info x86/platform/uv: Add UV Hubbed/Hubless Proc FS Files x86/platform/uv: Setup UV functions for Hubless UV Systems x86/platform/uv: Add return code to UV BIOS Init function x86/platform/uv: Return UV Hubless System Type x86/platform/uv: Save OEM_ID from ACPI MADT probe
This commit is contained in:
commit
da42761df5
|
@ -138,7 +138,7 @@ extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect);
|
||||||
extern s64 uv_bios_reserved_page_pa(u64, u64 *, u64 *, u64 *);
|
extern s64 uv_bios_reserved_page_pa(u64, u64 *, u64 *, u64 *);
|
||||||
extern int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus);
|
extern int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus);
|
||||||
|
|
||||||
extern void uv_bios_init(void);
|
extern int uv_bios_init(void);
|
||||||
|
|
||||||
extern unsigned long sn_rtc_cycles_per_second;
|
extern unsigned long sn_rtc_cycles_per_second;
|
||||||
extern int uv_type;
|
extern int uv_type;
|
||||||
|
|
|
@ -12,6 +12,16 @@ struct mm_struct;
|
||||||
#ifdef CONFIG_X86_UV
|
#ifdef CONFIG_X86_UV
|
||||||
#include <linux/efi.h>
|
#include <linux/efi.h>
|
||||||
|
|
||||||
|
#define UV_PROC_NODE "sgi_uv"
|
||||||
|
|
||||||
|
static inline int uv(int uvtype)
|
||||||
|
{
|
||||||
|
/* uv(0) is "any" */
|
||||||
|
if (uvtype >= 0 && uvtype <= 30)
|
||||||
|
return 1 << uvtype;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
extern unsigned long uv_systab_phys;
|
extern unsigned long uv_systab_phys;
|
||||||
|
|
||||||
extern enum uv_system_type get_uv_system_type(void);
|
extern enum uv_system_type get_uv_system_type(void);
|
||||||
|
@ -20,7 +30,8 @@ static inline bool is_early_uv_system(void)
|
||||||
return uv_systab_phys && uv_systab_phys != EFI_INVALID_TABLE_ADDR;
|
return uv_systab_phys && uv_systab_phys != EFI_INVALID_TABLE_ADDR;
|
||||||
}
|
}
|
||||||
extern int is_uv_system(void);
|
extern int is_uv_system(void);
|
||||||
extern int is_uv_hubless(void);
|
extern int is_uv_hubbed(int uvtype);
|
||||||
|
extern int is_uv_hubless(int uvtype);
|
||||||
extern void uv_cpu_init(void);
|
extern void uv_cpu_init(void);
|
||||||
extern void uv_nmi_init(void);
|
extern void uv_nmi_init(void);
|
||||||
extern void uv_system_init(void);
|
extern void uv_system_init(void);
|
||||||
|
@ -32,7 +43,8 @@ extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
|
||||||
static inline enum uv_system_type get_uv_system_type(void) { return UV_NONE; }
|
static inline enum uv_system_type get_uv_system_type(void) { return UV_NONE; }
|
||||||
static inline bool is_early_uv_system(void) { return 0; }
|
static inline bool is_early_uv_system(void) { return 0; }
|
||||||
static inline int is_uv_system(void) { return 0; }
|
static inline int is_uv_system(void) { return 0; }
|
||||||
static inline int is_uv_hubless(void) { return 0; }
|
static inline int is_uv_hubbed(int uv) { return 0; }
|
||||||
|
static inline int is_uv_hubless(int uv) { return 0; }
|
||||||
static inline void uv_cpu_init(void) { }
|
static inline void uv_cpu_init(void) { }
|
||||||
static inline void uv_system_init(void) { }
|
static inline void uv_system_init(void) { }
|
||||||
static inline const struct cpumask *
|
static inline const struct cpumask *
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/topology.h>
|
#include <linux/topology.h>
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
#include <asm/percpu.h>
|
#include <asm/percpu.h>
|
||||||
|
#include <asm/uv/uv.h>
|
||||||
#include <asm/uv/uv_mmrs.h>
|
#include <asm/uv/uv_mmrs.h>
|
||||||
#include <asm/uv/bios.h>
|
#include <asm/uv/bios.h>
|
||||||
#include <asm/irq_vectors.h>
|
#include <asm/irq_vectors.h>
|
||||||
|
@ -243,83 +244,61 @@ static inline int uv_hub_info_check(int version)
|
||||||
#define UV4_HUB_REVISION_BASE 7
|
#define UV4_HUB_REVISION_BASE 7
|
||||||
#define UV4A_HUB_REVISION_BASE 8 /* UV4 (fixed) rev 2 */
|
#define UV4A_HUB_REVISION_BASE 8 /* UV4 (fixed) rev 2 */
|
||||||
|
|
||||||
|
/* WARNING: UVx_HUB_IS_SUPPORTED defines are deprecated and will be removed */
|
||||||
|
static inline int is_uv1_hub(void)
|
||||||
|
{
|
||||||
#ifdef UV1_HUB_IS_SUPPORTED
|
#ifdef UV1_HUB_IS_SUPPORTED
|
||||||
static inline int is_uv1_hub(void)
|
return is_uv_hubbed(uv(1));
|
||||||
{
|
|
||||||
return uv_hub_info->hub_revision < UV2_HUB_REVISION_BASE;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
static inline int is_uv1_hub(void)
|
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int is_uv2_hub(void)
|
||||||
|
{
|
||||||
#ifdef UV2_HUB_IS_SUPPORTED
|
#ifdef UV2_HUB_IS_SUPPORTED
|
||||||
static inline int is_uv2_hub(void)
|
return is_uv_hubbed(uv(2));
|
||||||
{
|
|
||||||
return ((uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE) &&
|
|
||||||
(uv_hub_info->hub_revision < UV3_HUB_REVISION_BASE));
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
static inline int is_uv2_hub(void)
|
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int is_uv3_hub(void)
|
||||||
|
{
|
||||||
#ifdef UV3_HUB_IS_SUPPORTED
|
#ifdef UV3_HUB_IS_SUPPORTED
|
||||||
static inline int is_uv3_hub(void)
|
return is_uv_hubbed(uv(3));
|
||||||
{
|
|
||||||
return ((uv_hub_info->hub_revision >= UV3_HUB_REVISION_BASE) &&
|
|
||||||
(uv_hub_info->hub_revision < UV4_HUB_REVISION_BASE));
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
static inline int is_uv3_hub(void)
|
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* First test "is UV4A", then "is UV4" */
|
/* First test "is UV4A", then "is UV4" */
|
||||||
|
static inline int is_uv4a_hub(void)
|
||||||
|
{
|
||||||
#ifdef UV4A_HUB_IS_SUPPORTED
|
#ifdef UV4A_HUB_IS_SUPPORTED
|
||||||
static inline int is_uv4a_hub(void)
|
if (is_uv_hubbed(uv(4)))
|
||||||
{
|
return (uv_hub_info->hub_revision == UV4A_HUB_REVISION_BASE);
|
||||||
return (uv_hub_info->hub_revision >= UV4A_HUB_REVISION_BASE);
|
#endif
|
||||||
}
|
|
||||||
#else
|
|
||||||
static inline int is_uv4a_hub(void)
|
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
static inline int is_uv4_hub(void)
|
||||||
|
{
|
||||||
#ifdef UV4_HUB_IS_SUPPORTED
|
#ifdef UV4_HUB_IS_SUPPORTED
|
||||||
static inline int is_uv4_hub(void)
|
return is_uv_hubbed(uv(4));
|
||||||
{
|
|
||||||
return uv_hub_info->hub_revision >= UV4_HUB_REVISION_BASE;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
static inline int is_uv4_hub(void)
|
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline int is_uvx_hub(void)
|
static inline int is_uvx_hub(void)
|
||||||
{
|
{
|
||||||
if (uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE)
|
return (is_uv_hubbed(-2) >= uv(2));
|
||||||
return uv_hub_info->hub_revision;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_uv_hub(void)
|
static inline int is_uv_hub(void)
|
||||||
{
|
{
|
||||||
#ifdef UV1_HUB_IS_SUPPORTED
|
return is_uv1_hub() || is_uvx_hub();
|
||||||
return uv_hub_info->hub_revision;
|
|
||||||
#endif
|
|
||||||
return is_uvx_hub();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
union uvh_apicid {
|
union uvh_apicid {
|
||||||
|
|
|
@ -153,15 +153,22 @@ struct boot_e820_entry {
|
||||||
* setup data structure.
|
* setup data structure.
|
||||||
*/
|
*/
|
||||||
struct jailhouse_setup_data {
|
struct jailhouse_setup_data {
|
||||||
__u16 version;
|
struct {
|
||||||
__u16 compatible_version;
|
__u16 version;
|
||||||
__u16 pm_timer_address;
|
__u16 compatible_version;
|
||||||
__u16 num_cpus;
|
} __attribute__((packed)) hdr;
|
||||||
__u64 pci_mmconfig_base;
|
struct {
|
||||||
__u32 tsc_khz;
|
__u16 pm_timer_address;
|
||||||
__u32 apic_khz;
|
__u16 num_cpus;
|
||||||
__u8 standard_ioapic;
|
__u64 pci_mmconfig_base;
|
||||||
__u8 cpu_ids[255];
|
__u32 tsc_khz;
|
||||||
|
__u32 apic_khz;
|
||||||
|
__u8 standard_ioapic;
|
||||||
|
__u8 cpu_ids[255];
|
||||||
|
} __attribute__((packed)) v1;
|
||||||
|
struct {
|
||||||
|
__u32 flags;
|
||||||
|
} __attribute__((packed)) v2;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
/* The so-called "zeropage" */
|
/* The so-called "zeropage" */
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <linux/memory.h>
|
#include <linux/memory.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/efi.h>
|
||||||
|
|
||||||
#include <asm/e820/api.h>
|
#include <asm/e820/api.h>
|
||||||
#include <asm/uv/uv_mmrs.h>
|
#include <asm/uv/uv_mmrs.h>
|
||||||
|
@ -25,12 +27,17 @@
|
||||||
static DEFINE_PER_CPU(int, x2apic_extra_bits);
|
static DEFINE_PER_CPU(int, x2apic_extra_bits);
|
||||||
|
|
||||||
static enum uv_system_type uv_system_type;
|
static enum uv_system_type uv_system_type;
|
||||||
static bool uv_hubless_system;
|
static int uv_hubbed_system;
|
||||||
|
static int uv_hubless_system;
|
||||||
static u64 gru_start_paddr, gru_end_paddr;
|
static u64 gru_start_paddr, gru_end_paddr;
|
||||||
static u64 gru_dist_base, gru_first_node_paddr = -1LL, gru_last_node_paddr;
|
static u64 gru_dist_base, gru_first_node_paddr = -1LL, gru_last_node_paddr;
|
||||||
static u64 gru_dist_lmask, gru_dist_umask;
|
static u64 gru_dist_lmask, gru_dist_umask;
|
||||||
static union uvh_apicid uvh_apicid;
|
static union uvh_apicid uvh_apicid;
|
||||||
|
|
||||||
|
/* Unpack OEM/TABLE ID's to be NULL terminated strings */
|
||||||
|
static u8 oem_id[ACPI_OEM_ID_SIZE + 1];
|
||||||
|
static u8 oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
|
||||||
|
|
||||||
/* Information derived from CPUID: */
|
/* Information derived from CPUID: */
|
||||||
static struct {
|
static struct {
|
||||||
unsigned int apicid_shift;
|
unsigned int apicid_shift;
|
||||||
|
@ -248,17 +255,35 @@ static void __init uv_set_apicid_hibit(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
|
static void __init uv_stringify(int len, char *to, char *from)
|
||||||
|
{
|
||||||
|
/* Relies on 'to' being NULL chars so result will be NULL terminated */
|
||||||
|
strncpy(to, from, len-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init uv_acpi_madt_oem_check(char *_oem_id, char *_oem_table_id)
|
||||||
{
|
{
|
||||||
int pnodeid;
|
int pnodeid;
|
||||||
int uv_apic;
|
int uv_apic;
|
||||||
|
|
||||||
|
uv_stringify(sizeof(oem_id), oem_id, _oem_id);
|
||||||
|
uv_stringify(sizeof(oem_table_id), oem_table_id, _oem_table_id);
|
||||||
|
|
||||||
if (strncmp(oem_id, "SGI", 3) != 0) {
|
if (strncmp(oem_id, "SGI", 3) != 0) {
|
||||||
if (strncmp(oem_id, "NSGI", 4) == 0) {
|
if (strncmp(oem_id, "NSGI", 4) != 0)
|
||||||
uv_hubless_system = true;
|
return 0;
|
||||||
pr_info("UV: OEM IDs %s/%s, HUBLESS\n",
|
|
||||||
oem_id, oem_table_id);
|
/* UV4 Hubless, CH, (0x11:UV4+Any) */
|
||||||
}
|
if (strncmp(oem_id, "NSGI4", 5) == 0)
|
||||||
|
uv_hubless_system = 0x11;
|
||||||
|
|
||||||
|
/* UV3 Hubless, UV300/MC990X w/o hub (0x9:UV3+Any) */
|
||||||
|
else
|
||||||
|
uv_hubless_system = 0x9;
|
||||||
|
|
||||||
|
pr_info("UV: OEM IDs %s/%s, HUBLESS(0x%x)\n",
|
||||||
|
oem_id, oem_table_id, uv_hubless_system);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +311,24 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
|
||||||
if (uv_hub_info->hub_revision == 0)
|
if (uv_hub_info->hub_revision == 0)
|
||||||
goto badbios;
|
goto badbios;
|
||||||
|
|
||||||
|
switch (uv_hub_info->hub_revision) {
|
||||||
|
case UV4_HUB_REVISION_BASE:
|
||||||
|
uv_hubbed_system = 0x11;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UV3_HUB_REVISION_BASE:
|
||||||
|
uv_hubbed_system = 0x9;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UV2_HUB_REVISION_BASE:
|
||||||
|
uv_hubbed_system = 0x5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UV1_HUB_REVISION_BASE:
|
||||||
|
uv_hubbed_system = 0x3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
pnodeid = early_get_pnodeid();
|
pnodeid = early_get_pnodeid();
|
||||||
early_get_apic_socketid_shift();
|
early_get_apic_socketid_shift();
|
||||||
|
|
||||||
|
@ -336,9 +379,15 @@ int is_uv_system(void)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(is_uv_system);
|
EXPORT_SYMBOL_GPL(is_uv_system);
|
||||||
|
|
||||||
int is_uv_hubless(void)
|
int is_uv_hubbed(int uvtype)
|
||||||
{
|
{
|
||||||
return uv_hubless_system;
|
return (uv_hubbed_system & uvtype);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(is_uv_hubbed);
|
||||||
|
|
||||||
|
int is_uv_hubless(int uvtype)
|
||||||
|
{
|
||||||
|
return (uv_hubless_system & uvtype);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(is_uv_hubless);
|
EXPORT_SYMBOL_GPL(is_uv_hubless);
|
||||||
|
|
||||||
|
@ -1255,7 +1304,8 @@ static int __init decode_uv_systab(void)
|
||||||
struct uv_systab *st;
|
struct uv_systab *st;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (uv_hub_info->hub_revision < UV4_HUB_REVISION_BASE)
|
/* If system is uv3 or lower, there is no extended UVsystab */
|
||||||
|
if (is_uv_hubbed(0xfffffe) < uv(4) && is_uv_hubless(0xfffffe) < uv(4))
|
||||||
return 0; /* No extended UVsystab required */
|
return 0; /* No extended UVsystab required */
|
||||||
|
|
||||||
st = uv_systab;
|
st = uv_systab;
|
||||||
|
@ -1434,6 +1484,103 @@ static void __init build_socket_tables(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check which reboot to use */
|
||||||
|
static void check_efi_reboot(void)
|
||||||
|
{
|
||||||
|
/* If EFI reboot not available, use ACPI reboot */
|
||||||
|
if (!efi_enabled(EFI_BOOT))
|
||||||
|
reboot_type = BOOT_ACPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup user proc fs files */
|
||||||
|
static int proc_hubbed_show(struct seq_file *file, void *data)
|
||||||
|
{
|
||||||
|
seq_printf(file, "0x%x\n", uv_hubbed_system);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_hubless_show(struct seq_file *file, void *data)
|
||||||
|
{
|
||||||
|
seq_printf(file, "0x%x\n", uv_hubless_system);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_oemid_show(struct seq_file *file, void *data)
|
||||||
|
{
|
||||||
|
seq_printf(file, "%s/%s\n", oem_id, oem_table_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_hubbed_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, proc_hubbed_show, (void *)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_hubless_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, proc_hubless_show, (void *)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_oemid_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, proc_oemid_show, (void *)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (struct is "non-const" as open function is set at runtime) */
|
||||||
|
static struct file_operations proc_version_fops = {
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct file_operations proc_oemid_fops = {
|
||||||
|
.open = proc_oemid_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __init void uv_setup_proc_files(int hubless)
|
||||||
|
{
|
||||||
|
struct proc_dir_entry *pde;
|
||||||
|
char *name = hubless ? "hubless" : "hubbed";
|
||||||
|
|
||||||
|
pde = proc_mkdir(UV_PROC_NODE, NULL);
|
||||||
|
proc_create("oemid", 0, pde, &proc_oemid_fops);
|
||||||
|
proc_create(name, 0, pde, &proc_version_fops);
|
||||||
|
if (hubless)
|
||||||
|
proc_version_fops.open = proc_hubless_open;
|
||||||
|
else
|
||||||
|
proc_version_fops.open = proc_hubbed_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize UV hubless systems */
|
||||||
|
static __init int uv_system_init_hubless(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Setup PCH NMI handler */
|
||||||
|
uv_nmi_setup_hubless();
|
||||||
|
|
||||||
|
/* Init kernel/BIOS interface */
|
||||||
|
rc = uv_bios_init();
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Process UVsystab */
|
||||||
|
rc = decode_uv_systab();
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Create user access node */
|
||||||
|
if (rc >= 0)
|
||||||
|
uv_setup_proc_files(1);
|
||||||
|
|
||||||
|
check_efi_reboot();
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static void __init uv_system_init_hub(void)
|
static void __init uv_system_init_hub(void)
|
||||||
{
|
{
|
||||||
struct uv_hub_info_s hub_info = {0};
|
struct uv_hub_info_s hub_info = {0};
|
||||||
|
@ -1559,32 +1706,27 @@ static void __init uv_system_init_hub(void)
|
||||||
uv_nmi_setup();
|
uv_nmi_setup();
|
||||||
uv_cpu_init();
|
uv_cpu_init();
|
||||||
uv_scir_register_cpu_notifier();
|
uv_scir_register_cpu_notifier();
|
||||||
proc_mkdir("sgi_uv", NULL);
|
uv_setup_proc_files(0);
|
||||||
|
|
||||||
/* Register Legacy VGA I/O redirection handler: */
|
/* Register Legacy VGA I/O redirection handler: */
|
||||||
pci_register_set_vga_state(uv_set_vga_state);
|
pci_register_set_vga_state(uv_set_vga_state);
|
||||||
|
|
||||||
/*
|
check_efi_reboot();
|
||||||
* For a kdump kernel the reset must be BOOT_ACPI, not BOOT_EFI, as
|
|
||||||
* EFI is not enabled in the kdump kernel:
|
|
||||||
*/
|
|
||||||
if (is_kdump_kernel())
|
|
||||||
reboot_type = BOOT_ACPI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There is a small amount of UV specific code needed to initialize a
|
* There is a different code path needed to initialize a UV system that does
|
||||||
* UV system that does not have a "UV HUB" (referred to as "hubless").
|
* not have a "UV HUB" (referred to as "hubless").
|
||||||
*/
|
*/
|
||||||
void __init uv_system_init(void)
|
void __init uv_system_init(void)
|
||||||
{
|
{
|
||||||
if (likely(!is_uv_system() && !is_uv_hubless()))
|
if (likely(!is_uv_system() && !is_uv_hubless(1)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (is_uv_system())
|
if (is_uv_system())
|
||||||
uv_system_init_hub();
|
uv_system_init_hub();
|
||||||
else
|
else
|
||||||
uv_nmi_setup_hubless();
|
uv_system_init_hubless();
|
||||||
}
|
}
|
||||||
|
|
||||||
apic_driver(apic_x2apic_uv_x);
|
apic_driver(apic_x2apic_uv_x);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/acpi_pmtmr.h>
|
#include <linux/acpi_pmtmr.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
|
#include <linux/serial_8250.h>
|
||||||
#include <asm/apic.h>
|
#include <asm/apic.h>
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include <asm/hypervisor.h>
|
#include <asm/hypervisor.h>
|
||||||
|
@ -21,9 +22,24 @@
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
#include <asm/jailhouse_para.h>
|
#include <asm/jailhouse_para.h>
|
||||||
|
|
||||||
static __initdata struct jailhouse_setup_data setup_data;
|
static struct jailhouse_setup_data setup_data;
|
||||||
|
#define SETUP_DATA_V1_LEN (sizeof(setup_data.hdr) + sizeof(setup_data.v1))
|
||||||
|
#define SETUP_DATA_V2_LEN (SETUP_DATA_V1_LEN + sizeof(setup_data.v2))
|
||||||
|
|
||||||
static unsigned int precalibrated_tsc_khz;
|
static unsigned int precalibrated_tsc_khz;
|
||||||
|
|
||||||
|
static void jailhouse_setup_irq(unsigned int irq)
|
||||||
|
{
|
||||||
|
struct mpc_intsrc mp_irq = {
|
||||||
|
.type = MP_INTSRC,
|
||||||
|
.irqtype = mp_INT,
|
||||||
|
.irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE,
|
||||||
|
.srcbusirq = irq,
|
||||||
|
.dstirq = irq,
|
||||||
|
};
|
||||||
|
mp_save_irq(&mp_irq);
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t jailhouse_cpuid_base(void)
|
static uint32_t jailhouse_cpuid_base(void)
|
||||||
{
|
{
|
||||||
if (boot_cpu_data.cpuid_level < 0 ||
|
if (boot_cpu_data.cpuid_level < 0 ||
|
||||||
|
@ -45,7 +61,7 @@ static void jailhouse_get_wallclock(struct timespec64 *now)
|
||||||
|
|
||||||
static void __init jailhouse_timer_init(void)
|
static void __init jailhouse_timer_init(void)
|
||||||
{
|
{
|
||||||
lapic_timer_period = setup_data.apic_khz * (1000 / HZ);
|
lapic_timer_period = setup_data.v1.apic_khz * (1000 / HZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long jailhouse_get_tsc(void)
|
static unsigned long jailhouse_get_tsc(void)
|
||||||
|
@ -77,33 +93,28 @@ static void __init jailhouse_get_smp_config(unsigned int early)
|
||||||
.type = IOAPIC_DOMAIN_STRICT,
|
.type = IOAPIC_DOMAIN_STRICT,
|
||||||
.ops = &mp_ioapic_irqdomain_ops,
|
.ops = &mp_ioapic_irqdomain_ops,
|
||||||
};
|
};
|
||||||
struct mpc_intsrc mp_irq = {
|
|
||||||
.type = MP_INTSRC,
|
|
||||||
.irqtype = mp_INT,
|
|
||||||
.irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE,
|
|
||||||
};
|
|
||||||
unsigned int cpu;
|
unsigned int cpu;
|
||||||
|
|
||||||
jailhouse_x2apic_init();
|
jailhouse_x2apic_init();
|
||||||
|
|
||||||
register_lapic_address(0xfee00000);
|
register_lapic_address(0xfee00000);
|
||||||
|
|
||||||
for (cpu = 0; cpu < setup_data.num_cpus; cpu++) {
|
for (cpu = 0; cpu < setup_data.v1.num_cpus; cpu++) {
|
||||||
generic_processor_info(setup_data.cpu_ids[cpu],
|
generic_processor_info(setup_data.v1.cpu_ids[cpu],
|
||||||
boot_cpu_apic_version);
|
boot_cpu_apic_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
smp_found_config = 1;
|
smp_found_config = 1;
|
||||||
|
|
||||||
if (setup_data.standard_ioapic) {
|
if (setup_data.v1.standard_ioapic) {
|
||||||
mp_register_ioapic(0, 0xfec00000, gsi_top, &ioapic_cfg);
|
mp_register_ioapic(0, 0xfec00000, gsi_top, &ioapic_cfg);
|
||||||
|
|
||||||
/* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
|
if (IS_ENABLED(CONFIG_SERIAL_8250) &&
|
||||||
mp_irq.srcbusirq = mp_irq.dstirq = 3;
|
setup_data.hdr.version < 2) {
|
||||||
mp_save_irq(&mp_irq);
|
/* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
|
||||||
|
jailhouse_setup_irq(3);
|
||||||
mp_irq.srcbusirq = mp_irq.dstirq = 4;
|
jailhouse_setup_irq(4);
|
||||||
mp_save_irq(&mp_irq);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,9 +137,9 @@ static int __init jailhouse_pci_arch_init(void)
|
||||||
pcibios_last_bus = 0xff;
|
pcibios_last_bus = 0xff;
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_MMCONFIG
|
#ifdef CONFIG_PCI_MMCONFIG
|
||||||
if (setup_data.pci_mmconfig_base) {
|
if (setup_data.v1.pci_mmconfig_base) {
|
||||||
pci_mmconfig_add(0, 0, pcibios_last_bus,
|
pci_mmconfig_add(0, 0, pcibios_last_bus,
|
||||||
setup_data.pci_mmconfig_base);
|
setup_data.v1.pci_mmconfig_base);
|
||||||
pci_mmcfg_arch_init();
|
pci_mmcfg_arch_init();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -136,9 +147,57 @@ static int __init jailhouse_pci_arch_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_8250
|
||||||
|
static inline bool jailhouse_uart_enabled(unsigned int uart_nr)
|
||||||
|
{
|
||||||
|
return setup_data.v2.flags & BIT(uart_nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jailhouse_serial_fixup(int port, struct uart_port *up,
|
||||||
|
u32 *capabilities)
|
||||||
|
{
|
||||||
|
static const u16 pcuart_base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
|
||||||
|
unsigned int n;
|
||||||
|
|
||||||
|
for (n = 0; n < ARRAY_SIZE(pcuart_base); n++) {
|
||||||
|
if (pcuart_base[n] != up->iobase)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (jailhouse_uart_enabled(n)) {
|
||||||
|
pr_info("Enabling UART%u (port 0x%lx)\n", n,
|
||||||
|
up->iobase);
|
||||||
|
jailhouse_setup_irq(up->irq);
|
||||||
|
} else {
|
||||||
|
/* Deactivate UART if access isn't allowed */
|
||||||
|
up->iobase = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __init jailhouse_serial_workaround(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* There are flags inside setup_data that indicate availability of
|
||||||
|
* platform UARTs since setup data version 2.
|
||||||
|
*
|
||||||
|
* In case of version 1, we don't know which UARTs belong Linux. In
|
||||||
|
* this case, unconditionally register 1:1 mapping for legacy UART IRQs
|
||||||
|
* 3 and 4.
|
||||||
|
*/
|
||||||
|
if (setup_data.hdr.version > 1)
|
||||||
|
serial8250_set_isa_configurator(jailhouse_serial_fixup);
|
||||||
|
}
|
||||||
|
#else /* !CONFIG_SERIAL_8250 */
|
||||||
|
static inline void jailhouse_serial_workaround(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SERIAL_8250 */
|
||||||
|
|
||||||
static void __init jailhouse_init_platform(void)
|
static void __init jailhouse_init_platform(void)
|
||||||
{
|
{
|
||||||
u64 pa_data = boot_params.hdr.setup_data;
|
u64 pa_data = boot_params.hdr.setup_data;
|
||||||
|
unsigned long setup_data_len;
|
||||||
struct setup_data header;
|
struct setup_data header;
|
||||||
void *mapping;
|
void *mapping;
|
||||||
|
|
||||||
|
@ -163,16 +222,8 @@ static void __init jailhouse_init_platform(void)
|
||||||
memcpy(&header, mapping, sizeof(header));
|
memcpy(&header, mapping, sizeof(header));
|
||||||
early_memunmap(mapping, sizeof(header));
|
early_memunmap(mapping, sizeof(header));
|
||||||
|
|
||||||
if (header.type == SETUP_JAILHOUSE &&
|
if (header.type == SETUP_JAILHOUSE)
|
||||||
header.len >= sizeof(setup_data)) {
|
|
||||||
pa_data += offsetof(struct setup_data, data);
|
|
||||||
|
|
||||||
mapping = early_memremap(pa_data, sizeof(setup_data));
|
|
||||||
memcpy(&setup_data, mapping, sizeof(setup_data));
|
|
||||||
early_memunmap(mapping, sizeof(setup_data));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
pa_data = header.next;
|
pa_data = header.next;
|
||||||
}
|
}
|
||||||
|
@ -180,13 +231,28 @@ static void __init jailhouse_init_platform(void)
|
||||||
if (!pa_data)
|
if (!pa_data)
|
||||||
panic("Jailhouse: No valid setup data found");
|
panic("Jailhouse: No valid setup data found");
|
||||||
|
|
||||||
if (setup_data.compatible_version > JAILHOUSE_SETUP_REQUIRED_VERSION)
|
/* setup data must at least contain the header */
|
||||||
panic("Jailhouse: Unsupported setup data structure");
|
if (header.len < sizeof(setup_data.hdr))
|
||||||
|
goto unsupported;
|
||||||
|
|
||||||
pmtmr_ioport = setup_data.pm_timer_address;
|
pa_data += offsetof(struct setup_data, data);
|
||||||
|
setup_data_len = min_t(unsigned long, sizeof(setup_data),
|
||||||
|
(unsigned long)header.len);
|
||||||
|
mapping = early_memremap(pa_data, setup_data_len);
|
||||||
|
memcpy(&setup_data, mapping, setup_data_len);
|
||||||
|
early_memunmap(mapping, setup_data_len);
|
||||||
|
|
||||||
|
if (setup_data.hdr.version == 0 ||
|
||||||
|
setup_data.hdr.compatible_version !=
|
||||||
|
JAILHOUSE_SETUP_REQUIRED_VERSION ||
|
||||||
|
(setup_data.hdr.version == 1 && header.len < SETUP_DATA_V1_LEN) ||
|
||||||
|
(setup_data.hdr.version >= 2 && header.len < SETUP_DATA_V2_LEN))
|
||||||
|
goto unsupported;
|
||||||
|
|
||||||
|
pmtmr_ioport = setup_data.v1.pm_timer_address;
|
||||||
pr_debug("Jailhouse: PM-Timer IO Port: %#x\n", pmtmr_ioport);
|
pr_debug("Jailhouse: PM-Timer IO Port: %#x\n", pmtmr_ioport);
|
||||||
|
|
||||||
precalibrated_tsc_khz = setup_data.tsc_khz;
|
precalibrated_tsc_khz = setup_data.v1.tsc_khz;
|
||||||
setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
|
setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
|
||||||
|
|
||||||
pci_probe = 0;
|
pci_probe = 0;
|
||||||
|
@ -196,6 +262,12 @@ static void __init jailhouse_init_platform(void)
|
||||||
* are none in a non-root cell.
|
* are none in a non-root cell.
|
||||||
*/
|
*/
|
||||||
disable_acpi();
|
disable_acpi();
|
||||||
|
|
||||||
|
jailhouse_serial_workaround();
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsupported:
|
||||||
|
panic("Jailhouse: Unsupported setup data structure");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool jailhouse_paravirt(void)
|
bool jailhouse_paravirt(void)
|
||||||
|
|
|
@ -184,20 +184,20 @@ int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target);
|
EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target);
|
||||||
|
|
||||||
void uv_bios_init(void)
|
int uv_bios_init(void)
|
||||||
{
|
{
|
||||||
uv_systab = NULL;
|
uv_systab = NULL;
|
||||||
if ((uv_systab_phys == EFI_INVALID_TABLE_ADDR) ||
|
if ((uv_systab_phys == EFI_INVALID_TABLE_ADDR) ||
|
||||||
!uv_systab_phys || efi_runtime_disabled()) {
|
!uv_systab_phys || efi_runtime_disabled()) {
|
||||||
pr_crit("UV: UVsystab: missing\n");
|
pr_crit("UV: UVsystab: missing\n");
|
||||||
return;
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
uv_systab = ioremap(uv_systab_phys, sizeof(struct uv_systab));
|
uv_systab = ioremap(uv_systab_phys, sizeof(struct uv_systab));
|
||||||
if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) {
|
if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) {
|
||||||
pr_err("UV: UVsystab: bad signature!\n");
|
pr_err("UV: UVsystab: bad signature!\n");
|
||||||
iounmap(uv_systab);
|
iounmap(uv_systab);
|
||||||
return;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Starting with UV4 the UV systab size is variable */
|
/* Starting with UV4 the UV systab size is variable */
|
||||||
|
@ -208,8 +208,9 @@ void uv_bios_init(void)
|
||||||
uv_systab = ioremap(uv_systab_phys, size);
|
uv_systab = ioremap(uv_systab_phys, size);
|
||||||
if (!uv_systab) {
|
if (!uv_systab) {
|
||||||
pr_err("UV: UVsystab: ioremap(%d) failed!\n", size);
|
pr_err("UV: UVsystab: ioremap(%d) failed!\n", size);
|
||||||
return;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pr_info("UV: UVsystab: Revision:%x\n", uv_systab->revision);
|
pr_info("UV: UVsystab: Revision:%x\n", uv_systab->revision);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue