]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 26 Nov 2019 17:52:37 +0000 (09:52 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 26 Nov 2019 17:52:37 +0000 (09:52 -0800)
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

arch/x86/include/asm/uv/bios.h
arch/x86/include/asm/uv/uv.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/jailhouse.c
arch/x86/platform/uv/bios_uv.c

index 6e7caf65fa401c804d60258c12851f85863ccd57..389174eaec7941341bac35d66767eefeb72e46f2 100644 (file)
@@ -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 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 int uv_type;
index 6bc6d89d8e2ad8d36819ae2457a815c9083f2d4b..45ea95ce79b461b83929acc9a199fb9196ee1497 100644 (file)
@@ -12,6 +12,16 @@ struct mm_struct;
 #ifdef CONFIG_X86_UV
 #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 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;
 }
 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_nmi_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 bool is_early_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_system_init(void)        { }
 static inline const struct cpumask *
index 44cf6d6deb7a8a9ae644707b80e30d9e5a810d9b..950cd1395d5dd3bc65d5d03514d0d7236fe2f54d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/topology.h>
 #include <asm/types.h>
 #include <asm/percpu.h>
+#include <asm/uv/uv.h>
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/bios.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 UV4A_HUB_REVISION_BASE         8       /* UV4 (fixed) rev 2 */
 
-#ifdef UV1_HUB_IS_SUPPORTED
+/* WARNING: UVx_HUB_IS_SUPPORTED defines are deprecated and will be removed */
 static inline int is_uv1_hub(void)
 {
-       return uv_hub_info->hub_revision < UV2_HUB_REVISION_BASE;
-}
+#ifdef UV1_HUB_IS_SUPPORTED
+       return is_uv_hubbed(uv(1));
 #else
-static inline int is_uv1_hub(void)
-{
        return 0;
-}
 #endif
+}
 
-#ifdef UV2_HUB_IS_SUPPORTED
 static inline int is_uv2_hub(void)
 {
-       return ((uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE) &&
-               (uv_hub_info->hub_revision < UV3_HUB_REVISION_BASE));
-}
+#ifdef UV2_HUB_IS_SUPPORTED
+       return is_uv_hubbed(uv(2));
 #else
-static inline int is_uv2_hub(void)
-{
        return 0;
-}
 #endif
+}
 
-#ifdef UV3_HUB_IS_SUPPORTED
 static inline int is_uv3_hub(void)
 {
-       return ((uv_hub_info->hub_revision >= UV3_HUB_REVISION_BASE) &&
-               (uv_hub_info->hub_revision < UV4_HUB_REVISION_BASE));
-}
+#ifdef UV3_HUB_IS_SUPPORTED
+       return is_uv_hubbed(uv(3));
 #else
-static inline int is_uv3_hub(void)
-{
        return 0;
-}
 #endif
+}
 
 /* First test "is UV4A", then "is UV4" */
-#ifdef UV4A_HUB_IS_SUPPORTED
-static inline int is_uv4a_hub(void)
-{
-       return (uv_hub_info->hub_revision >= UV4A_HUB_REVISION_BASE);
-}
-#else
 static inline int is_uv4a_hub(void)
 {
+#ifdef UV4A_HUB_IS_SUPPORTED
+       if (is_uv_hubbed(uv(4)))
+               return (uv_hub_info->hub_revision == UV4A_HUB_REVISION_BASE);
+#endif
        return 0;
 }
-#endif
 
-#ifdef UV4_HUB_IS_SUPPORTED
 static inline int is_uv4_hub(void)
 {
-       return uv_hub_info->hub_revision >= UV4_HUB_REVISION_BASE;
-}
+#ifdef UV4_HUB_IS_SUPPORTED
+       return is_uv_hubbed(uv(4));
 #else
-static inline int is_uv4_hub(void)
-{
        return 0;
-}
 #endif
+}
 
 static inline int is_uvx_hub(void)
 {
-       if (uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE)
-               return uv_hub_info->hub_revision;
-
-       return 0;
+       return (is_uv_hubbed(-2) >= uv(2));
 }
 
 static inline int is_uv_hub(void)
 {
-#ifdef UV1_HUB_IS_SUPPORTED
-       return uv_hub_info->hub_revision;
-#endif
-       return is_uvx_hub();
+       return is_uv1_hub() || is_uvx_hub();
 }
 
 union uvh_apicid {
index 949066b5398a4734cfff2e0a5a3ee91db7fbf016..8669c6bdbb84691c2425f4fa17d32fd2300f4040 100644 (file)
@@ -153,15 +153,22 @@ struct boot_e820_entry {
  * setup data structure.
  */
 struct jailhouse_setup_data {
-       __u16   version;
-       __u16   compatible_version;
-       __u16   pm_timer_address;
-       __u16   num_cpus;
-       __u64   pci_mmconfig_base;
-       __u32   tsc_khz;
-       __u32   apic_khz;
-       __u8    standard_ioapic;
-       __u8    cpu_ids[255];
+       struct {
+               __u16   version;
+               __u16   compatible_version;
+       } __attribute__((packed)) hdr;
+       struct {
+               __u16   pm_timer_address;
+               __u16   num_cpus;
+               __u64   pci_mmconfig_base;
+               __u32   tsc_khz;
+               __u32   apic_khz;
+               __u8    standard_ioapic;
+               __u8    cpu_ids[255];
+       } __attribute__((packed)) v1;
+       struct {
+               __u32   flags;
+       } __attribute__((packed)) v2;
 } __attribute__((packed));
 
 /* The so-called "zeropage" */
index e6230af1986468d2f0a03464988dcd576e7ca081..d5b51a740524d6759a1a3c88a0b022a6335abe48 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/memory.h>
 #include <linux/export.h>
 #include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/efi.h>
 
 #include <asm/e820/api.h>
 #include <asm/uv/uv_mmrs.h>
 static DEFINE_PER_CPU(int, x2apic_extra_bits);
 
 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_dist_base, gru_first_node_paddr = -1LL, gru_last_node_paddr;
 static u64                     gru_dist_lmask, gru_dist_umask;
 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: */
 static struct {
        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 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, "NSGI", 4) == 0) {
-                       uv_hubless_system = true;
-                       pr_info("UV: OEM IDs %s/%s, HUBLESS\n",
-                               oem_id, oem_table_id);
-               }
+               if (strncmp(oem_id, "NSGI", 4) != 0)
+                       return 0;
+
+               /* 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;
        }
 
@@ -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)
                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();
        early_get_apic_socketid_shift();
 
@@ -336,9 +379,15 @@ int is_uv_system(void)
 }
 EXPORT_SYMBOL_GPL(is_uv_system);
 
-int is_uv_hubless(void)
+int is_uv_hubbed(int uvtype)
+{
+       return (uv_hubbed_system & uvtype);
+}
+EXPORT_SYMBOL_GPL(is_uv_hubbed);
+
+int is_uv_hubless(int uvtype)
 {
-       return uv_hubless_system;
+       return (uv_hubless_system & uvtype);
 }
 EXPORT_SYMBOL_GPL(is_uv_hubless);
 
@@ -1255,7 +1304,8 @@ static int __init decode_uv_systab(void)
        struct uv_systab *st;
        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 */
 
        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)
 {
        struct uv_hub_info_s hub_info = {0};
@@ -1559,32 +1706,27 @@ static void __init uv_system_init_hub(void)
        uv_nmi_setup();
        uv_cpu_init();
        uv_scir_register_cpu_notifier();
-       proc_mkdir("sgi_uv", NULL);
+       uv_setup_proc_files(0);
 
        /* Register Legacy VGA I/O redirection handler: */
        pci_register_set_vga_state(uv_set_vga_state);
 
-       /*
-        * 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;
+       check_efi_reboot();
 }
 
 /*
- * There is a small amount of UV specific code needed to initialize a
- * UV system that does not have a "UV HUB" (referred to as "hubless").
+ * There is a different code path needed to initialize a UV system that does
+ * not have a "UV HUB" (referred to as "hubless").
  */
 void __init uv_system_init(void)
 {
-       if (likely(!is_uv_system() && !is_uv_hubless()))
+       if (likely(!is_uv_system() && !is_uv_hubless(1)))
                return;
 
        if (is_uv_system())
                uv_system_init_hub();
        else
-               uv_nmi_setup_hubless();
+               uv_system_init_hubless();
 }
 
 apic_driver(apic_x2apic_uv_x);
index 3ad34f01de2a6779b134600b8837cf04465da0b5..6eb8b50ea07e86f116b34bc6960b3976dc27e3b8 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/acpi_pmtmr.h>
 #include <linux/kernel.h>
 #include <linux/reboot.h>
+#include <linux/serial_8250.h>
 #include <asm/apic.h>
 #include <asm/cpu.h>
 #include <asm/hypervisor.h>
 #include <asm/setup.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 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)
 {
        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)
 {
-       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)
@@ -77,33 +93,28 @@ static void __init jailhouse_get_smp_config(unsigned int early)
                .type = IOAPIC_DOMAIN_STRICT,
                .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;
 
        jailhouse_x2apic_init();
 
        register_lapic_address(0xfee00000);
 
-       for (cpu = 0; cpu < setup_data.num_cpus; cpu++) {
-               generic_processor_info(setup_data.cpu_ids[cpu],
+       for (cpu = 0; cpu < setup_data.v1.num_cpus; cpu++) {
+               generic_processor_info(setup_data.v1.cpu_ids[cpu],
                                       boot_cpu_apic_version);
        }
 
        smp_found_config = 1;
 
-       if (setup_data.standard_ioapic) {
+       if (setup_data.v1.standard_ioapic) {
                mp_register_ioapic(0, 0xfec00000, gsi_top, &ioapic_cfg);
 
-               /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
-               mp_irq.srcbusirq = mp_irq.dstirq = 3;
-               mp_save_irq(&mp_irq);
-
-               mp_irq.srcbusirq = mp_irq.dstirq = 4;
-               mp_save_irq(&mp_irq);
+               if (IS_ENABLED(CONFIG_SERIAL_8250) &&
+                   setup_data.hdr.version < 2) {
+                       /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
+                       jailhouse_setup_irq(3);
+                       jailhouse_setup_irq(4);
+               }
        }
 }
 
@@ -126,9 +137,9 @@ static int __init jailhouse_pci_arch_init(void)
                pcibios_last_bus = 0xff;
 
 #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,
-                                setup_data.pci_mmconfig_base);
+                                setup_data.v1.pci_mmconfig_base);
                pci_mmcfg_arch_init();
        }
 #endif
@@ -136,9 +147,57 @@ static int __init jailhouse_pci_arch_init(void)
        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)
 {
        u64 pa_data = boot_params.hdr.setup_data;
+       unsigned long setup_data_len;
        struct setup_data header;
        void *mapping;
 
@@ -163,16 +222,8 @@ static void __init jailhouse_init_platform(void)
                memcpy(&header, mapping, sizeof(header));
                early_memunmap(mapping, sizeof(header));
 
-               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));
-
+               if (header.type == SETUP_JAILHOUSE)
                        break;
-               }
 
                pa_data = header.next;
        }
@@ -180,13 +231,28 @@ static void __init jailhouse_init_platform(void)
        if (!pa_data)
                panic("Jailhouse: No valid setup data found");
 
-       if (setup_data.compatible_version > JAILHOUSE_SETUP_REQUIRED_VERSION)
-               panic("Jailhouse: Unsupported setup data structure");
-
-       pmtmr_ioport = setup_data.pm_timer_address;
+       /* setup data must at least contain the header */
+       if (header.len < sizeof(setup_data.hdr))
+               goto unsupported;
+
+       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);
 
-       precalibrated_tsc_khz = setup_data.tsc_khz;
+       precalibrated_tsc_khz = setup_data.v1.tsc_khz;
        setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
 
        pci_probe = 0;
@@ -196,6 +262,12 @@ static void __init jailhouse_init_platform(void)
         * are none in a non-root cell.
         */
        disable_acpi();
+
+       jailhouse_serial_workaround();
+       return;
+
+unsupported:
+       panic("Jailhouse: Unsupported setup data structure");
 }
 
 bool jailhouse_paravirt(void)
index c2ee31953372d4ed2b8a5fc9b19d9856eeaa9398..ece9cb9c1189bdaf135e1a07375c0334d2f3fc47 100644 (file)
@@ -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);
 
-void uv_bios_init(void)
+int uv_bios_init(void)
 {
        uv_systab = NULL;
        if ((uv_systab_phys == EFI_INVALID_TABLE_ADDR) ||
            !uv_systab_phys || efi_runtime_disabled()) {
                pr_crit("UV: UVsystab: missing\n");
-               return;
+               return -EEXIST;
        }
 
        uv_systab = ioremap(uv_systab_phys, sizeof(struct uv_systab));
        if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) {
                pr_err("UV: UVsystab: bad signature!\n");
                iounmap(uv_systab);
-               return;
+               return -EINVAL;
        }
 
        /* 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);
                if (!uv_systab) {
                        pr_err("UV: UVsystab: ioremap(%d) failed!\n", size);
-                       return;
+                       return -EFAULT;
                }
        }
        pr_info("UV: UVsystab: Revision:%x\n", uv_systab->revision);
+       return 0;
 }