aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-08-04 12:41:22 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-08-04 12:41:22 -0400
commit12952784e5271374b7cb926501f51b9649bf5a2b (patch)
tree7e6e16d08df7553f30b345a65d46fdc8b4737a38
parentefe78cda3596f8a6d1c2d4a6b1a221bafa3e1a48 (diff)
parent12e704db809cd4101b7d3594fc9a96f30fe88a31 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
* master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq: [CPUFREQ] Propagate acpi_processor_preregister_performance return value. [CPUFREQ] [2/2] demand load governor modules. [CPUFREQ] [1/2] add __find_governor helper and clean up some error handling. [CPUFREQ] Longhaul - Rename & fix multipliers table [CPUFREQ] Longhaul - Fix power state test to do something more useful [CPUFREQ] Longhaul - Readd accidentally dropped line [CPUFREQ] Make longhaul_walk_callback() static [CPUFREQ] X86_GX_SUSPMOD must depend on PCI [CPUFREQ] Longhaul - Initialise later. [CPUFREQ] Longhaul - Workaround issues with APIC. [CPUFREQ] Longhaul - Hook into ACPI C states. [CPUFREQ] return error when failing to set minfreq
-rw-r--r--Documentation/cpu-freq/user-guide.txt5
-rw-r--r--arch/i386/kernel/cpu/cpufreq/Kconfig3
-rw-r--r--arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c3
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c221
-rw-r--r--drivers/cpufreq/cpufreq.c75
5 files changed, 190 insertions, 117 deletions
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
index 7fedc00c3d30..555c8cf3650a 100644
--- a/Documentation/cpu-freq/user-guide.txt
+++ b/Documentation/cpu-freq/user-guide.txt
@@ -153,10 +153,13 @@ scaling_governor, and by "echoing" the name of another
153 that some governors won't load - they only 153 that some governors won't load - they only
154 work on some specific architectures or 154 work on some specific architectures or
155 processors. 155 processors.
156scaling_min_freq and 156scaling_min_freq and
157scaling_max_freq show the current "policy limits" (in 157scaling_max_freq show the current "policy limits" (in
158 kHz). By echoing new values into these 158 kHz). By echoing new values into these
159 files, you can change these limits. 159 files, you can change these limits.
160 NOTE: when setting a policy you need to
161 first set scaling_max_freq, then
162 scaling_min_freq.
160 163
161 164
162If you have selected the "userspace" governor which allows you to 165If you have selected the "userspace" governor which allows you to
diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig
index e44a4c6a4fe5..ccc1edff5c97 100644
--- a/arch/i386/kernel/cpu/cpufreq/Kconfig
+++ b/arch/i386/kernel/cpu/cpufreq/Kconfig
@@ -96,6 +96,7 @@ config X86_POWERNOW_K8_ACPI
96 96
97config X86_GX_SUSPMOD 97config X86_GX_SUSPMOD
98 tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation" 98 tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
99 depends on PCI
99 help 100 help
100 This add the CPUFreq driver for NatSemi Geode processors which 101 This add the CPUFreq driver for NatSemi Geode processors which
101 support suspend modulation. 102 support suspend modulation.
@@ -202,7 +203,7 @@ config X86_LONGRUN
202config X86_LONGHAUL 203config X86_LONGHAUL
203 tristate "VIA Cyrix III Longhaul" 204 tristate "VIA Cyrix III Longhaul"
204 select CPU_FREQ_TABLE 205 select CPU_FREQ_TABLE
205 depends on BROKEN 206 depends on ACPI_PROCESSOR
206 help 207 help
207 This adds the CPUFreq driver for VIA Samuel/CyrixIII, 208 This adds the CPUFreq driver for VIA Samuel/CyrixIII,
208 VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T 209 VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
index 567b39bea07e..efb41e81351c 100644
--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -384,8 +384,7 @@ static int acpi_cpufreq_early_init_acpi(void)
384 } 384 }
385 385
386 /* Do initialization in ACPI core */ 386 /* Do initialization in ACPI core */
387 acpi_processor_preregister_performance(acpi_perf_data); 387 return acpi_processor_preregister_performance(acpi_perf_data);
388 return 0;
389} 388}
390 389
391static int 390static int
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 146f607e9c44..4f2c3aeef724 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -29,11 +29,13 @@
29#include <linux/cpufreq.h> 29#include <linux/cpufreq.h>
30#include <linux/slab.h> 30#include <linux/slab.h>
31#include <linux/string.h> 31#include <linux/string.h>
32#include <linux/pci.h>
33 32
34#include <asm/msr.h> 33#include <asm/msr.h>
35#include <asm/timex.h> 34#include <asm/timex.h>
36#include <asm/io.h> 35#include <asm/io.h>
36#include <asm/acpi.h>
37#include <linux/acpi.h>
38#include <acpi/processor.h>
37 39
38#include "longhaul.h" 40#include "longhaul.h"
39 41
@@ -56,6 +58,8 @@ static int minvid, maxvid;
56static unsigned int minmult, maxmult; 58static unsigned int minmult, maxmult;
57static int can_scale_voltage; 59static int can_scale_voltage;
58static int vrmrev; 60static int vrmrev;
61static struct acpi_processor *pr = NULL;
62static struct acpi_processor_cx *cx = NULL;
59 63
60/* Module parameters */ 64/* Module parameters */
61static int dont_scale_voltage; 65static int dont_scale_voltage;
@@ -118,84 +122,65 @@ static int longhaul_get_cpu_mult(void)
118 return eblcr_table[invalue]; 122 return eblcr_table[invalue];
119} 123}
120 124
125/* For processor with BCR2 MSR */
121 126
122static void do_powersaver(union msr_longhaul *longhaul, 127static void do_longhaul1(int cx_address, unsigned int clock_ratio_index)
123 unsigned int clock_ratio_index)
124{ 128{
125 struct pci_dev *dev; 129 union msr_bcr2 bcr2;
126 unsigned long flags; 130 u32 t;
127 unsigned int tmp_mask;
128 int version;
129 int i;
130 u16 pci_cmd;
131 u16 cmd_state[64];
132 131
133 switch (cpu_model) { 132 rdmsrl(MSR_VIA_BCR2, bcr2.val);
134 case CPU_EZRA_T: 133 /* Enable software clock multiplier */
135 version = 3; 134 bcr2.bits.ESOFTBF = 1;
136 break; 135 bcr2.bits.CLOCKMUL = clock_ratio_index;
137 case CPU_NEHEMIAH:
138 version = 0xf;
139 break;
140 default:
141 return;
142 }
143 136
144 rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); 137 /* Sync to timer tick */
145 longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf; 138 safe_halt();
146 longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; 139 ACPI_FLUSH_CPU_CACHE();
147 longhaul->bits.EnableSoftBusRatio = 1; 140 /* Change frequency on next halt or sleep */
148 longhaul->bits.RevisionKey = 0; 141 wrmsrl(MSR_VIA_BCR2, bcr2.val);
142 /* Invoke C3 */
143 inb(cx_address);
144 /* Dummy op - must do something useless after P_LVL3 read */
145 t = inl(acpi_fadt.xpm_tmr_blk.address);
146
147 /* Disable software clock multiplier */
148 local_irq_disable();
149 rdmsrl(MSR_VIA_BCR2, bcr2.val);
150 bcr2.bits.ESOFTBF = 0;
151 wrmsrl(MSR_VIA_BCR2, bcr2.val);
152}
149 153
150 preempt_disable(); 154/* For processor with Longhaul MSR */
151 local_irq_save(flags);
152 155
153 /* 156static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
154 * get current pci bus master state for all devices 157{
155 * and clear bus master bit 158 union msr_longhaul longhaul;
156 */ 159 u32 t;
157 dev = NULL;
158 i = 0;
159 do {
160 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
161 if (dev != NULL) {
162 pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
163 cmd_state[i++] = pci_cmd;
164 pci_cmd &= ~PCI_COMMAND_MASTER;
165 pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
166 }
167 } while (dev != NULL);
168 160
169 tmp_mask=inb(0x21); /* works on C3. save mask. */ 161 rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
170 outb(0xFE,0x21); /* TMR0 only */ 162 longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
171 outb(0xFF,0x80); /* delay */ 163 longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
164 longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
165 longhaul.bits.EnableSoftBusRatio = 1;
172 166
167 /* Sync to timer tick */
173 safe_halt(); 168 safe_halt();
174 wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); 169 ACPI_FLUSH_CPU_CACHE();
175 halt(); 170 /* Change frequency on next halt or sleep */
176 171 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
172 /* Invoke C3 */
173 inb(cx_address);
174 /* Dummy op - must do something useless after P_LVL3 read */
175 t = inl(acpi_fadt.xpm_tmr_blk.address);
176
177 /* Disable bus ratio bit */
177 local_irq_disable(); 178 local_irq_disable();
178 179 longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
179 outb(tmp_mask,0x21); /* restore mask */ 180 longhaul.bits.EnableSoftBusRatio = 0;
180 181 longhaul.bits.EnableSoftBSEL = 0;
181 /* restore pci bus master state for all devices */ 182 longhaul.bits.EnableSoftVID = 0;
182 dev = NULL; 183 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
183 i = 0;
184 do {
185 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
186 if (dev != NULL) {
187 pci_cmd = cmd_state[i++];
188 pci_write_config_byte(dev, PCI_COMMAND, pci_cmd);
189 }
190 } while (dev != NULL);
191 local_irq_restore(flags);
192 preempt_enable();
193
194 /* disable bus ratio bit */
195 rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
196 longhaul->bits.EnableSoftBusRatio = 0;
197 longhaul->bits.RevisionKey = version;
198 wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
199} 184}
200 185
201/** 186/**
@@ -209,9 +194,9 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
209{ 194{
210 int speed, mult; 195 int speed, mult;
211 struct cpufreq_freqs freqs; 196 struct cpufreq_freqs freqs;
212 union msr_longhaul longhaul;
213 union msr_bcr2 bcr2;
214 static unsigned int old_ratio=-1; 197 static unsigned int old_ratio=-1;
198 unsigned long flags;
199 unsigned int pic1_mask, pic2_mask;
215 200
216 if (old_ratio == clock_ratio_index) 201 if (old_ratio == clock_ratio_index)
217 return; 202 return;
@@ -234,6 +219,20 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
234 dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", 219 dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
235 fsb, mult/10, mult%10, print_speed(speed/1000)); 220 fsb, mult/10, mult%10, print_speed(speed/1000));
236 221
222 preempt_disable();
223 local_irq_save(flags);
224
225 pic2_mask = inb(0xA1);
226 pic1_mask = inb(0x21); /* works on C3. save mask. */
227 outb(0xFF,0xA1); /* Overkill */
228 outb(0xFE,0x21); /* TMR0 only */
229
230 /* Disable bus master arbitration */
231 if (pr->flags.bm_check) {
232 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
233 ACPI_MTX_DO_NOT_LOCK);
234 }
235
237 switch (longhaul_version) { 236 switch (longhaul_version) {
238 237
239 /* 238 /*
@@ -245,20 +244,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
245 */ 244 */
246 case TYPE_LONGHAUL_V1: 245 case TYPE_LONGHAUL_V1:
247 case TYPE_LONGHAUL_V2: 246 case TYPE_LONGHAUL_V2:
248 rdmsrl (MSR_VIA_BCR2, bcr2.val); 247 do_longhaul1(cx->address, clock_ratio_index);
249 /* Enable software clock multiplier */
250 bcr2.bits.ESOFTBF = 1;
251 bcr2.bits.CLOCKMUL = clock_ratio_index;
252 local_irq_disable();
253 wrmsrl (MSR_VIA_BCR2, bcr2.val);
254 safe_halt();
255
256 /* Disable software clock multiplier */
257 rdmsrl (MSR_VIA_BCR2, bcr2.val);
258 bcr2.bits.ESOFTBF = 0;
259 local_irq_disable();
260 wrmsrl (MSR_VIA_BCR2, bcr2.val);
261 local_irq_enable();
262 break; 248 break;
263 249
264 /* 250 /*
@@ -273,10 +259,22 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
273 * to work in practice. 259 * to work in practice.
274 */ 260 */
275 case TYPE_POWERSAVER: 261 case TYPE_POWERSAVER:
276 do_powersaver(&longhaul, clock_ratio_index); 262 do_powersaver(cx->address, clock_ratio_index);
277 break; 263 break;
278 } 264 }
279 265
266 /* Enable bus master arbitration */
267 if (pr->flags.bm_check) {
268 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
269 ACPI_MTX_DO_NOT_LOCK);
270 }
271
272 outb(pic2_mask,0xA1); /* restore mask */
273 outb(pic1_mask,0x21);
274
275 local_irq_restore(flags);
276 preempt_enable();
277
280 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 278 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
281} 279}
282 280
@@ -324,9 +322,11 @@ static int guess_fsb(void)
324static int __init longhaul_get_ranges(void) 322static int __init longhaul_get_ranges(void)
325{ 323{
326 unsigned long invalue; 324 unsigned long invalue;
327 unsigned int multipliers[32]= { 325 unsigned int ezra_t_multipliers[32]= {
328 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, 326 90, 30, 40, 100, 55, 35, 45, 95,
329 -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 }; 327 50, 70, 80, 60, 120, 75, 85, 65,
328 -1, 110, 120, -1, 135, 115, 125, 105,
329 130, 150, 160, 140, -1, 155, -1, 145 };
330 unsigned int j, k = 0; 330 unsigned int j, k = 0;
331 union msr_longhaul longhaul; 331 union msr_longhaul longhaul;
332 unsigned long lo, hi; 332 unsigned long lo, hi;
@@ -355,13 +355,13 @@ static int __init longhaul_get_ranges(void)
355 invalue = longhaul.bits.MaxMHzBR; 355 invalue = longhaul.bits.MaxMHzBR;
356 if (longhaul.bits.MaxMHzBR4) 356 if (longhaul.bits.MaxMHzBR4)
357 invalue += 16; 357 invalue += 16;
358 maxmult=multipliers[invalue]; 358 maxmult=ezra_t_multipliers[invalue];
359 359
360 invalue = longhaul.bits.MinMHzBR; 360 invalue = longhaul.bits.MinMHzBR;
361 if (longhaul.bits.MinMHzBR4 == 1) 361 if (longhaul.bits.MinMHzBR4 == 1)
362 minmult = 30; 362 minmult = 30;
363 else 363 else
364 minmult = multipliers[invalue]; 364 minmult = ezra_t_multipliers[invalue];
365 fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB]; 365 fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
366 break; 366 break;
367 } 367 }
@@ -527,6 +527,18 @@ static unsigned int longhaul_get(unsigned int cpu)
527 return calc_speed(longhaul_get_cpu_mult()); 527 return calc_speed(longhaul_get_cpu_mult());
528} 528}
529 529
530static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
531 u32 nesting_level,
532 void *context, void **return_value)
533{
534 struct acpi_device *d;
535
536 if ( acpi_bus_get_device(obj_handle, &d) ) {
537 return 0;
538 }
539 *return_value = (void *)acpi_driver_data(d);
540 return 1;
541}
530 542
531static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 543static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
532{ 544{
@@ -534,6 +546,15 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
534 char *cpuname=NULL; 546 char *cpuname=NULL;
535 int ret; 547 int ret;
536 548
549 /* Check ACPI support for C3 state */
550 acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
551 &longhaul_walk_callback, NULL, (void *)&pr);
552 if (pr == NULL) goto err_acpi;
553
554 cx = &pr->power.states[ACPI_STATE_C3];
555 if (cx->address == 0 || cx->latency > 1000) goto err_acpi;
556
557 /* Now check what we have on this motherboard */
537 switch (c->x86_model) { 558 switch (c->x86_model) {
538 case 6: 559 case 6:
539 cpu_model = CPU_SAMUEL; 560 cpu_model = CPU_SAMUEL;
@@ -634,6 +655,10 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
634 cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); 655 cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu);
635 656
636 return 0; 657 return 0;
658
659err_acpi:
660 printk(KERN_ERR PFX "No ACPI support for CPU frequency changes.\n");
661 return -ENODEV;
637} 662}
638 663
639static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) 664static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)
@@ -666,6 +691,18 @@ static int __init longhaul_init(void)
666 if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6) 691 if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)
667 return -ENODEV; 692 return -ENODEV;
668 693
694#ifdef CONFIG_SMP
695 if (num_online_cpus() > 1) {
696 return -ENODEV;
697 printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n");
698 }
699#endif
700#ifdef CONFIG_X86_IO_APIC
701 if (cpu_has_apic) {
702 printk(KERN_ERR PFX "APIC detected. Longhaul is currently broken in this configuration.\n");
703 return -ENODEV;
704 }
705#endif
669 switch (c->x86_model) { 706 switch (c->x86_model) {
670 case 6 ... 9: 707 case 6 ... 9:
671 return cpufreq_register_driver(&longhaul_driver); 708 return cpufreq_register_driver(&longhaul_driver);
@@ -699,6 +736,6 @@ MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
699MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); 736MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
700MODULE_LICENSE ("GPL"); 737MODULE_LICENSE ("GPL");
701 738
702module_init(longhaul_init); 739late_initcall(longhaul_init);
703module_exit(longhaul_exit); 740module_exit(longhaul_exit);
704 741
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index bc1088d9b379..b3df613ae4ec 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -284,39 +284,69 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
284 * SYSFS INTERFACE * 284 * SYSFS INTERFACE *
285 *********************************************************************/ 285 *********************************************************************/
286 286
287static struct cpufreq_governor *__find_governor(const char *str_governor)
288{
289 struct cpufreq_governor *t;
290
291 list_for_each_entry(t, &cpufreq_governor_list, governor_list)
292 if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN))
293 return t;
294
295 return NULL;
296}
297
287/** 298/**
288 * cpufreq_parse_governor - parse a governor string 299 * cpufreq_parse_governor - parse a governor string
289 */ 300 */
290static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, 301static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
291 struct cpufreq_governor **governor) 302 struct cpufreq_governor **governor)
292{ 303{
304 int err = -EINVAL;
305
293 if (!cpufreq_driver) 306 if (!cpufreq_driver)
294 return -EINVAL; 307 goto out;
308
295 if (cpufreq_driver->setpolicy) { 309 if (cpufreq_driver->setpolicy) {
296 if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { 310 if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
297 *policy = CPUFREQ_POLICY_PERFORMANCE; 311 *policy = CPUFREQ_POLICY_PERFORMANCE;
298 return 0; 312 err = 0;
299 } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) { 313 } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
300 *policy = CPUFREQ_POLICY_POWERSAVE; 314 *policy = CPUFREQ_POLICY_POWERSAVE;
301 return 0; 315 err = 0;
302 } 316 }
303 return -EINVAL; 317 } else if (cpufreq_driver->target) {
304 } else {
305 struct cpufreq_governor *t; 318 struct cpufreq_governor *t;
319
306 mutex_lock(&cpufreq_governor_mutex); 320 mutex_lock(&cpufreq_governor_mutex);
307 if (!cpufreq_driver || !cpufreq_driver->target) 321
308 goto out; 322 t = __find_governor(str_governor);
309 list_for_each_entry(t, &cpufreq_governor_list, governor_list) { 323
310 if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) { 324 if (t == NULL) {
311 *governor = t; 325 char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", str_governor);
326
327 if (name) {
328 int ret;
329
312 mutex_unlock(&cpufreq_governor_mutex); 330 mutex_unlock(&cpufreq_governor_mutex);
313 return 0; 331 ret = request_module(name);
332 mutex_lock(&cpufreq_governor_mutex);
333
334 if (ret == 0)
335 t = __find_governor(str_governor);
314 } 336 }
337
338 kfree(name);
315 } 339 }
316out: 340
341 if (t != NULL) {
342 *governor = t;
343 err = 0;
344 }
345
317 mutex_unlock(&cpufreq_governor_mutex); 346 mutex_unlock(&cpufreq_governor_mutex);
318 } 347 }
319 return -EINVAL; 348 out:
349 return err;
320} 350}
321 351
322 352
@@ -1265,23 +1295,21 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
1265 1295
1266int cpufreq_register_governor(struct cpufreq_governor *governor) 1296int cpufreq_register_governor(struct cpufreq_governor *governor)
1267{ 1297{
1268 struct cpufreq_governor *t; 1298 int err;
1269 1299
1270 if (!governor) 1300 if (!governor)
1271 return -EINVAL; 1301 return -EINVAL;
1272 1302
1273 mutex_lock(&cpufreq_governor_mutex); 1303 mutex_lock(&cpufreq_governor_mutex);
1274 1304
1275 list_for_each_entry(t, &cpufreq_governor_list, governor_list) { 1305 err = -EBUSY;
1276 if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) { 1306 if (__find_governor(governor->name) == NULL) {
1277 mutex_unlock(&cpufreq_governor_mutex); 1307 err = 0;
1278 return -EBUSY; 1308 list_add(&governor->governor_list, &cpufreq_governor_list);
1279 }
1280 } 1309 }
1281 list_add(&governor->governor_list, &cpufreq_governor_list);
1282 1310
1283 mutex_unlock(&cpufreq_governor_mutex); 1311 mutex_unlock(&cpufreq_governor_mutex);
1284 return 0; 1312 return err;
1285} 1313}
1286EXPORT_SYMBOL_GPL(cpufreq_register_governor); 1314EXPORT_SYMBOL_GPL(cpufreq_register_governor);
1287 1315
@@ -1343,6 +1371,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli
1343 1371
1344 memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo)); 1372 memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo));
1345 1373
1374 if (policy->min > data->min && policy->min > policy->max) {
1375 ret = -EINVAL;
1376 goto error_out;
1377 }
1378
1346 /* verify the cpu speed can be set within this limit */ 1379 /* verify the cpu speed can be set within this limit */
1347 ret = cpufreq_driver->verify(policy); 1380 ret = cpufreq_driver->verify(policy);
1348 if (ret) 1381 if (ret)