genio: u-boot: patch: UFS 4k UMS fixes + BTRFS fixes/enablement

- backport fixes from upstream u-boot for
  - BTRFS (plus enable BTRFS and BZIP2 support for radxa-nio-12l)
    - tested with `CARD_DEVICE=/dev/mmcblk1 ROOTFS_TYPE=btrfs BTRFS_COMPRESSION=zstd` (no UFS!)
    - also with `EXT=ufs CARD_DEVICE=/dev/sdc ROOTFS_TYPE=btrfs BTRFS_COMPRESSION=zstd` (UFS!)
  - 4k block size UFS for UMS: fixes block size issue (USB issues unhandled)
- Enable "bind" command for the Mediatek-standard USB Gadget Ethernet
This commit is contained in:
Ricardo Pardini 2026-01-04 16:18:59 +01:00 committed by Igor
parent 872863b95a
commit 324d1ed403
4 changed files with 1197 additions and 0 deletions

View File

@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ricardo Pardini <ricardo@pardini.net>
Date: Sat, 3 Jan 2026 21:06:01 +0100
Subject: GENIO: radxa-nio-12l: Enable bind command
After commit 9bc199d7ea5 ("GENIO: board: 350/510/700/1200 EVK: Drop
deprecated usb_ether_init()") USB Ethernet Gadget needs to be manually
binded using the `bind` command. Let's enable that on Radxa NIO-12L.
Fixes: 8d921703e1fc5b446b041a7c81e93ca0455d573c # when nio-12l did not exist yet
Signed-off-by: Ricardo Pardini <ricardo@pardini.net>
---
configs/genio_1200_radxa_nio_12l_d16_defconfig | 1 +
configs/genio_1200_radxa_nio_12l_d4_defconfig | 1 +
configs/genio_1200_radxa_nio_12l_d8_defconfig | 1 +
3 files changed, 3 insertions(+)
diff --git a/configs/genio_1200_radxa_nio_12l_d16_defconfig b/configs/genio_1200_radxa_nio_12l_d16_defconfig
index 111111111111..222222222222 100644
--- a/configs/genio_1200_radxa_nio_12l_d16_defconfig
+++ b/configs/genio_1200_radxa_nio_12l_d16_defconfig
@@ -36,6 +36,7 @@ CONFIG_CMD_NVEDIT_EFI=y
CONFIG_CMD_NVEDIT_INFO=y
# CONFIG_CMD_CRC32 is not set
CONFIG_CMD_ADC=y
+CONFIG_CMD_BIND=y
CONFIG_CMD_CLK=y
CONFIG_CMD_DFU=y
CONFIG_CMD_DM=y
diff --git a/configs/genio_1200_radxa_nio_12l_d4_defconfig b/configs/genio_1200_radxa_nio_12l_d4_defconfig
index 111111111111..222222222222 100644
--- a/configs/genio_1200_radxa_nio_12l_d4_defconfig
+++ b/configs/genio_1200_radxa_nio_12l_d4_defconfig
@@ -36,6 +36,7 @@ CONFIG_CMD_NVEDIT_EFI=y
CONFIG_CMD_NVEDIT_INFO=y
# CONFIG_CMD_CRC32 is not set
CONFIG_CMD_ADC=y
+CONFIG_CMD_BIND=y
CONFIG_CMD_CLK=y
CONFIG_CMD_DFU=y
CONFIG_CMD_DM=y
diff --git a/configs/genio_1200_radxa_nio_12l_d8_defconfig b/configs/genio_1200_radxa_nio_12l_d8_defconfig
index 111111111111..222222222222 100644
--- a/configs/genio_1200_radxa_nio_12l_d8_defconfig
+++ b/configs/genio_1200_radxa_nio_12l_d8_defconfig
@@ -36,6 +36,7 @@ CONFIG_CMD_NVEDIT_EFI=y
CONFIG_CMD_NVEDIT_INFO=y
# CONFIG_CMD_CRC32 is not set
CONFIG_CMD_ADC=y
+CONFIG_CMD_BIND=y
CONFIG_CMD_CLK=y
CONFIG_CMD_DFU=y
CONFIG_CMD_DM=y
--
Armbian

View File

@ -0,0 +1,545 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tom Rini <trini@konsulko.com>
Date: Wed, 5 Apr 2023 19:48:57 -0400
Subject: UPSTREAM: usb: gadget: UMS: support multiple sector sizes (plus three
others)
--> rpardini: this indeed fixes UFS support for UMS. Unfortunately,
it seems there's still trouble with USB/OTG impl
itself on Mediatek; UMS doesn't really work either
with MMC or with UFS. Still, this would be needed
when the USB stuff is hopefully fixed.
--> rpardini: This cherry-picks and squashes upstream revisions:
---> 73b39a76e34a3b88a7a2c58588c9a5a604a51d90
usb: gadget: f_mass_storage: Rework do_request_sense slightly
When building with clang, it notes that sdinfo may be unused
uninitialized in some cases. This appears to be true from reading the
code, and we can simply set the variable to zero to start with and be as
correct as before.
Signed-off-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Marek Vasut <marex@denx.de>
---> f032260c7c336cf88c1914286fd42a1588080db3
cmd: ums: Use plain udevice for UDC controller interaction
Convert to plain udevice interaction with UDC controller
device, avoid the use of UDC uclass dev_array .
Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
Tested-by: Mattijs Korpershoek <mkorpershoek@baylibre.com> # on khadas vim3
Signed-off-by: Marek Vasut <marex@denx.de>
---> 1041ee64eb18f7a3af30085765ced149cb4dc7cf
usb: gadget: f_mass_storage: Stop ums on START-STOP UNIT SCSI command
Exit the UMS handler loop in case START-STOP UNIT SCSI command is
received. This is sent e.g. by the util-linux eject(1) command and
indicates to the device that it is supposed to spin down the media
and enter low power state.
This effectively adds support for exitting the 'ums' command from
host using 'eject /dev/sdN' that is on par with 'dfu-util -e' .
Signed-off-by: Marek Vasut <marex@denx.de>
Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
Link: https://lore.kernel.org/r/20231107001018.55640-1-marex@denx.de
Signed-off-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
---> 304fa0aa445384e5e681a54abf413850591cec10
usb: gadget: UMS: support multiple sector sizes
UFS storage often uses a 4096-byte sector size, add support for dynamic
sector sizes based loosely on the Linux implementation.
Support for dynamic sector sizes changes the types used in some
divisions, resulting in the compiler attempting to use
libgcc helpers (__aeabi_ldivmod).
Replace these divisions with calls to lldiv() to handle this correctly.
Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
Link: https://lore.kernel.org/r/20240320-b4-qcom-usb-v4-4-41be480172e1@linaro.org
[mkorpershoek: squashed the lldiv() fix from caleb]
Signed-off-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
---
cmd/usb_mass_storage.c | 14 +-
drivers/usb/gadget/f_mass_storage.c | 120 ++++++----
drivers/usb/gadget/storage_common.c | 12 +-
include/usb_mass_storage.h | 3 +-
4 files changed, 85 insertions(+), 64 deletions(-)
diff --git a/cmd/usb_mass_storage.c b/cmd/usb_mass_storage.c
index 111111111111..222222222222 100644
--- a/cmd/usb_mass_storage.c
+++ b/cmd/usb_mass_storage.c
@@ -87,10 +87,6 @@ static int ums_init(const char *devtype, const char *devnums_part_str)
if (!strchr(devnum_part_str, ':'))
partnum = 0;
- /* f_mass_storage.c assumes SECTOR_SIZE sectors */
- if (block_dev->blksz != SECTOR_SIZE)
- goto cleanup;
-
ums_new = realloc(ums, (ums_count + 1) * sizeof(*ums));
if (!ums_new)
goto cleanup;
@@ -143,6 +139,7 @@ static int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag,
const char *devtype;
const char *devnum;
unsigned int controller_index;
+ struct udevice *udc;
int rc;
int cable_ready_timeout __maybe_unused;
@@ -164,13 +161,14 @@ static int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag,
controller_index = (unsigned int)(simple_strtoul(
usb_controller, NULL, 0));
- if (usb_gadget_initialize(controller_index)) {
+ rc = udc_device_get_by_index(controller_index, &udc);
+ if (rc) {
pr_err("Couldn't init USB controller.\n");
rc = CMD_RET_FAILURE;
goto cleanup_ums_init;
}
- rc = fsg_init(ums, ums_count, controller_index);
+ rc = fsg_init(ums, ums_count, udc);
if (rc) {
pr_err("fsg_init failed\n");
rc = CMD_RET_FAILURE;
@@ -215,7 +213,7 @@ static int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag,
}
while (1) {
- usb_gadget_handle_interrupts(controller_index);
+ dm_usb_gadget_handle_interrupts(udc);
rc = fsg_main_thread(NULL);
if (rc) {
@@ -237,7 +235,7 @@ static int do_usb_mass_storage(struct cmd_tbl *cmdtp, int flag,
cleanup_register:
g_dnl_unregister();
cleanup_board:
- usb_gadget_release(controller_index);
+ udc_device_put(udc);
cleanup_ums_init:
ums_fini();
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 111111111111..222222222222 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -240,6 +240,7 @@
/* #define DUMP_MSGS */
#include <config.h>
+#include <div64.h>
#include <hexdump.h>
#include <log.h>
#include <malloc.h>
@@ -327,6 +328,7 @@ struct fsg_common {
unsigned int short_packet_received:1;
unsigned int bad_lun_okay:1;
unsigned int running:1;
+ unsigned int eject:1;
int thread_wakeup_needed;
struct completion thread_notifier;
@@ -435,7 +437,7 @@ static void set_bulk_out_req_length(struct fsg_common *common,
static struct ums *ums;
static int ums_count;
static struct fsg_common *the_fsg_common;
-static unsigned int controller_index;
+static struct udevice *udcdev;
static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
{
@@ -669,6 +671,10 @@ static int sleep_thread(struct fsg_common *common)
}
if (k == 10) {
+ /* Handle START-STOP UNIT */
+ if (common->eject)
+ return -EPIPE;
+
/* Handle CTRL+C */
if (ctrlc())
return -EPIPE;
@@ -680,7 +686,7 @@ static int sleep_thread(struct fsg_common *common)
k = 0;
}
- usb_gadget_handle_interrupts(controller_index);
+ dm_usb_gadget_handle_interrupts(udcdev);
}
common->thread_wakeup_needed = 0;
return rc;
@@ -719,12 +725,13 @@ static int do_read(struct fsg_common *common)
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
}
- file_offset = ((loff_t) lba) << 9;
+ file_offset = ((loff_t)lba) << curlun->blkbits;
/* Carry out the file reads */
amount_left = common->data_size_from_cmnd;
- if (unlikely(amount_left == 0))
+ if (unlikely(amount_left == 0)) {
return -EIO; /* No default reply */
+ }
for (;;) {
@@ -763,13 +770,13 @@ static int do_read(struct fsg_common *common)
/* Perform the read */
rc = ums[common->lun].read_sector(&ums[common->lun],
- file_offset / SECTOR_SIZE,
- amount / SECTOR_SIZE,
+ lldiv(file_offset, curlun->blksize),
+ lldiv(amount, curlun->blksize),
(char __user *)bh->buf);
if (!rc)
return -EIO;
- nread = rc * SECTOR_SIZE;
+ nread = rc * curlun->blksize;
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset,
@@ -782,7 +789,7 @@ static int do_read(struct fsg_common *common)
} else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n",
(int) nread, amount);
- nread -= (nread & 511); /* Round down to a block */
+ nread -= (nread & (curlun->blksize - 1)); /* Round down to a block */
}
file_offset += nread;
amount_left -= nread;
@@ -856,7 +863,7 @@ static int do_write(struct fsg_common *common)
/* Carry out the file writes */
get_some_more = 1;
- file_offset = usb_offset = ((loff_t) lba) << 9;
+ file_offset = usb_offset = ((loff_t)lba) << curlun->blkbits;
amount_left_to_req = common->data_size_from_cmnd;
amount_left_to_write = common->data_size_from_cmnd;
@@ -888,7 +895,7 @@ static int do_write(struct fsg_common *common)
curlun->info_valid = 1;
continue;
}
- amount -= (amount & 511);
+ amount -= (amount & (curlun->blksize - 1));
if (amount == 0) {
/* Why were we were asked to transfer a
@@ -937,12 +944,12 @@ static int do_write(struct fsg_common *common)
/* Perform the write */
rc = ums[common->lun].write_sector(&ums[common->lun],
- file_offset / SECTOR_SIZE,
- amount / SECTOR_SIZE,
+ lldiv(file_offset, curlun->blksize),
+ lldiv(amount, curlun->blksize),
(char __user *)bh->buf);
if (!rc)
return -EIO;
- nwritten = rc * SECTOR_SIZE;
+ nwritten = rc * curlun->blksize;
VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset,
@@ -955,7 +962,7 @@ static int do_write(struct fsg_common *common)
} else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n",
(int) nwritten, amount);
- nwritten -= (nwritten & 511);
+ nwritten -= (nwritten & (curlun->blksize - 1));
/* Round down to a block */
}
file_offset += nwritten;
@@ -1029,8 +1036,8 @@ static int do_verify(struct fsg_common *common)
return -EIO; /* No default reply */
/* Prepare to carry out the file verify */
- amount_left = verification_length << 9;
- file_offset = ((loff_t) lba) << 9;
+ amount_left = verification_length << curlun->blkbits;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Write out all the dirty buffers before invalidating them */
@@ -1053,12 +1060,12 @@ static int do_verify(struct fsg_common *common)
/* Perform the read */
rc = ums[common->lun].read_sector(&ums[common->lun],
- file_offset / SECTOR_SIZE,
- amount / SECTOR_SIZE,
+ lldiv(file_offset, curlun->blksize),
+ lldiv(amount, curlun->blksize),
(char __user *)bh->buf);
if (!rc)
return -EIO;
- nread = rc * SECTOR_SIZE;
+ nread = rc * curlun->blksize;
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset,
@@ -1070,7 +1077,7 @@ static int do_verify(struct fsg_common *common)
} else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n",
(int) nread, amount);
- nread -= (nread & 511); /* Round down to a sector */
+ nread -= (nread & (curlun->blksize - 1)); /* Round down to a sector */
}
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
@@ -1117,7 +1124,7 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
{
struct fsg_lun *curlun = &common->luns[common->lun];
u8 *buf = (u8 *) bh->buf;
- u32 sd, sdinfo;
+ u32 sd, sdinfo = 0;
int valid;
/*
@@ -1145,7 +1152,6 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
if (!curlun) { /* Unsupported LUNs are okay */
common->bad_lun_okay = 1;
sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
- sdinfo = 0;
valid = 0;
} else {
sd = curlun->sense_data;
@@ -1179,7 +1185,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
return 8;
}
@@ -1326,6 +1332,8 @@ static int do_start_stop(struct fsg_common *common)
return -EINVAL;
}
+ common->eject = 1;
+
return 0;
}
@@ -1364,7 +1372,7 @@ static int do_read_format_capacities(struct fsg_common *common,
put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
buf[4] = 0x02; /* Current capacity */
return 12;
}
@@ -1775,6 +1783,16 @@ static int check_command(struct fsg_common *common, int cmnd_size,
return 0;
}
+/* wrapper of check_command for data size in blocks handling */
+static int check_command_size_in_blocks(struct fsg_common *common,
+ int cmnd_size, enum data_direction data_dir,
+ unsigned int mask, int needs_medium, const char *name)
+{
+ common->data_size_from_cmnd <<= common->luns[common->lun].blkbits;
+ return check_command(common, cmnd_size, data_dir,
+ mask, needs_medium, name);
+}
+
static int do_scsi_command(struct fsg_common *common)
{
@@ -1859,30 +1877,30 @@ static int do_scsi_command(struct fsg_common *common)
case SC_READ_6:
i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
- reply = check_command(common, 6, DATA_DIR_TO_HOST,
- (7<<1) | (1<<4), 1,
- "READ(6)");
+ common->data_size_from_cmnd = (i == 0 ? 256 : i);
+ reply = check_command_size_in_blocks(common, 6, DATA_DIR_TO_HOST,
+ (7<<1) | (1<<4), 1,
+ "READ(6)");
if (reply == 0)
reply = do_read(common);
break;
case SC_READ_10:
common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]) << 9;
- reply = check_command(common, 10, DATA_DIR_TO_HOST,
- (1<<1) | (0xf<<2) | (3<<7), 1,
- "READ(10)");
+ get_unaligned_be16(&common->cmnd[7]);
+ reply = check_command_size_in_blocks(common, 10, DATA_DIR_TO_HOST,
+ (1<<1) | (0xf<<2) | (3<<7), 1,
+ "READ(10)");
if (reply == 0)
reply = do_read(common);
break;
case SC_READ_12:
common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]) << 9;
- reply = check_command(common, 12, DATA_DIR_TO_HOST,
- (1<<1) | (0xf<<2) | (0xf<<6), 1,
- "READ(12)");
+ get_unaligned_be32(&common->cmnd[6]);
+ reply = check_command_size_in_blocks(common, 12, DATA_DIR_TO_HOST,
+ (1<<1) | (0xf<<2) | (0xf<<6), 1,
+ "READ(12)");
if (reply == 0)
reply = do_read(common);
break;
@@ -1977,30 +1995,30 @@ static int do_scsi_command(struct fsg_common *common)
case SC_WRITE_6:
i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
- reply = check_command(common, 6, DATA_DIR_FROM_HOST,
- (7<<1) | (1<<4), 1,
- "WRITE(6)");
+ common->data_size_from_cmnd = (i == 0 ? 256 : i);
+ reply = check_command_size_in_blocks(common, 6, DATA_DIR_FROM_HOST,
+ (7<<1) | (1<<4), 1,
+ "WRITE(6)");
if (reply == 0)
reply = do_write(common);
break;
case SC_WRITE_10:
common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]) << 9;
- reply = check_command(common, 10, DATA_DIR_FROM_HOST,
- (1<<1) | (0xf<<2) | (3<<7), 1,
- "WRITE(10)");
+ get_unaligned_be16(&common->cmnd[7]);
+ reply = check_command_size_in_blocks(common, 10, DATA_DIR_FROM_HOST,
+ (1<<1) | (0xf<<2) | (3<<7), 1,
+ "WRITE(10)");
if (reply == 0)
reply = do_write(common);
break;
case SC_WRITE_12:
common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]) << 9;
- reply = check_command(common, 12, DATA_DIR_FROM_HOST,
- (1<<1) | (0xf<<2) | (0xf<<6), 1,
- "WRITE(12)");
+ get_unaligned_be32(&common->cmnd[6]);
+ reply = check_command_size_in_blocks(common, 12, DATA_DIR_FROM_HOST,
+ (1<<1) | (0xf<<2) | (0xf<<6), 1,
+ "WRITE(12)");
if (reply == 0)
reply = do_write(common);
break;
@@ -2491,7 +2509,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
for (i = 0; i < nluns; i++) {
common->luns[i].removable = 1;
- rc = fsg_lun_open(&common->luns[i], ums[i].num_sectors, "");
+ rc = fsg_lun_open(&common->luns[i], ums[i].num_sectors, ums->block_dev.blksz, "");
if (rc)
goto error_luns;
}
@@ -2765,11 +2783,11 @@ int fsg_add(struct usb_configuration *c)
return fsg_bind_config(c->cdev, c, fsg_common);
}
-int fsg_init(struct ums *ums_devs, int count, unsigned int controller_idx)
+int fsg_init(struct ums *ums_devs, int count, struct udevice *udc)
{
ums = ums_devs;
ums_count = count;
- controller_index = controller_idx;
+ udcdev = udc;
return 0;
}
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 111111111111..222222222222 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -269,6 +269,7 @@ struct device_attribute { int i; };
#define ETOOSMALL 525
#include <log.h>
+#include <linux/log2.h>
#include <usb_mass_storage.h>
#include <dm/device_compat.h>
@@ -290,6 +291,8 @@ struct fsg_lun {
u32 sense_data;
u32 sense_data_info;
u32 unit_attention_data;
+ unsigned int blkbits;
+ unsigned int blksize; /* logical block size of bound block device */
struct device dev;
};
@@ -566,7 +569,7 @@ static struct usb_gadget_strings fsg_stringtab = {
*/
static int fsg_lun_open(struct fsg_lun *curlun, unsigned int num_sectors,
- const char *filename)
+ unsigned int sector_size, const char *filename)
{
int ro;
@@ -574,9 +577,12 @@ static int fsg_lun_open(struct fsg_lun *curlun, unsigned int num_sectors,
ro = curlun->initially_ro;
curlun->ro = ro;
- curlun->file_length = num_sectors << 9;
+ curlun->file_length = num_sectors * sector_size;
curlun->num_sectors = num_sectors;
- debug("open backing file: %s\n", filename);
+ curlun->blksize = sector_size;
+ curlun->blkbits = order_base_2(sector_size >> 9) + 9;
+ debug("blksize: %u\n", sector_size);
+ debug("open backing file: '%s'\n", filename);
return 0;
}
diff --git a/include/usb_mass_storage.h b/include/usb_mass_storage.h
index 111111111111..222222222222 100644
--- a/include/usb_mass_storage.h
+++ b/include/usb_mass_storage.h
@@ -7,7 +7,6 @@
#ifndef __USB_MASS_STORAGE_H__
#define __USB_MASS_STORAGE_H__
-#define SECTOR_SIZE 0x200
#include <part.h>
#include <linux/usb/composite.h>
@@ -25,7 +24,7 @@ struct ums {
struct blk_desc block_dev;
};
-int fsg_init(struct ums *ums_devs, int count, unsigned int controller_idx);
+int fsg_init(struct ums *ums_devs, int count, struct udevice *udc);
void fsg_cleanup(void);
int fsg_main_thread(void *);
int fsg_add(struct usb_configuration *c);
--
Armbian

View File

@ -0,0 +1,518 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Qu Wenruo <wqu@suse.com>
Date: Fri, 30 Dec 2022 09:07:05 +0800
Subject: UPSTREAM: multiple fixes for btrfs
fs: btrfs: Do not free multi when guaranteed to be NULL
multi is guaranteed to be NULL in the first two error exit paths so the
attempt to free it is not needed. Remove those calls.
This issue found by Smatch.
Signed-off-by: Andrew Goodbody <andrew.goodbody@linaro.org>
(cherry picked from commit 9204cae0937c0e26fcff1ee08e51ef37f59844fe)
fs: btrfs: hide duplicate 'Cannot lookup file' error on 'load'
Running commands such as 'load mmc 2:1 $addr $path' when path does not
exists will print an error twice if the file does not exist, e.g.:
```
Cannot lookup file boot/boot.scr
Failed to load 'boot/boot.scr'
```
(where the first line is printed by btrfs and the second by common fs
code)
Historically other filesystems such as ext4 or fat have not been
printing a message here, so do the same here to avoid duplicate.
The other error messages in this function are also somewhat redundant,
but bring useful diagnostics if they happen somewhere, so have been left
as printf.
Note that if a user wants no message to be printed for optional file
loads, they have to check for file existence first with other commands
such as 'size'.
Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
(cherry picked from commit 6e988fde65b0a89d49c20553d47a8ec1e5461c12)
fs: btrfs: fix out of bounds write
Fix btrfs_read/read_and_truncate_page write out of bounds of destination
buffer. Old behavior break bootstd malloc'd buffers of exact file size.
Previously this OOB write have not been noticed because distroboot usually
read files into huge static memory areas.
Signed-off-by: Alex Shumsky <alexthreed@gmail.com>
Fixes: e342718 ("fs: btrfs: Implement btrfs_file_read()")
Reviewed-by: Qu Wenruo <wqu@suse.com>
(cherry picked from commit ee1941e4fec601a8444f49c7dad04ad700d501a6)
fs: btrfs: fix reading when length specified
The btrfs read function limits the read length to ensure that it
and the read offset do not together exceed the size of the file.
However, this size was only being queried if the read length was
passed a value of zero (meaning "whole file"), and the size is
defaulted to 0 otherwise. This means the clamp will just zero out
the length if one is specified, preventing reading of the file.
Fix this by checking the file size unconditionally, and unifying
the default length and clamping logic as a single range check instead.
This bug was discovered when trying to boot Linux with initrd= via
'bootefi' from a btrfs partition. The EFI stub entered an infinite
loop of zero-length reads while trying to read the initrd, and the
boot process stalled indefinitely.
Signed-off-by: Sam Edwards <CFSworks@gmail.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
(cherry picked from commit 6d6ea52b629c384fb8605678b9003d2a077f9148)
btrfs: fix some error checking for btrfs_decompress()
The btrfs_decompress() function mostly (u32)-1 on error but it can
also return -EPERM or other kernel error codes from zstd_decompress().
The "ret" variable is an int, so we could just check for negatives.
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
Reviewed-by: Qu Wenruo <wqu@suse.com>
(cherry picked from commit 08404fa2087946bb370430d466fe5011f18ef072)
fs: btrfs: Prevent error pointer dereference in list_subvolums()
If btrfs_read_fs_root() fails with -ENOENT, then we go to the next
entry. Fine. But if it fails for a different reason then we need
to clean up and return an error code. In the current code it
doesn't clean up but instead dereferences "root" and crashes.
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
Reviewed-by: Marek Behun <kabel@kernel.org>
Reviewed-by: Qu Wenruo <wqu@suse.com>
(cherry picked from commit c331efd08766aa610aa14c957856ef5b0fa915df)
fs/btrfs: use asm/unaligned.h
Use asm/unaligned.h instead of linux/unaligned/access_ok.h for unaligned
access. This is needed on architectures that doesn't handle unaligned
accesses directly.
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
(cherry picked from commit 6ba08b3f56c93d2e97e5be3e9deccadd1e8c0796)
btrfs: fix offset when reading compressed extents
btrfs_read_extent_reg correctly computed the extent offset in the
BTRFS_COMPRESS_NONE case, but did not account for the 'offset - key.offset'
part correctly in the compressed case, making the function read
incorrect data.
In the case I examined, the last 4k of a file was corrupted and
contained data from a few blocks prior, e.g. reading a 10k file with a
single extent:
btrfs_file_read()
-> btrfs_read_extent_reg
(aligned part loop, until 8k)
-> read_and_truncate_page
-> btrfs_read_extent_reg
(re-reads the last extent from 8k to the end,
incorrectly reading the first 2k of data)
This can be reproduced as follow:
$ truncate -s 200M btr
$ mount btr -o compress /mnt
$ pat() { dd if=/dev/zero bs=1M count=$1 iflag=count_bytes status=none | tr '\0' "\\$2"; }
$ { pat 4K 1; pat 4K 2; pat 2K 3; } > /mnt/file
$ sync
$ filefrag -v /mnt/file
File size of /mnt/file is 10240 (3 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 2: 3328.. 3330: 3: last,encoded,eof
$ umount /mnt
Then in u-boot:
=> load scsi 0 2000000 file
10240 bytes read in 3 ms (3.3 MiB/s)
=> md 2001ff0
02001ff0: 02020202 02020202 02020202 02020202 ................
02002000: 01010101 01010101 01010101 01010101 ................
02002010: 01010101 01010101 01010101 01010101 ................
(02002000 onwards should contain '03' pattern but went back to 01,
start of the extent)
After patch, data is read properly:
=> md 2001ff0
02001ff0: 02020202 02020202 02020202 02020202 ................
02002000: 03030303 03030303 03030303 03030303 ................
02002010: 03030303 03030303 03030303 03030303 ................
Note that the code previously (before commit e3427184f38a ("fs: btrfs:
Implement btrfs_file_read()")) did not split that read in two, so
this is a regression even if the previous code might not have been
handling offsets correctly either (something that booted now fails to
boot)
Fixes: a26a6bedafcf ("fs: btrfs: Introduce btrfs_read_extent_inline() and btrfs_read_extent_reg()")
Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
(cherry picked from commit b1d3013d024086c042dbae4ddd99db56bb55b5e7)
fs: btrfs: limit the mapped length to the original length
[BUG]
There is a bug report that btrfs driver caused hang during file read:
This breaks btrfs on the HiFive Unmatched.
=> pci enum
PCIE-0: Link up (Gen1-x8, Bus0)
=> nvme scan
=> load nvme 0:2 0x8c000000 /boot/dtb/sifive/hifive-unmatched-a00.dtb
[hangs]
[CAUSE]
The reporter provided some debug output:
read_extent_data: cur=615817216, orig_len=16384, cur_len=16384
read_extent_data: btrfs_map_block: cur_len=479944704; ret=0
read_extent_data: ret=0
read_extent_data: cur=615833600, orig_len=4096, cur_len=4096
read_extent_data: btrfs_map_block: cur_len=479928320; ret=0
Note the second and the last line, the @cur_len is 450+MiB, which is
almost a chunk size.
And inside __btrfs_map_block(), we limits the returned value to stripe
length, but that's depending on the chunk type:
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID1C3 | BTRFS_BLOCK_GROUP_RAID1C4 |
BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6 |
BTRFS_BLOCK_GROUP_RAID10 |
BTRFS_BLOCK_GROUP_DUP)) {
/* we limit the length of each bio to what fits in a stripe */
*length = min_t(u64, ce->size - offset,
map->stripe_len - stripe_offset);
} else {
*length = ce->size - offset;
}
This means, if the chunk is SINGLE profile, then we don't limit the
returned length at all, and even for other profiles, we can still return
a length much larger than the requested one.
[FIX]
Properly clamp the returned length, preventing it from returning a much
larger range than expected.
Reported-by: Andreas Schwab <schwab@linux-m68k.org>
Signed-off-by: Qu Wenruo <wqu@suse.com>
(cherry picked from commit 511a1303c9cf9663c7d4312e3a0693319f41095b)
fs/btrfs: handle data extents, which crosss stripe boundaries, correctly
[BUG]
Since btrfs supports single device RAID0 at mkfs time after btrfs-progs
v5.14, if we create a single device raid0 btrfs, and created a file
crossing stripe boundary:
# mkfs.btrfs -m dup -d raid0 test.img
# mount test.img mnt
# xfs_io -f -c "pwrite 0 128K" mnt/file
# umount mnt
Since btrfs is using 64K as stripe length, above 128K data write is
definitely going to cross at least one stripe boundary.
Then u-boot would fail to read above 128K file:
=> host bind 0 /home/adam/test.img
=> ls host 0
< > 131072 Fri Dec 30 00:18:25 2022 file
=> load host 0 0 file
BTRFS: An error occurred while reading file file
Failed to load 'file'
[CAUSE]
Unlike tree blocks read, data extent reads doesn't consider cases in which
one data extent can cross stripe boundary.
In read_data_extent(), we just call btrfs_map_block() once and read the
first mapped range.
And if the first mapped range is smaller than the desired range, it
would return error.
But since even single device btrfs can utilize RAID0 profiles, the first
mapped range can only be at most 64K for RAID0 profiles, and cause false
error.
[FIX]
Just like read_whole_eb(), we should call btrfs_map_block() in a loop
until we read all data.
Since we're here, also add extra error messages for the following cases:
- btrfs_map_block() failure
We already have the error message for it.
- Missing device
This should not happen, as we only support single device for now.
- __btrfs_devread() failure
With this bug fixed, btrfs driver of u-boot can properly read the above
128K file, and have the correct content:
=> host bind 0 /home/adam/test.img
=> ls host 0
< > 131072 Fri Dec 30 00:18:25 2022 file
=> load host 0 0 file
131072 bytes read in 0 ms
=> md5sum 0 0x20000
md5 for 00000000 ... 0001ffff ==> d48858312a922db7eb86377f638dbc9f
^^^ Above md5sum also matches.
Reported-by: Sam Winchenbach <swichenbach@tethers.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
(cherry picked from commit 11d567012558fab7da9d1189948cb6005c081ccd)
---
fs/btrfs/btrfs.c | 17 ++--
fs/btrfs/crypto/hash.c | 2 +-
fs/btrfs/disk-io.c | 49 +++++-----
fs/btrfs/inode.c | 16 ++-
fs/btrfs/subvolume.c | 1 +
fs/btrfs/volumes.c | 4 +-
6 files changed, 49 insertions(+), 40 deletions(-)
diff --git a/fs/btrfs/btrfs.c b/fs/btrfs/btrfs.c
index 111111111111..222222222222 100644
--- a/fs/btrfs/btrfs.c
+++ b/fs/btrfs/btrfs.c
@@ -193,7 +193,7 @@ int btrfs_size(const char *file, loff_t *size)
ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
file, &root, &ino, &type, 40);
if (ret < 0) {
- printf("Cannot lookup file %s\n", file);
+ debug("Cannot lookup file %s\n", file);
return ret;
}
if (type != BTRFS_FT_REG_FILE) {
@@ -228,7 +228,7 @@ int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
{
struct btrfs_fs_info *fs_info = current_fs_info;
struct btrfs_root *root;
- loff_t real_size = 0;
+ loff_t real_size;
u64 ino;
u8 type;
int ret;
@@ -246,16 +246,13 @@ int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
return -EINVAL;
}
- if (!len) {
- ret = btrfs_size(file, &real_size);
- if (ret < 0) {
- error("Failed to get inode size: %s", file);
- return ret;
- }
- len = real_size;
+ ret = btrfs_size(file, &real_size);
+ if (ret < 0) {
+ error("Failed to get inode size: %s", file);
+ return ret;
}
- if (len > real_size - offset)
+ if (!len || len > real_size - offset)
len = real_size - offset;
ret = btrfs_file_read(root, ino, offset, len, buf);
diff --git a/fs/btrfs/crypto/hash.c b/fs/btrfs/crypto/hash.c
index 111111111111..222222222222 100644
--- a/fs/btrfs/crypto/hash.c
+++ b/fs/btrfs/crypto/hash.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
+#include <asm/unaligned.h>
#include <linux/xxhash.h>
-#include <linux/unaligned/access_ok.h>
#include <linux/types.h>
#include <u-boot/sha256.h>
#include <u-boot/blake2.h>
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 111111111111..222222222222 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -540,34 +540,39 @@ struct extent_buffer* read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
int read_extent_data(struct btrfs_fs_info *fs_info, char *data, u64 logical,
u64 *len, int mirror)
{
- u64 offset = 0;
+ u64 orig_len = *len;
+ u64 cur = logical;
struct btrfs_multi_bio *multi = NULL;
struct btrfs_device *device;
int ret = 0;
- u64 max_len = *len;
- ret = btrfs_map_block(fs_info, READ, logical, len, &multi, mirror,
- NULL);
- if (ret) {
- fprintf(stderr, "Couldn't map the block %llu\n",
- logical + offset);
- goto err;
- }
- device = multi->stripes[0].dev;
-
- if (*len > max_len)
- *len = max_len;
- if (!device->desc || !device->part) {
- ret = -EIO;
- goto err;
- }
+ while (cur < logical + orig_len) {
+ u64 cur_len = logical + orig_len - cur;
- ret = __btrfs_devread(device->desc, device->part, data, *len,
- multi->stripes[0].physical);
- if (ret != *len)
- ret = -EIO;
- else
+ ret = btrfs_map_block(fs_info, READ, cur, &cur_len, &multi,
+ mirror, NULL);
+ if (ret) {
+ error("Couldn't map the block %llu", cur);
+ goto err;
+ }
+ device = multi->stripes[0].dev;
+ if (!device->desc || !device->part) {
+ error("devid %llu is missing", device->devid);
+ ret = -EIO;
+ goto err;
+ }
+ ret = __btrfs_devread(device->desc, device->part,
+ data + (cur - logical), cur_len,
+ multi->stripes[0].physical);
+ if (ret != cur_len) {
+ error("read failed on devid %llu physical %llu",
+ device->devid, multi->stripes[0].physical);
+ ret = -EIO;
+ goto err;
+ }
+ cur += cur_len;
ret = 0;
+ }
err:
kfree(multi);
return ret;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 111111111111..222222222222 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -390,7 +390,7 @@ int btrfs_read_extent_inline(struct btrfs_path *path,
csize);
ret = btrfs_decompress(btrfs_file_extent_compression(leaf, fi),
cbuf, csize, dbuf, dsize);
- if (ret == (u32)-1) {
+ if (ret < 0) {
ret = -EIO;
goto out;
}
@@ -500,7 +500,7 @@ int btrfs_read_extent_reg(struct btrfs_path *path,
ret = btrfs_decompress(btrfs_file_extent_compression(leaf, fi), cbuf,
csize, dbuf, dsize);
- if (ret == (u32)-1) {
+ if (ret < 0) {
ret = -EIO;
goto out;
}
@@ -511,7 +511,9 @@ int btrfs_read_extent_reg(struct btrfs_path *path,
if (ret < dsize)
memset(dbuf + ret, 0, dsize - ret);
/* Then copy the needed part */
- memcpy(dest, dbuf + btrfs_file_extent_offset(leaf, fi), len);
+ memcpy(dest,
+ dbuf + btrfs_file_extent_offset(leaf, fi) + offset - key.offset,
+ len);
ret = len;
out:
free(cbuf);
@@ -638,7 +640,11 @@ static int read_and_truncate_page(struct btrfs_path *path,
extent_type = btrfs_file_extent_type(leaf, fi);
if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
ret = btrfs_read_extent_inline(path, fi, buf);
- memcpy(dest, buf + page_off, min(page_len, ret));
+ if (ret < 0) {
+ free(buf);
+ return ret;
+ }
+ memcpy(dest, buf + page_off, min3(page_len, ret, len));
free(buf);
return len;
}
@@ -650,7 +656,7 @@ static int read_and_truncate_page(struct btrfs_path *path,
free(buf);
return ret;
}
- memcpy(dest, buf + page_off, page_len);
+ memcpy(dest, buf + page_off, min(page_len, len));
free(buf);
return len;
}
diff --git a/fs/btrfs/subvolume.c b/fs/btrfs/subvolume.c
index 111111111111..222222222222 100644
--- a/fs/btrfs/subvolume.c
+++ b/fs/btrfs/subvolume.c
@@ -199,6 +199,7 @@ static int list_subvolums(struct btrfs_fs_info *fs_info)
ret = PTR_ERR(root);
if (ret == -ENOENT)
goto next;
+ goto out;
}
ret = list_one_subvol(root, result);
if (ret < 0)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 111111111111..222222222222 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -956,6 +956,7 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
struct cache_extent *ce;
struct map_lookup *map;
+ u64 orig_len = *length;
u64 offset;
u64 stripe_offset;
u64 *raid_map = NULL;
@@ -972,12 +973,10 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
again:
ce = search_cache_extent(&map_tree->cache_tree, logical);
if (!ce) {
- kfree(multi);
*length = (u64)-1;
return -ENOENT;
}
if (ce->start > logical) {
- kfree(multi);
*length = ce->start - logical;
return -ENOENT;
}
@@ -1047,6 +1046,7 @@ again:
} else {
*length = ce->size - offset;
}
+ *length = min_t(u64, *length, orig_len);
if (!multi_ret)
goto out;
--
Armbian

View File

@ -0,0 +1,78 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ricardo Pardini <ricardo@pardini.net>
Date: Sun, 4 Jan 2026 15:58:51 +0100
Subject: GENIO: radxa-nio-12l: Enable BTRFS and BZIP2 support
After cherry-picking from upstream, BTRFS should work, so enable it
for the NIO-12L. Also add support for general BZIP2 compression.
Signed-off-by: Ricardo Pardini <ricardo@pardini.net>
---
configs/genio_1200_radxa_nio_12l_d16_defconfig | 2 ++
configs/genio_1200_radxa_nio_12l_d4_defconfig | 2 ++
configs/genio_1200_radxa_nio_12l_d8_defconfig | 2 ++
3 files changed, 6 insertions(+)
diff --git a/configs/genio_1200_radxa_nio_12l_d16_defconfig b/configs/genio_1200_radxa_nio_12l_d16_defconfig
index 111111111111..222222222222 100644
--- a/configs/genio_1200_radxa_nio_12l_d16_defconfig
+++ b/configs/genio_1200_radxa_nio_12l_d16_defconfig
@@ -53,6 +53,7 @@ CONFIG_CMD_USB_MASS_STORAGE=y
# CONFIG_CMD_ITEST is not set
# CONFIG_CMD_BLOCK_CACHE is not set
CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_BTRFS=y
CONFIG_PARTITION_TYPE_GUID=y
CONFIG_ENV_IS_IN_SCSI=y
CONFIG_SYS_SCSI_ENV_DEV=1
@@ -122,6 +123,7 @@ CONFIG_USB_ETHER=y
CONFIG_UFS=y
CONFIG_UFS_MEDIATEK=y
CONFIG_WDT=y
+CONFIG_BZIP2=y
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_EFI_SET_TIME=y
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
diff --git a/configs/genio_1200_radxa_nio_12l_d4_defconfig b/configs/genio_1200_radxa_nio_12l_d4_defconfig
index 111111111111..222222222222 100644
--- a/configs/genio_1200_radxa_nio_12l_d4_defconfig
+++ b/configs/genio_1200_radxa_nio_12l_d4_defconfig
@@ -53,6 +53,7 @@ CONFIG_CMD_USB_MASS_STORAGE=y
# CONFIG_CMD_ITEST is not set
# CONFIG_CMD_BLOCK_CACHE is not set
CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_BTRFS=y
CONFIG_PARTITION_TYPE_GUID=y
CONFIG_ENV_IS_IN_SCSI=y
CONFIG_SYS_SCSI_ENV_DEV=1
@@ -122,6 +123,7 @@ CONFIG_USB_ETHER=y
CONFIG_UFS=y
CONFIG_UFS_MEDIATEK=y
CONFIG_WDT=y
+CONFIG_BZIP2=y
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_EFI_SET_TIME=y
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
diff --git a/configs/genio_1200_radxa_nio_12l_d8_defconfig b/configs/genio_1200_radxa_nio_12l_d8_defconfig
index 111111111111..222222222222 100644
--- a/configs/genio_1200_radxa_nio_12l_d8_defconfig
+++ b/configs/genio_1200_radxa_nio_12l_d8_defconfig
@@ -53,6 +53,7 @@ CONFIG_CMD_USB_MASS_STORAGE=y
# CONFIG_CMD_ITEST is not set
# CONFIG_CMD_BLOCK_CACHE is not set
CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_BTRFS=y
CONFIG_PARTITION_TYPE_GUID=y
CONFIG_ENV_IS_IN_SCSI=y
CONFIG_SYS_SCSI_ENV_DEV=1
@@ -122,6 +123,7 @@ CONFIG_USB_ETHER=y
CONFIG_UFS=y
CONFIG_UFS_MEDIATEK=y
CONFIG_WDT=y
+CONFIG_BZIP2=y
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_EFI_SET_TIME=y
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
--
Armbian