[U-Boot] [PATCH] usb: Add new command to regress USB devices

Rajesh Bhagat rajesh.bhagat at nxp.com
Thu Mar 10 05:52:18 CET 2016



> -----Original Message-----
> From: sjg at google.com [mailto:sjg at google.com] On Behalf Of Simon Glass
> Sent: Thursday, March 10, 2016 3:09 AM
> To: Rajat Srivastava <rajat.srivastava at nxp.com>
> Cc: U-Boot Mailing List <u-boot at lists.denx.de>; Marek Vašut <marex at denx.de>;
> Rajesh Bhagat <rajesh.bhagat at nxp.com>
> Subject: Re: [PATCH] usb: Add new command to regress USB devices
> 
> Hi Rajat,
> 
> On 9 March 2016 at 04:22, Rajat Srivastava <rajat.srivastava at nxp.com> wrote:
> > This patch adds a new 'usb regress' command, that can be used to
> > regress test a USB device. It performs the following operations:
> >
> > 1. starts the USB device
> > 2. performs read/write operations
> > 3. stops the USB device
> > 4. verifies the contents of read/write operations
> >
> > Sample Output:
> > => usb regress 81000000 82000000 32m
> > regressing USB..
> > starting USB...
> > USB0:   Register 200017f NbrPorts 2
> > Starting the controller
> > USB XHCI 1.00
> > scanning bus 0 for devices... 2 USB Device(s) found
> >        scanning usb for storage devices... 1 Storage Device(s) found
> > USB write: device 0 block # 0, count 65536 ... 65536 blocks write: OK
> > USB read: device 0 block # 0, count 65536 ... 65536 blocks read: OK
> > stopping USB..
> > verifying data on addresses 0x81000000 and 0x82000000 Total of 65536
> > word(s) were the same
> >
> > Signed-off-by: Rajat Srivastava <rajat.srivastava at nxp.com>
> > Signed-off-by: Rajesh Bhagat <rajesh.bhagat at nxp.com>
> > ---
> >  common/cmd_usb.c | 174
> >
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++-
> >  1 file changed, 173 insertions(+), 1 deletion(-)
> 
> Can you rebase to mainline? This file has been renamed.
> 

Will take care v2.

> >
> > diff --git a/common/cmd_usb.c b/common/cmd_usb.c index
> > a540b42..25fdeab 100644
> > --- a/common/cmd_usb.c
> > +++ b/common/cmd_usb.c
> > @@ -20,6 +20,7 @@
> >  #include <asm/unaligned.h>
> >  #include <part.h>
> >  #include <usb.h>
> > +#include <mapmem.h>
> >
> >  #ifdef CONFIG_USB_STORAGE
> >  static int usb_stor_curr_dev = -1; /* current device */ @@ -616,6
> > +617,167 @@ static int usb_device_info(void)  }  #endif
> >
> > +static unsigned long calc_blockcount(char * const size)
> 
> Can you put this function in lib/display_options.c? I suggest something that decodes a
> string and returns a value (i.e. it would return 1024 for K, not 2, since that assumes a
> block size).
> 
> The multiple check can go in cmd/usb.c
> 

Will take care v2.

> > +{
> > +       unsigned long value, multiplier;
> > +       int size_len = strlen(size);
> > +       char unit;
> > +
> > +       /* extract the unit of size passed */
> > +       unit = size[size_len - 1];
> > +       /* updating the source string to remove unit */
> > +       size[size_len - 1] = '\0';
> > +
> > +       value = simple_strtoul(size, NULL, 10);
> > +       if (value <= 0) {
> > +               printf("invalid size\n");
> > +               return 0;
> > +       }
> > +
> > +       if (unit == 'G' || unit == 'g') {
> > +               multiplier = 2 * 1024 * 1024;
> > +       } else if (unit == 'M' || unit == 'm') {
> > +               multiplier = 2 * 1024;
> > +       } else if (unit == 'K' || unit == 'k') {
> > +               multiplier = 2;
> > +       } else if (unit == 'B' || unit == 'b') {
> > +               if (value % 512 != 0) {
> > +                       printf("size can only be multiples of 512 bytes\n");
> > +                       return 0;
> > +               }
> > +               multiplier = 1;
> > +               value /= 512;
> > +       } else {
> > +               printf("syntax mismatch\n");
> > +               return 0;
> > +       }
> > +
> > +       return value * multiplier;
> > +}
> > +
> > +static int usb_read_write_verify(unsigned long w_addr, unsigned long r_addr,
> > +                                                       unsigned long
> > +cnt) {
> > +       cmd_tbl_t *c;
> > +       char str[3][16];
> > +       char *ptr[4] = { "cmp", str[0], str[1], str[2] };
> > +
> > +       c = find_cmd("cmp");
> > +       if (!c) {
> > +               printf("compare command not found\n");
> > +               return -1;
> > +       }
> > +       printf("verifying data on addresses 0x%lx and 0x%lx\n", w_addr, r_addr);
> > +       sprintf(str[0], "%lx", w_addr);
> > +       sprintf(str[1], "%lx", r_addr);
> > +       sprintf(str[2], "%lx", cnt);
> > +       (c->cmd)(c, 0, 4, ptr);
> 
> We shouldn't call U-Boot functions via the command line parsing.
> 
> Please can you refactor do_mem_cmp() to separate the command parsing from the
> memory comparison logic? Then you can call the latter directory.
> 

AFAIU, we need to refactor do_mem_cmp to two functions and call mem_cmp function 
in our code. Please confirm. 

> > +       return 0;
> > +}
> > +
> > +
> > +static int do_usb_regress(int argc, char * const argv[])
> 
> Would 'usb datatest' be a better name?
> 

How about renaming the existing "usb test" command to "usb hwtest" as it supports hardware
tests. And add the new proposed command as "usb test" ?
        "usb test [dev] [port] [mode] - set USB 2.0 test mode\n"
        "    (specify port 0 to indicate the device's upstream port)\n"
        "    Available modes: J, K, S[E0_NAK], P[acket], F[orce_Enable]\n"

And it will also help to align the naming convention with "sf test".  Please share your opinion.

> > +{
> > +       unsigned long loopcount, iteration;
> > +       unsigned long w_addr, r_addr, cnt, n;
> > +       unsigned long blk = 0;
> > +       extern char usb_started;
> > +
> > +#ifdef CONFIG_USB_STORAGE
> > +       block_dev_desc_t *stor_dev;
> > +#endif
> > +
> > +       if (argc < 5 || argc > 6) {
> > +               printf("syntax mismatch\n");
> > +               return -1;
> > +       }
> > +
> > +       if (argc == 5)
> > +               loopcount = 1;
> > +       else
> > +               loopcount = simple_strtoul(argv[5], NULL, 10);
> > +
> > +       if (loopcount <= 0) {
> > +               printf("syntax mismatch\n");
> > +               return -1;
> > +       }
> > +
> > +       cnt = calc_blockcount(argv[4]);
> > +       if (cnt == 0)
> > +               return -1;
> > +
> > +       iteration = loopcount;
> > +       while (loopcount--) {
> > +               if (argc > 5)
> > +                       printf("\niteration #%lu\n\n", iteration -
> > + loopcount);
> > +
> > +               /* start USB */
> > +               if (usb_started) {
> > +                       printf("USB already started\n");
> > +               } else {
> > +                       printf("starting USB...\n");
> > +                       do_usb_start();
> > +               }
> > +               if (!usb_started) {
> > +                       printf("USB did not start\n");
> > +                       return -1;
> > +               }
> > +               if (usb_stor_curr_dev < 0) {
> > +                       printf("no current device selected\nstopping USB...\n");
> > +                       usb_stop();
> > +                       return -1;
> > +               }
> > +
> > +#ifdef CONFIG_USB_STORAGE
> 
> If this is not defined, perhaps this command shouldn't be included at all?
> 

Will take care v2. And add command definition in above flag.

> > +               /* write on USB from address (w_addr) of RAM */
> > +               w_addr = simple_strtoul(argv[2], NULL, 16);
> 
> Parse your arguments at the start, not in the loop.
> 

Agreed. Will take care v2

> > +               printf("USB write: device %d block # %ld, count %ld ... ",
> > +                      usb_stor_curr_dev, blk, cnt);
> > +               stor_dev = usb_stor_get_dev(usb_stor_curr_dev);
> > +               n = stor_dev->block_write(usb_stor_curr_dev, blk, cnt,
> > +                                                       (ulong *)w_addr);
> > +               printf("%ld blocks write: %s\n", n, (n == cnt) ?
> > +               "OK" : "ERROR");
> > +               if (n != cnt) {
> > +                       printf("aborting.. USB write failed\n");
> > +                       usb_stop();
> > +                       return -1;
> > +               }
> > +
> > +               /* read from USB and write on to address (r_addr) on RAM */
> > +               r_addr = simple_strtoul(argv[3], NULL, 16);
> > +               printf("USB read: device %d block # %ld, count %ld ... ",
> > +                      usb_stor_curr_dev, blk, cnt);
> > +               stor_dev = usb_stor_get_dev(usb_stor_curr_dev);
> > +               n = stor_dev->block_read(usb_stor_curr_dev, blk, cnt,
> > +                                                       (ulong *)r_addr);
> > +               printf("%ld blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
> > +               if (n != cnt) {
> > +                       printf("aborting.. USB read failed\n");
> > +                       usb_stop();
> > +                       return -1;
> 
> I think this needs to be CMD_RET_FAILURE.
> 

Agreed. Will take care v2

> > +               }
> > +#endif
> 
> Can this test pass on sandbox?
> 

Ok, We try to make its setup and share results. 

> > +
> > +               /* stop USB */
> > +               printf("stopping USB..\n");
> 
> It would be good to display the average read and write transfer speed here. See 'sf
> test'.
> 

Ok, we will refer "sf test" command" and add it in v2.

> > +               usb_stop();
> > +
> > +#ifdef CONFIG_USB_STORAGE
> > +               /*
> > +                * verify the content written on USB and
> > +                * content read from USB.
> > +                */
> > +               if (usb_read_write_verify(w_addr, r_addr, cnt) == -1)
> > +                       return -1;
> > +#endif
> > +               if (ctrlc())
> > +                       return -1;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> >
> /**********************************************************************
> ********
> >   * usb command intepreter
> >   */
> > @@ -656,6 +818,13 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char
> * const argv[])
> >                 usb_stop();
> >                 return 0;
> >         }
> > +       if (strncmp(argv[1], "regress", 6) == 0) {
> > +               if (do_usb_stop_keyboard(0) != 0)
> > +                       return 1;
> > +               printf("regressing USB..\n");
> > +               do_usb_regress(argc, argv);
> > +               return 0;
> > +       }
> >         if (!usb_started) {
> >                 printf("USB is stopped. Please issue 'usb start' first.\n");
> >                 return 1;
> > @@ -821,7 +990,7 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int
> > argc, char * const argv[])  }
> >
> >  U_BOOT_CMD(
> > -       usb,    5,      1,      do_usb,
> > +       usb,    6,      1,      do_usb,
> >         "USB sub-system",
> >         "start - start (scan) USB controller\n"
> >         "usb reset - reset (rescan) USB controller\n"
> > @@ -831,6 +1000,9 @@ U_BOOT_CMD(
> >         "usb test [dev] [port] [mode] - set USB 2.0 test mode\n"
> >         "    (specify port 0 to indicate the device's upstream port)\n"
> >         "    Available modes: J, K, S[E0_NAK], P[acket], F[orce_Enable]\n"
> > +       "usb regress waddr raddr size [iterations] - regress a USB device\n"
> > +       "    (starts, writes to waddr, reads from raddr, stops and verifies.\n"
> > +       "    `size' format 1B/1K/1M/1G)\n "
> >  #ifdef CONFIG_USB_STORAGE
> >         "usb storage - show details of USB storage devices\n"
> >         "usb dev [dev] - show or set current USB storage device\n"
> > --
> > 1.9.1
> >

Best Regards,
Rajesh Bhagat 


More information about the U-Boot mailing list