aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/cpufreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r--drivers/cpufreq/cpufreq.c85
1 files changed, 67 insertions, 18 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 109d62ccf651..6c6121b85a54 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -4,6 +4,9 @@
4 * Copyright (C) 2001 Russell King 4 * Copyright (C) 2001 Russell King
5 * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> 5 * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
6 * 6 *
7 * Oct 2005 - Ashok Raj <ashok.raj@intel.com>
8 * Added handling for CPU hotplug
9 *
7 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 11 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
@@ -36,13 +39,6 @@ static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
36static DEFINE_SPINLOCK(cpufreq_driver_lock); 39static DEFINE_SPINLOCK(cpufreq_driver_lock);
37 40
38 41
39/* we keep a copy of all ->add'ed CPU's struct sys_device here;
40 * as it is only accessed in ->add and ->remove, no lock or reference
41 * count is necessary.
42 */
43static struct sys_device *cpu_sys_devices[NR_CPUS];
44
45
46/* internal prototypes */ 42/* internal prototypes */
47static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); 43static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
48static void handle_update(void *data); 44static void handle_update(void *data);
@@ -574,6 +570,9 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
574 unsigned long flags; 570 unsigned long flags;
575 unsigned int j; 571 unsigned int j;
576 572
573 if (cpu_is_offline(cpu))
574 return 0;
575
577 cpufreq_debug_disable_ratelimit(); 576 cpufreq_debug_disable_ratelimit();
578 dprintk("adding CPU %u\n", cpu); 577 dprintk("adding CPU %u\n", cpu);
579 578
@@ -582,7 +581,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
582 * CPU because it is in the same boat. */ 581 * CPU because it is in the same boat. */
583 policy = cpufreq_cpu_get(cpu); 582 policy = cpufreq_cpu_get(cpu);
584 if (unlikely(policy)) { 583 if (unlikely(policy)) {
585 cpu_sys_devices[cpu] = sys_dev;
586 dprintk("CPU already managed, adding link\n"); 584 dprintk("CPU already managed, adding link\n");
587 sysfs_create_link(&sys_dev->kobj, &policy->kobj, "cpufreq"); 585 sysfs_create_link(&sys_dev->kobj, &policy->kobj, "cpufreq");
588 cpufreq_debug_enable_ratelimit(); 586 cpufreq_debug_enable_ratelimit();
@@ -657,7 +655,6 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
657 } 655 }
658 656
659 module_put(cpufreq_driver->owner); 657 module_put(cpufreq_driver->owner);
660 cpu_sys_devices[cpu] = sys_dev;
661 dprintk("initialization complete\n"); 658 dprintk("initialization complete\n");
662 cpufreq_debug_enable_ratelimit(); 659 cpufreq_debug_enable_ratelimit();
663 660
@@ -682,7 +679,7 @@ err_out:
682 679
683nomem_out: 680nomem_out:
684 module_put(cpufreq_driver->owner); 681 module_put(cpufreq_driver->owner);
685 module_out: 682module_out:
686 cpufreq_debug_enable_ratelimit(); 683 cpufreq_debug_enable_ratelimit();
687 return ret; 684 return ret;
688} 685}
@@ -698,6 +695,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
698 unsigned int cpu = sys_dev->id; 695 unsigned int cpu = sys_dev->id;
699 unsigned long flags; 696 unsigned long flags;
700 struct cpufreq_policy *data; 697 struct cpufreq_policy *data;
698 struct sys_device *cpu_sys_dev;
701#ifdef CONFIG_SMP 699#ifdef CONFIG_SMP
702 unsigned int j; 700 unsigned int j;
703#endif 701#endif
@@ -710,7 +708,6 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
710 708
711 if (!data) { 709 if (!data) {
712 spin_unlock_irqrestore(&cpufreq_driver_lock, flags); 710 spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
713 cpu_sys_devices[cpu] = NULL;
714 cpufreq_debug_enable_ratelimit(); 711 cpufreq_debug_enable_ratelimit();
715 return -EINVAL; 712 return -EINVAL;
716 } 713 }
@@ -725,14 +722,12 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
725 dprintk("removing link\n"); 722 dprintk("removing link\n");
726 spin_unlock_irqrestore(&cpufreq_driver_lock, flags); 723 spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
727 sysfs_remove_link(&sys_dev->kobj, "cpufreq"); 724 sysfs_remove_link(&sys_dev->kobj, "cpufreq");
728 cpu_sys_devices[cpu] = NULL;
729 cpufreq_cpu_put(data); 725 cpufreq_cpu_put(data);
730 cpufreq_debug_enable_ratelimit(); 726 cpufreq_debug_enable_ratelimit();
731 return 0; 727 return 0;
732 } 728 }
733#endif 729#endif
734 730
735 cpu_sys_devices[cpu] = NULL;
736 731
737 if (!kobject_get(&data->kobj)) { 732 if (!kobject_get(&data->kobj)) {
738 spin_unlock_irqrestore(&cpufreq_driver_lock, flags); 733 spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -761,7 +756,8 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
761 if (j == cpu) 756 if (j == cpu)
762 continue; 757 continue;
763 dprintk("removing link for cpu %u\n", j); 758 dprintk("removing link for cpu %u\n", j);
764 sysfs_remove_link(&cpu_sys_devices[j]->kobj, "cpufreq"); 759 cpu_sys_dev = get_cpu_sysdev(j);
760 sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");
765 cpufreq_cpu_put(data); 761 cpufreq_cpu_put(data);
766 } 762 }
767 } 763 }
@@ -772,7 +768,6 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
772 down(&data->lock); 768 down(&data->lock);
773 if (cpufreq_driver->target) 769 if (cpufreq_driver->target)
774 __cpufreq_governor(data, CPUFREQ_GOV_STOP); 770 __cpufreq_governor(data, CPUFREQ_GOV_STOP);
775 cpufreq_driver->target = NULL;
776 up(&data->lock); 771 up(&data->lock);
777 772
778 kobject_unregister(&data->kobj); 773 kobject_unregister(&data->kobj);
@@ -1119,17 +1114,30 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
1119 unsigned int relation) 1114 unsigned int relation)
1120{ 1115{
1121 int retval = -EINVAL; 1116 int retval = -EINVAL;
1122 lock_cpu_hotplug(); 1117
1118 /*
1119 * Converted the lock_cpu_hotplug to preempt_disable()
1120 * and preempt_enable(). This is a bit kludgy and relies on how cpu
1121 * hotplug works. All we need is a guarantee that cpu hotplug won't make
1122 * progress on any cpu. Once we do preempt_disable(), this would ensure
1123 * that hotplug threads don't get onto this cpu, thereby delaying
1124 * the cpu remove process.
1125 *
1126 * We removed the lock_cpu_hotplug since we need to call this function
1127 * via cpu hotplug callbacks, which result in locking the cpu hotplug
1128 * thread itself. Agree this is not very clean, cpufreq community
1129 * could improve this if required. - Ashok Raj <ashok.raj@intel.com>
1130 */
1131 preempt_disable();
1123 dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu, 1132 dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
1124 target_freq, relation); 1133 target_freq, relation);
1125 if (cpu_online(policy->cpu) && cpufreq_driver->target) 1134 if (cpu_online(policy->cpu) && cpufreq_driver->target)
1126 retval = cpufreq_driver->target(policy, target_freq, relation); 1135 retval = cpufreq_driver->target(policy, target_freq, relation);
1127 unlock_cpu_hotplug(); 1136 preempt_enable();
1128 return retval; 1137 return retval;
1129} 1138}
1130EXPORT_SYMBOL_GPL(__cpufreq_driver_target); 1139EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
1131 1140
1132
1133int cpufreq_driver_target(struct cpufreq_policy *policy, 1141int cpufreq_driver_target(struct cpufreq_policy *policy,
1134 unsigned int target_freq, 1142 unsigned int target_freq,
1135 unsigned int relation) 1143 unsigned int relation)
@@ -1416,6 +1424,45 @@ int cpufreq_update_policy(unsigned int cpu)
1416} 1424}
1417EXPORT_SYMBOL(cpufreq_update_policy); 1425EXPORT_SYMBOL(cpufreq_update_policy);
1418 1426
1427static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
1428 unsigned long action, void *hcpu)
1429{
1430 unsigned int cpu = (unsigned long)hcpu;
1431 struct cpufreq_policy *policy;
1432 struct sys_device *sys_dev;
1433
1434 sys_dev = get_cpu_sysdev(cpu);
1435
1436 if (sys_dev) {
1437 switch (action) {
1438 case CPU_ONLINE:
1439 cpufreq_add_dev(sys_dev);
1440 break;
1441 case CPU_DOWN_PREPARE:
1442 /*
1443 * We attempt to put this cpu in lowest frequency
1444 * possible before going down. This will permit
1445 * hardware-managed P-State to switch other related
1446 * threads to min or higher speeds if possible.
1447 */
1448 policy = cpufreq_cpu_data[cpu];
1449 if (policy) {
1450 cpufreq_driver_target(policy, policy->min,
1451 CPUFREQ_RELATION_H);
1452 }
1453 break;
1454 case CPU_DEAD:
1455 cpufreq_remove_dev(sys_dev);
1456 break;
1457 }
1458 }
1459 return NOTIFY_OK;
1460}
1461
1462static struct notifier_block cpufreq_cpu_notifier =
1463{
1464 .notifier_call = cpufreq_cpu_callback,
1465};
1419 1466
1420/********************************************************************* 1467/*********************************************************************
1421 * REGISTER / UNREGISTER CPUFREQ DRIVER * 1468 * REGISTER / UNREGISTER CPUFREQ DRIVER *
@@ -1476,6 +1523,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
1476 } 1523 }
1477 1524
1478 if (!ret) { 1525 if (!ret) {
1526 register_cpu_notifier(&cpufreq_cpu_notifier);
1479 dprintk("driver %s up and running\n", driver_data->name); 1527 dprintk("driver %s up and running\n", driver_data->name);
1480 cpufreq_debug_enable_ratelimit(); 1528 cpufreq_debug_enable_ratelimit();
1481 } 1529 }
@@ -1507,6 +1555,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
1507 dprintk("unregistering driver %s\n", driver->name); 1555 dprintk("unregistering driver %s\n", driver->name);
1508 1556
1509 sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); 1557 sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
1558 unregister_cpu_notifier(&cpufreq_cpu_notifier);
1510 1559
1511 spin_lock_irqsave(&cpufreq_driver_lock, flags); 1560 spin_lock_irqsave(&cpufreq_driver_lock, flags);
1512 cpufreq_driver = NULL; 1561 cpufreq_driver = NULL;