diff options
author | Antonino Daplas <adaplas@hotpop.com> | 2005-03-30 16:42:48 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-03-30 16:42:48 -0800 |
commit | 2859de99c8a8f32ee7287d2c01e268b7e64bdd2a (patch) | |
tree | d0efe20d402194f680f242996a08d03a8ebce062 | |
parent | 835b1e211a24ffce3115b25f39882108a1af5386 (diff) | |
download | history-2859de99c8a8f32ee7287d2c01e268b7e64bdd2a.tar.gz |
[PATCH] fbcon: Stop framebuffer operations before hardware is properly initialized
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 <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/video/console/fbcon.c | 41 | ||||
-rw-r--r-- | drivers/video/console/fbcon.h | 1 | ||||
-rw-r--r-- | drivers/video/nvidia/nvidia.c | 3 | ||||
-rw-r--r-- | drivers/video/riva/fbdev.c | 3 | ||||
-rw-r--r-- | drivers/video/savage/savagefb_driver.c | 3 | ||||
-rw-r--r-- | include/linux/fb.h | 4 |
6 files changed, 22 insertions, 33 deletions
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index de92afb5eecf4d..f51a71f323a383 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -204,8 +204,10 @@ static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp) 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 vc_data *vc, struct fb_info *info, 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 *vc, int init) 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 *vc, unsigned int width, 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 *vc) 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 *vc) 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 *vc, int blank, int mode_switch) { 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 --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 30e641160bf674..80c8dbb8424a07 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -67,6 +67,7 @@ struct fbcon_ops { int cursor_flash; int cursor_reset; int blank_state; + int graphics; char *cursor_data; }; /* diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 2dfecddc308e30..05ea3a31be9a5a 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -1191,6 +1191,7 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var, 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(struct fb_info *info) | 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 --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 7a6e82567ff897..5c5714a7dde634 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -1708,8 +1708,7 @@ static int __devinit riva_set_fbinfo(struct fb_info *info) | 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 --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 301cef041a4e02..e1c9c946be2dc2 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -1883,8 +1883,7 @@ static int __devinit savage_init_fb_info (struct fb_info *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 --git a/include/linux/fb.h b/include/linux/fb.h index 9d1507c87cecc5..b45d3e2d711a38 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -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; |