Merge branch '2022-09-24-add-console-flush' into next

To quote the author:
On certain places it is required to flush output print buffers to ensure
that text strings were sent to console or serial devices. For example when
printing message that U-Boot is going to boot kernel or when U-Boot is
going to change baudrate of terminal device.

Some console devices, like UART, have putc/puts functions which just put
characters into HW transmit queue and do not wait until all data are
transmitted. Doing some sensitive operations (like changing baudrate or
starting kernel which resets UART HW) cause that U-Boot messages are lost.

Therefore introduce a new flush() function, implement it for all serial
devices via pending(false) callback and use this new flush() function on
sensitive places after which output device may go into reset state.

This change fixes printing of U-Boot messages:
"## Starting application at ..."
"## Switch baudrate to ..."

In addition, take a patch from Heinrich to rename some EFI test
functions in order to not conflict with this series.
This commit is contained in:
Tom Rini 2022-09-24 13:58:49 -04:00
commit 81da5042e5
15 changed files with 205 additions and 43 deletions

View file

@ -669,6 +669,11 @@ void os_puts(const char *str)
os_putc(*str++);
}
void os_flush(void)
{
fflush(stdout);
}
int os_write_ram_buf(const char *fname)
{
struct sandbox_state *state = state_get_current();

View file

@ -303,6 +303,7 @@ static void do_bootvx_fdt(bootm_headers_t *images)
#else
printf("## Starting vxWorks at 0x%08lx\n", (ulong)images->ep);
#endif
flush();
boot_jump_vxworks(images);

View file

@ -32,6 +32,7 @@ static int do_go(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
addr = hextoul(argv[1], NULL);
printf ("## Starting application at 0x%08lX ...\n", addr);
flush();
/*
* pass address parameter as argv[0] (aka command name),

View file

@ -72,6 +72,7 @@ int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
return rcode;
printf("## Starting application at 0x%08lx ...\n", addr);
flush();
/*
* pass address parameter as argv[0] (aka command name),
@ -274,6 +275,7 @@ int do_bootvx(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
puts("## Not an ELF image, assuming binary\n");
printf("## Starting vxWorks at 0x%08lx ...\n", addr);
flush();
dcache_disable();
#if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)

View file

@ -83,6 +83,7 @@ static int do_load_serial(struct cmd_tbl *cmdtp, int flag, int argc,
printf("## Switch baudrate to %d bps and press ENTER ...\n",
load_baudrate);
udelay(50000);
flush();
gd->baudrate = load_baudrate;
serial_setbrg();
udelay(50000);
@ -126,6 +127,7 @@ static int do_load_serial(struct cmd_tbl *cmdtp, int flag, int argc,
printf("## Switch baudrate to %d bps and press ESC ...\n",
current_baudrate);
udelay(50000);
flush();
gd->baudrate = current_baudrate;
serial_setbrg();
udelay(50000);
@ -317,6 +319,7 @@ int do_save_serial(struct cmd_tbl *cmdtp, int flag, int argc,
printf("## Switch baudrate to %d bps and press ESC ...\n",
(int)current_baudrate);
udelay(50000);
flush();
gd->baudrate = current_baudrate;
serial_setbrg();
udelay(50000);
@ -471,6 +474,7 @@ static int do_load_serial_bin(struct cmd_tbl *cmdtp, int flag, int argc,
printf("## Switch baudrate to %d bps and press ENTER ...\n",
load_baudrate);
udelay(50000);
flush();
gd->baudrate = load_baudrate;
serial_setbrg();
udelay(50000);
@ -533,6 +537,7 @@ static int do_load_serial_bin(struct cmd_tbl *cmdtp, int flag, int argc,
printf("## Switch baudrate to %d bps and press ESC ...\n",
current_baudrate);
udelay(50000);
flush();
gd->baudrate = current_baudrate;
serial_setbrg();
udelay(50000);

View file

@ -186,6 +186,12 @@ config PRE_CON_BUF_ADDR
We should consider removing this option and allocating the memory
in board_init_f_init_reserve() instead.
config CONSOLE_FLUSH_SUPPORT
bool "Enable console flush support"
default y
help
This enables compilation of flush() function for console flush support.
config CONSOLE_MUX
bool "Enable console multiplexing"
default y if DM_VIDEO || VIDEO || LCD

View file

@ -199,6 +199,7 @@ static int console_setfile(int file, struct stdio_dev * dev)
case stdout:
gd->jt->putc = putc;
gd->jt->puts = puts;
STDIO_DEV_ASSIGN_FLUSH(gd->jt, flush);
gd->jt->printf = printf;
break;
}
@ -364,6 +365,19 @@ static void console_puts(int file, const char *s)
}
}
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
static void console_flush(int file)
{
int i;
struct stdio_dev *dev;
for_each_console_dev(i, file, dev) {
if (dev->flush != NULL)
dev->flush(dev);
}
}
#endif
#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
static inline void console_doenv(int file, struct stdio_dev *dev)
{
@ -413,6 +427,14 @@ static inline void console_puts(int file, const char *s)
stdio_devices[file]->puts(stdio_devices[file], s);
}
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
static inline void console_flush(int file)
{
if (stdio_devices[file]->flush)
stdio_devices[file]->flush(stdio_devices[file]);
}
#endif
#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
static inline void console_doenv(int file, struct stdio_dev *dev)
{
@ -526,6 +548,14 @@ void fputs(int file, const char *s)
console_puts(file, s);
}
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
void fflush(int file)
{
if (file < MAX_FILES)
console_flush(file);
}
#endif
int fprintf(int file, const char *fmt, ...)
{
va_list args;
@ -740,6 +770,40 @@ void puts(const char *s)
}
}
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
void flush(void)
{
if (!gd)
return;
/* sandbox can send characters to stdout before it has a console */
if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
os_flush();
return;
}
if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY))
return;
if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
return;
if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
return;
if (!gd->have_console)
return;
if (gd->flags & GD_FLG_DEVINIT) {
/* Send to the standard output */
fflush(stdout);
} else {
/* Send directly to the handler */
serial_flush();
}
}
#endif
#ifdef CONFIG_CONSOLE_RECORD
int console_record_init(void)
{

View file

@ -87,6 +87,13 @@ static void stdio_serial_puts(struct stdio_dev *dev, const char *s)
serial_puts(s);
}
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
static void stdio_serial_flush(struct stdio_dev *dev)
{
serial_flush();
}
#endif
static int stdio_serial_getc(struct stdio_dev *dev)
{
return serial_getc();
@ -112,6 +119,7 @@ static void drv_system_init (void)
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
dev.putc = stdio_serial_putc;
dev.puts = stdio_serial_puts;
STDIO_DEV_ASSIGN_FLUSH(&dev, stdio_serial_flush);
dev.getc = stdio_serial_getc;
dev.tstc = stdio_serial_tstc;
stdio_register (&dev);

View file

@ -238,6 +238,18 @@ static void _serial_puts(struct udevice *dev, const char *str)
} while (*str);
}
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
static void _serial_flush(struct udevice *dev)
{
struct dm_serial_ops *ops = serial_get_ops(dev);
if (!ops->pending)
return;
while (ops->pending(dev, false) > 0)
;
}
#endif
static int __serial_getc(struct udevice *dev)
{
struct dm_serial_ops *ops = serial_get_ops(dev);
@ -315,6 +327,16 @@ void serial_puts(const char *str)
_serial_puts(gd->cur_serial_dev, str);
}
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
void serial_flush(void)
{
if (!gd->cur_serial_dev)
return;
_serial_flush(gd->cur_serial_dev);
}
#endif
int serial_getc(void)
{
if (!gd->cur_serial_dev)
@ -398,6 +420,13 @@ static void serial_stub_puts(struct stdio_dev *sdev, const char *str)
_serial_puts(sdev->priv, str);
}
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
static void serial_stub_flush(struct stdio_dev *sdev)
{
_serial_flush(sdev->priv);
}
#endif
static int serial_stub_getc(struct stdio_dev *sdev)
{
return _serial_getc(sdev->priv);
@ -447,6 +476,7 @@ static int on_baudrate(const char *name, const char *value, enum env_op op,
printf("## Switch baudrate to %d bps and press ENTER ...\n",
baudrate);
udelay(50000);
flush();
}
gd->baudrate = baudrate;
@ -520,6 +550,7 @@ static int serial_post_probe(struct udevice *dev)
sdev.priv = dev;
sdev.putc = serial_stub_putc;
sdev.puts = serial_stub_puts;
STDIO_DEV_ASSIGN_FLUSH(&sdev, serial_stub_flush);
sdev.getc = serial_stub_getc;
sdev.tstc = serial_stub_tstc;

View file

@ -12,6 +12,9 @@
EXPORT_FUNC(tstc, int, tstc, void)
EXPORT_FUNC(putc, void, putc, const char)
EXPORT_FUNC(puts, void, puts, const char *)
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
EXPORT_FUNC(flush, void, flush, void)
#endif
EXPORT_FUNC(printf, int, printf, const char*, ...)
#if (defined(CONFIG_X86) && !defined(CONFIG_X86_64)) || defined(CONFIG_PPC)
EXPORT_FUNC(irq_install_handler, void, install_hdlr,

View file

@ -295,6 +295,14 @@ void os_putc(int ch);
*/
void os_puts(const char *str);
/**
* os_flush() - flush controlling OS terminal
*
* This bypasses the U-Boot console support and flushes directly the OS
* stdout file descriptor.
*/
void os_flush(void);
/**
* os_write_ram_buf() - write the sandbox RAM buffer to a existing file
*

View file

@ -362,6 +362,11 @@ void serial_setbrg(void);
void serial_putc(const char ch);
void serial_putc_raw(const char ch);
void serial_puts(const char *str);
#if defined(CONFIG_CONSOLE_FLUSH_SUPPORT) && CONFIG_IS_ENABLED(DM_SERIAL)
void serial_flush(void);
#else
static inline void serial_flush(void) {}
#endif
int serial_getc(void);
int serial_tstc(void);

View file

@ -15,6 +15,11 @@ int tstc(void);
defined(CONFIG_SPL_SERIAL))
void putc(const char c);
void puts(const char *s);
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
void flush(void);
#else
static inline void flush(void) {}
#endif
int __printf(1, 2) printf(const char *fmt, ...);
int vprintf(const char *fmt, va_list args);
#else
@ -26,6 +31,10 @@ static inline void puts(const char *s)
{
}
static inline void flush(void)
{
}
static inline int __printf(1, 2) printf(const char *fmt, ...)
{
return 0;
@ -48,11 +57,17 @@ static inline int vprintf(const char *fmt, va_list args)
/* stderr */
#define eputc(c) fputc(stderr, c)
#define eputs(s) fputs(stderr, s)
#define eflush() fflush(stderr)
#define eprintf(fmt, args...) fprintf(stderr, fmt, ##args)
int __printf(2, 3) fprintf(int file, const char *fmt, ...);
void fputs(int file, const char *s);
void fputc(int file, const char c);
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
void fflush(int file);
#else
static inline void fflush(int file) {}
#endif
int ftstc(int file);
int fgetc(int file);

View file

@ -37,6 +37,13 @@ struct stdio_dev {
void (*putc)(struct stdio_dev *dev, const char c);
/* To put a string (accelerator) */
void (*puts)(struct stdio_dev *dev, const char *s);
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
/* To flush output queue */
void (*flush)(struct stdio_dev *dev);
#define STDIO_DEV_ASSIGN_FLUSH(dev, flush_func) ((dev)->flush = (flush_func))
#else
#define STDIO_DEV_ASSIGN_FLUSH(dev, flush_func)
#endif
/* INPUT functions */

View file

@ -142,38 +142,39 @@ static struct efi_file_system_info *file_system_info =
&priv_file_system_info.info;
/* Forward definitions of file and file system functions */
static efi_status_t EFIAPI open_volume
static efi_status_t EFIAPI efi_st_open_volume
(struct efi_simple_file_system_protocol *this,
struct efi_file_handle **root);
static efi_status_t EFIAPI open
static efi_status_t EFIAPI efi_st_open
(struct efi_file_handle *this,
struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode, u64 attributes);
static efi_status_t EFIAPI close(struct efi_file_handle *this);
static efi_status_t EFIAPI efi_st_close(struct efi_file_handle *this);
static efi_status_t EFIAPI delete(struct efi_file_handle *this);
static efi_status_t EFIAPI efi_st_delete(struct efi_file_handle *this);
static efi_status_t EFIAPI read
static efi_status_t EFIAPI efi_st_read
(struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer);
static efi_status_t EFIAPI write
static efi_status_t EFIAPI efi_st_write
(struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer);
static efi_status_t EFIAPI getpos(struct efi_file_handle *this, u64 *pos);
static efi_status_t EFIAPI efi_st_getpos(struct efi_file_handle *this,
u64 *pos);
static efi_status_t EFIAPI setpos(struct efi_file_handle *this, u64 pos);
static efi_status_t EFIAPI efi_st_setpos(struct efi_file_handle *this, u64 pos);
static efi_status_t EFIAPI getinfo
static efi_status_t EFIAPI efi_st_getinfo
(struct efi_file_handle *this, const efi_guid_t *info_type,
efi_uintn_t *buffer_size, void *buffer);
static efi_status_t EFIAPI setinfo
static efi_status_t EFIAPI efi_st_setinfo
(struct efi_file_handle *this, const efi_guid_t *info_type,
efi_uintn_t buffer_size, void *buffer);
static efi_status_t EFIAPI flush(struct efi_file_handle *this);
static efi_status_t EFIAPI efi_st_flush(struct efi_file_handle *this);
/* Internal information about status of file system */
static struct {
@ -190,40 +191,40 @@ static struct {
/* EFI_FILE_PROTOCOL for file */
static struct efi_file_handle file = {
.rev = 0x00010000,
.open = open,
.close = close,
.delete = delete,
.read = read,
.write = write,
.getpos = getpos,
.setpos = setpos,
.getinfo = getinfo,
.setinfo = setinfo,
.flush = flush,
.open = efi_st_open,
.close = efi_st_close,
.delete = efi_st_delete,
.read = efi_st_read,
.write = efi_st_write,
.getpos = efi_st_getpos,
.setpos = efi_st_setpos,
.getinfo = efi_st_getinfo,
.setinfo = efi_st_setinfo,
.flush = efi_st_flush,
};
/* EFI_FILE_PROTOCOL for root directory */
static struct efi_file_handle volume = {
.rev = 0x00010000,
.open = open,
.close = close,
.delete = delete,
.read = read,
.write = write,
.getpos = getpos,
.setpos = setpos,
.getinfo = getinfo,
.setinfo = setinfo,
.flush = flush,
.open = efi_st_open,
.close = efi_st_close,
.delete = efi_st_delete,
.read = efi_st_read,
.write = efi_st_write,
.getpos = efi_st_getpos,
.setpos = efi_st_setpos,
.getinfo = efi_st_getinfo,
.setinfo = efi_st_setinfo,
.flush = efi_st_flush,
};
/* EFI_SIMPLE_FILE_SYSTEM_PROTOCOL of the block device */
struct efi_simple_file_system_protocol file_system = {
.rev = 0x00010000,
.open_volume = open_volume,
.open_volume = efi_st_open_volume,
};
static efi_status_t EFIAPI open_volume
static efi_status_t EFIAPI efi_st_open_volume
(struct efi_simple_file_system_protocol *this,
struct efi_file_handle **root)
{
@ -236,7 +237,7 @@ static efi_status_t EFIAPI open_volume
return EFI_SUCCESS;
}
static efi_status_t EFIAPI open
static efi_status_t EFIAPI efi_st_open
(struct efi_file_handle *this,
struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode, u64 attributes)
@ -251,7 +252,7 @@ static efi_status_t EFIAPI open
return EFI_SUCCESS;
}
static efi_status_t EFIAPI close(struct efi_file_handle *this)
static efi_status_t EFIAPI efi_st_close(struct efi_file_handle *this)
{
if (this == &file)
priv.file_open_count--;
@ -263,7 +264,7 @@ static efi_status_t EFIAPI close(struct efi_file_handle *this)
return EFI_SUCCESS;
}
static efi_status_t EFIAPI delete(struct efi_file_handle *this)
static efi_status_t EFIAPI efi_st_delete(struct efi_file_handle *this)
{
if (this != &file)
return EFI_INVALID_PARAMETER;
@ -271,7 +272,7 @@ static efi_status_t EFIAPI delete(struct efi_file_handle *this)
return EFI_UNSUPPORTED;
}
static efi_status_t EFIAPI read
static efi_status_t EFIAPI efi_st_read
(struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer)
{
if (this != &file)
@ -288,7 +289,7 @@ static efi_status_t EFIAPI read
return EFI_SUCCESS;
}
static efi_status_t EFIAPI write
static efi_status_t EFIAPI efi_st_write
(struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer)
{
if (this != &file)
@ -297,7 +298,7 @@ static efi_status_t EFIAPI write
return EFI_UNSUPPORTED;
}
static efi_status_t EFIAPI getpos(struct efi_file_handle *this, u64 *pos)
static efi_status_t EFIAPI efi_st_getpos(struct efi_file_handle *this, u64 *pos)
{
if (this != &file)
return EFI_INVALID_PARAMETER;
@ -307,7 +308,7 @@ static efi_status_t EFIAPI getpos(struct efi_file_handle *this, u64 *pos)
return EFI_SUCCESS;
}
static efi_status_t EFIAPI setpos(struct efi_file_handle *this, u64 pos)
static efi_status_t EFIAPI efi_st_setpos(struct efi_file_handle *this, u64 pos)
{
if (this != &file)
return EFI_INVALID_PARAMETER;
@ -317,7 +318,7 @@ static efi_status_t EFIAPI setpos(struct efi_file_handle *this, u64 pos)
return EFI_SUCCESS;
}
static efi_status_t EFIAPI getinfo
static efi_status_t EFIAPI efi_st_getinfo
(struct efi_file_handle *this, const efi_guid_t *info_type,
efi_uintn_t *buffer_size, void *buffer)
{
@ -348,7 +349,7 @@ static efi_status_t EFIAPI getinfo
return EFI_SUCCESS;
}
static efi_status_t EFIAPI setinfo
static efi_status_t EFIAPI efi_st_setinfo
(struct efi_file_handle *this, const efi_guid_t *info_type,
efi_uintn_t buffer_size, void *buffer)
{
@ -358,7 +359,7 @@ static efi_status_t EFIAPI setinfo
return EFI_UNSUPPORTED;
}
static efi_status_t EFIAPI flush(struct efi_file_handle *this)
static efi_status_t EFIAPI efi_st_flush(struct efi_file_handle *this)
{
if (this != &file)
return EFI_INVALID_PARAMETER;