]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
x86/platform/UV: Add obtaining GAM Range Table from UV BIOS
authorMike Travis <travis@sgi.com>
Fri, 29 Apr 2016 21:54:18 +0000 (16:54 -0500)
committerIngo Molnar <mingo@kernel.org>
Wed, 4 May 2016 06:48:50 +0000 (08:48 +0200)
UV4 uses a GAM (globally addressed memory) architecture that supports
variable sized memory per node.  This replaces the old "M" value (number
of address bits per node) with a range table for conversions between
addresses and physical node (pnode) id's.  This table is obtained from UV
BIOS via the EFI UVsystab table.  Support for older EFI UVsystab tables
is maintained.

Tested-by: Dimitri Sivanich <sivanich@sgi.com>
Tested-by: John Estabrook <estabrook@sgi.com>
Tested-by: Gary Kroening <gfk@sgi.com>
Tested-by: Nathan Zimmer <nzimmer@sgi.com>
Signed-off-by: Mike Travis <travis@sgi.com>
Cc: Andrew Banman <abanman@sgi.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Len Brown <len.brown@intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160429215405.329827545@asylum.americas.sgi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/include/asm/uv/bios.h
arch/x86/platform/uv/bios_uv.c
arch/x86/platform/uv/uv_sysfs.c

index 71605c7d5c5c52989d64a3c9305f58b091cd15eb..c852590254d5f4191609f92fce8ee488896efe8b 100644 (file)
@@ -51,15 +51,66 @@ enum {
        BIOS_STATUS_UNAVAIL             = -EBUSY
 };
 
+/* Address map parameters */
+struct uv_gam_parameters {
+       u64     mmr_base;
+       u64     gru_base;
+       u8      mmr_shift;      /* Convert PNode to MMR space offset */
+       u8      gru_shift;      /* Convert PNode to GRU space offset */
+       u8      gpa_shift;      /* Size of offset field in GRU phys addr */
+       u8      unused1;
+};
+
+/* UV_TABLE_GAM_RANGE_ENTRY values */
+#define UV_GAM_RANGE_TYPE_UNUSED       0 /* End of table */
+#define UV_GAM_RANGE_TYPE_RAM          1 /* Normal RAM */
+#define UV_GAM_RANGE_TYPE_NVRAM                2 /* Non-volatile memory */
+#define UV_GAM_RANGE_TYPE_NV_WINDOW    3 /* NVMDIMM block window */
+#define UV_GAM_RANGE_TYPE_NV_MAILBOX   4 /* NVMDIMM mailbox */
+#define UV_GAM_RANGE_TYPE_HOLE         5 /* Unused address range */
+#define UV_GAM_RANGE_TYPE_MAX          6
+
+/* The structure stores PA bits 56:26, for 64MB granularity */
+#define UV_GAM_RANGE_SHFT              26              /* 64MB */
+
+struct uv_gam_range_entry {
+       char    type;           /* Entry type: GAM_RANGE_TYPE_UNUSED, etc. */
+       char    unused1;
+       u16     nasid;          /* HNasid */
+       u16     sockid;         /* Socket ID, high bits of APIC ID */
+       u16     pnode;          /* Index to MMR and GRU spaces */
+       u32     pxm;            /* ACPI proximity domain number */
+       u32     limit;          /* PA bits 56:26 (UV_GAM_RANGE_SHFT) */
+};
+
+#define        UV_SYSTAB_SIG                   "UVST"
+#define        UV_SYSTAB_VERSION_1             1       /* UV1/2/3 BIOS version */
+#define        UV_SYSTAB_VERSION_UV4           0x400   /* UV4 BIOS base version */
+#define        UV_SYSTAB_VERSION_UV4_1         0x401   /* + gpa_shift */
+#define        UV_SYSTAB_VERSION_UV4_2         0x402   /* + TYPE_NVRAM/WINDOW/MBOX */
+#define        UV_SYSTAB_VERSION_UV4_LATEST    UV_SYSTAB_VERSION_UV4_2
+
+#define        UV_SYSTAB_TYPE_UNUSED           0       /* End of table (offset == 0) */
+#define        UV_SYSTAB_TYPE_GAM_PARAMS       1       /* GAM PARAM conversions */
+#define        UV_SYSTAB_TYPE_GAM_RNG_TBL      2       /* GAM entry table */
+#define        UV_SYSTAB_TYPE_MAX              3
+
 /*
  * The UV system table describes specific firmware
  * capabilities available to the Linux kernel at runtime.
  */
 struct uv_systab {
-       char signature[4];      /* must be "UVST" */
+       char signature[4];      /* must be UV_SYSTAB_SIG */
        u32 revision;           /* distinguish different firmware revs */
        u64 function;           /* BIOS runtime callback function ptr */
+       u32 size;               /* systab size (starting with _VERSION_UV4) */
+       struct {
+               u32 type:8;     /* type of entry */
+               u32 offset:24;  /* byte offset from struct start to entry */
+       } entry[1];             /* additional entries follow */
 };
+extern struct uv_systab *uv_systab;
+/* (... end of definitions from UV BIOS ...) */
 
 enum {
        BIOS_FREQ_BASE_PLATFORM = 0,
@@ -99,7 +150,11 @@ 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);
 
+#ifdef CONFIG_EFI
 extern void uv_bios_init(void);
+#else
+void uv_bios_init(void) { }
+#endif
 
 extern unsigned long sn_rtc_cycles_per_second;
 extern int uv_type;
@@ -107,7 +162,7 @@ extern long sn_partition_id;
 extern long sn_coherency_id;
 extern long sn_region_size;
 extern long system_serial_number;
-#define partition_coherence_id()       (sn_coherency_id)
+#define uv_partition_coherence_id()    (sn_coherency_id)
 
 extern struct kobject *sgi_uv_kobj;    /* /sys/firmware/sgi_uv */
 
index 1584cbed0dce25eab259cdaf00ad49724cd09bac..815fec6e05e2b8801f83c0aa34baef9aeeeb27ef 100644 (file)
 
 #include <linux/efi.h>
 #include <linux/export.h>
+#include <linux/slab.h>
 #include <asm/efi.h>
 #include <linux/io.h>
 #include <asm/uv/bios.h>
 #include <asm/uv/uv_hub.h>
 
-static struct uv_systab uv_systab;
+struct uv_systab *uv_systab;
 
 s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
 {
-       struct uv_systab *tab = &uv_systab;
+       struct uv_systab *tab = uv_systab;
        s64 ret;
 
-       if (!tab->function)
+       if (!tab || !tab->function)
                /*
                 * BIOS does not support UV systab
                 */
@@ -183,34 +184,31 @@ int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus)
 }
 EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target);
 
-
 #ifdef CONFIG_EFI
 void uv_bios_init(void)
 {
-       struct uv_systab *tab;
-
-       if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) ||
-           (efi.uv_systab == (unsigned long)NULL)) {
-               printk(KERN_CRIT "No EFI UV System Table.\n");
-               uv_systab.function = (unsigned long)NULL;
+       uv_systab = NULL;
+       if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) || !efi.uv_systab) {
+               pr_crit("UV: UVsystab: missing\n");
                return;
        }
 
-       tab = (struct uv_systab *)ioremap(efi.uv_systab,
-                                       sizeof(struct uv_systab));
-       if (strncmp(tab->signature, "UVST", 4) != 0)
-               printk(KERN_ERR "bad signature in UV system table!");
-
-       /*
-        * Copy table to permanent spot for later use.
-        */
-       memcpy(&uv_systab, tab, sizeof(struct uv_systab));
-       iounmap(tab);
+       uv_systab = ioremap(efi.uv_systab, 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;
+       }
 
-       printk(KERN_INFO "EFI UV System Table Revision %d\n",
-                                       uv_systab.revision);
+       if (uv_systab->revision >= UV_SYSTAB_VERSION_UV4) {
+               iounmap(uv_systab);
+               uv_systab = ioremap(efi.uv_systab, uv_systab->size);
+               if (!uv_systab) {
+                       pr_err("UV: UVsystab: ioremap(%d) failed!\n",
+                               uv_systab->size);
+                       return;
+               }
+       }
+       pr_info("UV: UVsystab: Revision:%x\n", uv_systab->revision);
 }
-#else  /* !CONFIG_EFI */
-
-void uv_bios_init(void) { }
 #endif
index 5d4ba301e776eb238e1d8e3736c7fb3fa6fb824c..e9da9ebd924a60676ee2cd60c32702e6ce0e6e50 100644 (file)
@@ -34,7 +34,7 @@ static ssize_t partition_id_show(struct kobject *kobj,
 static ssize_t coherence_id_show(struct kobject *kobj,
                        struct kobj_attribute *attr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%ld\n", partition_coherence_id());
+       return snprintf(buf, PAGE_SIZE, "%ld\n", uv_partition_coherence_id());
 }
 
 static struct kobj_attribute partition_id_attr =