diff options
author | Rafał Bilski <rafalbilski@interia.pl> | 2006-08-08 13:12:20 -0400 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2006-08-11 17:59:57 -0400 |
commit | 179da8e6e8903a8cdb19bb12672d50dc33f0fde6 (patch) | |
tree | 0e791d2d3890db822508f64d2bc1301ac307c982 /arch | |
parent | 05ca0350e8caa91a5ec9961c585c98005b6934ea (diff) |
[CPUFREQ] Longhaul - Disable arbiter
ACPI C3 works for "Powersaver" processors, so use it only for them.
Older CPU will change frequency on "halt" only. But we can protect transition
in two ways:
- by ACPI PM2 register, there is "bus master arbiter disable" bit.
This isn't tested because VIA mainboards don't have PM2 register,
- by PLE133 PCI/AGP arbiter disable register.
There are two bits in this register. First is "PCI arbiter disable",
second "AGP arbiter disable". This is working on VIA Epia 800 mainboards.
Test on bm_control is more proper because this is true
when PM2 register exist.
Signed-off-by: Rafał Bilski <rafalbilski@interia.pl>
Signed-off-by: Dave Jones <davej@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 86 |
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; | |||
60 | static int vrmrev; | 61 | static int vrmrev; |
61 | static struct acpi_processor *pr = NULL; | 62 | static struct acpi_processor *pr = NULL; |
62 | static struct acpi_processor_cx *cx = NULL; | 63 | static struct acpi_processor_cx *cx = NULL; |
64 | static int port22_en = 0; | ||
63 | 65 | ||
64 | /* Module parameters */ | 66 | /* Module parameters */ |
65 | static int dont_scale_voltage; | 67 | static 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 | ||
127 | static void do_longhaul1(int cx_address, unsigned int clock_ratio_index) | 129 | static 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 */ | ||
552 | static 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 | |||
543 | static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | 571 | static 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; |