Archived
14
0
Fork 0

Merge branch 'x86/core' into x86/unify-cpu-detect

This commit is contained in:
Ingo Molnar 2008-09-05 09:27:23 +02:00
commit 0c8c708a7e
398 changed files with 6554 additions and 2635 deletions

View file

@ -1425,6 +1425,12 @@ and is between 256 and 4096 characters. It is defined in the file
nolapic_timer [X86-32,APIC] Do not use the local APIC timer. nolapic_timer [X86-32,APIC] Do not use the local APIC timer.
nox2apic [X86-64,APIC] Do not enable x2APIC mode.
x2apic_phys [X86-64,APIC] Use x2apic physical mode instead of
default x2apic cluster mode on platforms
supporting x2apic.
noltlbs [PPC] Do not use large page/tlb entries for kernel noltlbs [PPC] Do not use large page/tlb entries for kernel
lowmem mapping on PPC40x. lowmem mapping on PPC40x.
@ -1882,6 +1888,12 @@ and is between 256 and 4096 characters. It is defined in the file
shapers= [NET] shapers= [NET]
Maximal number of shapers. Maximal number of shapers.
show_msr= [x86] show boot-time MSR settings
Format: { <integer> }
Show boot-time (BIOS-initialized) MSR settings.
The parameter means the number of CPUs to show,
for example 1 means boot CPU only.
sim710= [SCSI,HW] sim710= [SCSI,HW]
See header of drivers/scsi/sim710.c. See header of drivers/scsi/sim710.c.

View file

@ -41,12 +41,12 @@
#define stub_rt_sigreturn sys_rt_sigreturn #define stub_rt_sigreturn sys_rt_sigreturn
#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; #define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ;
#undef _ASM_X86_64_UNISTD_H_ #undef ASM_X86__UNISTD_64_H
#include <asm-x86/unistd_64.h> #include <asm-x86/unistd_64.h>
#undef __SYSCALL #undef __SYSCALL
#define __SYSCALL(nr, sym) [ nr ] = sym, #define __SYSCALL(nr, sym) [ nr ] = sym,
#undef _ASM_X86_64_UNISTD_H_ #undef ASM_X86__UNISTD_64_H
typedef void (*sys_call_ptr_t)(void); typedef void (*sys_call_ptr_t)(void);

View file

@ -1643,6 +1643,14 @@ config DMAR_FLOPPY_WA
workaround will setup a 1:1 mapping for the first workaround will setup a 1:1 mapping for the first
16M to make floppy (an ISA device) work. 16M to make floppy (an ISA device) work.
config INTR_REMAP
bool "Support for Interrupt Remapping (EXPERIMENTAL)"
depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL
help
Supports Interrupt remapping for IO-APIC and MSI devices.
To use x2apic mode in the CPU's which support x2APIC enhancements or
to support platforms with CPU's having > 8 bit APIC ID, say Y.
source "drivers/pci/pcie/Kconfig" source "drivers/pci/pcie/Kconfig"
source "drivers/pci/Kconfig" source "drivers/pci/Kconfig"

View file

@ -415,3 +415,73 @@ config X86_MINIMUM_CPU_FAMILY
config X86_DEBUGCTLMSR config X86_DEBUGCTLMSR
def_bool y def_bool y
depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386) depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
menuconfig PROCESSOR_SELECT
default y
bool "Supported processor vendors" if EMBEDDED
help
This lets you choose what x86 vendor support code your kernel
will include.
config CPU_SUP_INTEL_32
default y
bool "Support Intel processors" if PROCESSOR_SELECT
depends on !64BIT
help
This enables extended support for Intel processors
config CPU_SUP_INTEL_64
default y
bool "Support Intel processors" if PROCESSOR_SELECT
depends on 64BIT
help
This enables extended support for Intel processors
config CPU_SUP_CYRIX_32
default y
bool "Support Cyrix processors" if PROCESSOR_SELECT
depends on !64BIT
help
This enables extended support for Cyrix processors
config CPU_SUP_AMD_32
default y
bool "Support AMD processors" if PROCESSOR_SELECT
depends on !64BIT
help
This enables extended support for AMD processors
config CPU_SUP_AMD_64
default y
bool "Support AMD processors" if PROCESSOR_SELECT
depends on 64BIT
help
This enables extended support for AMD processors
config CPU_SUP_CENTAUR_32
default y
bool "Support Centaur processors" if PROCESSOR_SELECT
depends on !64BIT
help
This enables extended support for Centaur processors
config CPU_SUP_CENTAUR_64
default y
bool "Support Centaur processors" if PROCESSOR_SELECT
depends on 64BIT
help
This enables extended support for Centaur processors
config CPU_SUP_TRANSMETA_32
default y
bool "Support Transmeta processors" if PROCESSOR_SELECT
depends on !64BIT
help
This enables extended support for Transmeta processors
config CPU_SUP_UMC_32
default y
bool "Support UMC processors" if PROCESSOR_SELECT
depends on !64BIT
help
This enables extended support for UMC processors

View file

@ -16,7 +16,7 @@
*/ */
#undef CONFIG_PARAVIRT #undef CONFIG_PARAVIRT
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
#define _ASM_DESC_H_ 1 #define ASM_X86__DESC_H 1
#endif #endif
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64

View file

@ -38,12 +38,12 @@ static const u32 req_flags[NCAPINTS] =
{ {
REQUIRED_MASK0, REQUIRED_MASK0,
REQUIRED_MASK1, REQUIRED_MASK1,
REQUIRED_MASK2, 0, /* REQUIRED_MASK2 not implemented in this file */
REQUIRED_MASK3, 0, /* REQUIRED_MASK3 not implemented in this file */
REQUIRED_MASK4, REQUIRED_MASK4,
REQUIRED_MASK5, 0, /* REQUIRED_MASK5 not implemented in this file */
REQUIRED_MASK6, REQUIRED_MASK6,
REQUIRED_MASK7, 0, /* REQUIRED_MASK7 not implemented in this file */
}; };
#define A32(a, b, c, d) (((d) << 24)+((c) << 16)+((b) << 8)+(a)) #define A32(a, b, c, d) (((d) << 24)+((c) << 16)+((b) << 8)+(a))

View file

@ -15,7 +15,7 @@
#include <stdio.h> #include <stdio.h>
#include "../kernel/cpu/feature_names.c" #include "../kernel/cpu/capflags.c"
#if NCAPFLAGS > 8 #if NCAPFLAGS > 8
# error "Need to adjust the boot code handling of CPUID strings" # error "Need to adjust the boot code handling of CPUID strings"

View file

@ -179,9 +179,10 @@ struct sigframe
u32 pretcode; u32 pretcode;
int sig; int sig;
struct sigcontext_ia32 sc; struct sigcontext_ia32 sc;
struct _fpstate_ia32 fpstate; struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */
unsigned int extramask[_COMPAT_NSIG_WORDS-1]; unsigned int extramask[_COMPAT_NSIG_WORDS-1];
char retcode[8]; char retcode[8];
/* fp state follows here */
}; };
struct rt_sigframe struct rt_sigframe
@ -192,8 +193,8 @@ struct rt_sigframe
u32 puc; u32 puc;
compat_siginfo_t info; compat_siginfo_t info;
struct ucontext_ia32 uc; struct ucontext_ia32 uc;
struct _fpstate_ia32 fpstate;
char retcode[8]; char retcode[8];
/* fp state follows here */
}; };
#define COPY(x) { \ #define COPY(x) { \
@ -215,7 +216,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
unsigned int *peax) unsigned int *peax)
{ {
unsigned int tmpflags, gs, oldgs, err = 0; unsigned int tmpflags, gs, oldgs, err = 0;
struct _fpstate_ia32 __user *buf; void __user *buf;
u32 tmp; u32 tmp;
/* Always make any pending restarted system calls return -EINTR */ /* Always make any pending restarted system calls return -EINTR */
@ -259,26 +260,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
err |= __get_user(tmp, &sc->fpstate); err |= __get_user(tmp, &sc->fpstate);
buf = compat_ptr(tmp); buf = compat_ptr(tmp);
if (buf) { err |= restore_i387_xstate_ia32(buf);
if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
goto badframe;
err |= restore_i387_ia32(buf);
} else {
struct task_struct *me = current;
if (used_math()) {
clear_fpu(me);
clear_used_math();
}
}
err |= __get_user(tmp, &sc->ax); err |= __get_user(tmp, &sc->ax);
*peax = tmp; *peax = tmp;
return err; return err;
badframe:
return 1;
} }
asmlinkage long sys32_sigreturn(struct pt_regs *regs) asmlinkage long sys32_sigreturn(struct pt_regs *regs)
@ -350,7 +337,7 @@ badframe:
*/ */
static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
struct _fpstate_ia32 __user *fpstate, void __user *fpstate,
struct pt_regs *regs, unsigned int mask) struct pt_regs *regs, unsigned int mask)
{ {
int tmp, err = 0; int tmp, err = 0;
@ -381,7 +368,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
err |= __put_user((u32)regs->flags, &sc->flags); err |= __put_user((u32)regs->flags, &sc->flags);
err |= __put_user((u32)regs->sp, &sc->sp_at_signal); err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
tmp = save_i387_ia32(fpstate); tmp = save_i387_xstate_ia32(fpstate);
if (tmp < 0) if (tmp < 0)
err = -EFAULT; err = -EFAULT;
else { else {
@ -402,7 +389,8 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
* Determine which stack to use.. * Determine which stack to use..
*/ */
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
size_t frame_size) size_t frame_size,
void **fpstate)
{ {
unsigned long sp; unsigned long sp;
@ -421,6 +409,11 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
ka->sa.sa_restorer) ka->sa.sa_restorer)
sp = (unsigned long) ka->sa.sa_restorer; sp = (unsigned long) ka->sa.sa_restorer;
if (used_math()) {
sp = sp - sig_xstate_ia32_size;
*fpstate = (struct _fpstate_ia32 *) sp;
}
sp -= frame_size; sp -= frame_size;
/* Align the stack pointer according to the i386 ABI, /* Align the stack pointer according to the i386 ABI,
* i.e. so that on function entry ((sp + 4) & 15) == 0. */ * i.e. so that on function entry ((sp + 4) & 15) == 0. */
@ -434,6 +427,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
struct sigframe __user *frame; struct sigframe __user *frame;
void __user *restorer; void __user *restorer;
int err = 0; int err = 0;
void __user *fpstate = NULL;
/* copy_to_user optimizes that into a single 8 byte store */ /* copy_to_user optimizes that into a single 8 byte store */
static const struct { static const struct {
@ -448,7 +442,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
0, 0,
}; };
frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
@ -457,8 +451,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
set->sig[0]);
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
@ -522,6 +515,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
struct rt_sigframe __user *frame; struct rt_sigframe __user *frame;
void __user *restorer; void __user *restorer;
int err = 0; int err = 0;
void __user *fpstate = NULL;
/* __copy_to_user optimizes that into a single 8 byte store */ /* __copy_to_user optimizes that into a single 8 byte store */
static const struct { static const struct {
@ -537,7 +531,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
0, 0,
}; };
frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
@ -550,13 +544,16 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv; goto give_sigsegv;
/* Create the ucontext. */ /* Create the ucontext. */
if (cpu_has_xsave)
err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
else
err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->sp), err |= __put_user(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags); &frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]); regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err) if (err)

View file

@ -38,7 +38,7 @@ obj-y += tsc.o io_delay.o rtc.o
obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
obj-y += process.o obj-y += process.o
obj-y += i387.o obj-y += i387.o xsave.o
obj-y += ptrace.o obj-y += ptrace.o
obj-y += ds.o obj-y += ds.o
obj-$(CONFIG_X86_32) += tls.o obj-$(CONFIG_X86_32) += tls.o
@ -69,6 +69,7 @@ obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o
obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o
obj-$(CONFIG_X86_NUMAQ) += numaq_32.o obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
obj-$(CONFIG_X86_ES7000) += es7000_32.o
obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o
obj-y += vsmp_64.o obj-y += vsmp_64.o
obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KPROBES) += kprobes.o
@ -104,6 +105,8 @@ obj-$(CONFIG_OLPC) += olpc.o
ifeq ($(CONFIG_X86_64),y) ifeq ($(CONFIG_X86_64),y)
obj-y += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o obj-y += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o
obj-y += bios_uv.o obj-y += bios_uv.o
obj-y += genx2apic_cluster.o
obj-y += genx2apic_phys.o
obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o
obj-$(CONFIG_AUDIT) += audit_64.o obj-$(CONFIG_AUDIT) += audit_64.o

View file

@ -775,7 +775,7 @@ static void __init acpi_register_lapic_address(unsigned long address)
set_fixmap_nocache(FIX_APIC_BASE, address); set_fixmap_nocache(FIX_APIC_BASE, address);
if (boot_cpu_physical_apicid == -1U) { if (boot_cpu_physical_apicid == -1U) {
boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); boot_cpu_physical_apicid = read_apic_id();
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
apic_version[boot_cpu_physical_apicid] = apic_version[boot_cpu_physical_apicid] =
GET_APIC_VERSION(apic_read(APIC_LVR)); GET_APIC_VERSION(apic_read(APIC_LVR));
@ -1351,7 +1351,9 @@ static void __init acpi_process_madt(void)
acpi_ioapic = 1; acpi_ioapic = 1;
smp_found_config = 1; smp_found_config = 1;
#ifdef CONFIG_X86_32
setup_apic_routing(); setup_apic_routing();
#endif
} }
} }
if (error == -EINVAL) { if (error == -EINVAL) {

View file

@ -145,35 +145,25 @@ static const unsigned char *const p6_nops[ASM_NOP_MAX+1] = {
extern char __vsyscall_0; extern char __vsyscall_0;
const unsigned char *const *find_nop_table(void) const unsigned char *const *find_nop_table(void)
{ {
return boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
boot_cpu_data.x86 < 6 ? k8_nops : p6_nops; boot_cpu_has(X86_FEATURE_NOPL))
return p6_nops;
else
return k8_nops;
} }
#else /* CONFIG_X86_64 */ #else /* CONFIG_X86_64 */
static const struct nop {
int cpuid;
const unsigned char *const *noptable;
} noptypes[] = {
{ X86_FEATURE_K8, k8_nops },
{ X86_FEATURE_K7, k7_nops },
{ X86_FEATURE_P4, p6_nops },
{ X86_FEATURE_P3, p6_nops },
{ -1, NULL }
};
const unsigned char *const *find_nop_table(void) const unsigned char *const *find_nop_table(void)
{ {
const unsigned char *const *noptable = intel_nops; if (boot_cpu_has(X86_FEATURE_K8))
int i; return k8_nops;
else if (boot_cpu_has(X86_FEATURE_K7))
for (i = 0; noptypes[i].cpuid >= 0; i++) { return k7_nops;
if (boot_cpu_has(noptypes[i].cpuid)) { else if (boot_cpu_has(X86_FEATURE_NOPL))
noptable = noptypes[i].noptable; return p6_nops;
break; else
} return intel_nops;
}
return noptable;
} }
#endif /* CONFIG_X86_64 */ #endif /* CONFIG_X86_64 */

View file

@ -145,13 +145,18 @@ static int modern_apic(void)
return lapic_get_version() >= 0x14; return lapic_get_version() >= 0x14;
} }
void apic_wait_icr_idle(void) /*
* Paravirt kernels also might be using these below ops. So we still
* use generic apic_read()/apic_write(), which might be pointing to different
* ops in PARAVIRT case.
*/
void xapic_wait_icr_idle(void)
{ {
while (apic_read(APIC_ICR) & APIC_ICR_BUSY) while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
cpu_relax(); cpu_relax();
} }
u32 safe_apic_wait_icr_idle(void) u32 safe_xapic_wait_icr_idle(void)
{ {
u32 send_status; u32 send_status;
int timeout; int timeout;
@ -167,16 +172,48 @@ u32 safe_apic_wait_icr_idle(void)
return send_status; return send_status;
} }
void xapic_icr_write(u32 low, u32 id)
{
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id));
apic_write(APIC_ICR, low);
}
u64 xapic_icr_read(void)
{
u32 icr1, icr2;
icr2 = apic_read(APIC_ICR2);
icr1 = apic_read(APIC_ICR);
return icr1 | ((u64)icr2 << 32);
}
static struct apic_ops xapic_ops = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
.icr_read = xapic_icr_read,
.icr_write = xapic_icr_write,
.wait_icr_idle = xapic_wait_icr_idle,
.safe_wait_icr_idle = safe_xapic_wait_icr_idle,
};
struct apic_ops __read_mostly *apic_ops = &xapic_ops;
EXPORT_SYMBOL_GPL(apic_ops);
/** /**
* enable_NMI_through_LVT0 - enable NMI through local vector table 0 * enable_NMI_through_LVT0 - enable NMI through local vector table 0
*/ */
void __cpuinit enable_NMI_through_LVT0(void) void __cpuinit enable_NMI_through_LVT0(void)
{ {
unsigned int v = APIC_DM_NMI; unsigned int v;
/* Level triggered for 82489DX */ /* unmask and set to NMI */
v = APIC_DM_NMI;
/* Level triggered for 82489DX (32bit mode) */
if (!lapic_is_integrated()) if (!lapic_is_integrated())
v |= APIC_LVT_LEVEL_TRIGGER; v |= APIC_LVT_LEVEL_TRIGGER;
apic_write(APIC_LVT0, v); apic_write(APIC_LVT0, v);
} }
@ -193,9 +230,13 @@ int get_physical_broadcast(void)
*/ */
int lapic_get_maxlvt(void) int lapic_get_maxlvt(void)
{ {
unsigned int v = apic_read(APIC_LVR); unsigned int v;
/* 82489DXs do not report # of LVT entries. */ v = apic_read(APIC_LVR);
/*
* - we always have APIC integrated on 64bit mode
* - 82489DXs do not report # of LVT entries
*/
return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2; return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
} }
@ -1205,7 +1246,7 @@ void __init init_apic_mappings(void)
* default configuration (or the MP table is broken). * default configuration (or the MP table is broken).
*/ */
if (boot_cpu_physical_apicid == -1U) if (boot_cpu_physical_apicid == -1U)
boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); boot_cpu_physical_apicid = read_apic_id();
} }
@ -1242,7 +1283,7 @@ int __init APIC_init_uniprocessor(void)
* might be zero if read from MP tables. Get it from LAPIC. * might be zero if read from MP tables. Get it from LAPIC.
*/ */
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_CRASH_DUMP
boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); boot_cpu_physical_apicid = read_apic_id();
#endif #endif
physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
@ -1321,54 +1362,6 @@ void smp_error_interrupt(struct pt_regs *regs)
irq_exit(); irq_exit();
} }
#ifdef CONFIG_SMP
void __init smp_intr_init(void)
{
/*
* IRQ0 must be given a fixed assignment and initialized,
* because it's used before the IO-APIC is set up.
*/
set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
/*
* The reschedule interrupt is a CPU-to-CPU reschedule-helper
* IPI, driven by wakeup.
*/
alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
/* IPI for invalidation */
alloc_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
/* IPI for generic function call */
alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
/* IPI for single call function */
set_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
call_function_single_interrupt);
}
#endif
/*
* Initialize APIC interrupts
*/
void __init apic_intr_init(void)
{
#ifdef CONFIG_SMP
smp_intr_init();
#endif
/* self generated IPI for local APIC timer */
alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
/* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
/* thermal monitor LVT interrupt */
#ifdef CONFIG_X86_MCE_P4THERMAL
alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
#endif
}
/** /**
* connect_bsp_APIC - attach the APIC to the interrupt system * connect_bsp_APIC - attach the APIC to the interrupt system
*/ */

View file

@ -27,6 +27,7 @@
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/acpi_pmtmr.h> #include <linux/acpi_pmtmr.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/dmar.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/smp.h> #include <asm/smp.h>
@ -39,6 +40,7 @@
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/timex.h> #include <asm/timex.h>
#include <asm/apic.h> #include <asm/apic.h>
#include <asm/i8259.h>
#include <mach_ipi.h> #include <mach_ipi.h>
#include <mach_apic.h> #include <mach_apic.h>
@ -46,6 +48,11 @@
static int disable_apic_timer __cpuinitdata; static int disable_apic_timer __cpuinitdata;
static int apic_calibrate_pmtmr __initdata; static int apic_calibrate_pmtmr __initdata;
int disable_apic; int disable_apic;
int disable_x2apic;
int x2apic;
/* x2apic enabled before OS handover */
int x2apic_preenabled;
/* Local APIC timer works in C2 */ /* Local APIC timer works in C2 */
int local_apic_timer_c2_ok; int local_apic_timer_c2_ok;
@ -118,13 +125,13 @@ static int modern_apic(void)
return lapic_get_version() >= 0x14; return lapic_get_version() >= 0x14;
} }
void apic_wait_icr_idle(void) void xapic_wait_icr_idle(void)
{ {
while (apic_read(APIC_ICR) & APIC_ICR_BUSY) while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
cpu_relax(); cpu_relax();
} }
u32 safe_apic_wait_icr_idle(void) u32 safe_xapic_wait_icr_idle(void)
{ {
u32 send_status; u32 send_status;
int timeout; int timeout;
@ -140,6 +147,69 @@ u32 safe_apic_wait_icr_idle(void)
return send_status; return send_status;
} }
void xapic_icr_write(u32 low, u32 id)
{
apic_write(APIC_ICR2, id << 24);
apic_write(APIC_ICR, low);
}
u64 xapic_icr_read(void)
{
u32 icr1, icr2;
icr2 = apic_read(APIC_ICR2);
icr1 = apic_read(APIC_ICR);
return (icr1 | ((u64)icr2 << 32));
}
static struct apic_ops xapic_ops = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
.icr_read = xapic_icr_read,
.icr_write = xapic_icr_write,
.wait_icr_idle = xapic_wait_icr_idle,
.safe_wait_icr_idle = safe_xapic_wait_icr_idle,
};
struct apic_ops __read_mostly *apic_ops = &xapic_ops;
EXPORT_SYMBOL_GPL(apic_ops);
static void x2apic_wait_icr_idle(void)
{
/* no need to wait for icr idle in x2apic */
return;
}
static u32 safe_x2apic_wait_icr_idle(void)
{
/* no need to wait for icr idle in x2apic */
return 0;
}
void x2apic_icr_write(u32 low, u32 id)
{
wrmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), ((__u64) id) << 32 | low);
}
u64 x2apic_icr_read(void)
{
unsigned long val;
rdmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), val);
return val;
}
static struct apic_ops x2apic_ops = {
.read = native_apic_msr_read,
.write = native_apic_msr_write,
.icr_read = x2apic_icr_read,
.icr_write = x2apic_icr_write,
.wait_icr_idle = x2apic_wait_icr_idle,
.safe_wait_icr_idle = safe_x2apic_wait_icr_idle,
};
/** /**
* enable_NMI_through_LVT0 - enable NMI through local vector table 0 * enable_NMI_through_LVT0 - enable NMI through local vector table 0
*/ */
@ -149,6 +219,11 @@ void __cpuinit enable_NMI_through_LVT0(void)
/* unmask and set to NMI */ /* unmask and set to NMI */
v = APIC_DM_NMI; v = APIC_DM_NMI;
/* Level triggered for 82489DX (32bit mode) */
if (!lapic_is_integrated())
v |= APIC_LVT_LEVEL_TRIGGER;
apic_write(APIC_LVT0, v); apic_write(APIC_LVT0, v);
} }
@ -157,11 +232,14 @@ void __cpuinit enable_NMI_through_LVT0(void)
*/ */
int lapic_get_maxlvt(void) int lapic_get_maxlvt(void)
{ {
unsigned int v, maxlvt; unsigned int v;
v = apic_read(APIC_LVR); v = apic_read(APIC_LVR);
maxlvt = GET_APIC_MAXLVT(v); /*
return maxlvt; * - we always have APIC integrated on 64bit mode
* - 82489DXs do not report # of LVT entries
*/
return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
} }
/* /*
@ -629,10 +707,10 @@ int __init verify_local_APIC(void)
/* /*
* The ID register is read/write in a real APIC. * The ID register is read/write in a real APIC.
*/ */
reg0 = read_apic_id(); reg0 = apic_read(APIC_ID);
apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0);
apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);
reg1 = read_apic_id(); reg1 = apic_read(APIC_ID);
apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1); apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1);
apic_write(APIC_ID, reg0); apic_write(APIC_ID, reg0);
if (reg1 != (reg0 ^ APIC_ID_MASK)) if (reg1 != (reg0 ^ APIC_ID_MASK))
@ -833,6 +911,125 @@ void __cpuinit end_local_APIC_setup(void)
apic_pm_activate(); apic_pm_activate();
} }
void check_x2apic(void)
{
int msr, msr2;
rdmsr(MSR_IA32_APICBASE, msr, msr2);
if (msr & X2APIC_ENABLE) {
printk("x2apic enabled by BIOS, switching to x2apic ops\n");
x2apic_preenabled = x2apic = 1;
apic_ops = &x2apic_ops;
}
}
void enable_x2apic(void)
{
int msr, msr2;
rdmsr(MSR_IA32_APICBASE, msr, msr2);
if (!(msr & X2APIC_ENABLE)) {
printk("Enabling x2apic\n");
wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
}
}
void enable_IR_x2apic(void)
{
#ifdef CONFIG_INTR_REMAP
int ret;
unsigned long flags;
if (!cpu_has_x2apic)
return;
if (!x2apic_preenabled && disable_x2apic) {
printk(KERN_INFO
"Skipped enabling x2apic and Interrupt-remapping "
"because of nox2apic\n");
return;
}
if (x2apic_preenabled && disable_x2apic)
panic("Bios already enabled x2apic, can't enforce nox2apic");
if (!x2apic_preenabled && skip_ioapic_setup) {
printk(KERN_INFO
"Skipped enabling x2apic and Interrupt-remapping "
"because of skipping io-apic setup\n");
return;
}
ret = dmar_table_init();
if (ret) {
printk(KERN_INFO
"dmar_table_init() failed with %d:\n", ret);
if (x2apic_preenabled)
panic("x2apic enabled by bios. But IR enabling failed");
else
printk(KERN_INFO
"Not enabling x2apic,Intr-remapping\n");
return;
}
local_irq_save(flags);
mask_8259A();
save_mask_IO_APIC_setup();
ret = enable_intr_remapping(1);
if (ret && x2apic_preenabled) {
local_irq_restore(flags);
panic("x2apic enabled by bios. But IR enabling failed");
}
if (ret)
goto end;
if (!x2apic) {
x2apic = 1;
apic_ops = &x2apic_ops;
enable_x2apic();
}
end:
if (ret)
/*
* IR enabling failed
*/
restore_IO_APIC_setup();
else
reinit_intr_remapped_IO_APIC(x2apic_preenabled);
unmask_8259A();
local_irq_restore(flags);
if (!ret) {
if (!x2apic_preenabled)
printk(KERN_INFO
"Enabled x2apic and interrupt-remapping\n");
else
printk(KERN_INFO
"Enabled Interrupt-remapping\n");
} else
printk(KERN_ERR
"Failed to enable Interrupt-remapping and x2apic\n");
#else
if (!cpu_has_x2apic)
return;
if (x2apic_preenabled)
panic("x2apic enabled prior OS handover,"
" enable CONFIG_INTR_REMAP");
printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping "
" and x2apic\n");
#endif
return;
}
/* /*
* Detect and enable local APICs on non-SMP boards. * Detect and enable local APICs on non-SMP boards.
* Original code written by Keir Fraser. * Original code written by Keir Fraser.
@ -872,7 +1069,7 @@ void __init early_init_lapic_mapping(void)
* Fetch the APIC ID of the BSP in case we have a * Fetch the APIC ID of the BSP in case we have a
* default configuration (or the MP table is broken). * default configuration (or the MP table is broken).
*/ */
boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); boot_cpu_physical_apicid = read_apic_id();
} }
/** /**
@ -880,6 +1077,11 @@ void __init early_init_lapic_mapping(void)
*/ */
void __init init_apic_mappings(void) void __init init_apic_mappings(void)
{ {
if (x2apic) {
boot_cpu_physical_apicid = read_apic_id();
return;
}
/* /*
* If no local APIC can be found then set up a fake all * If no local APIC can be found then set up a fake all
* zeroes page to simulate the local APIC and another * zeroes page to simulate the local APIC and another
@ -899,7 +1101,7 @@ void __init init_apic_mappings(void)
* Fetch the APIC ID of the BSP in case we have a * Fetch the APIC ID of the BSP in case we have a
* default configuration (or the MP table is broken). * default configuration (or the MP table is broken).
*/ */
boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); boot_cpu_physical_apicid = read_apic_id();
} }
/* /*
@ -918,6 +1120,9 @@ int __init APIC_init_uniprocessor(void)
return -1; return -1;
} }
enable_IR_x2apic();
setup_apic_routing();
verify_local_APIC(); verify_local_APIC();
connect_bsp_APIC(); connect_bsp_APIC();
@ -1093,6 +1298,11 @@ void __cpuinit generic_processor_info(int apicid, int version)
cpu_set(cpu, cpu_present_map); cpu_set(cpu, cpu_present_map);
} }
int hard_smp_processor_id(void)
{
return read_apic_id();
}
/* /*
* Power management * Power management
*/ */
@ -1129,7 +1339,7 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
maxlvt = lapic_get_maxlvt(); maxlvt = lapic_get_maxlvt();
apic_pm_state.apic_id = read_apic_id(); apic_pm_state.apic_id = apic_read(APIC_ID);
apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
apic_pm_state.apic_ldr = apic_read(APIC_LDR); apic_pm_state.apic_ldr = apic_read(APIC_LDR);
apic_pm_state.apic_dfr = apic_read(APIC_DFR); apic_pm_state.apic_dfr = apic_read(APIC_DFR);
@ -1164,10 +1374,14 @@ static int lapic_resume(struct sys_device *dev)
maxlvt = lapic_get_maxlvt(); maxlvt = lapic_get_maxlvt();
local_irq_save(flags); local_irq_save(flags);
if (!x2apic) {
rdmsr(MSR_IA32_APICBASE, l, h); rdmsr(MSR_IA32_APICBASE, l, h);
l &= ~MSR_IA32_APICBASE_BASE; l &= ~MSR_IA32_APICBASE_BASE;
l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
wrmsr(MSR_IA32_APICBASE, l, h); wrmsr(MSR_IA32_APICBASE, l, h);
} else
enable_x2apic();
apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
apic_write(APIC_ID, apic_pm_state.apic_id); apic_write(APIC_ID, apic_pm_state.apic_id);
apic_write(APIC_DFR, apic_pm_state.apic_dfr); apic_write(APIC_DFR, apic_pm_state.apic_dfr);
@ -1307,6 +1521,15 @@ __cpuinit int apic_is_clustered_box(void)
return (clusters > 2); return (clusters > 2);
} }
static __init int setup_nox2apic(char *str)
{
disable_x2apic = 1;
clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC);
return 0;
}
early_param("nox2apic", setup_nox2apic);
/* /*
* APIC command line parameters * APIC command line parameters
*/ */

View file

@ -22,7 +22,7 @@
#define __NO_STUBS 1 #define __NO_STUBS 1
#undef __SYSCALL #undef __SYSCALL
#undef _ASM_X86_64_UNISTD_H_ #undef ASM_X86__UNISTD_64_H
#define __SYSCALL(nr, sym) [nr] = 1, #define __SYSCALL(nr, sym) [nr] = 1,
static char syscalls[] = { static char syscalls[] = {
#include <asm/unistd.h> #include <asm/unistd.h>

View file

@ -3,22 +3,32 @@
# #
obj-y := intel_cacheinfo.o addon_cpuid_features.o obj-y := intel_cacheinfo.o addon_cpuid_features.o
obj-y += proc.o feature_names.o obj-y += proc.o capflags.o powerflags.o
obj-$(CONFIG_X86_32) += common.o bugs.o obj-$(CONFIG_X86_32) += common.o bugs.o cmpxchg.o
obj-$(CONFIG_X86_64) += common_64.o bugs_64.o obj-$(CONFIG_X86_64) += common_64.o bugs_64.o
obj-$(CONFIG_X86_32) += amd.o
obj-$(CONFIG_X86_64) += amd_64.o obj-$(CONFIG_CPU_SUP_INTEL_32) += intel.o
obj-$(CONFIG_X86_32) += cyrix.o obj-$(CONFIG_CPU_SUP_INTEL_64) += intel_64.o
obj-$(CONFIG_X86_32) += centaur.o obj-$(CONFIG_CPU_SUP_AMD_32) += amd.o
obj-$(CONFIG_X86_64) += centaur_64.o obj-$(CONFIG_CPU_SUP_AMD_64) += amd_64.o
obj-$(CONFIG_X86_32) += transmeta.o obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
obj-$(CONFIG_X86_32) += intel.o obj-$(CONFIG_CPU_SUP_CENTAUR_32) += centaur.o
obj-$(CONFIG_X86_64) += intel_64.o obj-$(CONFIG_CPU_SUP_CENTAUR_64) += centaur_64.o
obj-$(CONFIG_X86_32) += umc.o obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o
obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o
obj-$(CONFIG_X86_MCE) += mcheck/ obj-$(CONFIG_X86_MCE) += mcheck/
obj-$(CONFIG_MTRR) += mtrr/ obj-$(CONFIG_MTRR) += mtrr/
obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o
quiet_cmd_mkcapflags = MKCAP $@
cmd_mkcapflags = $(PERL) $(srctree)/$(src)/mkcapflags.pl $< $@
cpufeature = $(src)/../../../../include/asm-x86/cpufeature.h
targets += capflags.c
$(obj)/capflags.c: $(cpufeature) $(src)/mkcapflags.pl FORCE
$(call if_changed,mkcapflags)

View file

@ -7,6 +7,8 @@
#include <asm/pat.h> #include <asm/pat.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <mach_apic.h>
struct cpuid_bit { struct cpuid_bit {
u16 feature; u16 feature;
u8 reg; u8 reg;
@ -48,6 +50,92 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
} }
} }
/* leaf 0xb SMT level */
#define SMT_LEVEL 0
/* leaf 0xb sub-leaf types */
#define INVALID_TYPE 0
#define SMT_TYPE 1
#define CORE_TYPE 2
#define LEAFB_SUBTYPE(ecx) (((ecx) >> 8) & 0xff)
#define BITS_SHIFT_NEXT_LEVEL(eax) ((eax) & 0x1f)
#define LEVEL_MAX_SIBLINGS(ebx) ((ebx) & 0xffff)
/*
* Check for extended topology enumeration cpuid leaf 0xb and if it
* exists, use it for populating initial_apicid and cpu topology
* detection.
*/
void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_SMP
unsigned int eax, ebx, ecx, edx, sub_index;
unsigned int ht_mask_width, core_plus_mask_width;
unsigned int core_select_mask, core_level_siblings;
if (c->cpuid_level < 0xb)
return;
cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
/*
* check if the cpuid leaf 0xb is actually implemented.
*/
if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
return;
set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
/*
* initial apic id, which also represents 32-bit extended x2apic id.
*/
c->initial_apicid = edx;
/*
* Populate HT related information from sub-leaf level 0.
*/
core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
sub_index = 1;
do {
cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
/*
* Check for the Core type in the implemented sub leaves.
*/
if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
break;
}
sub_index++;
} while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
#ifdef CONFIG_X86_32
c->cpu_core_id = phys_pkg_id(c->initial_apicid, ht_mask_width)
& core_select_mask;
c->phys_proc_id = phys_pkg_id(c->initial_apicid, core_plus_mask_width);
#else
c->cpu_core_id = phys_pkg_id(ht_mask_width) & core_select_mask;
c->phys_proc_id = phys_pkg_id(core_plus_mask_width);
#endif
c->x86_max_cores = (core_level_siblings / smp_num_siblings);
printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
c->phys_proc_id);
if (c->x86_max_cores > 1)
printk(KERN_INFO "CPU: Processor Core ID: %d\n",
c->cpu_core_id);
return;
#endif
}
#ifdef CONFIG_X86_PAT #ifdef CONFIG_X86_PAT
void __cpuinit validate_pat_support(struct cpuinfo_x86 *c) void __cpuinit validate_pat_support(struct cpuinfo_x86 *c)
{ {

View file

@ -31,6 +31,11 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
if (c->x86_power & (1<<8)) if (c->x86_power & (1<<8))
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
} }
/* Set MTRR capability flag if appropriate */
if (c->x86_model == 13 || c->x86_model == 9 ||
(c->x86_model == 8 && c->x86_mask >= 8))
set_cpu_cap(c, X86_FEATURE_K6_MTRR);
} }
static void __cpuinit init_amd(struct cpuinfo_x86 *c) static void __cpuinit init_amd(struct cpuinfo_x86 *c)
@ -166,10 +171,6 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
mbytes); mbytes);
} }
/* Set MTRR capability flag if appropriate */
if (c->x86_model == 13 || c->x86_model == 9 ||
(c->x86_model == 8 && c->x86_mask >= 8))
set_cpu_cap(c, X86_FEATURE_K6_MTRR);
break; break;
} }
@ -297,6 +298,7 @@ static struct cpu_dev amd_cpu_dev __cpuinitdata = {
.c_early_init = early_init_amd, .c_early_init = early_init_amd,
.c_init = init_amd, .c_init = init_amd,
.c_size_cache = amd_size_cache, .c_size_cache = amd_size_cache,
.c_x86_vendor = X86_VENDOR_AMD,
}; };
cpu_vendor_dev_register(X86_VENDOR_AMD, &amd_cpu_dev); cpu_dev_register(amd_cpu_dev);

View file

@ -218,7 +218,7 @@ static struct cpu_dev amd_cpu_dev __cpuinitdata = {
.c_ident = { "AuthenticAMD" }, .c_ident = { "AuthenticAMD" },
.c_early_init = early_init_amd, .c_early_init = early_init_amd,
.c_init = init_amd, .c_init = init_amd,
.c_x86_vendor = X86_VENDOR_AMD,
}; };
cpu_vendor_dev_register(X86_VENDOR_AMD, &amd_cpu_dev); cpu_dev_register(amd_cpu_dev);

View file

@ -314,6 +314,16 @@ enum {
EAMD3D = 1<<20, EAMD3D = 1<<20,
}; };
static void __cpuinit early_init_centaur(struct cpuinfo_x86 *c)
{
switch (c->x86) {
case 5:
/* Emulate MTRRs using Centaur's MCR. */
set_cpu_cap(c, X86_FEATURE_CENTAUR_MCR);
break;
}
}
static void __cpuinit init_centaur(struct cpuinfo_x86 *c) static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
{ {
@ -462,8 +472,10 @@ centaur_size_cache(struct cpuinfo_x86 *c, unsigned int size)
static struct cpu_dev centaur_cpu_dev __cpuinitdata = { static struct cpu_dev centaur_cpu_dev __cpuinitdata = {
.c_vendor = "Centaur", .c_vendor = "Centaur",
.c_ident = { "CentaurHauls" }, .c_ident = { "CentaurHauls" },
.c_early_init = early_init_centaur,
.c_init = init_centaur, .c_init = init_centaur,
.c_size_cache = centaur_size_cache, .c_size_cache = centaur_size_cache,
.c_x86_vendor = X86_VENDOR_CENTAUR,
}; };
cpu_vendor_dev_register(X86_VENDOR_CENTAUR, &centaur_cpu_dev); cpu_dev_register(centaur_cpu_dev);

View file

@ -29,7 +29,8 @@ static struct cpu_dev centaur_cpu_dev __cpuinitdata = {
.c_ident = { "CentaurHauls" }, .c_ident = { "CentaurHauls" },
.c_early_init = early_init_centaur, .c_early_init = early_init_centaur,
.c_init = init_centaur, .c_init = init_centaur,
.c_x86_vendor = X86_VENDOR_CENTAUR,
}; };
cpu_vendor_dev_register(X86_VENDOR_CENTAUR, &centaur_cpu_dev); cpu_dev_register(centaur_cpu_dev);

View file

@ -0,0 +1,72 @@
/*
* cmpxchg*() fallbacks for CPU not supporting these instructions
*/
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/module.h>
#ifndef CONFIG_X86_CMPXCHG
unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
{
u8 prev;
unsigned long flags;
/* Poor man's cmpxchg for 386. Unsuitable for SMP */
local_irq_save(flags);
prev = *(u8 *)ptr;
if (prev == old)
*(u8 *)ptr = new;
local_irq_restore(flags);
return prev;
}
EXPORT_SYMBOL(cmpxchg_386_u8);
unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new)
{
u16 prev;
unsigned long flags;
/* Poor man's cmpxchg for 386. Unsuitable for SMP */
local_irq_save(flags);
prev = *(u16 *)ptr;
if (prev == old)
*(u16 *)ptr = new;
local_irq_restore(flags);
return prev;
}
EXPORT_SYMBOL(cmpxchg_386_u16);
unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
{
u32 prev;
unsigned long flags;
/* Poor man's cmpxchg for 386. Unsuitable for SMP */
local_irq_save(flags);
prev = *(u32 *)ptr;
if (prev == old)
*(u32 *)ptr = new;
local_irq_restore(flags);
return prev;
}
EXPORT_SYMBOL(cmpxchg_386_u32);
#endif
#ifndef CONFIG_X86_CMPXCHG64
unsigned long long cmpxchg_486_u64(volatile void *ptr, u64 old, u64 new)
{
u64 prev;
unsigned long flags;
/* Poor man's cmpxchg8b for 386 and 486. Unsuitable for SMP */
local_irq_save(flags);
prev = *(u64 *)ptr;
if (prev == old)
*(u64 *)ptr = new;
local_irq_restore(flags);
return prev;
}
EXPORT_SYMBOL(cmpxchg_486_u64);
#endif

View file

@ -13,6 +13,7 @@
#include <asm/mtrr.h> #include <asm/mtrr.h>
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/pat.h> #include <asm/pat.h>
#include <asm/asm.h>
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/apic.h> #include <asm/apic.h>
@ -21,7 +22,9 @@
#include "cpu.h" #include "cpu.h"
DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { static struct cpu_dev *this_cpu __cpuinitdata;
DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
[GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } }, [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } },
[GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } }, [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } },
[GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } }, [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } },
@ -57,32 +60,9 @@ DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
} }; } };
EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
static int cachesize_override __cpuinitdata = -1; static int cachesize_override __cpuinitdata = -1;
static int disable_x86_serial_nr __cpuinitdata = 1; static int disable_x86_serial_nr __cpuinitdata = 1;
struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
static void __cpuinit default_init(struct cpuinfo_x86 *c)
{
/* Not much we can do here... */
/* Check if at least it has cpuid */
if (c->cpuid_level == -1) {
/* No cpuid. It must be an ancient CPU */
if (c->x86 == 4)
strcpy(c->x86_model_id, "486");
else if (c->x86 == 3)
strcpy(c->x86_model_id, "386");
}
}
static struct cpu_dev __cpuinitdata default_cpu = {
.c_init = default_init,
.c_vendor = "Unknown",
};
static struct cpu_dev *this_cpu __cpuinitdata = &default_cpu;
static int __init cachesize_setup(char *str) static int __init cachesize_setup(char *str)
{ {
get_option(&str, &cachesize_override); get_option(&str, &cachesize_override);
@ -90,72 +70,6 @@ static int __init cachesize_setup(char *str)
} }
__setup("cachesize=", cachesize_setup); __setup("cachesize=", cachesize_setup);
int __cpuinit get_model_name(struct cpuinfo_x86 *c)
{
unsigned int *v;
char *p, *q;
if (cpuid_eax(0x80000000) < 0x80000004)
return 0;
v = (unsigned int *) c->x86_model_id;
cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
c->x86_model_id[48] = 0;
/* Intel chips right-justify this string for some dumb reason;
undo that brain damage */
p = q = &c->x86_model_id[0];
while (*p == ' ')
p++;
if (p != q) {
while (*p)
*q++ = *p++;
while (q <= &c->x86_model_id[48])
*q++ = '\0'; /* Zero-pad the rest */
}
return 1;
}
void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
{
unsigned int n, dummy, ecx, edx, l2size;
n = cpuid_eax(0x80000000);
if (n >= 0x80000005) {
cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
c->x86_cache_size = (ecx>>24)+(edx>>24);
}
if (n < 0x80000006) /* Some chips just has a large L1. */
return;
ecx = cpuid_ecx(0x80000006);
l2size = ecx >> 16;
/* do processor-specific cache resizing */
if (this_cpu->c_size_cache)
l2size = this_cpu->c_size_cache(c, l2size);
/* Allow user to override all this if necessary. */
if (cachesize_override != -1)
l2size = cachesize_override;
if (l2size == 0)
return; /* Again, no L2 cache is possible */
c->x86_cache_size = l2size;
printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
l2size, ecx & 0xFF);
}
/* /*
* Naming convention should be: <Name> [(<Codename>)] * Naming convention should be: <Name> [(<Codename>)]
* This table only is used unless init_<vendor>() below doesn't set it; * This table only is used unless init_<vendor>() below doesn't set it;
@ -184,35 +98,6 @@ static char __cpuinit *table_lookup_model(struct cpuinfo_x86 *c)
return NULL; /* Not found */ return NULL; /* Not found */
} }
static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
{
char *v = c->x86_vendor_id;
int i;
static int printed;
for (i = 0; i < X86_VENDOR_NUM; i++) {
if (cpu_devs[i]) {
if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
(cpu_devs[i]->c_ident[1] &&
!strcmp(v, cpu_devs[i]->c_ident[1]))) {
c->x86_vendor = i;
if (!early)
this_cpu = cpu_devs[i];
return;
}
}
}
if (!printed) {
printed++;
printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
printk(KERN_ERR "CPU: Your system may be unstable.\n");
}
c->x86_vendor = X86_VENDOR_UNKNOWN;
this_cpu = &default_cpu;
}
static int __init x86_fxsr_setup(char *s) static int __init x86_fxsr_setup(char *s)
{ {
setup_clear_cpu_cap(X86_FEATURE_FXSR); setup_clear_cpu_cap(X86_FEATURE_FXSR);
@ -221,7 +106,6 @@ static int __init x86_fxsr_setup(char *s)
} }
__setup("nofxsr", x86_fxsr_setup); __setup("nofxsr", x86_fxsr_setup);
static int __init x86_sep_setup(char *s) static int __init x86_sep_setup(char *s)
{ {
setup_clear_cpu_cap(X86_FEATURE_SEP); setup_clear_cpu_cap(X86_FEATURE_SEP);
@ -229,7 +113,6 @@ static int __init x86_sep_setup(char *s)
} }
__setup("nosep", x86_sep_setup); __setup("nosep", x86_sep_setup);
/* Standard macro to see if a specific flag is changeable */ /* Standard macro to see if a specific flag is changeable */
static inline int flag_is_changeable_p(u32 flag) static inline int flag_is_changeable_p(u32 flag)
{ {
@ -251,154 +134,12 @@ static inline int flag_is_changeable_p(u32 flag)
return ((f1^f2) & flag) != 0; return ((f1^f2) & flag) != 0;
} }
/* Probe for the CPUID instruction */ /* Probe for the CPUID instruction */
static int __cpuinit have_cpuid_p(void) static int __cpuinit have_cpuid_p(void)
{ {
return flag_is_changeable_p(X86_EFLAGS_ID); return flag_is_changeable_p(X86_EFLAGS_ID);
} }
void __init cpu_detect(struct cpuinfo_x86 *c)
{
/* Get vendor name */
cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
(unsigned int *)&c->x86_vendor_id[0],
(unsigned int *)&c->x86_vendor_id[8],
(unsigned int *)&c->x86_vendor_id[4]);
c->x86 = 4;
if (c->cpuid_level >= 0x00000001) {
u32 junk, tfms, cap0, misc;
cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
c->x86 = (tfms >> 8) & 15;
c->x86_model = (tfms >> 4) & 15;
if (c->x86 == 0xf)
c->x86 += (tfms >> 20) & 0xff;
if (c->x86 >= 0x6)
c->x86_model += ((tfms >> 16) & 0xF) << 4;
c->x86_mask = tfms & 15;
if (cap0 & (1<<19)) {
c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
}
}
}
static void __cpuinit early_get_cap(struct cpuinfo_x86 *c)
{
u32 tfms, xlvl;
unsigned int ebx;
memset(&c->x86_capability, 0, sizeof c->x86_capability);
if (have_cpuid_p()) {
/* Intel-defined flags: level 0x00000001 */
if (c->cpuid_level >= 0x00000001) {
u32 capability, excap;
cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
c->x86_capability[0] = capability;
c->x86_capability[4] = excap;
}
/* AMD-defined flags: level 0x80000001 */
xlvl = cpuid_eax(0x80000000);
if ((xlvl & 0xffff0000) == 0x80000000) {
if (xlvl >= 0x80000001) {
c->x86_capability[1] = cpuid_edx(0x80000001);
c->x86_capability[6] = cpuid_ecx(0x80000001);
}
}
}
}
/*
* Do minimum CPU detection early.
* Fields really needed: vendor, cpuid_level, family, model, mask,
* cache alignment.
* The others are not touched to avoid unwanted side effects.
*
* WARNING: this function is only called on the BP. Don't add code here
* that is supposed to run on all CPUs.
*/
static void __init early_cpu_detect(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
c->x86_cache_alignment = 32;
c->x86_clflush_size = 32;
if (!have_cpuid_p())
return;
cpu_detect(c);
get_cpu_vendor(c, 1);
if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
cpu_devs[c->x86_vendor]->c_early_init)
cpu_devs[c->x86_vendor]->c_early_init(c);
early_get_cap(c);
}
static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
{
u32 tfms, xlvl;
unsigned int ebx;
if (have_cpuid_p()) {
/* Get vendor name */
cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
(unsigned int *)&c->x86_vendor_id[0],
(unsigned int *)&c->x86_vendor_id[8],
(unsigned int *)&c->x86_vendor_id[4]);
get_cpu_vendor(c, 0);
/* Initialize the standard set of capabilities */
/* Note that the vendor-specific code below might override */
/* Intel-defined flags: level 0x00000001 */
if (c->cpuid_level >= 0x00000001) {
u32 capability, excap;
cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
c->x86_capability[0] = capability;
c->x86_capability[4] = excap;
c->x86 = (tfms >> 8) & 15;
c->x86_model = (tfms >> 4) & 15;
if (c->x86 == 0xf)
c->x86 += (tfms >> 20) & 0xff;
if (c->x86 >= 0x6)
c->x86_model += ((tfms >> 16) & 0xF) << 4;
c->x86_mask = tfms & 15;
c->initial_apicid = (ebx >> 24) & 0xFF;
#ifdef CONFIG_X86_HT
c->apicid = phys_pkg_id(c->initial_apicid, 0);
c->phys_proc_id = c->initial_apicid;
#else
c->apicid = c->initial_apicid;
#endif
if (test_cpu_cap(c, X86_FEATURE_CLFLSH))
c->x86_clflush_size = ((ebx >> 8) & 0xff) * 8;
} else {
/* Have CPUID level 0 only - unheard of */
c->x86 = 4;
}
/* AMD-defined flags: level 0x80000001 */
xlvl = cpuid_eax(0x80000000);
if ((xlvl & 0xffff0000) == 0x80000000) {
if (xlvl >= 0x80000001) {
c->x86_capability[1] = cpuid_edx(0x80000001);
c->x86_capability[6] = cpuid_ecx(0x80000001);
}
if (xlvl >= 0x80000004)
get_model_name(c); /* Default name */
}
init_scattered_cpuid_features(c);
}
}
static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c) static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
{ {
if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr) { if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr) {
@ -422,7 +163,353 @@ static int __init x86_serial_nr_setup(char *s)
} }
__setup("serialnumber", x86_serial_nr_setup); __setup("serialnumber", x86_serial_nr_setup);
__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
/* Current gdt points %fs at the "master" per-cpu area: after this,
* it's on the real one. */
void switch_to_new_gdt(void)
{
struct desc_ptr gdt_descr;
gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
gdt_descr.size = GDT_SIZE - 1;
load_gdt(&gdt_descr);
asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
}
static struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
static void __cpuinit default_init(struct cpuinfo_x86 *c)
{
/* Not much we can do here... */
/* Check if at least it has cpuid */
if (c->cpuid_level == -1) {
/* No cpuid. It must be an ancient CPU */
if (c->x86 == 4)
strcpy(c->x86_model_id, "486");
else if (c->x86 == 3)
strcpy(c->x86_model_id, "386");
}
}
static struct cpu_dev __cpuinitdata default_cpu = {
.c_init = default_init,
.c_vendor = "Unknown",
.c_x86_vendor = X86_VENDOR_UNKNOWN,
};
int __cpuinit get_model_name(struct cpuinfo_x86 *c)
{
unsigned int *v;
char *p, *q;
if (c->extended_cpuid_level < 0x80000004)
return 0;
v = (unsigned int *) c->x86_model_id;
cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
c->x86_model_id[48] = 0;
/* Intel chips right-justify this string for some dumb reason;
undo that brain damage */
p = q = &c->x86_model_id[0];
while (*p == ' ')
p++;
if (p != q) {
while (*p)
*q++ = *p++;
while (q <= &c->x86_model_id[48])
*q++ = '\0'; /* Zero-pad the rest */
}
return 1;
}
void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
{
unsigned int n, dummy, ebx, ecx, edx, l2size;
n = c->extended_cpuid_level;
if (n >= 0x80000005) {
cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
c->x86_cache_size = (ecx>>24) + (edx>>24);
}
if (n < 0x80000006) /* Some chips just has a large L1. */
return;
cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
l2size = ecx >> 16;
/* do processor-specific cache resizing */
if (this_cpu->c_size_cache)
l2size = this_cpu->c_size_cache(c, l2size);
/* Allow user to override all this if necessary. */
if (cachesize_override != -1)
l2size = cachesize_override;
if (l2size == 0)
return; /* Again, no L2 cache is possible */
c->x86_cache_size = l2size;
printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
l2size, ecx & 0xFF);
}
#ifdef CONFIG_X86_HT
void __cpuinit detect_ht(struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
int index_msb, core_bits;
if (!cpu_has(c, X86_FEATURE_HT))
return;
if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
goto out;
cpuid(1, &eax, &ebx, &ecx, &edx);
smp_num_siblings = (ebx & 0xff0000) >> 16;
if (smp_num_siblings == 1) {
printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
} else if (smp_num_siblings > 1) {
if (smp_num_siblings > NR_CPUS) {
printk(KERN_WARNING "CPU: Unsupported number of siblings %d",
smp_num_siblings);
smp_num_siblings = 1;
return;
}
index_msb = get_count_order(smp_num_siblings);
c->phys_proc_id = phys_pkg_id(c->initial_apicid, index_msb);
smp_num_siblings = smp_num_siblings / c->x86_max_cores;
index_msb = get_count_order(smp_num_siblings);
core_bits = get_count_order(c->x86_max_cores);
c->cpu_core_id = phys_pkg_id(c->initial_apicid, index_msb) &
((1 << core_bits) - 1);
}
out:
if ((c->x86_max_cores * smp_num_siblings) > 1) {
printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
c->phys_proc_id);
printk(KERN_INFO "CPU: Processor Core ID: %d\n",
c->cpu_core_id);
}
}
#endif
static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
{
char *v = c->x86_vendor_id;
int i;
static int printed;
for (i = 0; i < X86_VENDOR_NUM; i++) {
if (!cpu_devs[i])
break;
if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
(cpu_devs[i]->c_ident[1] &&
!strcmp(v, cpu_devs[i]->c_ident[1]))) {
this_cpu = cpu_devs[i];
c->x86_vendor = this_cpu->c_x86_vendor;
return;
}
}
if (!printed) {
printed++;
printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
printk(KERN_ERR "CPU: Your system may be unstable.\n");
}
c->x86_vendor = X86_VENDOR_UNKNOWN;
this_cpu = &default_cpu;
}
void __cpuinit cpu_detect(struct cpuinfo_x86 *c)
{
/* Get vendor name */
cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
(unsigned int *)&c->x86_vendor_id[0],
(unsigned int *)&c->x86_vendor_id[8],
(unsigned int *)&c->x86_vendor_id[4]);
c->x86 = 4;
/* Intel-defined flags: level 0x00000001 */
if (c->cpuid_level >= 0x00000001) {
u32 junk, tfms, cap0, misc;
cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
c->x86 = (tfms >> 8) & 0xf;
c->x86_model = (tfms >> 4) & 0xf;
c->x86_mask = tfms & 0xf;
if (c->x86 == 0xf)
c->x86 += (tfms >> 20) & 0xff;
if (c->x86 >= 0x6)
c->x86_model += ((tfms >> 16) & 0xf) << 4;
if (cap0 & (1<<19)) {
c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
c->x86_cache_alignment = c->x86_clflush_size;
}
}
}
static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
{
u32 tfms, xlvl;
u32 ebx;
/* Intel-defined flags: level 0x00000001 */
if (c->cpuid_level >= 0x00000001) {
u32 capability, excap;
cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
c->x86_capability[0] = capability;
c->x86_capability[4] = excap;
}
/* AMD-defined flags: level 0x80000001 */
xlvl = cpuid_eax(0x80000000);
c->extended_cpuid_level = xlvl;
if ((xlvl & 0xffff0000) == 0x80000000) {
if (xlvl >= 0x80000001) {
c->x86_capability[1] = cpuid_edx(0x80000001);
c->x86_capability[6] = cpuid_ecx(0x80000001);
}
}
}
/*
* Do minimum CPU detection early.
* Fields really needed: vendor, cpuid_level, family, model, mask,
* cache alignment.
* The others are not touched to avoid unwanted side effects.
*
* WARNING: this function is only called on the BP. Don't add code here
* that is supposed to run on all CPUs.
*/
static void __init early_identify_cpu(struct cpuinfo_x86 *c)
{
c->x86_clflush_size = 32;
c->x86_cache_alignment = c->x86_clflush_size;
if (!have_cpuid_p())
return;
memset(&c->x86_capability, 0, sizeof c->x86_capability);
c->extended_cpuid_level = 0;
cpu_detect(c);
get_cpu_vendor(c);
get_cpu_cap(c);
if (this_cpu->c_early_init)
this_cpu->c_early_init(c);
validate_pat_support(c);
}
void __init early_cpu_init(void)
{
struct cpu_dev **cdev;
int count = 0;
printk("KERNEL supported cpus:\n");
for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
struct cpu_dev *cpudev = *cdev;
unsigned int j;
if (count >= X86_VENDOR_NUM)
break;
cpu_devs[count] = cpudev;
count++;
for (j = 0; j < 2; j++) {
if (!cpudev->c_ident[j])
continue;
printk(" %s %s\n", cpudev->c_vendor,
cpudev->c_ident[j]);
}
}
early_identify_cpu(&boot_cpu_data);
}
/*
* The NOPL instruction is supposed to exist on all CPUs with
* family >= 6, unfortunately, that's not true in practice because
* of early VIA chips and (more importantly) broken virtualizers that
* are not easy to detect. Hence, probe for it based on first
* principles.
*/
static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
{
const u32 nopl_signature = 0x888c53b1; /* Random number */
u32 has_nopl = nopl_signature;
clear_cpu_cap(c, X86_FEATURE_NOPL);
if (c->x86 >= 6) {
asm volatile("\n"
"1: .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */
"2:\n"
" .section .fixup,\"ax\"\n"
"3: xor %0,%0\n"
" jmp 2b\n"
" .previous\n"
_ASM_EXTABLE(1b,3b)
: "+a" (has_nopl));
if (has_nopl == nopl_signature)
set_cpu_cap(c, X86_FEATURE_NOPL);
}
}
static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
{
if (!have_cpuid_p())
return;
c->extended_cpuid_level = 0;
cpu_detect(c);
get_cpu_vendor(c);
get_cpu_cap(c);
if (c->cpuid_level >= 0x00000001) {
c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xFF;
#ifdef CONFIG_X86_HT
c->apicid = phys_pkg_id(c->initial_apicid, 0);
c->phys_proc_id = c->initial_apicid;
#else
c->apicid = c->initial_apicid;
#endif
}
if (c->extended_cpuid_level >= 0x80000004)
get_model_name(c); /* Default name */
init_scattered_cpuid_features(c);
detect_nopl(c);
}
/* /*
* This does the hard work of actually picking apart the CPU stuff... * This does the hard work of actually picking apart the CPU stuff...
@ -499,7 +586,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
*/ */
if (c != &boot_cpu_data) { if (c != &boot_cpu_data) {
/* AND the already accumulated flags with these */ /* AND the already accumulated flags with these */
for (i = 0 ; i < NCAPINTS ; i++) for (i = 0; i < NCAPINTS; i++)
boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
} }
@ -528,51 +615,48 @@ void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
mtrr_ap_init(); mtrr_ap_init();
} }
#ifdef CONFIG_X86_HT struct msr_range {
void __cpuinit detect_ht(struct cpuinfo_x86 *c) unsigned min;
unsigned max;
};
static struct msr_range msr_range_array[] __cpuinitdata = {
{ 0x00000000, 0x00000418},
{ 0xc0000000, 0xc000040b},
{ 0xc0010000, 0xc0010142},
{ 0xc0011000, 0xc001103b},
};
static void __cpuinit print_cpu_msr(void)
{ {
u32 eax, ebx, ecx, edx; unsigned index;
int index_msb, core_bits; u64 val;
int i;
unsigned index_min, index_max;
cpuid(1, &eax, &ebx, &ecx, &edx); for (i = 0; i < ARRAY_SIZE(msr_range_array); i++) {
index_min = msr_range_array[i].min;
if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY)) index_max = msr_range_array[i].max;
return; for (index = index_min; index < index_max; index++) {
if (rdmsrl_amd_safe(index, &val))
smp_num_siblings = (ebx & 0xff0000) >> 16; continue;
printk(KERN_INFO " MSR%08x: %016llx\n", index, val);
if (smp_num_siblings == 1) {
printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
} else if (smp_num_siblings > 1) {
if (smp_num_siblings > NR_CPUS) {
printk(KERN_WARNING "CPU: Unsupported number of the "
"siblings %d", smp_num_siblings);
smp_num_siblings = 1;
return;
} }
index_msb = get_count_order(smp_num_siblings);
c->phys_proc_id = phys_pkg_id(c->initial_apicid, index_msb);
printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
c->phys_proc_id);
smp_num_siblings = smp_num_siblings / c->x86_max_cores;
index_msb = get_count_order(smp_num_siblings) ;
core_bits = get_count_order(c->x86_max_cores);
c->cpu_core_id = phys_pkg_id(c->initial_apicid, index_msb) &
((1 << core_bits) - 1);
if (c->x86_max_cores > 1)
printk(KERN_INFO "CPU: Processor Core ID: %d\n",
c->cpu_core_id);
} }
} }
#endif
static int show_msr __cpuinitdata;
static __init int setup_show_msr(char *arg)
{
int num;
get_option(&arg, &num);
if (num > 0)
show_msr = num;
return 1;
}
__setup("show_msr=", setup_show_msr);
static __init int setup_noclflush(char *arg) static __init int setup_noclflush(char *arg)
{ {
@ -591,17 +675,25 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
vendor = c->x86_vendor_id; vendor = c->x86_vendor_id;
if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor))) if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
printk("%s ", vendor); printk(KERN_CONT "%s ", vendor);
if (!c->x86_model_id[0]) if (c->x86_model_id[0])
printk("%d86", c->x86); printk(KERN_CONT "%s", c->x86_model_id);
else else
printk("%s", c->x86_model_id); printk(KERN_CONT "%d86", c->x86);
if (c->x86_mask || c->cpuid_level >= 0) if (c->x86_mask || c->cpuid_level >= 0)
printk(" stepping %02x\n", c->x86_mask); printk(KERN_CONT " stepping %02x\n", c->x86_mask);
else else
printk("\n"); printk(KERN_CONT "\n");
#ifdef CONFIG_SMP
if (c->cpu_index < show_msr)
print_cpu_msr();
#else
if (show_msr)
print_cpu_msr();
#endif
} }
static __init int setup_disablecpuid(char *arg) static __init int setup_disablecpuid(char *arg)
@ -617,19 +709,6 @@ __setup("clearcpuid=", setup_disablecpuid);
cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
void __init early_cpu_init(void)
{
struct cpu_vendor_dev *cvdev;
for (cvdev = __x86cpuvendor_start ;
cvdev < __x86cpuvendor_end ;
cvdev++)
cpu_devs[cvdev->vendor] = cvdev->cpu_dev;
early_cpu_detect();
validate_pat_support(&boot_cpu_data);
}
/* Make sure %fs is initialized properly in idle threads */ /* Make sure %fs is initialized properly in idle threads */
struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs) struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
{ {
@ -638,18 +717,6 @@ struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
return regs; return regs;
} }
/* Current gdt points %fs at the "master" per-cpu area: after this,
* it's on the real one. */
void switch_to_new_gdt(void)
{
struct desc_ptr gdt_descr;
gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
gdt_descr.size = GDT_SIZE - 1;
load_gdt(&gdt_descr);
asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
}
/* /*
* cpu_init() initializes state that is per-CPU. Some data is already * cpu_init() initializes state that is per-CPU. Some data is already
* initialized (naturally) in the bootstrap process, such as the GDT * initialized (naturally) in the bootstrap process, such as the GDT
@ -709,9 +776,20 @@ void __cpuinit cpu_init(void)
/* /*
* Force FPU initialization: * Force FPU initialization:
*/ */
if (cpu_has_xsave)
current_thread_info()->status = TS_XSAVE;
else
current_thread_info()->status = 0; current_thread_info()->status = 0;
clear_used_math(); clear_used_math();
mxcsr_feature_mask_init(); mxcsr_feature_mask_init();
/*
* Boot processor to setup the FP and extended state context info.
*/
if (!smp_processor_id())
init_thread_xstate();
xsave_init();
} }
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU

View file

@ -18,6 +18,7 @@
#include <asm/mtrr.h> #include <asm/mtrr.h>
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/pat.h> #include <asm/pat.h>
#include <asm/asm.h>
#include <asm/numa.h> #include <asm/numa.h>
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
#include <asm/mpspec.h> #include <asm/mpspec.h>
@ -36,6 +37,8 @@
#include "cpu.h" #include "cpu.h"
static struct cpu_dev *this_cpu __cpuinitdata;
/* We need valid kernel segments for data and code in long mode too /* We need valid kernel segments for data and code in long mode too
* IRET will check the segment types kkeil 2000/10/28 * IRET will check the segment types kkeil 2000/10/28
* Also sysret mandates a special GDT layout * Also sysret mandates a special GDT layout
@ -65,7 +68,7 @@ void switch_to_new_gdt(void)
load_gdt(&gdt_descr); load_gdt(&gdt_descr);
} }
struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {}; static struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
static void __cpuinit default_init(struct cpuinfo_x86 *c) static void __cpuinit default_init(struct cpuinfo_x86 *c)
{ {
@ -75,12 +78,13 @@ static void __cpuinit default_init(struct cpuinfo_x86 *c)
static struct cpu_dev __cpuinitdata default_cpu = { static struct cpu_dev __cpuinitdata default_cpu = {
.c_init = default_init, .c_init = default_init,
.c_vendor = "Unknown", .c_vendor = "Unknown",
.c_x86_vendor = X86_VENDOR_UNKNOWN,
}; };
static struct cpu_dev *this_cpu __cpuinitdata = &default_cpu;
int __cpuinit get_model_name(struct cpuinfo_x86 *c) int __cpuinit get_model_name(struct cpuinfo_x86 *c)
{ {
unsigned int *v; unsigned int *v;
char *p, *q;
if (c->extended_cpuid_level < 0x80000004) if (c->extended_cpuid_level < 0x80000004)
return 0; return 0;
@ -90,35 +94,49 @@ int __cpuinit get_model_name(struct cpuinfo_x86 *c)
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
c->x86_model_id[48] = 0; c->x86_model_id[48] = 0;
/* Intel chips right-justify this string for some dumb reason;
undo that brain damage */
p = q = &c->x86_model_id[0];
while (*p == ' ')
p++;
if (p != q) {
while (*p)
*q++ = *p++;
while (q <= &c->x86_model_id[48])
*q++ = '\0'; /* Zero-pad the rest */
}
return 1; return 1;
} }
void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c) void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
{ {
unsigned int n, dummy, ebx, ecx, edx; unsigned int n, dummy, ebx, ecx, edx, l2size;
n = c->extended_cpuid_level; n = c->extended_cpuid_level;
if (n >= 0x80000005) { if (n >= 0x80000005) {
cpuid(0x80000005, &dummy, &ebx, &ecx, &edx); cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), " printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
"D cache %dK (%d bytes/line)\n",
edx>>24, edx&0xFF, ecx>>24, ecx&0xFF); edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
c->x86_cache_size = (ecx>>24) + (edx>>24); c->x86_cache_size = (ecx>>24) + (edx>>24);
/* On K8 L1 TLB is inclusive, so don't count it */ /* On K8 L1 TLB is inclusive, so don't count it */
c->x86_tlbsize = 0; c->x86_tlbsize = 0;
} }
if (n >= 0x80000006) { if (n < 0x80000006) /* Some chips just has a large L1. */
return;
cpuid(0x80000006, &dummy, &ebx, &ecx, &edx); cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
ecx = cpuid_ecx(0x80000006); l2size = ecx >> 16;
c->x86_cache_size = ecx >> 16;
c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff); c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
c->x86_cache_size = l2size;
printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n", printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
c->x86_cache_size, ecx & 0xFF); l2size, ecx & 0xFF);
}
} }
void __cpuinit detect_ht(struct cpuinfo_x86 *c) void __cpuinit detect_ht(struct cpuinfo_x86 *c)
@ -127,14 +145,16 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
u32 eax, ebx, ecx, edx; u32 eax, ebx, ecx, edx;
int index_msb, core_bits; int index_msb, core_bits;
cpuid(1, &eax, &ebx, &ecx, &edx);
if (!cpu_has(c, X86_FEATURE_HT)) if (!cpu_has(c, X86_FEATURE_HT))
return; return;
if (cpu_has(c, X86_FEATURE_CMP_LEGACY)) if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
goto out; goto out;
if (cpu_has(c, X86_FEATURE_XTOPOLOGY))
return;
cpuid(1, &eax, &ebx, &ecx, &edx);
smp_num_siblings = (ebx & 0xff0000) >> 16; smp_num_siblings = (ebx & 0xff0000) >> 16;
if (smp_num_siblings == 1) { if (smp_num_siblings == 1) {
@ -142,8 +162,8 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
} else if (smp_num_siblings > 1) { } else if (smp_num_siblings > 1) {
if (smp_num_siblings > NR_CPUS) { if (smp_num_siblings > NR_CPUS) {
printk(KERN_WARNING "CPU: Unsupported number of " printk(KERN_WARNING "CPU: Unsupported number of siblings %d",
"siblings %d", smp_num_siblings); smp_num_siblings);
smp_num_siblings = 1; smp_num_siblings = 1;
return; return;
} }
@ -160,6 +180,7 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c)
c->cpu_core_id = phys_pkg_id(index_msb) & c->cpu_core_id = phys_pkg_id(index_msb) &
((1 << core_bits) - 1); ((1 << core_bits) - 1);
} }
out: out:
if ((c->x86_max_cores * smp_num_siblings) > 1) { if ((c->x86_max_cores * smp_num_siblings) > 1) {
printk(KERN_INFO "CPU: Physical Processor ID: %d\n", printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
@ -167,7 +188,6 @@ out:
printk(KERN_INFO "CPU: Processor Core ID: %d\n", printk(KERN_INFO "CPU: Processor Core ID: %d\n",
c->cpu_core_id); c->cpu_core_id);
} }
#endif #endif
} }
@ -178,111 +198,70 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
static int printed; static int printed;
for (i = 0; i < X86_VENDOR_NUM; i++) { for (i = 0; i < X86_VENDOR_NUM; i++) {
if (cpu_devs[i]) { if (!cpu_devs[i])
break;
if (!strcmp(v, cpu_devs[i]->c_ident[0]) || if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
(cpu_devs[i]->c_ident[1] && (cpu_devs[i]->c_ident[1] &&
!strcmp(v, cpu_devs[i]->c_ident[1]))) { !strcmp(v, cpu_devs[i]->c_ident[1]))) {
c->x86_vendor = i;
this_cpu = cpu_devs[i]; this_cpu = cpu_devs[i];
c->x86_vendor = this_cpu->c_x86_vendor;
return; return;
} }
} }
}
if (!printed) { if (!printed) {
printed++; printed++;
printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n"); printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
printk(KERN_ERR "CPU: Your system may be unstable.\n"); printk(KERN_ERR "CPU: Your system may be unstable.\n");
} }
c->x86_vendor = X86_VENDOR_UNKNOWN; c->x86_vendor = X86_VENDOR_UNKNOWN;
this_cpu = &default_cpu;
} }
static void __init early_cpu_support_print(void) void __cpuinit cpu_detect(struct cpuinfo_x86 *c)
{ {
int i,j;
struct cpu_dev *cpu_devx;
printk("KERNEL supported cpus:\n");
for (i = 0; i < X86_VENDOR_NUM; i++) {
cpu_devx = cpu_devs[i];
if (!cpu_devx)
continue;
for (j = 0; j < 2; j++) {
if (!cpu_devx->c_ident[j])
continue;
printk(" %s %s\n", cpu_devx->c_vendor,
cpu_devx->c_ident[j]);
}
}
}
static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c);
void __init early_cpu_init(void)
{
struct cpu_vendor_dev *cvdev;
for (cvdev = __x86cpuvendor_start ;
cvdev < __x86cpuvendor_end ;
cvdev++)
cpu_devs[cvdev->vendor] = cvdev->cpu_dev;
early_cpu_support_print();
early_identify_cpu(&boot_cpu_data);
}
/* Do some early cpuid on the boot CPU to get some parameter that are
needed before check_bugs. Everything advanced is in identify_cpu
below. */
static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
{
u32 tfms, xlvl;
c->loops_per_jiffy = loops_per_jiffy;
c->x86_cache_size = -1;
c->x86_vendor = X86_VENDOR_UNKNOWN;
c->x86_model = c->x86_mask = 0; /* So far unknown... */
c->x86_vendor_id[0] = '\0'; /* Unset */
c->x86_model_id[0] = '\0'; /* Unset */
c->x86_clflush_size = 64;
c->x86_cache_alignment = c->x86_clflush_size;
c->x86_max_cores = 1;
c->x86_coreid_bits = 0;
c->extended_cpuid_level = 0;
memset(&c->x86_capability, 0, sizeof c->x86_capability);
/* Get vendor name */ /* Get vendor name */
cpuid(0x00000000, (unsigned int *)&c->cpuid_level, cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
(unsigned int *)&c->x86_vendor_id[0], (unsigned int *)&c->x86_vendor_id[0],
(unsigned int *)&c->x86_vendor_id[8], (unsigned int *)&c->x86_vendor_id[8],
(unsigned int *)&c->x86_vendor_id[4]); (unsigned int *)&c->x86_vendor_id[4]);
get_cpu_vendor(c); c->x86 = 4;
/* Initialize the standard set of capabilities */
/* Note that the vendor-specific code below might override */
/* Intel-defined flags: level 0x00000001 */ /* Intel-defined flags: level 0x00000001 */
if (c->cpuid_level >= 0x00000001) { if (c->cpuid_level >= 0x00000001) {
__u32 misc; u32 junk, tfms, cap0, misc;
cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4], cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
&c->x86_capability[0]);
c->x86 = (tfms >> 8) & 0xf; c->x86 = (tfms >> 8) & 0xf;
c->x86_model = (tfms >> 4) & 0xf; c->x86_model = (tfms >> 4) & 0xf;
c->x86_mask = tfms & 0xf; c->x86_mask = tfms & 0xf;
if (c->x86 == 0xf) if (c->x86 == 0xf)
c->x86 += (tfms >> 20) & 0xff; c->x86 += (tfms >> 20) & 0xff;
if (c->x86 >= 0x6) if (c->x86 >= 0x6)
c->x86_model += ((tfms >> 16) & 0xF) << 4; c->x86_model += ((tfms >> 16) & 0xf) << 4;
if (test_cpu_cap(c, X86_FEATURE_CLFLSH)) if (cap0 & (1<<19)) {
c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
} else { c->x86_cache_alignment = c->x86_clflush_size;
/* Have CPUID level 0 only - unheard of */ }
c->x86 = 4; }
}
static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
{
u32 tfms, xlvl;
u32 ebx;
/* Intel-defined flags: level 0x00000001 */
if (c->cpuid_level >= 0x00000001) {
u32 capability, excap;
cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
c->x86_capability[0] = capability;
c->x86_capability[4] = excap;
} }
c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xff;
#ifdef CONFIG_SMP
c->phys_proc_id = c->initial_apicid;
#endif
/* AMD-defined flags: level 0x80000001 */ /* AMD-defined flags: level 0x80000001 */
xlvl = cpuid_eax(0x80000000); xlvl = cpuid_eax(0x80000000);
c->extended_cpuid_level = xlvl; c->extended_cpuid_level = xlvl;
@ -291,8 +270,6 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
c->x86_capability[1] = cpuid_edx(0x80000001); c->x86_capability[1] = cpuid_edx(0x80000001);
c->x86_capability[6] = cpuid_ecx(0x80000001); c->x86_capability[6] = cpuid_ecx(0x80000001);
} }
if (xlvl >= 0x80000004)
get_model_name(c); /* Default name */
} }
/* Transmeta-defined flags: level 0x80860001 */ /* Transmeta-defined flags: level 0x80860001 */
@ -312,14 +289,114 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
c->x86_virt_bits = (eax >> 8) & 0xff; c->x86_virt_bits = (eax >> 8) & 0xff;
c->x86_phys_bits = eax & 0xff; c->x86_phys_bits = eax & 0xff;
} }
}
if (c->x86_vendor != X86_VENDOR_UNKNOWN && /* Do some early cpuid on the boot CPU to get some parameter that are
cpu_devs[c->x86_vendor]->c_early_init) needed before check_bugs. Everything advanced is in identify_cpu
cpu_devs[c->x86_vendor]->c_early_init(c); below. */
static void __init early_identify_cpu(struct cpuinfo_x86 *c)
{
c->x86_clflush_size = 64;
c->x86_cache_alignment = c->x86_clflush_size;
memset(&c->x86_capability, 0, sizeof c->x86_capability);
c->extended_cpuid_level = 0;
cpu_detect(c);
get_cpu_vendor(c);
get_cpu_cap(c);
if (this_cpu->c_early_init)
this_cpu->c_early_init(c);
validate_pat_support(c); validate_pat_support(c);
} }
void __init early_cpu_init(void)
{
struct cpu_dev **cdev;
int count = 0;
printk("KERNEL supported cpus:\n");
for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
struct cpu_dev *cpudev = *cdev;
unsigned int j;
if (count >= X86_VENDOR_NUM)
break;
cpu_devs[count] = cpudev;
count++;
for (j = 0; j < 2; j++) {
if (!cpudev->c_ident[j])
continue;
printk(" %s %s\n", cpudev->c_vendor,
cpudev->c_ident[j]);
}
}
early_identify_cpu(&boot_cpu_data);
}
/*
* The NOPL instruction is supposed to exist on all CPUs with
* family >= 6, unfortunately, that's not true in practice because
* of early VIA chips and (more importantly) broken virtualizers that
* are not easy to detect. Hence, probe for it based on first
* principles.
*
* Note: no 64-bit chip is known to lack these, but put the code here
* for consistency with 32 bits, and to make it utterly trivial to
* diagnose the problem should it ever surface.
*/
static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
{
const u32 nopl_signature = 0x888c53b1; /* Random number */
u32 has_nopl = nopl_signature;
clear_cpu_cap(c, X86_FEATURE_NOPL);
if (c->x86 >= 6) {
asm volatile("\n"
"1: .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */
"2:\n"
" .section .fixup,\"ax\"\n"
"3: xor %0,%0\n"
" jmp 2b\n"
" .previous\n"
_ASM_EXTABLE(1b,3b)
: "+a" (has_nopl));
if (has_nopl == nopl_signature)
set_cpu_cap(c, X86_FEATURE_NOPL);
}
}
static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
{
c->extended_cpuid_level = 0;
cpu_detect(c);
get_cpu_vendor(c);
get_cpu_cap(c);
c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xff;
#ifdef CONFIG_SMP
c->phys_proc_id = c->initial_apicid;
#endif
if (c->extended_cpuid_level >= 0x80000004)
get_model_name(c); /* Default name */
init_scattered_cpuid_features(c);
detect_nopl(c);
}
/* /*
* This does the hard work of actually picking apart the CPU stuff... * This does the hard work of actually picking apart the CPU stuff...
*/ */
@ -327,9 +404,19 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
{ {
int i; int i;
early_identify_cpu(c); c->loops_per_jiffy = loops_per_jiffy;
c->x86_cache_size = -1;
c->x86_vendor = X86_VENDOR_UNKNOWN;
c->x86_model = c->x86_mask = 0; /* So far unknown... */
c->x86_vendor_id[0] = '\0'; /* Unset */
c->x86_model_id[0] = '\0'; /* Unset */
c->x86_max_cores = 1;
c->x86_coreid_bits = 0;
c->x86_clflush_size = 64;
c->x86_cache_alignment = c->x86_clflush_size;
memset(&c->x86_capability, 0, sizeof c->x86_capability);
init_scattered_cpuid_features(c); generic_identify(c);
c->apicid = phys_pkg_id(0); c->apicid = phys_pkg_id(0);
@ -375,7 +462,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
} }
void __cpuinit identify_boot_cpu(void) void __init identify_boot_cpu(void)
{ {
identify_cpu(&boot_cpu_data); identify_cpu(&boot_cpu_data);
} }
@ -387,6 +474,49 @@ void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
mtrr_ap_init(); mtrr_ap_init();
} }
struct msr_range {
unsigned min;
unsigned max;
};
static struct msr_range msr_range_array[] __cpuinitdata = {
{ 0x00000000, 0x00000418},
{ 0xc0000000, 0xc000040b},
{ 0xc0010000, 0xc0010142},
{ 0xc0011000, 0xc001103b},
};
static void __cpuinit print_cpu_msr(void)
{
unsigned index;
u64 val;
int i;
unsigned index_min, index_max;
for (i = 0; i < ARRAY_SIZE(msr_range_array); i++) {
index_min = msr_range_array[i].min;
index_max = msr_range_array[i].max;
for (index = index_min; index < index_max; index++) {
if (rdmsrl_amd_safe(index, &val))
continue;
printk(KERN_INFO " MSR%08x: %016llx\n", index, val);
}
}
}
static int show_msr __cpuinitdata;
static __init int setup_show_msr(char *arg)
{
int num;
get_option(&arg, &num);
if (num > 0)
show_msr = num;
return 1;
}
__setup("show_msr=", setup_show_msr);
static __init int setup_noclflush(char *arg) static __init int setup_noclflush(char *arg)
{ {
setup_clear_cpu_cap(X86_FEATURE_CLFLSH); setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
@ -403,6 +533,14 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
printk(KERN_CONT " stepping %02x\n", c->x86_mask); printk(KERN_CONT " stepping %02x\n", c->x86_mask);
else else
printk(KERN_CONT "\n"); printk(KERN_CONT "\n");
#ifdef CONFIG_SMP
if (c->cpu_index < show_msr)
print_cpu_msr();
#else
if (show_msr)
print_cpu_msr();
#endif
} }
static __init int setup_disablecpuid(char *arg) static __init int setup_disablecpuid(char *arg)
@ -493,17 +631,20 @@ void pda_init(int cpu)
/* others are initialized in smpboot.c */ /* others are initialized in smpboot.c */
pda->pcurrent = &init_task; pda->pcurrent = &init_task;
pda->irqstackptr = boot_cpu_stack; pda->irqstackptr = boot_cpu_stack;
pda->irqstackptr += IRQSTACKSIZE - 64;
} else { } else {
if (!pda->irqstackptr) {
pda->irqstackptr = (char *) pda->irqstackptr = (char *)
__get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER); __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
if (!pda->irqstackptr) if (!pda->irqstackptr)
panic("cannot allocate irqstack for cpu %d", cpu); panic("cannot allocate irqstack for cpu %d",
cpu);
pda->irqstackptr += IRQSTACKSIZE - 64;
}
if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE) if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE)
pda->nodenumber = cpu_to_node(cpu); pda->nodenumber = cpu_to_node(cpu);
} }
pda->irqstackptr += IRQSTACKSIZE-64;
} }
char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ +
@ -597,23 +738,28 @@ void __cpuinit cpu_init(void)
barrier(); barrier();
check_efer(); check_efer();
if (cpu != 0 && x2apic)
enable_x2apic();
/* /*
* set up and load the per-CPU TSS * set up and load the per-CPU TSS
*/ */
for (v = 0; v < N_EXCEPTION_STACKS; v++) { if (!orig_ist->ist[0]) {
static const unsigned int order[N_EXCEPTION_STACKS] = { static const unsigned int order[N_EXCEPTION_STACKS] = {
[0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
[DEBUG_STACK - 1] = DEBUG_STACK_ORDER [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
}; };
for (v = 0; v < N_EXCEPTION_STACKS; v++) {
if (cpu) { if (cpu) {
estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]); estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
if (!estacks) if (!estacks)
panic("Cannot allocate exception stack %ld %d\n", panic("Cannot allocate exception "
v, cpu); "stack %ld %d\n", v, cpu);
} }
estacks += PAGE_SIZE << order[v]; estacks += PAGE_SIZE << order[v];
orig_ist->ist[v] = t->x86_tss.ist[v] = (unsigned long)estacks; orig_ist->ist[v] = t->x86_tss.ist[v] =
(unsigned long)estacks;
}
} }
t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap); t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);

View file

@ -21,21 +21,15 @@ struct cpu_dev {
void (*c_init)(struct cpuinfo_x86 * c); void (*c_init)(struct cpuinfo_x86 * c);
void (*c_identify)(struct cpuinfo_x86 * c); void (*c_identify)(struct cpuinfo_x86 * c);
unsigned int (*c_size_cache)(struct cpuinfo_x86 * c, unsigned int size); unsigned int (*c_size_cache)(struct cpuinfo_x86 * c, unsigned int size);
int c_x86_vendor;
}; };
extern struct cpu_dev * cpu_devs [X86_VENDOR_NUM]; #define cpu_dev_register(cpu_devX) \
static struct cpu_dev *__cpu_dev_##cpu_devX __used \
__attribute__((__section__(".x86_cpu_dev.init"))) = \
&cpu_devX;
struct cpu_vendor_dev { extern struct cpu_dev *__x86_cpu_dev_start[], *__x86_cpu_dev_end[];
int vendor;
struct cpu_dev *cpu_dev;
};
#define cpu_vendor_dev_register(cpu_vendor_id, cpu_dev) \
static struct cpu_vendor_dev __cpu_vendor_dev_##cpu_vendor_id __used \
__attribute__((__section__(".x86cpuvendor.init"))) = \
{ cpu_vendor_id, cpu_dev }
extern struct cpu_vendor_dev __x86cpuvendor_start[], __x86cpuvendor_end[];
extern int get_model_name(struct cpuinfo_x86 *c); extern int get_model_name(struct cpuinfo_x86 *c);
extern void display_cacheinfo(struct cpuinfo_x86 *c); extern void display_cacheinfo(struct cpuinfo_x86 *c);

View file

@ -15,13 +15,11 @@
/* /*
* Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
*/ */
static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) static void __cpuinit __do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
{ {
unsigned char ccr2, ccr3; unsigned char ccr2, ccr3;
unsigned long flags;
/* we test for DEVID by checking whether CCR3 is writable */ /* we test for DEVID by checking whether CCR3 is writable */
local_irq_save(flags);
ccr3 = getCx86(CX86_CCR3); ccr3 = getCx86(CX86_CCR3);
setCx86(CX86_CCR3, ccr3 ^ 0x80); setCx86(CX86_CCR3, ccr3 ^ 0x80);
getCx86(0xc0); /* dummy to change bus */ getCx86(0xc0); /* dummy to change bus */
@ -44,9 +42,16 @@ static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
*dir0 = getCx86(CX86_DIR0); *dir0 = getCx86(CX86_DIR0);
*dir1 = getCx86(CX86_DIR1); *dir1 = getCx86(CX86_DIR1);
} }
local_irq_restore(flags);
} }
static void __cpuinit do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
{
unsigned long flags;
local_irq_save(flags);
__do_cyrix_devid(dir0, dir1);
local_irq_restore(flags);
}
/* /*
* Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
* order to identify the Cyrix CPU model after we're out of setup.c * order to identify the Cyrix CPU model after we're out of setup.c
@ -116,7 +121,7 @@ static void __cpuinit set_cx86_reorder(void)
setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
/* Load/Store Serialize to mem access disable (=reorder it) */ /* Load/Store Serialize to mem access disable (=reorder it) */
setCx86(CX86_PCR0, getCx86(CX86_PCR0) & ~0x80); setCx86_old(CX86_PCR0, getCx86_old(CX86_PCR0) & ~0x80);
/* set load/store serialize from 1GB to 4GB */ /* set load/store serialize from 1GB to 4GB */
ccr3 |= 0xe0; ccr3 |= 0xe0;
setCx86(CX86_CCR3, ccr3); setCx86(CX86_CCR3, ccr3);
@ -127,11 +132,11 @@ static void __cpuinit set_cx86_memwb(void)
printk(KERN_INFO "Enable Memory-Write-back mode on Cyrix/NSC processor.\n"); printk(KERN_INFO "Enable Memory-Write-back mode on Cyrix/NSC processor.\n");
/* CCR2 bit 2: unlock NW bit */ /* CCR2 bit 2: unlock NW bit */
setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04); setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) & ~0x04);
/* set 'Not Write-through' */ /* set 'Not Write-through' */
write_cr0(read_cr0() | X86_CR0_NW); write_cr0(read_cr0() | X86_CR0_NW);
/* CCR2 bit 2: lock NW bit and set WT1 */ /* CCR2 bit 2: lock NW bit and set WT1 */
setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14); setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x14);
} }
/* /*
@ -145,14 +150,14 @@ static void __cpuinit geode_configure(void)
local_irq_save(flags); local_irq_save(flags);
/* Suspend on halt power saving and enable #SUSP pin */ /* Suspend on halt power saving and enable #SUSP pin */
setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88); setCx86_old(CX86_CCR2, getCx86_old(CX86_CCR2) | 0x88);
ccr3 = getCx86(CX86_CCR3); ccr3 = getCx86(CX86_CCR3);
setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
/* FPU fast, DTE cache, Mem bypass */ /* FPU fast, DTE cache, Mem bypass */
setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x38); setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x38);
setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
set_cx86_memwb(); set_cx86_memwb();
@ -161,6 +166,24 @@ static void __cpuinit geode_configure(void)
local_irq_restore(flags); local_irq_restore(flags);
} }
static void __cpuinit early_init_cyrix(struct cpuinfo_x86 *c)
{
unsigned char dir0, dir0_msn, dir1 = 0;
__do_cyrix_devid(&dir0, &dir1);
dir0_msn = dir0 >> 4; /* identifies CPU "family" */
switch (dir0_msn) {
case 3: /* 6x86/6x86L */
/* Emulate MTRRs using Cyrix's ARRs. */
set_cpu_cap(c, X86_FEATURE_CYRIX_ARR);
break;
case 5: /* 6x86MX/M II */
/* Emulate MTRRs using Cyrix's ARRs. */
set_cpu_cap(c, X86_FEATURE_CYRIX_ARR);
break;
}
}
static void __cpuinit init_cyrix(struct cpuinfo_x86 *c) static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
{ {
@ -268,7 +291,7 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
/* GXm supports extended cpuid levels 'ala' AMD */ /* GXm supports extended cpuid levels 'ala' AMD */
if (c->cpuid_level == 2) { if (c->cpuid_level == 2) {
/* Enable cxMMX extensions (GX1 Datasheet 54) */ /* Enable cxMMX extensions (GX1 Datasheet 54) */
setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1); setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7) | 1);
/* /*
* GXm : 0x30 ... 0x5f GXm datasheet 51 * GXm : 0x30 ... 0x5f GXm datasheet 51
@ -291,7 +314,7 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
if (dir1 > 7) { if (dir1 > 7) {
dir0_msn++; /* M II */ dir0_msn++; /* M II */
/* Enable MMX extensions (App note 108) */ /* Enable MMX extensions (App note 108) */
setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1); setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7)|1);
} else { } else {
c->coma_bug = 1; /* 6x86MX, it has the bug. */ c->coma_bug = 1; /* 6x86MX, it has the bug. */
} }
@ -406,7 +429,7 @@ static void __cpuinit cyrix_identify(struct cpuinfo_x86 *c)
local_irq_save(flags); local_irq_save(flags);
ccr3 = getCx86(CX86_CCR3); ccr3 = getCx86(CX86_CCR3);
setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80); /* enable cpuid */ setCx86_old(CX86_CCR4, getCx86_old(CX86_CCR4) | 0x80); /* enable cpuid */
setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
local_irq_restore(flags); local_irq_restore(flags);
} }
@ -416,16 +439,19 @@ static void __cpuinit cyrix_identify(struct cpuinfo_x86 *c)
static struct cpu_dev cyrix_cpu_dev __cpuinitdata = { static struct cpu_dev cyrix_cpu_dev __cpuinitdata = {
.c_vendor = "Cyrix", .c_vendor = "Cyrix",
.c_ident = { "CyrixInstead" }, .c_ident = { "CyrixInstead" },
.c_early_init = early_init_cyrix,
.c_init = init_cyrix, .c_init = init_cyrix,
.c_identify = cyrix_identify, .c_identify = cyrix_identify,
.c_x86_vendor = X86_VENDOR_CYRIX,
}; };
cpu_vendor_dev_register(X86_VENDOR_CYRIX, &cyrix_cpu_dev); cpu_dev_register(cyrix_cpu_dev);
static struct cpu_dev nsc_cpu_dev __cpuinitdata = { static struct cpu_dev nsc_cpu_dev __cpuinitdata = {
.c_vendor = "NSC", .c_vendor = "NSC",
.c_ident = { "Geode by NSC" }, .c_ident = { "Geode by NSC" },
.c_init = init_nsc, .c_init = init_nsc,
.c_x86_vendor = X86_VENDOR_NSC,
}; };
cpu_vendor_dev_register(X86_VENDOR_NSC, &nsc_cpu_dev); cpu_dev_register(nsc_cpu_dev);

View file

@ -1,83 +0,0 @@
/*
* Strings for the various x86 capability flags.
*
* This file must not contain any executable code.
*/
#include <asm/cpufeature.h>
/*
* These flag bits must match the definitions in <asm/cpufeature.h>.
* NULL means this bit is undefined or reserved; either way it doesn't
* have meaning as far as Linux is concerned. Note that it's important
* to realize there is a difference between this table and CPUID -- if
* applications want to get the raw CPUID data, they should access
* /dev/cpu/<cpu_nr>/cpuid instead.
*/
const char * const x86_cap_flags[NCAPINTS*32] = {
/* Intel-defined */
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
"pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
"fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
/* AMD-defined */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
"3dnowext", "3dnow",
/* Transmeta-defined */
"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Other (Linux-defined) */
"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
NULL, NULL, NULL, NULL,
"constant_tsc", "up", NULL, "arch_perfmon",
"pebs", "bts", NULL, NULL,
"rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Intel-defined (#2) */
"pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
"tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* VIA/Cyrix/Centaur-defined */
NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
"ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* AMD-defined (#2) */
"lahf_lm", "cmp_legacy", "svm", "extapic",
"cr8_legacy", "abm", "sse4a", "misalignsse",
"3dnowprefetch", "osvw", "ibs", "sse5",
"skinit", "wdt", NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Auxiliary (Linux-defined) */
"ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
const char *const x86_power_flags[32] = {
"ts", /* temperature sensor */
"fid", /* frequency id control */
"vid", /* voltage id control */
"ttp", /* thermal trip */
"tm",
"stc",
"100mhzsteps",
"hwpstate",
"", /* tsc invariant mapped to constant_tsc */
/* nothing */
};

View file

@ -23,13 +23,6 @@
#include <mach_apic.h> #include <mach_apic.h>
#endif #endif
#ifdef CONFIG_X86_INTEL_USERCOPY
/*
* Alignment at which movsl is preferred for bulk memory copies.
*/
struct movsl_mask movsl_mask __read_mostly;
#endif
static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
{ {
/* Netburst reports 64 bytes clflush size, but does IO in 128 bytes */ /* Netburst reports 64 bytes clflush size, but does IO in 128 bytes */
@ -183,9 +176,16 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
if (p) if (p)
strcpy(c->x86_model_id, p); strcpy(c->x86_model_id, p);
c->x86_max_cores = num_cpu_cores(c); detect_extended_topology(c);
if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) {
/*
* let's use the legacy cpuid vector 0x1 and 0x4 for topology
* detection.
*/
c->x86_max_cores = num_cpu_cores(c);
detect_ht(c); detect_ht(c);
}
/* Work around errata */ /* Work around errata */
Intel_errata_workarounds(c); Intel_errata_workarounds(c);
@ -310,73 +310,10 @@ static struct cpu_dev intel_cpu_dev __cpuinitdata = {
.c_early_init = early_init_intel, .c_early_init = early_init_intel,
.c_init = init_intel, .c_init = init_intel,
.c_size_cache = intel_size_cache, .c_size_cache = intel_size_cache,
.c_x86_vendor = X86_VENDOR_INTEL,
}; };
cpu_vendor_dev_register(X86_VENDOR_INTEL, &intel_cpu_dev); cpu_dev_register(intel_cpu_dev);
#ifndef CONFIG_X86_CMPXCHG
unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
{
u8 prev;
unsigned long flags;
/* Poor man's cmpxchg for 386. Unsuitable for SMP */
local_irq_save(flags);
prev = *(u8 *)ptr;
if (prev == old)
*(u8 *)ptr = new;
local_irq_restore(flags);
return prev;
}
EXPORT_SYMBOL(cmpxchg_386_u8);
unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new)
{
u16 prev;
unsigned long flags;
/* Poor man's cmpxchg for 386. Unsuitable for SMP */
local_irq_save(flags);
prev = *(u16 *)ptr;
if (prev == old)
*(u16 *)ptr = new;
local_irq_restore(flags);
return prev;
}
EXPORT_SYMBOL(cmpxchg_386_u16);
unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
{
u32 prev;
unsigned long flags;
/* Poor man's cmpxchg for 386. Unsuitable for SMP */
local_irq_save(flags);
prev = *(u32 *)ptr;
if (prev == old)
*(u32 *)ptr = new;
local_irq_restore(flags);
return prev;
}
EXPORT_SYMBOL(cmpxchg_386_u32);
#endif
#ifndef CONFIG_X86_CMPXCHG64
unsigned long long cmpxchg_486_u64(volatile void *ptr, u64 old, u64 new)
{
u64 prev;
unsigned long flags;
/* Poor man's cmpxchg8b for 386 and 486. Unsuitable for SMP */
local_irq_save(flags);
prev = *(u64 *)ptr;
if (prev == old)
*(u64 *)ptr = new;
local_irq_restore(flags);
return prev;
}
EXPORT_SYMBOL(cmpxchg_486_u64);
#endif
/* arch_initcall(intel_cpu_init); */ /* arch_initcall(intel_cpu_init); */

View file

@ -80,6 +80,9 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
if (c->x86 == 6) if (c->x86 == 6)
set_cpu_cap(c, X86_FEATURE_REP_GOOD); set_cpu_cap(c, X86_FEATURE_REP_GOOD);
set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
detect_extended_topology(c);
if (!cpu_has(c, X86_FEATURE_XTOPOLOGY))
c->x86_max_cores = intel_num_cpu_cores(c); c->x86_max_cores = intel_num_cpu_cores(c);
srat_detect_node(); srat_detect_node();
@ -90,6 +93,7 @@ static struct cpu_dev intel_cpu_dev __cpuinitdata = {
.c_ident = { "GenuineIntel" }, .c_ident = { "GenuineIntel" },
.c_early_init = early_init_intel, .c_early_init = early_init_intel,
.c_init = init_intel, .c_init = init_intel,
.c_x86_vendor = X86_VENDOR_INTEL,
}; };
cpu_vendor_dev_register(X86_VENDOR_INTEL, &intel_cpu_dev);
cpu_dev_register(intel_cpu_dev);

View file

@ -13,6 +13,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/pci.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/smp.h> #include <asm/smp.h>
@ -130,9 +131,18 @@ struct _cpuid4_info {
union _cpuid4_leaf_ebx ebx; union _cpuid4_leaf_ebx ebx;
union _cpuid4_leaf_ecx ecx; union _cpuid4_leaf_ecx ecx;
unsigned long size; unsigned long size;
unsigned long can_disable;
cpumask_t shared_cpu_map; /* future?: only cpus/node is needed */ cpumask_t shared_cpu_map; /* future?: only cpus/node is needed */
}; };
#ifdef CONFIG_PCI
static struct pci_device_id k8_nb_id[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1203) },
{}
};
#endif
unsigned short num_cache_leaves; unsigned short num_cache_leaves;
/* AMD doesn't have CPUID4. Emulate it here to report the same /* AMD doesn't have CPUID4. Emulate it here to report the same
@ -182,7 +192,8 @@ static unsigned short assocs[] __cpuinitdata = {
static unsigned char levels[] __cpuinitdata = { 1, 1, 2, 3 }; static unsigned char levels[] __cpuinitdata = { 1, 1, 2, 3 };
static unsigned char types[] __cpuinitdata = { 1, 2, 3, 3 }; static unsigned char types[] __cpuinitdata = { 1, 2, 3, 3 };
static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, static void __cpuinit
amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
union _cpuid4_leaf_ebx *ebx, union _cpuid4_leaf_ebx *ebx,
union _cpuid4_leaf_ecx *ecx) union _cpuid4_leaf_ecx *ecx)
{ {
@ -251,17 +262,30 @@ static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
(ebx->split.ways_of_associativity + 1) - 1; (ebx->split.ways_of_associativity + 1) - 1;
} }
static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf) static void __cpuinit
amd_check_l3_disable(int index, struct _cpuid4_info *this_leaf)
{
if (index < 3)
return;
this_leaf->can_disable = 1;
}
static int
__cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
{ {
union _cpuid4_leaf_eax eax; union _cpuid4_leaf_eax eax;
union _cpuid4_leaf_ebx ebx; union _cpuid4_leaf_ebx ebx;
union _cpuid4_leaf_ecx ecx; union _cpuid4_leaf_ecx ecx;
unsigned edx; unsigned edx;
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
amd_cpuid4(index, &eax, &ebx, &ecx); amd_cpuid4(index, &eax, &ebx, &ecx);
else if (boot_cpu_data.x86 >= 0x10)
amd_check_l3_disable(index, this_leaf);
} else {
cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx); cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
}
if (eax.split.type == CACHE_TYPE_NULL) if (eax.split.type == CACHE_TYPE_NULL)
return -EIO; /* better error ? */ return -EIO; /* better error ? */
@ -637,6 +661,99 @@ static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) {
} }
} }
#define to_object(k) container_of(k, struct _index_kobject, kobj)
#define to_attr(a) container_of(a, struct _cache_attr, attr)
#ifdef CONFIG_PCI
static struct pci_dev *get_k8_northbridge(int node)
{
struct pci_dev *dev = NULL;
int i;
for (i = 0; i <= node; i++) {
do {
dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
if (!dev)
break;
} while (!pci_match_id(&k8_nb_id[0], dev));
if (!dev)
break;
}
return dev;
}
#else
static struct pci_dev *get_k8_northbridge(int node)
{
return NULL;
}
#endif
static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf)
{
int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
struct pci_dev *dev = NULL;
ssize_t ret = 0;
int i;
if (!this_leaf->can_disable)
return sprintf(buf, "Feature not enabled\n");
dev = get_k8_northbridge(node);
if (!dev) {
printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n");
return -EINVAL;
}
for (i = 0; i < 2; i++) {
unsigned int reg;
pci_read_config_dword(dev, 0x1BC + i * 4, &reg);
ret += sprintf(buf, "%sEntry: %d\n", buf, i);
ret += sprintf(buf, "%sReads: %s\tNew Entries: %s\n",
buf,
reg & 0x80000000 ? "Disabled" : "Allowed",
reg & 0x40000000 ? "Disabled" : "Allowed");
ret += sprintf(buf, "%sSubCache: %x\tIndex: %x\n",
buf, (reg & 0x30000) >> 16, reg & 0xfff);
}
return ret;
}
static ssize_t
store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf,
size_t count)
{
int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
struct pci_dev *dev = NULL;
unsigned int ret, index, val;
if (!this_leaf->can_disable)
return 0;
if (strlen(buf) > 15)
return -EINVAL;
ret = sscanf(buf, "%x %x", &index, &val);
if (ret != 2)
return -EINVAL;
if (index > 1)
return -EINVAL;
val |= 0xc0000000;
dev = get_k8_northbridge(node);
if (!dev) {
printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n");
return -EINVAL;
}
pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000);
wbinvd();
pci_write_config_dword(dev, 0x1BC + index * 4, val);
return 1;
}
struct _cache_attr { struct _cache_attr {
struct attribute attr; struct attribute attr;
ssize_t (*show)(struct _cpuid4_info *, char *); ssize_t (*show)(struct _cpuid4_info *, char *);
@ -657,6 +774,8 @@ define_one_ro(size);
define_one_ro(shared_cpu_map); define_one_ro(shared_cpu_map);
define_one_ro(shared_cpu_list); define_one_ro(shared_cpu_list);
static struct _cache_attr cache_disable = __ATTR(cache_disable, 0644, show_cache_disable, store_cache_disable);
static struct attribute * default_attrs[] = { static struct attribute * default_attrs[] = {
&type.attr, &type.attr,
&level.attr, &level.attr,
@ -667,12 +786,10 @@ static struct attribute * default_attrs[] = {
&size.attr, &size.attr,
&shared_cpu_map.attr, &shared_cpu_map.attr,
&shared_cpu_list.attr, &shared_cpu_list.attr,
&cache_disable.attr,
NULL NULL
}; };
#define to_object(k) container_of(k, struct _index_kobject, kobj)
#define to_attr(a) container_of(a, struct _cache_attr, attr)
static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf) static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf)
{ {
struct _cache_attr *fattr = to_attr(attr); struct _cache_attr *fattr = to_attr(attr);
@ -689,7 +806,15 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf)
static ssize_t store(struct kobject * kobj, struct attribute * attr, static ssize_t store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count) const char * buf, size_t count)
{ {
return 0; struct _cache_attr *fattr = to_attr(attr);
struct _index_kobject *this_leaf = to_object(kobj);
ssize_t ret;
ret = fattr->store ?
fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
buf, count) :
0;
return ret;
} }
static struct sysfs_ops sysfs_ops = { static struct sysfs_ops sysfs_ops = {

View file

@ -0,0 +1,32 @@
#!/usr/bin/perl
#
# Generate the x86_cap_flags[] array from include/asm-x86/cpufeature.h
#
($in, $out) = @ARGV;
open(IN, "< $in\0") or die "$0: cannot open: $in: $!\n";
open(OUT, "> $out\0") or die "$0: cannot create: $out: $!\n";
print OUT "#include <asm/cpufeature.h>\n\n";
print OUT "const char * const x86_cap_flags[NCAPINTS*32] = {\n";
while (defined($line = <IN>)) {
if ($line =~ /^\s*\#\s*define\s+(X86_FEATURE_(\S+))\s+(.*)$/) {
$macro = $1;
$feature = $2;
$tail = $3;
if ($tail =~ /\/\*\s*\"([^"]*)\".*\*\//) {
$feature = $1;
}
if ($feature ne '') {
printf OUT "\t%-32s = \"%s\",\n",
"[$macro]", "\L$feature";
}
}
}
print OUT "};\n";
close(IN);
close(OUT);

View file

@ -729,7 +729,7 @@ struct var_mtrr_range_state {
mtrr_type type; mtrr_type type;
}; };
struct var_mtrr_range_state __initdata range_state[RANGE_NUM]; static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
static int __initdata debug_print; static int __initdata debug_print;
static int __init static int __init

View file

@ -0,0 +1,20 @@
/*
* Strings for the various x86 power flags
*
* This file must not contain any executable code.
*/
#include <asm/cpufeature.h>
const char *const x86_power_flags[32] = {
"ts", /* temperature sensor */
"fid", /* frequency id control */
"vid", /* voltage id control */
"ttp", /* thermal trip */
"tm",
"stc",
"100mhzsteps",
"hwpstate",
"", /* tsc invariant mapped to constant_tsc */
/* nothing */
};

View file

@ -102,6 +102,7 @@ static struct cpu_dev transmeta_cpu_dev __cpuinitdata = {
.c_ident = { "GenuineTMx86", "TransmetaCPU" }, .c_ident = { "GenuineTMx86", "TransmetaCPU" },
.c_init = init_transmeta, .c_init = init_transmeta,
.c_identify = transmeta_identify, .c_identify = transmeta_identify,
.c_x86_vendor = X86_VENDOR_TRANSMETA,
}; };
cpu_vendor_dev_register(X86_VENDOR_TRANSMETA, &transmeta_cpu_dev); cpu_dev_register(transmeta_cpu_dev);

View file

@ -19,7 +19,8 @@ static struct cpu_dev umc_cpu_dev __cpuinitdata = {
} }
}, },
}, },
.c_x86_vendor = X86_VENDOR_UMC,
}; };
cpu_vendor_dev_register(X86_VENDOR_UMC, &umc_cpu_dev); cpu_dev_register(umc_cpu_dev);

View file

@ -148,6 +148,9 @@ void __init e820_print_map(char *who)
case E820_NVS: case E820_NVS:
printk(KERN_CONT "(ACPI NVS)\n"); printk(KERN_CONT "(ACPI NVS)\n");
break; break;
case E820_UNUSABLE:
printk("(unusable)\n");
break;
default: default:
printk(KERN_CONT "type %u\n", e820.map[i].type); printk(KERN_CONT "type %u\n", e820.map[i].type);
break; break;
@ -1260,6 +1263,7 @@ static inline const char *e820_type_to_string(int e820_type)
case E820_RAM: return "System RAM"; case E820_RAM: return "System RAM";
case E820_ACPI: return "ACPI Tables"; case E820_ACPI: return "ACPI Tables";
case E820_NVS: return "ACPI Non-volatile Storage"; case E820_NVS: return "ACPI Non-volatile Storage";
case E820_UNUSABLE: return "Unusable memory";
default: return "reserved"; default: return "reserved";
} }
} }
@ -1267,6 +1271,7 @@ static inline const char *e820_type_to_string(int e820_type)
/* /*
* Mark e820 reserved areas as busy for the resource manager. * Mark e820 reserved areas as busy for the resource manager.
*/ */
static struct resource __initdata *e820_res;
void __init e820_reserve_resources(void) void __init e820_reserve_resources(void)
{ {
int i; int i;
@ -1274,6 +1279,7 @@ void __init e820_reserve_resources(void)
u64 end; u64 end;
res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map); res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map);
e820_res = res;
for (i = 0; i < e820.nr_map; i++) { for (i = 0; i < e820.nr_map; i++) {
end = e820.map[i].addr + e820.map[i].size - 1; end = e820.map[i].addr + e820.map[i].size - 1;
#ifndef CONFIG_RESOURCES_64BIT #ifndef CONFIG_RESOURCES_64BIT
@ -1287,6 +1293,13 @@ void __init e820_reserve_resources(void)
res->end = end; res->end = end;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
/*
* don't register the region that could be conflicted with
* pci device BAR resource and insert them later in
* pcibios_resource_survey()
*/
if (e820.map[i].type != E820_RESERVED || res->start < (1ULL<<20))
insert_resource(&iomem_resource, res); insert_resource(&iomem_resource, res);
res++; res++;
} }
@ -1299,6 +1312,19 @@ void __init e820_reserve_resources(void)
} }
} }
void __init e820_reserve_resources_late(void)
{
int i;
struct resource *res;
res = e820_res;
for (i = 0; i < e820.nr_map; i++) {
if (!res->parent && res->end)
reserve_region_with_split(&iomem_resource, res->start, res->end, res->name);
res++;
}
}
char *__init default_machine_specific_memory_setup(void) char *__init default_machine_specific_memory_setup(void)
{ {
char *who = "BIOS-e820"; char *who = "BIOS-e820";

View file

@ -275,9 +275,9 @@ ENTRY(native_usergs_sysret64)
ENTRY(ret_from_fork) ENTRY(ret_from_fork)
CFI_DEFAULT_STACK CFI_DEFAULT_STACK
push kernel_eflags(%rip) push kernel_eflags(%rip)
CFI_ADJUST_CFA_OFFSET 4 CFI_ADJUST_CFA_OFFSET 8
popf # reset kernel eflags popf # reset kernel eflags
CFI_ADJUST_CFA_OFFSET -4 CFI_ADJUST_CFA_OFFSET -8
call schedule_tail call schedule_tail
GET_THREAD_INFO(%rcx) GET_THREAD_INFO(%rcx)
testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%rcx) testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%rcx)

View file

@ -39,9 +39,92 @@
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
#include "es7000.h"
#include <mach_mpparse.h> #include <mach_mpparse.h>
/*
* ES7000 chipsets
*/
#define NON_UNISYS 0
#define ES7000_CLASSIC 1
#define ES7000_ZORRO 2
#define MIP_REG 1
#define MIP_PSAI_REG 4
#define MIP_BUSY 1
#define MIP_SPIN 0xf0000
#define MIP_VALID 0x0100000000000000ULL
#define MIP_PORT(VALUE) ((VALUE >> 32) & 0xffff)
#define MIP_RD_LO(VALUE) (VALUE & 0xffffffff)
struct mip_reg_info {
unsigned long long mip_info;
unsigned long long delivery_info;
unsigned long long host_reg;
unsigned long long mip_reg;
};
struct part_info {
unsigned char type;
unsigned char length;
unsigned char part_id;
unsigned char apic_mode;
unsigned long snum;
char ptype[16];
char sname[64];
char pname[64];
};
struct psai {
unsigned long long entry_type;
unsigned long long addr;
unsigned long long bep_addr;
};
struct es7000_mem_info {
unsigned char type;
unsigned char length;
unsigned char resv[6];
unsigned long long start;
unsigned long long size;
};
struct es7000_oem_table {
unsigned long long hdr;
struct mip_reg_info mip;
struct part_info pif;
struct es7000_mem_info shm;
struct psai psai;
};
#ifdef CONFIG_ACPI
struct oem_table {
struct acpi_table_header Header;
u32 OEMTableAddr;
u32 OEMTableSize;
};
extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
#endif
struct mip_reg {
unsigned long long off_0;
unsigned long long off_8;
unsigned long long off_10;
unsigned long long off_18;
unsigned long long off_20;
unsigned long long off_28;
unsigned long long off_30;
unsigned long long off_38;
};
#define MIP_SW_APIC 0x1020b
#define MIP_FUNC(VALUE) (VALUE & 0xff)
/* /*
* ES7000 Globals * ES7000 Globals
*/ */

View file

@ -16,87 +16,63 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/dmar.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/ipi.h> #include <asm/ipi.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#ifdef CONFIG_ACPI extern struct genapic apic_flat;
#include <acpi/acpi_bus.h> extern struct genapic apic_physflat;
#endif extern struct genapic apic_x2xpic_uv_x;
extern struct genapic apic_x2apic_phys;
DEFINE_PER_CPU(int, x2apic_extra_bits); extern struct genapic apic_x2apic_cluster;
struct genapic __read_mostly *genapic = &apic_flat; struct genapic __read_mostly *genapic = &apic_flat;
static enum uv_system_type uv_system_type; static struct genapic *apic_probe[] __initdata = {
&apic_x2apic_uv_x,
&apic_x2apic_phys,
&apic_x2apic_cluster,
&apic_physflat,
NULL,
};
/* /*
* Check the APIC IDs in bios_cpu_apicid and choose the APIC mode. * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
*/ */
void __init setup_apic_routing(void) void __init setup_apic_routing(void)
{ {
if (uv_system_type == UV_NON_UNIQUE_APIC) if (genapic == &apic_x2apic_phys || genapic == &apic_x2apic_cluster) {
genapic = &apic_x2apic_uv_x; if (!intr_remapping_enabled)
else
#ifdef CONFIG_ACPI
/*
* Quirk: some x86_64 machines can only use physical APIC mode
* regardless of how many processors are present (x86_64 ES7000
* is an example).
*/
if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL))
genapic = &apic_physflat;
else
#endif
if (max_physical_apicid < 8)
genapic = &apic_flat; genapic = &apic_flat;
else }
genapic = &apic_physflat;
if (genapic == &apic_flat) {
if (max_physical_apicid >= 8)
genapic = &apic_physflat;
printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name); printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
}
} }
/* Same for both flat and physical. */ /* Same for both flat and physical. */
void send_IPI_self(int vector) void apic_send_IPI_self(int vector)
{ {
__send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL); __send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
} }
int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{ {
if (!strcmp(oem_id, "SGI")) { int i;
if (!strcmp(oem_table_id, "UVL"))
uv_system_type = UV_LEGACY_APIC; for (i = 0; apic_probe[i]; ++i) {
else if (!strcmp(oem_table_id, "UVX")) if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) {
uv_system_type = UV_X2APIC; genapic = apic_probe[i];
else if (!strcmp(oem_table_id, "UVH")) printk(KERN_INFO "Setting APIC routing to %s.\n",
uv_system_type = UV_NON_UNIQUE_APIC; genapic->name);
return 1;
}
} }
return 0; return 0;
} }
unsigned int read_apic_id(void)
{
unsigned int id;
WARN_ON(preemptible() && num_online_cpus() > 1);
id = apic_read(APIC_ID);
if (uv_system_type >= UV_X2APIC)
id |= __get_cpu_var(x2apic_extra_bits);
return id;
}
enum uv_system_type get_uv_system_type(void)
{
return uv_system_type;
}
int is_uv_system(void)
{
return uv_system_type != UV_NONE;
}
EXPORT_SYMBOL_GPL(is_uv_system);

View file

@ -15,9 +15,20 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/hardirq.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/ipi.h> #include <asm/ipi.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#include <mach_apicdef.h>
#ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h>
#endif
static int __init flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
return 1;
}
static cpumask_t flat_target_cpus(void) static cpumask_t flat_target_cpus(void)
{ {
@ -95,9 +106,33 @@ static void flat_send_IPI_all(int vector)
__send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL); __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
} }
static unsigned int get_apic_id(unsigned long x)
{
unsigned int id;
id = (((x)>>24) & 0xFFu);
return id;
}
static unsigned long set_apic_id(unsigned int id)
{
unsigned long x;
x = ((id & 0xFFu)<<24);
return x;
}
static unsigned int read_xapic_id(void)
{
unsigned int id;
id = get_apic_id(apic_read(APIC_ID));
return id;
}
static int flat_apic_id_registered(void) static int flat_apic_id_registered(void)
{ {
return physid_isset(GET_APIC_ID(read_apic_id()), phys_cpu_present_map); return physid_isset(read_xapic_id(), phys_cpu_present_map);
} }
static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask) static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask)
@ -112,6 +147,7 @@ static unsigned int phys_pkg_id(int index_msb)
struct genapic apic_flat = { struct genapic apic_flat = {
.name = "flat", .name = "flat",
.acpi_madt_oem_check = flat_acpi_madt_oem_check,
.int_delivery_mode = dest_LowestPrio, .int_delivery_mode = dest_LowestPrio,
.int_dest_mode = (APIC_DEST_LOGICAL != 0), .int_dest_mode = (APIC_DEST_LOGICAL != 0),
.target_cpus = flat_target_cpus, .target_cpus = flat_target_cpus,
@ -121,8 +157,12 @@ struct genapic apic_flat = {
.send_IPI_all = flat_send_IPI_all, .send_IPI_all = flat_send_IPI_all,
.send_IPI_allbutself = flat_send_IPI_allbutself, .send_IPI_allbutself = flat_send_IPI_allbutself,
.send_IPI_mask = flat_send_IPI_mask, .send_IPI_mask = flat_send_IPI_mask,
.send_IPI_self = apic_send_IPI_self,
.cpu_mask_to_apicid = flat_cpu_mask_to_apicid, .cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
.phys_pkg_id = phys_pkg_id, .phys_pkg_id = phys_pkg_id,
.get_apic_id = get_apic_id,
.set_apic_id = set_apic_id,
.apic_id_mask = (0xFFu<<24),
}; };
/* /*
@ -130,6 +170,21 @@ struct genapic apic_flat = {
* We cannot use logical delivery in this case because the mask * We cannot use logical delivery in this case because the mask
* overflows, so use physical mode. * overflows, so use physical mode.
*/ */
static int __init physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
#ifdef CONFIG_ACPI
/*
* Quirk: some x86_64 machines can only use physical APIC mode
* regardless of how many processors are present (x86_64 ES7000
* is an example).
*/
if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL))
return 1;
#endif
return 0;
}
static cpumask_t physflat_target_cpus(void) static cpumask_t physflat_target_cpus(void)
{ {
@ -176,6 +231,7 @@ static unsigned int physflat_cpu_mask_to_apicid(cpumask_t cpumask)
struct genapic apic_physflat = { struct genapic apic_physflat = {
.name = "physical flat", .name = "physical flat",
.acpi_madt_oem_check = physflat_acpi_madt_oem_check,
.int_delivery_mode = dest_Fixed, .int_delivery_mode = dest_Fixed,
.int_dest_mode = (APIC_DEST_PHYSICAL != 0), .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
.target_cpus = physflat_target_cpus, .target_cpus = physflat_target_cpus,
@ -185,6 +241,10 @@ struct genapic apic_physflat = {
.send_IPI_all = physflat_send_IPI_all, .send_IPI_all = physflat_send_IPI_all,
.send_IPI_allbutself = physflat_send_IPI_allbutself, .send_IPI_allbutself = physflat_send_IPI_allbutself,
.send_IPI_mask = physflat_send_IPI_mask, .send_IPI_mask = physflat_send_IPI_mask,
.send_IPI_self = apic_send_IPI_self,
.cpu_mask_to_apicid = physflat_cpu_mask_to_apicid, .cpu_mask_to_apicid = physflat_cpu_mask_to_apicid,
.phys_pkg_id = phys_pkg_id, .phys_pkg_id = phys_pkg_id,
.get_apic_id = get_apic_id,
.set_apic_id = set_apic_id,
.apic_id_mask = (0xFFu<<24),
}; };

View file

@ -0,0 +1,159 @@
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/dmar.h>
#include <asm/smp.h>
#include <asm/ipi.h>
#include <asm/genapic.h>
DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
if (cpu_has_x2apic)
return 1;
return 0;
}
/* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */
static cpumask_t x2apic_target_cpus(void)
{
return cpumask_of_cpu(0);
}
/*
* for now each logical cpu is in its own vector allocation domain.
*/
static cpumask_t x2apic_vector_allocation_domain(int cpu)
{
cpumask_t domain = CPU_MASK_NONE;
cpu_set(cpu, domain);
return domain;
}
static void __x2apic_send_IPI_dest(unsigned int apicid, int vector,
unsigned int dest)
{
unsigned long cfg;
cfg = __prepare_ICR(0, vector, dest);
/*
* send the IPI.
*/
x2apic_icr_write(cfg, apicid);
}
/*
* for now, we send the IPI's one by one in the cpumask.
* TBD: Based on the cpu mask, we can send the IPI's to the cluster group
* at once. We have 16 cpu's in a cluster. This will minimize IPI register
* writes.
*/
static void x2apic_send_IPI_mask(cpumask_t mask, int vector)
{
unsigned long flags;
unsigned long query_cpu;
local_irq_save(flags);
for_each_cpu_mask(query_cpu, mask) {
__x2apic_send_IPI_dest(per_cpu(x86_cpu_to_logical_apicid, query_cpu),
vector, APIC_DEST_LOGICAL);
}
local_irq_restore(flags);
}
static void x2apic_send_IPI_allbutself(int vector)
{
cpumask_t mask = cpu_online_map;
cpu_clear(smp_processor_id(), mask);
if (!cpus_empty(mask))
x2apic_send_IPI_mask(mask, vector);
}
static void x2apic_send_IPI_all(int vector)
{
x2apic_send_IPI_mask(cpu_online_map, vector);
}
static int x2apic_apic_id_registered(void)
{
return 1;
}
static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask)
{
int cpu;
/*
* We're using fixed IRQ delivery, can only return one phys APIC ID.
* May as well be the first.
*/
cpu = first_cpu(cpumask);
if ((unsigned)cpu < NR_CPUS)
return per_cpu(x86_cpu_to_logical_apicid, cpu);
else
return BAD_APICID;
}
static unsigned int get_apic_id(unsigned long x)
{
unsigned int id;
id = x;
return id;
}
static unsigned long set_apic_id(unsigned int id)
{
unsigned long x;
x = id;
return x;
}
static unsigned int phys_pkg_id(int index_msb)
{
return current_cpu_data.initial_apicid >> index_msb;
}
static void x2apic_send_IPI_self(int vector)
{
apic_write(APIC_SELF_IPI, vector);
}
static void init_x2apic_ldr(void)
{
int cpu = smp_processor_id();
per_cpu(x86_cpu_to_logical_apicid, cpu) = apic_read(APIC_LDR);
return;
}
struct genapic apic_x2apic_cluster = {
.name = "cluster x2apic",
.acpi_madt_oem_check = x2apic_acpi_madt_oem_check,
.int_delivery_mode = dest_LowestPrio,
.int_dest_mode = (APIC_DEST_LOGICAL != 0),
.target_cpus = x2apic_target_cpus,
.vector_allocation_domain = x2apic_vector_allocation_domain,
.apic_id_registered = x2apic_apic_id_registered,
.init_apic_ldr = init_x2apic_ldr,
.send_IPI_all = x2apic_send_IPI_all,
.send_IPI_allbutself = x2apic_send_IPI_allbutself,
.send_IPI_mask = x2apic_send_IPI_mask,
.send_IPI_self = x2apic_send_IPI_self,
.cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid,
.phys_pkg_id = phys_pkg_id,
.get_apic_id = get_apic_id,
.set_apic_id = set_apic_id,
.apic_id_mask = (0xFFFFFFFFu),
};

View file

@ -0,0 +1,154 @@
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/dmar.h>
#include <asm/smp.h>
#include <asm/ipi.h>
#include <asm/genapic.h>
static int x2apic_phys;
static int set_x2apic_phys_mode(char *arg)
{
x2apic_phys = 1;
return 0;
}
early_param("x2apic_phys", set_x2apic_phys_mode);
static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
if (cpu_has_x2apic && x2apic_phys)
return 1;
return 0;
}
/* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */
static cpumask_t x2apic_target_cpus(void)
{
return cpumask_of_cpu(0);
}
static cpumask_t x2apic_vector_allocation_domain(int cpu)
{
cpumask_t domain = CPU_MASK_NONE;
cpu_set(cpu, domain);
return domain;
}
static void __x2apic_send_IPI_dest(unsigned int apicid, int vector,
unsigned int dest)
{
unsigned long cfg;
cfg = __prepare_ICR(0, vector, dest);
/*
* send the IPI.
*/
x2apic_icr_write(cfg, apicid);
}
static void x2apic_send_IPI_mask(cpumask_t mask, int vector)
{
unsigned long flags;
unsigned long query_cpu;
local_irq_save(flags);
for_each_cpu_mask(query_cpu, mask) {
__x2apic_send_IPI_dest(per_cpu(x86_cpu_to_apicid, query_cpu),
vector, APIC_DEST_PHYSICAL);
}
local_irq_restore(flags);
}
static void x2apic_send_IPI_allbutself(int vector)
{
cpumask_t mask = cpu_online_map;
cpu_clear(smp_processor_id(), mask);
if (!cpus_empty(mask))
x2apic_send_IPI_mask(mask, vector);
}
static void x2apic_send_IPI_all(int vector)
{
x2apic_send_IPI_mask(cpu_online_map, vector);
}
static int x2apic_apic_id_registered(void)
{
return 1;
}
static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask)
{
int cpu;
/*
* We're using fixed IRQ delivery, can only return one phys APIC ID.
* May as well be the first.
*/
cpu = first_cpu(cpumask);
if ((unsigned)cpu < NR_CPUS)
return per_cpu(x86_cpu_to_apicid, cpu);
else
return BAD_APICID;
}
static unsigned int get_apic_id(unsigned long x)
{
unsigned int id;
id = x;
return id;
}
static unsigned long set_apic_id(unsigned int id)
{
unsigned long x;
x = id;
return x;
}
static unsigned int phys_pkg_id(int index_msb)
{
return current_cpu_data.initial_apicid >> index_msb;
}
void x2apic_send_IPI_self(int vector)
{
apic_write(APIC_SELF_IPI, vector);
}
void init_x2apic_ldr(void)
{
return;
}
struct genapic apic_x2apic_phys = {
.name = "physical x2apic",
.acpi_madt_oem_check = x2apic_acpi_madt_oem_check,
.int_delivery_mode = dest_Fixed,
.int_dest_mode = (APIC_DEST_PHYSICAL != 0),
.target_cpus = x2apic_target_cpus,
.vector_allocation_domain = x2apic_vector_allocation_domain,
.apic_id_registered = x2apic_apic_id_registered,
.init_apic_ldr = init_x2apic_ldr,
.send_IPI_all = x2apic_send_IPI_all,
.send_IPI_allbutself = x2apic_send_IPI_allbutself,
.send_IPI_mask = x2apic_send_IPI_mask,
.send_IPI_self = x2apic_send_IPI_self,
.cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid,
.phys_pkg_id = phys_pkg_id,
.get_apic_id = get_apic_id,
.set_apic_id = set_apic_id,
.apic_id_mask = (0xFFFFFFFFu),
};

View file

@ -12,12 +12,12 @@
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/hardirq.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/ipi.h> #include <asm/ipi.h>
#include <asm/genapic.h> #include <asm/genapic.h>
@ -26,6 +26,36 @@
#include <asm/uv/uv_hub.h> #include <asm/uv/uv_hub.h>
#include <asm/uv/bios.h> #include <asm/uv/bios.h>
DEFINE_PER_CPU(int, x2apic_extra_bits);
static enum uv_system_type uv_system_type;
static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
if (!strcmp(oem_id, "SGI")) {
if (!strcmp(oem_table_id, "UVL"))
uv_system_type = UV_LEGACY_APIC;
else if (!strcmp(oem_table_id, "UVX"))
uv_system_type = UV_X2APIC;
else if (!strcmp(oem_table_id, "UVH")) {
uv_system_type = UV_NON_UNIQUE_APIC;
return 1;
}
}
return 0;
}
enum uv_system_type get_uv_system_type(void)
{
return uv_system_type;
}
int is_uv_system(void)
{
return uv_system_type != UV_NONE;
}
EXPORT_SYMBOL_GPL(is_uv_system);
DEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); DEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info); EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info);
@ -123,6 +153,10 @@ static int uv_apic_id_registered(void)
return 1; return 1;
} }
static void uv_init_apic_ldr(void)
{
}
static unsigned int uv_cpu_mask_to_apicid(cpumask_t cpumask) static unsigned int uv_cpu_mask_to_apicid(cpumask_t cpumask)
{ {
int cpu; int cpu;
@ -138,9 +172,34 @@ static unsigned int uv_cpu_mask_to_apicid(cpumask_t cpumask)
return BAD_APICID; return BAD_APICID;
} }
static unsigned int get_apic_id(unsigned long x)
{
unsigned int id;
WARN_ON(preemptible() && num_online_cpus() > 1);
id = x | __get_cpu_var(x2apic_extra_bits);
return id;
}
static unsigned long set_apic_id(unsigned int id)
{
unsigned long x;
/* maskout x2apic_extra_bits ? */
x = id;
return x;
}
static unsigned int uv_read_apic_id(void)
{
return get_apic_id(apic_read(APIC_ID));
}
static unsigned int phys_pkg_id(int index_msb) static unsigned int phys_pkg_id(int index_msb)
{ {
return GET_APIC_ID(read_apic_id()) >> index_msb; return uv_read_apic_id() >> index_msb;
} }
#ifdef ZZZ /* Needs x2apic patch */ #ifdef ZZZ /* Needs x2apic patch */
@ -152,17 +211,22 @@ static void uv_send_IPI_self(int vector)
struct genapic apic_x2apic_uv_x = { struct genapic apic_x2apic_uv_x = {
.name = "UV large system", .name = "UV large system",
.acpi_madt_oem_check = uv_acpi_madt_oem_check,
.int_delivery_mode = dest_Fixed, .int_delivery_mode = dest_Fixed,
.int_dest_mode = (APIC_DEST_PHYSICAL != 0), .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
.target_cpus = uv_target_cpus, .target_cpus = uv_target_cpus,
.vector_allocation_domain = uv_vector_allocation_domain,/* Fixme ZZZ */ .vector_allocation_domain = uv_vector_allocation_domain,/* Fixme ZZZ */
.apic_id_registered = uv_apic_id_registered, .apic_id_registered = uv_apic_id_registered,
.init_apic_ldr = uv_init_apic_ldr,
.send_IPI_all = uv_send_IPI_all, .send_IPI_all = uv_send_IPI_all,
.send_IPI_allbutself = uv_send_IPI_allbutself, .send_IPI_allbutself = uv_send_IPI_allbutself,
.send_IPI_mask = uv_send_IPI_mask, .send_IPI_mask = uv_send_IPI_mask,
/* ZZZ.send_IPI_self = uv_send_IPI_self, */ /* ZZZ.send_IPI_self = uv_send_IPI_self, */
.cpu_mask_to_apicid = uv_cpu_mask_to_apicid, .cpu_mask_to_apicid = uv_cpu_mask_to_apicid,
.phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */ .phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */
.get_apic_id = get_apic_id,
.set_apic_id = set_apic_id,
.apic_id_mask = (0xFFFFFFFFu),
}; };
static __cpuinit void set_x2apic_extra_bits(int pnode) static __cpuinit void set_x2apic_extra_bits(int pnode)
@ -401,3 +465,5 @@ void __cpuinit uv_cpu_init(void)
if (get_uv_system_type() == UV_NON_UNIQUE_APIC) if (get_uv_system_type() == UV_NON_UNIQUE_APIC)
set_x2apic_extra_bits(uv_hub_info->pnode); set_x2apic_extra_bits(uv_hub_info->pnode);
} }

View file

@ -21,9 +21,12 @@
# include <asm/sigcontext32.h> # include <asm/sigcontext32.h>
# include <asm/user32.h> # include <asm/user32.h>
#else #else
# define save_i387_ia32 save_i387 # define save_i387_xstate_ia32 save_i387_xstate
# define restore_i387_ia32 restore_i387 # define restore_i387_xstate_ia32 restore_i387_xstate
# define _fpstate_ia32 _fpstate # define _fpstate_ia32 _fpstate
# define _xstate_ia32 _xstate
# define sig_xstate_ia32_size sig_xstate_size
# define fx_sw_reserved_ia32 fx_sw_reserved
# define user_i387_ia32_struct user_i387_struct # define user_i387_ia32_struct user_i387_struct
# define user32_fxsr_struct user_fxsr_struct # define user32_fxsr_struct user_fxsr_struct
#endif #endif
@ -36,6 +39,7 @@
static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
unsigned int xstate_size; unsigned int xstate_size;
unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
static struct i387_fxsave_struct fx_scratch __cpuinitdata; static struct i387_fxsave_struct fx_scratch __cpuinitdata;
void __cpuinit mxcsr_feature_mask_init(void) void __cpuinit mxcsr_feature_mask_init(void)
@ -61,6 +65,11 @@ void __init init_thread_xstate(void)
return; return;
} }
if (cpu_has_xsave) {
xsave_cntxt_init();
return;
}
if (cpu_has_fxsr) if (cpu_has_fxsr)
xstate_size = sizeof(struct i387_fxsave_struct); xstate_size = sizeof(struct i387_fxsave_struct);
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
@ -83,8 +92,18 @@ void __cpuinit fpu_init(void)
write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */ write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */
/*
* Boot processor to setup the FP and extended state context info.
*/
if (!smp_processor_id())
init_thread_xstate();
xsave_init();
mxcsr_feature_mask_init(); mxcsr_feature_mask_init();
/* clean state in init */ /* clean state in init */
if (cpu_has_xsave)
current_thread_info()->status = TS_XSAVE;
else
current_thread_info()->status = 0; current_thread_info()->status = 0;
clear_used_math(); clear_used_math();
} }
@ -195,6 +214,13 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
*/ */
target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
/*
* update the header bits in the xsave header, indicating the
* presence of FP and SSE state.
*/
if (cpu_has_xsave)
target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
return ret; return ret;
} }
@ -395,6 +421,12 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
if (!ret) if (!ret)
convert_to_fxsr(target, &env); convert_to_fxsr(target, &env);
/*
* update the header bit in the xsave header, indicating the
* presence of FP.
*/
if (cpu_has_xsave)
target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FP;
return ret; return ret;
} }
@ -407,7 +439,6 @@ static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave; struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave;
unlazy_fpu(tsk);
fp->status = fp->swd; fp->status = fp->swd;
if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct))) if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
return -1; return -1;
@ -421,8 +452,6 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
struct user_i387_ia32_struct env; struct user_i387_ia32_struct env;
int err = 0; int err = 0;
unlazy_fpu(tsk);
convert_from_fxsr(&env, tsk); convert_from_fxsr(&env, tsk);
if (__copy_to_user(buf, &env, sizeof(env))) if (__copy_to_user(buf, &env, sizeof(env)))
return -1; return -1;
@ -432,16 +461,40 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
if (err) if (err)
return -1; return -1;
if (__copy_to_user(&buf->_fxsr_env[0], fx, if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
sizeof(struct i387_fxsave_struct)))
return -1; return -1;
return 1; return 1;
} }
int save_i387_ia32(struct _fpstate_ia32 __user *buf) static int save_i387_xsave(void __user *buf)
{ {
struct _fpstate_ia32 __user *fx = buf;
int err = 0;
if (save_i387_fxsave(fx) < 0)
return -1;
err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
sizeof(struct _fpx_sw_bytes));
err |= __put_user(FP_XSTATE_MAGIC2,
(__u32 __user *) (buf + sig_xstate_ia32_size
- FP_XSTATE_MAGIC2_SIZE));
if (err)
return -1;
return 1;
}
int save_i387_xstate_ia32(void __user *buf)
{
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
struct task_struct *tsk = current;
if (!used_math()) if (!used_math())
return 0; return 0;
if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
return -EACCES;
/* /*
* This will cause a "finit" to be triggered by the next * This will cause a "finit" to be triggered by the next
* attempted FPU operation by the 'current' process. * attempted FPU operation by the 'current' process.
@ -451,13 +504,17 @@ int save_i387_ia32(struct _fpstate_ia32 __user *buf)
if (!HAVE_HWFP) { if (!HAVE_HWFP) {
return fpregs_soft_get(current, NULL, return fpregs_soft_get(current, NULL,
0, sizeof(struct user_i387_ia32_struct), 0, sizeof(struct user_i387_ia32_struct),
NULL, buf) ? -1 : 1; NULL, fp) ? -1 : 1;
} }
unlazy_fpu(tsk);
if (cpu_has_xsave)
return save_i387_xsave(fp);
if (cpu_has_fxsr) if (cpu_has_fxsr)
return save_i387_fxsave(buf); return save_i387_fxsave(fp);
else else
return save_i387_fsave(buf); return save_i387_fsave(fp);
} }
static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
@ -468,14 +525,15 @@ static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
sizeof(struct i387_fsave_struct)); sizeof(struct i387_fsave_struct));
} }
static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
unsigned int size)
{ {
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct user_i387_ia32_struct env; struct user_i387_ia32_struct env;
int err; int err;
err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0], err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0],
sizeof(struct i387_fxsave_struct)); size);
/* mxcsr reserved bits must be masked to zero for security reasons */ /* mxcsr reserved bits must be masked to zero for security reasons */
tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
if (err || __copy_from_user(&env, buf, sizeof(env))) if (err || __copy_from_user(&env, buf, sizeof(env)))
@ -485,14 +543,69 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
return 0; return 0;
} }
int restore_i387_ia32(struct _fpstate_ia32 __user *buf) static int restore_i387_xsave(void __user *buf)
{
struct _fpx_sw_bytes fx_sw_user;
struct _fpstate_ia32 __user *fx_user =
((struct _fpstate_ia32 __user *) buf);
struct i387_fxsave_struct __user *fx =
(struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
struct xsave_hdr_struct *xsave_hdr =
&current->thread.xstate->xsave.xsave_hdr;
u64 mask;
int err;
if (check_for_xstate(fx, buf, &fx_sw_user))
goto fx_only;
mask = fx_sw_user.xstate_bv;
err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
xsave_hdr->xstate_bv &= pcntxt_mask;
/*
* These bits must be zero.
*/
xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
/*
* Init the state that is not present in the memory layout
* and enabled by the OS.
*/
mask = ~(pcntxt_mask & ~mask);
xsave_hdr->xstate_bv &= mask;
return err;
fx_only:
/*
* Couldn't find the extended state information in the memory
* layout. Restore the FP/SSE and init the other extended state
* enabled by the OS.
*/
xsave_hdr->xstate_bv = XSTATE_FPSSE;
return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
}
int restore_i387_xstate_ia32(void __user *buf)
{ {
int err; int err;
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
if (HAVE_HWFP) if (HAVE_HWFP)
clear_fpu(tsk); clear_fpu(tsk);
if (!buf) {
if (used_math()) {
clear_fpu(tsk);
clear_used_math();
}
return 0;
} else
if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
return -EACCES;
if (!used_math()) { if (!used_math()) {
err = init_fpu(tsk); err = init_fpu(tsk);
if (err) if (err)
@ -500,14 +613,17 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
} }
if (HAVE_HWFP) { if (HAVE_HWFP) {
if (cpu_has_fxsr) if (cpu_has_xsave)
err = restore_i387_fxsave(buf); err = restore_i387_xsave(buf);
else if (cpu_has_fxsr)
err = restore_i387_fxsave(fp, sizeof(struct
i387_fxsave_struct));
else else
err = restore_i387_fsave(buf); err = restore_i387_fsave(fp);
} else { } else {
err = fpregs_soft_set(current, NULL, err = fpregs_soft_set(current, NULL,
0, sizeof(struct user_i387_ia32_struct), 0, sizeof(struct user_i387_ia32_struct),
NULL, buf) != 0; NULL, fp) != 0;
} }
set_used_math(); set_used_math();

View file

@ -282,6 +282,30 @@ static int __init i8259A_init_sysfs(void)
device_initcall(i8259A_init_sysfs); device_initcall(i8259A_init_sysfs);
void mask_8259A(void)
{
unsigned long flags;
spin_lock_irqsave(&i8259A_lock, flags);
outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */
spin_unlock_irqrestore(&i8259A_lock, flags);
}
void unmask_8259A(void)
{
unsigned long flags;
spin_lock_irqsave(&i8259A_lock, flags);
outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */
spin_unlock_irqrestore(&i8259A_lock, flags);
}
void init_8259A(int auto_eoi) void init_8259A(int auto_eoi)
{ {
unsigned long flags; unsigned long flags;

View file

@ -46,10 +46,13 @@
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/msidef.h> #include <asm/msidef.h>
#include <asm/hypertransport.h> #include <asm/hypertransport.h>
#include <asm/setup.h>
#include <mach_apic.h> #include <mach_apic.h>
#include <mach_apicdef.h> #include <mach_apicdef.h>
#define __apicdebuginit(type) static type __init
int (*ioapic_renumber_irq)(int ioapic, int irq); int (*ioapic_renumber_irq)(int ioapic, int irq);
atomic_t irq_mis_count; atomic_t irq_mis_count;
@ -1341,7 +1344,8 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
ioapic_write_entry(apic, pin, entry); ioapic_write_entry(apic, pin, entry);
} }
void __init print_IO_APIC(void)
__apicdebuginit(void) print_IO_APIC(void)
{ {
int apic, i; int apic, i;
union IO_APIC_reg_00 reg_00; union IO_APIC_reg_00 reg_00;
@ -1456,9 +1460,7 @@ void __init print_IO_APIC(void)
return; return;
} }
#if 0 __apicdebuginit(void) print_APIC_bitfield(int base)
static void print_APIC_bitfield(int base)
{ {
unsigned int v; unsigned int v;
int i, j; int i, j;
@ -1479,9 +1481,10 @@ static void print_APIC_bitfield(int base)
} }
} }
void /*__init*/ print_local_APIC(void *dummy) __apicdebuginit(void) print_local_APIC(void *dummy)
{ {
unsigned int v, ver, maxlvt; unsigned int v, ver, maxlvt;
u64 icr;
if (apic_verbosity == APIC_QUIET) if (apic_verbosity == APIC_QUIET)
return; return;
@ -1490,7 +1493,7 @@ void /*__init*/ print_local_APIC(void *dummy)
smp_processor_id(), hard_smp_processor_id()); smp_processor_id(), hard_smp_processor_id());
v = apic_read(APIC_ID); v = apic_read(APIC_ID);
printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v,
GET_APIC_ID(read_apic_id())); GET_APIC_ID(v));
v = apic_read(APIC_LVR); v = apic_read(APIC_LVR);
printk(KERN_INFO "... APIC VERSION: %08x\n", v); printk(KERN_INFO "... APIC VERSION: %08x\n", v);
ver = GET_APIC_VERSION(v); ver = GET_APIC_VERSION(v);
@ -1532,10 +1535,9 @@ void /*__init*/ print_local_APIC(void *dummy)
printk(KERN_DEBUG "... APIC ESR: %08x\n", v); printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
} }
v = apic_read(APIC_ICR); icr = apic_icr_read();
printk(KERN_DEBUG "... APIC ICR: %08x\n", v); printk(KERN_DEBUG "... APIC ICR: %08x\n", icr);
v = apic_read(APIC_ICR2); printk(KERN_DEBUG "... APIC ICR2: %08x\n", icr >> 32);
printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
v = apic_read(APIC_LVTT); v = apic_read(APIC_LVTT);
printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
@ -1563,12 +1565,12 @@ void /*__init*/ print_local_APIC(void *dummy)
printk("\n"); printk("\n");
} }
void print_all_local_APICs(void) __apicdebuginit(void) print_all_local_APICs(void)
{ {
on_each_cpu(print_local_APIC, NULL, 1); on_each_cpu(print_local_APIC, NULL, 1);
} }
void /*__init*/ print_PIC(void) __apicdebuginit(void) print_PIC(void)
{ {
unsigned int v; unsigned int v;
unsigned long flags; unsigned long flags;
@ -1600,7 +1602,17 @@ void /*__init*/ print_PIC(void)
printk(KERN_DEBUG "... PIC ELCR: %04x\n", v); printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
} }
#endif /* 0 */ __apicdebuginit(int) print_all_ICs(void)
{
print_PIC();
print_all_local_APICs();
print_IO_APIC();
return 0;
}
fs_initcall(print_all_ICs);
static void __init enable_IO_APIC(void) static void __init enable_IO_APIC(void)
{ {
@ -1698,8 +1710,7 @@ void disable_IO_APIC(void)
entry.dest_mode = 0; /* Physical */ entry.dest_mode = 0; /* Physical */
entry.delivery_mode = dest_ExtINT; /* ExtInt */ entry.delivery_mode = dest_ExtINT; /* ExtInt */
entry.vector = 0; entry.vector = 0;
entry.dest.physical.physical_dest = entry.dest.physical.physical_dest = read_apic_id();
GET_APIC_ID(read_apic_id());
/* /*
* Add it to the IO-APIC irq-routing table: * Add it to the IO-APIC irq-routing table:
@ -1725,10 +1736,8 @@ static void __init setup_ioapic_ids_from_mpc(void)
unsigned char old_id; unsigned char old_id;
unsigned long flags; unsigned long flags;
#ifdef CONFIG_X86_NUMAQ if (x86_quirks->setup_ioapic_ids && x86_quirks->setup_ioapic_ids())
if (found_numaq)
return; return;
#endif
/* /*
* Don't check I/O APIC IDs for xAPIC systems. They have * Don't check I/O APIC IDs for xAPIC systems. They have
@ -2329,8 +2338,6 @@ void __init setup_IO_APIC(void)
setup_IO_APIC_irqs(); setup_IO_APIC_irqs();
init_IO_APIC_traps(); init_IO_APIC_traps();
check_timer(); check_timer();
if (!acpi_ioapic)
print_IO_APIC();
} }
/* /*

View file

@ -37,6 +37,7 @@
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#endif #endif
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/dmar.h>
#include <asm/idle.h> #include <asm/idle.h>
#include <asm/io.h> #include <asm/io.h>
@ -49,10 +50,13 @@
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/msidef.h> #include <asm/msidef.h>
#include <asm/hypertransport.h> #include <asm/hypertransport.h>
#include <asm/irq_remapping.h>
#include <mach_ipi.h> #include <mach_ipi.h>
#include <mach_apic.h> #include <mach_apic.h>
#define __apicdebuginit(type) static type __init
struct irq_cfg { struct irq_cfg {
cpumask_t domain; cpumask_t domain;
cpumask_t old_domain; cpumask_t old_domain;
@ -87,8 +91,6 @@ int first_system_vector = 0xfe;
char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE}; char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE};
#define __apicdebuginit __init
int sis_apic_bug; /* not actually supported, dummy for compile */ int sis_apic_bug; /* not actually supported, dummy for compile */
static int no_timer_check; static int no_timer_check;
@ -108,6 +110,9 @@ static DEFINE_SPINLOCK(vector_lock);
*/ */
int nr_ioapic_registers[MAX_IO_APICS]; int nr_ioapic_registers[MAX_IO_APICS];
/* I/O APIC RTE contents at the OS boot up */
struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS];
/* I/O APIC entries */ /* I/O APIC entries */
struct mp_config_ioapic mp_ioapics[MAX_IO_APICS]; struct mp_config_ioapic mp_ioapics[MAX_IO_APICS];
int nr_ioapics; int nr_ioapics;
@ -303,6 +308,11 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
pin = entry->pin; pin = entry->pin;
if (pin == -1) if (pin == -1)
break; break;
/*
* With interrupt-remapping, destination information comes
* from interrupt-remapping table entry.
*/
if (!irq_remapped(irq))
io_apic_write(apic, 0x11 + pin*2, dest); io_apic_write(apic, 0x11 + pin*2, dest);
reg = io_apic_read(apic, 0x10 + pin*2); reg = io_apic_read(apic, 0x10 + pin*2);
reg &= ~IO_APIC_REDIR_VECTOR_MASK; reg &= ~IO_APIC_REDIR_VECTOR_MASK;
@ -440,6 +450,69 @@ static void clear_IO_APIC (void)
clear_IO_APIC_pin(apic, pin); clear_IO_APIC_pin(apic, pin);
} }
/*
* Saves and masks all the unmasked IO-APIC RTE's
*/
int save_mask_IO_APIC_setup(void)
{
union IO_APIC_reg_01 reg_01;
unsigned long flags;
int apic, pin;
/*
* The number of IO-APIC IRQ registers (== #pins):
*/
for (apic = 0; apic < nr_ioapics; apic++) {
spin_lock_irqsave(&ioapic_lock, flags);
reg_01.raw = io_apic_read(apic, 1);
spin_unlock_irqrestore(&ioapic_lock, flags);
nr_ioapic_registers[apic] = reg_01.bits.entries+1;
}
for (apic = 0; apic < nr_ioapics; apic++) {
early_ioapic_entries[apic] =
kzalloc(sizeof(struct IO_APIC_route_entry) *
nr_ioapic_registers[apic], GFP_KERNEL);
if (!early_ioapic_entries[apic])
return -ENOMEM;
}
for (apic = 0; apic < nr_ioapics; apic++)
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
struct IO_APIC_route_entry entry;
entry = early_ioapic_entries[apic][pin] =
ioapic_read_entry(apic, pin);
if (!entry.mask) {
entry.mask = 1;
ioapic_write_entry(apic, pin, entry);
}
}
return 0;
}
void restore_IO_APIC_setup(void)
{
int apic, pin;
for (apic = 0; apic < nr_ioapics; apic++)
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
ioapic_write_entry(apic, pin,
early_ioapic_entries[apic][pin]);
}
void reinit_intr_remapped_IO_APIC(int intr_remapping)
{
/*
* for now plain restore of previous settings.
* TBD: In the case of OS enabling interrupt-remapping,
* IO-APIC RTE's need to be setup to point to interrupt-remapping
* table entries. for now, do a plain restore, and wait for
* the setup_IO_APIC_irqs() to do proper initialization.
*/
restore_IO_APIC_setup();
}
int skip_ioapic_setup; int skip_ioapic_setup;
int ioapic_force; int ioapic_force;
@ -839,18 +912,98 @@ void __setup_vector_irq(int cpu)
} }
static struct irq_chip ioapic_chip; static struct irq_chip ioapic_chip;
#ifdef CONFIG_INTR_REMAP
static struct irq_chip ir_ioapic_chip;
#endif
static void ioapic_register_intr(int irq, unsigned long trigger) static void ioapic_register_intr(int irq, unsigned long trigger)
{ {
if (trigger) { if (trigger)
irq_desc[irq].status |= IRQ_LEVEL; irq_desc[irq].status |= IRQ_LEVEL;
set_irq_chip_and_handler_name(irq, &ioapic_chip, else
handle_fasteoi_irq, "fasteoi");
} else {
irq_desc[irq].status &= ~IRQ_LEVEL; irq_desc[irq].status &= ~IRQ_LEVEL;
#ifdef CONFIG_INTR_REMAP
if (irq_remapped(irq)) {
irq_desc[irq].status |= IRQ_MOVE_PCNTXT;
if (trigger)
set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
handle_fasteoi_irq,
"fasteoi");
else
set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
handle_edge_irq, "edge");
return;
}
#endif
if (trigger)
set_irq_chip_and_handler_name(irq, &ioapic_chip,
handle_fasteoi_irq,
"fasteoi");
else
set_irq_chip_and_handler_name(irq, &ioapic_chip, set_irq_chip_and_handler_name(irq, &ioapic_chip,
handle_edge_irq, "edge"); handle_edge_irq, "edge");
}
static int setup_ioapic_entry(int apic, int irq,
struct IO_APIC_route_entry *entry,
unsigned int destination, int trigger,
int polarity, int vector)
{
/*
* add it to the IO-APIC irq-routing table:
*/
memset(entry,0,sizeof(*entry));
#ifdef CONFIG_INTR_REMAP
if (intr_remapping_enabled) {
struct intel_iommu *iommu = map_ioapic_to_ir(apic);
struct irte irte;
struct IR_IO_APIC_route_entry *ir_entry =
(struct IR_IO_APIC_route_entry *) entry;
int index;
if (!iommu)
panic("No mapping iommu for ioapic %d\n", apic);
index = alloc_irte(iommu, irq, 1);
if (index < 0)
panic("Failed to allocate IRTE for ioapic %d\n", apic);
memset(&irte, 0, sizeof(irte));
irte.present = 1;
irte.dst_mode = INT_DEST_MODE;
irte.trigger_mode = trigger;
irte.dlvry_mode = INT_DELIVERY_MODE;
irte.vector = vector;
irte.dest_id = IRTE_DEST(destination);
modify_irte(irq, &irte);
ir_entry->index2 = (index >> 15) & 0x1;
ir_entry->zero = 0;
ir_entry->format = 1;
ir_entry->index = (index & 0x7fff);
} else
#endif
{
entry->delivery_mode = INT_DELIVERY_MODE;
entry->dest_mode = INT_DEST_MODE;
entry->dest = destination;
} }
entry->mask = 0; /* enable IRQ */
entry->trigger = trigger;
entry->polarity = polarity;
entry->vector = vector;
/* Mask level triggered irqs.
* Use IRQ_DELAYED_DISABLE for edge triggered irqs.
*/
if (trigger)
entry->mask = 1;
return 0;
} }
static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
@ -875,24 +1028,15 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
apic, mp_ioapics[apic].mp_apicid, pin, cfg->vector, apic, mp_ioapics[apic].mp_apicid, pin, cfg->vector,
irq, trigger, polarity); irq, trigger, polarity);
/*
* add it to the IO-APIC irq-routing table:
*/
memset(&entry,0,sizeof(entry));
entry.delivery_mode = INT_DELIVERY_MODE; if (setup_ioapic_entry(mp_ioapics[apic].mp_apicid, irq, &entry,
entry.dest_mode = INT_DEST_MODE; cpu_mask_to_apicid(mask), trigger, polarity,
entry.dest = cpu_mask_to_apicid(mask); cfg->vector)) {
entry.mask = 0; /* enable IRQ */ printk("Failed to setup ioapic entry for ioapic %d, pin %d\n",
entry.trigger = trigger; mp_ioapics[apic].mp_apicid, pin);
entry.polarity = polarity; __clear_irq_vector(irq);
entry.vector = cfg->vector; return;
}
/* Mask level triggered irqs.
* Use IRQ_DELAYED_DISABLE for edge triggered irqs.
*/
if (trigger)
entry.mask = 1;
ioapic_register_intr(irq, trigger); ioapic_register_intr(irq, trigger);
if (irq < 16) if (irq < 16)
@ -944,6 +1088,9 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
{ {
struct IO_APIC_route_entry entry; struct IO_APIC_route_entry entry;
if (intr_remapping_enabled)
return;
memset(&entry, 0, sizeof(entry)); memset(&entry, 0, sizeof(entry));
/* /*
@ -970,7 +1117,8 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
ioapic_write_entry(apic, pin, entry); ioapic_write_entry(apic, pin, entry);
} }
void __apicdebuginit print_IO_APIC(void)
__apicdebuginit(void) print_IO_APIC(void)
{ {
int apic, i; int apic, i;
union IO_APIC_reg_00 reg_00; union IO_APIC_reg_00 reg_00;
@ -1064,9 +1212,7 @@ void __apicdebuginit print_IO_APIC(void)
return; return;
} }
#if 0 __apicdebuginit(void) print_APIC_bitfield(int base)
static __apicdebuginit void print_APIC_bitfield (int base)
{ {
unsigned int v; unsigned int v;
int i, j; int i, j;
@ -1087,9 +1233,10 @@ static __apicdebuginit void print_APIC_bitfield (int base)
} }
} }
void __apicdebuginit print_local_APIC(void * dummy) __apicdebuginit(void) print_local_APIC(void *dummy)
{ {
unsigned int v, ver, maxlvt; unsigned int v, ver, maxlvt;
unsigned long icr;
if (apic_verbosity == APIC_QUIET) if (apic_verbosity == APIC_QUIET)
return; return;
@ -1097,7 +1244,7 @@ void __apicdebuginit print_local_APIC(void * dummy)
printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
smp_processor_id(), hard_smp_processor_id()); smp_processor_id(), hard_smp_processor_id());
v = apic_read(APIC_ID); v = apic_read(APIC_ID);
printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(read_apic_id())); printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, read_apic_id());
v = apic_read(APIC_LVR); v = apic_read(APIC_LVR);
printk(KERN_INFO "... APIC VERSION: %08x\n", v); printk(KERN_INFO "... APIC VERSION: %08x\n", v);
ver = GET_APIC_VERSION(v); ver = GET_APIC_VERSION(v);
@ -1133,10 +1280,9 @@ void __apicdebuginit print_local_APIC(void * dummy)
v = apic_read(APIC_ESR); v = apic_read(APIC_ESR);
printk(KERN_DEBUG "... APIC ESR: %08x\n", v); printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
v = apic_read(APIC_ICR); icr = apic_icr_read();
printk(KERN_DEBUG "... APIC ICR: %08x\n", v); printk(KERN_DEBUG "... APIC ICR: %08x\n", icr);
v = apic_read(APIC_ICR2); printk(KERN_DEBUG "... APIC ICR2: %08x\n", icr >> 32);
printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);
v = apic_read(APIC_LVTT); v = apic_read(APIC_LVTT);
printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
@ -1164,12 +1310,12 @@ void __apicdebuginit print_local_APIC(void * dummy)
printk("\n"); printk("\n");
} }
void print_all_local_APICs (void) __apicdebuginit(void) print_all_local_APICs(void)
{ {
on_each_cpu(print_local_APIC, NULL, 1); on_each_cpu(print_local_APIC, NULL, 1);
} }
void __apicdebuginit print_PIC(void) __apicdebuginit(void) print_PIC(void)
{ {
unsigned int v; unsigned int v;
unsigned long flags; unsigned long flags;
@ -1201,7 +1347,17 @@ void __apicdebuginit print_PIC(void)
printk(KERN_DEBUG "... PIC ELCR: %04x\n", v); printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
} }
#endif /* 0 */ __apicdebuginit(int) print_all_ICs(void)
{
print_PIC();
print_all_local_APICs();
print_IO_APIC();
return 0;
}
fs_initcall(print_all_ICs);
void __init enable_IO_APIC(void) void __init enable_IO_APIC(void)
{ {
@ -1291,7 +1447,7 @@ void disable_IO_APIC(void)
entry.dest_mode = 0; /* Physical */ entry.dest_mode = 0; /* Physical */
entry.delivery_mode = dest_ExtINT; /* ExtInt */ entry.delivery_mode = dest_ExtINT; /* ExtInt */
entry.vector = 0; entry.vector = 0;
entry.dest = GET_APIC_ID(read_apic_id()); entry.dest = read_apic_id();
/* /*
* Add it to the IO-APIC irq-routing table: * Add it to the IO-APIC irq-routing table:
@ -1397,6 +1553,147 @@ static int ioapic_retrigger_irq(unsigned int irq)
*/ */
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#ifdef CONFIG_INTR_REMAP
static void ir_irq_migration(struct work_struct *work);
static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration);
/*
* Migrate the IO-APIC irq in the presence of intr-remapping.
*
* For edge triggered, irq migration is a simple atomic update(of vector
* and cpu destination) of IRTE and flush the hardware cache.
*
* For level triggered, we need to modify the io-apic RTE aswell with the update
* vector information, along with modifying IRTE with vector and destination.
* So irq migration for level triggered is little bit more complex compared to
* edge triggered migration. But the good news is, we use the same algorithm
* for level triggered migration as we have today, only difference being,
* we now initiate the irq migration from process context instead of the
* interrupt context.
*
* In future, when we do a directed EOI (combined with cpu EOI broadcast
* suppression) to the IO-APIC, level triggered irq migration will also be
* as simple as edge triggered migration and we can do the irq migration
* with a simple atomic update to IO-APIC RTE.
*/
static void migrate_ioapic_irq(int irq, cpumask_t mask)
{
struct irq_cfg *cfg = irq_cfg + irq;
struct irq_desc *desc = irq_desc + irq;
cpumask_t tmp, cleanup_mask;
struct irte irte;
int modify_ioapic_rte = desc->status & IRQ_LEVEL;
unsigned int dest;
unsigned long flags;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return;
if (get_irte(irq, &irte))
return;
if (assign_irq_vector(irq, mask))
return;
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
if (modify_ioapic_rte) {
spin_lock_irqsave(&ioapic_lock, flags);
__target_IO_APIC_irq(irq, dest, cfg->vector);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
irte.vector = cfg->vector;
irte.dest_id = IRTE_DEST(dest);
/*
* Modified the IRTE and flushes the Interrupt entry cache.
*/
modify_irte(irq, &irte);
if (cfg->move_in_progress) {
cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
cfg->move_cleanup_count = cpus_weight(cleanup_mask);
send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
cfg->move_in_progress = 0;
}
irq_desc[irq].affinity = mask;
}
static int migrate_irq_remapped_level(int irq)
{
int ret = -1;
mask_IO_APIC_irq(irq);
if (io_apic_level_ack_pending(irq)) {
/*
* Interrupt in progress. Migrating irq now will change the
* vector information in the IO-APIC RTE and that will confuse
* the EOI broadcast performed by cpu.
* So, delay the irq migration to the next instance.
*/
schedule_delayed_work(&ir_migration_work, 1);
goto unmask;
}
/* everthing is clear. we have right of way */
migrate_ioapic_irq(irq, irq_desc[irq].pending_mask);
ret = 0;
irq_desc[irq].status &= ~IRQ_MOVE_PENDING;
cpus_clear(irq_desc[irq].pending_mask);
unmask:
unmask_IO_APIC_irq(irq);
return ret;
}
static void ir_irq_migration(struct work_struct *work)
{
int irq;
for (irq = 0; irq < NR_IRQS; irq++) {
struct irq_desc *desc = irq_desc + irq;
if (desc->status & IRQ_MOVE_PENDING) {
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
if (!desc->chip->set_affinity ||
!(desc->status & IRQ_MOVE_PENDING)) {
desc->status &= ~IRQ_MOVE_PENDING;
spin_unlock_irqrestore(&desc->lock, flags);
continue;
}
desc->chip->set_affinity(irq,
irq_desc[irq].pending_mask);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
}
/*
* Migrates the IRQ destination in the process context.
*/
static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
{
if (irq_desc[irq].status & IRQ_LEVEL) {
irq_desc[irq].status |= IRQ_MOVE_PENDING;
irq_desc[irq].pending_mask = mask;
migrate_irq_remapped_level(irq);
return;
}
migrate_ioapic_irq(irq, mask);
}
#endif
asmlinkage void smp_irq_move_cleanup_interrupt(void) asmlinkage void smp_irq_move_cleanup_interrupt(void)
{ {
unsigned vector, me; unsigned vector, me;
@ -1453,6 +1750,17 @@ static void irq_complete_move(unsigned int irq)
#else #else
static inline void irq_complete_move(unsigned int irq) {} static inline void irq_complete_move(unsigned int irq) {}
#endif #endif
#ifdef CONFIG_INTR_REMAP
static void ack_x2apic_level(unsigned int irq)
{
ack_x2APIC_irq();
}
static void ack_x2apic_edge(unsigned int irq)
{
ack_x2APIC_irq();
}
#endif
static void ack_apic_edge(unsigned int irq) static void ack_apic_edge(unsigned int irq)
{ {
@ -1527,6 +1835,21 @@ static struct irq_chip ioapic_chip __read_mostly = {
.retrigger = ioapic_retrigger_irq, .retrigger = ioapic_retrigger_irq,
}; };
#ifdef CONFIG_INTR_REMAP
static struct irq_chip ir_ioapic_chip __read_mostly = {
.name = "IR-IO-APIC",
.startup = startup_ioapic_irq,
.mask = mask_IO_APIC_irq,
.unmask = unmask_IO_APIC_irq,
.ack = ack_x2apic_edge,
.eoi = ack_x2apic_level,
#ifdef CONFIG_SMP
.set_affinity = set_ir_ioapic_affinity_irq,
#endif
.retrigger = ioapic_retrigger_irq,
};
#endif
static inline void init_IO_APIC_traps(void) static inline void init_IO_APIC_traps(void)
{ {
int irq; int irq;
@ -1712,6 +2035,8 @@ static inline void __init check_timer(void)
* 8259A. * 8259A.
*/ */
if (pin1 == -1) { if (pin1 == -1) {
if (intr_remapping_enabled)
panic("BIOS bug: timer not connected to IO-APIC");
pin1 = pin2; pin1 = pin2;
apic1 = apic2; apic1 = apic2;
no_pin1 = 1; no_pin1 = 1;
@ -1738,6 +2063,8 @@ static inline void __init check_timer(void)
clear_IO_APIC_pin(0, pin1); clear_IO_APIC_pin(0, pin1);
goto out; goto out;
} }
if (intr_remapping_enabled)
panic("timer doesn't work through Interrupt-remapped IO-APIC");
clear_IO_APIC_pin(apic1, pin1); clear_IO_APIC_pin(apic1, pin1);
if (!no_pin1) if (!no_pin1)
apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: " apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: "
@ -1854,8 +2181,6 @@ void __init setup_IO_APIC(void)
setup_IO_APIC_irqs(); setup_IO_APIC_irqs();
init_IO_APIC_traps(); init_IO_APIC_traps();
check_timer(); check_timer();
if (!acpi_ioapic)
print_IO_APIC();
} }
struct sysfs_ioapic_data { struct sysfs_ioapic_data {
@ -1977,6 +2302,9 @@ void destroy_irq(unsigned int irq)
dynamic_irq_cleanup(irq); dynamic_irq_cleanup(irq);
#ifdef CONFIG_INTR_REMAP
free_irte(irq);
#endif
spin_lock_irqsave(&vector_lock, flags); spin_lock_irqsave(&vector_lock, flags);
__clear_irq_vector(irq); __clear_irq_vector(irq);
spin_unlock_irqrestore(&vector_lock, flags); spin_unlock_irqrestore(&vector_lock, flags);
@ -1995,10 +2323,41 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
tmp = TARGET_CPUS; tmp = TARGET_CPUS;
err = assign_irq_vector(irq, tmp); err = assign_irq_vector(irq, tmp);
if (!err) { if (err)
return err;
cpus_and(tmp, cfg->domain, tmp); cpus_and(tmp, cfg->domain, tmp);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
#ifdef CONFIG_INTR_REMAP
if (irq_remapped(irq)) {
struct irte irte;
int ir_index;
u16 sub_handle;
ir_index = map_irq_to_irte_handle(irq, &sub_handle);
BUG_ON(ir_index == -1);
memset (&irte, 0, sizeof(irte));
irte.present = 1;
irte.dst_mode = INT_DEST_MODE;
irte.trigger_mode = 0; /* edge */
irte.dlvry_mode = INT_DELIVERY_MODE;
irte.vector = cfg->vector;
irte.dest_id = IRTE_DEST(dest);
modify_irte(irq, &irte);
msg->address_hi = MSI_ADDR_BASE_HI;
msg->data = sub_handle;
msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
MSI_ADDR_IR_SHV |
MSI_ADDR_IR_INDEX1(ir_index) |
MSI_ADDR_IR_INDEX2(ir_index);
} else
#endif
{
msg->address_hi = MSI_ADDR_BASE_HI; msg->address_hi = MSI_ADDR_BASE_HI;
msg->address_lo = msg->address_lo =
MSI_ADDR_BASE_LO | MSI_ADDR_BASE_LO |
@ -2049,6 +2408,55 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
write_msi_msg(irq, &msg); write_msi_msg(irq, &msg);
irq_desc[irq].affinity = mask; irq_desc[irq].affinity = mask;
} }
#ifdef CONFIG_INTR_REMAP
/*
* Migrate the MSI irq to another cpumask. This migration is
* done in the process context using interrupt-remapping hardware.
*/
static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
{
struct irq_cfg *cfg = irq_cfg + irq;
unsigned int dest;
cpumask_t tmp, cleanup_mask;
struct irte irte;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return;
if (get_irte(irq, &irte))
return;
if (assign_irq_vector(irq, mask))
return;
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
irte.vector = cfg->vector;
irte.dest_id = IRTE_DEST(dest);
/*
* atomically update the IRTE with the new destination and vector.
*/
modify_irte(irq, &irte);
/*
* After this point, all the interrupts will start arriving
* at the new destination. So, time to cleanup the previous
* vector allocation.
*/
if (cfg->move_in_progress) {
cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
cfg->move_cleanup_count = cpus_weight(cleanup_mask);
send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
cfg->move_in_progress = 0;
}
irq_desc[irq].affinity = mask;
}
#endif
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
/* /*
@ -2066,28 +2474,159 @@ static struct irq_chip msi_chip = {
.retrigger = ioapic_retrigger_irq, .retrigger = ioapic_retrigger_irq,
}; };
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) #ifdef CONFIG_INTR_REMAP
static struct irq_chip msi_ir_chip = {
.name = "IR-PCI-MSI",
.unmask = unmask_msi_irq,
.mask = mask_msi_irq,
.ack = ack_x2apic_edge,
#ifdef CONFIG_SMP
.set_affinity = ir_set_msi_irq_affinity,
#endif
.retrigger = ioapic_retrigger_irq,
};
/*
* Map the PCI dev to the corresponding remapping hardware unit
* and allocate 'nvec' consecutive interrupt-remapping table entries
* in it.
*/
static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
{ {
struct intel_iommu *iommu;
int index;
iommu = map_dev_to_ir(dev);
if (!iommu) {
printk(KERN_ERR
"Unable to map PCI %s to iommu\n", pci_name(dev));
return -ENOENT;
}
index = alloc_irte(iommu, irq, nvec);
if (index < 0) {
printk(KERN_ERR
"Unable to allocate %d IRTE for PCI %s\n", nvec,
pci_name(dev));
return -ENOSPC;
}
return index;
}
#endif
static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
{
int ret;
struct msi_msg msg; struct msi_msg msg;
int irq, ret;
irq = create_irq();
if (irq < 0)
return irq;
ret = msi_compose_msg(dev, irq, &msg); ret = msi_compose_msg(dev, irq, &msg);
if (ret < 0) { if (ret < 0)
destroy_irq(irq);
return ret; return ret;
}
set_irq_msi(irq, desc); set_irq_msi(irq, desc);
write_msi_msg(irq, &msg); write_msi_msg(irq, &msg);
#ifdef CONFIG_INTR_REMAP
if (irq_remapped(irq)) {
struct irq_desc *desc = irq_desc + irq;
/*
* irq migration in process context
*/
desc->status |= IRQ_MOVE_PCNTXT;
set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge");
} else
#endif
set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
return 0; return 0;
} }
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
{
int irq, ret;
irq = create_irq();
if (irq < 0)
return irq;
#ifdef CONFIG_INTR_REMAP
if (!intr_remapping_enabled)
goto no_ir;
ret = msi_alloc_irte(dev, irq, 1);
if (ret < 0)
goto error;
no_ir:
#endif
ret = setup_msi_irq(dev, desc, irq);
if (ret < 0) {
destroy_irq(irq);
return ret;
}
return 0;
#ifdef CONFIG_INTR_REMAP
error:
destroy_irq(irq);
return ret;
#endif
}
int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
int irq, ret, sub_handle;
struct msi_desc *desc;
#ifdef CONFIG_INTR_REMAP
struct intel_iommu *iommu = 0;
int index = 0;
#endif
sub_handle = 0;
list_for_each_entry(desc, &dev->msi_list, list) {
irq = create_irq();
if (irq < 0)
return irq;
#ifdef CONFIG_INTR_REMAP
if (!intr_remapping_enabled)
goto no_ir;
if (!sub_handle) {
/*
* allocate the consecutive block of IRTE's
* for 'nvec'
*/
index = msi_alloc_irte(dev, irq, nvec);
if (index < 0) {
ret = index;
goto error;
}
} else {
iommu = map_dev_to_ir(dev);
if (!iommu) {
ret = -ENOENT;
goto error;
}
/*
* setup the mapping between the irq and the IRTE
* base index, the sub_handle pointing to the
* appropriate interrupt remap table entry.
*/
set_irte_irq(irq, iommu, index, sub_handle);
}
no_ir:
#endif
ret = setup_msi_irq(dev, desc, irq);
if (ret < 0)
goto error;
sub_handle++;
}
return 0;
error:
destroy_irq(irq);
return ret;
}
void arch_teardown_msi_irq(unsigned int irq) void arch_teardown_msi_irq(unsigned int irq)
{ {
destroy_irq(irq); destroy_irq(irq);
@ -2333,6 +2872,10 @@ void __init setup_ioapic_dest(void)
setup_IO_APIC_irq(ioapic, pin, irq, setup_IO_APIC_irq(ioapic, pin, irq,
irq_trigger(irq_entry), irq_trigger(irq_entry),
irq_polarity(irq_entry)); irq_polarity(irq_entry));
#ifdef CONFIG_INTR_REMAP
else if (intr_remapping_enabled)
set_ir_ioapic_affinity_irq(irq, TARGET_CPUS);
#endif
else else
set_ioapic_affinity_irq(irq, TARGET_CPUS); set_ioapic_affinity_irq(irq, TARGET_CPUS);
} }

View file

@ -14,6 +14,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/thread_info.h> #include <linux/thread_info.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <asm/syscalls.h>
/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
static void set_bitmap(unsigned long *bitmap, unsigned int base, static void set_bitmap(unsigned long *bitmap, unsigned int base,

View file

@ -20,6 +20,8 @@
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
#include <mach_apic.h> #include <mach_apic.h>
#include <mach_ipi.h>
/* /*
* the following functions deal with sending IPIs between CPUs. * the following functions deal with sending IPIs between CPUs.
* *
@ -147,7 +149,6 @@ void send_IPI_mask_sequence(cpumask_t mask, int vector)
} }
/* must come after the send_IPI functions above for inlining */ /* must come after the send_IPI functions above for inlining */
#include <mach_ipi.h>
static int convert_apicid_to_cpu(int apic_id) static int convert_apicid_to_cpu(int apic_id)
{ {
int i; int i;

View file

@ -74,6 +74,15 @@ void __init init_ISA_irqs (void)
} }
} }
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
static struct irqaction irq2 = {
.handler = no_action,
.mask = CPU_MASK_NONE,
.name = "cascade",
};
/* Overridden in paravirt.c */ /* Overridden in paravirt.c */
void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ"))); void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
@ -98,6 +107,46 @@ void __init native_init_IRQ(void)
set_intr_gate(vector, interrupt[i]); set_intr_gate(vector, interrupt[i]);
} }
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_SMP)
/*
* IRQ0 must be given a fixed assignment and initialized,
* because it's used before the IO-APIC is set up.
*/
set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
/*
* The reschedule interrupt is a CPU-to-CPU reschedule-helper
* IPI, driven by wakeup.
*/
alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
/* IPI for invalidation */
alloc_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
/* IPI for generic function call */
alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
/* IPI for single call function */
set_intr_gate(CALL_FUNCTION_SINGLE_VECTOR, call_function_single_interrupt);
#endif
#ifdef CONFIG_X86_LOCAL_APIC
/* self generated IPI for local APIC timer */
alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
/* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
#endif
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_MCE_P4THERMAL)
/* thermal monitor LVT interrupt */
alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
#endif
if (!acpi_ioapic)
setup_irq(2, &irq2);
/* setup after call gates are initialised (usually add in /* setup after call gates are initialised (usually add in
* the architecture specific gates) * the architecture specific gates)
*/ */

View file

@ -18,6 +18,7 @@
#include <asm/ldt.h> #include <asm/ldt.h>
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/syscalls.h>
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static void flush_ldt(void *current_mm) static void flush_ldt(void *current_mm)

View file

@ -397,7 +397,9 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
generic_bigsmp_probe(); generic_bigsmp_probe();
#endif #endif
#ifdef CONFIG_X86_32
setup_apic_routing(); setup_apic_routing();
#endif
if (!num_processors) if (!num_processors)
printk(KERN_ERR "MPTABLE: no processors registered!\n"); printk(KERN_ERR "MPTABLE: no processors registered!\n");
return num_processors; return num_processors;

View file

@ -229,6 +229,12 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable,
} }
} }
static int __init numaq_setup_ioapic_ids(void)
{
/* so can skip it */
return 1;
}
static struct x86_quirks numaq_x86_quirks __initdata = { static struct x86_quirks numaq_x86_quirks __initdata = {
.arch_pre_time_init = numaq_pre_time_init, .arch_pre_time_init = numaq_pre_time_init,
.arch_time_init = NULL, .arch_time_init = NULL,
@ -243,6 +249,7 @@ static struct x86_quirks numaq_x86_quirks __initdata = {
.mpc_oem_bus_info = mpc_oem_bus_info, .mpc_oem_bus_info = mpc_oem_bus_info,
.mpc_oem_pci_bus = mpc_oem_pci_bus, .mpc_oem_pci_bus = mpc_oem_pci_bus,
.smp_read_mpc_oem = smp_read_mpc_oem, .smp_read_mpc_oem = smp_read_mpc_oem,
.setup_ioapic_ids = numaq_setup_ioapic_ids,
}; };
void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem, void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,

View file

@ -330,6 +330,7 @@ struct pv_cpu_ops pv_cpu_ops = {
#endif #endif
.wbinvd = native_wbinvd, .wbinvd = native_wbinvd,
.read_msr = native_read_msr_safe, .read_msr = native_read_msr_safe,
.read_msr_amd = native_read_msr_amd_safe,
.write_msr = native_write_msr_safe, .write_msr = native_write_msr_safe,
.read_tsc = native_read_tsc, .read_tsc = native_read_tsc,
.read_pmc = native_read_pmc, .read_pmc = native_read_pmc,
@ -373,8 +374,6 @@ struct pv_cpu_ops pv_cpu_ops = {
struct pv_apic_ops pv_apic_ops = { struct pv_apic_ops pv_apic_ops = {
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
.apic_write = native_apic_write,
.apic_read = native_apic_read,
.setup_boot_clock = setup_boot_APIC_clock, .setup_boot_clock = setup_boot_APIC_clock,
.setup_secondary_clock = setup_secondary_APIC_clock, .setup_secondary_clock = setup_secondary_APIC_clock,
.startup_ipi_hook = paravirt_nop, .startup_ipi_hook = paravirt_nop,

View file

@ -55,6 +55,8 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/cpu.h> #include <asm/cpu.h>
#include <asm/kdebug.h> #include <asm/kdebug.h>
#include <asm/syscalls.h>
#include <asm/smp.h>
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");

View file

@ -51,6 +51,7 @@
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/ia32.h> #include <asm/ia32.h>
#include <asm/idle.h> #include <asm/idle.h>
#include <asm/syscalls.h>
asmlinkage extern void ret_from_fork(void); asmlinkage extern void ret_from_fork(void);

View file

@ -69,7 +69,7 @@ static inline bool invalid_selector(u16 value)
#define FLAG_MASK FLAG_MASK_32 #define FLAG_MASK FLAG_MASK_32
static long *pt_regs_access(struct pt_regs *regs, unsigned long regno) static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
{ {
BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0); BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
regno >>= 2; regno >>= 2;

View file

@ -739,6 +739,8 @@ void __init setup_arch(char **cmdline_p)
num_physpages = max_pfn; num_physpages = max_pfn;
check_efer(); check_efer();
if (cpu_has_x2apic)
check_x2apic();
/* How many end-of-memory variables you have, grandma! */ /* How many end-of-memory variables you have, grandma! */
/* need this before calling reserve_initrd */ /* need this before calling reserve_initrd */

View file

@ -162,9 +162,16 @@ void __init setup_per_cpu_areas(void)
printk(KERN_INFO printk(KERN_INFO
"cpu %d has no node %d or node-local memory\n", "cpu %d has no node %d or node-local memory\n",
cpu, node); cpu, node);
if (ptr)
printk(KERN_DEBUG "per cpu data for cpu%d at %016lx\n",
cpu, __pa(ptr));
} }
else else {
ptr = alloc_bootmem_pages_node(NODE_DATA(node), size); ptr = alloc_bootmem_pages_node(NODE_DATA(node), size);
if (ptr)
printk(KERN_DEBUG "per cpu data for cpu%d on node%d at %016lx\n",
cpu, node, __pa(ptr));
}
#endif #endif
per_cpu_offset(cpu) = ptr - __per_cpu_start; per_cpu_offset(cpu) = ptr - __per_cpu_start;
memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);

View file

@ -3,9 +3,18 @@ struct sigframe {
char __user *pretcode; char __user *pretcode;
int sig; int sig;
struct sigcontext sc; struct sigcontext sc;
struct _fpstate fpstate; /*
* fpstate is unused. fpstate is moved/allocated after
* retcode[] below. This movement allows to have the FP state and the
* future state extensions (xsave) stay together.
* And at the same time retaining the unused fpstate, prevents changing
* the offset of extramask[] in the sigframe and thus prevent any
* legacy application accessing/modifying it.
*/
struct _fpstate fpstate_unused;
unsigned long extramask[_NSIG_WORDS-1]; unsigned long extramask[_NSIG_WORDS-1];
char retcode[8]; char retcode[8];
/* fp state follows here */
}; };
struct rt_sigframe { struct rt_sigframe {
@ -15,13 +24,14 @@ struct rt_sigframe {
void __user *puc; void __user *puc;
struct siginfo info; struct siginfo info;
struct ucontext uc; struct ucontext uc;
struct _fpstate fpstate;
char retcode[8]; char retcode[8];
/* fp state follows here */
}; };
#else #else
struct rt_sigframe { struct rt_sigframe {
char __user *pretcode; char __user *pretcode;
struct ucontext uc; struct ucontext uc;
struct siginfo info; struct siginfo info;
/* fp state follows here */
}; };
#endif #endif

View file

@ -26,6 +26,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/i387.h> #include <asm/i387.h>
#include <asm/vdso.h> #include <asm/vdso.h>
#include <asm/syscalls.h>
#include "sigframe.h" #include "sigframe.h"
@ -159,28 +160,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
} }
{ {
struct _fpstate __user *buf; void __user *buf;
err |= __get_user(buf, &sc->fpstate); err |= __get_user(buf, &sc->fpstate);
if (buf) { err |= restore_i387_xstate(buf);
if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
goto badframe;
err |= restore_i387(buf);
} else {
struct task_struct *me = current;
if (used_math()) {
clear_fpu(me);
clear_used_math();
}
}
} }
err |= __get_user(*pax, &sc->ax); err |= __get_user(*pax, &sc->ax);
return err; return err;
badframe:
return 1;
} }
asmlinkage unsigned long sys_sigreturn(unsigned long __unused) asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
@ -262,7 +249,7 @@ badframe:
* Set up a signal frame. * Set up a signal frame.
*/ */
static int static int
setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
struct pt_regs *regs, unsigned long mask) struct pt_regs *regs, unsigned long mask)
{ {
int tmp, err = 0; int tmp, err = 0;
@ -289,7 +276,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
err |= __put_user(regs->sp, &sc->sp_at_signal); err |= __put_user(regs->sp, &sc->sp_at_signal);
err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
tmp = save_i387(fpstate); tmp = save_i387_xstate(fpstate);
if (tmp < 0) if (tmp < 0)
err = 1; err = 1;
else else
@ -306,7 +293,8 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
* Determine which stack to use.. * Determine which stack to use..
*/ */
static inline void __user * static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
void **fpstate)
{ {
unsigned long sp; unsigned long sp;
@ -332,6 +320,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
sp = (unsigned long) ka->sa.sa_restorer; sp = (unsigned long) ka->sa.sa_restorer;
} }
if (used_math()) {
sp = sp - sig_xstate_size;
*fpstate = (struct _fpstate *) sp;
}
sp -= frame_size; sp -= frame_size;
/* /*
* Align the stack pointer according to the i386 ABI, * Align the stack pointer according to the i386 ABI,
@ -350,8 +343,9 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
void __user *restorer; void __user *restorer;
int err = 0; int err = 0;
int usig; int usig;
void __user *fpstate = NULL;
frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
@ -366,7 +360,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
@ -427,8 +421,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
void __user *restorer; void __user *restorer;
int err = 0; int err = 0;
int usig; int usig;
void __user *fpstate = NULL;
frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
@ -447,13 +442,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv; goto give_sigsegv;
/* Create the ucontext. */ /* Create the ucontext. */
if (cpu_has_xsave)
err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
else
err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->sp), err |= __put_user(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags); &frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]); regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err) if (err)

View file

@ -26,6 +26,7 @@
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/ia32_unistd.h> #include <asm/ia32_unistd.h>
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/syscalls.h>
#include "sigframe.h" #include "sigframe.h"
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@ -53,69 +54,6 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
return do_sigaltstack(uss, uoss, regs->sp); return do_sigaltstack(uss, uoss, regs->sp);
} }
/*
* Signal frame handlers.
*/
static inline int save_i387(struct _fpstate __user *buf)
{
struct task_struct *tsk = current;
int err = 0;
BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
sizeof(tsk->thread.xstate->fxsave));
if ((unsigned long)buf % 16)
printk("save_i387: bad fpstate %p\n", buf);
if (!used_math())
return 0;
clear_used_math(); /* trigger finit */
if (task_thread_info(tsk)->status & TS_USEDFPU) {
err = save_i387_checking((struct i387_fxsave_struct __user *)
buf);
if (err)
return err;
task_thread_info(tsk)->status &= ~TS_USEDFPU;
stts();
} else {
if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
sizeof(struct i387_fxsave_struct)))
return -1;
}
return 1;
}
/*
* This restores directly out of user space. Exceptions are handled.
*/
static inline int restore_i387(struct _fpstate __user *buf)
{
struct task_struct *tsk = current;
int err;
if (!used_math()) {
err = init_fpu(tsk);
if (err)
return err;
}
if (!(task_thread_info(current)->status & TS_USEDFPU)) {
clts();
task_thread_info(current)->status |= TS_USEDFPU;
}
err = restore_fpu_checking((__force struct i387_fxsave_struct *)buf);
if (unlikely(err)) {
/*
* Encountered an error while doing the restore from the
* user buffer, clear the fpu state.
*/
clear_fpu(tsk);
clear_used_math();
}
return err;
}
/* /*
* Do a signal return; undo the signal stack. * Do a signal return; undo the signal stack.
*/ */
@ -160,25 +98,11 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
{ {
struct _fpstate __user * buf; struct _fpstate __user * buf;
err |= __get_user(buf, &sc->fpstate); err |= __get_user(buf, &sc->fpstate);
err |= restore_i387_xstate(buf);
if (buf) {
if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
goto badframe;
err |= restore_i387(buf);
} else {
struct task_struct *me = current;
if (used_math()) {
clear_fpu(me);
clear_used_math();
}
}
} }
err |= __get_user(*pax, &sc->ax); err |= __get_user(*pax, &sc->ax);
return err; return err;
badframe:
return 1;
} }
asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
@ -269,26 +193,23 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
sp = current->sas_ss_sp + current->sas_ss_size; sp = current->sas_ss_sp + current->sas_ss_size;
} }
return (void __user *)round_down(sp - size, 16); return (void __user *)round_down(sp - size, 64);
} }
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs * regs) sigset_t *set, struct pt_regs * regs)
{ {
struct rt_sigframe __user *frame; struct rt_sigframe __user *frame;
struct _fpstate __user *fp = NULL; void __user *fp = NULL;
int err = 0; int err = 0;
struct task_struct *me = current; struct task_struct *me = current;
if (used_math()) { if (used_math()) {
fp = get_stack(ka, regs, sizeof(struct _fpstate)); fp = get_stack(ka, regs, sig_xstate_size);
frame = (void __user *)round_down( frame = (void __user *)round_down(
(unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8; (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) if (save_i387_xstate(fp) < 0)
goto give_sigsegv;
if (save_i387(fp) < 0)
err |= -1; err |= -1;
} else } else
frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8; frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
@ -303,6 +224,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
} }
/* Create the ucontext. */ /* Create the ucontext. */
if (cpu_has_xsave)
err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
else
err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);

View file

@ -88,7 +88,7 @@ static DEFINE_PER_CPU(struct task_struct *, idle_thread_array);
#define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x)) #define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x))
#define set_idle_for_cpu(x, p) (per_cpu(idle_thread_array, x) = (p)) #define set_idle_for_cpu(x, p) (per_cpu(idle_thread_array, x) = (p))
#else #else
struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ; static struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
#define get_idle_for_cpu(x) (idle_thread_array[(x)]) #define get_idle_for_cpu(x) (idle_thread_array[(x)])
#define set_idle_for_cpu(x, p) (idle_thread_array[(x)] = (p)) #define set_idle_for_cpu(x, p) (idle_thread_array[(x)] = (p))
#endif #endif
@ -123,13 +123,12 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
static atomic_t init_deasserted; static atomic_t init_deasserted;
static int boot_cpu_logical_apicid;
/* representing cpus for which sibling maps can be computed */ /* representing cpus for which sibling maps can be computed */
static cpumask_t cpu_sibling_setup_map; static cpumask_t cpu_sibling_setup_map;
/* Set if we find a B stepping CPU */ /* Set if we find a B stepping CPU */
int __cpuinitdata smp_b_stepping; static int __cpuinitdata smp_b_stepping;
#if defined(CONFIG_NUMA) && defined(CONFIG_X86_32) #if defined(CONFIG_NUMA) && defined(CONFIG_X86_32)
@ -165,6 +164,8 @@ static void unmap_cpu_to_node(int cpu)
#endif #endif
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
static int boot_cpu_logical_apicid;
u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly =
{ [0 ... NR_CPUS-1] = BAD_APICID }; { [0 ... NR_CPUS-1] = BAD_APICID };
@ -210,7 +211,7 @@ static void __cpuinit smp_callin(void)
/* /*
* (This works even if the APIC is not enabled.) * (This works even if the APIC is not enabled.)
*/ */
phys_id = GET_APIC_ID(read_apic_id()); phys_id = read_apic_id();
cpuid = smp_processor_id(); cpuid = smp_processor_id();
if (cpu_isset(cpuid, cpu_callin_map)) { if (cpu_isset(cpuid, cpu_callin_map)) {
panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__, panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__,
@ -550,8 +551,7 @@ static inline void __inquire_remote_apic(int apicid)
printk(KERN_CONT printk(KERN_CONT
"a previous APIC delivery may have failed\n"); "a previous APIC delivery may have failed\n");
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); apic_icr_write(APIC_DM_REMRD | regs[i], apicid);
apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]);
timeout = 0; timeout = 0;
do { do {
@ -583,11 +583,9 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
int maxlvt; int maxlvt;
/* Target chip */ /* Target chip */
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
/* Boot on the stack */ /* Boot on the stack */
/* Kick the second */ /* Kick the second */
apic_write(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL); apic_icr_write(APIC_DM_NMI | APIC_DEST_LOGICAL, logical_apicid);
pr_debug("Waiting for send to finish...\n"); pr_debug("Waiting for send to finish...\n");
send_status = safe_apic_wait_icr_idle(); send_status = safe_apic_wait_icr_idle();
@ -640,13 +638,11 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
/* /*
* Turn INIT on target chip * Turn INIT on target chip
*/ */
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
/* /*
* Send IPI * Send IPI
*/ */
apic_write(APIC_ICR, apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT,
APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT); phys_apicid);
pr_debug("Waiting for send to finish...\n"); pr_debug("Waiting for send to finish...\n");
send_status = safe_apic_wait_icr_idle(); send_status = safe_apic_wait_icr_idle();
@ -656,10 +652,8 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
pr_debug("Deasserting INIT.\n"); pr_debug("Deasserting INIT.\n");
/* Target chip */ /* Target chip */
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
/* Send IPI */ /* Send IPI */
apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid);
pr_debug("Waiting for send to finish...\n"); pr_debug("Waiting for send to finish...\n");
send_status = safe_apic_wait_icr_idle(); send_status = safe_apic_wait_icr_idle();
@ -702,11 +696,10 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
*/ */
/* Target chip */ /* Target chip */
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
/* Boot on the stack */ /* Boot on the stack */
/* Kick the second */ /* Kick the second */
apic_write(APIC_ICR, APIC_DM_STARTUP | (start_eip >> 12)); apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12),
phys_apicid);
/* /*
* Give the other CPU some time to accept the IPI. * Give the other CPU some time to accept the IPI.
@ -1175,10 +1168,17 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
* Setup boot CPU information * Setup boot CPU information
*/ */
smp_store_cpu_info(0); /* Final full version of the data */ smp_store_cpu_info(0); /* Final full version of the data */
#ifdef CONFIG_X86_32
boot_cpu_logical_apicid = logical_smp_processor_id(); boot_cpu_logical_apicid = logical_smp_processor_id();
#endif
current_thread_info()->cpu = 0; /* needed? */ current_thread_info()->cpu = 0; /* needed? */
set_cpu_sibling_map(0); set_cpu_sibling_map(0);
#ifdef CONFIG_X86_64
enable_IR_x2apic();
setup_apic_routing();
#endif
if (smp_sanity_check(max_cpus) < 0) { if (smp_sanity_check(max_cpus) < 0) {
printk(KERN_INFO "SMP disabled\n"); printk(KERN_INFO "SMP disabled\n");
disable_smp(); disable_smp();
@ -1186,9 +1186,9 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
} }
preempt_disable(); preempt_disable();
if (GET_APIC_ID(read_apic_id()) != boot_cpu_physical_apicid) { if (read_apic_id() != boot_cpu_physical_apicid) {
panic("Boot APIC ID in local APIC unexpected (%d vs %d)", panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
GET_APIC_ID(read_apic_id()), boot_cpu_physical_apicid); read_apic_id(), boot_cpu_physical_apicid);
/* Or can we switch back to PIC here? */ /* Or can we switch back to PIC here? */
} }
preempt_enable(); preempt_enable();

View file

@ -30,7 +30,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/bios_ebda.h> #include <asm/bios_ebda.h>
#include <asm/mach-summit/mach_mpparse.h> #include <asm/summit/mpparse.h>
static struct rio_table_hdr *rio_table_hdr __initdata; static struct rio_table_hdr *rio_table_hdr __initdata;
static struct scal_detail *scal_devs[MAX_NUMNODES] __initdata; static struct scal_detail *scal_devs[MAX_NUMNODES] __initdata;

View file

@ -22,6 +22,8 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#include <asm/syscalls.h>
asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags, unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff) unsigned long fd, unsigned long pgoff)

View file

@ -16,6 +16,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ia32.h> #include <asm/ia32.h>
#include <asm/syscalls.h>
asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long off) unsigned long fd, unsigned long off)

View file

@ -8,12 +8,12 @@
#define __NO_STUBS #define __NO_STUBS
#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; #define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ;
#undef _ASM_X86_64_UNISTD_H_ #undef ASM_X86__UNISTD_64_H
#include <asm/unistd_64.h> #include <asm/unistd_64.h>
#undef __SYSCALL #undef __SYSCALL
#define __SYSCALL(nr, sym) [nr] = sym, #define __SYSCALL(nr, sym) [nr] = sym,
#undef _ASM_X86_64_UNISTD_H_ #undef ASM_X86__UNISTD_64_H
typedef void (*sys_call_ptr_t)(void); typedef void (*sys_call_ptr_t)(void);

View file

@ -36,6 +36,7 @@
#include <asm/arch_hooks.h> #include <asm/arch_hooks.h>
#include <asm/hpet.h> #include <asm/hpet.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/timer.h>
#include "do_timer.h" #include "do_timer.h"

View file

@ -10,6 +10,7 @@
#include <asm/ldt.h> #include <asm/ldt.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/syscalls.h>
#include "tls.h" #include "tls.h"

View file

@ -1228,7 +1228,6 @@ void __init trap_init(void)
set_bit(SYSCALL_VECTOR, used_vectors); set_bit(SYSCALL_VECTOR, used_vectors);
init_thread_xstate();
/* /*
* Should be a barrier for any external CPU state: * Should be a barrier for any external CPU state:
*/ */

View file

@ -339,9 +339,8 @@ static void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, unsigned long bp, char *log_lvl) unsigned long *stack, unsigned long bp, char *log_lvl)
{ {
printk("\nCall Trace:\n"); printk("Call Trace:\n");
dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
printk("\n");
} }
void show_trace(struct task_struct *task, struct pt_regs *regs, void show_trace(struct task_struct *task, struct pt_regs *regs,
@ -386,6 +385,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
printk(" %016lx", *stack++); printk(" %016lx", *stack++);
touch_nmi_watchdog(); touch_nmi_watchdog();
} }
printk("\n");
show_trace_log_lvl(task, regs, sp, bp, log_lvl); show_trace_log_lvl(task, regs, sp, bp, log_lvl);
} }
@ -443,7 +443,6 @@ void show_registers(struct pt_regs *regs)
printk("Stack: "); printk("Stack: ");
show_stack_log_lvl(NULL, regs, (unsigned long *)sp, show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
regs->bp, ""); regs->bp, "");
printk("\n");
printk(KERN_EMERG "Code: "); printk(KERN_EMERG "Code: ");
@ -1134,7 +1133,7 @@ asmlinkage void math_state_restore(void)
/* /*
* Paranoid restore. send a SIGSEGV if we fail to restore the state. * Paranoid restore. send a SIGSEGV if we fail to restore the state.
*/ */
if (unlikely(restore_fpu_checking(&me->thread.xstate->fxsave))) { if (unlikely(restore_fpu_checking(me))) {
stts(); stts();
force_sig(SIGSEGV, me); force_sig(SIGSEGV, me);
return; return;
@ -1172,10 +1171,6 @@ void __init trap_init(void)
#ifdef CONFIG_IA32_EMULATION #ifdef CONFIG_IA32_EMULATION
set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall); set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
#endif #endif
/*
* initialize the per thread extended state:
*/
init_thread_xstate();
/* /*
* Should be a barrier for any external CPU state: * Should be a barrier for any external CPU state:
*/ */

View file

@ -46,6 +46,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/syscalls.h>
/* /*
* Known problems: * Known problems:

View file

@ -905,8 +905,8 @@ static inline int __init activate_vmi(void)
#endif #endif
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
para_fill(pv_apic_ops.apic_read, APICRead); para_fill(apic_ops->read, APICRead);
para_fill(pv_apic_ops.apic_write, APICWrite); para_fill(apic_ops->write, APICWrite);
#endif #endif
/* /*

View file

@ -140,10 +140,10 @@ SECTIONS
*(.con_initcall.init) *(.con_initcall.init)
__con_initcall_end = .; __con_initcall_end = .;
} }
.x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) { .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
__x86cpuvendor_start = .; __x86_cpu_dev_start = .;
*(.x86cpuvendor.init) *(.x86_cpu_dev.init)
__x86cpuvendor_end = .; __x86_cpu_dev_end = .;
} }
SECURITY_INIT SECURITY_INIT
. = ALIGN(4); . = ALIGN(4);
@ -180,6 +180,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE); . = ALIGN(PAGE_SIZE);
.data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) {
__per_cpu_start = .; __per_cpu_start = .;
*(.data.percpu.page_aligned)
*(.data.percpu) *(.data.percpu)
*(.data.percpu.shared_aligned) *(.data.percpu.shared_aligned)
__per_cpu_end = .; __per_cpu_end = .;

View file

@ -168,13 +168,12 @@ SECTIONS
*(.con_initcall.init) *(.con_initcall.init)
} }
__con_initcall_end = .; __con_initcall_end = .;
. = ALIGN(16); __x86_cpu_dev_start = .;
__x86cpuvendor_start = .; .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
.x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) { *(.x86_cpu_dev.init)
*(.x86cpuvendor.init)
} }
__x86cpuvendor_end = .;
SECURITY_INIT SECURITY_INIT
__x86_cpu_dev_end = .;
. = ALIGN(8); . = ALIGN(8);
.parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {

316
arch/x86/kernel/xsave.c Normal file
View file

@ -0,0 +1,316 @@
/*
* xsave/xrstor support.
*
* Author: Suresh Siddha <suresh.b.siddha@intel.com>
*/
#include <linux/bootmem.h>
#include <linux/compat.h>
#include <asm/i387.h>
#ifdef CONFIG_IA32_EMULATION
#include <asm/sigcontext32.h>
#endif
#include <asm/xcr.h>
/*
* Supported feature mask by the CPU and the kernel.
*/
u64 pcntxt_mask;
struct _fpx_sw_bytes fx_sw_reserved;
#ifdef CONFIG_IA32_EMULATION
struct _fpx_sw_bytes fx_sw_reserved_ia32;
#endif
/*
* Check for the presence of extended state information in the
* user fpstate pointer in the sigcontext.
*/
int check_for_xstate(struct i387_fxsave_struct __user *buf,
void __user *fpstate,
struct _fpx_sw_bytes *fx_sw_user)
{
int min_xstate_size = sizeof(struct i387_fxsave_struct) +
sizeof(struct xsave_hdr_struct);
unsigned int magic2;
int err;
err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
sizeof(struct _fpx_sw_bytes));
if (err)
return err;
/*
* First Magic check failed.
*/
if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
return -1;
/*
* Check for error scenarios.
*/
if (fx_sw_user->xstate_size < min_xstate_size ||
fx_sw_user->xstate_size > xstate_size ||
fx_sw_user->xstate_size > fx_sw_user->extended_size)
return -1;
err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
fx_sw_user->extended_size -
FP_XSTATE_MAGIC2_SIZE));
/*
* Check for the presence of second magic word at the end of memory
* layout. This detects the case where the user just copied the legacy
* fpstate layout with out copying the extended state information
* in the memory layout.
*/
if (err || magic2 != FP_XSTATE_MAGIC2)
return -1;
return 0;
}
#ifdef CONFIG_X86_64
/*
* Signal frame handlers.
*/
int save_i387_xstate(void __user *buf)
{
struct task_struct *tsk = current;
int err = 0;
if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
return -EACCES;
BUG_ON(sig_xstate_size < xstate_size);
if ((unsigned long)buf % 64)
printk("save_i387_xstate: bad fpstate %p\n", buf);
if (!used_math())
return 0;
clear_used_math(); /* trigger finit */
if (task_thread_info(tsk)->status & TS_USEDFPU) {
/*
* Start with clearing the user buffer. This will present a
* clean context for the bytes not touched by the fxsave/xsave.
*/
__clear_user(buf, sig_xstate_size);
if (task_thread_info(tsk)->status & TS_XSAVE)
err = xsave_user(buf);
else
err = fxsave_user(buf);
if (err)
return err;
task_thread_info(tsk)->status &= ~TS_USEDFPU;
stts();
} else {
if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
xstate_size))
return -1;
}
if (task_thread_info(tsk)->status & TS_XSAVE) {
struct _fpstate __user *fx = buf;
err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
sizeof(struct _fpx_sw_bytes));
err |= __put_user(FP_XSTATE_MAGIC2,
(__u32 __user *) (buf + sig_xstate_size
- FP_XSTATE_MAGIC2_SIZE));
}
return 1;
}
/*
* Restore the extended state if present. Otherwise, restore the FP/SSE
* state.
*/
int restore_user_xstate(void __user *buf)
{
struct _fpx_sw_bytes fx_sw_user;
u64 mask;
int err;
if (((unsigned long)buf % 64) ||
check_for_xstate(buf, buf, &fx_sw_user))
goto fx_only;
mask = fx_sw_user.xstate_bv;
/*
* restore the state passed by the user.
*/
err = xrestore_user(buf, mask);
if (err)
return err;
/*
* init the state skipped by the user.
*/
mask = pcntxt_mask & ~mask;
xrstor_state(init_xstate_buf, mask);
return 0;
fx_only:
/*
* couldn't find the extended state information in the
* memory layout. Restore just the FP/SSE and init all
* the other extended state.
*/
xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
}
/*
* This restores directly out of user space. Exceptions are handled.
*/
int restore_i387_xstate(void __user *buf)
{
struct task_struct *tsk = current;
int err = 0;
if (!buf) {
if (used_math())
goto clear;
return 0;
} else
if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
return -EACCES;
if (!used_math()) {
err = init_fpu(tsk);
if (err)
return err;
}
if (!(task_thread_info(current)->status & TS_USEDFPU)) {
clts();
task_thread_info(current)->status |= TS_USEDFPU;
}
if (task_thread_info(tsk)->status & TS_XSAVE)
err = restore_user_xstate(buf);
else
err = fxrstor_checking((__force struct i387_fxsave_struct *)
buf);
if (unlikely(err)) {
/*
* Encountered an error while doing the restore from the
* user buffer, clear the fpu state.
*/
clear:
clear_fpu(tsk);
clear_used_math();
}
return err;
}
#endif
/*
* Prepare the SW reserved portion of the fxsave memory layout, indicating
* the presence of the extended state information in the memory layout
* pointed by the fpstate pointer in the sigcontext.
* This will be saved when ever the FP and extended state context is
* saved on the user stack during the signal handler delivery to the user.
*/
void prepare_fx_sw_frame(void)
{
int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
FP_XSTATE_MAGIC2_SIZE;
sig_xstate_size = sizeof(struct _fpstate) + size_extended;
#ifdef CONFIG_IA32_EMULATION
sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
#endif
memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
fx_sw_reserved.extended_size = sig_xstate_size;
fx_sw_reserved.xstate_bv = pcntxt_mask;
fx_sw_reserved.xstate_size = xstate_size;
#ifdef CONFIG_IA32_EMULATION
memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
sizeof(struct _fpx_sw_bytes));
fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
#endif
}
/*
* Represents init state for the supported extended state.
*/
struct xsave_struct *init_xstate_buf;
#ifdef CONFIG_X86_64
unsigned int sig_xstate_size = sizeof(struct _fpstate);
#endif
/*
* Enable the extended processor state save/restore feature
*/
void __cpuinit xsave_init(void)
{
if (!cpu_has_xsave)
return;
set_in_cr4(X86_CR4_OSXSAVE);
/*
* Enable all the features that the HW is capable of
* and the Linux kernel is aware of.
*/
xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
}
/*
* setup the xstate image representing the init state
*/
void setup_xstate_init(void)
{
init_xstate_buf = alloc_bootmem(xstate_size);
init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
}
/*
* Enable and initialize the xsave feature.
*/
void __init xsave_cntxt_init(void)
{
unsigned int eax, ebx, ecx, edx;
cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
pcntxt_mask = eax + ((u64)edx << 32);
if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx\n",
pcntxt_mask);
BUG();
}
/*
* for now OS knows only about FP/SSE
*/
pcntxt_mask = pcntxt_mask & XCNTXT_MASK;
xsave_init();
/*
* Recompute the context size for enabled features
*/
cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
xstate_size = ebx;
prepare_fx_sw_frame();
setup_xstate_init();
printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, "
"cntxt size 0x%x\n",
pcntxt_mask, xstate_size);
}

View file

@ -55,6 +55,7 @@
#include <linux/lguest_launcher.h> #include <linux/lguest_launcher.h>
#include <linux/virtio_console.h> #include <linux/virtio_console.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <asm/apic.h>
#include <asm/lguest.h> #include <asm/lguest.h>
#include <asm/paravirt.h> #include <asm/paravirt.h>
#include <asm/param.h> #include <asm/param.h>
@ -783,14 +784,44 @@ static void lguest_wbinvd(void)
* code qualifies for Advanced. It will also never interrupt anything. It * code qualifies for Advanced. It will also never interrupt anything. It
* does, however, allow us to get through the Linux boot code. */ * does, however, allow us to get through the Linux boot code. */
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
static void lguest_apic_write(unsigned long reg, u32 v) static void lguest_apic_write(u32 reg, u32 v)
{ {
} }
static u32 lguest_apic_read(unsigned long reg) static u32 lguest_apic_read(u32 reg)
{ {
return 0; return 0;
} }
static u64 lguest_apic_icr_read(void)
{
return 0;
}
static void lguest_apic_icr_write(u32 low, u32 id)
{
/* Warn to see if there's any stray references */
WARN_ON(1);
}
static void lguest_apic_wait_icr_idle(void)
{
return;
}
static u32 lguest_apic_safe_wait_icr_idle(void)
{
return 0;
}
static struct apic_ops lguest_basic_apic_ops = {
.read = lguest_apic_read,
.write = lguest_apic_write,
.icr_read = lguest_apic_icr_read,
.icr_write = lguest_apic_icr_write,
.wait_icr_idle = lguest_apic_wait_icr_idle,
.safe_wait_icr_idle = lguest_apic_safe_wait_icr_idle,
};
#endif #endif
/* STOP! Until an interrupt comes in. */ /* STOP! Until an interrupt comes in. */
@ -990,8 +1021,7 @@ __init void lguest_init(void)
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
/* apic read/write intercepts */ /* apic read/write intercepts */
pv_apic_ops.apic_write = lguest_apic_write; apic_ops = &lguest_basic_apic_ops;
pv_apic_ops.apic_read = lguest_apic_read;
#endif #endif
/* time operations */ /* time operations */

View file

@ -17,9 +17,6 @@ ifeq ($(CONFIG_X86_32),y)
lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o
else else
obj-y += io_64.o iomap_copy_64.o obj-y += io_64.o iomap_copy_64.o
CFLAGS_csum-partial_64.o := -funroll-loops
lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o
lib-y += thunk_64.o clear_page_64.o copy_page_64.o lib-y += thunk_64.o clear_page_64.o copy_page_64.o
lib-y += memmove_64.o memset_64.o lib-y += memmove_64.o memset_64.o

View file

@ -14,6 +14,13 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/mmx.h> #include <asm/mmx.h>
#ifdef CONFIG_X86_INTEL_USERCOPY
/*
* Alignment at which movsl is preferred for bulk memory copies.
*/
struct movsl_mask movsl_mask __read_mostly;
#endif
static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n) static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n)
{ {
#ifdef CONFIG_X86_INTEL_USERCOPY #ifdef CONFIG_X86_INTEL_USERCOPY

View file

@ -10,13 +10,15 @@
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <mach_ipi.h>
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
#define DEFAULT_SEND_IPI (1) #define DEFAULT_SEND_IPI (1)
#else #else
#define DEFAULT_SEND_IPI (0) #define DEFAULT_SEND_IPI (0)
#endif #endif
int no_broadcast=DEFAULT_SEND_IPI; int no_broadcast = DEFAULT_SEND_IPI;
/** /**
* pre_intr_init_hook - initialisation prior to setting up interrupt vectors * pre_intr_init_hook - initialisation prior to setting up interrupt vectors
@ -36,15 +38,6 @@ void __init pre_intr_init_hook(void)
init_ISA_irqs(); init_ISA_irqs();
} }
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
static struct irqaction irq2 = {
.handler = no_action,
.mask = CPU_MASK_NONE,
.name = "cascade",
};
/** /**
* intr_init_hook - post gate setup interrupt initialisation * intr_init_hook - post gate setup interrupt initialisation
* *
@ -60,12 +53,6 @@ void __init intr_init_hook(void)
if (x86_quirks->arch_intr_init()) if (x86_quirks->arch_intr_init())
return; return;
} }
#ifdef CONFIG_X86_LOCAL_APIC
apic_intr_init();
#endif
if (!acpi_ioapic)
setup_irq(2, &irq2);
} }
/** /**

View file

@ -1,5 +0,0 @@
#
# Makefile for the linux kernel.
#
obj-$(CONFIG_X86_ES7000) := es7000plat.o

View file

@ -1,114 +0,0 @@
/*
* Written by: Garry Forsgren, Unisys Corporation
* Natalie Protasevich, Unisys Corporation
* This file contains the code to configure and interface
* with Unisys ES7000 series hardware system manager.
*
* Copyright (c) 2003 Unisys Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* Contact information: Unisys Corporation, Township Line & Union Meeting
* Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or:
*
* http://www.unisys.com
*/
/*
* ES7000 chipsets
*/
#define NON_UNISYS 0
#define ES7000_CLASSIC 1
#define ES7000_ZORRO 2
#define MIP_REG 1
#define MIP_PSAI_REG 4
#define MIP_BUSY 1
#define MIP_SPIN 0xf0000
#define MIP_VALID 0x0100000000000000ULL
#define MIP_PORT(VALUE) ((VALUE >> 32) & 0xffff)
#define MIP_RD_LO(VALUE) (VALUE & 0xffffffff)
struct mip_reg_info {
unsigned long long mip_info;
unsigned long long delivery_info;
unsigned long long host_reg;
unsigned long long mip_reg;
};
struct part_info {
unsigned char type;
unsigned char length;
unsigned char part_id;
unsigned char apic_mode;
unsigned long snum;
char ptype[16];
char sname[64];
char pname[64];
};
struct psai {
unsigned long long entry_type;
unsigned long long addr;
unsigned long long bep_addr;
};
struct es7000_mem_info {
unsigned char type;
unsigned char length;
unsigned char resv[6];
unsigned long long start;
unsigned long long size;
};
struct es7000_oem_table {
unsigned long long hdr;
struct mip_reg_info mip;
struct part_info pif;
struct es7000_mem_info shm;
struct psai psai;
};
#ifdef CONFIG_ACPI
struct oem_table {
struct acpi_table_header Header;
u32 OEMTableAddr;
u32 OEMTableSize;
};
extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
#endif
struct mip_reg {
unsigned long long off_0;
unsigned long long off_8;
unsigned long long off_10;
unsigned long long off_18;
unsigned long long off_20;
unsigned long long off_28;
unsigned long long off_30;
unsigned long long off_38;
};
#define MIP_SW_APIC 0x1020b
#define MIP_FUNC(VALUE) (VALUE & 0xff)
extern int parse_unisys_oem (char *oemptr);
extern void setup_unisys(void);
extern int es7000_start_cpu(int cpu, unsigned long eip);
extern void es7000_sw_apic(void);

View file

@ -9,4 +9,3 @@ obj-$(CONFIG_X86_NUMAQ) += numaq.o
obj-$(CONFIG_X86_SUMMIT) += summit.o obj-$(CONFIG_X86_SUMMIT) += summit.o
obj-$(CONFIG_X86_BIGSMP) += bigsmp.o obj-$(CONFIG_X86_BIGSMP) += bigsmp.o
obj-$(CONFIG_X86_ES7000) += es7000.o obj-$(CONFIG_X86_ES7000) += es7000.o
obj-$(CONFIG_X86_ES7000) += ../../x86/mach-es7000/

View file

@ -5,18 +5,17 @@
#define APIC_DEFINITION 1 #define APIC_DEFINITION 1
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <asm/smp.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <asm/mach-bigsmp/mach_apic.h> #include <asm/bigsmp/apicdef.h>
#include <asm/mach-bigsmp/mach_apicdef.h> #include <linux/smp.h>
#include <asm/mach-bigsmp/mach_ipi.h> #include <asm/bigsmp/apic.h>
#include <asm/bigsmp/ipi.h>
#include <asm/mach-default/mach_mpparse.h> #include <asm/mach-default/mach_mpparse.h>
static int dmi_bigsmp; /* can be set by dmi scanners */ static int dmi_bigsmp; /* can be set by dmi scanners */

View file

@ -4,20 +4,19 @@
#define APIC_DEFINITION 1 #define APIC_DEFINITION 1
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <asm/smp.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/smp.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/mach-es7000/mach_apicdef.h> #include <asm/es7000/apicdef.h>
#include <asm/mach-es7000/mach_apic.h> #include <linux/smp.h>
#include <asm/mach-es7000/mach_ipi.h> #include <asm/es7000/apic.h>
#include <asm/mach-es7000/mach_mpparse.h> #include <asm/es7000/ipi.h>
#include <asm/mach-es7000/mach_wakecpu.h> #include <asm/es7000/mpparse.h>
#include <asm/es7000/wakecpu.h>
static int probe_es7000(void) static int probe_es7000(void)
{ {

View file

@ -4,7 +4,6 @@
#define APIC_DEFINITION 1 #define APIC_DEFINITION 1
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/smp.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
@ -12,11 +11,12 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/mach-numaq/mach_apic.h> #include <asm/numaq/apicdef.h>
#include <asm/mach-numaq/mach_apicdef.h> #include <linux/smp.h>
#include <asm/mach-numaq/mach_ipi.h> #include <asm/numaq/apic.h>
#include <asm/mach-numaq/mach_mpparse.h> #include <asm/numaq/ipi.h>
#include <asm/mach-numaq/mach_wakecpu.h> #include <asm/numaq/mpparse.h>
#include <asm/numaq/wakecpu.h>
#include <asm/numaq.h> #include <asm/numaq.h>
static int mps_oem_check(struct mp_config_table *mpc, char *oem, static int mps_oem_check(struct mp_config_table *mpc, char *oem,

View file

@ -4,19 +4,18 @@
#define APIC_DEFINITION 1 #define APIC_DEFINITION 1
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <asm/smp.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/smp.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/mach-summit/mach_apic.h> #include <asm/summit/apicdef.h>
#include <asm/mach-summit/mach_apicdef.h> #include <linux/smp.h>
#include <asm/mach-summit/mach_ipi.h> #include <asm/summit/apic.h>
#include <asm/mach-summit/mach_mpparse.h> #include <asm/summit/ipi.h>
#include <asm/summit/mpparse.h>
static int probe_summit(void) static int probe_summit(void)
{ {

View file

@ -35,6 +35,7 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/proto.h> #include <asm/proto.h>
#include <asm-generic/sections.h> #include <asm-generic/sections.h>
#include <asm/traps.h>
/* /*
* Page fault error code bits * Page fault error code bits
@ -357,8 +358,6 @@ static int is_errata100(struct pt_regs *regs, unsigned long address)
return 0; return 0;
} }
void do_invalid_op(struct pt_regs *, unsigned long);
static int is_f00f_bug(struct pt_regs *regs, unsigned long address) static int is_f00f_bug(struct pt_regs *regs, unsigned long address)
{ {
#ifdef CONFIG_X86_F00F_BUG #ifdef CONFIG_X86_F00F_BUG

View file

@ -47,6 +47,7 @@
#include <asm/paravirt.h> #include <asm/paravirt.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/smp.h>
unsigned int __VMALLOC_RESERVE = 128 << 20; unsigned int __VMALLOC_RESERVE = 128 << 20;

View file

@ -421,7 +421,7 @@ void unxlate_dev_mem_ptr(unsigned long phys, void *addr)
return; return;
} }
int __initdata early_ioremap_debug; static int __initdata early_ioremap_debug;
static int __init early_ioremap_debug_setup(char *str) static int __init early_ioremap_debug_setup(char *str)
{ {
@ -547,7 +547,7 @@ static inline void __init early_clear_fixmap(enum fixed_addresses idx)
} }
int __initdata early_ioremap_nested; static int __initdata early_ioremap_nested;
static int __init check_early_ioremap_leak(void) static int __init check_early_ioremap_leak(void)
{ {

View file

@ -250,10 +250,5 @@ int __init pci_acpi_init(void)
acpi_pci_irq_enable(dev); acpi_pci_irq_enable(dev);
} }
#ifdef CONFIG_X86_IO_APIC
if (acpi_ioapic)
print_IO_APIC();
#endif
return 0; return 0;
} }

View file

@ -33,6 +33,7 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <asm/pat.h> #include <asm/pat.h>
#include <asm/e820.h>
#include "pci.h" #include "pci.h"
@ -227,6 +228,8 @@ void __init pcibios_resource_survey(void)
pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_bus_resources(&pci_root_buses);
pcibios_allocate_resources(0); pcibios_allocate_resources(0);
pcibios_allocate_resources(1); pcibios_allocate_resources(1);
e820_reserve_resources_late();
} }
/** /**

View file

@ -209,7 +209,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
return name != NULL; return name != NULL;
} }
static void __init pci_mmcfg_insert_resources(unsigned long resource_flags) static void __init pci_mmcfg_insert_resources(void)
{ {
#define PCI_MMCFG_RESOURCE_NAME_LEN 19 #define PCI_MMCFG_RESOURCE_NAME_LEN 19
int i; int i;
@ -233,7 +233,7 @@ static void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
cfg->pci_segment); cfg->pci_segment);
res->start = cfg->address; res->start = cfg->address;
res->end = res->start + (num_buses << 20) - 1; res->end = res->start + (num_buses << 20) - 1;
res->flags = IORESOURCE_MEM | resource_flags; res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
insert_resource(&iomem_resource, res); insert_resource(&iomem_resource, res);
names += PCI_MMCFG_RESOURCE_NAME_LEN; names += PCI_MMCFG_RESOURCE_NAME_LEN;
} }
@ -434,11 +434,9 @@ static void __init __pci_mmcfg_init(int early)
(pci_mmcfg_config[0].address == 0)) (pci_mmcfg_config[0].address == 0))
return; return;
if (pci_mmcfg_arch_init()) { if (pci_mmcfg_arch_init())
if (known_bridge)
pci_mmcfg_insert_resources(IORESOURCE_BUSY);
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
} else { else {
/* /*
* Signal not to attempt to insert mmcfg resources because * Signal not to attempt to insert mmcfg resources because
* the architecture mmcfg setup could not initialize. * the architecture mmcfg setup could not initialize.
@ -475,7 +473,7 @@ static int __init pci_mmcfg_late_insert_resources(void)
* marked so it won't cause request errors when __request_region is * marked so it won't cause request errors when __request_region is
* called. * called.
*/ */
pci_mmcfg_insert_resources(0); pci_mmcfg_insert_resources();
return 0; return 0;
} }

View file

@ -11,6 +11,7 @@
#include <linux/suspend.h> #include <linux/suspend.h>
#include <asm/mtrr.h> #include <asm/mtrr.h>
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/xcr.h>
static struct saved_context saved_context; static struct saved_context saved_context;
@ -126,6 +127,12 @@ static void __restore_processor_state(struct saved_context *ctxt)
if (boot_cpu_has(X86_FEATURE_SEP)) if (boot_cpu_has(X86_FEATURE_SEP))
enable_sep_cpu(); enable_sep_cpu();
/*
* restore XCR0 for xsave capable cpu's.
*/
if (cpu_has_xsave)
xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
fix_processor_context(); fix_processor_context();
do_fpu_end(); do_fpu_end();
mtrr_ap_init(); mtrr_ap_init();

View file

@ -14,6 +14,7 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/mtrr.h> #include <asm/mtrr.h>
#include <asm/xcr.h>
static void fix_processor_context(void); static void fix_processor_context(void);
@ -122,6 +123,12 @@ static void __restore_processor_state(struct saved_context *ctxt)
wrmsrl(MSR_GS_BASE, ctxt->gs_base); wrmsrl(MSR_GS_BASE, ctxt->gs_base);
wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
/*
* restore XCR0 for xsave capable cpu's.
*/
if (cpu_has_xsave)
xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
fix_processor_context(); fix_processor_context();
do_fpu_end(); do_fpu_end();

View file

@ -36,6 +36,7 @@
#include <xen/hvc-console.h> #include <xen/hvc-console.h>
#include <asm/paravirt.h> #include <asm/paravirt.h>
#include <asm/apic.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/xen/hypercall.h> #include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
@ -580,16 +581,47 @@ static void xen_io_delay(void)
} }
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
static u32 xen_apic_read(unsigned long reg) static u32 xen_apic_read(u32 reg)
{ {
return 0; return 0;
} }
static void xen_apic_write(unsigned long reg, u32 val) static void xen_apic_write(u32 reg, u32 val)
{ {
/* Warn to see if there's any stray references */ /* Warn to see if there's any stray references */
WARN_ON(1); WARN_ON(1);
} }
static u64 xen_apic_icr_read(void)
{
return 0;
}
static void xen_apic_icr_write(u32 low, u32 id)
{
/* Warn to see if there's any stray references */
WARN_ON(1);
}
static void xen_apic_wait_icr_idle(void)
{
return;
}
static u32 xen_safe_apic_wait_icr_idle(void)
{
return 0;
}
static struct apic_ops xen_basic_apic_ops = {
.read = xen_apic_read,
.write = xen_apic_write,
.icr_read = xen_apic_icr_read,
.icr_write = xen_apic_icr_write,
.wait_icr_idle = xen_apic_wait_icr_idle,
.safe_wait_icr_idle = xen_safe_apic_wait_icr_idle,
};
#endif #endif
static void xen_flush_tlb(void) static void xen_flush_tlb(void)
@ -1273,8 +1305,6 @@ static const struct pv_irq_ops xen_irq_ops __initdata = {
static const struct pv_apic_ops xen_apic_ops __initdata = { static const struct pv_apic_ops xen_apic_ops __initdata = {
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
.apic_write = xen_apic_write,
.apic_read = xen_apic_read,
.setup_boot_clock = paravirt_nop, .setup_boot_clock = paravirt_nop,
.setup_secondary_clock = paravirt_nop, .setup_secondary_clock = paravirt_nop,
.startup_ipi_hook = paravirt_nop, .startup_ipi_hook = paravirt_nop,
@ -1677,6 +1707,13 @@ asmlinkage void __init xen_start_kernel(void)
pv_apic_ops = xen_apic_ops; pv_apic_ops = xen_apic_ops;
pv_mmu_ops = xen_mmu_ops; pv_mmu_ops = xen_mmu_ops;
#ifdef CONFIG_X86_LOCAL_APIC
/*
* set up the basic apic ops.
*/
apic_ops = &xen_basic_apic_ops;
#endif
if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) {
pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start; pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start;
pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit; pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit;

View file

@ -26,6 +26,8 @@ obj-$(CONFIG_HT_IRQ) += htirq.o
# Build Intel IOMMU support # Build Intel IOMMU support
obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o
# #
# Some architectures use the generic PCI setup functions # Some architectures use the generic PCI setup functions
# #

157
drivers/pci/dma_remapping.h Normal file
View file

@ -0,0 +1,157 @@
#ifndef _DMA_REMAPPING_H
#define _DMA_REMAPPING_H
/*
* We need a fixed PAGE_SIZE of 4K irrespective of
* arch PAGE_SIZE for IOMMU page tables.
*/
#define PAGE_SHIFT_4K (12)
#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K)
#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
/*
* 0: Present
* 1-11: Reserved
* 12-63: Context Ptr (12 - (haw-1))
* 64-127: Reserved
*/
struct root_entry {
u64 val;
u64 rsvd1;
};
#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry))
static inline bool root_present(struct root_entry *root)
{
return (root->val & 1);
}
static inline void set_root_present(struct root_entry *root)
{
root->val |= 1;
}
static inline void set_root_value(struct root_entry *root, unsigned long value)
{
root->val |= value & PAGE_MASK_4K;
}
struct context_entry;
static inline struct context_entry *
get_context_addr_from_root(struct root_entry *root)
{
return (struct context_entry *)
(root_present(root)?phys_to_virt(
root->val & PAGE_MASK_4K):
NULL);
}
/*
* low 64 bits:
* 0: present
* 1: fault processing disable
* 2-3: translation type
* 12-63: address space root
* high 64 bits:
* 0-2: address width
* 3-6: aval
* 8-23: domain id
*/
struct context_entry {
u64 lo;
u64 hi;
};
#define context_present(c) ((c).lo & 1)
#define context_fault_disable(c) (((c).lo >> 1) & 1)
#define context_translation_type(c) (((c).lo >> 2) & 3)
#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
#define context_address_width(c) ((c).hi & 7)
#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
#define context_set_present(c) do {(c).lo |= 1;} while (0)
#define context_set_fault_enable(c) \
do {(c).lo &= (((u64)-1) << 2) | 1;} while (0)
#define context_set_translation_type(c, val) \
do { \
(c).lo &= (((u64)-1) << 4) | 3; \
(c).lo |= ((val) & 3) << 2; \
} while (0)
#define CONTEXT_TT_MULTI_LEVEL 0
#define context_set_address_root(c, val) \
do {(c).lo |= (val) & PAGE_MASK_4K;} while (0)
#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
#define context_set_domain_id(c, val) \
do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0)
/*
* 0: readable
* 1: writable
* 2-6: reserved
* 7: super page
* 8-11: available
* 12-63: Host physcial address
*/
struct dma_pte {
u64 val;
};
#define dma_clear_pte(p) do {(p).val = 0;} while (0)
#define DMA_PTE_READ (1)
#define DMA_PTE_WRITE (2)
#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0)
#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
#define dma_set_pte_prot(p, prot) \
do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
#define dma_set_pte_addr(p, addr) do {\
(p).val |= ((addr) & PAGE_MASK_4K); } while (0)
#define dma_pte_present(p) (((p).val & 3) != 0)
struct intel_iommu;
struct dmar_domain {
int id; /* domain id */
struct intel_iommu *iommu; /* back pointer to owning iommu */
struct list_head devices; /* all devices' list */
struct iova_domain iovad; /* iova's that belong to this domain */
struct dma_pte *pgd; /* virtual address */
spinlock_t mapping_lock; /* page table lock */
int gaw; /* max guest address width */
/* adjusted guest address width, 0 is level 2 30-bit */
int agaw;
#define DOMAIN_FLAG_MULTIPLE_DEVICES 1
int flags;
};
/* PCI domain-device relationship */
struct device_domain_info {
struct list_head link; /* link to domain siblings */
struct list_head global; /* link to global list */
u8 bus; /* PCI bus numer */
u8 devfn; /* PCI devfn number */
struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
struct dmar_domain *domain; /* pointer to domain */
};
extern int init_dmars(void);
extern void free_dmar_iommu(struct intel_iommu *iommu);
extern int dmar_disabled;
#ifndef CONFIG_DMAR_GFX_WA
static inline void iommu_prepare_gfx_mapping(void)
{
return;
}
#endif /* !CONFIG_DMAR_GFX_WA */
#endif

View file

@ -19,13 +19,16 @@
* Author: Shaohua Li <shaohua.li@intel.com> * Author: Shaohua Li <shaohua.li@intel.com>
* Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
* *
* This file implements early detection/parsing of DMA Remapping Devices * This file implements early detection/parsing of Remapping Devices
* reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI
* tables. * tables.
*
* These routines are used by both DMA-remapping and Interrupt-remapping
*/ */
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/dmar.h> #include <linux/dmar.h>
#include <linux/timer.h>
#include "iova.h" #include "iova.h"
#include "intel-iommu.h" #include "intel-iommu.h"
@ -37,7 +40,6 @@
* these units are not supported by the architecture. * these units are not supported by the architecture.
*/ */
LIST_HEAD(dmar_drhd_units); LIST_HEAD(dmar_drhd_units);
LIST_HEAD(dmar_rmrr_units);
static struct acpi_table_header * __initdata dmar_tbl; static struct acpi_table_header * __initdata dmar_tbl;
@ -53,11 +55,6 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
list_add(&drhd->list, &dmar_drhd_units); list_add(&drhd->list, &dmar_drhd_units);
} }
static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
{
list_add(&rmrr->list, &dmar_rmrr_units);
}
static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
struct pci_dev **dev, u16 segment) struct pci_dev **dev, u16 segment)
{ {
@ -172,19 +169,37 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
struct acpi_dmar_hardware_unit *drhd; struct acpi_dmar_hardware_unit *drhd;
struct dmar_drhd_unit *dmaru; struct dmar_drhd_unit *dmaru;
int ret = 0; int ret = 0;
static int include_all;
dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
if (!dmaru) if (!dmaru)
return -ENOMEM; return -ENOMEM;
dmaru->hdr = header;
drhd = (struct acpi_dmar_hardware_unit *)header; drhd = (struct acpi_dmar_hardware_unit *)header;
dmaru->reg_base_addr = drhd->address; dmaru->reg_base_addr = drhd->address;
dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */ dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
ret = alloc_iommu(dmaru);
if (ret) {
kfree(dmaru);
return ret;
}
dmar_register_drhd_unit(dmaru);
return 0;
}
static int __init
dmar_parse_dev(struct dmar_drhd_unit *dmaru)
{
struct acpi_dmar_hardware_unit *drhd;
static int include_all;
int ret;
drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr;
if (!dmaru->include_all) if (!dmaru->include_all)
ret = dmar_parse_dev_scope((void *)(drhd + 1), ret = dmar_parse_dev_scope((void *)(drhd + 1),
((void *)drhd) + header->length, ((void *)drhd) + drhd->header.length,
&dmaru->devices_cnt, &dmaru->devices, &dmaru->devices_cnt, &dmaru->devices,
drhd->segment); drhd->segment);
else { else {
@ -197,37 +212,59 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
include_all = 1; include_all = 1;
} }
if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) {
list_del(&dmaru->list);
kfree(dmaru); kfree(dmaru);
else }
dmar_register_drhd_unit(dmaru);
return ret; return ret;
} }
#ifdef CONFIG_DMAR
LIST_HEAD(dmar_rmrr_units);
static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
{
list_add(&rmrr->list, &dmar_rmrr_units);
}
static int __init static int __init
dmar_parse_one_rmrr(struct acpi_dmar_header *header) dmar_parse_one_rmrr(struct acpi_dmar_header *header)
{ {
struct acpi_dmar_reserved_memory *rmrr; struct acpi_dmar_reserved_memory *rmrr;
struct dmar_rmrr_unit *rmrru; struct dmar_rmrr_unit *rmrru;
int ret = 0;
rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
if (!rmrru) if (!rmrru)
return -ENOMEM; return -ENOMEM;
rmrru->hdr = header;
rmrr = (struct acpi_dmar_reserved_memory *)header; rmrr = (struct acpi_dmar_reserved_memory *)header;
rmrru->base_address = rmrr->base_address; rmrru->base_address = rmrr->base_address;
rmrru->end_address = rmrr->end_address; rmrru->end_address = rmrr->end_address;
dmar_register_rmrr_unit(rmrru);
return 0;
}
static int __init
rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
{
struct acpi_dmar_reserved_memory *rmrr;
int ret;
rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
ret = dmar_parse_dev_scope((void *)(rmrr + 1), ret = dmar_parse_dev_scope((void *)(rmrr + 1),
((void *)rmrr) + header->length, ((void *)rmrr) + rmrr->header.length,
&rmrru->devices_cnt, &rmrru->devices, rmrr->segment); &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
if (ret || (rmrru->devices_cnt == 0)) if (ret || (rmrru->devices_cnt == 0)) {
list_del(&rmrru->list);
kfree(rmrru); kfree(rmrru);
else }
dmar_register_rmrr_unit(rmrru);
return ret; return ret;
} }
#endif
static void __init static void __init
dmar_table_print_dmar_entry(struct acpi_dmar_header *header) dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
@ -252,6 +289,7 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
} }
} }
/** /**
* parse_dmar_table - parses the DMA reporting table * parse_dmar_table - parses the DMA reporting table
*/ */
@ -284,7 +322,9 @@ parse_dmar_table(void)
ret = dmar_parse_one_drhd(entry_header); ret = dmar_parse_one_drhd(entry_header);
break; break;
case ACPI_DMAR_TYPE_RESERVED_MEMORY: case ACPI_DMAR_TYPE_RESERVED_MEMORY:
#ifdef CONFIG_DMAR
ret = dmar_parse_one_rmrr(entry_header); ret = dmar_parse_one_rmrr(entry_header);
#endif
break; break;
default: default:
printk(KERN_WARNING PREFIX printk(KERN_WARNING PREFIX
@ -300,14 +340,76 @@ parse_dmar_table(void)
return ret; return ret;
} }
int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
struct pci_dev *dev)
{
int index;
while (dev) {
for (index = 0; index < cnt; index++)
if (dev == devices[index])
return 1;
/* Check our parent */
dev = dev->bus->self;
}
return 0;
}
struct dmar_drhd_unit *
dmar_find_matched_drhd_unit(struct pci_dev *dev)
{
struct dmar_drhd_unit *drhd = NULL;
list_for_each_entry(drhd, &dmar_drhd_units, list) {
if (drhd->include_all || dmar_pci_device_match(drhd->devices,
drhd->devices_cnt, dev))
return drhd;
}
return NULL;
}
int __init dmar_dev_scope_init(void)
{
struct dmar_drhd_unit *drhd;
int ret = -ENODEV;
for_each_drhd_unit(drhd) {
ret = dmar_parse_dev(drhd);
if (ret)
return ret;
}
#ifdef CONFIG_DMAR
{
struct dmar_rmrr_unit *rmrr;
for_each_rmrr_units(rmrr) {
ret = rmrr_parse_dev(rmrr);
if (ret)
return ret;
}
}
#endif
return ret;
}
int __init dmar_table_init(void) int __init dmar_table_init(void)
{ {
static int dmar_table_initialized;
int ret; int ret;
if (dmar_table_initialized)
return 0;
dmar_table_initialized = 1;
ret = parse_dmar_table(); ret = parse_dmar_table();
if (ret) { if (ret) {
if (ret != -ENODEV)
printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
return ret; return ret;
} }
@ -317,9 +419,14 @@ int __init dmar_table_init(void)
return -ENODEV; return -ENODEV;
} }
#ifdef CONFIG_DMAR
if (list_empty(&dmar_rmrr_units)) if (list_empty(&dmar_rmrr_units))
printk(KERN_INFO PREFIX "No RMRR found\n"); printk(KERN_INFO PREFIX "No RMRR found\n");
#endif
#ifdef CONFIG_INTR_REMAP
parse_ioapics_under_ir();
#endif
return 0; return 0;
} }
@ -341,3 +448,255 @@ int __init early_dmar_detect(void)
return (ACPI_SUCCESS(status) ? 1 : 0); return (ACPI_SUCCESS(status) ? 1 : 0);
} }
void __init detect_intel_iommu(void)
{
int ret;
ret = early_dmar_detect();
#ifdef CONFIG_DMAR
{
struct acpi_table_dmar *dmar;
/*
* for now we will disable dma-remapping when interrupt
* remapping is enabled.
* When support for queued invalidation for IOTLB invalidation
* is added, we will not need this any more.
*/
dmar = (struct acpi_table_dmar *) dmar_tbl;
if (ret && cpu_has_x2apic && dmar->flags & 0x1) {
printk(KERN_INFO
"Queued invalidation will be enabled to support "
"x2apic and Intr-remapping.\n");
printk(KERN_INFO
"Disabling IOMMU detection, because of missing "
"queued invalidation support for IOTLB "
"invalidation\n");
printk(KERN_INFO
"Use \"nox2apic\", if you want to use Intel "
" IOMMU for DMA-remapping and don't care about "
" x2apic support\n");
dmar_disabled = 1;
return;
}
if (ret && !no_iommu && !iommu_detected && !swiotlb &&
!dmar_disabled)
iommu_detected = 1;
}
#endif
}
int alloc_iommu(struct dmar_drhd_unit *drhd)
{
struct intel_iommu *iommu;
int map_size;
u32 ver;
static int iommu_allocated = 0;
iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
if (!iommu)
return -ENOMEM;
iommu->seq_id = iommu_allocated++;
iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K);
if (!iommu->reg) {
printk(KERN_ERR "IOMMU: can't map the region\n");
goto error;
}
iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
/* the registers might be more than one page */
map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
cap_max_fault_reg_offset(iommu->cap));
map_size = PAGE_ALIGN_4K(map_size);
if (map_size > PAGE_SIZE_4K) {
iounmap(iommu->reg);
iommu->reg = ioremap(drhd->reg_base_addr, map_size);
if (!iommu->reg) {
printk(KERN_ERR "IOMMU: can't map the region\n");
goto error;
}
}
ver = readl(iommu->reg + DMAR_VER_REG);
pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
iommu->cap, iommu->ecap);
spin_lock_init(&iommu->register_lock);
drhd->iommu = iommu;
return 0;
error:
kfree(iommu);
return -1;
}
void free_iommu(struct intel_iommu *iommu)
{
if (!iommu)
return;
#ifdef CONFIG_DMAR
free_dmar_iommu(iommu);
#endif
if (iommu->reg)
iounmap(iommu->reg);
kfree(iommu);
}
/*
* Reclaim all the submitted descriptors which have completed its work.
*/
static inline void reclaim_free_desc(struct q_inval *qi)
{
while (qi->desc_status[qi->free_tail] == QI_DONE) {
qi->desc_status[qi->free_tail] = QI_FREE;
qi->free_tail = (qi->free_tail + 1) % QI_LENGTH;
qi->free_cnt++;
}
}
/*
* Submit the queued invalidation descriptor to the remapping
* hardware unit and wait for its completion.
*/
void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
{
struct q_inval *qi = iommu->qi;
struct qi_desc *hw, wait_desc;
int wait_index, index;
unsigned long flags;
if (!qi)
return;
hw = qi->desc;
spin_lock(&qi->q_lock);
while (qi->free_cnt < 3) {
spin_unlock(&qi->q_lock);
cpu_relax();
spin_lock(&qi->q_lock);
}
index = qi->free_head;
wait_index = (index + 1) % QI_LENGTH;
qi->desc_status[index] = qi->desc_status[wait_index] = QI_IN_USE;
hw[index] = *desc;
wait_desc.low = QI_IWD_STATUS_DATA(2) | QI_IWD_STATUS_WRITE | QI_IWD_TYPE;
wait_desc.high = virt_to_phys(&qi->desc_status[wait_index]);
hw[wait_index] = wait_desc;
__iommu_flush_cache(iommu, &hw[index], sizeof(struct qi_desc));
__iommu_flush_cache(iommu, &hw[wait_index], sizeof(struct qi_desc));
qi->free_head = (qi->free_head + 2) % QI_LENGTH;
qi->free_cnt -= 2;
spin_lock_irqsave(&iommu->register_lock, flags);
/*
* update the HW tail register indicating the presence of
* new descriptors.
*/
writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG);
spin_unlock_irqrestore(&iommu->register_lock, flags);
while (qi->desc_status[wait_index] != QI_DONE) {
spin_unlock(&qi->q_lock);
cpu_relax();
spin_lock(&qi->q_lock);
}
qi->desc_status[index] = QI_DONE;
reclaim_free_desc(qi);
spin_unlock(&qi->q_lock);
}
/*
* Flush the global interrupt entry cache.
*/
void qi_global_iec(struct intel_iommu *iommu)
{
struct qi_desc desc;
desc.low = QI_IEC_TYPE;
desc.high = 0;
qi_submit_sync(&desc, iommu);
}
/*
* Enable Queued Invalidation interface. This is a must to support
* interrupt-remapping. Also used by DMA-remapping, which replaces
* register based IOTLB invalidation.
*/
int dmar_enable_qi(struct intel_iommu *iommu)
{
u32 cmd, sts;
unsigned long flags;
struct q_inval *qi;
if (!ecap_qis(iommu->ecap))
return -ENOENT;
/*
* queued invalidation is already setup and enabled.
*/
if (iommu->qi)
return 0;
iommu->qi = kmalloc(sizeof(*qi), GFP_KERNEL);
if (!iommu->qi)
return -ENOMEM;
qi = iommu->qi;
qi->desc = (void *)(get_zeroed_page(GFP_KERNEL));
if (!qi->desc) {
kfree(qi);
iommu->qi = 0;
return -ENOMEM;
}
qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_KERNEL);
if (!qi->desc_status) {
free_page((unsigned long) qi->desc);
kfree(qi);
iommu->qi = 0;
return -ENOMEM;
}
qi->free_head = qi->free_tail = 0;
qi->free_cnt = QI_LENGTH;
spin_lock_init(&qi->q_lock);
spin_lock_irqsave(&iommu->register_lock, flags);
/* write zero to the tail reg */
writel(0, iommu->reg + DMAR_IQT_REG);
dmar_writeq(iommu->reg + DMAR_IQA_REG, virt_to_phys(qi->desc));
cmd = iommu->gcmd | DMA_GCMD_QIE;
iommu->gcmd |= DMA_GCMD_QIE;
writel(cmd, iommu->reg + DMAR_GCMD_REG);
/* Make sure hardware complete it */
IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_QIES), sts);
spin_unlock_irqrestore(&iommu->register_lock, flags);
return 0;
}

View file

@ -49,8 +49,6 @@
#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48 #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */
#define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1) #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
@ -58,8 +56,6 @@ static void flush_unmaps_timeout(unsigned long data);
DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0); DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0);
static struct intel_iommu *g_iommus;
#define HIGH_WATER_MARK 250 #define HIGH_WATER_MARK 250
struct deferred_flush_tables { struct deferred_flush_tables {
int next; int next;
@ -80,7 +76,7 @@ static long list_size;
static void domain_remove_dev_info(struct dmar_domain *domain); static void domain_remove_dev_info(struct dmar_domain *domain);
static int dmar_disabled; int dmar_disabled;
static int __initdata dmar_map_gfx = 1; static int __initdata dmar_map_gfx = 1;
static int dmar_forcedac; static int dmar_forcedac;
static int intel_iommu_strict; static int intel_iommu_strict;
@ -185,13 +181,6 @@ void free_iova_mem(struct iova *iova)
kmem_cache_free(iommu_iova_cache, iova); kmem_cache_free(iommu_iova_cache, iova);
} }
static inline void __iommu_flush_cache(
struct intel_iommu *iommu, void *addr, int size)
{
if (!ecap_coherent(iommu->ecap))
clflush_cache_range(addr, size);
}
/* Gets context entry for a given bus and devfn */ /* Gets context entry for a given bus and devfn */
static struct context_entry * device_to_context_entry(struct intel_iommu *iommu, static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
u8 bus, u8 devfn) u8 bus, u8 devfn)
@ -488,19 +477,6 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu)
return 0; return 0;
} }
#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
{\
cycles_t start_time = get_cycles();\
while (1) {\
sts = op (iommu->reg + offset);\
if (cond)\
break;\
if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
panic("DMAR hardware is malfunctioning\n");\
cpu_relax();\
}\
}
static void iommu_set_root_entry(struct intel_iommu *iommu) static void iommu_set_root_entry(struct intel_iommu *iommu)
{ {
void *addr; void *addr;
@ -990,6 +966,8 @@ static int iommu_init_domains(struct intel_iommu *iommu)
return -ENOMEM; return -ENOMEM;
} }
spin_lock_init(&iommu->lock);
/* /*
* if Caching mode is set, then invalid translations are tagged * if Caching mode is set, then invalid translations are tagged
* with domainid 0. Hence we need to pre-allocate it. * with domainid 0. Hence we need to pre-allocate it.
@ -998,62 +976,15 @@ static int iommu_init_domains(struct intel_iommu *iommu)
set_bit(0, iommu->domain_ids); set_bit(0, iommu->domain_ids);
return 0; return 0;
} }
static struct intel_iommu *alloc_iommu(struct intel_iommu *iommu,
struct dmar_drhd_unit *drhd)
{
int ret;
int map_size;
u32 ver;
iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K);
if (!iommu->reg) {
printk(KERN_ERR "IOMMU: can't map the region\n");
goto error;
}
iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
/* the registers might be more than one page */
map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
cap_max_fault_reg_offset(iommu->cap));
map_size = PAGE_ALIGN_4K(map_size);
if (map_size > PAGE_SIZE_4K) {
iounmap(iommu->reg);
iommu->reg = ioremap(drhd->reg_base_addr, map_size);
if (!iommu->reg) {
printk(KERN_ERR "IOMMU: can't map the region\n");
goto error;
}
}
ver = readl(iommu->reg + DMAR_VER_REG);
pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
iommu->cap, iommu->ecap);
ret = iommu_init_domains(iommu);
if (ret)
goto error_unmap;
spin_lock_init(&iommu->lock);
spin_lock_init(&iommu->register_lock);
drhd->iommu = iommu;
return iommu;
error_unmap:
iounmap(iommu->reg);
error:
kfree(iommu);
return NULL;
}
static void domain_exit(struct dmar_domain *domain); static void domain_exit(struct dmar_domain *domain);
static void free_iommu(struct intel_iommu *iommu)
void free_dmar_iommu(struct intel_iommu *iommu)
{ {
struct dmar_domain *domain; struct dmar_domain *domain;
int i; int i;
if (!iommu)
return;
i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap)); i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
for (; i < cap_ndoms(iommu->cap); ) { for (; i < cap_ndoms(iommu->cap); ) {
domain = iommu->domains[i]; domain = iommu->domains[i];
@ -1078,10 +1009,6 @@ static void free_iommu(struct intel_iommu *iommu)
/* free context mapping */ /* free context mapping */
free_context_table(iommu); free_context_table(iommu);
if (iommu->reg)
iounmap(iommu->reg);
kfree(iommu);
} }
static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu) static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
@ -1426,37 +1353,6 @@ find_domain(struct pci_dev *pdev)
return NULL; return NULL;
} }
static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
struct pci_dev *dev)
{
int index;
while (dev) {
for (index = 0; index < cnt; index++)
if (dev == devices[index])
return 1;
/* Check our parent */
dev = dev->bus->self;
}
return 0;
}
static struct dmar_drhd_unit *
dmar_find_matched_drhd_unit(struct pci_dev *dev)
{
struct dmar_drhd_unit *drhd = NULL;
list_for_each_entry(drhd, &dmar_drhd_units, list) {
if (drhd->include_all || dmar_pci_device_match(drhd->devices,
drhd->devices_cnt, dev))
return drhd;
}
return NULL;
}
/* domain is initialized */ /* domain is initialized */
static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
{ {
@ -1729,8 +1625,6 @@ int __init init_dmars(void)
* endfor * endfor
*/ */
for_each_drhd_unit(drhd) { for_each_drhd_unit(drhd) {
if (drhd->ignored)
continue;
g_num_of_iommus++; g_num_of_iommus++;
/* /*
* lock not needed as this is only incremented in the single * lock not needed as this is only incremented in the single
@ -1739,12 +1633,6 @@ int __init init_dmars(void)
*/ */
} }
g_iommus = kzalloc(g_num_of_iommus * sizeof(*iommu), GFP_KERNEL);
if (!g_iommus) {
ret = -ENOMEM;
goto error;
}
deferred_flush = kzalloc(g_num_of_iommus * deferred_flush = kzalloc(g_num_of_iommus *
sizeof(struct deferred_flush_tables), GFP_KERNEL); sizeof(struct deferred_flush_tables), GFP_KERNEL);
if (!deferred_flush) { if (!deferred_flush) {
@ -1752,16 +1640,15 @@ int __init init_dmars(void)
goto error; goto error;
} }
i = 0;
for_each_drhd_unit(drhd) { for_each_drhd_unit(drhd) {
if (drhd->ignored) if (drhd->ignored)
continue; continue;
iommu = alloc_iommu(&g_iommus[i], drhd);
i++; iommu = drhd->iommu;
if (!iommu) {
ret = -ENOMEM; ret = iommu_init_domains(iommu);
if (ret)
goto error; goto error;
}
/* /*
* TBD: * TBD:
@ -1845,7 +1732,6 @@ error:
iommu = drhd->iommu; iommu = drhd->iommu;
free_iommu(iommu); free_iommu(iommu);
} }
kfree(g_iommus);
return ret; return ret;
} }
@ -2002,7 +1888,10 @@ static void flush_unmaps(void)
/* just flush them all */ /* just flush them all */
for (i = 0; i < g_num_of_iommus; i++) { for (i = 0; i < g_num_of_iommus; i++) {
if (deferred_flush[i].next) { if (deferred_flush[i].next) {
iommu_flush_iotlb_global(&g_iommus[i], 0); struct intel_iommu *iommu =
deferred_flush[i].domain[0]->iommu;
iommu_flush_iotlb_global(iommu, 0);
for (j = 0; j < deferred_flush[i].next; j++) { for (j = 0; j < deferred_flush[i].next; j++) {
__free_iova(&deferred_flush[i].domain[j]->iovad, __free_iova(&deferred_flush[i].domain[j]->iovad,
deferred_flush[i].iova[j]); deferred_flush[i].iova[j]);
@ -2032,7 +1921,8 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova)
if (list_size == HIGH_WATER_MARK) if (list_size == HIGH_WATER_MARK)
flush_unmaps(); flush_unmaps();
iommu_id = dom->iommu - g_iommus; iommu_id = dom->iommu->seq_id;
next = deferred_flush[iommu_id].next; next = deferred_flush[iommu_id].next;
deferred_flush[iommu_id].domain[next] = dom; deferred_flush[iommu_id].domain[next] = dom;
deferred_flush[iommu_id].iova[next] = iova; deferred_flush[iommu_id].iova[next] = iova;
@ -2348,15 +2238,6 @@ static void __init iommu_exit_mempool(void)
} }
void __init detect_intel_iommu(void)
{
if (swiotlb || no_iommu || iommu_detected || dmar_disabled)
return;
if (early_dmar_detect()) {
iommu_detected = 1;
}
}
static void __init init_no_remapping_devices(void) static void __init init_no_remapping_devices(void)
{ {
struct dmar_drhd_unit *drhd; struct dmar_drhd_unit *drhd;
@ -2403,10 +2284,17 @@ int __init intel_iommu_init(void)
{ {
int ret = 0; int ret = 0;
if (no_iommu || swiotlb || dmar_disabled) if (dmar_table_init())
return -ENODEV; return -ENODEV;
if (dmar_table_init()) if (dmar_dev_scope_init())
return -ENODEV;
/*
* Check the need for DMA-remapping initialization now.
* Above initialization will also be used by Interrupt-remapping.
*/
if (no_iommu || swiotlb || dmar_disabled)
return -ENODEV; return -ENODEV;
iommu_init_mempool(); iommu_init_mempool();

View file

@ -27,19 +27,8 @@
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include "iova.h" #include "iova.h"
#include <linux/io.h> #include <linux/io.h>
#include <asm/cacheflush.h>
/* #include "dma_remapping.h"
* We need a fixed PAGE_SIZE of 4K irrespective of
* arch PAGE_SIZE for IOMMU page tables.
*/
#define PAGE_SHIFT_4K (12)
#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K)
#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
/* /*
* Intel IOMMU register specification per version 1.0 public spec. * Intel IOMMU register specification per version 1.0 public spec.
@ -63,6 +52,11 @@
#define DMAR_PLMLIMIT_REG 0x6c /* PMRR low limit */ #define DMAR_PLMLIMIT_REG 0x6c /* PMRR low limit */
#define DMAR_PHMBASE_REG 0x70 /* pmrr high base addr */ #define DMAR_PHMBASE_REG 0x70 /* pmrr high base addr */
#define DMAR_PHMLIMIT_REG 0x78 /* pmrr high limit */ #define DMAR_PHMLIMIT_REG 0x78 /* pmrr high limit */
#define DMAR_IQH_REG 0x80 /* Invalidation queue head register */
#define DMAR_IQT_REG 0x88 /* Invalidation queue tail register */
#define DMAR_IQA_REG 0x90 /* Invalidation queue addr register */
#define DMAR_ICS_REG 0x98 /* Invalidation complete status register */
#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr register */
#define OFFSET_STRIDE (9) #define OFFSET_STRIDE (9)
/* /*
@ -126,6 +120,10 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define ecap_max_iotlb_offset(e) \ #define ecap_max_iotlb_offset(e) \
(ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16) (ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16)
#define ecap_coherent(e) ((e) & 0x1) #define ecap_coherent(e) ((e) & 0x1)
#define ecap_qis(e) ((e) & 0x2)
#define ecap_eim_support(e) ((e >> 4) & 0x1)
#define ecap_ir_support(e) ((e >> 3) & 0x1)
#define ecap_max_handle_mask(e) ((e >> 20) & 0xf)
/* IOTLB_REG */ /* IOTLB_REG */
@ -141,6 +139,17 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define DMA_TLB_IH_NONLEAF (((u64)1) << 6) #define DMA_TLB_IH_NONLEAF (((u64)1) << 6)
#define DMA_TLB_MAX_SIZE (0x3f) #define DMA_TLB_MAX_SIZE (0x3f)
/* INVALID_DESC */
#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 3)
#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 3)
#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 3)
#define DMA_ID_TLB_READ_DRAIN (((u64)1) << 7)
#define DMA_ID_TLB_WRITE_DRAIN (((u64)1) << 6)
#define DMA_ID_TLB_DID(id) (((u64)((id & 0xffff) << 16)))
#define DMA_ID_TLB_IH_NONLEAF (((u64)1) << 6)
#define DMA_ID_TLB_ADDR(addr) (addr)
#define DMA_ID_TLB_ADDR_MASK(mask) (mask)
/* PMEN_REG */ /* PMEN_REG */
#define DMA_PMEN_EPM (((u32)1)<<31) #define DMA_PMEN_EPM (((u32)1)<<31)
#define DMA_PMEN_PRS (((u32)1)<<0) #define DMA_PMEN_PRS (((u32)1)<<0)
@ -151,6 +160,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define DMA_GCMD_SFL (((u32)1) << 29) #define DMA_GCMD_SFL (((u32)1) << 29)
#define DMA_GCMD_EAFL (((u32)1) << 28) #define DMA_GCMD_EAFL (((u32)1) << 28)
#define DMA_GCMD_WBF (((u32)1) << 27) #define DMA_GCMD_WBF (((u32)1) << 27)
#define DMA_GCMD_QIE (((u32)1) << 26)
#define DMA_GCMD_SIRTP (((u32)1) << 24)
#define DMA_GCMD_IRE (((u32) 1) << 25)
/* GSTS_REG */ /* GSTS_REG */
#define DMA_GSTS_TES (((u32)1) << 31) #define DMA_GSTS_TES (((u32)1) << 31)
@ -158,6 +170,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define DMA_GSTS_FLS (((u32)1) << 29) #define DMA_GSTS_FLS (((u32)1) << 29)
#define DMA_GSTS_AFLS (((u32)1) << 28) #define DMA_GSTS_AFLS (((u32)1) << 28)
#define DMA_GSTS_WBFS (((u32)1) << 27) #define DMA_GSTS_WBFS (((u32)1) << 27)
#define DMA_GSTS_QIES (((u32)1) << 26)
#define DMA_GSTS_IRTPS (((u32)1) << 24)
#define DMA_GSTS_IRES (((u32)1) << 25)
/* CCMD_REG */ /* CCMD_REG */
#define DMA_CCMD_ICC (((u64)1) << 63) #define DMA_CCMD_ICC (((u64)1) << 63)
@ -187,158 +202,106 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define dma_frcd_source_id(c) (c & 0xffff) #define dma_frcd_source_id(c) (c & 0xffff)
#define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */ #define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */
/* #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */
* 0: Present
* 1-11: Reserved #define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
* 12-63: Context Ptr (12 - (haw-1)) {\
* 64-127: Reserved cycles_t start_time = get_cycles();\
*/ while (1) {\
struct root_entry { sts = op (iommu->reg + offset);\
u64 val; if (cond)\
u64 rsvd1; break;\
}; if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\
#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry)) panic("DMAR hardware is malfunctioning\n");\
static inline bool root_present(struct root_entry *root) cpu_relax();\
{ }\
return (root->val & 1);
}
static inline void set_root_present(struct root_entry *root)
{
root->val |= 1;
}
static inline void set_root_value(struct root_entry *root, unsigned long value)
{
root->val |= value & PAGE_MASK_4K;
} }
struct context_entry; #define QI_LENGTH 256 /* queue length */
static inline struct context_entry *
get_context_addr_from_root(struct root_entry *root)
{
return (struct context_entry *)
(root_present(root)?phys_to_virt(
root->val & PAGE_MASK_4K):
NULL);
}
/* enum {
* low 64 bits: QI_FREE,
* 0: present QI_IN_USE,
* 1: fault processing disable QI_DONE
* 2-3: translation type
* 12-63: address space root
* high 64 bits:
* 0-2: address width
* 3-6: aval
* 8-23: domain id
*/
struct context_entry {
u64 lo;
u64 hi;
};
#define context_present(c) ((c).lo & 1)
#define context_fault_disable(c) (((c).lo >> 1) & 1)
#define context_translation_type(c) (((c).lo >> 2) & 3)
#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
#define context_address_width(c) ((c).hi & 7)
#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
#define context_set_present(c) do {(c).lo |= 1;} while (0)
#define context_set_fault_enable(c) \
do {(c).lo &= (((u64)-1) << 2) | 1;} while (0)
#define context_set_translation_type(c, val) \
do { \
(c).lo &= (((u64)-1) << 4) | 3; \
(c).lo |= ((val) & 3) << 2; \
} while (0)
#define CONTEXT_TT_MULTI_LEVEL 0
#define context_set_address_root(c, val) \
do {(c).lo |= (val) & PAGE_MASK_4K;} while (0)
#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
#define context_set_domain_id(c, val) \
do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0)
/*
* 0: readable
* 1: writable
* 2-6: reserved
* 7: super page
* 8-11: available
* 12-63: Host physcial address
*/
struct dma_pte {
u64 val;
};
#define dma_clear_pte(p) do {(p).val = 0;} while (0)
#define DMA_PTE_READ (1)
#define DMA_PTE_WRITE (2)
#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0)
#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
#define dma_set_pte_prot(p, prot) \
do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
#define dma_set_pte_addr(p, addr) do {\
(p).val |= ((addr) & PAGE_MASK_4K); } while (0)
#define dma_pte_present(p) (((p).val & 3) != 0)
struct intel_iommu;
struct dmar_domain {
int id; /* domain id */
struct intel_iommu *iommu; /* back pointer to owning iommu */
struct list_head devices; /* all devices' list */
struct iova_domain iovad; /* iova's that belong to this domain */
struct dma_pte *pgd; /* virtual address */
spinlock_t mapping_lock; /* page table lock */
int gaw; /* max guest address width */
/* adjusted guest address width, 0 is level 2 30-bit */
int agaw;
#define DOMAIN_FLAG_MULTIPLE_DEVICES 1
int flags;
}; };
/* PCI domain-device relationship */ #define QI_CC_TYPE 0x1
struct device_domain_info { #define QI_IOTLB_TYPE 0x2
struct list_head link; /* link to domain siblings */ #define QI_DIOTLB_TYPE 0x3
struct list_head global; /* link to global list */ #define QI_IEC_TYPE 0x4
u8 bus; /* PCI bus numer */ #define QI_IWD_TYPE 0x5
u8 devfn; /* PCI devfn number */
struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */ #define QI_IEC_SELECTIVE (((u64)1) << 4)
struct dmar_domain *domain; /* pointer to domain */ #define QI_IEC_IIDEX(idx) (((u64)(idx & 0xffff) << 32))
#define QI_IEC_IM(m) (((u64)(m & 0x1f) << 27))
#define QI_IWD_STATUS_DATA(d) (((u64)d) << 32)
#define QI_IWD_STATUS_WRITE (((u64)1) << 5)
struct qi_desc {
u64 low, high;
}; };
extern int init_dmars(void); struct q_inval {
spinlock_t q_lock;
struct qi_desc *desc; /* invalidation queue */
int *desc_status; /* desc status */
int free_head; /* first free entry */
int free_tail; /* last free entry */
int free_cnt;
};
#ifdef CONFIG_INTR_REMAP
/* 1MB - maximum possible interrupt remapping table size */
#define INTR_REMAP_PAGE_ORDER 8
#define INTR_REMAP_TABLE_REG_SIZE 0xf
#define INTR_REMAP_TABLE_ENTRIES 65536
struct ir_table {
struct irte *base;
};
#endif
struct intel_iommu { struct intel_iommu {
void __iomem *reg; /* Pointer to hardware regs, virtual addr */ void __iomem *reg; /* Pointer to hardware regs, virtual addr */
u64 cap; u64 cap;
u64 ecap; u64 ecap;
unsigned long *domain_ids; /* bitmap of domains */
struct dmar_domain **domains; /* ptr to domains */
int seg; int seg;
u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */ u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
spinlock_t lock; /* protect context, domain ids */
spinlock_t register_lock; /* protect register handling */ spinlock_t register_lock; /* protect register handling */
int seq_id; /* sequence id of the iommu */
#ifdef CONFIG_DMAR
unsigned long *domain_ids; /* bitmap of domains */
struct dmar_domain **domains; /* ptr to domains */
spinlock_t lock; /* protect context, domain ids */
struct root_entry *root_entry; /* virtual address */ struct root_entry *root_entry; /* virtual address */
unsigned int irq; unsigned int irq;
unsigned char name[7]; /* Device Name */ unsigned char name[7]; /* Device Name */
struct msi_msg saved_msg; struct msi_msg saved_msg;
struct sys_device sysdev; struct sys_device sysdev;
#endif
struct q_inval *qi; /* Queued invalidation info */
#ifdef CONFIG_INTR_REMAP
struct ir_table *ir_table; /* Interrupt remapping info */
#endif
}; };
#ifndef CONFIG_DMAR_GFX_WA static inline void __iommu_flush_cache(
static inline void iommu_prepare_gfx_mapping(void) struct intel_iommu *iommu, void *addr, int size)
{ {
return; if (!ecap_coherent(iommu->ecap))
clflush_cache_range(addr, size);
} }
#endif /* !CONFIG_DMAR_GFX_WA */
extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
extern int alloc_iommu(struct dmar_drhd_unit *drhd);
extern void free_iommu(struct intel_iommu *iommu);
extern int dmar_enable_qi(struct intel_iommu *iommu);
extern void qi_global_iec(struct intel_iommu *iommu);
extern void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
#endif #endif

Some files were not shown because too many files have changed in this diff Show more