return 0;
}
+void bootdev_list_hunters(struct bootstd_priv *std)
+{
+ struct bootdev_hunter *orig, *start;
+ int n_ent, i;
+
+ orig = ll_entry_start(struct bootdev_hunter, bootdev_hunter);
+ n_ent = ll_entry_count(struct bootdev_hunter, bootdev_hunter);
+
+ /*
+ * workaround for strange bug in clang-12 which sees all the below data
+ * as zeroes. Any access of start seems to fix it, such as
+ *
+ * printf("%p", start);
+ *
+ * Use memcpy() to force the correct behaviour.
+ */
+ memcpy(&start, &orig, sizeof(orig));
+ printf("%4s %4s %-15s %s\n", "Prio", "Used", "Uclass", "Hunter");
+ printf("%4s %4s %-15s %s\n", "----", "----", "---------------", "---------------");
+ for (i = 0; i < n_ent; i++) {
+ struct bootdev_hunter *info = start + i;
+
+ printf("%4d %4s %-15s %s\n", info->prio,
+ std->hunters_used & BIT(i) ? "*" : "",
+ uclass_get_name(info->uclass),
+ info->drv ? info->drv->name : "(none)");
+ }
+
+ printf("(total hunters: %d)\n", n_ent);
+}
+
static int bootdev_post_bind(struct udevice *dev)
{
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
return 0;
}
+static int do_bootdev_hunt(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct bootstd_priv *priv;
+ const char *spec = NULL;
+ bool list = false;
+ int ret = 0;
+
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "-l"))
+ list = true;
+ else
+ spec = argv[1];
+ }
+
+ ret = bootstd_get_priv(&priv);
+ if (ret)
+ return ret;
+ if (list) {
+ bootdev_list_hunters(priv);
+ } else {
+ /* TODO: implement hunting */
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_SYS_LONGHELP
static char bootdev_help_text[] =
- "list [-p] - list all available bootdevs (-p to probe)\n"
- "bootdev select <bd> - select a bootdev by name | label | seq\n"
- "bootdev info [-p] - show information about a bootdev (-p to probe)";
+ "list [-p] - list all available bootdevs (-p to probe)\n"
+ "bootdev hunt [-l|<spec>] - use hunt drivers to find bootdevs\n"
+ "bootdev select <bd> - select a bootdev by name | label | seq\n"
+ "bootdev info [-p] - show information about a bootdev (-p to probe)";
#endif
U_BOOT_CMD_WITH_SUBCMDS(bootdev, "Boot devices", bootdev_help_text,
U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootdev_list),
+ U_BOOT_SUBCMD_MKENT(hunt, 2, 1, do_bootdev_hunt),
U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootdev_select),
U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootdev_info));
struct bootflow;
struct bootflow_iter;
+struct bootstd_priv;
struct udevice;
/**
BOOTDEVP_COUNT,
};
+struct bootdev_hunter;
+
+/**
+ * bootdev_hunter_func - function to probe for bootdevs of a given type
+ *
+ * This should hunt around for bootdevs of the given type, binding them as it
+ * finds them. This may involve bus enumeration, etc.
+ *
+ * @info: Info structure describing this hunter
+ * @show: true to show information from the hunter
+ * Returns: 0 if OK, -ve on error
+ */
+typedef int (*bootdev_hunter_func)(struct bootdev_hunter *info, bool show);
+
+/**
+ * struct bootdev_hunter - information about how to hunt for bootdevs
+ *
+ * @prio: Scanning priority of this hunter
+ * @uclass: Uclass ID for the media associated with this bootdev
+ * @drv: bootdev driver for the things found by this hunter
+ * @hunt: Function to call to hunt for bootdevs of this type (NULL if none)
+ *
+ * Some bootdevs are not visible until other devices are enumerated. For
+ * example, USB bootdevs only appear when the USB bus is enumerated.
+ *
+ * On the other hand, we don't always want to enumerate all the buses just to
+ * find the first valid bootdev. Ideally we want to work through them in
+ * priority order, so that the fastest bootdevs are discovered first.
+ *
+ * This struct holds information about the bootdev so we can determine the probe
+ * order and how to hunt for bootdevs of this type
+ */
+struct bootdev_hunter {
+ enum bootdev_prio_t prio;
+ enum uclass_id uclass;
+ struct driver *drv;
+ bootdev_hunter_func hunt;
+};
+
+/* declare a new bootdev hunter */
+#define BOOTDEV_HUNTER(__name) \
+ ll_entry_declare(struct bootdev_hunter, __name, bootdev_hunter)
+
+/* access a bootdev hunter by name */
+#define BOOTDEV_HUNTER_GET(__name) \
+ ll_entry_get(struct bootdev_hunter, __name, bootdev_hunter)
+
/**
* struct bootdev_uc_plat - uclass information about a bootdev
*
*/
int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp);
+/**
+ * bootdev_list_hunters() - List the available bootdev hunters
+ *
+ * These provide a way to find new bootdevs by enumerating buses, etc. This
+ * function lists the available hunters
+ *
+ * @std: Pointer to bootstd private info
+ */
+void bootdev_list_hunters(struct bootstd_priv *std);
+
#if CONFIG_IS_ENABLED(BOOTSTD)
/**
* bootdev_setup_for_dev() - Bind a new bootdev device (deprecated)
* @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated
* @vbe_bootmeth: Currently selected VBE bootmeth, NULL if none
* @theme: Node containing the theme information
+ * @hunters_used: Bitmask of used hunters, indexed by their position in the
+ * linker list. The bit is set if the hunter has been used already
*/
struct bootstd_priv {
const char **prefixes;
struct udevice **bootmeth_order;
struct udevice *vbe_bootmeth;
ofnode theme;
+ uint hunters_used;
};
/**
return 0;
}
BOOTSTD_TEST(bootdev_test_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
+/* Check listing hunters */
+static int bootdev_test_hunter(struct unit_test_state *uts)
+{
+ struct bootstd_priv *std;
+
+ /* get access to the used hunters */
+ ut_assertok(bootstd_get_priv(&std));
+
+ console_record_reset_enable();
+ bootdev_list_hunters(std);
+ ut_assert_nextline("Prio Used Uclass Hunter");
+ ut_assert_nextlinen("----");
+ ut_assert_nextline("(total hunters: 0)");
+ ut_assert_console_end();
+
+ return 0;
+}
+BOOTSTD_TEST(bootdev_test_hunter, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
+/* Check 'bootdev hunt' command */
+static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
+{
+ struct bootstd_priv *std;
+
+ /* get access to the used hunters */
+ ut_assertok(bootstd_get_priv(&std));
+
+ console_record_reset_enable();
+ ut_assertok(run_command("bootdev hunt -l", 0));
+ ut_assert_nextline("Prio Used Uclass Hunter");
+ ut_assert_nextlinen("----");
+ ut_assert_nextline("(total hunters: 0)");
+ ut_assert_console_end();
+
+ /* Scan all hunters */
+ ut_assertok(run_command("bootdev hunt", 0));
+ ut_assert_console_end();
+
+ /* List available hunters */
+ ut_assertok(run_command("bootdev hunt -l", 0));
+ ut_assert_nextlinen("Prio");
+ ut_assert_nextlinen("----");
+ ut_assert_nextline("(total hunters: 0)");
+ ut_assert_console_end();
+
+ ut_asserteq(0, std->hunters_used);
+
+ return 0;
+}
+BOOTSTD_TEST(bootdev_test_cmd_hunt, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
+ UT_TESTF_ETH_BOOTDEV);