aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c86
1 files changed, 64 insertions, 22 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 4f2c3aeef724..83a8793f1db8 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -27,6 +27,7 @@
27#include <linux/moduleparam.h> 27#include <linux/moduleparam.h>
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/cpufreq.h> 29#include <linux/cpufreq.h>
30#include <linux/pci.h>
30#include <linux/slab.h> 31#include <linux/slab.h>
31#include <linux/string.h> 32#include <linux/string.h>
32 33
@@ -60,6 +61,7 @@ static int can_scale_voltage;
60static int vrmrev; 61static int vrmrev;
61static struct acpi_processor *pr = NULL; 62static struct acpi_processor *pr = NULL;
62static struct acpi_processor_cx *cx = NULL; 63static struct acpi_processor_cx *cx = NULL;
64static int port22_en = 0;
63 65
64/* Module parameters */ 66/* Module parameters */
65static int dont_scale_voltage; 67static int dont_scale_voltage;
@@ -124,10 +126,9 @@ static int longhaul_get_cpu_mult(void)
124 126
125/* For processor with BCR2 MSR */ 127/* For processor with BCR2 MSR */
126 128
127static void do_longhaul1(int cx_address, unsigned int clock_ratio_index) 129static void do_longhaul1(unsigned int clock_ratio_index)
128{ 130{
129 union msr_bcr2 bcr2; 131 union msr_bcr2 bcr2;
130 u32 t;
131 132
132 rdmsrl(MSR_VIA_BCR2, bcr2.val); 133 rdmsrl(MSR_VIA_BCR2, bcr2.val);
133 /* Enable software clock multiplier */ 134 /* Enable software clock multiplier */
@@ -136,13 +137,11 @@ static void do_longhaul1(int cx_address, unsigned int clock_ratio_index)
136 137
137 /* Sync to timer tick */ 138 /* Sync to timer tick */
138 safe_halt(); 139 safe_halt();
139 ACPI_FLUSH_CPU_CACHE();
140 /* Change frequency on next halt or sleep */ 140 /* Change frequency on next halt or sleep */
141 wrmsrl(MSR_VIA_BCR2, bcr2.val); 141 wrmsrl(MSR_VIA_BCR2, bcr2.val);
142 /* Invoke C3 */ 142 /* Invoke transition */
143 inb(cx_address); 143 ACPI_FLUSH_CPU_CACHE();
144 /* Dummy op - must do something useless after P_LVL3 read */ 144 halt();
145 t = inl(acpi_fadt.xpm_tmr_blk.address);
146 145
147 /* Disable software clock multiplier */ 146 /* Disable software clock multiplier */
148 local_irq_disable(); 147 local_irq_disable();
@@ -166,9 +165,9 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
166 165
167 /* Sync to timer tick */ 166 /* Sync to timer tick */
168 safe_halt(); 167 safe_halt();
169 ACPI_FLUSH_CPU_CACHE();
170 /* Change frequency on next halt or sleep */ 168 /* Change frequency on next halt or sleep */
171 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); 169 wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
170 ACPI_FLUSH_CPU_CACHE();
172 /* Invoke C3 */ 171 /* Invoke C3 */
173 inb(cx_address); 172 inb(cx_address);
174 /* Dummy op - must do something useless after P_LVL3 read */ 173 /* Dummy op - must do something useless after P_LVL3 read */
@@ -227,10 +226,13 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
227 outb(0xFF,0xA1); /* Overkill */ 226 outb(0xFF,0xA1); /* Overkill */
228 outb(0xFE,0x21); /* TMR0 only */ 227 outb(0xFE,0x21); /* TMR0 only */
229 228
230 /* Disable bus master arbitration */ 229 if (pr->flags.bm_control) {
231 if (pr->flags.bm_check) { 230 /* Disable bus master arbitration */
232 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, 231 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
233 ACPI_MTX_DO_NOT_LOCK); 232 ACPI_MTX_DO_NOT_LOCK);
233 } else if (port22_en) {
234 /* Disable AGP and PCI arbiters */
235 outb(3, 0x22);
234 } 236 }
235 237
236 switch (longhaul_version) { 238 switch (longhaul_version) {
@@ -244,7 +246,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
244 */ 246 */
245 case TYPE_LONGHAUL_V1: 247 case TYPE_LONGHAUL_V1:
246 case TYPE_LONGHAUL_V2: 248 case TYPE_LONGHAUL_V2:
247 do_longhaul1(cx->address, clock_ratio_index); 249 do_longhaul1(clock_ratio_index);
248 break; 250 break;
249 251
250 /* 252 /*
@@ -259,14 +261,20 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
259 * to work in practice. 261 * to work in practice.
260 */ 262 */
261 case TYPE_POWERSAVER: 263 case TYPE_POWERSAVER:
264 /* Don't allow wakeup */
265 acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
266 ACPI_MTX_DO_NOT_LOCK);
262 do_powersaver(cx->address, clock_ratio_index); 267 do_powersaver(cx->address, clock_ratio_index);
263 break; 268 break;
264 } 269 }
265 270
266 /* Enable bus master arbitration */ 271 if (pr->flags.bm_control) {
267 if (pr->flags.bm_check) { 272 /* Enable bus master arbitration */
268 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, 273 acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
269 ACPI_MTX_DO_NOT_LOCK); 274 ACPI_MTX_DO_NOT_LOCK);
275 } else if (port22_en) {
276 /* Enable arbiters */
277 outb(0, 0x22);
270 } 278 }
271 279
272 outb(pic2_mask,0xA1); /* restore mask */ 280 outb(pic2_mask,0xA1); /* restore mask */
@@ -540,21 +548,33 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
540 return 1; 548 return 1;
541} 549}
542 550
551/* VIA don't support PM2 reg, but have something similar */
552static int enable_arbiter_disable(void)
553{
554 struct pci_dev *dev;
555 u8 pci_cmd;
556
557 /* Find PLE133 host bridge */
558 dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL);
559 if (dev != NULL) {
560 /* Enable access to port 0x22 */
561 pci_read_config_byte(dev, 0x78, &pci_cmd);
562 if ( !(pci_cmd & 1<<7) ) {
563 pci_cmd |= 1<<7;
564 pci_write_config_byte(dev, 0x78, pci_cmd);
565 }
566 return 1;
567 }
568 return 0;
569}
570
543static int __init longhaul_cpu_init(struct cpufreq_policy *policy) 571static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
544{ 572{
545 struct cpuinfo_x86 *c = cpu_data; 573 struct cpuinfo_x86 *c = cpu_data;
546 char *cpuname=NULL; 574 char *cpuname=NULL;
547 int ret; 575 int ret;
548 576
549 /* Check ACPI support for C3 state */ 577 /* Check what we have on this motherboard */
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 */
558 switch (c->x86_model) { 578 switch (c->x86_model) {
559 case 6: 579 case 6:
560 cpu_model = CPU_SAMUEL; 580 cpu_model = CPU_SAMUEL;
@@ -636,6 +656,28 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
636 break; 656 break;
637 }; 657 };
638 658
659 /* Find ACPI data for processor */
660 acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
661 &longhaul_walk_callback, NULL, (void *)&pr);
662 if (pr == NULL)
663 goto err_acpi;
664
665 if (longhaul_version == TYPE_POWERSAVER) {
666 /* Check ACPI support for C3 state */
667 cx = &pr->power.states[ACPI_STATE_C3];
668 if (cx->address == 0 || cx->latency > 1000)
669 goto err_acpi;
670 } else {
671 /* Check ACPI support for bus master arbiter disable */
672 if (!pr->flags.bm_control) {
673 if (!enable_arbiter_disable()) {
674 printk(KERN_ERR PFX "No ACPI support. No VT8601 host bridge. Aborting.\n");
675 return -ENODEV;
676 } else
677 port22_en = 1;
678 }
679 }
680
639 ret = longhaul_get_ranges(); 681 ret = longhaul_get_ranges();
640 if (ret != 0) 682 if (ret != 0)
641 return ret; 683 return ret;