From 831d991821daedd4839073dbca55514432ef1768 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 3 Sep 2007 10:17:39 +0200 Subject: x86: add PCI extended config space access for AMD Barcelona This patch implements PCI extended configuration space access for AMD's Barcelona CPUs. It extends the method using CF8/CFC IO addresses. An x86 capability bit has been introduced that is set for CPUs supporting PCI extended config space accesses. Signed-off-by: Robert Richter Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/amd.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/x86/kernel/cpu/amd.c') diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 24586682829..99221f9834e 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -6,6 +6,7 @@ #include #include +#include "../setup.h" #include "cpu.h" /* @@ -308,6 +309,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) if (cpu_has_xmm2) set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); + + if (c->x86 == 0x10) + amd_enable_pci_ext_cfg(c); } static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) -- cgit v1.2.3-70-g09d2 From 1a5726528a70bb239bdd149aef7f2155cd2b1699 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 2 Jun 2008 12:21:36 +0200 Subject: fix build bug in "x86: add PCI extended config space access for AMD Barcelona" --- arch/x86/kernel/cpu/amd.c | 1 + include/asm-x86/mmconfig.h | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'arch/x86/kernel/cpu/amd.c') diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 99221f9834e..656b40aed64 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "../setup.h" diff --git a/include/asm-x86/mmconfig.h b/include/asm-x86/mmconfig.h index 46d6bb135df..691798fbee1 100644 --- a/include/asm-x86/mmconfig.h +++ b/include/asm-x86/mmconfig.h @@ -9,6 +9,10 @@ static inline void fam10h_check_enable_mmcfg(void) { } static inline void check_enable_amd_mmconf_dmi(void) { } #endif +#if defined(CONFIG_SMP) && defined(CONFIG_X86_64) extern void __cpuinit amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c); +#else +static inline void amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c) { } +#endif #endif -- cgit v1.2.3-70-g09d2 From 9e26d84273541a8c6c2efb705457ca8e6245fb73 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 6 Jun 2008 12:01:13 +0200 Subject: fix build bug in "x86: add PCI extended config space access for AMD Barcelona" Also much less code now. Signed-off-by: Robert Richter Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/amd.c | 2 -- arch/x86/kernel/cpu/amd_64.c | 1 + arch/x86/kernel/cpu/cpu.h | 5 +++++ arch/x86/kernel/setup.c | 2 +- arch/x86/kernel/setup.h | 26 -------------------------- arch/x86/kernel/setup_64.c | 2 -- include/asm-x86/mmconfig.h | 6 ------ 7 files changed, 7 insertions(+), 37 deletions(-) delete mode 100644 arch/x86/kernel/setup.h (limited to 'arch/x86/kernel/cpu/amd.c') diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 656b40aed64..a38d54f4ff2 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -4,10 +4,8 @@ #include #include #include -#include #include -#include "../setup.h" #include "cpu.h" /* diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c index 180097e9921..626fc21f027 100644 --- a/arch/x86/kernel/cpu/amd_64.c +++ b/arch/x86/kernel/cpu/amd_64.c @@ -6,6 +6,7 @@ #include #include +#include "cpu.h" extern int __cpuinit get_model_name(struct cpuinfo_x86 *c); extern void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c); diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h index 783691b2a73..f5d5bb1b554 100644 --- a/arch/x86/kernel/cpu/cpu.h +++ b/arch/x86/kernel/cpu/cpu.h @@ -1,3 +1,4 @@ +#ifdef CONFIG_X86_32 struct cpu_model_info { int vendor; @@ -36,3 +37,7 @@ extern struct cpu_vendor_dev __x86cpuvendor_start[], __x86cpuvendor_end[]; extern int get_model_name(struct cpuinfo_x86 *c); extern void display_cacheinfo(struct cpuinfo_x86 *c); + +#endif /* CONFIG_X86_32 */ + +extern void __cpuinit amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index d8f17123401..20e14dbef10 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -136,6 +136,7 @@ void __init setup_per_cpu_areas(void) setup_cpumask_of_cpu(); } +#endif #define ENABLE_CF8_EXT_CFG (1ULL << 46) void __cpuinit amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c) @@ -149,4 +150,3 @@ void __cpuinit amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c) set_cpu_cap(c, X86_FEATURE_PCI_EXT_CFG); } -#endif diff --git a/arch/x86/kernel/setup.h b/arch/x86/kernel/setup.h deleted file mode 100644 index 66cc2c7f961..00000000000 --- a/arch/x86/kernel/setup.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Internal declarations for shared x86 setup code. - * - * Copyright (c) 2008 Advanced Micro Devices, Inc. - * Contributed by Robert Richter - * - * 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 will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#ifndef _ARCH_X86_KERNEL_SETUP_H - -extern void __cpuinit amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c); - -#endif /* _ARCH_X86_KERNEL_SETUP_H */ diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index 215bd67e5b6..25afdd80a3c 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c @@ -73,8 +73,6 @@ #include #include -#include "setup.h" - #include #ifdef CONFIG_PARAVIRT #include diff --git a/include/asm-x86/mmconfig.h b/include/asm-x86/mmconfig.h index 691798fbee1..95beda07c6f 100644 --- a/include/asm-x86/mmconfig.h +++ b/include/asm-x86/mmconfig.h @@ -9,10 +9,4 @@ static inline void fam10h_check_enable_mmcfg(void) { } static inline void check_enable_amd_mmconf_dmi(void) { } #endif -#if defined(CONFIG_SMP) && defined(CONFIG_X86_64) -extern void __cpuinit amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c); -#else -static inline void amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c) { } -#endif - #endif -- cgit v1.2.3-70-g09d2 From aa83f3f2cfc74d66d01b1d2eb1485ea1103a0f4e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 9 Jun 2008 17:11:13 +0200 Subject: x86: cleanup C1E enabled detection Rename the "MSR_K8_ENABLE_C1E" MSR to INT_PENDING_MSG, which is the name in the data sheet as well. Move the C1E mask to the header file. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/amd.c | 5 ++--- arch/x86/kernel/cpu/amd_64.c | 5 ++--- include/asm-x86/msr-index.h | 4 +++- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'arch/x86/kernel/cpu/amd.c') diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index a38d54f4ff2..30b5055be35 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -25,7 +25,6 @@ extern void vide(void); __asm__(".align 4\nvide: ret"); #ifdef CONFIG_X86_LOCAL_APIC -#define ENABLE_C1E_MASK 0x18000000 #define CPUID_PROCESSOR_SIGNATURE 1 #define CPUID_XFAM 0x0ff00000 #define CPUID_XFAM_K8 0x00000000 @@ -45,8 +44,8 @@ static __cpuinit int amd_apic_timer_broken(void) break; case CPUID_XFAM_10H: case CPUID_XFAM_11H: - rdmsr(MSR_K8_ENABLE_C1E, lo, hi); - if (lo & ENABLE_C1E_MASK) { + rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); + if (lo & K8_INTP_C1E_ACTIVE_MASK) { if (smp_processor_id() != boot_cpu_physical_apicid) printk(KERN_INFO "AMD C1E detected late. " " Force timer broadcast.\n"); diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c index 626fc21f027..6eef3c79d15 100644 --- a/arch/x86/kernel/cpu/amd_64.c +++ b/arch/x86/kernel/cpu/amd_64.c @@ -110,7 +110,6 @@ static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c) #endif } -#define ENABLE_C1E_MASK 0x18000000 #define CPUID_PROCESSOR_SIGNATURE 1 #define CPUID_XFAM 0x0ff00000 #define CPUID_XFAM_K8 0x00000000 @@ -130,8 +129,8 @@ static __cpuinit int amd_apic_timer_broken(void) break; case CPUID_XFAM_10H: case CPUID_XFAM_11H: - rdmsr(MSR_K8_ENABLE_C1E, lo, hi); - if (lo & ENABLE_C1E_MASK) + rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); + if (lo & K8_INTP_C1E_ACTIVE_MASK) return 1; break; default: diff --git a/include/asm-x86/msr-index.h b/include/asm-x86/msr-index.h index 09413ad39d3..44bce773012 100644 --- a/include/asm-x86/msr-index.h +++ b/include/asm-x86/msr-index.h @@ -111,7 +111,9 @@ #define MSR_K8_TOP_MEM2 0xc001001d #define MSR_K8_SYSCFG 0xc0010010 #define MSR_K8_HWCR 0xc0010015 -#define MSR_K8_ENABLE_C1E 0xc0010055 +#define MSR_K8_INT_PENDING_MSG 0xc0010055 +/* C1E active bits in int pending message */ +#define K8_INTP_C1E_ACTIVE_MASK 0x18000000 #define MSR_K8_TSEG_ADDR 0xc0010112 #define K8_MTRRFIXRANGE_DRAM_ENABLE 0x00040000 /* MtrrFixDramEn bit */ #define K8_MTRRFIXRANGE_DRAM_MODIFY 0x00080000 /* MtrrFixDramModEn bit */ -- cgit v1.2.3-70-g09d2 From 732d7be17b98ebfd59e5864c3490f19856fa832c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 9 Jun 2008 17:27:20 +0200 Subject: x86: use cpuinfo to check for interrupt pending message msr Simplify code: no need to do a cpuid(1) again. The cpuinfo structure has all necessary information already. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/amd.c | 41 +++++++++++++++-------------------------- arch/x86/kernel/cpu/amd_64.c | 38 +++++++++++++++----------------------- 2 files changed, 30 insertions(+), 49 deletions(-) (limited to 'arch/x86/kernel/cpu/amd.c') diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 30b5055be35..e76b49e7a91 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -25,35 +25,24 @@ extern void vide(void); __asm__(".align 4\nvide: ret"); #ifdef CONFIG_X86_LOCAL_APIC -#define CPUID_PROCESSOR_SIGNATURE 1 -#define CPUID_XFAM 0x0ff00000 -#define CPUID_XFAM_K8 0x00000000 -#define CPUID_XFAM_10H 0x00100000 -#define CPUID_XFAM_11H 0x00200000 -#define CPUID_XMOD 0x000f0000 -#define CPUID_XMOD_REV_F 0x00040000 /* AMD systems with C1E don't have a working lAPIC timer. Check for that. */ -static __cpuinit int amd_apic_timer_broken(void) +static __cpuinit int amd_apic_timer_broken(struct cpuinfo_x86 *c) { u32 lo, hi; - u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); - switch (eax & CPUID_XFAM) { - case CPUID_XFAM_K8: - if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F) - break; - case CPUID_XFAM_10H: - case CPUID_XFAM_11H: - rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); - if (lo & K8_INTP_C1E_ACTIVE_MASK) { - if (smp_processor_id() != boot_cpu_physical_apicid) - printk(KERN_INFO "AMD C1E detected late. " - " Force timer broadcast.\n"); - return 1; - } - break; - default: - /* err on the side of caution */ + + if (c->x86 < 0x0F) + return 0; + + /* Family 0x0f models < rev F do not have this MSR */ + if (c->x86 == 0x0f && c->x86_model < 0x40) + return 0; + + rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); + if (lo & K8_INTP_C1E_ACTIVE_MASK) { + if (smp_processor_id() != boot_cpu_physical_apicid) + printk(KERN_INFO "AMD C1E detected late. " + "Force timer broadcast.\n"); return 1; } return 0; @@ -297,7 +286,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) } #ifdef CONFIG_X86_LOCAL_APIC - if (amd_apic_timer_broken()) + if (amd_apic_timer_broken(c)) local_apic_timer_disabled = 1; #endif diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c index 6eef3c79d15..f5fc161d8f2 100644 --- a/arch/x86/kernel/cpu/amd_64.c +++ b/arch/x86/kernel/cpu/amd_64.c @@ -110,31 +110,23 @@ static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c) #endif } -#define CPUID_PROCESSOR_SIGNATURE 1 -#define CPUID_XFAM 0x0ff00000 -#define CPUID_XFAM_K8 0x00000000 -#define CPUID_XFAM_10H 0x00100000 -#define CPUID_XFAM_11H 0x00200000 -#define CPUID_XMOD 0x000f0000 -#define CPUID_XMOD_REV_F 0x00040000 - /* AMD systems with C1E don't have a working lAPIC timer. Check for that. */ -static __cpuinit int amd_apic_timer_broken(void) +static __cpuinit int amd_apic_timer_broken(struct cpuinfo_x86 *c) { - u32 lo, hi, eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); + u32 lo, hi; - switch (eax & CPUID_XFAM) { - case CPUID_XFAM_K8: - if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F) - break; - case CPUID_XFAM_10H: - case CPUID_XFAM_11H: - rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); - if (lo & K8_INTP_C1E_ACTIVE_MASK) - return 1; - break; - default: - /* err on the side of caution */ + if (c->x86 < 0x0F) + return 0; + + /* Family 0x0f models < rev F do not have this MSR */ + if (c->x86 == 0x0f && c->x86_model < 0x40) + return 0; + + rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); + if (lo & K8_INTP_C1E_ACTIVE_MASK) { + if (smp_processor_id() != boot_cpu_physical_apicid) + printk(KERN_INFO "AMD C1E detected late. " + "Force timer broadcast.\n"); return 1; } return 0; @@ -220,7 +212,7 @@ void __cpuinit init_amd(struct cpuinfo_x86 *c) if (c->x86 == 0x10) amd_enable_pci_ext_cfg(c); - if (amd_apic_timer_broken()) + if (amd_apic_timer_broken(c)) disable_apic_timer = 1; if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) { -- cgit v1.2.3-70-g09d2 From aa276e1cafb3ce9d01d1e837bcd67e92616013ac Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 9 Jun 2008 19:15:00 +0200 Subject: x86, clockevents: add C1E aware idle function C1E on AMD machines is like C3 but without control from the OS. Up to now we disabled the local apic timer for those machines as it stops when the CPU goes into C1E. This excludes those machines from high resolution timers / dynamic ticks, which hurts especially X2 based laptops. The current boot time C1E detection has another, more serious flaw as well: some BIOSes do not enable C1E until the ACPI processor module is loaded. This causes systems to stop working after that point. To work nicely with C1E enabled machines we use a separate idle function, which checks on idle entry whether C1E was enabled in the Interrupt Pending Message MSR. This allows us to do timer broadcasting for C1E and covers the late enablement of C1E as well. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic_32.c | 5 ++-- arch/x86/kernel/apic_64.c | 26 +---------------- arch/x86/kernel/cpu/amd.c | 30 -------------------- arch/x86/kernel/cpu/amd_64.c | 25 ----------------- arch/x86/kernel/process.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/apic.h | 3 -- kernel/time/tick-broadcast.c | 6 ++-- 7 files changed, 73 insertions(+), 88 deletions(-) (limited to 'arch/x86/kernel/cpu/amd.c') diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c index 4b99b1bdeb6..c44206e731d 100644 --- a/arch/x86/kernel/apic_32.c +++ b/arch/x86/kernel/apic_32.c @@ -64,9 +64,8 @@ static int enable_local_apic __initdata; /* Local APIC timer verification ok */ static int local_apic_timer_verify_ok; -/* Disable local APIC timer from the kernel commandline or via dmi quirk - or using CPU MSR check */ -int local_apic_timer_disabled; +/* Disable local APIC timer from the kernel commandline or via dmi quirk */ +static int local_apic_timer_disabled; /* Local APIC timer works in C2 */ int local_apic_timer_c2_ok; EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 0633cfd0dc2..a5cc8447cf4 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c @@ -43,7 +43,7 @@ #include #include -int disable_apic_timer __cpuinitdata; +static int disable_apic_timer __cpuinitdata; static int apic_calibrate_pmtmr __initdata; int disable_apic; @@ -422,32 +422,8 @@ void __init setup_boot_APIC_clock(void) setup_APIC_timer(); } -/* - * AMD C1E enabled CPUs have a real nasty problem: Some BIOSes set the - * C1E flag only in the secondary CPU, so when we detect the wreckage - * we already have enabled the boot CPU local apic timer. Check, if - * disable_apic_timer is set and the DUMMY flag is cleared. If yes, - * set the DUMMY flag again and force the broadcast mode in the - * clockevents layer. - */ -static void __cpuinit check_boot_apic_timer_broadcast(void) -{ - if (!disable_apic_timer || - (lapic_clockevent.features & CLOCK_EVT_FEAT_DUMMY)) - return; - - printk(KERN_INFO "AMD C1E detected late. Force timer broadcast.\n"); - lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY; - - local_irq_enable(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE, - &boot_cpu_physical_apicid); - local_irq_disable(); -} - void __cpuinit setup_secondary_APIC_clock(void) { - check_boot_apic_timer_broadcast(); setup_APIC_timer(); } diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index e76b49e7a91..acc891ae590 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -24,31 +24,6 @@ extern void vide(void); __asm__(".align 4\nvide: ret"); -#ifdef CONFIG_X86_LOCAL_APIC - -/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */ -static __cpuinit int amd_apic_timer_broken(struct cpuinfo_x86 *c) -{ - u32 lo, hi; - - if (c->x86 < 0x0F) - return 0; - - /* Family 0x0f models < rev F do not have this MSR */ - if (c->x86 == 0x0f && c->x86_model < 0x40) - return 0; - - rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); - if (lo & K8_INTP_C1E_ACTIVE_MASK) { - if (smp_processor_id() != boot_cpu_physical_apicid) - printk(KERN_INFO "AMD C1E detected late. " - "Force timer broadcast.\n"); - return 1; - } - return 0; -} -#endif - int force_mwait __cpuinitdata; static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) @@ -285,11 +260,6 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) num_cache_leaves = 3; } -#ifdef CONFIG_X86_LOCAL_APIC - if (amd_apic_timer_broken(c)) - local_apic_timer_disabled = 1; -#endif - /* K6s reports MCEs but don't actually have all the MSRs */ if (c->x86 < 6) clear_cpu_cap(c, X86_FEATURE_MCE); diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c index f5fc161d8f2..f8d20588bde 100644 --- a/arch/x86/kernel/cpu/amd_64.c +++ b/arch/x86/kernel/cpu/amd_64.c @@ -110,28 +110,6 @@ static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c) #endif } -/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */ -static __cpuinit int amd_apic_timer_broken(struct cpuinfo_x86 *c) -{ - u32 lo, hi; - - if (c->x86 < 0x0F) - return 0; - - /* Family 0x0f models < rev F do not have this MSR */ - if (c->x86 == 0x0f && c->x86_model < 0x40) - return 0; - - rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); - if (lo & K8_INTP_C1E_ACTIVE_MASK) { - if (smp_processor_id() != boot_cpu_physical_apicid) - printk(KERN_INFO "AMD C1E detected late. " - "Force timer broadcast.\n"); - return 1; - } - return 0; -} - void __cpuinit early_init_amd(struct cpuinfo_x86 *c) { early_init_amd_mc(c); @@ -212,9 +190,6 @@ void __cpuinit init_amd(struct cpuinfo_x86 *c) if (c->x86 == 0x10) amd_enable_pci_ext_cfg(c); - if (amd_apic_timer_broken(c)) - disable_apic_timer = 1; - if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) { unsigned long long tseg; diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 9fea14607df..68ad3539b14 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -6,6 +6,7 @@ #include #include #include +#include struct kmem_cache *task_xstate_cachep; @@ -219,6 +220,68 @@ static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c) return (edx & MWAIT_EDX_C1); } +/* + * Check for AMD CPUs, which have potentially C1E support + */ +static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c) +{ + if (c->x86_vendor != X86_VENDOR_AMD) + return 0; + + if (c->x86 < 0x0F) + return 0; + + /* Family 0x0f models < rev F do not have C1E */ + if (c->x86 == 0x0f && c->x86_model < 0x40) + return 0; + + return 1; +} + +/* + * C1E aware idle routine. We check for C1E active in the interrupt + * pending message MSR. If we detect C1E, then we handle it the same + * way as C3 power states (local apic timer and TSC stop) + */ +static void c1e_idle(void) +{ + static cpumask_t c1e_mask = CPU_MASK_NONE; + static int c1e_detected; + + if (need_resched()) + return; + + if (!c1e_detected) { + u32 lo, hi; + + rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi); + if (lo & K8_INTP_C1E_ACTIVE_MASK) { + c1e_detected = 1; + mark_tsc_unstable("TSC halt in C1E"); + printk(KERN_INFO "System has C1E enabled\n"); + } + } + + if (c1e_detected) { + int cpu = smp_processor_id(); + + if (!cpu_isset(cpu, c1e_mask)) { + cpu_set(cpu, c1e_mask); + /* Force broadcast so ACPI can not interfere */ + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE, + &cpu); + printk(KERN_INFO "Switch to broadcast mode on CPU%d\n", + cpu); + } + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); + default_idle(); + local_irq_disable(); + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); + local_irq_enable(); + } else + default_idle(); +} + void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) { #ifdef CONFIG_X86_SMP @@ -236,6 +299,9 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) */ printk(KERN_INFO "using mwait in idle threads.\n"); pm_idle = mwait_idle; + } else if (check_c1e_idle(c)) { + printk(KERN_INFO "using C1E aware idle routine\n"); + pm_idle = c1e_idle; } else pm_idle = default_idle; } diff --git a/include/asm-x86/apic.h b/include/asm-x86/apic.h index be9639a9a18..3c387cda95f 100644 --- a/include/asm-x86/apic.h +++ b/include/asm-x86/apic.h @@ -38,12 +38,9 @@ extern void generic_apic_probe(void); extern int apic_verbosity; extern int timer_over_8254; extern int local_apic_timer_c2_ok; -extern int local_apic_timer_disabled; -extern int apic_runs_main_timer; extern int ioapic_force; extern int disable_apic; -extern int disable_apic_timer; /* * Basic functions accessing APICs. diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 57a1f02e5ec..67f80c26170 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -30,6 +30,7 @@ struct tick_device tick_broadcast_device; static cpumask_t tick_broadcast_mask; static DEFINE_SPINLOCK(tick_broadcast_lock); +static int tick_broadcast_force; #ifdef CONFIG_TICK_ONESHOT static void tick_broadcast_clear_oneshot(int cpu); @@ -232,10 +233,11 @@ static void tick_do_broadcast_on_off(void *why) CLOCK_EVT_MODE_SHUTDOWN); } if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE) - dev->features |= CLOCK_EVT_FEAT_DUMMY; + tick_broadcast_force = 1; break; case CLOCK_EVT_NOTIFY_BROADCAST_OFF: - if (cpu_isset(cpu, tick_broadcast_mask)) { + if (!tick_broadcast_force && + cpu_isset(cpu, tick_broadcast_mask)) { cpu_clear(cpu, tick_broadcast_mask); if (td->mode == TICKDEV_MODE_PERIODIC) tick_setup_periodic(dev, 0); -- cgit v1.2.3-70-g09d2 From 3a27dd1ce5de08e21e0266ddf00e6f1f843bfe8b Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 12 Jun 2008 20:19:23 +0200 Subject: x86: Move PCI IO ECS code to x86/pci "Form follows function". Code is now where it belongs to. Signed-off-by: Robert Richter Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/amd.c | 3 --- arch/x86/kernel/cpu/amd_64.c | 4 ---- arch/x86/kernel/cpu/cpu.h | 2 -- arch/x86/kernel/setup.c | 13 ------------- arch/x86/pci/Makefile_32 | 1 + arch/x86/pci/amd_bus.c | 32 ++++++++++++++++++++++++++++++++ arch/x86/pci/direct.c | 16 +++++++++------- arch/x86/pci/pci.h | 1 + include/asm-x86/cpufeature.h | 2 -- 9 files changed, 43 insertions(+), 31 deletions(-) (limited to 'arch/x86/kernel/cpu/amd.c') diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index acc891ae590..81a07ca65d4 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -266,9 +266,6 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) if (cpu_has_xmm2) set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC); - - if (c->x86 == 0x10) - amd_enable_pci_ext_cfg(c); } static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c index f8d20588bde..250bfe6064a 100644 --- a/arch/x86/kernel/cpu/amd_64.c +++ b/arch/x86/kernel/cpu/amd_64.c @@ -6,7 +6,6 @@ #include #include -#include "cpu.h" extern int __cpuinit get_model_name(struct cpuinfo_x86 *c); extern void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c); @@ -187,9 +186,6 @@ void __cpuinit init_amd(struct cpuinfo_x86 *c) if (c->x86 == 0x10) fam10h_check_enable_mmcfg(); - if (c->x86 == 0x10) - amd_enable_pci_ext_cfg(c); - if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) { unsigned long long tseg; diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h index f5d5bb1b554..40ad1893fe8 100644 --- a/arch/x86/kernel/cpu/cpu.h +++ b/arch/x86/kernel/cpu/cpu.h @@ -39,5 +39,3 @@ extern int get_model_name(struct cpuinfo_x86 *c); extern void display_cacheinfo(struct cpuinfo_x86 *c); #endif /* CONFIG_X86_32 */ - -extern void __cpuinit amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 20e14dbef10..6f80b852a19 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -137,16 +137,3 @@ void __init setup_per_cpu_areas(void) } #endif -#define ENABLE_CF8_EXT_CFG (1ULL << 46) - -void __cpuinit amd_enable_pci_ext_cfg(struct cpuinfo_x86 *c) -{ - u64 reg; - rdmsrl(MSR_AMD64_NB_CFG, reg); - if (!(reg & ENABLE_CF8_EXT_CFG)) { - reg |= ENABLE_CF8_EXT_CFG; - wrmsrl(MSR_AMD64_NB_CFG, reg); - } - set_cpu_cap(c, X86_FEATURE_PCI_EXT_CFG); -} - diff --git a/arch/x86/pci/Makefile_32 b/arch/x86/pci/Makefile_32 index 89ec35d00ef..f647e7e56da 100644 --- a/arch/x86/pci/Makefile_32 +++ b/arch/x86/pci/Makefile_32 @@ -22,3 +22,4 @@ pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o pci-$(CONFIG_NUMA) += mp_bus_to_node.o obj-y += $(pci-y) common.o early.o +obj-y += amd_bus.o diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 5c2799c20e4..15f505d3a78 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c @@ -1,5 +1,9 @@ #include #include +#include "pci.h" + +#ifdef CONFIG_X86_64 + #include #include #include @@ -526,3 +530,31 @@ static int __init early_fill_mp_bus_info(void) } postcore_initcall(early_fill_mp_bus_info); + +#endif + +/* common 32/64 bit code */ + +#define ENABLE_CF8_EXT_CFG (1ULL << 46) + +static void enable_pci_io_ecs_per_cpu(void *unused) +{ + u64 reg; + rdmsrl(MSR_AMD64_NB_CFG, reg); + if (!(reg & ENABLE_CF8_EXT_CFG)) { + reg |= ENABLE_CF8_EXT_CFG; + wrmsrl(MSR_AMD64_NB_CFG, reg); + } +} + +static int __init enable_pci_io_ecs(void) +{ + /* assume all cpus from fam10h have IO ECS */ + if (boot_cpu_data.x86 < 0x10) + return 0; + on_each_cpu(enable_pci_io_ecs_per_cpu, NULL, 1, 1); + pci_probe |= PCI_HAS_IO_ECS; + return 0; +} + +postcore_initcall(enable_pci_io_ecs); diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c index 27d61b63def..9915293500f 100644 --- a/arch/x86/pci/direct.c +++ b/arch/x86/pci/direct.c @@ -265,14 +265,16 @@ void __init pci_direct_init(int type) type); if (type == 1) { raw_pci_ops = &pci_direct_conf1; - if (!raw_pci_ext_ops && cpu_has_pci_ext_cfg) { - printk(KERN_INFO "PCI: Using configuration type 1 " - "for extended access\n"); - raw_pci_ext_ops = &pci_direct_conf1; - } - } else { - raw_pci_ops = &pci_direct_conf2; + if (raw_pci_ext_ops) + return; + if (!(pci_probe & PCI_HAS_IO_ECS)) + return; + printk(KERN_INFO "PCI: Using configuration type 1 " + "for extended access\n"); + raw_pci_ext_ops = &pci_direct_conf1; + return; } + raw_pci_ops = &pci_direct_conf2; } int __init pci_direct_probe(void) diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index f3972b12c60..fd53db50eee 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h @@ -27,6 +27,7 @@ #define PCI_CAN_SKIP_ISA_ALIGN 0x8000 #define PCI_USE__CRS 0x10000 #define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000 +#define PCI_HAS_IO_ECS 0x40000 extern unsigned int pci_probe; extern unsigned long pirq_table_addr; diff --git a/include/asm-x86/cpufeature.h b/include/asm-x86/cpufeature.h index 40fcbba00f1..0d609c837a4 100644 --- a/include/asm-x86/cpufeature.h +++ b/include/asm-x86/cpufeature.h @@ -79,7 +79,6 @@ #define X86_FEATURE_REP_GOOD (3*32+16) /* rep microcode works well on this CPU */ #define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */ #define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */ -#define X86_FEATURE_PCI_EXT_CFG (3*32+19) /* PCI extended cfg access */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ @@ -188,7 +187,6 @@ extern const char * const x86_power_flags[32]; #define cpu_has_gbpages boot_cpu_has(X86_FEATURE_GBPAGES) #define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON) #define cpu_has_pat boot_cpu_has(X86_FEATURE_PAT) -#define cpu_has_pci_ext_cfg boot_cpu_has(X86_FEATURE_PCI_EXT_CFG) #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64) # define cpu_has_invlpg 1 -- cgit v1.2.3-70-g09d2