Skip to content

Commit

Permalink
cirrusfb: check_par fixes
Browse files Browse the repository at this point in the history
1. Check if virtual resolution fits into memory.
   Otherwise, Linux hangs during panning.
2. When selected use all available memory to
    maximize yres_virtual to speed up panning
   (previously also xres_virtual was increased).
3. Simplify memory restriction calculations.

Signed-off-by: Krzysztof Helt <krzysztof.h1@poczta.fm>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Krzysztof Helt authored and Linus Torvalds committed Sep 3, 2008
1 parent 950bbab commit 09a2910
Showing 1 changed file with 18 additions and 41 deletions.
59 changes: 18 additions & 41 deletions drivers/video/cirrusfb.c
Original file line number Diff line number Diff line change
Expand Up @@ -628,27 +628,18 @@ static long cirrusfb_get_mclk(long freq, int bpp, long *div)
static int cirrusfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
int nom, den; /* translyting from pixels->bytes */
int yres, i;
static struct { int xres, yres; } modes[] =
{ { 1600, 1280 },
{ 1280, 1024 },
{ 1024, 768 },
{ 800, 600 },
{ 640, 480 },
{ -1, -1 } };
int yres;
/* memory size in pixels */
unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;

switch (var->bits_per_pixel) {
case 1:
nom = 4;
den = 8;
pixels /= 4;
break; /* 8 pixel per byte, only 1/4th of mem usable */
case 8:
case 16:
case 24:
case 32:
nom = var->bits_per_pixel / 8;
den = 1;
break; /* 1 pixel == 1 byte */
default:
printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
Expand All @@ -658,43 +649,29 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
return -EINVAL;
}

if (var->xres * nom / den * var->yres > info->screen_size) {
printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
"resolution too high to fit into video memory!\n",
var->xres, var->yres, var->bits_per_pixel);
DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}

if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
/* use highest possible virtual resolution */
if (var->xres_virtual == -1 &&
var->yres_virtual == -1) {
printk(KERN_INFO
"cirrusfb: using maximum available virtual resolution\n");
for (i = 0; modes[i].xres != -1; i++) {
int size = modes[i].xres * nom / den * modes[i].yres;
if (size < info->screen_size / 2)
break;
}
if (modes[i].xres == -1) {
printk(KERN_ERR "cirrusfb: could not find a virtual "
"resolution that fits into video memory!!\n");
DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
var->xres_virtual = modes[i].xres;
var->yres_virtual = modes[i].yres;
if (var->yres_virtual == -1) {
var->yres_virtual = pixels / var->xres_virtual;

printk(KERN_INFO "cirrusfb: virtual resolution set to "
"maximum of %dx%d\n", var->xres_virtual,
var->yres_virtual);
}

if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;

if (var->xres_virtual * var->yres_virtual > pixels) {
printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... "
"virtual resolution too high to fit into video memory!\n",
var->xres_virtual, var->yres_virtual,
var->bits_per_pixel);
DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}


if (var->xoffset < 0)
var->xoffset = 0;
if (var->yoffset < 0)
Expand Down

0 comments on commit 09a2910

Please sign in to comment.