@@ -218,8 +218,13 @@ static int extlinux_read_bootflow(struct udevice *dev, struct bootflow *bflow)
static int extlinux_local_boot(struct udevice *dev, struct bootflow *bflow)
{
struct extlinux_priv *priv = dev_get_priv(dev);
+ struct pxe_context *ctx;
- return extlinux_boot(dev, bflow, &priv->ctx, extlinux_getfile, true,
+ ctx = extlinux_get_ctx(priv, bflow);
+ if (!ctx)
+ return log_msg_ret("ctx", -ENOMEM);
+
+ return extlinux_boot(dev, bflow, ctx, extlinux_getfile, true,
bflow->fname, false);
}
@@ -227,19 +232,37 @@ static int extlinux_local_boot(struct udevice *dev, struct bootflow *bflow)
static int extlinux_local_read_all(struct udevice *dev, struct bootflow *bflow)
{
struct extlinux_priv *priv = dev_get_priv(dev);
+ struct pxe_context *ctx;
+
+ ctx = extlinux_get_ctx(priv, bflow);
+ if (!ctx)
+ return log_msg_ret("ctx", -ENOMEM);
- return extlinux_read_all(dev, bflow, &priv->ctx, extlinux_getfile,
+ return extlinux_read_all(dev, bflow, ctx, extlinux_getfile,
true, bflow->fname);
}
#endif
+int extlinux_bootmeth_probe(struct udevice *dev)
+{
+ struct extlinux_priv *priv = dev_get_priv(dev);
+
+ alist_init_struct(&priv->ctxs, struct pxe_context);
+
+ return 0;
+}
+
int extlinux_bootmeth_remove(struct udevice *dev)
{
struct extlinux_priv *priv = dev_get_priv(dev);
+ struct pxe_context *ctx;
- if (priv->ctx.cfg)
- pxe_menu_uninit(priv->ctx.cfg);
- pxe_destroy_ctx(&priv->ctx);
+ alist_for_each(ctx, &priv->ctxs) {
+ if (ctx->cfg)
+ pxe_menu_uninit(ctx->cfg);
+ pxe_destroy_ctx(ctx);
+ }
+ alist_uninit(&priv->ctxs);
return 0;
}
@@ -278,6 +301,7 @@ U_BOOT_DRIVER(bootmeth_1extlinux) = {
.of_match = extlinux_bootmeth_ids,
.ops = &extlinux_bootmeth_ops,
.bind = extlinux_bootmeth_bind,
+ .probe = extlinux_bootmeth_probe,
.remove = extlinux_bootmeth_remove,
.plat_auto = sizeof(struct extlinux_plat),
.priv_auto = sizeof(struct extlinux_priv),
@@ -146,8 +146,13 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow,
static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow)
{
struct extlinux_priv *priv = dev_get_priv(dev);
+ struct pxe_context *ctx;
- return extlinux_boot(dev, bflow, &priv->ctx, extlinux_pxe_getfile,
+ ctx = extlinux_get_ctx(priv, bflow);
+ if (!ctx)
+ return log_msg_ret("ctx", -ENOMEM);
+
+ return extlinux_boot(dev, bflow, ctx, extlinux_pxe_getfile,
false, bflow->subdir, false);
}
@@ -155,8 +160,13 @@ static int extlinux_pxe_boot(struct udevice *dev, struct bootflow *bflow)
static int extlinux_pxe_read_all(struct udevice *dev, struct bootflow *bflow)
{
struct extlinux_priv *priv = dev_get_priv(dev);
+ struct pxe_context *ctx;
+
+ ctx = extlinux_get_ctx(priv, bflow);
+ if (!ctx)
+ return log_msg_ret("ctx", -ENOMEM);
- return extlinux_read_all(dev, bflow, &priv->ctx,
+ return extlinux_read_all(dev, bflow, ctx,
extlinux_pxe_getfile, false, bflow->subdir);
}
#endif
@@ -193,6 +203,7 @@ U_BOOT_DRIVER(bootmeth_zpxe) = {
.of_match = extlinux_bootmeth_pxe_ids,
.ops = &extlinux_bootmeth_pxe_ops,
.bind = extlinux_bootmeth_pxe_bind,
+ .probe = extlinux_bootmeth_probe,
.remove = extlinux_bootmeth_remove,
.plat_auto = sizeof(struct extlinux_plat),
.priv_auto = sizeof(struct extlinux_priv),
@@ -75,6 +75,28 @@ int extlinux_set_property(struct udevice *dev, const char *property,
return 0;
}
+struct pxe_context *extlinux_get_ctx(struct extlinux_priv *priv,
+ struct bootflow *bflow)
+{
+ struct pxe_context *ctx;
+
+ /* Return existing context if one was already allocated */
+ if (bflow->bootmeth_id >= 0) {
+ ctx = alist_getw(&priv->ctxs, bflow->bootmeth_id,
+ struct pxe_context);
+ if (ctx)
+ return ctx;
+ }
+
+ /* Allocate a new one */
+ ctx = alist_add_placeholder(&priv->ctxs);
+ if (!ctx)
+ return NULL;
+ bflow->bootmeth_id = priv->ctxs.count - 1;
+
+ return ctx;
+}
+
static int extlinux_setup(struct udevice *dev, struct bootflow *bflow,
pxe_getfile_func getfile, bool allow_abs_path,
const char *bootfile, struct pxe_context *ctx)
@@ -288,5 +288,5 @@ U_BOOT_DRIVER(vbe_abrec_os) = {
.bind = bootmeth_vbe_abrec_os_bind,
.probe = bootmeth_vbe_abrec_os_probe,
.priv_auto = sizeof(struct abrec_priv),
- .plat_auto = sizeof(struct extlinux_plat)
+ .plat_auto = sizeof(struct extlinux_plat),
};
@@ -36,22 +36,48 @@ struct extlinux_plat {
/**
* struct extlinux_priv - private runtime data for this bootmeth
*
- * @ctx: holds the PXE context
+ * @ctxs: list of parsed PXE contexts (alist of struct pxe_context), one per
+ * extlinux.conf file found during scanning
*/
struct extlinux_priv {
- struct pxe_context ctx;
+ struct alist ctxs;
};
+/**
+ * extlinux_bootmeth_probe() - Probe function for extlinux-based bootmeths
+ *
+ * Initialises the context alist in extlinux_priv. Must be called from the
+ * probe function of any driver that uses extlinux_priv.
+ *
+ * @dev: Bootmethod device
+ * Return: 0 if OK
+ */
+int extlinux_bootmeth_probe(struct udevice *dev);
+
/**
* extlinux_bootmeth_remove() - Remove function for extlinux-based bootmeths
*
- * Frees the PXE context. Shared by extlinux and PXE drivers.
+ * Frees all cached PXE contexts in the alist.
*
* @dev: Bootmethod device
* Return: 0 if OK
*/
int extlinux_bootmeth_remove(struct udevice *dev);
+/**
+ * extlinux_get_ctx() - Get or allocate a PXE context for a bootflow
+ *
+ * If bflow->bootmeth_id already points to a valid context (e.g. from a
+ * prior read_all), return it. Otherwise allocate a new context in the
+ * alist and store its index in bflow->bootmeth_id.
+ *
+ * @priv: Private data for this bootmeth
+ * @bflow: Bootflow to get context for
+ * Return: Context, or NULL on allocation failure
+ */
+struct pxe_context *extlinux_get_ctx(struct extlinux_priv *priv,
+ struct bootflow *bflow);
+
/**
* extlinux_set_property() - set an extlinux property
*