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 on boards where one interface (e.g. scsi) is the default block target but another (e.g. mtd) is also present, so fastboot can dynamically switch between the two interfaces at runtime instead of being locked to a single build-time default. 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 on boards where one interface (e.g. scsi) is the default block target but another (e.g. mtd) is also present, so fastboot can dynamically switch between the two interfaces at runtime instead of being locked to a single build-time default. 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]/ --- Changes in v2: - Drop the redundant IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK) guards from fb_block_interface() and fb_block_device(). - Retain config_opt_enabled() to keep fb_block.c compile-safe when built for CONFIG_FASTBOOT_FLASH_MMC without CONFIG_FASTBOOT_FLASH_BLOCK. - Use simple_strtol() instead of simple_strtoul() when parsing the device ID. - Reject malformed and negative device IDs. - Generalize the commit message rationale to a scsi/mtd dynamic-switching example instead of calling out SPI-NOR specifically. - Link to v1: https://lore.kernel.org/all/20260824-series2-fastboot-block-target-v1-1-c8e9418ba...@oss.qualcomm.com/ --- drivers/fastboot/Kconfig | 11 +++++++ drivers/fastboot/fb_block.c | 69 ++++++++++++++++++++++++++++++++++++------- drivers/fastboot/fb_command.c | 59 ++++++++++++++++++++++++++++++++++++ include/fastboot.h | 1 + include/fb_block.h | 9 ++++++ 5 files changed, 138 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..e6f998dd2db 100644 --- a/drivers/fastboot/fb_block.c +++ b/drivers/fastboot/fb_block.c @@ -125,6 +125,60 @@ 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 (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 (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 +194,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 +243,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 +436,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 +448,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..a015669c43a 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,56 @@ 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; + char *endp; + long val; + + if (len >= sizeof(interface)) { + fastboot_fail("interface name too long", response); + return; + } + memcpy(interface, cmd_parameter, len); + interface[len] = '\0'; + + val = simple_strtol(space + 1, &endp, 10); + if (*endp != '\0' || endp == space + 1 || val < 0) { + fastboot_fail("invalid device id", response); + return; + } + device = val; + } 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]>
