x86/cpu: Create Hygon Dhyana architecture support file
authorPu Wen <puwen@hygon.cn>
Thu, 4 Apr 2019 13:45:03 +0000 (21:45 +0800)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 6 Jun 2019 14:28:20 +0000 (15:28 +0100)
Add x86 architecture support for a new processor: Hygon Dhyana Family
18h. To make Hygon initialization flow more clear, carve out code from
amd.c into a separate file hygon.c, and remove unnecessary code for
Hygon Dhyana.

To identify Hygon Dhyana CPU, add a new vendor type X86_VENDOR_HYGON
and vendor ID "HygonGenuine" for system recognition, and fit the new
x86 vendor lookup mechanism.

Hygon can fully use the function early_init_amd(), so make this common
function non-static and direct call it from Hygon code.

Add a separate hygon_get_topology(), which calculate phys_proc_id from
AcpiId[6](see reference [1]).

Reference:
[1] https://git.kernel.org/tip/e0ceeae708cebf22c990c3d703a4ca187dc837f5

Signed-off-by: Pu Wen <puwen@hygon.cn>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
[Rebase over 0cd074144cb "x86/cpu: Renumber X86_VENDOR_* to form a bitmap" and
             64933920c9b "x86/cpu: Drop cpu_devs[] and $VENDOR_init_cpu() hooks"]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
tools/tests/cpu-policy/test-cpu-policy.c
xen/arch/x86/cpu/Makefile
xen/arch/x86/cpu/amd.c
xen/arch/x86/cpu/common.c
xen/arch/x86/cpu/cpu.h
xen/arch/x86/cpu/hygon.c [new file with mode: 0644]
xen/include/asm-x86/x86-vendors.h
xen/lib/x86/cpuid.c

index cb2c920e82feb3e124602c62f27d5372127414b6..ca3b8dd45fe18fd809804e8ec2e1a7c8d098c3da 100644 (file)
@@ -46,6 +46,7 @@ static void test_vendor_identification(void)
         { { "AuthenticAMD" }, X86_VENDOR_AMD },
         { { "CentaurHauls" }, X86_VENDOR_CENTAUR },
         { { "  Shanghai  " }, X86_VENDOR_SHANGHAI },
+        { { "HygonGenuine" }, X86_VENDOR_HYGON },
 
         { { ""             }, X86_VENDOR_UNKNOWN },
         { { "            " }, X86_VENDOR_UNKNOWN },
index 34a01ca061c4a89ee107d58bdc6c98f902bdc0dd..466acc8b10e54cc8f9e53abe52cb713ddba1def6 100644 (file)
@@ -4,6 +4,7 @@ subdir-y += mtrr
 obj-y += amd.o
 obj-y += centaur.o
 obj-y += common.o
+obj-y += hygon.o
 obj-y += intel.o
 obj-y += intel_cacheinfo.o
 obj-y += mwait-idle.o
index 23de258c78df1375b190491fc43ee601db0662f1..8404cf290fc04dbd2a7d91f6e2bfadb23e96a307 100644 (file)
@@ -526,7 +526,7 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
                                                           : c->cpu_core_id);
 }
 
-static void early_init_amd(struct cpuinfo_x86 *c)
+void early_init_amd(struct cpuinfo_x86 *c)
 {
        if (c == &boot_cpu_data)
                amd_init_levelling();
index 33f5d3255793488bd176a77f18fba590ca713e5f..4eee12da23fa7e74580956af459c1a44b6145527 100644 (file)
@@ -286,6 +286,7 @@ void __init early_cpu_init(void)
        case X86_VENDOR_AMD:      this_cpu = &amd_cpu_dev;      break;
        case X86_VENDOR_CENTAUR:  this_cpu = &centaur_cpu_dev;  break;
        case X86_VENDOR_SHANGHAI: this_cpu = &shanghai_cpu_dev; break;
+       case X86_VENDOR_HYGON:    this_cpu = &hygon_cpu_dev;    break;
        default:
                printk(XENLOG_ERR
                       "Unrecognised or unsupported CPU vendor '%.12s'\n",
index 54bd0d31740db12c5813a62f5a349fcbde6ad30e..30cd3a85783cb12e4b59059859ec68686a86f26c 100644 (file)
@@ -5,7 +5,7 @@ struct cpu_dev {
 };
 
 extern const struct cpu_dev intel_cpu_dev, amd_cpu_dev, centaur_cpu_dev,
-    shanghai_cpu_dev;
+    shanghai_cpu_dev, hygon_cpu_dev;
 
 extern bool_t opt_arat;
 extern unsigned int opt_cpuid_mask_ecx, opt_cpuid_mask_edx;
@@ -14,3 +14,5 @@ extern unsigned int opt_cpuid_mask_ext_ecx, opt_cpuid_mask_ext_edx;
 
 extern int get_model_name(struct cpuinfo_x86 *c);
 extern void display_cacheinfo(struct cpuinfo_x86 *c);
+
+void early_init_amd(struct cpuinfo_x86 *c);
diff --git a/xen/arch/x86/cpu/hygon.c b/xen/arch/x86/cpu/hygon.c
new file mode 100644 (file)
index 0000000..9ab7aa8
--- /dev/null
@@ -0,0 +1,107 @@
+#include <xen/init.h>
+#include <asm/processor.h>
+#include <asm/hvm/support.h>
+#include <asm/spec_ctrl.h>
+
+#include "cpu.h"
+
+#define APICID_SOCKET_ID_BIT 6
+
+static void hygon_get_topology(struct cpuinfo_x86 *c)
+{
+       unsigned int ebx;
+
+       if (c->x86_max_cores <= 1)
+               return;
+
+       /* Socket ID is ApicId[6] for Hygon processors. */
+       c->phys_proc_id >>= APICID_SOCKET_ID_BIT;
+
+       ebx = cpuid_ebx(0x8000001e);
+       c->x86_num_siblings = ((ebx >> 8) & 0x3) + 1;
+       c->x86_max_cores /= c->x86_num_siblings;
+       c->cpu_core_id = ebx & 0xff;
+
+       if (opt_cpu_info)
+               printk("CPU %d(%d) -> Processor %d, Core %d\n",
+                       smp_processor_id(), c->x86_max_cores,
+                               c->phys_proc_id, c->cpu_core_id);
+}
+
+static void init_hygon(struct cpuinfo_x86 *c)
+{
+       unsigned long long value;
+
+       /*
+        * Attempt to set lfence to be Dispatch Serialising.  This MSR almost
+        * certainly isn't virtualised (and Xen at least will leak the real
+        * value in but silently discard writes), as well as being per-core
+        * rather than per-thread, so do a full safe read/write/readback cycle
+        * in the worst case.
+        */
+       if (rdmsr_safe(MSR_AMD64_DE_CFG, value))
+               /* Unable to read.  Assume the safer default. */
+               __clear_bit(X86_FEATURE_LFENCE_DISPATCH,
+                           c->x86_capability);
+       else if (value & AMD64_DE_CFG_LFENCE_SERIALISE)
+               /* Already dispatch serialising. */
+               __set_bit(X86_FEATURE_LFENCE_DISPATCH,
+                         c->x86_capability);
+       else if (wrmsr_safe(MSR_AMD64_DE_CFG,
+                           value | AMD64_DE_CFG_LFENCE_SERIALISE) ||
+                rdmsr_safe(MSR_AMD64_DE_CFG, value) ||
+                !(value & AMD64_DE_CFG_LFENCE_SERIALISE))
+               /* Attempt to set failed.  Assume the safer default. */
+               __clear_bit(X86_FEATURE_LFENCE_DISPATCH,
+                           c->x86_capability);
+       else
+               /* Successfully enabled! */
+               __set_bit(X86_FEATURE_LFENCE_DISPATCH,
+                         c->x86_capability);
+
+       /*
+        * If the user has explicitly chosen to disable Memory Disambiguation
+        * to mitigiate Speculative Store Bypass, poke the appropriate MSR.
+        */
+       if (opt_ssbd && !rdmsr_safe(MSR_AMD64_LS_CFG, value)) {
+               value |= 1ull << 10;
+               wrmsr_safe(MSR_AMD64_LS_CFG, value);
+       }
+
+       /* MFENCE stops RDTSC speculation */
+       if (!cpu_has_lfence_dispatch)
+               __set_bit(X86_FEATURE_MFENCE_RDTSC, c->x86_capability);
+
+       display_cacheinfo(c);
+
+       if (c->extended_cpuid_level >= 0x80000008)
+               c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
+
+       if (c->extended_cpuid_level >= 0x80000007) {
+               if (cpu_has(c, X86_FEATURE_ITSC)) {
+                       __set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability);
+                       __set_bit(X86_FEATURE_NONSTOP_TSC, c->x86_capability);
+                       __set_bit(X86_FEATURE_TSC_RELIABLE, c->x86_capability);
+               }
+       }
+
+       hygon_get_topology(c);
+
+       /* Hygon CPUs do not support SYSENTER outside of legacy mode. */
+       __clear_bit(X86_FEATURE_SEP, c->x86_capability);
+
+       /* Hygon processors have APIC timer running in deep C states. */
+       if (opt_arat)
+               __set_bit(X86_FEATURE_ARAT, c->x86_capability);
+
+       if (cpu_has(c, X86_FEATURE_EFRO)) {
+               rdmsrl(MSR_K7_HWCR, value);
+               value |= (1 << 27); /* Enable read-only APERF/MPERF bit */
+               wrmsrl(MSR_K7_HWCR, value);
+       }
+}
+
+const struct cpu_dev hygon_cpu_dev = {
+       .c_early_init   = early_init_amd,
+       .c_init         = init_hygon,
+};
index a201946fcab0cb7c3e7c5e9a7054d4851e5f4da9..0a37024cbdc4f7065cf4876b8224629f57477ffa 100644 (file)
@@ -31,4 +31,9 @@
 #define X86_VENDOR_SHANGHAI_ECX 0x20206961U
 #define X86_VENDOR_SHANGHAI_EDX 0x68676e61U
 
+#define X86_VENDOR_HYGON (1 << 4)
+#define X86_VENDOR_HYGON_EBX 0x6f677948U /* "HygonGenuine" */
+#define X86_VENDOR_HYGON_ECX 0x656e6975U
+#define X86_VENDOR_HYGON_EDX 0x6e65476eU
+
 #endif /* __XEN_X86_VENDORS_H__ */
index ea6e476a4f4128273a3490f41346c59ebdea5797..266084e61357b7b0e289d0d8ed1e3630345e03a2 100644 (file)
@@ -36,6 +36,12 @@ unsigned int x86_cpuid_lookup_vendor(uint32_t ebx, uint32_t ecx, uint32_t edx)
              edx == X86_VENDOR_SHANGHAI_EDX )
             return X86_VENDOR_SHANGHAI;
         break;
+
+    case X86_VENDOR_HYGON_EBX:
+        if ( ecx == X86_VENDOR_HYGON_ECX &&
+             edx == X86_VENDOR_HYGON_EDX )
+            return X86_VENDOR_HYGON;
+        break;
     }
 
     return X86_VENDOR_UNKNOWN;
@@ -49,6 +55,7 @@ const char *x86_cpuid_vendor_to_str(unsigned int vendor)
     case X86_VENDOR_AMD:      return "AMD";
     case X86_VENDOR_CENTAUR:  return "Centaur";
     case X86_VENDOR_SHANGHAI: return "Shanghai";
+    case X86_VENDOR_HYGON:    return "Hygon";
     default:                  return "Unknown";
     }
 }