Re: [U-Boot] [PATCH v2 20/21] cmd: mtd: add 'mtd' command

2018-07-12 Thread Miquel Raynal
Hi Boris,

> > > +
> > > + if (full_erase) {
> > > + off = 0;
> > > + len = mtd->size;
> > > + }
> > > +
> > > + if ((u32)off % mtd->erasesize) {
> > 
> > Sounds dangerous. We have 8GB NANDs on sunxi platforms...  
> 
> [...]
> 
> > > +
> > > + if ((u32)len % mtd->erasesize) {
> > 
> > Same here. I guess there's a do_div() in uboot.  
> 
> In both cases I take the less significant bytes of a 64-bit value. The
> modulo operation is safe as long as mtd->erasesize is a 32-bit value
> too. I don't think there is any danger?

As discussed out of this thread, this works because mtd->erasesize is
always a power of 2. Erase sizes not being a power of 2 do not exist
but it will be safer to switch to do_div().

Thanks,
Miquèl
___
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot


Re: [U-Boot] [PATCH v2 20/21] cmd: mtd: add 'mtd' command

2018-07-12 Thread Miquel Raynal
Hi Boris,

Boris Brezillon  wrote on Thu, 12 Jul 2018
00:42:13 +0200:

> On Wed, 11 Jul 2018 17:25:28 +0200
> Miquel Raynal  wrote:
> 
> > +
> > +static void mtd_show_device(struct mtd_info *mtd)
> > +{
> > +   printf("* %s", mtd->name);  
> 
> Printing the device type might be interesting? And maybe also the size,
> writesize, oobsize and erasesize?

Absolutely.

> 
> > +   if (mtd->dev)
> > +   printf(" [device: %s] [parent: %s] [driver: %s]",
> > +  mtd->dev->name, mtd->dev->parent->name,
> > +  mtd->dev->driver->name);
> > +
> > +   printf("\n");
> > +}  

[...]

> > +   } else if (!strcmp(cmd, "erase")) {
> > +   bool scrub = strstr(cmd, ".dontskipbad");
> > +   bool full_erase = strstr(cmd, ".chip");  
> 
> Again, I think .chip extension is not needed. Just consider a full erase
> is requested when offset and length are not provided. Plus, chip is
> misleading since I guess mtd partitions are also exposed as mtd devices,
> and could thus be erased with the .chip extension as well.

".chip" removed.

Default now is mtd->size (the entire MTD device) for erase/read/write,
and mtd->writesize (a page) for a dump.

> 
> > +   struct erase_info erase_op = {};
> > +   u64 off, len;
> > +
> > +   off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
> > +   len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : 
> > mtd->erasesize;  
> 
> Hm. Are we sure we want the default to be 1 eraseblock? Shouldn't we
> consider that missing size means "erase up to the MTD device end". Same
> goes for the read/write accesses, but maybe not for dump where dumping
> a single page makes more sense.

See above.

> 
> > +
> > +   if (full_erase) {
> > +   off = 0;
> > +   len = mtd->size;
> > +   }
> > +
> > +   if ((u32)off % mtd->erasesize) {  
> 
> Sounds dangerous. We have 8GB NANDs on sunxi platforms...

[...]

> > +
> > +   if ((u32)len % mtd->erasesize) {  
> 
> Same here. I guess there's a do_div() in uboot.

In both cases I take the less significant bytes of a 64-bit value. The
modulo operation is safe as long as mtd->erasesize is a 32-bit value
too. I don't think there is any danger?

[...]

Thanks,
Miquèl
___
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot


Re: [U-Boot] [PATCH v2 20/21] cmd: mtd: add 'mtd' command

2018-07-11 Thread Boris Brezillon
On Wed, 11 Jul 2018 17:25:28 +0200
Miquel Raynal  wrote:

> +
> +static void mtd_show_device(struct mtd_info *mtd)
> +{
> + printf("* %s", mtd->name);

Printing the device type might be interesting? And maybe also the size,
writesize, oobsize and erasesize?

> + if (mtd->dev)
> + printf(" [device: %s] [parent: %s] [driver: %s]",
> +mtd->dev->name, mtd->dev->parent->name,
> +mtd->dev->driver->name);
> +
> + printf("\n");
> +}


> +static int do_mtd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> + struct mtd_info *mtd;
> + const char *cmd;
> + char *mtdname;
> + int ret;
> +
> + /* All MTD commands need at least two arguments */
> + if (argc < 2)
> + return CMD_RET_USAGE;
> +
> + /* Parse the command name and its optional suffixes */
> + cmd = argv[1];
> +
> + /* List the MTD devices if that is what the user wants */
> + if (strcmp(cmd, "list") == 0)
> + return do_mtd_list();
> +
> + /*
> +  * The remaining commands require also at least a device ID.
> +  * Check the selected device is valid. Ensure it is probed.
> +  */
> + if (argc < 3)
> + return CMD_RET_USAGE;
> +
> + mtdname = argv[2];
> + mtd = get_mtd_device_nm(mtdname);
> + if (IS_ERR_OR_NULL(mtd)) {
> + mtd_probe_devices_dm();
> + mtd = get_mtd_device_nm(mtdname);
> + if (IS_ERR_OR_NULL(mtd)) {
> + printf("MTD device %s not found, ret %ld\n",
> +mtdname, PTR_ERR(mtd));
> + return 1;
> + }
> + }
> +
> + argc -= 3;
> + argv += 3;
> +
> + /* Do the parsing */
> + if (!strncmp(cmd, "read", 4) || !strncmp(cmd, "dump", 4) ||
> + !strncmp(cmd, "write", 5)) {
> + struct mtd_oob_ops io_op = {};
> + bool dump, read, raw, woob;
> + uint user_addr = 0;
> + uint nb_pages;
> + u8 *buf;
> + u64 off, len;
> + u32 oob_len;
> +
> + dump = !strncmp(cmd, "dump", 4);
> + read = dump || !strncmp(cmd, "read", 4);
> + raw = strstr(cmd, ".raw");
> + woob = strstr(cmd, ".oob");
> +
> + if (!dump) {
> + if (!argc)
> + return CMD_RET_USAGE;
> +
> + user_addr = simple_strtoul(argv[0], NULL, 16);
> + argc--;
> + argv++;
> + }
> +
> + off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0;
> + len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : 
> mtd->writesize;
> + nb_pages = mtd_len_to_pages(mtd, len);
> + oob_len = woob ? nb_pages * mtd->oobsize : 0;
> +
> + if ((u32)off % mtd->writesize) {
> + printf("Offset not aligned with a page (0x%x)\n",
> +mtd->writesize);
> + return -EINVAL;
> + }
> +
> + if ((u32)len % mtd->writesize) {
> + printf("Size not a multiple of a page (0x%x)\n",
> +mtd->writesize);
> + return -EINVAL;
> + }
> +
> + if (dump)
> + buf = kmalloc(len + oob_len, GFP_KERNEL);
> + else
> + buf = map_sysmem(user_addr, 0);
> +
> + if (!buf) {
> + printf("Could not map/allocate the user buffer\n");
> + return -ENOMEM;
> + }
> +
> + printf("%s %lldB (%d page(s)) at offset 0x%08llx%s%s\n",
> +read ? "Reading" : "Writing", len, nb_pages, off,
> +raw ? " [raw]" : "", woob ? " [oob]" : "");
> +
> + io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
> + io_op.len = len;
> + io_op.ooblen = oob_len;
> + io_op.datbuf = buf;
> + io_op.oobbuf = woob ? [len] : NULL;
> +
> + if (read)
> + ret = mtd_read_oob(mtd, off, _op);
> + else
> + ret = mtd_write_oob(mtd, off, _op);
> +
> + if (ret) {
> + printf("%s on %s failed with error %d\n",
> +read ? "Read" : "Write", mtd->name, ret);
> + return ret;
> + }
> +
> + if (dump) {
> + uint page;
> +
> + for (page = 0; page < nb_pages; page++) {
> + u64 data_off = page * mtd->writesize;
> + printf("\nDump %d data bytes from 0x%08llx:\n",
> +mtd->writesize, data_off);
> + mtd_dump_buf(buf, mtd->writesize, data_off);
> +
> + if (woob) {
> +