blob: 79133b1c259559db48895057deb3d9183af9adf6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * This file contains work-arounds for x86 and x86_64 platform bugs.
3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004#include <linux/pci.h>
5#include <linux/irq.h>
6
Venki Pallipadid54bd572007-10-12 23:04:23 +02007#include <asm/hpet.h>
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
10
Andrew Mortona86f34b2007-05-02 19:27:04 +020011static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070012{
13 u8 config, rev;
14 u32 word;
15
16 /* BIOS may enable hardware IRQ balancing for
17 * E7520/E7320/E7525(revision ID 0x9 and below)
18 * based platforms.
19 * Disable SW irqbalance/affinity on those platforms.
20 */
Andrew Mortona86f34b2007-05-02 19:27:04 +020021 pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 if (rev > 0x9)
23 return;
24
Andrew Mortona86f34b2007-05-02 19:27:04 +020025 /* enable access to config space*/
26 pci_read_config_byte(dev, 0xf4, &config);
27 pci_write_config_byte(dev, 0xf4, config|0x2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29 /* read xTPR register */
Andrew Mortona86f34b2007-05-02 19:27:04 +020030 raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32 if (!(word & (1 << 13))) {
Dave Jones38377be2007-07-06 14:59:43 -040033 printk(KERN_INFO "Intel E7520/7320/7525 detected. "
34 "Disabling irq balancing and affinity\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#ifdef CONFIG_IRQBALANCE
36 irqbalance_disable("");
37#endif
38 noirqdebug_setup("");
39#ifdef CONFIG_PROC_FS
40 no_irq_affinity = 1;
41#endif
42 }
43
Andrew Mortona86f34b2007-05-02 19:27:04 +020044 /* put back the original value for config space*/
Alan Coxda9bb1d2006-01-18 17:44:13 -080045 if (!(config & 0x2))
Andrew Mortona86f34b2007-05-02 19:27:04 +020046 pci_write_config_byte(dev, 0xf4, config);
Linus Torvalds1da177e2005-04-16 15:20:36 -070047}
Andrew Mortona86f34b2007-05-02 19:27:04 +020048DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance);
49DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance);
50DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#endif
Venki Pallipadid54bd572007-10-12 23:04:23 +020052
53#if defined(CONFIG_HPET_TIMER)
54unsigned long force_hpet_address;
55
Venki Pallipadibfe0c1c2007-10-12 23:04:24 +020056static enum {
57 NONE_FORCE_HPET_RESUME,
58 OLD_ICH_FORCE_HPET_RESUME,
59 ICH_FORCE_HPET_RESUME
60} force_hpet_resume_type;
61
Venki Pallipadid54bd572007-10-12 23:04:23 +020062static void __iomem *rcba_base;
63
Venki Pallipadibfe0c1c2007-10-12 23:04:24 +020064static void ich_force_hpet_resume(void)
Venki Pallipadid54bd572007-10-12 23:04:23 +020065{
66 u32 val;
67
68 if (!force_hpet_address)
69 return;
70
71 if (rcba_base == NULL)
72 BUG();
73
74 /* read the Function Disable register, dword mode only */
75 val = readl(rcba_base + 0x3404);
76 if (!(val & 0x80)) {
77 /* HPET disabled in HPTC. Trying to enable */
78 writel(val | 0x80, rcba_base + 0x3404);
79 }
80
81 val = readl(rcba_base + 0x3404);
82 if (!(val & 0x80))
83 BUG();
84 else
85 printk(KERN_DEBUG "Force enabled HPET at resume\n");
86
87 return;
88}
89
90static void ich_force_enable_hpet(struct pci_dev *dev)
91{
92 u32 val;
93 u32 uninitialized_var(rcba);
94 int err = 0;
95
96 if (hpet_address || force_hpet_address)
97 return;
98
99 pci_read_config_dword(dev, 0xF0, &rcba);
100 rcba &= 0xFFFFC000;
101 if (rcba == 0) {
102 printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n");
103 return;
104 }
105
106 /* use bits 31:14, 16 kB aligned */
107 rcba_base = ioremap_nocache(rcba, 0x4000);
108 if (rcba_base == NULL) {
109 printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n");
110 return;
111 }
112
113 /* read the Function Disable register, dword mode only */
114 val = readl(rcba_base + 0x3404);
115
116 if (val & 0x80) {
117 /* HPET is enabled in HPTC. Just not reported by BIOS */
118 val = val & 0x3;
119 force_hpet_address = 0xFED00000 | (val << 12);
120 printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
121 force_hpet_address);
122 iounmap(rcba_base);
123 return;
124 }
125
126 /* HPET disabled in HPTC. Trying to enable */
127 writel(val | 0x80, rcba_base + 0x3404);
128
129 val = readl(rcba_base + 0x3404);
130 if (!(val & 0x80)) {
131 err = 1;
132 } else {
133 val = val & 0x3;
134 force_hpet_address = 0xFED00000 | (val << 12);
135 }
136
137 if (err) {
138 force_hpet_address = 0;
139 iounmap(rcba_base);
140 printk(KERN_DEBUG "Failed to force enable HPET\n");
141 } else {
Venki Pallipadibfe0c1c2007-10-12 23:04:24 +0200142 force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
Venki Pallipadid54bd572007-10-12 23:04:23 +0200143 printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
144 force_hpet_address);
145 }
146}
147
148DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
149 ich_force_enable_hpet);
150DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1,
151 ich_force_enable_hpet);
152DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,
153 ich_force_enable_hpet);
154DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
155 ich_force_enable_hpet);
156DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1,
157 ich_force_enable_hpet);
Venki Pallipadibfe0c1c2007-10-12 23:04:24 +0200158
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
Venki Pallipadid54bd572007-10-12 23:04:23 +0200252#endif