[U-Boot] [PATCH 6/8] dm: core: look up drivers more efficiently
Masahiro Yamada
yamada.m at jp.panasonic.com
Mon Nov 17 09:19:43 CET 2014
The DM initialization function, dm_init_and_scan() is called twice,
before and after relocation.
In the first DM scan, only some of drivers are bound for the use in
pre-reloc code (mostly UART drivers). In the second scan, all the
drivers are bound.
In the current implementation, all the drivers are collected into a
single array. Every driver is searched through the array and then
the DM_FLAG_PRE_RELOC flag is checked. In the pre-reloc DM scan,
drivers without DM_FLAG_PRE_RELOC are ignored. This algorithm works
enough, but is not very efficient.
This commit aims to split drivers into two contiguous arrays,
pre-reloc drivers and post-reloc drivers. The drivers in the former
group are declared with U_BOOT_DRIVER_F. The others are declared with
U_BOOT_DRIVER.
pre post
_____________________ reloc reloc
.u_boot_list_2_driver1_1 | | || ||
| | || ||
| | || ||
| U_BOOT_DRIVER_F | || ||
| (driver1) | || ||
| | _||_ ||
| | \ / ||
.u_boot_list_2_driver1_3 |___________________| \/ ||
.u_boot_list_2_driver2_1 | | ||
| | ||
| | ||
| U_BOOT_DRIVER | ||
| (driver2) | ||
| | _||_
| | \ /
.u_boot_list_2_driver2_3 |___________________| \/
The pre-reloc DM scan searches drivers from .u_boot_list_2_driver1_1
to .u_boot_list_2_driver1_3. The post-reloc scan searches ones from
.u_boot_list_2_driver1_1 and .u_boot_list_2_driver2_3.
Signed-off-by: Masahiro Yamada <yamada.m at jp.panasonic.com>
---
doc/driver-model/README.txt | 2 +-
drivers/core/device.c | 4 +---
drivers/core/lists.c | 22 +++++++++++++---------
drivers/core/root.c | 3 ++-
include/dm/device.h | 8 ++++++--
include/dm/lists.h | 16 ++++++++++++----
include/dm/root.h | 16 ++++++++--------
7 files changed, 43 insertions(+), 28 deletions(-)
diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index 0278dda..e4114d5 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -739,7 +739,7 @@ Pre-Relocation Support
----------------------
For pre-relocation we simply call the driver model init function. Only
-drivers marked with DM_FLAG_PRE_RELOC or the device tree
+drivers declared with U_BOOT_DRIVER_F or the device tree
'u-boot,dm-pre-reloc' flag are initialised prior to relocation. This helps
to reduce the driver model overhead.
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 49faa29..6fd2f07 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -157,11 +157,9 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
{
struct driver *drv;
- drv = lists_driver_lookup_name(info->name);
+ drv = __lists_driver_lookup_name(info->name, pre_reloc_only);
if (!drv)
return -ENOENT;
- if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
- return -EPERM;
return device_bind(parent, drv, info->name, (void *)info->platdata,
-1, devp);
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 1476715..5b61ab5 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -18,10 +18,13 @@
#include <fdtdec.h>
#include <linux/compiler.h>
-struct driver *lists_driver_lookup_name(const char *name)
+#define driver_entry_end(p) (p) ? ll_entry_end(struct driver, driver1) : \
+ ll_entry_end(struct driver, driver2);
+
+struct driver *__lists_driver_lookup_name(const char *name, bool pre_reloc_only)
{
- struct driver *entry = ll_entry_start(struct driver, driver);
- struct driver *end = ll_entry_end(struct driver, driver);
+ struct driver *entry = ll_entry_start(struct driver, driver1);
+ struct driver *end = driver_entry_end(pre_reloc_only);
for (; entry < end; entry++) {
if (!strcmp(name, entry->name))
@@ -58,11 +61,12 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
for (; entry < end; entry++) {
ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev);
- if (ret && ret != -EPERM) {
+
+ if (!pre_reloc_only && ret == -ENOENT)
dm_warn("No match for driver '%s'\n", entry->name);
- if (!result || ret != -ENOENT)
- result = ret;
- }
+
+ if (!result || ret != -ENOENT)
+ result = ret;
}
return result;
@@ -105,8 +109,8 @@ static int driver_check_compatible(const void *blob, int offset,
int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
struct udevice **devp)
{
- struct driver *entry = ll_entry_start(struct driver, driver);
- struct driver *end = ll_entry_end(struct driver, driver);
+ struct driver *entry = ll_entry_start(struct driver, driver1);
+ struct driver *end = ll_entry_end(struct driver, driver2);
struct udevice *dev;
bool found = false;
const char *name;
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 47b3acf..02970c8 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -70,7 +70,8 @@ int dm_scan_platdata(bool pre_reloc_only)
ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only);
if (ret == -ENOENT) {
- dm_warn("Some drivers were not found\n");
+ if (!pre_reloc_only)
+ dm_warn("Some drivers were not found\n");
ret = 0;
}
diff --git a/include/dm/device.h b/include/dm/device.h
index 9ce95a8..a2fd7b6 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -167,9 +167,13 @@ struct driver {
uint32_t flags;
};
-/* Declare a new U-Boot driver */
+/* Drivers bound before and after relocation */
+#define U_BOOT_DRIVER_F(__name) \
+ ll_entry_declare(struct driver, __name, driver1)
+
+/* Drivers bound only after relocation */
#define U_BOOT_DRIVER(__name) \
- ll_entry_declare(struct driver, __name, driver)
+ ll_entry_declare(struct driver, __name, driver2)
/**
* dev_get_platdata() - Get the platform data for a device
diff --git a/include/dm/lists.h b/include/dm/lists.h
index 704e33e..fbd428d 100644
--- a/include/dm/lists.h
+++ b/include/dm/lists.h
@@ -13,15 +13,23 @@
#include <dm/uclass-id.h>
/**
- * lists_driver_lookup_name() - Return u_boot_driver corresponding to name
+ * __lists_driver_lookup_name() - Return u_boot_driver corresponding to name
*
* This function returns a pointer to a driver given its name. This is used
* for binding a driver given its name and platdata.
*
* @name: Name of driver to look up
+ * @pre_reloc_only: If true, searches in drivers declared with U_BOOT_DRIVER_F.
+ * If false searches in all drivers.
* @return pointer to driver, or NULL if not found
*/
-struct driver *lists_driver_lookup_name(const char *name);
+struct driver *__lists_driver_lookup_name(const char *name,
+ bool pre_reloc_only);
+
+static inline struct driver *lists_driver_lookup_name(const char *name)
+{
+ return __lists_driver_lookup_name(name, false);
+}
/**
* lists_uclass_lookup() - Return uclass_driver based on ID of the class
@@ -39,8 +47,8 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id);
* each one. The devices will have @parent as their parent.
*
* @parent: parent device (root)
- * @early_only: If true, bind only drivers with the DM_INIT_F flag. If false
- * bind all drivers.
+ * @pre_reloc_only: If true, bind only drivers declared with U_BOOT_DRIVER_F.
+ * If false bind all drivers.
*/
int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only);
diff --git a/include/dm/root.h b/include/dm/root.h
index c7f0c1d..61d1cd8 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -26,8 +26,8 @@ struct udevice *dm_root(void);
*
* This scans all available platdata and creates drivers for each
*
- * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
- * flag. If false bind all drivers.
+ * @pre_reloc_only: If true, bind only drivers declared with U_BOOT_DRIVER_F.
+ * If false bind all drivers.
* @return 0 if OK, -ve on error
*/
int dm_scan_platdata(bool pre_reloc_only);
@@ -54,8 +54,8 @@ int dm_scan_fdt(const void *blob, bool pre_reloc_only);
* @parent: Parent device for the devices that will be created
* @blob: Pointer to device tree blob
* @offset: Offset of node to scan
- * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
- * flag. If false bind all drivers.
+ * @pre_reloc_only: If true, bind only drivers declared with U_BOOT_DRIVER_F.
+ * If false bind all drivers.
* @return 0 if OK, -ve on error
*/
int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
@@ -69,8 +69,8 @@ int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
* programmaticaly. They should do this by calling device_bind() on each
* device.
*
- * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
- * flag. If false bind all drivers.
+ * @pre_reloc_only: If true, bind only drivers declared with U_BOOT_DRIVER_F.
+ * If false bind all drivers.
*/
int dm_scan_other(bool pre_reloc_only);
@@ -81,8 +81,8 @@ int dm_scan_other(bool pre_reloc_only);
* then scans and binds available devices from platform data and the FDT.
* This calls dm_init() to set up Driver Model structures.
*
- * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
- * flag. If false bind all drivers.
+ * @pre_reloc_only: If true, bind only drivers declared with U_BOOT_DRIVER_F.
+ * If false bind all drivers.
* @return 0 if OK, -ve on error
*/
int dm_init_and_scan(bool pre_reloc_only);
--
1.9.1
More information about the U-Boot
mailing list