diff options
Diffstat (limited to 'drivers/firmware/efi/earlycon.c')
-rw-r--r-- | drivers/firmware/efi/earlycon.c | 41 |
1 files changed, 30 insertions, 11 deletions
diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c index 4d6c5327471a..f54e6fdf08e2 100644 --- a/drivers/firmware/efi/earlycon.c +++ b/drivers/firmware/efi/earlycon.c @@ -10,11 +10,14 @@ #include <linux/kernel.h> #include <linux/serial_core.h> #include <linux/screen_info.h> +#include <linux/string.h> #include <asm/early_ioremap.h> static const struct console *earlycon_console __initdata; static const struct font_desc *font; +static u16 cur_line_y, max_line_y; +static u32 efi_x_array[1024]; static u32 efi_x, efi_y; static u64 fb_base; static bool fb_wb; @@ -85,9 +88,17 @@ static void efi_earlycon_clear_scanline(unsigned int y) static void efi_earlycon_scroll_up(void) { unsigned long *dst, *src; + u16 maxlen = 0; u16 len; u32 i, height; + /* Find the cached maximum x coordinate */ + for (i = 0; i < max_line_y; i++) { + if (efi_x_array[i] > maxlen) + maxlen = efi_x_array[i]; + } + maxlen *= 4; + len = screen_info.lfb_linelength; height = screen_info.lfb_height; @@ -102,7 +113,7 @@ static void efi_earlycon_scroll_up(void) return; } - memmove(dst, src, len); + memmove(dst, src, maxlen); efi_earlycon_unmap(src, len); efi_earlycon_unmap(dst, len); @@ -135,6 +146,7 @@ static void efi_earlycon_write(struct console *con, const char *str, unsigned int num) { struct screen_info *si; + u32 cur_efi_x = efi_x; unsigned int len; const char *s; void *dst; @@ -143,16 +155,10 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) len = si->lfb_linelength; while (num) { - unsigned int linemax; - unsigned int h, count = 0; - - for (s = str; *s && *s != '\n'; s++) { - if (count == num) - break; - count++; - } + unsigned int linemax = (si->lfb_width - efi_x) / font->width; + unsigned int h, count; - linemax = (si->lfb_width - efi_x) / font->width; + count = strnchrnul(str, num, '\n') - str; if (count > linemax) count = linemax; @@ -181,6 +187,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) str += count; if (num > 0 && *s == '\n') { + cur_efi_x = efi_x; efi_x = 0; efi_y += font->height; str++; @@ -188,6 +195,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) } if (efi_x + font->width > si->lfb_width) { + cur_efi_x = efi_x; efi_x = 0; efi_y += font->height; } @@ -195,6 +203,9 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) if (efi_y + font->height > si->lfb_height) { u32 i; + efi_x_array[cur_line_y] = cur_efi_x; + cur_line_y = (cur_line_y + 1) % max_line_y; + efi_y -= font->height; efi_earlycon_scroll_up(); @@ -235,7 +246,15 @@ static int __init efi_earlycon_setup(struct earlycon_device *device, if (!font) return -ENODEV; - efi_y = rounddown(yres, font->height) - font->height; + /* Fill the cache with maximum possible value of x coordinate */ + memset32(efi_x_array, rounddown(xres, font->width), ARRAY_SIZE(efi_x_array)); + efi_y = rounddown(yres, font->height); + + /* Make sure we have cache for the x coordinate for the full screen */ + max_line_y = efi_y / font->height + 1; + cur_line_y = 0; + + efi_y -= font->height; for (i = 0; i < (yres - efi_y) / font->height; i++) efi_earlycon_scroll_up(); |