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]>