Hi Tom,
> > > From: Pantelis Antoniou <pa...@antoniou-consulting.com> > > > > Previously we didn't support upload/download larger than available > > memory. This is pretty bad when you have to update your root > > filesystem for example. > > > > This patch removes that limitation (and the crashes when you > > transfered any file larger than 4MB) by making raw image writes be > > done in chunks and making file maximum size be configurable. > > > > The sequence number is a 16 bit counter; make sure we handle > > rollover correctly. This fixes the wrong transfers for large (> > > 256MB) images. > > > > Also utilize a variable to handle initialization, so that we don't > > rely on just the counter sent by the host. > > > > Signed-off-by: Pantelis Antoniou <pa...@antoniou-consulting.com> > > Signed-off-by: Tom Rini <tr...@ti.com> > > Acked-by: Lukasz Majewski <l.majew...@samsung.com> > > Test-hw: Exynos 4210 (Trats) > > Tested-by: Lukasz Majewski <l.majew...@samsung.com> Sorry but, I've found a regression for reading image from a file system. It happens with EXT4 mmc read (like uImage). mmc_file_op: ext4load mmc 0:2 /uImage 0x0 0 0x7f95dc98 ** File not found 0x0 ** dfu: Read error! ext4load params: ext4load - load binary file from a Ext4 filesystem Usage: ext4load <interface> <dev[:part]> [addr] [filename] [bytes] - load binary file 'filename' from 'dev' on 'interface' to address 'addr' from ext4 filesystem. All numeric parameters are assumed to be hex. Some parameters are wrong (buffer - 0x0) and some are switched (address and filename). Please find more details below: > > > --- > > Changes in v5: > > - Rework Pantelis' "dfu: Support larger than memory transfers" to > > not break filesystem writing > > > > Changes in v4: None > > Changes in v3: None > > Changes in v2: None > > > > README | 7 ++ > > drivers/dfu/dfu.c | 245 > > ++++++++++++++++++++++++++++++++++++++----------- > > drivers/dfu/dfu_mmc.c | 116 +++++++++++++++++------ > > include/dfu.h | 26 +++++- 4 files changed, 310 > > insertions(+), 84 deletions(-) > > > > +static int dfu_write_buffer_drain(struct dfu_entity *dfu) > > +{ > > + long w_size; > > + int ret; > > + > > + /* flush size? */ > > + w_size = dfu->i_buf - dfu->i_buf_start; > > + if (w_size == 0) > > + return 0; > > + > > + /* update CRC32 */ > > + dfu->crc = crc32(dfu->crc, dfu->i_buf_start, w_size); > > + > > + ret = dfu->write_medium(dfu, dfu->offset, dfu->i_buf_start, > > &w_size); > > + if (ret) > > + debug("%s: Write error!\n", __func__); > > + > > + /* point back */ > > + dfu->i_buf = dfu->i_buf_start; > > + > > + /* update offset */ > > + dfu->offset += w_size; > > + > > + puts("#"); > > + > > + return ret; > > +} > > + > > int dfu_write(struct dfu_entity *dfu, void *buf, int size, int > > blk_seq_num) { > > - static unsigned char *i_buf; > > - static int i_blk_seq_num; > > - long w_size = 0; > > int ret = 0; > > + int tret; > > + > > + debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x " > > + "offset: 0x%llx bufoffset: 0x%x\n", > > + __func__, dfu->name, buf, size, blk_seq_num, > > dfu->offset, > > + dfu->i_buf - dfu->i_buf_start); > > + > > + if (!dfu->inited) { > > + /* initial state */ > > + dfu->crc = 0; > > + dfu->offset = 0; > > + dfu->i_blk_seq_num = 0; > > + dfu->i_buf_start = dfu_buf; > > + dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); > > + dfu->i_buf = dfu->i_buf_start; > > + > > + dfu->inited = 1; > > + } > > > > - debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: > > 0x%p\n", > > - __func__, dfu->name, buf, size, blk_seq_num, i_buf); > > + if (dfu->i_blk_seq_num != blk_seq_num) { > > + printf("%s: Wrong sequence number! [%d] [%d]\n", > > + __func__, dfu->i_blk_seq_num, blk_seq_num); > > + return -1; > > + } > > > > - if (blk_seq_num == 0) { > > - i_buf = dfu_buf; > > - i_blk_seq_num = 0; > > + /* DFU 1.1 standard says: > > + * The wBlockNum field is a block sequence number. It > > increments each > > + * time a block is transferred, wrapping to zero from > > 65,535. It is used > > + * to provide useful context to the DFU loader in the > > device." > > + * > > + * This means that it's a 16 bit counter that roll-overs at > > + * 0xffff -> 0x0000. By having a typical 4K transfer block > > + * we roll-over at exactly 256MB. Not very fun to debug. > > + * > > + * Handling rollover, and having an inited variable, > > + * makes things work. > > + */ > > + > > + /* handle rollover */ > > + dfu->i_blk_seq_num = (dfu->i_blk_seq_num + 1) & 0xffff; > > + > > + /* flush buffer if overflow */ > > + if ((dfu->i_buf + size) > dfu->i_buf_end) { > > + tret = dfu_write_buffer_drain(dfu); > > + if (ret == 0) > > + ret = tret; > > } > > > > - if (i_blk_seq_num++ != blk_seq_num) { > > - printf("%s: Wrong sequence number! [%d] [%d]\n", > > - __func__, i_blk_seq_num, blk_seq_num); > > + /* we should be in buffer now (if not then size too large) > > */ > > + if ((dfu->i_buf + size) > dfu->i_buf_end) { > > + printf("%s: Wrong size! [%d] [%d] - %d\n", > > + __func__, dfu->i_blk_seq_num, blk_seq_num, > > size); return -1; > > } > > > > - memcpy(i_buf, buf, size); > > - i_buf += size; > > + memcpy(dfu->i_buf, buf, size); > > + dfu->i_buf += size; > > > > + /* if end or if buffer full flush */ > > + if (size == 0 || (dfu->i_buf + size) > dfu->i_buf_end) { > > + tret = dfu_write_buffer_drain(dfu); > > + if (ret == 0) > > + ret = tret; > > + } > > + > > + /* end? */ > > if (size == 0) { > > - /* Integrity check (if needed) */ > > - debug("%s: %s %d [B] CRC32: 0x%x\n", __func__, > > dfu->name, > > - i_buf - dfu_buf, crc32(0, dfu_buf, i_buf - > > dfu_buf)); > > + /* Now try and flush to the medium if needed. */ > > + if (dfu->flush_medium) > > + ret = dfu->flush_medium(dfu); > > + printf("\nDFU complete CRC32: 0x%08x\n", dfu->crc); > > > > - w_size = i_buf - dfu_buf; > > - ret = dfu->write_medium(dfu, dfu_buf, &w_size); > > - if (ret) > > - debug("%s: Write error!\n", __func__); > > + /* clear everything */ > > + dfu->crc = 0; > > + dfu->offset = 0; > > + dfu->i_blk_seq_num = 0; > > + dfu->i_buf_start = dfu_buf; > > + dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); > > + dfu->i_buf = dfu->i_buf_start; > > + > > + dfu->inited = 0; > > > > - i_blk_seq_num = 0; > > - i_buf = NULL; > > - return ret; > > } > > > > - return ret; > > + return ret = 0 ? size : ret; > > +} > > + > > +static int dfu_read_buffer_fill(struct dfu_entity *dfu, void *buf, > > int size) +{ > > + long chunk; > > + int ret, readn; > > + > > + readn = 0; > > + while (size > 0) { > > + > > + /* get chunk that can be read */ > > + chunk = min(size, dfu->b_left); > > + /* consume */ > > + if (chunk > 0) { > > + memcpy(buf, dfu->i_buf, chunk); > > + dfu->crc = crc32(dfu->crc, buf, chunk); > > + dfu->i_buf += chunk; > > + dfu->b_left -= chunk; > > + size -= chunk; > > + buf += chunk; > > + readn += chunk; > > + } > > + > > + /* all done */ > > + if (size > 0) { > > + /* no more to read */ > > + if (dfu->r_left == 0) > > + break; > > + > > + dfu->i_buf = dfu->i_buf_start; > > + dfu->b_left = dfu->i_buf_end - > > dfu->i_buf_start; + > > + /* got to read, but buffer is empty */ > > + if (dfu->b_left > dfu->r_left) > > + dfu->b_left = dfu->r_left; > > + ret = dfu->read_medium(dfu, dfu->offset, > > dfu->i_buf, > > + &dfu->b_left); > > + if (ret != 0) { > > + debug("%s: Read error!\n", > > __func__); > > + return ret; > > + } > > + dfu->offset += dfu->b_left; > > + dfu->r_left -= dfu->b_left; > > + > > + puts("#"); > > + } > > + } > > + > > + return readn; > > } > > > > int dfu_read(struct dfu_entity *dfu, void *buf, int size, int > > blk_seq_num) { > > - static unsigned char *i_buf; > > - static int i_blk_seq_num; > > - static long r_size; > > - static u32 crc; > > int ret = 0; > > > > debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: > > 0x%p\n", > > - __func__, dfu->name, buf, size, blk_seq_num, i_buf); > > - > > - if (blk_seq_num == 0) { > > - i_buf = dfu_buf; > > - ret = dfu->read_medium(dfu, i_buf, &r_size); > > - debug("%s: %s %ld [B]\n", __func__, dfu->name, > > r_size); > > - i_blk_seq_num = 0; > > - /* Integrity check (if needed) */ > > - crc = crc32(0, dfu_buf, r_size); > > + __func__, dfu->name, buf, size, blk_seq_num, > > dfu->i_buf); + > > + if (!dfu->inited) { > > + ret = dfu->read_medium(dfu, 0, NULL, &dfu->r_left); ^^^^^^^^^^^^ this call causes read error. I suppose, that it is an initial "read". Does it read the whole file at once? The problem is that the command is fromatted in a wrong way. On the other hand write operations works on Trats. -- Best regards, Lukasz Majewski Samsung R&D Poland (SRPOL) | Linux Platform Group _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot