diff options
author | Borislav Petkov <borislav.petkov@amd.com> | 2010-03-31 15:56:42 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-04-09 17:05:43 -0400 |
commit | 73860c6b2fd159a35637e233d735e36887c266ad (patch) | |
tree | 74c657fbd87569441ef0f0e0683637ff0de7700f /arch/x86/kernel/cpu/cpufreq | |
parent | 5958f1d5d722df7a9e5d129676614a8e5219bacd (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.c | 161 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/powernow-k8.h | 2 |
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 | ||
55 | static int cpu_family = CPU_OPTERON; | 54 | static int cpu_family = CPU_OPTERON; |
56 | 55 | ||
56 | /* core performance boost */ | ||
57 | static bool cpb_capable, cpb_enabled; | ||
58 | static struct msr __percpu *msrs; | ||
59 | |||
57 | #ifndef CONFIG_SMP | 60 | #ifndef CONFIG_SMP |
58 | static inline const struct cpumask *cpu_core_mask(int cpu) | 61 | static 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 | ||
1399 | static 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 | */ | ||
1425 | static 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 | |||
1441 | static 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 | |||
1456 | static 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) \ | ||
1462 | static struct freq_attr _name = \ | ||
1463 | __ATTR(_name, 0644, show_##_name, store_##_name) | ||
1464 | |||
1465 | define_one_rw(cpb); | ||
1466 | |||
1396 | static struct freq_attr *powernow_k8_attr[] = { | 1467 | static 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 | */ | ||
1491 | static 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 | |||
1522 | static 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 */ |
1414 | static int __cpuinit powernowk8_init(void) | 1527 | static 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 | |||
9 | enum pstate { | 8 | enum 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 */ |