From 49867e804543f64ca216653c3905d8022c31fc84 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 15 Nov 2024 16:19:12 -0700 Subject: [PATCH] bootstd: Move the bootflow list into an alist 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 --- boot/bootdev-uclass.c | 47 +++++++++++++------------------------------ boot/bootflow.c | 16 ++++----------- boot/bootstd-uclass.c | 42 +++++++++++++++++++------------------- cmd/bootdev.c | 2 +- cmd/bootflow.c | 2 +- include/bootflow.h | 11 +++++----- include/bootstd.h | 8 +++++--- 7 files changed, 51 insertions(+), 77 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; - bflow = bootdev_next_bootflow_(std, dev, NULL); + ret = bootstd_get_priv(&std); + if (ret) + return log_msg_ret("bff", ret); + + 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; - bflow = bootdev_next_bootflow_(std, (*bflowp)->dev, *bflowp); + ret = bootstd_get_priv(&std); + if (ret) + return log_msg_ret("bff", ret); + + bflow = alist_nextw(&std->bootflows, *bflowp); if (!bflow) return -ENOENT; *bflowp = bflow; diff --git a/boot/bootflow.c b/boot/bootflow.c index 804809dc100..7ce04fd92cd 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..8c0fd4e63c3 100644 --- a/boot/bootstd-uclass.c +++ b/boot/bootstd-uclass.c @@ -6,6 +6,7 @@ * Written by Simon Glass */ +#include #include #include #include @@ -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,36 +63,37 @@ 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)); + ret = std->bootflows.count; + bflow = alist_add(&std->bootflows, *bflow); + if (!bflow) + return log_msg_ret("bf2", -ENOMEM); - list_add_tail(&new->glob_node, &std->glob_head); - - return 0; + return ret; } 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 +165,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/cmd/bootflow.c b/cmd/bootflow.c index 1c1146ce11e..f88995a478f 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -208,7 +208,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, if (!ret) num_valid++; ret = bootstd_add_bootflow(&bflow); - if (ret) { + if (ret < 0) { printf("Out of memory\n"); return CMD_RET_FAILURE; } 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..3398e48e88b 100644 --- a/include/bootstd.h +++ b/include/bootstd.h @@ -9,6 +9,7 @@ #ifndef __bootstd_h #define __bootstd_h +#include #include #include #include @@ -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; @@ -135,7 +137,7 @@ int bootstd_prog_boot(void); * since this function takes over ownership of these. This functions makes * a copy of @bflow itself (without allocating its fields again), so the * caller must dispose of the memory used by the @bflow pointer itself - * Return: 0 if OK, -ENOMEM if out of memory + * Return: element number in the list, if OK, -ENOMEM if out of memory */ int bootstd_add_bootflow(struct bootflow *bflow);