x86, pci: detect end_bus_number according to acpi/e820 reserved, v2

Jack Howarth reported that 2.6.26-rc9-git9 doesn't boot on MacBookPro2.

the reason is a faulty BIOS update that reportes faulty resources.

Nevertheless it's possible for Linux to be more resolent about this
situation (and similar situations) and work around this bug, by
cross-checking the mmconf range against the e820 table and ACPI resources.

Change the mconf bus range from [0,0xff] to to [0, 0x3f]
to match range [0xf0000000, 0xf4000000) in e820 tables.

[ v2, yhlu.kernel@gmail.com:
  x86, pci: detect end_bus_number according to acpi/e820 reserved - fix ]

Reported-by: Jack Howarth <howarth@bromo.msbb.uc.edu>
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Cc: jbarnes@virtuousgeek.org
Cc: Jack Howarth <howarth@bromo.msbb.uc.edu>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Yinghai Lu 2008-07-18 13:22:36 -07:00 committed by Ingo Molnar
parent 0679c2f47d
commit a83fe32fa6

View File

@ -293,7 +293,7 @@ static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
return AE_OK;
}
static int __init is_acpi_reserved(unsigned long start, unsigned long end)
static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
{
struct resource mcfg_res;
@ -310,6 +310,41 @@ static int __init is_acpi_reserved(unsigned long start, unsigned long end)
return mcfg_res.flags;
}
typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
static int __init is_mmconf_reserved(check_reserved_t is_reserved,
u64 addr, u64 size, int i,
typeof(pci_mmcfg_config[0]) *cfg, int with_e820)
{
u64 old_size = size;
int valid = 0;
while (!is_reserved(addr, addr + size - 1, E820_RESERVED)) {
size >>= 1;
if (size < (16UL<<20))
break;
}
if (size >= (16UL<<20) || size == old_size) {
printk(KERN_NOTICE
"PCI: MCFG area at %Lx reserved in %s\n",
addr, with_e820?"E820":"ACPI motherboard resources");
valid = 1;
if (old_size != size) {
/* update end_bus_number */
cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1);
printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx "
"segment %hu buses %u - %u\n",
i, (unsigned long)cfg->address, cfg->pci_segment,
(unsigned int)cfg->start_bus_number,
(unsigned int)cfg->end_bus_number);
}
}
return valid;
}
static void __init pci_mmcfg_reject_broken(int early)
{
typeof(pci_mmcfg_config[0]) *cfg;
@ -324,21 +359,22 @@ static void __init pci_mmcfg_reject_broken(int early)
for (i = 0; i < pci_mmcfg_config_num; i++) {
int valid = 0;
u32 size = (cfg->end_bus_number + 1) << 20;
u64 addr, size;
cfg = &pci_mmcfg_config[i];
addr = cfg->start_bus_number;
addr <<= 20;
addr += cfg->address;
size = cfg->end_bus_number + 1 - cfg->start_bus_number;
size <<= 20;
printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
"segment %hu buses %u - %u\n",
i, (unsigned long)cfg->address, cfg->pci_segment,
(unsigned int)cfg->start_bus_number,
(unsigned int)cfg->end_bus_number);
if (!early &&
is_acpi_reserved(cfg->address, cfg->address + size - 1)) {
printk(KERN_NOTICE "PCI: MCFG area at %Lx reserved "
"in ACPI motherboard resources\n",
cfg->address);
valid = 1;
}
if (!early)
valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0);
if (valid)
continue;
@ -347,16 +383,11 @@ static void __init pci_mmcfg_reject_broken(int early)
printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
" reserved in ACPI motherboard resources\n",
cfg->address);
/* Don't try to do this check unless configuration
type 1 is available. how about type 2 ?*/
if (raw_pci_ops && e820_all_mapped(cfg->address,
cfg->address + size - 1,
E820_RESERVED)) {
printk(KERN_NOTICE
"PCI: MCFG area at %Lx reserved in E820\n",
cfg->address);
valid = 1;
}
if (raw_pci_ops)
valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1);
if (!valid)
goto reject;