console: Fix pre-console flushing via cfb_console being very slow

On my A10 OlinuxIno Lime I noticed a huge (5+ seconds) delay coming from
console_init_r. This turns out to be caused by the preconsole buffer flushing
to the cfb_console. The Lime only has a 16 bit memory bus and that is already
heavy used to scan out the 1920x1080 framebuffer.

The problem is that print_pre_console_buffer() was printing the buffer once
character at a time and the cfb_console code then ends up doing a cache-flush
for touched display lines for each character.

This commit fixes this by first building a 0 terminated buffer and then
printing it in one puts() call, avoiding unnecessary cache flushes.

This changes the time for the flush from 5+ seconds to not noticable.

The downside of this approach is that the pre-console buffer needs to fit
on the stack, this is not that much to ask since we are talking about plain
text here. This commit also adjusts the sunxi CONFIG_PRE_CON_BUF_SZ to
actually fit on the stack. Sunxi currently is the only user of the pre-console
code so no other boards need to be adjusted.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
This commit is contained in:
Hans de Goede 2015-05-05 13:13:36 +02:00
parent f9b08fbf11
commit a8552c7c9b
3 changed files with 26 additions and 19 deletions

3
README
View File

@ -948,6 +948,9 @@ The following options need to be configured:
bytes are output before the console is initialised, the bytes are output before the console is initialised, the
earlier bytes are discarded. earlier bytes are discarded.
Note that when printing the buffer a copy is made on the
stack so CONFIG_PRE_CON_BUF_SZ must fit on the stack.
'Sane' compilers will generate smaller code if 'Sane' compilers will generate smaller code if
CONFIG_PRE_CON_BUF_SZ is a power of 2 CONFIG_PRE_CON_BUF_SZ is a power of 2

View File

@ -200,15 +200,15 @@ static void console_putc(int file, const char c)
} }
#ifdef CONFIG_PRE_CONSOLE_BUFFER #ifdef CONFIG_PRE_CONSOLE_BUFFER
static void console_putc_noserial(int file, const char c) static void console_puts_noserial(int file, const char *s)
{ {
int i; int i;
struct stdio_dev *dev; struct stdio_dev *dev;
for (i = 0; i < cd_count[file]; i++) { for (i = 0; i < cd_count[file]; i++) {
dev = console_devices[file][i]; dev = console_devices[file][i];
if (dev->putc != NULL && strcmp(dev->name, "serial") != 0) if (dev->puts != NULL && strcmp(dev->name, "serial") != 0)
dev->putc(dev, c); dev->puts(dev, s);
} }
} }
#endif #endif
@ -251,10 +251,10 @@ static inline void console_putc(int file, const char c)
} }
#ifdef CONFIG_PRE_CONSOLE_BUFFER #ifdef CONFIG_PRE_CONSOLE_BUFFER
static inline void console_putc_noserial(int file, const char c) static inline void console_puts_noserial(int file, const char *s)
{ {
if (strcmp(stdio_devices[file]->name, "serial") != 0) if (strcmp(stdio_devices[file]->name, "serial") != 0)
stdio_devices[file]->putc(stdio_devices[file], c); stdio_devices[file]->puts(stdio_devices[file], s);
} }
#endif #endif
@ -425,22 +425,26 @@ static void pre_console_puts(const char *s)
static void print_pre_console_buffer(int flushpoint) static void print_pre_console_buffer(int flushpoint)
{ {
unsigned long i = 0; unsigned long in = 0, out = 0;
char *buffer = (char *)CONFIG_PRE_CON_BUF_ADDR; char *buf_in = (char *)CONFIG_PRE_CON_BUF_ADDR;
char buf_out[CONFIG_PRE_CON_BUF_SZ + 1];
if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ) if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ)
i = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ; in = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ;
while (i < gd->precon_buf_idx) while (in < gd->precon_buf_idx)
switch (flushpoint) { buf_out[out++] = buf_in[CIRC_BUF_IDX(in++)];
case PRE_CONSOLE_FLUSHPOINT1_SERIAL:
putc(buffer[CIRC_BUF_IDX(i++)]); buf_out[out] = 0;
break;
case PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL: switch (flushpoint) {
console_putc_noserial(stdout, case PRE_CONSOLE_FLUSHPOINT1_SERIAL:
buffer[CIRC_BUF_IDX(i++)]); puts(buf_out);
break; break;
} case PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL:
console_puts_noserial(stdout, buf_out);
break;
}
} }
#else #else
static inline void pre_console_putc(const char c) {} static inline void pre_console_putc(const char c) {}

View File

@ -336,7 +336,7 @@ extern int soft_i2c_gpio_scl;
/* Enable pre-console buffer to get complete log on the VGA console */ /* Enable pre-console buffer to get complete log on the VGA console */
#define CONFIG_PRE_CONSOLE_BUFFER #define CONFIG_PRE_CONSOLE_BUFFER
#define CONFIG_PRE_CON_BUF_SZ (1024 * 1024) #define CONFIG_PRE_CON_BUF_SZ 4096 /* Aprox 2 80*25 screens */
/* Use the room between the end of bootm_size and the framebuffer */ /* Use the room between the end of bootm_size and the framebuffer */
#define CONFIG_PRE_CON_BUF_ADDR 0x4f000000 #define CONFIG_PRE_CON_BUF_ADDR 0x4f000000