dm: pci: Support selected device/driver binding before relocation
authorBin Meng <bmeng.cn@gmail.com>
Thu, 20 Aug 2015 13:40:17 +0000 (06:40 -0700)
committerSimon Glass <sjg@chromium.org>
Wed, 26 Aug 2015 14:54:11 +0000 (07:54 -0700)
On some platforms pci devices behind bridge need to be probed (eg:
a pci uart on recent x86 chipset) before relocation. But we won't
bind all devices found during the enumeration. Only devices whose
driver with DM_FLAG_PRE_RELOC set will be bound. Any other generic
devices except bridges won't be bound.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Simon Glass <sjg@chromium.org>
drivers/pci/pci-uclass.c

index 7d41d56fd488fbb1c11144e90bca9cc5592179e3..416027438f1850f518a71be359caed40bf707e00 100644 (file)
@@ -461,6 +461,7 @@ static int pci_find_and_bind_driver(struct udevice *parent,
        int n_ents;
        int ret;
        char name[30], *str;
+       bool bridge;
 
        *devp = NULL;
 
@@ -480,6 +481,17 @@ static int pci_find_and_bind_driver(struct udevice *parent,
                                continue;
 
                        drv = entry->driver;
+
+                       /*
+                        * In the pre-relocation phase, we only bind devices
+                        * whose driver has the DM_FLAG_PRE_RELOC set, to save
+                        * precious memory space as on some platforms as that
+                        * space is pretty limited (ie: using Cache As RAM).
+                        */
+                       if (!(gd->flags & GD_FLG_RELOC) &&
+                           !(drv->flags & DM_FLAG_PRE_RELOC))
+                               return 0;
+
                        /*
                         * We could pass the descriptor to the driver as
                         * platdata (instead of NULL) and allow its bind()
@@ -499,14 +511,23 @@ static int pci_find_and_bind_driver(struct udevice *parent,
                }
        }
 
+       bridge = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI;
+       /*
+        * In the pre-relocation phase, we only bind bridge devices to save
+        * precious memory space as on some platforms as that space is pretty
+        * limited (ie: using Cache As RAM).
+        */
+       if (!(gd->flags & GD_FLG_RELOC) && !bridge)
+               return 0;
+
        /* Bind a generic driver so that the device can be used */
        sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(bdf),
                PCI_FUNC(bdf));
        str = strdup(name);
        if (!str)
                return -ENOMEM;
-       drv = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI ? "pci_bridge_drv" :
-                       "pci_generic_drv";
+       drv = bridge ? "pci_bridge_drv" : "pci_generic_drv";
+
        ret = device_bind_driver(parent, drv, str, devp);
        if (ret) {
                debug("%s: Failed to bind generic driver: %d", __func__, ret);
@@ -589,11 +610,13 @@ int pci_bind_bus_devices(struct udevice *bus)
                        return ret;
 
                /* Update the platform data */
-               pplat = dev_get_parent_platdata(dev);
-               pplat->devfn = PCI_MASK_BUS(bdf);
-               pplat->vendor = vendor;
-               pplat->device = device;
-               pplat->class = class;
+               if (dev) {
+                       pplat = dev_get_parent_platdata(dev);
+                       pplat->devfn = PCI_MASK_BUS(bdf);
+                       pplat->vendor = vendor;
+                       pplat->device = device;
+                       pplat->class = class;
+               }
        }
 
        return 0;
@@ -717,10 +740,6 @@ static int pci_uclass_post_probe(struct udevice *bus)
 {
        int ret;
 
-       /* Don't scan buses before relocation */
-       if (!(gd->flags & GD_FLG_RELOC))
-               return 0;
-
        debug("%s: probing bus %d\n", __func__, bus->seq);
        ret = pci_bind_bus_devices(bus);
        if (ret)