diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 93 |
1 files changed, 69 insertions, 24 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 4f2c3aeef724..43bbf948d45d 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,10 +61,11 @@ 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; |
66 | 68 | static int ignore_latency = 0; | |
67 | 69 | ||
68 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) | 70 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) |
69 | 71 | ||
@@ -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,30 @@ 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 || | ||
669 | (cx->latency > 1000 && ignore_latency == 0) ) | ||
670 | goto err_acpi; | ||
671 | |||
672 | } else { | ||
673 | /* Check ACPI support for bus master arbiter disable */ | ||
674 | if (!pr->flags.bm_control) { | ||
675 | if (!enable_arbiter_disable()) { | ||
676 | printk(KERN_ERR PFX "No ACPI support. No VT8601 host bridge. Aborting.\n"); | ||
677 | return -ENODEV; | ||
678 | } else | ||
679 | port22_en = 1; | ||
680 | } | ||
681 | } | ||
682 | |||
639 | ret = longhaul_get_ranges(); | 683 | ret = longhaul_get_ranges(); |
640 | if (ret != 0) | 684 | if (ret != 0) |
641 | return ret; | 685 | return ret; |
@@ -731,6 +775,8 @@ static void __exit longhaul_exit(void) | |||
731 | 775 | ||
732 | module_param (dont_scale_voltage, int, 0644); | 776 | module_param (dont_scale_voltage, int, 0644); |
733 | MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor"); | 777 | MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor"); |
778 | module_param(ignore_latency, int, 0644); | ||
779 | MODULE_PARM_DESC(ignore_latency, "Skip ACPI C3 latency test"); | ||
734 | 780 | ||
735 | MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); | 781 | MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>"); |
736 | MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); | 782 | MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); |
@@ -738,4 +784,3 @@ MODULE_LICENSE ("GPL"); | |||
738 | 784 | ||
739 | late_initcall(longhaul_init); | 785 | late_initcall(longhaul_init); |
740 | module_exit(longhaul_exit); | 786 | module_exit(longhaul_exit); |
741 | |||