Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include <linux/sched.h>
0004 #include <linux/sched/clock.h>
0005 
0006 #include <asm/cpu.h>
0007 #include <asm/cpufeature.h>
0008 #include <asm/e820/api.h>
0009 #include <asm/mtrr.h>
0010 #include <asm/msr.h>
0011 
0012 #include "cpu.h"
0013 
0014 #define ACE_PRESENT (1 << 6)
0015 #define ACE_ENABLED (1 << 7)
0016 #define ACE_FCR     (1 << 28)   /* MSR_VIA_FCR */
0017 
0018 #define RNG_PRESENT (1 << 2)
0019 #define RNG_ENABLED (1 << 3)
0020 #define RNG_ENABLE  (1 << 6)    /* MSR_VIA_RNG */
0021 
0022 static void init_c3(struct cpuinfo_x86 *c)
0023 {
0024     u32  lo, hi;
0025 
0026     /* Test for Centaur Extended Feature Flags presence */
0027     if (cpuid_eax(0xC0000000) >= 0xC0000001) {
0028         u32 tmp = cpuid_edx(0xC0000001);
0029 
0030         /* enable ACE unit, if present and disabled */
0031         if ((tmp & (ACE_PRESENT | ACE_ENABLED)) == ACE_PRESENT) {
0032             rdmsr(MSR_VIA_FCR, lo, hi);
0033             lo |= ACE_FCR;      /* enable ACE unit */
0034             wrmsr(MSR_VIA_FCR, lo, hi);
0035             pr_info("CPU: Enabled ACE h/w crypto\n");
0036         }
0037 
0038         /* enable RNG unit, if present and disabled */
0039         if ((tmp & (RNG_PRESENT | RNG_ENABLED)) == RNG_PRESENT) {
0040             rdmsr(MSR_VIA_RNG, lo, hi);
0041             lo |= RNG_ENABLE;   /* enable RNG unit */
0042             wrmsr(MSR_VIA_RNG, lo, hi);
0043             pr_info("CPU: Enabled h/w RNG\n");
0044         }
0045 
0046         /* store Centaur Extended Feature Flags as
0047          * word 5 of the CPU capability bit array
0048          */
0049         c->x86_capability[CPUID_C000_0001_EDX] = cpuid_edx(0xC0000001);
0050     }
0051 #ifdef CONFIG_X86_32
0052     /* Cyrix III family needs CX8 & PGE explicitly enabled. */
0053     if (c->x86_model >= 6 && c->x86_model <= 13) {
0054         rdmsr(MSR_VIA_FCR, lo, hi);
0055         lo |= (1<<1 | 1<<7);
0056         wrmsr(MSR_VIA_FCR, lo, hi);
0057         set_cpu_cap(c, X86_FEATURE_CX8);
0058     }
0059 
0060     /* Before Nehemiah, the C3's had 3dNOW! */
0061     if (c->x86_model >= 6 && c->x86_model < 9)
0062         set_cpu_cap(c, X86_FEATURE_3DNOW);
0063 #endif
0064     if (c->x86 == 0x6 && c->x86_model >= 0xf) {
0065         c->x86_cache_alignment = c->x86_clflush_size * 2;
0066         set_cpu_cap(c, X86_FEATURE_REP_GOOD);
0067     }
0068 
0069     if (c->x86 >= 7)
0070         set_cpu_cap(c, X86_FEATURE_REP_GOOD);
0071 }
0072 
0073 enum {
0074         ECX8        = 1<<1,
0075         EIERRINT    = 1<<2,
0076         DPM     = 1<<3,
0077         DMCE        = 1<<4,
0078         DSTPCLK     = 1<<5,
0079         ELINEAR     = 1<<6,
0080         DSMC        = 1<<7,
0081         DTLOCK      = 1<<8,
0082         EDCTLB      = 1<<8,
0083         EMMX        = 1<<9,
0084         DPDC        = 1<<11,
0085         EBRPRED     = 1<<12,
0086         DIC     = 1<<13,
0087         DDC     = 1<<14,
0088         DNA     = 1<<15,
0089         ERETSTK     = 1<<16,
0090         E2MMX       = 1<<19,
0091         EAMD3D      = 1<<20,
0092 };
0093 
0094 static void early_init_centaur(struct cpuinfo_x86 *c)
0095 {
0096 #ifdef CONFIG_X86_32
0097     /* Emulate MTRRs using Centaur's MCR. */
0098     if (c->x86 == 5)
0099         set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR);
0100 #endif
0101     if ((c->x86 == 6 && c->x86_model >= 0xf) ||
0102         (c->x86 >= 7))
0103         set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
0104 
0105 #ifdef CONFIG_X86_64
0106     set_cpu_cap(c, X86_FEATURE_SYSENTER32);
0107 #endif
0108     if (c->x86_power & (1 << 8)) {
0109         set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
0110         set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC);
0111     }
0112 }
0113 
0114 static void init_centaur(struct cpuinfo_x86 *c)
0115 {
0116 #ifdef CONFIG_X86_32
0117     char *name;
0118     u32  fcr_set = 0;
0119     u32  fcr_clr = 0;
0120     u32  lo, hi, newlo;
0121     u32  aa, bb, cc, dd;
0122 
0123     /*
0124      * Bit 31 in normal CPUID used for nonstandard 3DNow ID;
0125      * 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway
0126      */
0127     clear_cpu_cap(c, 0*32+31);
0128 #endif
0129     early_init_centaur(c);
0130     init_intel_cacheinfo(c);
0131     detect_num_cpu_cores(c);
0132 #ifdef CONFIG_X86_32
0133     detect_ht(c);
0134 #endif
0135 
0136     if (c->cpuid_level > 9) {
0137         unsigned int eax = cpuid_eax(10);
0138 
0139         /*
0140          * Check for version and the number of counters
0141          * Version(eax[7:0]) can't be 0;
0142          * Counters(eax[15:8]) should be greater than 1;
0143          */
0144         if ((eax & 0xff) && (((eax >> 8) & 0xff) > 1))
0145             set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
0146     }
0147 
0148 #ifdef CONFIG_X86_32
0149     if (c->x86 == 5) {
0150         switch (c->x86_model) {
0151         case 4:
0152             name = "C6";
0153             fcr_set = ECX8|DSMC|EDCTLB|EMMX|ERETSTK;
0154             fcr_clr = DPDC;
0155             pr_notice("Disabling bugged TSC.\n");
0156             clear_cpu_cap(c, X86_FEATURE_TSC);
0157             break;
0158         case 8:
0159             switch (c->x86_stepping) {
0160             default:
0161             name = "2";
0162                 break;
0163             case 7 ... 9:
0164                 name = "2A";
0165                 break;
0166             case 10 ... 15:
0167                 name = "2B";
0168                 break;
0169             }
0170             fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
0171                   E2MMX|EAMD3D;
0172             fcr_clr = DPDC;
0173             break;
0174         case 9:
0175             name = "3";
0176             fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
0177                   E2MMX|EAMD3D;
0178             fcr_clr = DPDC;
0179             break;
0180         default:
0181             name = "??";
0182         }
0183 
0184         rdmsr(MSR_IDT_FCR1, lo, hi);
0185         newlo = (lo|fcr_set) & (~fcr_clr);
0186 
0187         if (newlo != lo) {
0188             pr_info("Centaur FCR was 0x%X now 0x%X\n",
0189                 lo, newlo);
0190             wrmsr(MSR_IDT_FCR1, newlo, hi);
0191         } else {
0192             pr_info("Centaur FCR is 0x%X\n", lo);
0193         }
0194         /* Emulate MTRRs using Centaur's MCR. */
0195         set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR);
0196         /* Report CX8 */
0197         set_cpu_cap(c, X86_FEATURE_CX8);
0198         /* Set 3DNow! on Winchip 2 and above. */
0199         if (c->x86_model >= 8)
0200             set_cpu_cap(c, X86_FEATURE_3DNOW);
0201         /* See if we can find out some more. */
0202         if (cpuid_eax(0x80000000) >= 0x80000005) {
0203             /* Yes, we can. */
0204             cpuid(0x80000005, &aa, &bb, &cc, &dd);
0205             /* Add L1 data and code cache sizes. */
0206             c->x86_cache_size = (cc>>24)+(dd>>24);
0207         }
0208         sprintf(c->x86_model_id, "WinChip %s", name);
0209     }
0210 #endif
0211     if (c->x86 == 6 || c->x86 >= 7)
0212         init_c3(c);
0213 #ifdef CONFIG_X86_64
0214     set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
0215 #endif
0216 
0217     init_ia32_feat_ctl(c);
0218 }
0219 
0220 #ifdef CONFIG_X86_32
0221 static unsigned int
0222 centaur_size_cache(struct cpuinfo_x86 *c, unsigned int size)
0223 {
0224     /* VIA C3 CPUs (670-68F) need further shifting. */
0225     if ((c->x86 == 6) && ((c->x86_model == 7) || (c->x86_model == 8)))
0226         size >>= 8;
0227 
0228     /*
0229      * There's also an erratum in Nehemiah stepping 1, which
0230      * returns '65KB' instead of '64KB'
0231      *  - Note, it seems this may only be in engineering samples.
0232      */
0233     if ((c->x86 == 6) && (c->x86_model == 9) &&
0234                 (c->x86_stepping == 1) && (size == 65))
0235         size -= 1;
0236     return size;
0237 }
0238 #endif
0239 
0240 static const struct cpu_dev centaur_cpu_dev = {
0241     .c_vendor   = "Centaur",
0242     .c_ident    = { "CentaurHauls" },
0243     .c_early_init   = early_init_centaur,
0244     .c_init     = init_centaur,
0245 #ifdef CONFIG_X86_32
0246     .legacy_cache_size = centaur_size_cache,
0247 #endif
0248     .c_x86_vendor   = X86_VENDOR_CENTAUR,
0249 };
0250 
0251 cpu_dev_register(centaur_cpu_dev);