aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/hpet.c2
-rw-r--r--arch/x86/kernel/quirks.c103
-rw-r--r--include/asm-x86/hpet.h2
-rw-r--r--include/linux/pci_ids.h1
4 files changed, 105 insertions, 3 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index a6c68915d2a9..f8367074da0d 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -181,7 +181,7 @@ static void hpet_start_counter(void)
181 181
182static void hpet_resume_device(void) 182static void hpet_resume_device(void)
183{ 183{
184 ich_force_hpet_resume(); 184 force_hpet_resume();
185} 185}
186 186
187static void hpet_restart_counter(void) 187static void hpet_restart_counter(void)
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index d3ac703867d6..79133b1c2595 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -53,9 +53,15 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quir
53#if defined(CONFIG_HPET_TIMER) 53#if defined(CONFIG_HPET_TIMER)
54unsigned long force_hpet_address; 54unsigned long force_hpet_address;
55 55
56static enum {
57 NONE_FORCE_HPET_RESUME,
58 OLD_ICH_FORCE_HPET_RESUME,
59 ICH_FORCE_HPET_RESUME
60} force_hpet_resume_type;
61
56static void __iomem *rcba_base; 62static void __iomem *rcba_base;
57 63
58void ich_force_hpet_resume(void) 64static void ich_force_hpet_resume(void)
59{ 65{
60 u32 val; 66 u32 val;
61 67
@@ -133,6 +139,7 @@ static void ich_force_enable_hpet(struct pci_dev *dev)
133 iounmap(rcba_base); 139 iounmap(rcba_base);
134 printk(KERN_DEBUG "Failed to force enable HPET\n"); 140 printk(KERN_DEBUG "Failed to force enable HPET\n");
135 } else { 141 } else {
142 force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
136 printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", 143 printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
137 force_hpet_address); 144 force_hpet_address);
138 } 145 }
@@ -148,4 +155,98 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
148 ich_force_enable_hpet); 155 ich_force_enable_hpet);
149DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, 156DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1,
150 ich_force_enable_hpet); 157 ich_force_enable_hpet);
158
159
160static struct pci_dev *cached_dev;
161
162static void old_ich_force_hpet_resume(void)
163{
164 u32 val;
165 u32 uninitialized_var(gen_cntl);
166
167 if (!force_hpet_address || !cached_dev)
168 return;
169
170 pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
171 gen_cntl &= (~(0x7 << 15));
172 gen_cntl |= (0x4 << 15);
173
174 pci_write_config_dword(cached_dev, 0xD0, gen_cntl);
175 pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
176 val = gen_cntl >> 15;
177 val &= 0x7;
178 if (val == 0x4)
179 printk(KERN_DEBUG "Force enabled HPET at resume\n");
180 else
181 BUG();
182}
183
184static void old_ich_force_enable_hpet(struct pci_dev *dev)
185{
186 u32 val;
187 u32 uninitialized_var(gen_cntl);
188
189 if (hpet_address || force_hpet_address)
190 return;
191
192 pci_read_config_dword(dev, 0xD0, &gen_cntl);
193 /*
194 * Bit 17 is HPET enable bit.
195 * Bit 16:15 control the HPET base address.
196 */
197 val = gen_cntl >> 15;
198 val &= 0x7;
199 if (val & 0x4) {
200 val &= 0x3;
201 force_hpet_address = 0xFED00000 | (val << 12);
202 printk(KERN_DEBUG "HPET at base address 0x%lx\n",
203 force_hpet_address);
204 cached_dev = dev;
205 return;
206 }
207
208 /*
209 * HPET is disabled. Trying enabling at FED00000 and check
210 * whether it sticks
211 */
212 gen_cntl &= (~(0x7 << 15));
213 gen_cntl |= (0x4 << 15);
214 pci_write_config_dword(dev, 0xD0, gen_cntl);
215
216 pci_read_config_dword(dev, 0xD0, &gen_cntl);
217
218 val = gen_cntl >> 15;
219 val &= 0x7;
220 if (val & 0x4) {
221 /* HPET is enabled in HPTC. Just not reported by BIOS */
222 val &= 0x3;
223 force_hpet_address = 0xFED00000 | (val << 12);
224 printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
225 force_hpet_address);
226 force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME;
227 return;
228 }
229
230 printk(KERN_DEBUG "Failed to force enable HPET\n");
231}
232
233DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
234 old_ich_force_enable_hpet);
235DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_12,
236 old_ich_force_enable_hpet);
237
238void force_hpet_resume(void)
239{
240 switch (force_hpet_resume_type) {
241 case ICH_FORCE_HPET_RESUME:
242 return ich_force_hpet_resume();
243
244 case OLD_ICH_FORCE_HPET_RESUME:
245 return old_ich_force_hpet_resume();
246
247 default:
248 break;
249 }
250}
251
151#endif 252#endif
diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h
index 47de4b8cdda9..d4ab6db050b6 100644
--- a/include/asm-x86/hpet.h
+++ b/include/asm-x86/hpet.h
@@ -67,7 +67,7 @@ extern unsigned long force_hpet_address;
67extern int is_hpet_enabled(void); 67extern int is_hpet_enabled(void);
68extern int hpet_enable(void); 68extern int hpet_enable(void);
69extern unsigned long hpet_readl(unsigned long a); 69extern unsigned long hpet_readl(unsigned long a);
70extern void ich_force_hpet_resume(void); 70extern void force_hpet_resume(void);
71 71
72#ifdef CONFIG_HPET_EMULATE_RTC 72#ifdef CONFIG_HPET_EMULATE_RTC
73 73
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 3948708c42ca..584741bb73b3 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2242,6 +2242,7 @@
2242#define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5 2242#define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5
2243#define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6 2243#define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6
2244#define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db 2244#define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db
2245#define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc
2245#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd 2246#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd
2246#define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1 2247#define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1
2247#define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2 2248#define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2