linux/arch
Ingo Molnar f5dbb55b99 fix BIOS PCI config cycle buglet causing ACPI boot regression
I figured out another ACPI related regression today.

randconfig testing triggered an early boot-time hang on a laptop of mine
(32-bit x86, config attached) - the screen was scrolling ACPI AML
exceptions [with no serial port and no early debugging available].

v2.6.24 works fine on that laptop with the same .config, so after a few
hours of bisection (had to restart it 3 times - other regressions
interacted), it honed in on this commit:

| 10270d4838 is first bad commit
|
| Author: Linus Torvalds <torvalds@woody.linux-foundation.org>
| Date:   Wed Feb 13 09:56:14 2008 -0800
|
|     acpi: fix acpi_os_read_pci_configuration() misuse of raw_pci_read()

reverting this commit ontop of -rc5 gave a correctly booting kernel.

But this commit fixes a real bug so the real question is, why did it
break the bootup?

After quite some head-scratching, the following change stood out:

-                               pci_id->bus = tu8;
+                               pci_id->bus = val;

pci_id->bus is defined as u16:

   struct acpi_pci_id {
           u16 segment;
           u16 bus;
   ...

and 'tu8' changed from u8 to u32. So previously we'd unconditionally
mask the return value of acpi_os_read_pci_configuration()
(raw_pci_read()) to 8 bits, but now we just trust whatever comes back
from the PCI access routines and only crop it to 16 bits.

But if the high 8 bits of that result contains any noise then we'll
write that into ACPI's PCI ID descriptor and confuse the heck out of the
rest of ACPI.

So lets check the PCI-BIOS code on that theory. We have this codepath
for 8-bit accesses (arch/x86/pci/pcbios.c:pci_bios_read()):

        switch (len) {
        case 1:
                __asm__("lcall *(%%esi); cld\n\t"
                        "jc 1f\n\t"
                        "xor %%ah, %%ah\n"
                        "1:"
                        : "=c" (*value),
                          "=a" (result)
                        : "1" (PCIBIOS_READ_CONFIG_BYTE),
                          "b" (bx),
                          "D" ((long)reg),
                          "S" (&pci_indirect));

Aha! The "=a" output constraint puts the full 32 bits of EAX into
*value. But if the BIOS's routines set any of the high bits to nonzero,
we'll return a value with more set in it than intended.

The other, more common PCI access methods (v1 and v2 PCI reads) clear
out the high bits already, for example pci_conf1_read() does:

        switch (len) {
        case 1:
                *value = inb(0xCFC + (reg & 3));

which explicitly converts the return byte up to 32 bits and zero-extends
it.

So zero-extending the result in the PCI-BIOS read routine fixes the
regression on my laptop. ( It might fix some other long-standing issues
we had with PCI-BIOS during the past decade ... ) Both 8-bit and 16-bit
accesses were buggy.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-03-10 18:09:05 -07:00
..
alpha alpha: fix iommu-related boot panic 2008-03-09 10:05:15 -07:00
arm Kprobes: indicate kretprobe support in Kconfig 2008-03-04 16:35:11 -08:00
avr32 avr32: Fix OCD refcounting bug 2008-02-27 14:23:53 +01:00
blackfin [Blackfin] arch: fix atomic and32/xor32 comments and ENDPROC markings 2008-03-03 17:44:14 -07:00
cris cris: correct usage of __user for copy to and from user space in lib/usercopy and uaccess.h 2008-03-04 16:35:16 -08:00
frv FRV: Change the timerfd syscalls to be the same as i386 2008-02-20 19:58:16 -08:00
h8300 h8300: defconfig update 2008-02-23 17:12:16 -08:00
ia64 [IA64] kprobes arch consolidation build fix 2008-03-06 09:49:01 -08:00
m32r ide: introduce HAVE_IDE 2008-02-09 10:46:40 +01:00
m68k m68k{,nommu}: Wire up new timerfd syscalls 2008-03-04 08:04:11 -08:00
m68knommu m68k{,nommu}: Wire up new timerfd syscalls 2008-03-04 08:04:11 -08:00
mips [MIPS] BCM47XX: Use new SSB SPROM data structure 2008-02-19 17:01:34 +00:00
mn10300 MN10300: define HZ as a config option 2008-02-23 17:12:13 -08:00
parisc Introduce path_put() 2008-02-14 21:13:33 -08:00
powerpc Kprobes: indicate kretprobe support in Kconfig 2008-03-04 16:35:11 -08:00
ppc [POWERPC] PPC440EP Interrupt Triggering and Level Settings 2008-02-15 21:33:02 -06:00
s390 [S390] incorrect reipl nss name. 2008-03-05 12:37:20 +01:00
sh sh: Fix up the sh64 build. 2008-03-06 17:23:15 +09:00
sparc [SPARC]: Fix link errors with gcc-4.3 2008-03-03 15:01:05 -08:00
sparc64 Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6 2008-03-04 20:20:32 -08:00
um sched: add declaration of sched_tail to sched.h 2008-02-25 16:34:17 +01:00
v850 ide: introduce HAVE_IDE 2008-02-09 10:46:40 +01:00
x86 fix BIOS PCI config cycle buglet causing ACPI boot regression 2008-03-10 18:09:05 -07:00
xtensa [XTENSA] Allow debugger to modify the WINDOWBASE register. 2008-02-13 17:45:36 -08:00
.gitignore arch: Ignore arch/i386 and arch/x86_64 2008-01-19 21:29:39 -08:00
Kconfig Kprobes: indicate kretprobe support in Kconfig 2008-03-04 16:35:11 -08:00