Commit 0333d835 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Linus Torvalds

ps3fb: use fb_info.par properly

ps3fb: Use fb_info.par properly:
  o Move mode-specific fields into struct ps3fb_par
  o Allocate struct ps3fb_par using framebuffer_alloc()
  o Protect access to ps3fb_par in ps3fb_sync() using the console semaphore
    (this semaphore is already held when ps3fb_set_par() is called)
  o Avoid calling ps3av_set_video_mode() if the actual video mode hasn't
    changed
Signed-off-by: default avatarGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 2ce32e15
...@@ -119,12 +119,10 @@ struct ps3fb_priv { ...@@ -119,12 +119,10 @@ struct ps3fb_priv {
void *xdr_ea; void *xdr_ea;
size_t xdr_size; size_t xdr_size;
struct gpu_driver_info *dinfo; struct gpu_driver_info *dinfo;
u32 res_index;
u64 vblank_count; /* frame count */ u64 vblank_count; /* frame count */
wait_queue_head_t wait_vsync; wait_queue_head_t wait_vsync;
u32 num_frames; /* num of frame buffers */
atomic_t ext_flip; /* on/off flip with vsync */ atomic_t ext_flip; /* on/off flip with vsync */
atomic_t f_count; /* fb_open count */ atomic_t f_count; /* fb_open count */
int is_blanked; int is_blanked;
...@@ -133,6 +131,13 @@ struct ps3fb_priv { ...@@ -133,6 +131,13 @@ struct ps3fb_priv {
}; };
static struct ps3fb_priv ps3fb; static struct ps3fb_priv ps3fb;
struct ps3fb_par {
u32 pseudo_palette[16];
int mode_id, new_mode_id;
int res_index;
unsigned int num_frames; /* num of frame buffers */
};
struct ps3fb_res_table { struct ps3fb_res_table {
u32 xres; u32 xres;
u32 yres; u32 yres;
...@@ -361,18 +366,17 @@ static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, ...@@ -361,18 +366,17 @@ static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
pr_debug("ps3fb_find_mode: mode not found\n"); pr_debug("ps3fb_find_mode: mode not found\n");
return 0; return 0;
} }
static const struct fb_videomode *ps3fb_default_mode(void) static const struct fb_videomode *ps3fb_default_mode(int id)
{ {
u32 mode = ps3fb_mode & PS3AV_MODE_MASK; u32 mode = id & PS3AV_MODE_MASK;
u32 flags; u32 flags;
if (mode < 1 || mode > 13) if (mode < 1 || mode > 13)
return NULL; return NULL;
flags = ps3fb_mode & ~PS3AV_MODE_MASK; flags = id & ~PS3AV_MODE_MASK;
if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) { if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
/* Full broadcast mode */ /* Full broadcast mode */
...@@ -384,18 +388,22 @@ static const struct fb_videomode *ps3fb_default_mode(void) ...@@ -384,18 +388,22 @@ static const struct fb_videomode *ps3fb_default_mode(void)
static int ps3fb_sync(struct fb_info *info, u32 frame) static int ps3fb_sync(struct fb_info *info, u32 frame)
{ {
int i, status; struct ps3fb_par *par = info->par;
int i, status, error = 0;
u32 xres, yres; u32 xres, yres;
u64 fb_ioif, offset; u64 fb_ioif, offset;
i = ps3fb.res_index; acquire_console_sem();
i = par->res_index;
xres = ps3fb_res[i].xres; xres = ps3fb_res[i].xres;
yres = ps3fb_res[i].yres; yres = ps3fb_res[i].yres;
if (frame > ps3fb.num_frames - 1) { if (frame > par->num_frames - 1) {
dev_dbg(info->device, "%s: invalid frame number (%u)\n", dev_dbg(info->device, "%s: invalid frame number (%u)\n",
__func__, frame); __func__, frame);
return -EINVAL; error = -EINVAL;
goto out;
} }
offset = xres * yres * BPP * frame; offset = xres * yres * BPP * frame;
...@@ -428,7 +436,10 @@ static int ps3fb_sync(struct fb_info *info, u32 frame) ...@@ -428,7 +436,10 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
"%s: lv1_gpu_context_attribute FLIP failed: %d\n", "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
__func__, status); __func__, status);
#endif #endif
return 0;
out:
release_console_sem();
return error;
} }
...@@ -547,6 +558,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -547,6 +558,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static int ps3fb_set_par(struct fb_info *info) static int ps3fb_set_par(struct fb_info *info)
{ {
struct ps3fb_par *par = info->par;
unsigned int mode; unsigned int mode;
int i; int i;
unsigned long offset; unsigned long offset;
...@@ -560,7 +572,7 @@ static int ps3fb_set_par(struct fb_info *info) ...@@ -560,7 +572,7 @@ static int ps3fb_set_par(struct fb_info *info)
return -EINVAL; return -EINVAL;
i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode); i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
ps3fb.res_index = i; par->res_index = i;
offset = VFB_OFF(i); offset = VFB_OFF(i);
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset; info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset;
...@@ -568,14 +580,19 @@ static int ps3fb_set_par(struct fb_info *info) ...@@ -568,14 +580,19 @@ static int ps3fb_set_par(struct fb_info *info)
info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset; info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size); memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
ps3fb.num_frames = info->fix.smem_len/ par->num_frames = info->fix.smem_len/
(ps3fb_res[i].xres*ps3fb_res[i].yres*BPP); (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP);
/* Keep the special bits we cannot set using fb_var_screeninfo */ /* Keep the special bits we cannot set using fb_var_screeninfo */
ps3fb_mode = (ps3fb_mode & ~PS3AV_MODE_MASK) | mode; par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
if (ps3av_set_video_mode(ps3fb_mode)) if (par->new_mode_id != par->mode_id) {
if (ps3av_set_video_mode(par->new_mode_id)) {
par->new_mode_id = par->mode_id;
return -EINVAL; return -EINVAL;
}
par->mode_id = par->new_mode_id;
}
return 0; return 0;
} }
...@@ -694,7 +711,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -694,7 +711,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
u32 val, old_mode; u32 val;
int retval = -EFAULT; int retval = -EFAULT;
switch (cmd) { switch (cmd) {
...@@ -724,6 +741,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -724,6 +741,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
case PS3FB_IOCTL_SETMODE: case PS3FB_IOCTL_SETMODE:
{ {
struct ps3fb_par *par = info->par;
const struct fb_videomode *mode; const struct fb_videomode *mode;
struct fb_var_screeninfo var; struct fb_var_screeninfo var;
...@@ -737,9 +755,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -737,9 +755,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
} }
dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val); dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
retval = -EINVAL; retval = -EINVAL;
old_mode = ps3fb_mode; mode = ps3fb_default_mode(val);
ps3fb_mode = val;
mode = ps3fb_default_mode();
if (mode) { if (mode) {
var = info->var; var = info->var;
fb_videomode_to_var(&var, mode); fb_videomode_to_var(&var, mode);
...@@ -747,12 +763,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -747,12 +763,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
info->flags |= FBINFO_MISC_USEREVENT; info->flags |= FBINFO_MISC_USEREVENT;
/* Force, in case only special bits changed */ /* Force, in case only special bits changed */
var.activate |= FB_ACTIVATE_FORCE; var.activate |= FB_ACTIVATE_FORCE;
par->new_mode_id = val;
retval = fb_set_var(info, &var); retval = fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_USEREVENT; info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem(); release_console_sem();
} }
if (retval)
ps3fb_mode = old_mode;
break; break;
} }
...@@ -765,14 +780,15 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, ...@@ -765,14 +780,15 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
case PS3FB_IOCTL_SCREENINFO: case PS3FB_IOCTL_SCREENINFO:
{ {
struct ps3fb_par *par = info->par;
struct ps3fb_ioctl_res res; struct ps3fb_ioctl_res res;
int i = ps3fb.res_index; int i = par->res_index;
dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n"); dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n");
res.xres = ps3fb_res[i].xres; res.xres = ps3fb_res[i].xres;
res.yres = ps3fb_res[i].yres; res.yres = ps3fb_res[i].yres;
res.xoff = ps3fb_res[i].xoff; res.xoff = ps3fb_res[i].xoff;
res.yoff = ps3fb_res[i].yoff; res.yoff = ps3fb_res[i].yoff;
res.num_frames = ps3fb.num_frames; res.num_frames = par->num_frames;
if (!copy_to_user(argp, &res, sizeof(res))) if (!copy_to_user(argp, &res, sizeof(res)))
retval = 0; retval = 0;
break; break;
...@@ -979,6 +995,7 @@ static int ps3fb_set_sync(struct device *dev) ...@@ -979,6 +995,7 @@ static int ps3fb_set_sync(struct device *dev)
static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
{ {
struct fb_info *info; struct fb_info *info;
struct ps3fb_par *par;
int retval = -ENOMEM; int retval = -ENOMEM;
u32 xres, yres; u32 xres, yres;
u64 ddr_lpar = 0; u64 ddr_lpar = 0;
...@@ -987,7 +1004,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) ...@@ -987,7 +1004,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
u64 lpar_reports = 0; u64 lpar_reports = 0;
u64 lpar_reports_size = 0; u64 lpar_reports_size = 0;
u64 xdr_lpar; u64 xdr_lpar;
int status; int status, res_index;
unsigned long offset; unsigned long offset;
struct task_struct *task; struct task_struct *task;
...@@ -1004,15 +1021,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) ...@@ -1004,15 +1021,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
if (ps3fb_mode > 0 && if (ps3fb_mode > 0 &&
!ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
ps3fb.res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode); res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
dev_dbg(&dev->core, "res_index:%d\n", ps3fb.res_index); dev_dbg(&dev->core, "res_index:%d\n", res_index);
} else } else
ps3fb.res_index = GPU_RES_INDEX; res_index = GPU_RES_INDEX;
atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
init_waitqueue_head(&ps3fb.wait_vsync); init_waitqueue_head(&ps3fb.wait_vsync);
ps3fb.num_frames = 1;
ps3fb_set_sync(&dev->core); ps3fb_set_sync(&dev->core);
...@@ -1062,19 +1078,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) ...@@ -1062,19 +1078,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
if (retval) if (retval)
goto err_free_irq; goto err_free_irq;
info = framebuffer_alloc(sizeof(u32) * 16, &dev->core); info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
if (!info) if (!info)
goto err_free_irq; goto err_free_irq;
offset = VFB_OFF(ps3fb.res_index); par = info->par;
par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
par->new_mode_id = ps3fb_mode;
par->res_index = res_index;
par->num_frames = 1;
offset = VFB_OFF(res_index);
info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset; info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
info->fbops = &ps3fb_ops; info->fbops = &ps3fb_ops;
info->fix = ps3fb_fix; info->fix = ps3fb_fix;
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset; info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset;
info->fix.smem_len = ps3fb.xdr_size - offset; info->fix.smem_len = ps3fb.xdr_size - offset;
info->pseudo_palette = info->par; info->pseudo_palette = par->pseudo_palette;
info->par = NULL;
info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST; info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
retval = fb_alloc_cmap(&info->cmap, 256, 0); retval = fb_alloc_cmap(&info->cmap, 256, 0);
...@@ -1082,7 +1103,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) ...@@ -1082,7 +1103,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
goto err_framebuffer_release; goto err_framebuffer_release;
if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb, if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
ARRAY_SIZE(ps3fb_modedb), ps3fb_default_mode(), 32)) { ARRAY_SIZE(ps3fb_modedb),
ps3fb_default_mode(par->new_mode_id), 32)) {
retval = -EINVAL; retval = -EINVAL;
goto err_fb_dealloc; goto err_fb_dealloc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment