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 <sjg@chromium.org>
This commit is contained in:
Simon Glass 2024-11-15 16:19:12 -07:00 committed by Tom Rini
parent 6a3eb84b18
commit 49867e8045
7 changed files with 51 additions and 77 deletions

View File

@ -32,41 +32,17 @@ enum {
BOOT_TARGETS_MAX_LEN = 100, 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) int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp)
{ {
struct bootstd_priv *std = bootstd_try_priv(); struct bootstd_priv *std;
struct bootflow *bflow; 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) if (!bflow)
return -ENOENT; return -ENOENT;
*bflowp = bflow; *bflowp = bflow;
@ -76,10 +52,15 @@ int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp)
int bootdev_next_bootflow(struct bootflow **bflowp) int bootdev_next_bootflow(struct bootflow **bflowp)
{ {
struct bootstd_priv *std = bootstd_try_priv(); struct bootstd_priv *std;
struct bootflow *bflow; 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) if (!bflow)
return -ENOENT; return -ENOENT;
*bflowp = bflow; *bflowp = bflow;

View File

@ -55,11 +55,10 @@ int bootflow_first_glob(struct bootflow **bflowp)
if (ret) if (ret)
return ret; return ret;
if (list_empty(&std->glob_head)) if (!std->bootflows.count)
return -ENOENT; return -ENOENT;
*bflowp = list_first_entry(&std->glob_head, struct bootflow, *bflowp = alist_getw(&std->bootflows, 0, struct bootflow);
glob_node);
return 0; return 0;
} }
@ -67,20 +66,16 @@ int bootflow_first_glob(struct bootflow **bflowp)
int bootflow_next_glob(struct bootflow **bflowp) int bootflow_next_glob(struct bootflow **bflowp)
{ {
struct bootstd_priv *std; struct bootstd_priv *std;
struct bootflow *bflow = *bflowp;
int ret; int ret;
ret = bootstd_get_priv(&std); ret = bootstd_get_priv(&std);
if (ret) if (ret)
return ret; return ret;
*bflowp = NULL; *bflowp = alist_nextw(&std->bootflows, *bflowp);
if (!*bflowp)
if (list_is_last(&bflow->glob_node, &std->glob_head))
return -ENOENT; return -ENOENT;
*bflowp = list_entry(bflow->glob_node.next, struct bootflow, glob_node);
return 0; return 0;
} }
@ -476,10 +471,7 @@ void bootflow_free(struct bootflow *bflow)
void bootflow_remove(struct bootflow *bflow) void bootflow_remove(struct bootflow *bflow)
{ {
list_del(&bflow->glob_node);
bootflow_free(bflow); bootflow_free(bflow);
free(bflow);
} }
#if CONFIG_IS_ENABLED(BOOTSTD_FULL) #if CONFIG_IS_ENABLED(BOOTSTD_FULL)

View File

@ -6,6 +6,7 @@
* Written by Simon Glass <sjg@chromium.org> * Written by Simon Glass <sjg@chromium.org>
*/ */
#include <alist.h>
#include <bootflow.h> #include <bootflow.h>
#include <bootstd.h> #include <bootstd.h>
#include <dm.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) 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, alist_for_each(bflow, &priv->bootflows)
glob_node);
bootflow_remove(bflow); bootflow_remove(bflow);
} alist_empty(&priv->bootflows);
} }
void bootstd_clear_glob(void) void bootstd_clear_glob(void)
@ -64,36 +63,37 @@ void bootstd_clear_glob(void)
int bootstd_add_bootflow(struct bootflow *bflow) int bootstd_add_bootflow(struct bootflow *bflow)
{ {
struct bootstd_priv *std; struct bootstd_priv *std;
struct bootflow *new;
int ret; int ret;
ret = bootstd_get_priv(&std); ret = bootstd_get_priv(&std);
if (ret) if (ret)
return ret; return ret;
new = malloc(sizeof(*bflow)); ret = std->bootflows.count;
if (!new) bflow = alist_add(&std->bootflows, *bflow);
return log_msg_ret("bflow", -ENOMEM); if (!bflow)
memcpy(new, bflow, sizeof(*bflow)); return log_msg_ret("bf2", -ENOMEM);
list_add_tail(&new->glob_node, &std->glob_head); return ret;
return 0;
} }
int bootstd_clear_bootflows_for_bootdev(struct udevice *dev) int bootstd_clear_bootflows_for_bootdev(struct udevice *dev)
{ {
struct bootstd_priv *std = bootstd_try_priv(); struct bootstd_priv *std = bootstd_try_priv();
struct bootflow *from, *to;
if (std) { /* if bootstd does not exist we cannot have any bootflows */
struct bootflow *bflow; if (!std)
struct list_head *pos; return 0;
list_for_each(pos, &std->glob_head) { /* Drop any bootflows that mention this dev */
bflow = list_entry(pos, struct bootflow, glob_node); alist_for_each_filter(from, to, &std->bootflows) {
bootflow_remove(bflow); if (from->dev == dev)
} bootflow_remove(from);
else
*to++ = *from;
} }
alist_update_end(&std->bootflows, to);
return 0; return 0;
} }
@ -165,7 +165,7 @@ static int bootstd_probe(struct udevice *dev)
{ {
struct bootstd_priv *std = dev_get_priv(dev); struct bootstd_priv *std = dev_get_priv(dev);
INIT_LIST_HEAD(&std->glob_head); alist_init_struct(&std->bootflows, struct bootflow);
return 0; return 0;
} }

View File

@ -81,7 +81,7 @@ static int do_bootdev_info(struct cmd_tbl *cmdtp, int flag, int argc,
dev = priv->cur_bootdev; 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; num_valid = 0;
for (ret = bootdev_first_bootflow(dev, &bflow), i = 0; for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
!ret; !ret;

View File

@ -208,7 +208,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
if (!ret) if (!ret)
num_valid++; num_valid++;
ret = bootstd_add_bootflow(&bflow); ret = bootstd_add_bootflow(&bflow);
if (ret) { if (ret < 0) {
printf("Out of memory\n"); printf("Out of memory\n");
return CMD_RET_FAILURE; return CMD_RET_FAILURE;
} }

View File

@ -56,11 +56,8 @@ enum bootflow_flags_t {
/** /**
* struct bootflow - information about a bootflow * 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 * @dev: Bootdev device which produced this bootflow, NULL for flows created by
* BOOTMETHF_GLOBAL bootmeths * BOOTMETHF_GLOBAL bootmeths
* @blk: Block device which contains this bootflow, NULL if this is a network * @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 * @bootmeth_priv: Private data for the bootmeth
*/ */
struct bootflow { struct bootflow {
struct list_head glob_node;
struct udevice *dev; struct udevice *dev;
struct udevice *blk; struct udevice *blk;
int part; 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 * 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 * @bflow: Bootflow to remove
*/ */

View File

@ -9,6 +9,7 @@
#ifndef __bootstd_h #ifndef __bootstd_h
#define __bootstd_h #define __bootstd_h
#include <alist.h>
#include <dm/ofnode_decl.h> #include <dm/ofnode_decl.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/types.h> #include <linux/types.h>
@ -30,7 +31,8 @@ struct udevice;
* terminated) * terminated)
* @cur_bootdev: Currently selected bootdev (for commands) * @cur_bootdev: Currently selected bootdev (for commands)
* @cur_bootflow: Currently selected bootflow (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_count: Number of bootmeth devices in @bootmeth_order
* @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated * @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated
* @vbe_bootmeth: Currently selected VBE bootmeth, NULL if none * @vbe_bootmeth: Currently selected VBE bootmeth, NULL if none
@ -44,7 +46,7 @@ struct bootstd_priv {
const char **env_order; const char **env_order;
struct udevice *cur_bootdev; struct udevice *cur_bootdev;
struct bootflow *cur_bootflow; struct bootflow *cur_bootflow;
struct list_head glob_head; struct alist bootflows;
int bootmeth_count; int bootmeth_count;
struct udevice **bootmeth_order; struct udevice **bootmeth_order;
struct udevice *vbe_bootmeth; struct udevice *vbe_bootmeth;
@ -135,7 +137,7 @@ int bootstd_prog_boot(void);
* since this function takes over ownership of these. This functions makes * since this function takes over ownership of these. This functions makes
* a copy of @bflow itself (without allocating its fields again), so the * a copy of @bflow itself (without allocating its fields again), so the
* caller must dispose of the memory used by the @bflow pointer itself * 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); int bootstd_add_bootflow(struct bootflow *bflow);