Use an alist for this data structure as it is somewhat simpler to
manage. This means that bootstd holds a simple list of bootflow structs
and can drop it at will, without chasing down lists.

Signed-off-by: Simon Glass <s...@chromium.org>
---

(no changes since v1)

 boot/bootdev-uclass.c | 47 +++++++++++++------------------------------
 boot/bootflow.c       | 16 ++++-----------
 boot/bootstd-uclass.c | 39 +++++++++++++++++------------------
 cmd/bootdev.c         |  2 +-
 include/bootflow.h    | 11 +++++-----
 include/bootstd.h     |  6 ++++--
 6 files changed, 47 insertions(+), 74 deletions(-)

diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c
index 81adfb4cfb7..a4e1d79ec9b 100644
--- a/boot/bootdev-uclass.c
+++ b/boot/bootdev-uclass.c
@@ -32,41 +32,17 @@ enum {
        BOOT_TARGETS_MAX_LEN    = 100,
 };
 
-struct bootflow *bootdev_next_bootflow_(struct bootstd_priv *std,
-                                       struct udevice *dev,
-                                       struct bootflow *prev)
-{
-       struct bootflow *bflow = prev;
-
-       if (bflow) {
-               if (list_is_last(&bflow->glob_node, &std->glob_head))
-                       return NULL;
-               bflow = list_entry(bflow->glob_node.next, struct bootflow,
-                                  glob_node);
-       } else {
-               if (list_empty(&std->glob_head))
-                       return NULL;
-
-               bflow = list_first_entry(&std->glob_head, struct bootflow,
-                                        glob_node);
-       }
-
-       while (bflow->dev != dev) {
-               if (list_is_last(&bflow->glob_node, &std->glob_head))
-                       return NULL;
-               bflow = list_entry(bflow->glob_node.next, struct bootflow,
-                                  glob_node);
-       }
-
-       return bflow;
-}
-
 int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp)
 {
-       struct bootstd_priv *std = bootstd_try_priv();
+       struct bootstd_priv *std;
        struct bootflow *bflow;
+       int ret;
+
+       ret = bootstd_get_priv(&std);
+       if (ret)
+               return log_msg_ret("bff", ret);
 
-       bflow = bootdev_next_bootflow_(std, dev, NULL);
+       bflow = alist_getw(&std->bootflows, 0, struct bootflow);
        if (!bflow)
                return -ENOENT;
        *bflowp = bflow;
@@ -76,10 +52,15 @@ int bootdev_first_bootflow(struct udevice *dev, struct 
bootflow **bflowp)
 
 int bootdev_next_bootflow(struct bootflow **bflowp)
 {
-       struct bootstd_priv *std = bootstd_try_priv();
+       struct bootstd_priv *std;
        struct bootflow *bflow;
+       int ret;
+
+       ret = bootstd_get_priv(&std);
+       if (ret)
+               return log_msg_ret("bff", ret);
 
-       bflow = bootdev_next_bootflow_(std, (*bflowp)->dev, *bflowp);
+       bflow = alist_nextw(&std->bootflows, *bflowp);
        if (!bflow)
                return -ENOENT;
        *bflowp = bflow;
diff --git a/boot/bootflow.c b/boot/bootflow.c
index ae59d1a4092..72b51ebd49b 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -55,11 +55,10 @@ int bootflow_first_glob(struct bootflow **bflowp)
        if (ret)
                return ret;
 
-       if (list_empty(&std->glob_head))
+       if (!std->bootflows.count)
                return -ENOENT;
 
-       *bflowp = list_first_entry(&std->glob_head, struct bootflow,
-                                  glob_node);
+       *bflowp = alist_getw(&std->bootflows, 0, struct bootflow);
 
        return 0;
 }
@@ -67,20 +66,16 @@ int bootflow_first_glob(struct bootflow **bflowp)
 int bootflow_next_glob(struct bootflow **bflowp)
 {
        struct bootstd_priv *std;
-       struct bootflow *bflow = *bflowp;
        int ret;
 
        ret = bootstd_get_priv(&std);
        if (ret)
                return ret;
 
-       *bflowp = NULL;
-
-       if (list_is_last(&bflow->glob_node, &std->glob_head))
+       *bflowp = alist_nextw(&std->bootflows, *bflowp);
+       if (!*bflowp)
                return -ENOENT;
 
-       *bflowp = list_entry(bflow->glob_node.next, struct bootflow, glob_node);
-
        return 0;
 }
 
@@ -476,10 +471,7 @@ void bootflow_free(struct bootflow *bflow)
 
 void bootflow_remove(struct bootflow *bflow)
 {
-       list_del(&bflow->glob_node);
-
        bootflow_free(bflow);
-       free(bflow);
 }
 
 #if CONFIG_IS_ENABLED(BOOTSTD_FULL)
diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c
index 91e90bdf43c..5675719ee84 100644
--- a/boot/bootstd-uclass.c
+++ b/boot/bootstd-uclass.c
@@ -6,6 +6,7 @@
  * Written by Simon Glass <s...@chromium.org>
  */
 
+#include <alist.h>
 #include <bootflow.h>
 #include <bootstd.h>
 #include <dm.h>
@@ -42,13 +43,11 @@ static int bootstd_of_to_plat(struct udevice *dev)
 
 static void bootstd_clear_glob_(struct bootstd_priv *priv)
 {
-       while (!list_empty(&priv->glob_head)) {
-               struct bootflow *bflow;
+       struct bootflow *bflow;
 
-               bflow = list_first_entry(&priv->glob_head, struct bootflow,
-                                        glob_node);
+       alist_for_each(bflow, &priv->bootflows)
                bootflow_remove(bflow);
-       }
+       alist_empty(&priv->bootflows);
 }
 
 void bootstd_clear_glob(void)
@@ -64,19 +63,15 @@ void bootstd_clear_glob(void)
 int bootstd_add_bootflow(struct bootflow *bflow)
 {
        struct bootstd_priv *std;
-       struct bootflow *new;
        int ret;
 
        ret = bootstd_get_priv(&std);
        if (ret)
                return ret;
 
-       new = malloc(sizeof(*bflow));
-       if (!new)
-               return log_msg_ret("bflow", -ENOMEM);
-       memcpy(new, bflow, sizeof(*bflow));
-
-       list_add_tail(&new->glob_node, &std->glob_head);
+       bflow = alist_add(&std->bootflows, *bflow);
+       if (!bflow)
+               return log_msg_ret("bf2", -ENOMEM);
 
        return 0;
 }
@@ -84,16 +79,20 @@ int bootstd_add_bootflow(struct bootflow *bflow)
 int bootstd_clear_bootflows_for_bootdev(struct udevice *dev)
 {
        struct bootstd_priv *std = bootstd_try_priv();
+       struct bootflow *from, *to;
 
-       if (std) {
-               struct bootflow *bflow;
-               struct list_head *pos;
+       /* if bootstd does not exist we cannot have any bootflows */
+       if (!std)
+               return 0;
 
-               list_for_each(pos, &std->glob_head) {
-                       bflow = list_entry(pos, struct bootflow, glob_node);
-                       bootflow_remove(bflow);
-               }
+       /* Drop any bootflows that mention this dev */
+       alist_for_each_filter(from, to, &std->bootflows) {
+               if (from->dev == dev)
+                       bootflow_remove(from);
+               else
+                       *to++ = *from;
        }
+       alist_update_end(&std->bootflows, to);
 
        return 0;
 }
@@ -165,7 +164,7 @@ static int bootstd_probe(struct udevice *dev)
 {
        struct bootstd_priv *std = dev_get_priv(dev);
 
-       INIT_LIST_HEAD(&std->glob_head);
+       alist_init_struct(&std->bootflows, struct bootflow);
 
        return 0;
 }
diff --git a/cmd/bootdev.c b/cmd/bootdev.c
index fa7285ba25e..4bc229e809a 100644
--- a/cmd/bootdev.c
+++ b/cmd/bootdev.c
@@ -81,7 +81,7 @@ static int do_bootdev_info(struct cmd_tbl *cmdtp, int flag, 
int argc,
 
        dev = priv->cur_bootdev;
 
-       /* Count the number of bootflows, including how many are valid*/
+       /* Count the number of bootflows, including how many are valid */
        num_valid = 0;
        for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
             !ret;
diff --git a/include/bootflow.h b/include/bootflow.h
index 64d1d6c3786..9b24fb5c3eb 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -56,11 +56,8 @@ enum bootflow_flags_t {
 /**
  * struct bootflow - information about a bootflow
  *
- * This is connected into a linked list:
+ * All bootflows are listed in bootstd's bootflow alist in struct bootstd_priv
  *
- *   glob_sibling - links all bootflows in all bootdevs
- *
- * @glob_node: Points to siblings in the global list (all bootdev)
  * @dev: Bootdev device which produced this bootflow, NULL for flows created by
  *      BOOTMETHF_GLOBAL bootmeths
  * @blk: Block device which contains this bootflow, NULL if this is a network
@@ -90,7 +87,6 @@ enum bootflow_flags_t {
  * @bootmeth_priv: Private data for the bootmeth
  */
 struct bootflow {
-       struct list_head glob_node;
        struct udevice *dev;
        struct udevice *blk;
        int part;
@@ -390,7 +386,10 @@ const char *bootflow_state_get_name(enum bootflow_state_t 
state);
 /**
  * bootflow_remove() - Remove a bootflow and free its memory
  *
- * This updates the linked lists containing the bootflow then frees it.
+ * This updates the 'global' linked list containing the bootflow, then frees 
it.
+ * It does not remove it from bootflows alist in struct bootstd_priv
+ *
+ * This does not free bflow itself, since this is assumed to be in an alist
  *
  * @bflow: Bootflow to remove
  */
diff --git a/include/bootstd.h b/include/bootstd.h
index 8aff536e3cb..c5b902372c3 100644
--- a/include/bootstd.h
+++ b/include/bootstd.h
@@ -9,6 +9,7 @@
 #ifndef __bootstd_h
 #define __bootstd_h
 
+#include <alist.h>
 #include <dm/ofnode_decl.h>
 #include <linux/list.h>
 #include <linux/types.h>
@@ -30,7 +31,8 @@ struct udevice;
  *     terminated)
  * @cur_bootdev: Currently selected bootdev (for commands)
  * @cur_bootflow: Currently selected bootflow (for commands)
- * @glob_head: Head for the global list of all bootflows across all bootdevs
+ * @bootflows: (struct bootflow) Global list of all bootflows across all
+ *     bootdevs
  * @bootmeth_count: Number of bootmeth devices in @bootmeth_order
  * @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated
  * @vbe_bootmeth: Currently selected VBE bootmeth, NULL if none
@@ -44,7 +46,7 @@ struct bootstd_priv {
        const char **env_order;
        struct udevice *cur_bootdev;
        struct bootflow *cur_bootflow;
-       struct list_head glob_head;
+       struct alist bootflows;
        int bootmeth_count;
        struct udevice **bootmeth_order;
        struct udevice *vbe_bootmeth;
-- 
2.34.1

Reply via email to