Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 495

kernel-2.6.18-238.el5.src.rpm

From: Matthew Garrett <mjg@redhat.com>
Date: Wed, 4 Aug 2010 17:05:55 -0400
Subject: [cpufreq] powernow-k8: support AMD Core Performance Boost
Message-id: <1280941555-29841-1-git-send-email-mjg@redhat.com>
Patchwork-id: 27396
O-Subject: [PATCH] [RHEL5.6 PATCH] Add support for AMD Core Performance Boost
Bugzilla: 568751
RH-Acked-by: Jarod Wilson <jarod@redhat.com>

bz: #568751

Recent AMD CPUs support an additional core performance state if the package
stays within its thermal envelope. This patch (backport of
73860c6b2fd159a35637e233d735e36887c266ad from upstream) adds support for
enabling or disabling this feature.

diff --git a/arch/i386/kernel/cpu/addon_cpuid_features.c b/arch/i386/kernel/cpu/addon_cpuid_features.c
index ea9d23d..fd45428 100644
--- a/arch/i386/kernel/cpu/addon_cpuid_features.c
+++ b/arch/i386/kernel/cpu/addon_cpuid_features.c
@@ -32,6 +32,7 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
 	static const struct cpuid_bit cpuid_bits[] = {
 		{ X86_FEATURE_IDA, CR_EAX, 1, 0x00000006 },
 		{ X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006 },
+		{ X86_FEATURE_CPB, CR_EDX, 9, 0x80000007 },
 		{ 0, 0, 0, 0 }
 	};
 
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
index 5ed35db..c32e28d 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -67,6 +67,9 @@ static int preregister_acpi_perf = 1;
 
 static int cpu_family = CPU_OPTERON;
 
+/* core performance boost */
+static bool cpb_capable, cpb_enabled;
+
 #ifndef CONFIG_SMP
 static cpumask_t cpu_core_map[1];
 #endif
@@ -1403,8 +1406,82 @@ out:
 	return khz;
 }
 
+static void _cpb_toggle_msrs(bool t)
+{
+	int cpu;
+	u32 l, h;
+	cpumask_t saved_mask;
+
+	lock_cpu_hotplug();
+
+	saved_mask = current->cpus_allowed;
+
+	for_each_online_cpu(cpu) {
+		set_cpus_allowed(current, cpumask_of_cpu(cpu));
+		rdmsr(MSR_K7_HWCR, l, h);
+
+		if (t)
+			l &= ~(1<<25);
+		else
+			l |= (1<<25);
+		wrmsr(MSR_K7_HWCR, l, h);
+		set_cpus_allowed(current, saved_mask);
+	}
+
+	unlock_cpu_hotplug();
+}
+
+/*
+ * Switch on/off core performance boosting.
+ *
+ * 0=disable
+ * 1=enable.
+ */
+static void cpb_toggle(bool t)
+{
+	if (!cpb_capable)
+		return;
+
+	if (t && !cpb_enabled) {
+		cpb_enabled = true;
+		_cpb_toggle_msrs(t);
+		printk(KERN_INFO PFX "Core Boosting enabled.\n");
+	} else if (!t && cpb_enabled) {
+		cpb_enabled = false;
+		_cpb_toggle_msrs(t);
+		printk(KERN_INFO PFX "Core Boosting disabled.\n");
+	}
+}
+
+static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
+			 size_t count)
+{
+	int ret = -EINVAL;
+	unsigned long val = 0;
+
+	ret = strict_strtoul(buf, 10, &val);
+	if (!ret && (val == 0 || val == 1) && cpb_capable)
+		cpb_toggle(val);
+	else
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
+{
+	       return sprintf(buf, "%u\n", cpb_enabled);
+}
+
+#define define_one_rw(_name) \
+static struct freq_attr _name = \
+	__ATTR(_name, 0644, show_##_name, store_##_name)
+
+define_one_rw(cpb);
+
 static struct freq_attr* powernow_k8_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
+	&cpb,
 	NULL,
 };
 
@@ -1419,10 +1496,53 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
 	.attr = powernow_k8_attr,
 };
 
+/*
+ * Clear the boost-disable flag on the CPU_DOWN path so that this cpu
+ * cannot block the remaining ones from boosting. On the CPU_UP path we
+ * simply keep the boost-disable flag in sync with the current global
+ * state.
+ */
+static int __cpuinit cpb_notify(struct notifier_block *nb, unsigned long action,
+				void *hcpu)
+{
+	unsigned cpu = (long)hcpu;
+	u32 lo, hi;
+	cpumask_t saved_mask;
+
+	saved_mask = current->cpus_allowed;
+	set_cpus_allowed(current, cpumask_of_cpu(cpu));
+
+	switch (action) {
+	case CPU_UP_PREPARE:
+		if (!cpb_enabled) {
+			rdmsr(MSR_K7_HWCR, lo, hi);
+			lo |= (1<<25);
+			wrmsr(MSR_K7_HWCR, lo, hi);
+		}
+		break;
+
+	case CPU_DOWN_PREPARE:
+		rdmsr(MSR_K7_HWCR, lo, hi);
+		lo &= ~(1<<25);
+		wrmsr(MSR_K7_HWCR, lo, hi);
+		break;
+
+	default:
+		break;
+	}
+
+	set_cpus_allowed(current, saved_mask);
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata cpb_nb = {
+	.notifier_call		= cpb_notify,
+};
+
 /* driver entry point for init */
 static int __cpuinit powernowk8_init(void)
 {
-	unsigned int i, supported_cpus = 0;
+	unsigned int i, supported_cpus = 0, cpu;
 
 #ifdef CONFIG_XEN
 	if (!is_initial_xendomain()) {
@@ -1494,6 +1614,25 @@ static int __cpuinit powernowk8_init(void)
 	printk(KERN_INFO PFX "Found %d virtualized processors\n",
 		supported_cpus);
 #endif
+	if (boot_cpu_has(X86_FEATURE_CPB)) {
+		u32 l, h;
+		cpumask_t saved_mask;
+		cpb_capable = true;
+
+		register_cpu_notifier(&cpb_nb);
+
+		saved_mask = current->cpus_allowed;
+
+		for_each_online_cpu(cpu) {
+			set_cpus_allowed(current, cpumask_of_cpu(cpu));
+			rdmsr(MSR_K7_HWCR, l, h);
+			cpb_enabled |= !(!!(l & (1<<25)));
+			set_cpus_allowed(current, saved_mask);
+		}
+		printk(KERN_INFO PFX "Core Performance Boosting: %s.\n",
+		       (cpb_enabled ? "on" : "off"));
+	}
+
 	return cpufreq_register_driver(&cpufreq_amd64_driver);
 }
 
@@ -1505,6 +1644,9 @@ static void __exit powernowk8_exit(void)
 	if (tscsync)
 		kfree(req_state);
 
+	if (boot_cpu_has(X86_FEATURE_CPB))
+		unregister_cpu_notifier(&cpb_nb);
+
 	cpufreq_unregister_driver(&cpufreq_amd64_driver);
 }
 
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index 52f50f5..5071348 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -80,6 +80,7 @@
 #define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
 #define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */
 #define X86_FEATURE_ARAT	(3*32+25) /* Always Running APIC Timer */
+#define X86_FEATURE_CPB		(7*32+ 2) /* AMD Core Performance Boost  */
 #define X86_FEATURE_EXTD_APICID	(3*32+26) /* has extended APICID (8 bits) */
 #define X86_FEATURE_AMD_DCM	(3*32+27) /* multi-node processor */
 
diff --git a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h
index dc2973f..2e6de04 100644
--- a/include/asm-x86_64/cpufeature.h
+++ b/include/asm-x86_64/cpufeature.h
@@ -75,6 +75,7 @@
 #define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
 #define X86_FEATURE_NONSTOP_TSC (3*32+24) /* TSC does not stop in C states */
 #define X86_FEATURE_ARAT	(3*32+25) /* Always Running APIC Timer */
+#define X86_FEATURE_CPB		(7*32+ 2) /* AMD Core Performance Boost */
 #define X86_FEATURE_AMD_DCM	(3*32+27) /* multi-node processor */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
diff --git a/include/asm-x86_64/mach-xen/asm/msr.h b/include/asm-x86_64/mach-xen/asm/msr.h
index bdc23c5..912c4d1 100644
--- a/include/asm-x86_64/mach-xen/asm/msr.h
+++ b/include/asm-x86_64/mach-xen/asm/msr.h
@@ -238,6 +238,7 @@ static inline unsigned int cpuid_edx(unsigned int op)
 #define MSR_K8_TOP_MEM1		   0xC001001A
 #define MSR_K8_TOP_MEM2		   0xC001001D
 #define MSR_K8_SYSCFG		   0xC0010010
+#define MSR_K7_HWCR		   0xC0010015
 #define MSR_K8_HWCR		   0xC0010015
 
 /* K6 MSRs */
diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
index 6c93e89..80964f5 100644
--- a/include/asm-x86_64/msr.h
+++ b/include/asm-x86_64/msr.h
@@ -261,6 +261,7 @@ static inline void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
 #define MSR_K7_EVNTSEL2            0xC0010002
 #define MSR_K7_PERFCTR2            0xC0010006
 #define MSR_K7_EVNTSEL3            0xC0010003
+#define MSR_K7_HWCR		   0xC0010015
 #define MSR_K7_PERFCTR3            0xC0010007
 #define MSR_K8_TOP_MEM1		   0xC001001A
 #define MSR_K8_TOP_MEM2		   0xC001001D