diff options
author | Joe Bonasera <Joe.Bonasera@sun.com> | 2009-07-14 10:51:37 -0700 |
---|---|---|
committer | Joe Bonasera <Joe.Bonasera@sun.com> | 2009-07-14 10:51:37 -0700 |
commit | 2ef50f010f7a3a07eb5a9f6001b9843fd868e26b (patch) | |
tree | 517cbe696d6da0bbb76aef7f2db59c73a0a6c7e5 /usr | |
parent | 349dcea37d1dc6e491c49c864c5e3773a4e3cae6 (diff) | |
download | illumos-gate-2ef50f010f7a3a07eb5a9f6001b9843fd868e26b.tar.gz |
6848982 32 bit kernel should use %cr8 to access the TPR when possible
Diffstat (limited to 'usr')
-rw-r--r-- | usr/src/uts/i86pc/io/pcplusmp/apic.c | 30 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/pcplusmp/apic_regops.c | 8 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/cpuid.c | 23 | ||||
-rw-r--r-- | usr/src/uts/intel/ia32/ml/i86_subr.s | 18 | ||||
-rw-r--r-- | usr/src/uts/intel/sys/archsystm.h | 2 | ||||
-rw-r--r-- | usr/src/uts/intel/sys/x86_archext.h | 2 |
6 files changed, 76 insertions, 7 deletions
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic.c b/usr/src/uts/i86pc/io/pcplusmp/apic.c index 5497c771ad..0cba2a9037 100644 --- a/usr/src/uts/i86pc/io/pcplusmp/apic.c +++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c @@ -118,6 +118,7 @@ int apic_oneshot_enable = 1; /* to allow disabling one-shot capability */ /* Now the ones for Dynamic Interrupt distribution */ int apic_enable_dynamic_migration = 0; +int apic_have_32bit_cr8 = 0; /* * These variables are frequently accessed in apic_intr_enter(), @@ -436,6 +437,9 @@ apic_init() for (i = 0; i <= MAXIPL; i++) apic_cr8pri[i] = apic_ipltopri[i] >> APIC_IPL_SHIFT; CPU->cpu_pri_data = apic_cr8pri; +#else + if (cpuid_have_cr8access(CPU)) + apic_have_32bit_cr8 = 1; #endif /* __amd64 */ } @@ -953,8 +957,12 @@ apic_intr_enter(int ipl, int *vectorp) setcr8((ulong_t)(apic_ipltopri[nipl] >> APIC_IPL_SHIFT)); #else - LOCAL_APIC_WRITE_REG(APIC_TASK_REG, - (uint32_t)apic_ipltopri[nipl]); + if (apic_have_32bit_cr8) + setcr8((ulong_t)(apic_ipltopri[nipl] >> + APIC_IPL_SHIFT)); + else + LOCAL_APIC_WRITE_REG(APIC_TASK_REG, + (uint32_t)apic_ipltopri[nipl]); #endif LOCAL_APIC_WRITE_REG(APIC_EOI_REG, 0); } else { @@ -995,8 +1003,12 @@ apic_intr_enter(int ipl, int *vectorp) #if defined(__amd64) setcr8((ulong_t)(apic_ipltopri[nipl] >> APIC_IPL_SHIFT)); #else - LOCAL_APIC_WRITE_REG(APIC_TASK_REG, - (uint32_t)apic_ipltopri[nipl]); + if (apic_have_32bit_cr8) + setcr8((ulong_t)(apic_ipltopri[nipl] >> + APIC_IPL_SHIFT)); + else + LOCAL_APIC_WRITE_REG(APIC_TASK_REG, + (uint32_t)apic_ipltopri[nipl]); #endif } else { X2APIC_WRITE(APIC_TASK_REG, apic_ipltopri[nipl]); @@ -1059,7 +1071,10 @@ apic_intr_exit(int prev_ipl, int irq) #if defined(__amd64) setcr8((ulong_t)apic_cr8pri[prev_ipl]); #else - apicadr[APIC_TASK_REG] = apic_ipltopri[prev_ipl]; + if (apic_have_32bit_cr8) + setcr8((ulong_t)(apic_ipltopri[prev_ipl] >> APIC_IPL_SHIFT)); + else + apicadr[APIC_TASK_REG] = apic_ipltopri[prev_ipl]; #endif APIC_INTR_EXIT(); @@ -1098,7 +1113,10 @@ apic_setspl(int ipl) #if defined(__amd64) setcr8((ulong_t)apic_cr8pri[ipl]); #else - apicadr[APIC_TASK_REG] = apic_ipltopri[ipl]; + if (apic_have_32bit_cr8) + setcr8((ulong_t)(apic_ipltopri[ipl] >> APIC_IPL_SHIFT)); + else + apicadr[APIC_TASK_REG] = apic_ipltopri[ipl]; #endif /* interrupts at ipl above this cannot be in progress */ diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c b/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c index bd341db9d1..937eb38bb1 100644 --- a/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c +++ b/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c @@ -83,6 +83,7 @@ static apic_reg_ops_t x2apic_regs_ops = { apic_send_EOI, }; +extern int apic_have_32bit_cr8; /* The default ops is local APIC (Memory Mapped IO) */ apic_reg_ops_t *apic_reg_ops = &local_apic_regs_ops; @@ -119,6 +120,8 @@ get_local_apic_pri(void) #if defined(__amd64) return ((int)getcr8()); #else + if (apic_have_32bit_cr8) + return ((int)getcr8()); return (apicadr[APIC_TASK_REG]); #endif } @@ -129,7 +132,10 @@ local_apic_write_task_reg(uint64_t value) #if defined(__amd64) setcr8((ulong_t)(value >> APIC_IPL_SHIFT)); #else - apicadr[APIC_TASK_REG] = (uint32_t)value; + if (apic_have_32bit_cr8) + setcr8((ulong_t)(value >> APIC_IPL_SHIFT)); + else + apicadr[APIC_TASK_REG] = (uint32_t)value; #endif } diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c index 8bb00a1018..78e1cdde99 100644 --- a/usr/src/uts/i86pc/os/cpuid.c +++ b/usr/src/uts/i86pc/os/cpuid.c @@ -364,6 +364,11 @@ platform_cpuid_mangle(uint_t vendor, uint32_t eax, struct cpuid_regs *cp) break; case X86_VENDOR_AMD: switch (eax) { + + case 0x80000001: + cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D; + break; + case 0x80000008: /* * Zero out the (ncores-per-chip - 1) field @@ -2535,6 +2540,24 @@ cpuid_get_clogid(cpu_t *cpu) return (cpu->cpu_m.mcpu_cpi->cpi_clogid); } +/*ARGSUSED*/ +int +cpuid_have_cr8access(cpu_t *cpu) +{ +#if defined(__amd64) + return (1); +#else + struct cpuid_info *cpi; + + ASSERT(cpu != NULL); + cpi = cpu->cpu_m.mcpu_cpi; + if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 && + (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0) + return (1); + return (0); +#endif +} + uint32_t cpuid_get_apicid(cpu_t *cpu) { diff --git a/usr/src/uts/intel/ia32/ml/i86_subr.s b/usr/src/uts/intel/ia32/ml/i86_subr.s index 6a083abb66..b16c2ce457 100644 --- a/usr/src/uts/intel/ia32/ml/i86_subr.s +++ b/usr/src/uts/intel/ia32/ml/i86_subr.s @@ -580,6 +580,24 @@ setcr8(ulong_t val) ret SET_SIZE(setcr0) + /* + * "lock mov %cr0" is used on processors which indicate it is + * supported via CPUID. Normally the 32 bit TPR is accessed via + * the local APIC. + */ + ENTRY(getcr8) + lock + movl %cr0, %eax + ret + SET_SIZE(getcr8) + + ENTRY(setcr8) + movl 4(%esp), %eax + lock + movl %eax, %cr0 + ret + SET_SIZE(setcr8) + ENTRY(getcr2) #if defined(__xpv) movl %gs:CPU_VCPU_INFO, %eax diff --git a/usr/src/uts/intel/sys/archsystm.h b/usr/src/uts/intel/sys/archsystm.h index fdd4f00478..92438659c0 100644 --- a/usr/src/uts/intel/sys/archsystm.h +++ b/usr/src/uts/intel/sys/archsystm.h @@ -45,6 +45,8 @@ extern int getpil(void); extern ulong_t getcr0(void); extern void setcr0(ulong_t); +extern ulong_t getcr8(void); +extern void setcr8(ulong_t); extern ulong_t getcr2(void); extern void iommu_cpu_nop(void); extern void clflush_insn(caddr_t addr); diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h index f81804541b..e765c8a018 100644 --- a/usr/src/uts/intel/sys/x86_archext.h +++ b/usr/src/uts/intel/sys/x86_archext.h @@ -629,6 +629,8 @@ extern const char *cpuid_getchiprevstr(struct cpu *); extern uint32_t cpuid_getsockettype(struct cpu *); extern const char *cpuid_getsocketstr(struct cpu *); +extern int cpuid_have_cr8access(struct cpu *); + extern int cpuid_opteron_erratum(struct cpu *, uint_t); struct cpuid_info; |