On Thu, 30 Oct 2008 12:59:49 +0100 Wolfgang Denk <[EMAIL PROTECTED]> wrote:
> In message <[EMAIL PROTECTED]> you wrote: > > > > Modifications to support console multiplexing. This is controlled using > > CONFIG_SYS_CONSOLE_MUX in the board configuration file. > > Is it correct to assume that this patch version does not yet include > any changes resultiung from the discussion we had yesterday how to > optimize timing behaviour? > Yes. It also doesn't appear to me that this has been resolved yet. > > > diff --git a/common/Makefile b/common/Makefile > > index f00cbd9..0296a8a 100644 > > --- a/common/Makefile > > +++ b/common/Makefile > > @@ -156,6 +156,7 @@ COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o > > COBJS-$(CONFIG_UPDATE_TFTP) += update.o > > COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o > > COBJS-$(CONFIG_DDR_SPD) += ddr_spd.o > > +COBJS-$(CONFIG_SYS_CONSOLE_MUX) += iomux.o > > As this is a user configurable option, it should be named > CONFIG_CONSOLE_MUX. Please remove the "SYS_" part. And please keep the > list sorted. > I chose this analogously to CONFIG_SYS_CONSOLE_IS_IN_ENV. Obviously I misunderstand something about how these names are chosen. Please enlighten me. > > @@ -115,7 +182,41 @@ void serial_printf (const char *fmt, ...) > > int fgetc (int file) > > { > > if (file < MAX_FILES) > > +#if defined(CONFIG_SYS_CONSOLE_MUX) > > + { > > Please move the braces outside the #ifdef. > OK > > + int cntr = 0; > > + > > + /* > > + * Effectively poll for input wherever it may be available. > > + */ > > + for (;;) { > > + /* > > + * Upper layer may have already called tstc() so > > + * check for that first. > > + */ > > + if (tstcdev != NULL) > > + return iomux_getc(); > > + iomux_tstc(file); > > + /* > > + * Even this is too slow for serial cut&paste due > > + * to the overhead of calling tstc() then getc(). > > + * It gets worse if nc is set as a console because > > + * nc_tstc() is rather slow. > > We discussed a potential solution to this problem yesterday. Do you > want to try this out in your implementation? > See my comment above. > > + * The idea behind this counter is to avoid calling > > + * the watchdog via udelay() too often. > > + * COUNT_TIL_UDELAY is defined in iomux.h and is just > > + * a guesstimate. > > + */ > > + if (cntr++ > COUNT_TIL_UDELAY) { > > + udelay(1); > > + cntr = 0; > > + } > > Please do not re-invent the wheel. If the watchdog triggering rate > needs to be limited then please use the CONFIG_WD_MAX_RATE parameter > as it was done in commit d32a874b "lwmon5 watchdog: limit trigger > rate". > Sounds good to me. I wasn't aware of CONFIG_WD_MAX_RATE. There are way too many undocumented options in u-boot. > > @@ -123,7 +224,11 @@ int fgetc (int file) > > int ftstc (int file) > > { > > if (file < MAX_FILES) > > +#if defined(CONFIG_SYS_CONSOLE_MUX) > > + return iomux_tstc(file); > > +#else > > return stdio_devices[file]->tstc (); > > +#endif > > > > return -1; > > } > > @@ -131,13 +236,21 @@ int ftstc (int file) > > void fputc (int file, const char c) > > { > > if (file < MAX_FILES) > > +#if defined(CONFIG_SYS_CONSOLE_MUX) > > + iomux_putc(file, c); > > +#else > > stdio_devices[file]->putc (c); > > +#endif > > } > > > > void fputs (int file, const char *s) > > { > > if (file < MAX_FILES) > > +#if defined(CONFIG_SYS_CONSOLE_MUX) > > + iomux_puts(file, s); > > +#else > > stdio_devices[file]->puts (s); > > +#endif > > } > > Would it be possible to just set > > stdio_devices[file]->tstc = iomux_tstc; > stdio_devices[file]->putc = iomux_putc; > stdio_devices[file]->puts = iomux_puts; > > ? > > This would eliminate the need for these #ifdef's (and possibly a few > more) ? > > > @@ -438,15 +562,34 @@ int console_init_r (void) > > } > > /* Initializes output console first */ > > if (outputdev != NULL) { > > +#ifdef CONFIG_SYS_CONSOLE_MUX > > + /* need to set a console if not done above. */ > > + iomux_doenv(stdout, outputdev->name); > > +#else > > console_setfile (stdout, outputdev); > > +#endif > > } > > if (errdev != NULL) { > > +#ifdef CONFIG_SYS_CONSOLE_MUX > > + /* need to set a console if not done above. */ > > + iomux_doenv(stderr, errdev->name); > > +#else > > console_setfile (stderr, errdev); > > +#endif > > } > > if (inputdev != NULL) { > > +#ifdef CONFIG_SYS_CONSOLE_MUX > > + /* need to set a console if not done above. */ > > + iomux_doenv(stdin, inputdev->name); > > +#else > > console_setfile (stdin, inputdev); > > +#endif > > } > > See above. Maybe these #ifdef's could be eliminated as well? > > > @@ -455,21 +598,33 @@ int console_init_r (void) > > if (stdio_devices[stdin] == NULL) { > > puts ("No input devices available!\n"); > > } else { > > +#ifdef CONFIG_SYS_CONSOLE_MUX > > + iomux_printdevs(stdin); > > +#else > > printf ("%s\n", stdio_devices[stdin]->name); > > +#endif > > } > > > > puts ("Out: "); > > if (stdio_devices[stdout] == NULL) { > > puts ("No output devices available!\n"); > > } else { > > +#ifdef CONFIG_SYS_CONSOLE_MUX > > + iomux_printdevs(stdout); > > +#else > > printf ("%s\n", stdio_devices[stdout]->name); > > +#endif > > } > > > > puts ("Err: "); > > if (stdio_devices[stderr] == NULL) { > > puts ("No error devices available!\n"); > > } else { > > +#ifdef CONFIG_SYS_CONSOLE_MUX > > + iomux_printdevs(stderr); > > +#else > > printf ("%s\n", stdio_devices[stderr]->name); > > +#endif > > } > > And these, too? > Seems like a good idea. I'll look at it. > > + int i; > > + device_t *dev; > > + > > + for (i = 0; i < cd_count[console]; i++) { > > + dev = console_devices[console][i]; > > + serial_printf("%s ", dev->name); > > + } > > + serial_printf("\n"); > > +} > > The old code uses plain printf(), while your new version explicitely > calls serial_printf(). I gues sthis is intentional? What is the > rationale behind it? > To avoid writing to e.g. nc before it's ready for output. > > +/* This tries to preserve the old list if an error occurs. */ > > +int iomux_doenv(const int console, const char *arg) > > +{ > > + char *console_args, *temp, **start; > > + int i, j, io_flag, cs_idx; > > + device_t *dev; > > + device_t **cons_set; > > + > > +#ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV > > + if (arg == NULL) > > + return 1; > > +#endif > > Do we need this special case test? > > > + console_args = strdup(arg); > > + if (console_args == NULL) > > + return 1; > > I think this test here would catch it as well? > Ah, I see that it's safe to pass NULL to strdup(). OK, I can simplify the code knowing that. > > + /* > > + * Check whether a comma separated list of devices was > > + * entered and count how many devices were entered. > > + * The array start[] has pointers to the beginning of > > + * each device name (up to MAX_CONSARGS devices). > > + * > > + * Have to do this twice - once to count the number of > > + * commas and then again to populate start. > > + */ > > + i = 0; > > + temp = console_args; > > + for (;;) { > > + temp = strchr(temp, ','); > > + if (temp != NULL) { > > + i++; > > + temp++; > > + continue; > > + } > > + /* There's always one entry more than the number of commas. */ > > + i++; > > + break; > > + } > > + start = (char **)malloc(i * sizeof(char *)); > > + if (start == NULL) { > > + free(console_args); > > + return 1; > > + } > > + i = 0; > > + start[0] = console_args; > > + for (;;) { > > + temp = strchr(start[i], ','); > > + if (temp != NULL) { > > + i++; > > + *temp = '\0'; > > + start[i] = temp + 1; > > + continue; > > + } > > + /* There's always one entry more than the number of commas. */ > > + i++; > > + break; > > + } > > I suggest to swap logic around as this allows for easier to read code: > > for (;;) { > temp = strchr(start[i++], ','); > if (temp == NULL) > break; > *temp = '\0'; > start[i] = temp + 1; > } > Seems reasonable, but I have to consider it in more detail. > > + cons_set = (device_t **)calloc(1, i * sizeof(device_t *)); > > Why not: > > cons_set = (device_t **)calloc(i, sizeof(device_t *)); > > ? > Hadn't thought of that. A good idea. > > + if (cons_set == NULL) { > > + free(start); > > + free(console_args); > > + return 1; > > + } > > + > > + switch (console) { > > + case stdin: > > + io_flag = DEV_FLAGS_INPUT; > > + break; > > + case stdout: > > + case stderr: > > + io_flag = DEV_FLAGS_OUTPUT; > > + break; > > + default: > > + return 1; > > Memory leak? free start & console_args & cons_set ?? > Yes, could be. I added default as an afterthought and didn't consider all its implications. > > +Two new files, common/iomux.c and include/iomux.h, contain the heart > > +of the environment setting implementation. > > It seems to me that they do much more than just setting environment > variables? > Their whole reason for their existence is to handle setenv. > > +The execution is then in common/cmd_nvedit.c and common/console.c. > > Hm... but cmd_nvedit.c really is for environment variables handling > only? > Yeah, the wording could be improved. > > +A user can use a comma-separated list of devices to set stdin, stdout > > +and stderr. For example: setenv stdin serial,nc. NOTE: No spaces > > Maybe it's better to quote the example to make it stand out: > > ...and stderr. For example: "setenv stdin serial,nc". NOTE: No spaces > > ? > I thought about that myself but didn't do it. > > +CAVEATS > > +------- > > + > > +Note that common/iomux.c calls console_assign() for every registered > > +device as it is discovered. This means that the environment settings > > +for application consoles will be set to the last device in the list. > > + > > +The overhead associated with calling tstc() and then getc() means that > > +copy&paste will normally not work, even if serial is set as the only device > > +for stdin, stdout and stderr. > > You should probably mention the conditions where you tested this with > such results. It probably depends on the system performance and the > console baud rate, doesn't it? > True. > > +Using nc as a stdin device results in even more overhead because nc_tstc() > > +is quite slow. > > There was discussion before how that could be accelerated. Has any > work spent on actually implementing / testing such measures? > Not by me. > > diff --git a/include/iomux.h b/include/iomux.h > > new file mode 100644 > > index 0000000..75b66e2 > > --- /dev/null > > +++ b/include/iomux.h > ... > > +/* > > + * Avoid invoking WATCHDOG via udelay() on every pass through the loop > > + * in fgetc(). Note this is all based on guesswork. > > + */ > > +#define COUNT_TIL_UDELAY 10000 > > I think we should use a more determinitic approach. See comment above. > I agree. --- Gary Jennejohn ********************************************************************* DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: [EMAIL PROTECTED] ********************************************************************* _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot