aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/cpufreq
diff options
context:
space:
mode:
authorBorislav Petkov <borislav.petkov@amd.com>2010-03-31 15:56:42 -0400
committerH. Peter Anvin <hpa@zytor.com>2010-04-09 17:05:43 -0400
commit73860c6b2fd159a35637e233d735e36887c266ad (patch)
tree74c657fbd87569441ef0f0e0683637ff0de7700f /arch/x86/kernel/cpu/cpufreq
parent5958f1d5d722df7a9e5d129676614a8e5219bacd (diff)
powernow-k8: Add core performance boost support
Starting with F10h, revE, AMD processors add support for a dynamic core boosting feature called Core Performance Boost. When a specific condition is present, a subset of the cores on a system are boosted beyond their P0 operating frequency to speed up the performance of single-threaded applications. In the normal case, the system comes out of reset with core boosting enabled. This patch adds a sysfs knob with which core boosting can be switched on or off for benchmarking purposes. While at it, make the CPB code hotplug-aware so that taking cores offline wouldn't interfere with boosting the remaining online cores. Furthermore, add cpu_online_mask hotplug protection as suggested by Andrew. Finally, cleanup the driver init codepath and update copyrights. Signed-off-by: Borislav Petkov <borislav.petkov@amd.com> LKML-Reference: <1270065406-1814-3-git-send-email-bp@amd64.org> Reviewed-by: Thomas Renninger <trenn@suse.de> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/kernel/cpu/cpufreq')
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k8.c161
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k8.h2
2 files changed, 151 insertions, 12 deletions
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index d360b56e9825..74ca34b5c003 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -1,6 +1,5 @@
1
2/* 1/*
3 * (c) 2003-2006 Advanced Micro Devices, Inc. 2 * (c) 2003-2010 Advanced Micro Devices, Inc.
4 * Your use of this code is subject to the terms and conditions of the 3 * Your use of this code is subject to the terms and conditions of the
5 * GNU general public license version 2. See "COPYING" or 4 * GNU general public license version 2. See "COPYING" or
6 * http://www.gnu.org/licenses/gpl.html 5 * http://www.gnu.org/licenses/gpl.html
@@ -54,6 +53,10 @@ static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data);
54 53
55static int cpu_family = CPU_OPTERON; 54static int cpu_family = CPU_OPTERON;
56 55
56/* core performance boost */
57static bool cpb_capable, cpb_enabled;
58static struct msr __percpu *msrs;
59
57#ifndef CONFIG_SMP 60#ifndef CONFIG_SMP
58static inline const struct cpumask *cpu_core_mask(int cpu) 61static inline const struct cpumask *cpu_core_mask(int cpu)
59{ 62{
@@ -1393,8 +1396,77 @@ out:
1393 return khz; 1396 return khz;
1394} 1397}
1395 1398
1399static void _cpb_toggle_msrs(bool t)
1400{
1401 int cpu;
1402
1403 get_online_cpus();
1404
1405 rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
1406
1407 for_each_cpu(cpu, cpu_online_mask) {
1408 struct msr *reg = per_cpu_ptr(msrs, cpu);
1409 if (t)
1410 reg->l &= ~BIT(25);
1411 else
1412 reg->l |= BIT(25);
1413 }
1414 wrmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
1415
1416 put_online_cpus();
1417}
1418
1419/*
1420 * Switch on/off core performance boosting.
1421 *
1422 * 0=disable
1423 * 1=enable.
1424 */
1425static void cpb_toggle(bool t)
1426{
1427 if (!cpb_capable)
1428 return;
1429
1430 if (t && !cpb_enabled) {
1431 cpb_enabled = true;
1432 _cpb_toggle_msrs(t);
1433 printk(KERN_INFO PFX "Core Boosting enabled.\n");
1434 } else if (!t && cpb_enabled) {
1435 cpb_enabled = false;
1436 _cpb_toggle_msrs(t);
1437 printk(KERN_INFO PFX "Core Boosting disabled.\n");
1438 }
1439}
1440
1441static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
1442 size_t count)
1443{
1444 int ret = -EINVAL;
1445 unsigned long val = 0;
1446
1447 ret = strict_strtoul(buf, 10, &val);
1448 if (!ret && (val == 0 || val == 1) && cpb_capable)
1449 cpb_toggle(val);
1450 else
1451 return -EINVAL;
1452
1453 return count;
1454}
1455
1456static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
1457{
1458 return sprintf(buf, "%u\n", cpb_enabled);
1459}
1460
1461#define define_one_rw(_name) \
1462static struct freq_attr _name = \
1463__ATTR(_name, 0644, show_##_name, store_##_name)
1464
1465define_one_rw(cpb);
1466
1396static struct freq_attr *powernow_k8_attr[] = { 1467static struct freq_attr *powernow_k8_attr[] = {
1397 &cpufreq_freq_attr_scaling_available_freqs, 1468 &cpufreq_freq_attr_scaling_available_freqs,
1469 &cpb,
1398 NULL, 1470 NULL,
1399}; 1471};
1400 1472
@@ -1410,10 +1482,51 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
1410 .attr = powernow_k8_attr, 1482 .attr = powernow_k8_attr,
1411}; 1483};
1412 1484
1485/*
1486 * Clear the boost-disable flag on the CPU_DOWN path so that this cpu
1487 * cannot block the remaining ones from boosting. On the CPU_UP path we
1488 * simply keep the boost-disable flag in sync with the current global
1489 * state.
1490 */
1491static int __cpuinit cpb_notify(struct notifier_block *nb, unsigned long action,
1492 void *hcpu)
1493{
1494 unsigned cpu = (long)hcpu;
1495 u32 lo, hi;
1496
1497 switch (action) {
1498 case CPU_UP_PREPARE:
1499 case CPU_UP_PREPARE_FROZEN:
1500
1501 if (!cpb_enabled) {
1502 rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi);
1503 lo |= BIT(25);
1504 wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi);
1505 }
1506 break;
1507
1508 case CPU_DOWN_PREPARE:
1509 case CPU_DOWN_PREPARE_FROZEN:
1510 rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi);
1511 lo &= ~BIT(25);
1512 wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi);
1513 break;
1514
1515 default:
1516 break;
1517 }
1518
1519 return NOTIFY_OK;
1520}
1521
1522static struct notifier_block __cpuinitdata cpb_nb = {
1523 .notifier_call = cpb_notify,
1524};
1525
1413/* driver entry point for init */ 1526/* driver entry point for init */
1414static int __cpuinit powernowk8_init(void) 1527static int __cpuinit powernowk8_init(void)
1415{ 1528{
1416 unsigned int i, supported_cpus = 0; 1529 unsigned int i, supported_cpus = 0, cpu;
1417 1530
1418 for_each_online_cpu(i) { 1531 for_each_online_cpu(i) {
1419 int rc; 1532 int rc;
@@ -1422,15 +1535,36 @@ static int __cpuinit powernowk8_init(void)
1422 supported_cpus++; 1535 supported_cpus++;
1423 } 1536 }
1424 1537
1425 if (supported_cpus == num_online_cpus()) { 1538 if (supported_cpus != num_online_cpus())
1426 printk(KERN_INFO PFX "Found %d %s " 1539 return -ENODEV;
1427 "processors (%d cpu cores) (" VERSION ")\n", 1540
1428 num_online_nodes(), 1541 printk(KERN_INFO PFX "Found %d %s (%d cpu cores) (" VERSION ")\n",
1429 boot_cpu_data.x86_model_id, supported_cpus); 1542 num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus);
1430 return cpufreq_register_driver(&cpufreq_amd64_driver); 1543
1544 if (boot_cpu_has(X86_FEATURE_CPB)) {
1545
1546 cpb_capable = true;
1547
1548 register_cpu_notifier(&cpb_nb);
1549
1550 msrs = msrs_alloc();
1551 if (!msrs) {
1552 printk(KERN_ERR "%s: Error allocating msrs!\n", __func__);
1553 return -ENOMEM;
1554 }
1555
1556 rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
1557
1558 for_each_cpu(cpu, cpu_online_mask) {
1559 struct msr *reg = per_cpu_ptr(msrs, cpu);
1560 cpb_enabled |= !(!!(reg->l & BIT(25)));
1561 }
1562
1563 printk(KERN_INFO PFX "Core Performance Boosting: %s.\n",
1564 (cpb_enabled ? "on" : "off"));
1431 } 1565 }
1432 1566
1433 return -ENODEV; 1567 return cpufreq_register_driver(&cpufreq_amd64_driver);
1434} 1568}
1435 1569
1436/* driver entry point for term */ 1570/* driver entry point for term */
@@ -1438,6 +1572,13 @@ static void __exit powernowk8_exit(void)
1438{ 1572{
1439 dprintk("exit\n"); 1573 dprintk("exit\n");
1440 1574
1575 if (boot_cpu_has(X86_FEATURE_CPB)) {
1576 msrs_free(msrs);
1577 msrs = NULL;
1578
1579 unregister_cpu_notifier(&cpb_nb);
1580 }
1581
1441 cpufreq_unregister_driver(&cpufreq_amd64_driver); 1582 cpufreq_unregister_driver(&cpufreq_amd64_driver);
1442} 1583}
1443 1584
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
index 02ce824073cb..df3529b1c02d 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
@@ -5,7 +5,6 @@
5 * http://www.gnu.org/licenses/gpl.html 5 * http://www.gnu.org/licenses/gpl.html
6 */ 6 */
7 7
8
9enum pstate { 8enum pstate {
10 HW_PSTATE_INVALID = 0xff, 9 HW_PSTATE_INVALID = 0xff,
11 HW_PSTATE_0 = 0, 10 HW_PSTATE_0 = 0,
@@ -55,7 +54,6 @@ struct powernow_k8_data {
55 struct cpumask *available_cores; 54 struct cpumask *available_cores;
56}; 55};
57 56
58
59/* processor's cpuid instruction support */ 57/* processor's cpuid instruction support */
60#define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */ 58#define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */
61#define CPUID_XFAM 0x0ff00000 /* extended family */ 59#define CPUID_XFAM 0x0ff00000 /* extended family */