Add fastboot_block_set_target() so an OEM command can point the generic block fastboot backend at a different interface/device at runtime, without requiring a rebuild. Falls back to the existing build-time CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME/ CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID defaults when no override is set.
Expose this to fastboot clients via a new "oem set-block-target <interface> [device]" command, gated behind CONFIG_FASTBOOT_CMD_OEM_SET_BLOCK_TARGET (depends on CONFIG_FASTBOOT_FLASH_BLOCK). This is needed to target storage devices, such as SPI-NOR exposed through the MTD block uclass, that aren't known until runtime or that coexist with another default block interface on the same board. To: [email protected] To: [email protected] Cc: Mattijs Korpershoek <[email protected]> Cc: Tom Rini <[email protected]> Cc: Quentin Schulz <[email protected]> Cc: Ilias Apalodimas <[email protected]> Cc: Dmitrii Merkurev <[email protected]> Cc: Balaji Selvanathan <[email protected]> Cc: Adrian Freihofer <[email protected]> Cc: Heiko Schocher <[email protected]> Cc: Neil Armstrong <[email protected]> Signed-off-by: Vandhiadevan Karunamoorthy <[email protected]> --- This series lets a fastboot client redirect the generic block fastboot backend (CONFIG_FASTBOOT_FLASH_BLOCK) to a different interface/device at runtime, instead of being fixed to the build-time CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME / CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID defaults. This is useful for storage devices that aren't known until runtime, or that coexist with another default block interface on the same board -- for example, SPI-NOR exposed through the MTD block uclass (see the companion "mtd: spi: Expose SPI-NOR as a GPT-capable MTD block device" series). The patch adds fastboot_block_set_target() to the generic block backend, plus a new "oem set-block-target <interface> [device]" fastboot command (gated behind CONFIG_FASTBOOT_CMD_OEM_SET_BLOCK_TARGET, which depends on CONFIG_FASTBOOT_FLASH_BLOCK) that lets a client invoke it. --- Depends on: [PATCH v6 0/8] arm: snapdragon: Add snagboot support for Lemans-EVK Link: https://lore.kernel.org/u-boot/[email protected]/ Depends on: [PATCH v2 0/4] fastboot: block: Add GPT/MBR and device selection Link: https://lore.kernel.org/u-boot/[email protected]/ --- drivers/fastboot/Kconfig | 11 +++++++ drivers/fastboot/fb_block.c | 75 ++++++++++++++++++++++++++++++++++++------- drivers/fastboot/fb_command.c | 51 +++++++++++++++++++++++++++++ include/fastboot.h | 1 + include/fb_block.h | 9 ++++++ 5 files changed, 136 insertions(+), 11 deletions(-) diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index a4539844d89..c7e0509eaad 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -225,6 +225,17 @@ config FASTBOOT_FLASH_BLOCK_DEVICE_ID Device identifiers are numbered starting from 0 and the most common case is to use the first controller on the system. +config FASTBOOT_CMD_OEM_SET_BLOCK_TARGET + bool "Enable the 'oem set-block-target' command" + depends on FASTBOOT_FLASH_BLOCK + help + Add support for the "oem set-block-target" command from a client. + This allows switching the block interface (e.g. scsi, mtd) and + device number used by the fastboot "flash"/"erase" commands at + runtime, instead of relying solely on the + CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME / + CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID build-time defaults. + config FASTBOOT_GPT_NAME string "Target name for updating GPT" depends on (FASTBOOT_FLASH_MMC || FASTBOOT_FLASH_BLOCK) && EFI_PARTITION diff --git a/drivers/fastboot/fb_block.c b/drivers/fastboot/fb_block.c index a8c74e35d0d..d3e5f6ed1f3 100644 --- a/drivers/fastboot/fb_block.c +++ b/drivers/fastboot/fb_block.c @@ -125,6 +125,66 @@ static lbaint_t fb_block_sparse_reserve(struct sparse_storage *info, return blkcnt; } +/** + * block_interface_override - runtime-set block interface name, empty if unset + */ +static char block_interface_override[16]; +/** + * block_device_override - runtime-set block device number, -1 if unset + */ +static int block_device_override = -1; + +/** + * fb_block_interface() - Resolve the block interface name to use + * + * Returns the runtime override set via fastboot_block_set_target() if one + * is active, otherwise falls back to the build-time config default. + */ +static const char *fb_block_interface(void) +{ + if (!IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK)) + return NULL; + + if (block_interface_override[0]) + return block_interface_override; + + return config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK, + CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME, NULL); +} + +/** + * fb_block_device() - Resolve the block device number to use + * + * Returns the runtime override set via fastboot_block_set_target() if one + * is active, otherwise falls back to the build-time config default. + */ +static int fb_block_device(void) +{ + if (!IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK)) + return -1; + + if (block_device_override >= 0) + return block_device_override; + + return config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK, + CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID, -1); +} + +int fastboot_block_set_target(const char *interface, int device) +{ + if (interface) { + if (strlen(interface) >= sizeof(block_interface_override)) + return -EINVAL; + strlcpy(block_interface_override, interface, + sizeof(block_interface_override)); + } + + if (device >= 0) + block_device_override = device; + + return 0; +} + /** * parse_device_partition() - Parse and validate device:partition format * @part_name: Input string in format "N:partition" or "partition" @@ -140,8 +200,7 @@ static int parse_device_partition(const char *part_name, int *device, { const char *colon_pos; - *device = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK, - CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID, -1); + *device = fb_block_device(); /* Check for colon in partition name */ colon_pos = strchr(part_name, ':'); @@ -190,9 +249,7 @@ int fastboot_block_get_part_info(const char *part_name, char *response) { int ret; - const char *interface = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK, - CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME, - NULL); + const char *interface = fb_block_interface(); int device; const char *partition_name; @@ -385,9 +442,7 @@ void fastboot_block_flash_write(const char *part_name, void *download_buffer, #if CONFIG_IS_ENABLED(EFI_PARTITION) if (is_partition_table_name(part_name, CONFIG_FASTBOOT_GPT_NAME)) { int device; - const char *interface = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK, - CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME, - NULL); + const char *interface = fb_block_interface(); parse_device_partition(part_name, &device, NULL); fastboot_flash_gpt_partition_table(interface, device, @@ -399,9 +454,7 @@ void fastboot_block_flash_write(const char *part_name, void *download_buffer, #if CONFIG_IS_ENABLED(DOS_PARTITION) if (is_partition_table_name(part_name, CONFIG_FASTBOOT_MBR_NAME)) { int device; - const char *interface = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK, - CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME, - NULL); + const char *interface = fb_block_interface(); parse_device_partition(part_name, &device, NULL); fastboot_flash_mbr_partition_table(interface, device, diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index 18d86988f4c..235fae74fee 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -45,6 +45,7 @@ static void oem_partconf(char *, char *); static void oem_bootbus(char *, char *); static void oem_console(char *, char *); static void oem_board(char *, char *); +static void oem_set_block_target(char *, char *); static void run_ucmd(char *, char *); static void run_acmd(char *, char *); @@ -120,6 +121,11 @@ static const struct { .command = "oem board", .dispatch = CONFIG_IS_ENABLED(FASTBOOT_OEM_BOARD, (oem_board), (NULL)) }, + [FASTBOOT_COMMAND_OEM_SET_BLOCK_TARGET] = { + .command = "oem set-block-target", + .dispatch = CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_SET_BLOCK_TARGET, + (oem_set_block_target), (NULL)) + }, [FASTBOOT_COMMAND_UCMD] = { .command = "UCmd", .dispatch = CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT, (run_ucmd), (NULL)) @@ -589,3 +595,48 @@ static void __maybe_unused oem_board(char *cmd_parameter, char *response) { fastboot_oem_board(cmd_parameter, (void *)fastboot_buf_addr, image_size, response); } + +/** + * oem_set_block_target() - Execute the OEM set-block-target command + * + * @cmd_parameter: Pointer to "<interface> [device]" command parameter + * @response: Pointer to fastboot response buffer + * + * Switches the block interface (e.g. "scsi", "mtd") and, optionally, + * device number used by the fastboot block backend at runtime. + */ +static void __maybe_unused oem_set_block_target(char *cmd_parameter, char *response) +{ + char interface[16] = { 0 }; + int device = -1; + char *space; + + if (!cmd_parameter) { + fastboot_fail("Expected command parameter", response); + return; + } + + space = strchr(cmd_parameter, ' '); + if (space) { + size_t len = space - cmd_parameter; + + if (len >= sizeof(interface)) { + fastboot_fail("interface name too long", response); + return; + } + memcpy(interface, cmd_parameter, len); + interface[len] = '\0'; + device = simple_strtoul(space + 1, NULL, 10); + } else { + if (strlen(cmd_parameter) >= sizeof(interface)) { + fastboot_fail("interface name too long", response); + return; + } + strlcpy(interface, cmd_parameter, sizeof(interface)); + } + + if (fastboot_block_set_target(interface, device)) + fastboot_fail("invalid interface name", response); + else + fastboot_okay(NULL, response); +} diff --git a/include/fastboot.h b/include/fastboot.h index b106d617749..13dcdf919bc 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -51,6 +51,7 @@ enum { FASTBOOT_COMMAND_OEM_RUN, FASTBOOT_COMMAND_OEM_CONSOLE, FASTBOOT_COMMAND_OEM_BOARD, + FASTBOOT_COMMAND_OEM_SET_BLOCK_TARGET, FASTBOOT_COMMAND_ACMD, FASTBOOT_COMMAND_UCMD, FASTBOOT_COMMAND_COUNT diff --git a/include/fb_block.h b/include/fb_block.h index 189c708e2f0..fd981d95316 100644 --- a/include/fb_block.h +++ b/include/fb_block.h @@ -102,4 +102,13 @@ void fastboot_block_write_sparse_image(struct blk_desc *dev_desc, struct disk_pa void fastboot_block_flash_write(const char *part_name, void *download_buffer, u32 download_bytes, char *response); +/** + * fastboot_block_set_target() - Override block interface/device at runtime + * + * @interface: New interface name (e.g. "scsi", "mtd"), or NULL to leave unchanged + * @device: New device number, or -1 to leave unchanged + * Return: 0 on success, -EINVAL if interface name too long + */ +int fastboot_block_set_target(const char *interface, int device); + #endif // _FB_BLOCK_H_ --- base-commit: 4d3823469724bca19ba4ed3a5a38fc8e951775e2 change-id: 20260824-series2-fastboot-block-target-c8e9418babdf Best regards, -- Vandhiadevan Karunamoorthy <[email protected]>
