[PATCH] fix x86 early quirk probing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux