On x86, we do early PCI probing to apply some quirks for chipset bugs. However, in a recent cleanup (7bcbc78dea92fdf0947fa48e248da3c993a5690f) a change was introduced that causes us to probe all subfunctions of even single function devices: commit 7bcbc78dea92fdf0947fa48e248da3c993a5690f Author: Neil Horman <nhorman@xxxxxxxxxxxxx> Date: Wed Jan 30 13:31:26 2008 +0100 x86: clean up arch/x86/kernel/early-quirks.c clean up checkpatch errors. No code changed. text data bss dec hex filename 705 120 0 825 339 early-quirks.o.before 705 120 0 825 339 early-quirks.o.after ... +static void check_dev_quirk(int num, int slot, int func) +{ + u16 class; + u16 vendor; + u16 device; + u8 type; + int i; + + class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE); + + if (class == 0xffff) + return; + + vendor = read_pci_config_16(num, slot, func, PCI_VENDOR_ID); + + device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID); + + for (i = 0; early_qrk[i].f != NULL; i++) { + if (((early_qrk[i].vendor == PCI_ANY_ID) || + (early_qrk[i].vendor == vendor)) && + ((early_qrk[i].device == PCI_ANY_ID) || + (early_qrk[i].device == device)) && + (!((early_qrk[i].class ^ class) & + early_qrk[i].class_mask))) { + if ((early_qrk[i].flags & + QFLAG_DONE) != QFLAG_DONE) + early_qrk[i].f(num, slot, func); + early_qrk[i].flags |= QFLAG_APPLIED; + } + } + + type = read_pci_config_byte(num, slot, func, + PCI_HEADER_TYPE); + if (!(type & 0x80)) + return; +} + void __init early_quirks(void) { int num, slot, func; @@ -138,45 +178,8 @@ void __init early_quirks(void) return; /* Poor man's PCI discovery */ - for (num = 0; num < 32; num++) { - for (slot = 0; slot < 32; slot++) { - for (func = 0; func < 8; func++) { - u16 class; - u16 vendor; - u16 device; - u8 type; - int i; - - class = read_pci_config_16(num,slot,func, - PCI_CLASS_REVISION); - if (class == 0xffff) - break; - - vendor = read_pci_config_16(num, slot, func, - PCI_VENDOR_ID); - - device = read_pci_config_16(num, slot, func, - PCI_DEVICE_ID); - - for(i=0;early_qrk[i].f != NULL;i++) { - if (((early_qrk[i].vendor == PCI_ANY_ID) - (early_qrk[i].vendor == vendor)) && - ((early_qrk[i].device == PCI_ANY_ID) - (early_qrk[i].device == device)) && - (!((early_qrk[i].class ^ class) & - early_qrk[i].class_mask))) { - if ((early_qrk[i].flags & QFLAG_ - early_qrk[i].f(num, slot - early_qrk[i].flags |= QFLAG_APPL - - } - } - - type = read_pci_config_byte(num, slot, func, - PCI_HEADER_TYPE); - if (!(type & 0x80)) - break; - } - } - } + for (num = 0; num < 32; num++) + for (slot = 0; slot < 32; slot++) + for (func = 0; func < 8; func++) + check_dev_quirk(num, slot, func); } ... So even though the code size remained the same, this was a pretty clear change in behavior (note how the old code would break out of the inner loop to the middle loop while the new code just has a "return" right before the new function returns anyway. This patch fixes things up by adding a return code that allows early_quirks to skip sub-function probing (rather than pulling check_dev_quirk back in, which would make things messier). Any thoughts here? Thanks, Jesse diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 9f51e1e..8566fea 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -133,7 +133,18 @@ static struct chipset early_qrk[] __initdata = { {} }; -static void __init check_dev_quirk(int num, int slot, int func) +/** + * check_dev_quirk - apply early quirks to a given PCI device + * @num: bus number + * @slot: slot number + * @func: PCI function + * + * Check the vendor & device ID against the early quirks table. + * + * If the device is single function, let early_quirks() know so we don't + * poke at this device again. + */ +static int __init check_dev_quirk(int num, int slot, int func) { u16 class; u16 vendor; @@ -144,7 +155,7 @@ static void __init check_dev_quirk(int num, int slot, int func) class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE); if (class == 0xffff) - return; + return -1; /* no class, treat as single function */ vendor = read_pci_config_16(num, slot, func, PCI_VENDOR_ID); @@ -167,7 +178,9 @@ static void __init check_dev_quirk(int num, int slot, int func) type = read_pci_config_byte(num, slot, func, PCI_HEADER_TYPE); if (!(type & 0x80)) - return; + return -1; + + return 0; } void __init early_quirks(void) @@ -180,6 +193,9 @@ void __init early_quirks(void) /* Poor man's PCI discovery */ for (num = 0; num < 32; num++) for (slot = 0; slot < 32; slot++) - for (func = 0; func < 8; func++) - check_dev_quirk(num, slot, func); + for (func = 0; func < 8; func++) { + /* Only probe function 0 on single fn devices */ + if (check_dev_quirk(num, slot, func)) + break; + } } -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html