diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 84 |
1 files changed, 36 insertions, 48 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index ae24e2b82c5a..9513ea78e6c1 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -175,57 +175,57 @@ static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no | |||
175 | return mpic->fixups[source_no].base != NULL; | 175 | return mpic->fixups[source_no].base != NULL; |
176 | } | 176 | } |
177 | 177 | ||
178 | |||
178 | static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) | 179 | static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) |
179 | { | 180 | { |
180 | struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; | 181 | struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; |
181 | u32 tmp; | ||
182 | 182 | ||
183 | spin_lock(&mpic->fixup_lock); | 183 | spin_lock(&mpic->fixup_lock); |
184 | writeb(0x11 + 2 * fixup->irq, fixup->base); | 184 | writeb(0x11 + 2 * fixup->irq, fixup->base + 2); |
185 | tmp = readl(fixup->base + 2); | 185 | writel(fixup->data, fixup->base + 4); |
186 | writel(tmp | 0x80000000ul, fixup->base + 2); | ||
187 | /* config writes shouldn't be posted but let's be safe ... */ | ||
188 | (void)readl(fixup->base + 2); | ||
189 | spin_unlock(&mpic->fixup_lock); | 186 | spin_unlock(&mpic->fixup_lock); |
190 | } | 187 | } |
191 | 188 | ||
192 | 189 | ||
193 | static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase) | 190 | static void __init mpic_scan_ioapic(struct mpic *mpic, u8 __iomem *devbase) |
194 | { | 191 | { |
195 | int i, irq; | 192 | int i, irq, n; |
196 | u32 tmp; | 193 | u32 tmp; |
194 | u8 pos; | ||
197 | 195 | ||
198 | printk(KERN_INFO "mpic: - Workarounds on AMD 8111 @ %p\n", devbase); | 196 | for (pos = readb(devbase + 0x34); pos; pos = readb(devbase + pos + 1)) { |
197 | u8 id = readb(devbase + pos); | ||
199 | 198 | ||
200 | for (i=0; i < 24; i++) { | 199 | if (id == 0x08) { |
201 | writeb(0x10 + 2*i, devbase + 0xf2); | 200 | id = readb(devbase + pos + 3); |
202 | tmp = readl(devbase + 0xf4); | 201 | if (id == 0x80) |
203 | if ((tmp & 0x1) || !(tmp & 0x20)) | 202 | break; |
204 | continue; | 203 | } |
205 | irq = (tmp >> 16) & 0xff; | ||
206 | mpic->fixups[irq].irq = i; | ||
207 | mpic->fixups[irq].base = devbase + 0xf2; | ||
208 | } | 204 | } |
209 | } | 205 | if (pos == 0) |
210 | 206 | return; | |
211 | static void __init mpic_amd8131_read_irq(struct mpic *mpic, u8 __iomem *devbase) | 207 | |
212 | { | 208 | printk(KERN_INFO "mpic: - Workarounds @ %p, pos = 0x%02x\n", devbase, pos); |
213 | int i, irq; | ||
214 | u32 tmp; | ||
215 | 209 | ||
216 | printk(KERN_INFO "mpic: - Workarounds on AMD 8131 @ %p\n", devbase); | 210 | devbase += pos; |
217 | 211 | ||
218 | for (i=0; i < 4; i++) { | 212 | writeb(0x01, devbase + 2); |
219 | writeb(0x10 + 2*i, devbase + 0xba); | 213 | n = (readl(devbase + 4) >> 16) & 0xff; |
220 | tmp = readl(devbase + 0xbc); | 214 | |
221 | if ((tmp & 0x1) || !(tmp & 0x20)) | 215 | for (i = 0; i <= n; i++) { |
216 | writeb(0x10 + 2 * i, devbase + 2); | ||
217 | tmp = readl(devbase + 4); | ||
218 | if ((tmp & 0x21) != 0x20) | ||
222 | continue; | 219 | continue; |
223 | irq = (tmp >> 16) & 0xff; | 220 | irq = (tmp >> 16) & 0xff; |
224 | mpic->fixups[irq].irq = i; | 221 | mpic->fixups[irq].irq = i; |
225 | mpic->fixups[irq].base = devbase + 0xba; | 222 | mpic->fixups[irq].base = devbase; |
223 | writeb(0x11 + 2 * i, devbase + 2); | ||
224 | mpic->fixups[irq].data = readl(devbase + 4) | 0x80000000; | ||
226 | } | 225 | } |
227 | } | 226 | } |
228 | 227 | ||
228 | |||
229 | static void __init mpic_scan_ioapics(struct mpic *mpic) | 229 | static void __init mpic_scan_ioapics(struct mpic *mpic) |
230 | { | 230 | { |
231 | unsigned int devfn; | 231 | unsigned int devfn; |
@@ -241,21 +241,19 @@ static void __init mpic_scan_ioapics(struct mpic *mpic) | |||
241 | /* Init spinlock */ | 241 | /* Init spinlock */ |
242 | spin_lock_init(&mpic->fixup_lock); | 242 | spin_lock_init(&mpic->fixup_lock); |
243 | 243 | ||
244 | /* Map u3 config space. We assume all IO-APICs are on the primary bus | 244 | /* Map U3 config space. We assume all IO-APICs are on the primary bus |
245 | * and slot will never be above "0xf" so we only need to map 32k | 245 | * so we only need to map 64kB. |
246 | */ | 246 | */ |
247 | cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000); | 247 | cfgspace = ioremap(0xf2000000, 0x10000); |
248 | BUG_ON(cfgspace == NULL); | 248 | BUG_ON(cfgspace == NULL); |
249 | 249 | ||
250 | /* Now we scan all slots. We do a very quick scan, we read the header type, | 250 | /* Now we scan all slots. We do a very quick scan, we read the header type, |
251 | * vendor ID and device ID only, that's plenty enough | 251 | * vendor ID and device ID only, that's plenty enough |
252 | */ | 252 | */ |
253 | for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) { | 253 | for (devfn = 0; devfn < 0x100; devfn++) { |
254 | u8 __iomem *devbase = cfgspace + (devfn << 8); | 254 | u8 __iomem *devbase = cfgspace + (devfn << 8); |
255 | u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); | 255 | u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); |
256 | u32 l = readl(devbase + PCI_VENDOR_ID); | 256 | u32 l = readl(devbase + PCI_VENDOR_ID); |
257 | u16 vendor_id, device_id; | ||
258 | int multifunc = 0; | ||
259 | 257 | ||
260 | DBG("devfn %x, l: %x\n", devfn, l); | 258 | DBG("devfn %x, l: %x\n", devfn, l); |
261 | 259 | ||
@@ -264,21 +262,11 @@ static void __init mpic_scan_ioapics(struct mpic *mpic) | |||
264 | l == 0x0000ffff || l == 0xffff0000) | 262 | l == 0x0000ffff || l == 0xffff0000) |
265 | goto next; | 263 | goto next; |
266 | 264 | ||
267 | /* Check if it's a multifunction device (only really used | 265 | mpic_scan_ioapic(mpic, devbase); |
268 | * to function 0 though | 266 | |
269 | */ | ||
270 | multifunc = !!(hdr_type & 0x80); | ||
271 | vendor_id = l & 0xffff; | ||
272 | device_id = (l >> 16) & 0xffff; | ||
273 | |||
274 | /* If a known device, go to fixup setup code */ | ||
275 | if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460) | ||
276 | mpic_amd8111_read_irq(mpic, devbase); | ||
277 | if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450) | ||
278 | mpic_amd8131_read_irq(mpic, devbase); | ||
279 | next: | 267 | next: |
280 | /* next device, if function 0 */ | 268 | /* next device, if function 0 */ |
281 | if ((PCI_FUNC(devfn) == 0) && !multifunc) | 269 | if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0) |
282 | devfn += 7; | 270 | devfn += 7; |
283 | } | 271 | } |
284 | } | 272 | } |