diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/Kconfig | 3 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 3 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 221 |
3 files changed, 132 insertions, 95 deletions
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 | ||
97 | config X86_GX_SUSPMOD | 97 | config 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 | |||
202 | config X86_LONGHAUL | 203 | config 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 | ||
391 | static int | 390 | static 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; | |||
56 | static unsigned int minmult, maxmult; | 58 | static unsigned int minmult, maxmult; |
57 | static int can_scale_voltage; | 59 | static int can_scale_voltage; |
58 | static int vrmrev; | 60 | static int vrmrev; |
61 | static struct acpi_processor *pr = NULL; | ||
62 | static struct acpi_processor_cx *cx = NULL; | ||
59 | 63 | ||
60 | /* Module parameters */ | 64 | /* Module parameters */ |
61 | static int dont_scale_voltage; | 65 | static 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 | ||
122 | static void do_powersaver(union msr_longhaul *longhaul, | 127 | static 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 | /* | 156 | static 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) | |||
324 | static int __init longhaul_get_ranges(void) | 322 | static 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 | ||
530 | static 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 | ||
531 | static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | 543 | static 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 | |||
659 | err_acpi: | ||
660 | printk(KERN_ERR PFX "No ACPI support for CPU frequency changes.\n"); | ||
661 | return -ENODEV; | ||
637 | } | 662 | } |
638 | 663 | ||
639 | static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) | 664 | static 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>"); | |||
699 | MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); | 736 | MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); |
700 | MODULE_LICENSE ("GPL"); | 737 | MODULE_LICENSE ("GPL"); |
701 | 738 | ||
702 | module_init(longhaul_init); | 739 | late_initcall(longhaul_init); |
703 | module_exit(longhaul_exit); | 740 | module_exit(longhaul_exit); |
704 | 741 | ||