aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/cpu/cpufreq/longhaul.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/cpu/cpufreq/longhaul.c')
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c194
1 files changed, 108 insertions, 86 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 146f607e9c44..d735cb460612 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,64 @@ 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;
172 165
166 /* Sync to timer tick */
173 safe_halt(); 167 safe_halt();
174 wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); 168 ACPI_FLUSH_CPU_CACHE();
175 halt(); 169 /* Change frequency on next halt or sleep */
176 170 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
171 /* Invoke C3 */
172 inb(cx_address);
173 /* Dummy op - must do something useless after P_LVL3 read */
174 t = inl(acpi_fadt.xpm_tmr_blk.address);
175
176 /* Disable bus ratio bit */
177 local_irq_disable(); 177 local_irq_disable();
178 178 longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
179 outb(tmp_mask,0x21); /* restore mask */ 179 longhaul.bits.EnableSoftBusRatio = 0;
180 180 longhaul.bits.EnableSoftBSEL = 0;
181 /* restore pci bus master state for all devices */ 181 longhaul.bits.EnableSoftVID = 0;
182 dev = NULL; 182 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} 183}
200 184
201/** 185/**
@@ -209,9 +193,9 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
209{ 193{
210 int speed, mult; 194 int speed, mult;
211 struct cpufreq_freqs freqs; 195 struct cpufreq_freqs freqs;
212 union msr_longhaul longhaul;
213 union msr_bcr2 bcr2;
214 static unsigned int old_ratio=-1; 196 static unsigned int old_ratio=-1;
197 unsigned long flags;
198 unsigned int pic1_mask, pic2_mask;
215 199
216 if (old_ratio == clock_ratio_index) 200 if (old_ratio == clock_ratio_index)
217 return; 201 return;
@@ -234,6 +218,20 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
234 dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", 218 dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
235 fsb, mult/10, mult%10, print_speed(speed/1000)); 219 fsb, mult/10, mult%10, print_speed(speed/1000));
236 220
221 preempt_disable();
222 local_irq_save(flags);
223
224 pic2_mask = inb(0xA1);
225 pic1_mask = inb(0x21); /* works on C3. save mask. */
226 outb(0xFF,0xA1); /* Overkill */
227 outb(0xFE,0x21); /* TMR0 only */
228
229 /* Disable bus master arbitration */
230 if (pr->flags.bm_check) {
231 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
232 ACPI_MTX_DO_NOT_LOCK);
233 }
234
237 switch (longhaul_version) { 235 switch (longhaul_version) {
238 236
239 /* 237 /*
@@ -245,20 +243,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
245 */ 243 */
246 case TYPE_LONGHAUL_V1: 244 case TYPE_LONGHAUL_V1:
247 case TYPE_LONGHAUL_V2: 245 case TYPE_LONGHAUL_V2:
248 rdmsrl (MSR_VIA_BCR2, bcr2.val); 246 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; 247 break;
263 248
264 /* 249 /*
@@ -273,10 +258,22 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
273 * to work in practice. 258 * to work in practice.
274 */ 259 */
275 case TYPE_POWERSAVER: 260 case TYPE_POWERSAVER:
276 do_powersaver(&longhaul, clock_ratio_index); 261 do_powersaver(cx->address, clock_ratio_index);
277 break; 262 break;
278 } 263 }
279 264
265 /* Enable bus master arbitration */
266 if (pr->flags.bm_check) {
267 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
268 ACPI_MTX_DO_NOT_LOCK);
269 }
270
271 outb(pic2_mask,0xA1); /* restore mask */
272 outb(pic1_mask,0x21);
273
274 local_irq_restore(flags);
275 preempt_enable();
276
280 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 277 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
281} 278}
282 279
@@ -527,6 +524,18 @@ static unsigned int longhaul_get(unsigned int cpu)
527 return calc_speed(longhaul_get_cpu_mult()); 524 return calc_speed(longhaul_get_cpu_mult());
528} 525}
529 526
527acpi_status longhaul_walk_callback(acpi_handle obj_handle,
528 u32 nesting_level,
529 void *context, void **return_value)
530{
531 struct acpi_device *d;
532
533 if ( acpi_bus_get_device(obj_handle, &d) ) {
534 return 0;
535 }
536 *return_value = (void *)acpi_driver_data(d);
537 return 1;
538}
530 539
531static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 540static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
532{ 541{
@@ -534,6 +543,15 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
534 char *cpuname=NULL; 543 char *cpuname=NULL;
535 int ret; 544 int ret;
536 545
546 /* Check ACPI support for C3 state */
547 acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
548 &longhaul_walk_callback, NULL, (void *)&pr);
549 if (pr == NULL) goto err_acpi;
550
551 cx = &pr->power.states[ACPI_STATE_C3];
552 if (cx == NULL || cx->latency > 1000) goto err_acpi;
553
554 /* Now check what we have on this motherboard */
537 switch (c->x86_model) { 555 switch (c->x86_model) {
538 case 6: 556 case 6:
539 cpu_model = CPU_SAMUEL; 557 cpu_model = CPU_SAMUEL;
@@ -634,6 +652,10 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
634 cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); 652 cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu);
635 653
636 return 0; 654 return 0;
655
656err_acpi:
657 printk(KERN_ERR PFX "No ACPI support for CPU frequency changes.\n");
658 return -ENODEV;
637} 659}
638 660
639static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) 661static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)