[PATCH v3 1/9] console: Introduce console_start() and console_stop()

In the future we would like to stop unused consoles and also add a reference counting to avoid imbalanced calls to ->start() and ->stop() in some cases.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org --- v3: added comments to the function declarations common/console.c | 30 +++++++++++++++++++++++------- include/console.h | 3 +++ 2 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/common/console.c b/common/console.c index 3348436da6f7..9973f96e7629 100644 --- a/common/console.c +++ b/common/console.c @@ -114,13 +114,9 @@ static int console_setfile(int file, struct stdio_dev * dev) case stdin: case stdout: case stderr: - /* Start new device */ - if (dev->start) { - error = dev->start(dev); - /* If it's not started dont use it */ - if (error < 0) - break; - } + error = console_start(file, dev); + if (error) + break;
/* Assign the new device (leaving the existing one started) */ stdio_devices[file] = dev; @@ -310,6 +306,26 @@ static inline void console_doenv(int file, struct stdio_dev *dev) #endif #endif /* CONIFIG_IS_ENABLED(CONSOLE_MUX) */
+int console_start(int file, struct stdio_dev *sdev) +{ + int error; + + /* Start new device */ + if (sdev->start) { + error = sdev->start(sdev); + /* If it's not started don't use it */ + if (error < 0) + return error; + } + return 0; +} + +void console_stop(int file, struct stdio_dev *sdev) +{ + if (sdev->stop) + sdev->stop(sdev); +} + /** U-Boot INITIAL CONSOLE-NOT COMPATIBLE FUNCTIONS *************************/
int serial_printf(const char *fmt, ...) diff --git a/include/console.h b/include/console.h index 432f892b6cce..58a4ec3f12ad 100644 --- a/include/console.h +++ b/include/console.h @@ -8,6 +8,7 @@ #define __CONSOLE_H
#include <stdbool.h> +#include <stdio_dev.h> #include <linux/errno.h>
extern char console_buffer[]; @@ -15,6 +16,8 @@ extern char console_buffer[]; /* common/console.c */ int console_init_f(void); /* Before relocation; uses the serial stuff */ int console_init_r(void); /* After relocation; uses the console stuff */ +int console_start(int file, struct stdio_dev *sdev); /* Start a console device */ +void console_stop(int file, struct stdio_dev *sdev); /* Stop a console device */ int console_assign(int file, const char *devname); /* Assign the console */ int ctrlc(void); int had_ctrlc(void); /* have we had a Control-C since last clear? */

There is no need to call ->start() for already started device. All the same, there is no need to call ->stop() for devices still in use.
For now enforce this only for IOMUX case.
Cc: Simon Glass sjg@chromium.org Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com --- v3: renamed new function and added a documentation for it common/console.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+)
diff --git a/common/console.c b/common/console.c index 9973f96e7629..e5fd214ae86f 100644 --- a/common/console.c +++ b/common/console.c @@ -174,6 +174,32 @@ static struct stdio_dev *tstcdev; struct stdio_dev **console_devices[MAX_FILES]; int cd_count[MAX_FILES];
+/** + * console_needs_start_stop() - check if we need to start or stop the STDIO device + * @file: STDIO file + * @sdev: STDIO device in question + * + * This function checks if we need to start or stop the stdio device used for + * a console. For IOMUX case it simply enforces one time start and one time + * stop of the device independently of how many STDIO files are using it. In + * other words, we start console once before first STDIO device wants it and + * stop after the last is gone. + */ +static bool console_needs_start_stop(int file, struct stdio_dev *sdev) +{ + int i, j; + + for (i = 0; i < ARRAY_SIZE(cd_count); i++) { + if (i == file) + continue; + + for (j = 0; j < cd_count[i]; j++) + if (console_devices[i][j] == sdev) + return false; + } + return true; +} + /* * This depends on tstc() always being called before getchar(). * This is guaranteed to be true because this routine is called @@ -272,6 +298,11 @@ static inline void console_doenv(int file, struct stdio_dev *dev) } #endif #else +static inline bool console_needs_start_stop(int file, struct stdio_dev *sdev) +{ + return true; +} + static inline int console_getc(int file) { return stdio_devices[file]->getc(stdio_devices[file]); @@ -310,6 +341,9 @@ int console_start(int file, struct stdio_dev *sdev) { int error;
+ if (!console_needs_start_stop(file, sdev)) + return 0; + /* Start new device */ if (sdev->start) { error = sdev->start(sdev); @@ -322,6 +356,9 @@ int console_start(int file, struct stdio_dev *sdev)
void console_stop(int file, struct stdio_dev *sdev) { + if (!console_needs_start_stop(file, sdev)) + return; + if (sdev->stop) sdev->stop(sdev); }

On Mon, 21 Dec 2020 at 05:30, Andy Shevchenko andriy.shevchenko@linux.intel.com wrote:
There is no need to call ->start() for already started device. All the same, there is no need to call ->stop() for devices still in use.
For now enforce this only for IOMUX case.
Cc: Simon Glass sjg@chromium.org Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com
v3: renamed new function and added a documentation for it common/console.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

On Mon, Dec 21, 2020 at 02:30:01PM +0200, Andy Shevchenko wrote:
There is no need to call ->start() for already started device. All the same, there is no need to call ->stop() for devices still in use.
For now enforce this only for IOMUX case.
Cc: Simon Glass sjg@chromium.org Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

search_device() is defined in console.c. Move its declaration to an appropriate header file.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org --- v3: added tag and changed subject prefix include/console.h | 2 ++ include/iomux.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/console.h b/include/console.h index 58a4ec3f12ad..4e06b13736c3 100644 --- a/include/console.h +++ b/include/console.h @@ -25,6 +25,8 @@ void clear_ctrlc(void); /* clear the Control-C condition */ int disable_ctrlc(int); /* 1 to disable, 0 to enable Control-C detect */ int confirm_yesno(void); /* 1 if input is "y", "Y", "yes" or "YES" */
+struct stdio_dev *search_device(int flags, const char *name); + #ifdef CONFIG_CONSOLE_RECORD /** * console_record_init() - set up the console recording buffers diff --git a/include/iomux.h b/include/iomux.h index e6e1097db5b2..da7ff697d218 100644 --- a/include/iomux.h +++ b/include/iomux.h @@ -26,6 +26,5 @@ extern int cd_count[MAX_FILES];
int iomux_doenv(const int, const char *); void iomux_printdevs(const int); -struct stdio_dev *search_device(int, const char *);
#endif /* _IO_MUX_H */

On Mon, Dec 21, 2020 at 02:30:02PM +0200, Andy Shevchenko wrote:
search_device() is defined in console.c. Move its declaration to an appropriate header file.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Rename search_device() to console_search_dev() since it's in console.h.
Suggested-by: Simon Glass sjg@chromium.org Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com --- v3: new patch common/console.c | 18 +++++++++--------- common/iomux.c | 4 ++-- common/stdio.c | 4 ++-- include/console.h | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/common/console.c b/common/console.c index e5fd214ae86f..a7ab50afa29f 100644 --- a/common/console.c +++ b/common/console.c @@ -778,7 +778,7 @@ void clear_ctrlc(void)
/** U-Boot INIT FUNCTIONS *************************************************/
-struct stdio_dev *search_device(int flags, const char *name) +struct stdio_dev *console_search_dev(int flags, const char *name) { struct stdio_dev *dev;
@@ -814,7 +814,7 @@ int console_assign(int file, const char *devname)
/* Check for valid device name */
- dev = search_device(flag, devname); + dev = console_search_dev(flag, devname);
if (dev) return console_setfile(file, dev); @@ -924,9 +924,9 @@ int console_init_r(void) stderrname = env_get("stderr");
if (OVERWRITE_CONSOLE == 0) { /* if not overwritten by config switch */ - inputdev = search_device(DEV_FLAGS_INPUT, stdinname); - outputdev = search_device(DEV_FLAGS_OUTPUT, stdoutname); - errdev = search_device(DEV_FLAGS_OUTPUT, stderrname); + inputdev = console_search_dev(DEV_FLAGS_INPUT, stdinname); + outputdev = console_search_dev(DEV_FLAGS_OUTPUT, stdoutname); + errdev = console_search_dev(DEV_FLAGS_OUTPUT, stderrname); #if CONFIG_IS_ENABLED(CONSOLE_MUX) iomux_err = iomux_doenv(stdin, stdinname); iomux_err += iomux_doenv(stdout, stdoutname); @@ -938,13 +938,13 @@ int console_init_r(void) } /* if the devices are overwritten or not found, use default device */ if (inputdev == NULL) { - inputdev = search_device(DEV_FLAGS_INPUT, "serial"); + inputdev = console_search_dev(DEV_FLAGS_INPUT, "serial"); } if (outputdev == NULL) { - outputdev = search_device(DEV_FLAGS_OUTPUT, "serial"); + outputdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial"); } if (errdev == NULL) { - errdev = search_device(DEV_FLAGS_OUTPUT, "serial"); + errdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial"); } /* Initializes output console first */ if (outputdev != NULL) { @@ -1018,7 +1018,7 @@ int console_init_r(void) */ if (env_get("splashimage") != NULL) { if (!(gd->flags & GD_FLG_SILENT)) - outputdev = search_device (DEV_FLAGS_OUTPUT, "serial"); + outputdev = console_search_dev (DEV_FLAGS_OUTPUT, "serial"); } #endif
diff --git a/common/iomux.c b/common/iomux.c index 7cfd9f2e9162..e1bd1b48cd03 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -95,10 +95,10 @@ int iomux_doenv(const int console, const char *arg) for (j = 0; j < i; j++) { /* * Check whether the device exists and is valid. - * console_assign() also calls search_device(), + * console_assign() also calls console_search_dev(), * but I need the pointer to the device. */ - dev = search_device(io_flag, start[j]); + dev = console_search_dev(io_flag, start[j]); if (dev == NULL) continue; /* diff --git a/common/stdio.c b/common/stdio.c index a15f30804bf5..abf9b1e91588 100644 --- a/common/stdio.c +++ b/common/stdio.c @@ -181,7 +181,7 @@ struct stdio_dev *stdio_get_by_name(const char *name) * 'stdout', which may include a list of devices separate by * commas. Obviously this is not going to work, so we ignore * that case. The call path in that case is - * console_init_r() -> search_device() -> stdio_get_by_name() + * console_init_r() -> console_search_dev() -> stdio_get_by_name() */ if (!strncmp(name, "vidconsole", 10) && !strchr(name, ',') && !stdio_probe_device(name, UCLASS_VIDEO, &sdev)) @@ -332,7 +332,7 @@ int stdio_add_devices(void) /* * If the console setting is not in environment variables then * console_init_r() will not be calling iomux_doenv() (which - * calls search_device()). So we will not dynamically add + * calls console_search_dev()). So we will not dynamically add * devices by calling stdio_probe_device(). * * So just probe all video devices now so that whichever one is diff --git a/include/console.h b/include/console.h index 4e06b13736c3..bb186e7be04d 100644 --- a/include/console.h +++ b/include/console.h @@ -25,7 +25,7 @@ void clear_ctrlc(void); /* clear the Control-C condition */ int disable_ctrlc(int); /* 1 to disable, 0 to enable Control-C detect */ int confirm_yesno(void); /* 1 if input is "y", "Y", "yes" or "YES" */
-struct stdio_dev *search_device(int flags, const char *name); +struct stdio_dev *console_search_dev(int flags, const char *name);
#ifdef CONFIG_CONSOLE_RECORD /**

On Mon, 21 Dec 2020 at 05:30, Andy Shevchenko andriy.shevchenko@linux.intel.com wrote:
Rename search_device() to console_search_dev() since it's in console.h.
Suggested-by: Simon Glass sjg@chromium.org Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com
v3: new patch common/console.c | 18 +++++++++--------- common/iomux.c | 4 ++-- common/stdio.c | 4 ++-- include/console.h | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

On Mon, Dec 21, 2020 at 02:30:03PM +0200, Andy Shevchenko wrote:
Rename search_device() to console_search_dev() since it's in console.h.
Suggested-by: Simon Glass sjg@chromium.org Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Provide a documentation for console_search_dev().
Suggested-by: Simon Glass sjg@chromium.org Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com --- v3: new patch include/console.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/include/console.h b/include/console.h index bb186e7be04d..7e628c0cf836 100644 --- a/include/console.h +++ b/include/console.h @@ -25,6 +25,16 @@ void clear_ctrlc(void); /* clear the Control-C condition */ int disable_ctrlc(int); /* 1 to disable, 0 to enable Control-C detect */ int confirm_yesno(void); /* 1 if input is "y", "Y", "yes" or "YES" */
+/** + * console_search_dev() - search for stdio device with given flags and name + * @flags: device flags as per input/output/system + * @name: device name + * + * Iterates over registered STDIO devices and match them with given @flags + * and @name. + * + * @return pointer to the &struct stdio_dev if found, or NULL otherwise + */ struct stdio_dev *console_search_dev(int flags, const char *name);
#ifdef CONFIG_CONSOLE_RECORD

On Mon, Dec 21, 2020 at 02:30:04PM +0200, Andy Shevchenko wrote:
Provide a documentation for console_search_dev().
Suggested-by: Simon Glass sjg@chromium.org Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com
Applied to u-boot/master, thanks!

It's realloc() 101 to avoid `foo = realloc(foo, ...);` call due to getting a memory leak.
Actually it's not clear why realloc() has been used here. If we shrink the array, the memcpy() overwrites it anyway with the contents of a new array. If it becomes bigger, same story.
Drop useless realloc() for good and thus preserve console list in case of failed allocation.
Fixes: 16a28ef219c2 ("IOMUX: Add console multiplexing support.") Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org --- v3: added tag common/iomux.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/common/iomux.c b/common/iomux.c index e1bd1b48cd03..7b7b063cfc6b 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -129,19 +129,10 @@ int iomux_doenv(const int console, const char *arg) return 1; } else { /* Works even if console_devices[console] is NULL. */ - console_devices[console] = - (struct stdio_dev **)realloc(console_devices[console], - cs_idx * sizeof(struct stdio_dev *)); - if (console_devices[console] == NULL) { - free(cons_set); - return 1; - } - memcpy(console_devices[console], cons_set, cs_idx * - sizeof(struct stdio_dev *)); - + free(console_devices[console]); + console_devices[console] = cons_set; cd_count[console] = cs_idx; } - free(cons_set); return 0; } #endif /* CONSOLE_MUX */

On Mon, Dec 21, 2020 at 02:30:05PM +0200, Andy Shevchenko wrote:
It's realloc() 101 to avoid `foo = realloc(foo, ...);` call due to getting a memory leak.
Actually it's not clear why realloc() has been used here. If we shrink the array, the memcpy() overwrites it anyway with the contents of a new array. If it becomes bigger, same story.
Drop useless realloc() for good and thus preserve console list in case of failed allocation.
Fixes: 16a28ef219c2 ("IOMUX: Add console multiplexing support.") Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Refactor iomux_doenv() a bit in order to increase readability. There is no change in code generation on x86.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org --- v3: added tag common/iomux.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/common/iomux.c b/common/iomux.c index 7b7b063cfc6b..7991235d1197 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -45,15 +45,14 @@ int iomux_doenv(const int console, const char *arg) 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; + + temp = strchr(temp, ','); + if (temp == NULL) + break; + + temp++; } start = (char **)malloc(i * sizeof(char *)); if (start == NULL) {

On Mon, Dec 21, 2020 at 02:30:06PM +0200, Andy Shevchenko wrote:
Refactor iomux_doenv() a bit in order to increase readability. There is no change in code generation on x86.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

Obviously the following has unnecessary indentation level in 'else' branch.
if (foo) { ... return; } else { ... }
Drop indentation level by removing redundant 'else'.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org --- v3: added tag common/iomux.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/common/iomux.c b/common/iomux.c index 7991235d1197..126d92ce850f 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -126,12 +126,12 @@ int iomux_doenv(const int console, const char *arg) if (cs_idx == 0) { free(cons_set); return 1; - } else { - /* Works even if console_devices[console] is NULL. */ - free(console_devices[console]); - console_devices[console] = cons_set; - cd_count[console] = cs_idx; } + + /* Works even if console_devices[console] is NULL. */ + free(console_devices[console]); + console_devices[console] = cons_set; + cd_count[console] = cs_idx; return 0; } #endif /* CONSOLE_MUX */

On Mon, Dec 21, 2020 at 02:30:07PM +0200, Andy Shevchenko wrote:
Obviously the following has unnecessary indentation level in 'else' branch.
if (foo) { ... return; } else { ... }
Drop indentation level by removing redundant 'else'.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

When at some point environment shrinks we need to stop dropped devices.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org --- v3: added tag common/iomux.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/common/iomux.c b/common/iomux.c index 126d92ce850f..15bf53388559 100644 --- a/common/iomux.c +++ b/common/iomux.c @@ -27,8 +27,8 @@ int iomux_doenv(const int console, const char *arg) { char *console_args, *temp, **start; int i, j, k, io_flag, cs_idx, repeat; + struct stdio_dev **cons_set, **old_set; struct stdio_dev *dev; - struct stdio_dev **cons_set;
console_args = strdup(arg); if (console_args == NULL) @@ -128,10 +128,23 @@ int iomux_doenv(const int console, const char *arg) return 1; }
- /* Works even if console_devices[console] is NULL. */ - free(console_devices[console]); + old_set = console_devices[console]; + repeat = cd_count[console]; + console_devices[console] = cons_set; cd_count[console] = cs_idx; + + /* Stop dropped consoles */ + for (i = 0; i < repeat; i++) { + for (j = 0; j < cs_idx; j++) { + if (old_set[i] == cons_set[j]) + break; + } + if (j == cs_idx) + console_stop(console, old_set[i]); + } + + free(old_set); return 0; } #endif /* CONSOLE_MUX */

On Mon, Dec 21, 2020 at 02:30:08PM +0200, Andy Shevchenko wrote:
When at some point environment shrinks we need to stop dropped devices.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!

On Mon, Dec 21, 2020 at 02:30:00PM +0200, Andy Shevchenko wrote:
In the future we would like to stop unused consoles and also add a reference counting to avoid imbalanced calls to ->start() and ->stop() in some cases.
Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!
participants (3)
-
Andy Shevchenko
-
Simon Glass
-
Tom Rini