From: "Antonino A. Daplas" Accessing the hardware before it is properly initialized can lead to crashes or screen corruption. This happens when switching to X then back to console. When console comes back from X, the device is in an undefined state. During this window, accessing the hardware is disallowed. A new field in fbcon_par is added (graphics), which will be set to nonzero just before initialization of the framebuffer and when coming back from KD_GRAPHICS, then unset when an fb_set_var/fb_set_par is done. While this field is set, no accesses to the hardware is done. The consequence of this change is, hopefully, more robust switching between KD_GRAPHICS<-> KD_TEXT. An added benefit coming from this change is that the MODESWITCHLATE hack is not needed anymore and thus removed. This hack is used by savagefb, rivafb and nvidiafb. Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton --- 25-akpm/drivers/video/console/fbcon.c | 41 +++++++++---------------- 25-akpm/drivers/video/console/fbcon.h | 1 25-akpm/drivers/video/nvidia/nvidia.c | 3 + 25-akpm/drivers/video/riva/fbdev.c | 3 - 25-akpm/drivers/video/savage/savagefb_driver.c | 3 - 25-akpm/include/linux/fb.h | 4 -- 6 files changed, 22 insertions(+), 33 deletions(-) diff -puN drivers/video/console/fbcon.c~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized drivers/video/console/fbcon.c --- 25/drivers/video/console/fbcon.c~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized 2005-03-13 13:32:40.000000000 -0800 +++ 25-akpm/drivers/video/console/fbcon.c 2005-03-13 13:32:40.000000000 -0800 @@ -204,8 +204,10 @@ static irqreturn_t fb_vbl_detect(int irq static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) { + struct fbcon_ops *ops = info->fbcon_par; + return (info->state != FBINFO_STATE_RUNNING || - vc->vc_mode != KD_TEXT); + vc->vc_mode != KD_TEXT || ops->graphics); } static inline int get_color(struct vc_data *vc, struct fb_info *info, @@ -596,6 +598,8 @@ static void con2fb_init_display(struct v if (info->fbops->fb_set_par) info->fbops->fb_set_par(info); + ops->graphics = 0; + if (vc) fbcon_set_disp(info, &info->var, vc); else @@ -763,6 +767,7 @@ static const char *fbcon_startup(void) memset(ops, 0, sizeof(struct fbcon_ops)); ops->currcon = -1; + ops->graphics = 1; info->fbcon_par = ops; set_blitting_type(vc, info, NULL); @@ -949,6 +954,7 @@ static void fbcon_init(struct vc_data *v if (CON_IS_VISIBLE(vc) && info->fbops->fb_set_par) info->fbops->fb_set_par(info); + ((struct fbcon_ops *) info->fbcon_par)->graphics = 0; if ((cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED)) @@ -1871,7 +1877,6 @@ static int fbcon_resize(struct vc_data * var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; fb_set_var(info, &var); - info->flags &= ~FBINFO_MISC_MODESWITCH; } var_to_display(p, &info->var, info); } @@ -1884,7 +1889,7 @@ static int fbcon_switch(struct vc_data * struct fb_info *info; struct display *p = &fb_display[vc->vc_num]; struct fb_var_screeninfo var; - int i, prev_console, do_set_par = 0; + int i, prev_console; info = registered_fb[con2fb_map[vc->vc_num]]; @@ -1943,14 +1948,9 @@ static int fbcon_switch(struct vc_data * fb_set_var(info, &var); if (prev_console != -1 && - registered_fb[con2fb_map[prev_console]] != info) - do_set_par = 1; - - if (do_set_par || info->flags & FBINFO_MISC_MODESWITCH) { - if (info->fbops->fb_set_par) - info->fbops->fb_set_par(info); - info->flags &= ~FBINFO_MISC_MODESWITCH; - } + registered_fb[con2fb_map[prev_console]] != info && + info->fbops->fb_set_par) + info->fbops->fb_set_par(info); set_blitting_type(vc, info, p); ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1; @@ -2013,29 +2013,20 @@ static int fbcon_blank(struct vc_data *v { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; - int active = !fbcon_is_inactive(vc, info); if (mode_switch) { struct fb_var_screeninfo var = info->var; -/* - * HACK ALERT: Some hardware will require reinitializion at this stage, - * others will require it to be done as late as possible. - * For now, we differentiate this with the - * FBINFO_MISC_MODESWITCHLATE bitflag. Worst case will be - * hardware that requires it here and another one later. - * A definitive solution may require fixing X or the VT - * system. - */ - if (info->flags & FBINFO_MISC_MODESWITCHLATE) - info->flags |= FBINFO_MISC_MODESWITCH; - if (!blank && !(info->flags & FBINFO_MISC_MODESWITCHLATE)) { + ops->graphics = 1; + + if (!blank) { var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; fb_set_var(info, &var); + ops->graphics = 0; } } - if (active) { + if (!fbcon_is_inactive(vc, info)) { if (ops->blank_state != blank) { ops->blank_state = blank; fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); diff -puN drivers/video/console/fbcon.h~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized drivers/video/console/fbcon.h --- 25/drivers/video/console/fbcon.h~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized 2005-03-13 13:32:40.000000000 -0800 +++ 25-akpm/drivers/video/console/fbcon.h 2005-03-13 13:32:40.000000000 -0800 @@ -67,6 +67,7 @@ struct fbcon_ops { int cursor_flash; int cursor_reset; int blank_state; + int graphics; char *cursor_data; }; /* diff -puN drivers/video/nvidia/nvidia.c~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized drivers/video/nvidia/nvidia.c --- 25/drivers/video/nvidia/nvidia.c~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized 2005-03-13 13:32:40.000000000 -0800 +++ 25-akpm/drivers/video/nvidia/nvidia.c 2005-03-13 13:32:40.000000000 -0800 @@ -1191,6 +1191,7 @@ static int nvidiafb_check_var(struct fb_ var->yres_virtual = var->yres; var->xres_virtual = vramlen / var->yres_virtual; var->xres_virtual /= var->bits_per_pixel / 8; + var->xres_virtual &= ~63; pitch = (var->xres_virtual * var->bits_per_pixel + 7) / 8; memlen = pitch * var->yres; @@ -1301,7 +1302,7 @@ static int __devinit nvidia_set_fbinfo(s | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA - | FBINFO_HWACCEL_YPAN | FBINFO_MISC_MODESWITCHLATE; + | FBINFO_HWACCEL_YPAN; fb_videomode_to_modelist(info->monspecs.modedb, info->monspecs.modedb_len, &info->modelist); diff -puN drivers/video/riva/fbdev.c~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized drivers/video/riva/fbdev.c --- 25/drivers/video/riva/fbdev.c~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized 2005-03-13 13:32:40.000000000 -0800 +++ 25-akpm/drivers/video/riva/fbdev.c 2005-03-13 13:32:40.000000000 -0800 @@ -1708,8 +1708,7 @@ static int __devinit riva_set_fbinfo(str | FBINFO_HWACCEL_YPAN | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT - | FBINFO_HWACCEL_IMAGEBLIT - | FBINFO_MISC_MODESWITCHLATE; + | FBINFO_HWACCEL_IMAGEBLIT; /* Accel seems to not work properly on NV30 yet...*/ if ((par->riva.Architecture == NV_ARCH_30) || noaccel) { diff -puN drivers/video/savage/savagefb_driver.c~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized drivers/video/savage/savagefb_driver.c --- 25/drivers/video/savage/savagefb_driver.c~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized 2005-03-13 13:32:40.000000000 -0800 +++ 25-akpm/drivers/video/savage/savagefb_driver.c 2005-03-13 13:32:40.000000000 -0800 @@ -1883,8 +1883,7 @@ static int __devinit savage_init_fb_info info->fbops = &savagefb_ops; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | - FBINFO_HWACCEL_XPAN | - FBINFO_MISC_MODESWITCHLATE; + FBINFO_HWACCEL_XPAN; info->pseudo_palette = par->pseudo_palette; diff -puN include/linux/fb.h~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized include/linux/fb.h --- 25/include/linux/fb.h~fbcon-stop-framebuffer-operations-before-hardware-is-properly-initialized 2005-03-13 13:32:40.000000000 -0800 +++ 25-akpm/include/linux/fb.h 2005-03-13 13:32:40.000000000 -0800 @@ -702,9 +702,7 @@ struct fb_tile_ops { #define FBINFO_MISC_USEREVENT 0x10000 /* event request from userspace */ -#define FBINFO_MISC_MODESWITCH 0x20000 /* mode switch */ -#define FBINFO_MISC_MODESWITCHLATE 0x40000 /* init hardware later */ -#define FBINFO_MISC_TILEBLITTING 0x80000 /* use tile blitting */ +#define FBINFO_MISC_TILEBLITTING 0x20000 /* use tile blitting */ struct fb_info { int node; _