From c194bdf226030e45bcb2db3dcbb2d72e5052820a Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Mon, 4 Jun 2018 15:53:39 +0900 Subject: [PATCH 01/11] gadget: f_thor: fix hang-up with ctrl-c After the commit 6aae84769a0b ("gadget: f_thor: Fix memory leaks of usb request and its buffer"), there is hang-up with ctrl-c in some udc. It is because req of out_ep is freed before out_ep is disabled. Fix hang-up with ctrl-c by disabling ep before free req of the ep. Signed-off-by: Seung-Woo Kim --- drivers/usb/gadget/f_thor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index 1aa6be4..8b3b19f 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -877,14 +877,14 @@ static void thor_func_disable(struct usb_function *f) /* Avoid freeing memory when ep is still claimed */ if (dev->in_ep->driver_data) { - free_ep_req(dev->in_ep, dev->in_req); usb_ep_disable(dev->in_ep); + free_ep_req(dev->in_ep, dev->in_req); dev->in_ep->driver_data = NULL; } if (dev->out_ep->driver_data) { - usb_ep_free_request(dev->out_ep, dev->out_req); usb_ep_disable(dev->out_ep); + usb_ep_free_request(dev->out_ep, dev->out_req); dev->out_ep->driver_data = NULL; } From cad66e324d31e14d1f9eb19b52c4fe81bdad6951 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Thu, 12 Jul 2018 13:05:41 +0200 Subject: [PATCH 02/11] usb: rockchip: fix command failed on host side due to missing data Two consecutive rockusb_tx_write without waiting for request complete do results in transfer reset of first request and thus no or incomplete data transfer. This because rockusb_tx_write do use just one USB request to keep serialization. So calls like: rockusb_tx_write_str(emmc_id); rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, CSW_GOOD); was succeeding only when DEBUG was defined because the time spent printing debug info was enough for transfer to complete. This patch fixes the issue adding a simple request complete handler called rockusb_tx_write_csw to be set as complete handler of in_req when sending back simple payload + CSW replies to commands. This new handler will always send CSW_GOOD replies because in case of error the command callback itself must send back an error CSW as unique reply to command. This patch fixes execution of: $ rkdeveloptool rfi when DEBUG is not defined. Signed-off-by: Alberto Panizzo --- drivers/usb/gadget/f_rockusb.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c index b8833d0..58e483c 100644 --- a/drivers/usb/gadget/f_rockusb.c +++ b/drivers/usb/gadget/f_rockusb.c @@ -388,6 +388,20 @@ static int rockusb_tx_write_csw(u32 tag, int residue, u8 status, int size) return rockusb_tx_write((char *)csw, size); } +static void tx_handler_send_csw(struct usb_ep *ep, struct usb_request *req) +{ + struct f_rockusb *f_rkusb = get_rkusb(); + int status = req->status; + + if (status) + debug("status: %d ep '%s' trans: %d\n", + status, ep->name, req->actual); + + /* Return back to default in_req complete function after sending CSW */ + req->complete = rockusb_complete; + rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_GOOD, USB_BULK_CS_WRAP_LEN); +} + static unsigned int rx_bytes_expected(struct usb_ep *ep) { struct f_rockusb *f_rkusb = get_rkusb(); @@ -496,13 +510,17 @@ static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req) { ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, sizeof(struct fsg_bulk_cb_wrap)); + struct f_rockusb *f_rkusb = get_rkusb(); char emmc_id[] = "EMMC "; printf("read storage id\n"); memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); + + /* Prepare for sending subsequent CSW_GOOD */ + f_rkusb->tag = cbw->tag; + f_rkusb->in_req->complete = tx_handler_send_csw; + rockusb_tx_write_str(emmc_id); - rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, CSW_GOOD, - USB_BULK_CS_WRAP_LEN); } static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) From e4b34a7634c30ee2476ce019b8793099d02e1ac0 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Thu, 12 Jul 2018 13:05:42 +0200 Subject: [PATCH 03/11] usb: rockchip: implement skeleton for K_FW_GET_CHIP_VER command Chip Version is a string saved in BOOTROM address space Little Endian. Ex for rk3288: 0x33323041 0x32303134 0x30383133 0x56323030 which brings: 320A20140813V200 Note that memory version do invert MSB/LSB so printing the char buffer would show: A02341023180002V Signed-off-by: Alberto Panizzo --- doc/README.rockusb | 9 ++++++--- drivers/usb/gadget/f_rockusb.c | 44 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/doc/README.rockusb b/doc/README.rockusb index 5405dc4..3a93edc 100644 --- a/doc/README.rockusb +++ b/doc/README.rockusb @@ -42,9 +42,12 @@ see doc/README.rockchip for more detail about how to get U-Boot binary. sudo rkdeveloptool wl 64 -There are plenty of Rockusb command. but wl(write lba) and -rd(reboot) command. These two command can let people flash -image to device. +Current set of rkdeveloptool commands supported: +- rci: Read Chip Info +- rfi: Read Flash Id +- rd : Reset Device +- td : Test Device Ready +- wl : Write blocks using LBA To do ----- diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c index 58e483c..0314ff0 100644 --- a/drivers/usb/gadget/f_rockusb.c +++ b/drivers/usb/gadget/f_rockusb.c @@ -523,6 +523,48 @@ static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req) rockusb_tx_write_str(emmc_id); } +int __weak rk_get_bootrom_chip_version(unsigned int *chip_info, int size) +{ + return 0; +} + +static void cb_get_chip_version(struct usb_ep *ep, struct usb_request *req) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, + sizeof(struct fsg_bulk_cb_wrap)); + struct f_rockusb *f_rkusb = get_rkusb(); + unsigned int chip_info[4], i; + + memset(chip_info, 0, sizeof(chip_info)); + rk_get_bootrom_chip_version(chip_info, 4); + + /* + * Chip Version is a string saved in BOOTROM address space Little Endian + * + * Ex for rk3288: 0x33323041 0x32303134 0x30383133 0x56323030 + * which brings: 320A20140813V200 + * + * Note that memory version do invert MSB/LSB so printing the char + * buffer will show: A02341023180002V + */ + printf("read chip version: "); + for (i = 0; i < 4; i++) { + printf("%c%c%c%c", + (chip_info[i] >> 24) & 0xFF, + (chip_info[i] >> 16) & 0xFF, + (chip_info[i] >> 8) & 0xFF, + (chip_info[i] >> 0) & 0xFF); + } + printf("\n"); + memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); + + /* Prepare for sending subsequent CSW_GOOD */ + f_rkusb->tag = cbw->tag; + f_rkusb->in_req->complete = tx_handler_send_csw; + + rockusb_tx_write((char *)chip_info, sizeof(chip_info)); +} + static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) { ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, @@ -661,7 +703,7 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = { }, { .cmd = K_FW_GET_CHIP_VER, - .cb = cb_not_support, + .cb = cb_get_chip_version, }, { .cmd = K_FW_LOW_FORMAT, From e11f9166f37c5d8e0f3c58bb5a1b03601e85643b Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Thu, 12 Jul 2018 13:05:44 +0200 Subject: [PATCH 04/11] usb: rockchip: implement K_FW_LBA_READ_10 command This patch implement reading blocks form selected device with LBA addressing. Corresponding command on workstation is: rkdeveloptool rl While we support reading more than one blocks per K_FW_LBA_READ_10 request, rkdeveloptool and original rockchip tool do perform chunk reads limiting the maximum size per chunk far lower than max int values. Signed-off-by: Alberto Panizzo Reviewed-by: Simon Glass --- arch/arm/include/asm/arch-rockchip/f_rockusb.h | 3 + doc/README.rockusb | 1 + drivers/usb/gadget/f_rockusb.c | 104 ++++++++++++++++++++++++- 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/arch-rockchip/f_rockusb.h b/arch/arm/include/asm/arch-rockchip/f_rockusb.h index 0b62771..3f2e763 100644 --- a/arch/arm/include/asm/arch-rockchip/f_rockusb.h +++ b/arch/arm/include/asm/arch-rockchip/f_rockusb.h @@ -27,6 +27,7 @@ */ #define RKUSB_BUF_SIZE EP_BUFFER_SIZE * 2 +#define RKBLOCK_BUF_SIZE 4096 #define RKUSB_STATUS_IDLE 0 #define RKUSB_STATUS_CMD 1 @@ -120,6 +121,8 @@ struct f_rockusb { unsigned int lba; unsigned int dl_size; unsigned int dl_bytes; + unsigned int ul_size; + unsigned int ul_bytes; struct blk_desc *desc; int reboot_flag; void *buf; diff --git a/doc/README.rockusb b/doc/README.rockusb index 3a93edc..7f58296 100644 --- a/doc/README.rockusb +++ b/doc/README.rockusb @@ -47,6 +47,7 @@ Current set of rkdeveloptool commands supported: - rfi: Read Flash Id - rd : Reset Device - td : Test Device Ready +- rl : Read blocks using LBA - wl : Write blocks using LBA To do diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c index 0314ff0..82f421c 100644 --- a/drivers/usb/gadget/f_rockusb.c +++ b/drivers/usb/gadget/f_rockusb.c @@ -328,6 +328,7 @@ static int rockusb_tx_write(const char *buffer, unsigned int buffer_size) memcpy(in_req->buf, buffer, buffer_size); in_req->length = buffer_size; + debug("Transferring 0x%x bytes\n", buffer_size); usb_ep_dequeue(rockusb_func->in_ep, in_req); ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0); if (ret) @@ -421,6 +422,65 @@ static unsigned int rx_bytes_expected(struct usb_ep *ep) return rx_remain; } +/* usb_request complete call back to handle upload image */ +static void tx_handler_ul_image(struct usb_ep *ep, struct usb_request *req) +{ + ALLOC_CACHE_ALIGN_BUFFER(char, rbuffer, RKBLOCK_BUF_SIZE); + struct f_rockusb *f_rkusb = get_rkusb(); + struct usb_request *in_req = rockusb_func->in_req; + int ret; + + /* Print error status of previous transfer */ + if (req->status) + debug("status: %d ep '%s' trans: %d len %d\n", req->status, + ep->name, req->actual, req->length); + + /* On transfer complete reset in_req and feedback host with CSW_GOOD */ + if (f_rkusb->ul_bytes >= f_rkusb->ul_size) { + in_req->length = 0; + in_req->complete = rockusb_complete; + + rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_GOOD, + USB_BULK_CS_WRAP_LEN); + return; + } + + /* Proceed with current chunk */ + unsigned int transfer_size = f_rkusb->ul_size - f_rkusb->ul_bytes; + + if (transfer_size > RKBLOCK_BUF_SIZE) + transfer_size = RKBLOCK_BUF_SIZE; + /* Read at least one block */ + unsigned int blkcount = (transfer_size + f_rkusb->desc->blksz - 1) / + f_rkusb->desc->blksz; + + debug("ul %x bytes, %x blks, read lba %x, ul_size:%x, ul_bytes:%x, ", + transfer_size, blkcount, f_rkusb->lba, + f_rkusb->ul_size, f_rkusb->ul_bytes); + + int blks = blk_dread(f_rkusb->desc, f_rkusb->lba, blkcount, rbuffer); + + if (blks != blkcount) { + printf("failed reading from device %s: %d\n", + f_rkusb->dev_type, f_rkusb->dev_index); + rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, + USB_BULK_CS_WRAP_LEN); + return; + } + f_rkusb->lba += blkcount; + f_rkusb->ul_bytes += transfer_size; + + /* Proceed with USB request */ + memcpy(in_req->buf, rbuffer, transfer_size); + in_req->length = transfer_size; + in_req->complete = tx_handler_ul_image; + printf("Uploading 0x%x bytes\n", transfer_size); + usb_ep_dequeue(rockusb_func->in_ep, in_req); + ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0); + if (ret) + printf("Error %d on queue\n", ret); +} + /* usb_request complete call back to handle down load image */ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) { @@ -565,6 +625,48 @@ static void cb_get_chip_version(struct usb_ep *ep, struct usb_request *req) rockusb_tx_write((char *)chip_info, sizeof(chip_info)); } +static void cb_read_lba(struct usb_ep *ep, struct usb_request *req) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, + sizeof(struct fsg_bulk_cb_wrap)); + struct f_rockusb *f_rkusb = get_rkusb(); + int sector_count; + + memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); + sector_count = (int)get_unaligned_be16(&cbw->CDB[7]); + f_rkusb->tag = cbw->tag; + + if (!f_rkusb->desc) { + char *type = f_rkusb->dev_type; + int index = f_rkusb->dev_index; + + f_rkusb->desc = blk_get_dev(type, index); + if (!f_rkusb->desc || + f_rkusb->desc->type == DEV_TYPE_UNKNOWN) { + printf("invalid device \"%s\", %d\n", type, index); + rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, + USB_BULK_CS_WRAP_LEN); + return; + } + } + + f_rkusb->lba = get_unaligned_be32(&cbw->CDB[2]); + f_rkusb->ul_size = sector_count * f_rkusb->desc->blksz; + f_rkusb->ul_bytes = 0; + + debug("require read %x bytes, %x sectors from lba %x\n", + f_rkusb->ul_size, sector_count, f_rkusb->lba); + + if (f_rkusb->ul_size == 0) { + rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, + CSW_FAIL, USB_BULK_CS_WRAP_LEN); + return; + } + + /* Start right now sending first chunk */ + tx_handler_ul_image(ep, req); +} + static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) { ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, @@ -675,7 +777,7 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = { }, { .cmd = K_FW_LBA_READ_10, - .cb = cb_not_support, + .cb = cb_read_lba, }, { .cmd = K_FW_LBA_WRITE_10, From f68c8e827c26d2911224f5abaa68a94faed07d3e Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Thu, 12 Jul 2018 13:05:45 +0200 Subject: [PATCH 05/11] usb: rockchip: implement K_FW_LBA_ERASE_10 command This command is part of the write partition sequence performed by rkdeveloptool: one partition is first completely erased and than wrote. Signed-off-by: Alberto Panizzo Reviewed-by: Simon Glass --- arch/arm/include/asm/arch-rockchip/f_rockusb.h | 1 + doc/README.rockusb | 1 + drivers/usb/gadget/f_rockusb.c | 48 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/arch/arm/include/asm/arch-rockchip/f_rockusb.h b/arch/arm/include/asm/arch-rockchip/f_rockusb.h index 3f2e763..9772321 100644 --- a/arch/arm/include/asm/arch-rockchip/f_rockusb.h +++ b/arch/arm/include/asm/arch-rockchip/f_rockusb.h @@ -63,6 +63,7 @@ K_FW_LOW_FORMAT = 0x1C, K_FW_SET_RESET_FLAG = 0x1E, K_FW_SPI_READ_10 = 0x21, K_FW_SPI_WRITE_10 = 0x22, +K_FW_LBA_ERASE_10 = 0x25, K_FW_SESSION = 0X30, K_FW_RESET = 0xff, diff --git a/doc/README.rockusb b/doc/README.rockusb index 7f58296..66437e1 100644 --- a/doc/README.rockusb +++ b/doc/README.rockusb @@ -49,6 +49,7 @@ Current set of rkdeveloptool commands supported: - td : Test Device Ready - rl : Read blocks using LBA - wl : Write blocks using LBA +- wlx: Write partition To do ----- diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c index 82f421c..bcdc2ba 100644 --- a/drivers/usb/gadget/f_rockusb.c +++ b/drivers/usb/gadget/f_rockusb.c @@ -692,6 +692,50 @@ static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) } } +static void cb_erase_lba(struct usb_ep *ep, struct usb_request *req) +{ + ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, + sizeof(struct fsg_bulk_cb_wrap)); + struct f_rockusb *f_rkusb = get_rkusb(); + int sector_count, lba, blks; + + memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); + sector_count = (int)get_unaligned_be16(&cbw->CDB[7]); + f_rkusb->tag = cbw->tag; + + if (!f_rkusb->desc) { + char *type = f_rkusb->dev_type; + int index = f_rkusb->dev_index; + + f_rkusb->desc = blk_get_dev(type, index); + if (!f_rkusb->desc || + f_rkusb->desc->type == DEV_TYPE_UNKNOWN) { + printf("invalid device \"%s\", %d\n", type, index); + rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, + USB_BULK_CS_WRAP_LEN); + return; + } + } + + lba = get_unaligned_be32(&cbw->CDB[2]); + + debug("require erase %x sectors from lba %x\n", + sector_count, lba); + + blks = blk_derase(f_rkusb->desc, lba, sector_count); + if (blks != sector_count) { + printf("failed erasing device %s: %d\n", f_rkusb->dev_type, + f_rkusb->dev_index); + rockusb_tx_write_csw(f_rkusb->tag, + cbw->data_transfer_length, CSW_FAIL, + USB_BULK_CS_WRAP_LEN); + return; + } + + rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, CSW_GOOD, + USB_BULK_CS_WRAP_LEN); +} + void __weak rkusb_set_reboot_flag(int flag) { struct f_rockusb *f_rkusb = get_rkusb(); @@ -824,6 +868,10 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = { .cb = cb_not_support, }, { + .cmd = K_FW_LBA_ERASE_10, + .cb = cb_erase_lba, + }, + { .cmd = K_FW_SESSION, .cb = cb_not_support, }, From 11758a56ab96c216512606ca470a72026e8d45ce Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Thu, 12 Jul 2018 13:05:46 +0200 Subject: [PATCH 06/11] usb: rockchip: be quiet on serial port while transferring data While downloading or uploading megabytes of data we had thousands of printf in console like: transfer 0x10000 bytes done OR Uploading 0x1000 bytes This because transfers are chunked and there is no way on target side to know the overall transfer size (to print one string per overall transfer). All these prints on serial console do slow down significantly the transfer and does not offer a significant information to the developer: rkdeveloptool and Rockchip original tool do use small chunks read/writes on big transfers. This allows on workstation to print percentage of transfer complete and as well offers to developer the information about: transfer is running OK. On error, either the percentage will stop or an error will be shown on workstation console. Signed-off-by: Alberto Panizzo --- drivers/usb/gadget/f_rockusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c index bcdc2ba..0959b8c 100644 --- a/drivers/usb/gadget/f_rockusb.c +++ b/drivers/usb/gadget/f_rockusb.c @@ -474,7 +474,7 @@ static void tx_handler_ul_image(struct usb_ep *ep, struct usb_request *req) memcpy(in_req->buf, rbuffer, transfer_size); in_req->length = transfer_size; in_req->complete = tx_handler_ul_image; - printf("Uploading 0x%x bytes\n", transfer_size); + debug("Uploading 0x%x bytes\n", transfer_size); usb_ep_dequeue(rockusb_func->in_ep, in_req); ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0); if (ret) @@ -536,7 +536,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) req->complete = rx_handler_command; req->length = EP_BUFFER_SIZE; f_rkusb->buf = f_rkusb->buf_head; - printf("transfer 0x%x bytes done\n", f_rkusb->dl_size); + debug("transfer 0x%x bytes done\n", f_rkusb->dl_size); f_rkusb->dl_size = 0; rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_GOOD, USB_BULK_CS_WRAP_LEN); From 4f6dc4c893de44e8d91008516c835e06b450e310 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Thu, 12 Jul 2018 13:05:48 +0200 Subject: [PATCH 07/11] usb: rockchip: fix printing csw debug info Workstation tool was happy while console on device were printing random numbers.. Signed-off-by: Alberto Panizzo --- drivers/usb/gadget/f_rockusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c index 0959b8c..574d610 100644 --- a/drivers/usb/gadget/f_rockusb.c +++ b/drivers/usb/gadget/f_rockusb.c @@ -384,7 +384,7 @@ static int rockusb_tx_write_csw(u32 tag, int residue, u8 status, int size) csw->residue = cpu_to_be32(residue); csw->status = status; #ifdef DEBUG - printcsw((char *)&csw); + printcsw((char *)csw); #endif return rockusb_tx_write((char *)csw, size); } From 92c7edae5eb2235bcfd19823cc00177d2463bd60 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Thu, 12 Jul 2018 13:05:49 +0200 Subject: [PATCH 08/11] usb: rockchip: on K_FW_LBA_WRITE_10 remove magic block size of 512 bytes As well as in K_FW_LBA_READ_10 and K_FW_LBA_ERASE_10 take device's block size from f_rkusb->desc->blksz instead of the fixed 512 bytes. Keep original behaviour of retry probing assigned block device on every host request to manage late SDCard plugs. Signed-off-by: Alberto Panizzo --- drivers/usb/gadget/f_rockusb.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c index 574d610..e81eb16 100644 --- a/drivers/usb/gadget/f_rockusb.c +++ b/drivers/usb/gadget/f_rockusb.c @@ -490,19 +490,6 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) unsigned int buffer_size = req->actual; transfer_size = f_rkusb->dl_size - f_rkusb->dl_bytes; - if (!f_rkusb->desc) { - char *type = f_rkusb->dev_type; - int index = f_rkusb->dev_index; - - f_rkusb->desc = blk_get_dev(type, index); - if (!f_rkusb->desc || - f_rkusb->desc->type == DEV_TYPE_UNKNOWN) { - puts("invalid mmc device\n"); - rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, - USB_BULK_CS_WRAP_LEN); - return; - } - } if (req->status != 0) { printf("Bad status: %d\n", req->status); @@ -516,7 +503,7 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) memcpy((void *)f_rkusb->buf, buffer, transfer_size); f_rkusb->dl_bytes += transfer_size; - int blks = 0, blkcnt = transfer_size / 512; + int blks = 0, blkcnt = transfer_size / f_rkusb->desc->blksz; debug("dl %x bytes, %x blks, write lba %x, dl_size:%x, dl_bytes:%x, ", transfer_size, blkcnt, f_rkusb->lba, f_rkusb->dl_size, @@ -547,8 +534,8 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) else f_rkusb->buf = f_rkusb->buf_head; - debug("remain %x bytes, %x sectors\n", req->length, - req->length / 512); + debug("remain %x bytes, %lx sectors\n", req->length, + req->length / f_rkusb->desc->blksz); } req->actual = 0; @@ -676,10 +663,26 @@ static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); sector_count = (int)get_unaligned_be16(&cbw->CDB[7]); + f_rkusb->tag = cbw->tag; + + if (!f_rkusb->desc) { + char *type = f_rkusb->dev_type; + int index = f_rkusb->dev_index; + + f_rkusb->desc = blk_get_dev(type, index); + if (!f_rkusb->desc || + f_rkusb->desc->type == DEV_TYPE_UNKNOWN) { + printf("invalid device \"%s\", %d\n", type, index); + rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, + USB_BULK_CS_WRAP_LEN); + return; + } + } + f_rkusb->lba = get_unaligned_be32(&cbw->CDB[2]); - f_rkusb->dl_size = sector_count * 512; + f_rkusb->dl_size = sector_count * f_rkusb->desc->blksz; f_rkusb->dl_bytes = 0; - f_rkusb->tag = cbw->tag; + debug("require write %x bytes, %x sectors to lba %x\n", f_rkusb->dl_size, sector_count, f_rkusb->lba); From feaa7856f50ec5bbf843d533ee223aedd845452c Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Fri, 13 Jul 2018 16:35:45 +0300 Subject: [PATCH 09/11] dfu: Fix data abort in dfu_free_entities() Commit 5d8fae79163e ("dfu: avoid memory leak") brings a regression which described below. This patch is effectively reverting that commit, adding corresponding comment to avoid such regressions in future. In case of error in dfu_config_entities(), it frees "dfu" array, which leads to "data abort" in dfu_free_entities(), which tries to free the same array (and even tries to access it from linked list first). The issue occurs e.g. when partition table on device does not match $dfu_alt_info layout: => dfu 0 mmc 1 Couldn't find part #2 on mmc device #1 DFU entities configuration failed! data abort To fix this issue, do not free "dfu" array in dfu_config_entities(). It will be freed later in dfu_free_entities(). Tested on BeagleBone Black (where this regression was originally found). Signed-off-by: Sam Protsenko --- drivers/dfu/dfu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index e7c9119..a3c0933 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -462,7 +462,7 @@ int dfu_config_entities(char *env, char *interface, char *devstr) ret = dfu_fill_entity(&dfu[i], s, alt_num_cnt, interface, devstr); if (ret) { - free(dfu); + /* We will free "dfu" in dfu_free_entities() */ return -1; } From 87a8ca985bc0b63f8ad166b648f54496e097101e Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Fri, 13 Jul 2018 16:35:46 +0300 Subject: [PATCH 10/11] dfu: Fix memory leak in dfu_init_env_entities() In case of error in dfu_init_env_entities(), env_bkp will leak. Fix it by providing single return path. Signed-off-by: Sam Protsenko --- drivers/dfu/dfu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index a3c0933..5b9abd6 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -56,7 +56,7 @@ int dfu_init_env_entities(char *interface, char *devstr) { const char *str_env; char *env_bkp; - int ret; + int ret = 0; #ifdef CONFIG_SET_DFU_ALT_INFO set_dfu_alt_info(interface, devstr); @@ -71,11 +71,12 @@ int dfu_init_env_entities(char *interface, char *devstr) ret = dfu_config_entities(env_bkp, interface, devstr); if (ret) { pr_err("DFU entities configuration failed!\n"); - return ret; + goto done; } +done: free(env_bkp); - return 0; + return ret; } static unsigned char *dfu_buf; From 28a5c88043c80a38040abde957fbe1755b796912 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Fri, 13 Jul 2018 16:35:47 +0300 Subject: [PATCH 11/11] dfu: Provide more verbose error message It might be useful for user to see some human-readable root cause message in addition to "configuration failed" message, so that the issue can be fixed quickly. Signed-off-by: Sam Protsenko --- drivers/dfu/dfu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 5b9abd6..3189495 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -71,6 +71,7 @@ int dfu_init_env_entities(char *interface, char *devstr) ret = dfu_config_entities(env_bkp, interface, devstr); if (ret) { pr_err("DFU entities configuration failed!\n"); + pr_err("(partition table does not match dfu_alt_info?)\n"); goto done; }