diff options
Diffstat (limited to 'arch/i386/kernel/cpu/cpufreq/longhaul.c')
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 58 |
1 files changed, 53 insertions, 5 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index ab0f9f5aac11..04e3563da4fe 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c | |||
@@ -29,6 +29,7 @@ | |||
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> | ||
32 | 33 | ||
33 | #include <asm/msr.h> | 34 | #include <asm/msr.h> |
34 | #include <asm/timex.h> | 35 | #include <asm/timex.h> |
@@ -119,7 +120,13 @@ static int longhaul_get_cpu_mult(void) | |||
119 | static void do_powersaver(union msr_longhaul *longhaul, | 120 | static void do_powersaver(union msr_longhaul *longhaul, |
120 | unsigned int clock_ratio_index) | 121 | unsigned int clock_ratio_index) |
121 | { | 122 | { |
123 | struct pci_dev *dev; | ||
124 | unsigned long flags; | ||
125 | unsigned int tmp_mask; | ||
122 | int version; | 126 | int version; |
127 | int i; | ||
128 | u16 pci_cmd; | ||
129 | u16 cmd_state[64]; | ||
123 | 130 | ||
124 | switch (cpu_model) { | 131 | switch (cpu_model) { |
125 | case CPU_EZRA_T: | 132 | case CPU_EZRA_T: |
@@ -137,17 +144,58 @@ static void do_powersaver(union msr_longhaul *longhaul, | |||
137 | longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; | 144 | longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; |
138 | longhaul->bits.EnableSoftBusRatio = 1; | 145 | longhaul->bits.EnableSoftBusRatio = 1; |
139 | longhaul->bits.RevisionKey = 0; | 146 | longhaul->bits.RevisionKey = 0; |
140 | local_irq_disable(); | 147 | |
141 | wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); | 148 | preempt_disable(); |
149 | local_irq_save(flags); | ||
150 | |||
151 | /* | ||
152 | * get current pci bus master state for all devices | ||
153 | * and clear bus master bit | ||
154 | */ | ||
155 | dev = NULL; | ||
156 | i = 0; | ||
157 | do { | ||
158 | dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); | ||
159 | if (dev != NULL) { | ||
160 | pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); | ||
161 | cmd_state[i++] = pci_cmd; | ||
162 | pci_cmd &= ~PCI_COMMAND_MASTER; | ||
163 | pci_write_config_word(dev, PCI_COMMAND, pci_cmd); | ||
164 | } | ||
165 | } while (dev != NULL); | ||
166 | |||
167 | tmp_mask=inb(0x21); /* works on C3. save mask. */ | ||
168 | outb(0xFE,0x21); /* TMR0 only */ | ||
169 | outb(0xFF,0x80); /* delay */ | ||
170 | |||
142 | local_irq_enable(); | 171 | local_irq_enable(); |
172 | |||
173 | __hlt(); | ||
174 | wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); | ||
143 | __hlt(); | 175 | __hlt(); |
144 | 176 | ||
177 | local_irq_disable(); | ||
178 | |||
179 | outb(tmp_mask,0x21); /* restore mask */ | ||
180 | |||
181 | /* restore pci bus master state for all devices */ | ||
182 | dev = NULL; | ||
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 */ | ||
145 | rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); | 195 | rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); |
146 | longhaul->bits.EnableSoftBusRatio = 0; | 196 | longhaul->bits.EnableSoftBusRatio = 0; |
147 | longhaul->bits.RevisionKey = version; | 197 | longhaul->bits.RevisionKey = version; |
148 | local_irq_disable(); | ||
149 | wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); | 198 | wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); |
150 | local_irq_enable(); | ||
151 | } | 199 | } |
152 | 200 | ||
153 | /** | 201 | /** |
@@ -578,7 +626,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) | |||
578 | longhaul_setup_voltagescaling(); | 626 | longhaul_setup_voltagescaling(); |
579 | 627 | ||
580 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | 628 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; |
581 | policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; | 629 | policy->cpuinfo.transition_latency = 200000; /* nsec */ |
582 | policy->cur = calc_speed(longhaul_get_cpu_mult()); | 630 | policy->cur = calc_speed(longhaul_get_cpu_mult()); |
583 | 631 | ||
584 | ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table); | 632 | ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table); |