aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntonino Daplas <adaplas@hotpop.com>2005-03-30 16:42:48 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-03-30 16:42:48 -0800
commit2859de99c8a8f32ee7287d2c01e268b7e64bdd2a (patch)
treed0efe20d402194f680f242996a08d03a8ebce062
parent835b1e211a24ffce3115b25f39882108a1af5386 (diff)
downloadhistory-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.c41
-rw-r--r--drivers/video/console/fbcon.h1
-rw-r--r--drivers/video/nvidia/nvidia.c3
-rw-r--r--drivers/video/riva/fbdev.c3
-rw-r--r--drivers/video/savage/savagefb_driver.c3
-rw-r--r--include/linux/fb.h4
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;