diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index ba689d42792d..af587ff02e43 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2391,6 +2391,10 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, font_data_t *old_fontdata = p->fontdata; const u8 *old_data = vc->vc_font.data; unsigned short old_hi_font_mask = vc->vc_hi_font_mask; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION + struct fbcon_rotated saved_rotated = { }; + bool rotated_saved = false; +#endif font_data_get(data); @@ -2409,6 +2413,27 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, else if (!vc->vc_hi_font_mask && charcount == 512) set_vc_hi_font(vc, true); + /* + * Select the console's blitting state and update par->rotated to + * match the new font, so that the rendering below does not use a + * cache that was built for the old font. Clear the cached state so + * the rebuild allocates a fresh buffer; the old state is kept until + * the font change can no longer fail. + */ + if (con_is_visible(vc)) { + set_blitting_type(vc, info); + if (par->bitops->rotate_font) { +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION + saved_rotated = par->rotated; + memset(&par->rotated, 0, sizeof(par->rotated)); + rotated_saved = true; +#endif + ret = par->bitops->rotate_font(info, vc); + if (ret) + goto err_out; + } + } + if (resize) { int cols, rows; @@ -2425,12 +2450,26 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, update_screen(vc); } +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION + if (rotated_saved) + kfree(saved_rotated.buf); +#endif if (old_fontdata) font_data_put(old_fontdata); return 0; err_out: +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION + /* + * Drop the buffer built for the new font and restore the saved + * state. + */ + if (rotated_saved) { + kfree(par->rotated.buf); + par->rotated = saved_rotated; + } +#endif p->fontdata = old_fontdata; vc->vc_font.data = old_data; vc->vc_font.width = old_width; @@ -2443,6 +2482,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount, else if (!old_hi_font_mask && vc->vc_hi_font_mask) set_vc_hi_font(vc, false); + /* + * Re-select the blitting type, which re-uploads the font map on + * tile-blitting hardware. + */ + if (con_is_visible(vc)) + set_blitting_type(vc, info); + font_data_put(data); return ret; diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h index 91b59b2990d2..d93a89877d04 100644 --- a/drivers/video/fbdev/core/fbcon.h +++ b/drivers/video/fbdev/core/fbcon.h @@ -72,6 +72,18 @@ struct fbcon_bitops { int (*rotate_font)(struct fb_info *info, struct vc_data *vc); }; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION +struct fbcon_rotated { + font_data_t *fontdata; /* source font */ + u8 *buf; /* rotated glyphs */ + size_t bufsize; + int buf_rotate; /* rotation of buf */ + unsigned int buf_width; /* geometry of source font */ + unsigned int buf_height; + unsigned int buf_charcount; +}; +#endif + struct fbcon_par { struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ struct delayed_work cursor_work; /* Cursor timer */ @@ -88,15 +100,7 @@ struct fbcon_par { int rotate; char *cursor_data; #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION - struct { - font_data_t *fontdata; /* source font */ - u8 *buf; /* rotated glyphs */ - size_t bufsize; - int buf_rotate; /* rotation of buf */ - unsigned int buf_width; /* geometry of source font */ - unsigned int buf_height; - unsigned int buf_charcount; - } rotated; + struct fbcon_rotated rotated; #endif u8 *cursor_src; u32 cursor_size;