diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-11-29 04:51:43 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-12-01 17:01:36 -0500 |
commit | fb1013a01673acf7e94e38cda169828ac76b345a (patch) | |
tree | 025b27e54e2a2e8eafbbd20e497de9309ca94365 | |
parent | 29d7bbada98e0969dd2ea159104aa55052a1c439 (diff) |
intel_idle: Convert to hotplug state machine
Install the callbacks via the state machine and let the core invoke the
callbacks on the already online CPUs.
The two smp_call_function_single() invocations in intel_idle_cpu_init() have
been removed because intel_idle_cpu_init() is now invoked via the hotplug
callback which runs on the target CPU. The IRQ-off calling convention for
auto_demotion_disable() and c1e_promotion_disable() has not been preserved
because only those two modify the MSR during CPU intialization.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/idle/intel_idle.c | 103 |
1 files changed, 39 insertions, 64 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 3828babfb77b..7d8ea3d5fda6 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -98,8 +98,6 @@ static int intel_idle(struct cpuidle_device *dev, | |||
98 | struct cpuidle_driver *drv, int index); | 98 | struct cpuidle_driver *drv, int index); |
99 | static void intel_idle_freeze(struct cpuidle_device *dev, | 99 | static void intel_idle_freeze(struct cpuidle_device *dev, |
100 | struct cpuidle_driver *drv, int index); | 100 | struct cpuidle_driver *drv, int index); |
101 | static int intel_idle_cpu_init(int cpu); | ||
102 | |||
103 | static struct cpuidle_state *cpuidle_state_table; | 101 | static struct cpuidle_state *cpuidle_state_table; |
104 | 102 | ||
105 | /* | 103 | /* |
@@ -951,50 +949,15 @@ static void intel_idle_freeze(struct cpuidle_device *dev, | |||
951 | mwait_idle_with_hints(eax, ecx); | 949 | mwait_idle_with_hints(eax, ecx); |
952 | } | 950 | } |
953 | 951 | ||
954 | static void __setup_broadcast_timer(void *arg) | 952 | static void __setup_broadcast_timer(bool on) |
955 | { | 953 | { |
956 | unsigned long on = (unsigned long)arg; | ||
957 | |||
958 | if (on) | 954 | if (on) |
959 | tick_broadcast_enable(); | 955 | tick_broadcast_enable(); |
960 | else | 956 | else |
961 | tick_broadcast_disable(); | 957 | tick_broadcast_disable(); |
962 | } | 958 | } |
963 | 959 | ||
964 | static int cpu_hotplug_notify(struct notifier_block *n, | 960 | static void auto_demotion_disable(void) |
965 | unsigned long action, void *hcpu) | ||
966 | { | ||
967 | int hotcpu = (unsigned long)hcpu; | ||
968 | struct cpuidle_device *dev; | ||
969 | |||
970 | switch (action & ~CPU_TASKS_FROZEN) { | ||
971 | case CPU_ONLINE: | ||
972 | |||
973 | if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) | ||
974 | __setup_broadcast_timer((void *)true); | ||
975 | |||
976 | /* | ||
977 | * Some systems can hotplug a cpu at runtime after | ||
978 | * the kernel has booted, we have to initialize the | ||
979 | * driver in this case | ||
980 | */ | ||
981 | dev = per_cpu_ptr(intel_idle_cpuidle_devices, hotcpu); | ||
982 | if (dev->registered) | ||
983 | break; | ||
984 | |||
985 | if (intel_idle_cpu_init(hotcpu)) | ||
986 | return NOTIFY_BAD; | ||
987 | |||
988 | break; | ||
989 | } | ||
990 | return NOTIFY_OK; | ||
991 | } | ||
992 | |||
993 | static struct notifier_block cpu_hotplug_notifier = { | ||
994 | .notifier_call = cpu_hotplug_notify, | ||
995 | }; | ||
996 | |||
997 | static void auto_demotion_disable(void *dummy) | ||
998 | { | 961 | { |
999 | unsigned long long msr_bits; | 962 | unsigned long long msr_bits; |
1000 | 963 | ||
@@ -1002,7 +965,7 @@ static void auto_demotion_disable(void *dummy) | |||
1002 | msr_bits &= ~(icpu->auto_demotion_disable_flags); | 965 | msr_bits &= ~(icpu->auto_demotion_disable_flags); |
1003 | wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); | 966 | wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); |
1004 | } | 967 | } |
1005 | static void c1e_promotion_disable(void *dummy) | 968 | static void c1e_promotion_disable(void) |
1006 | { | 969 | { |
1007 | unsigned long long msr_bits; | 970 | unsigned long long msr_bits; |
1008 | 971 | ||
@@ -1422,12 +1385,11 @@ static void __init intel_idle_cpuidle_driver_init(void) | |||
1422 | * allocate, initialize, register cpuidle_devices | 1385 | * allocate, initialize, register cpuidle_devices |
1423 | * @cpu: cpu/core to initialize | 1386 | * @cpu: cpu/core to initialize |
1424 | */ | 1387 | */ |
1425 | static int intel_idle_cpu_init(int cpu) | 1388 | static int intel_idle_cpu_init(unsigned int cpu) |
1426 | { | 1389 | { |
1427 | struct cpuidle_device *dev; | 1390 | struct cpuidle_device *dev; |
1428 | 1391 | ||
1429 | dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); | 1392 | dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); |
1430 | |||
1431 | dev->cpu = cpu; | 1393 | dev->cpu = cpu; |
1432 | 1394 | ||
1433 | if (cpuidle_register_device(dev)) { | 1395 | if (cpuidle_register_device(dev)) { |
@@ -1436,17 +1398,36 @@ static int intel_idle_cpu_init(int cpu) | |||
1436 | } | 1398 | } |
1437 | 1399 | ||
1438 | if (icpu->auto_demotion_disable_flags) | 1400 | if (icpu->auto_demotion_disable_flags) |
1439 | smp_call_function_single(cpu, auto_demotion_disable, NULL, 1); | 1401 | auto_demotion_disable(); |
1440 | 1402 | ||
1441 | if (icpu->disable_promotion_to_c1e) | 1403 | if (icpu->disable_promotion_to_c1e) |
1442 | smp_call_function_single(cpu, c1e_promotion_disable, NULL, 1); | 1404 | c1e_promotion_disable(); |
1405 | |||
1406 | return 0; | ||
1407 | } | ||
1408 | |||
1409 | static int intel_idle_cpu_online(unsigned int cpu) | ||
1410 | { | ||
1411 | struct cpuidle_device *dev; | ||
1412 | |||
1413 | if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) | ||
1414 | __setup_broadcast_timer(true); | ||
1415 | |||
1416 | /* | ||
1417 | * Some systems can hotplug a cpu at runtime after | ||
1418 | * the kernel has booted, we have to initialize the | ||
1419 | * driver in this case | ||
1420 | */ | ||
1421 | dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); | ||
1422 | if (!dev->registered) | ||
1423 | return intel_idle_cpu_init(cpu); | ||
1443 | 1424 | ||
1444 | return 0; | 1425 | return 0; |
1445 | } | 1426 | } |
1446 | 1427 | ||
1447 | static int __init intel_idle_init(void) | 1428 | static int __init intel_idle_init(void) |
1448 | { | 1429 | { |
1449 | int retval, i; | 1430 | int retval; |
1450 | 1431 | ||
1451 | /* Do not load intel_idle at all for now if idle= is passed */ | 1432 | /* Do not load intel_idle at all for now if idle= is passed */ |
1452 | if (boot_option_idle_override != IDLE_NO_OVERRIDE) | 1433 | if (boot_option_idle_override != IDLE_NO_OVERRIDE) |
@@ -1466,35 +1447,29 @@ static int __init intel_idle_init(void) | |||
1466 | struct cpuidle_driver *drv = cpuidle_get_driver(); | 1447 | struct cpuidle_driver *drv = cpuidle_get_driver(); |
1467 | printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", | 1448 | printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", |
1468 | drv ? drv->name : "none"); | 1449 | drv ? drv->name : "none"); |
1469 | free_percpu(intel_idle_cpuidle_devices); | 1450 | goto init_driver_fail; |
1470 | return retval; | ||
1471 | } | 1451 | } |
1472 | 1452 | ||
1473 | cpu_notifier_register_begin(); | ||
1474 | |||
1475 | for_each_online_cpu(i) { | ||
1476 | retval = intel_idle_cpu_init(i); | ||
1477 | if (retval) { | ||
1478 | intel_idle_cpuidle_devices_uninit(); | ||
1479 | cpu_notifier_register_done(); | ||
1480 | cpuidle_unregister_driver(&intel_idle_driver); | ||
1481 | free_percpu(intel_idle_cpuidle_devices); | ||
1482 | return retval; | ||
1483 | } | ||
1484 | } | ||
1485 | __register_cpu_notifier(&cpu_hotplug_notifier); | ||
1486 | |||
1487 | if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ | 1453 | if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ |
1488 | lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; | 1454 | lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; |
1489 | else | ||
1490 | on_each_cpu(__setup_broadcast_timer, (void *)true, 1); | ||
1491 | 1455 | ||
1492 | cpu_notifier_register_done(); | 1456 | retval = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "idle/intel:online", |
1457 | intel_idle_cpu_online, NULL); | ||
1458 | if (retval < 0) | ||
1459 | goto hp_setup_fail; | ||
1493 | 1460 | ||
1494 | pr_debug(PREFIX "lapic_timer_reliable_states 0x%x\n", | 1461 | pr_debug(PREFIX "lapic_timer_reliable_states 0x%x\n", |
1495 | lapic_timer_reliable_states); | 1462 | lapic_timer_reliable_states); |
1496 | 1463 | ||
1497 | return 0; | 1464 | return 0; |
1465 | |||
1466 | hp_setup_fail: | ||
1467 | intel_idle_cpuidle_devices_uninit(); | ||
1468 | cpuidle_unregister_driver(&intel_idle_driver); | ||
1469 | init_driver_fail: | ||
1470 | free_percpu(intel_idle_cpuidle_devices); | ||
1471 | return retval; | ||
1472 | |||
1498 | } | 1473 | } |
1499 | device_initcall(intel_idle_init); | 1474 | device_initcall(intel_idle_init); |
1500 | 1475 | ||