=== modified file 'grub-core/bus/pci.c'
--- grub-core/bus/pci.c	2010-06-30 00:30:05 +0000
+++ grub-core/bus/pci.c	2011-01-03 00:05:27 +0000
@@ -20,6 +20,7 @@
 #include <grub/dl.h>
 #include <grub/pci.h>
 #include <grub/mm.h>
+#include <grub/misc.h>
 
 /* FIXME: correctly support 64-bit architectures.  */
 /* #if GRUB_TARGET_SIZEOF_VOID_P == 4 */
@@ -78,9 +79,18 @@ grub_pci_iterate (grub_pci_iteratefunc_t
   grub_pci_address_t addr;
   grub_pci_id_t id;
   grub_uint32_t hdr;
+  grub_uint8_t bus_present[(GRUB_PCI_NUM_BUS + 7) / 8];
+
+  grub_memset (bus_present, 0, sizeof (bus_present));
+  bus_present[0] = 1; /* bus 0 is always enabled */
 
   for (dev.bus = 0; dev.bus < GRUB_PCI_NUM_BUS; dev.bus++)
     {
+      if (!(bus_present[dev.bus / 8] & (1 << (dev.bus % 8))))
+	continue;
+
+      grub_dprintf ("pci", "bus 0x%x\n", dev.bus);
+
       for (dev.device = 0; dev.device < GRUB_PCI_NUM_DEVICES; dev.device++)
 	{
 	  for (dev.function = 0; dev.function < 8; dev.function++)
@@ -90,7 +100,14 @@ grub_pci_iterate (grub_pci_iteratefunc_t
 
 	      /* Check if there is a device present.  */
 	      if (id >> 16 == 0xFFFF)
-		continue;
+		{
+		  if (dev.function == 0)
+		    /* Devices are required to implement function 0, so if
+		       it's missing then there is no device here.  */
+		    break;
+		  else
+		    continue;
+		}
 
 #ifdef GRUB_MACHINE_MIPS_YEELOONG
 	      /* Skip ghosts.  */
@@ -102,6 +119,37 @@ grub_pci_iterate (grub_pci_iteratefunc_t
 		continue;
 #endif
 
+	      /* On bus 0, look for PCI-to-PCI bridges and mark all buses
+	         within their ranges as present.  */
+	      if (dev.bus == 0)
+		{
+		  addr = grub_pci_make_address (dev, GRUB_PCI_REG_CACHELINE);
+		  hdr = grub_pci_read (addr);
+
+		  switch ((hdr >> 16) & 0x7F) {
+		    case GRUB_PCI_HEADER_PCI_BRIDGE:
+		    case GRUB_PCI_HEADER_CARDBUS_BRIDGE:
+		      {
+			grub_uint32_t bus_numbers;
+			grub_uint8_t secondary, subordinate, i;
+
+			addr = grub_pci_make_address
+			  (dev, GRUB_PCI_REG_SEC_LAT_TIMER);
+			bus_numbers = grub_pci_read (addr);
+			secondary = (bus_numbers >> 8) & 0xFF;
+			subordinate = (bus_numbers >> 16) & 0xFF;
+
+			grub_dprintf ("pci", "bridge range 0x%x-0x%x\n",
+				      secondary, subordinate);
+
+			for (i = secondary; i <= subordinate; i++)
+			  bus_present[i / 8] |= (1 << (i % 8));
+
+			break;
+		      }
+		  }
+		}
+
 	      if (hook (dev, id))
 		return;
 

=== modified file 'include/grub/pci.h'
--- include/grub/pci.h	2010-08-11 02:18:07 +0000
+++ include/grub/pci.h	2011-01-02 17:32:28 +0000
@@ -68,6 +68,24 @@
 #define  GRUB_PCI_REG_MIN_GNT      0x3e
 #define  GRUB_PCI_REG_MAX_LAT      0x3f
 
+/* Alternative register meanings if header type is 1 (PCI-to-PCI bridge).  */
+#define  GRUB_PCI_REG_SEC_LAT_TIMER     0x18
+#define  GRUB_PCI_REG_SUB_BUS_NUMBER    0x19
+#define  GRUB_PCI_REG_SEC_BUS_NUMBER    0x1a
+#define  GRUB_PCI_REG_PRI_BUS_NUMBER    0x1b
+#define  GRUB_PCI_REG_SEC_STATUS        0x1c
+#define  GRUB_PCI_REG_IO_LIMIT          0x1e
+#define  GRUB_PCI_REG_IO_BASE           0x1f
+#define  GRUB_PCI_REG_MEM_LIMIT         0x20
+#define  GRUB_PCI_REG_MEM_BASE          0x22
+#define  GRUB_PCI_REG_PF_MEM_LIMIT      0x24
+#define  GRUB_PCI_REG_PF_MEM_BASE       0x26
+#define  GRUB_PCI_REG_PF_MEM_BASE_HI    0x28
+#define  GRUB_PCI_REG_PF_MEM_LIMIT_HI   0x2c
+#define  GRUB_PCI_REG_IO_LIMIT_HI       0x30
+#define  GRUB_PCI_REG_IO_BASE_HI        0x32
+#define  GRUB_PCI_REG_BRIDGE_CONTROL    0x3c
+
 #define  GRUB_PCI_COMMAND_IO_ENABLED    0x0001
 #define  GRUB_PCI_COMMAND_MEM_ENABLED   0x0002
 #define  GRUB_PCI_COMMAND_BUS_MASTER    0x0004
@@ -82,6 +100,10 @@
 #define  GRUB_PCI_STATUS_DEVSEL_TIMING_MASK 0x0600
 #define  GRUB_PCI_CLASS_SUBCLASS_VGA  0x0300
 
+#define  GRUB_PCI_HEADER_GENERAL        0x0
+#define  GRUB_PCI_HEADER_PCI_BRIDGE     0x1
+#define  GRUB_PCI_HEADER_CARDBUS_BRIDGE 0x2
+
 #ifndef ASM_FILE
 typedef grub_uint32_t grub_pci_id_t;
 

