summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorJoe Bonasera <Joe.Bonasera@sun.com>2009-07-14 10:51:37 -0700
committerJoe Bonasera <Joe.Bonasera@sun.com>2009-07-14 10:51:37 -0700
commit2ef50f010f7a3a07eb5a9f6001b9843fd868e26b (patch)
tree517cbe696d6da0bbb76aef7f2db59c73a0a6c7e5 /usr
parent349dcea37d1dc6e491c49c864c5e3773a4e3cae6 (diff)
downloadillumos-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.c30
-rw-r--r--usr/src/uts/i86pc/io/pcplusmp/apic_regops.c8
-rw-r--r--usr/src/uts/i86pc/os/cpuid.c23
-rw-r--r--usr/src/uts/intel/ia32/ml/i86_subr.s18
-rw-r--r--usr/src/uts/intel/sys/archsystm.h2
-rw-r--r--usr/src/uts/intel/sys/x86_archext.h2
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;