aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/ps3fb.c
diff options
context:
space:
mode:
authorGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>2007-10-16 04:29:48 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:21 -0400
commit0333d83509c7d8496c8965b5ba9bc0c98e83c259 (patch)
treea0ce0a75b5e8770f7f7c2b2b1d88ba77a56afaaa /drivers/video/ps3fb.c
parent2ce32e15a16312d2c29c8bb188bf95bc821fdab6 (diff)
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: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/ps3fb.c')
-rw-r--r--drivers/video/ps3fb.c92
1 files changed, 57 insertions, 35 deletions
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 8bbe479f73f7..d6160e016b33 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -119,12 +119,10 @@ struct ps3fb_priv {
119 void *xdr_ea; 119 void *xdr_ea;
120 size_t xdr_size; 120 size_t xdr_size;
121 struct gpu_driver_info *dinfo; 121 struct gpu_driver_info *dinfo;
122 u32 res_index;
123 122
124 u64 vblank_count; /* frame count */ 123 u64 vblank_count; /* frame count */
125 wait_queue_head_t wait_vsync; 124 wait_queue_head_t wait_vsync;
126 125
127 u32 num_frames; /* num of frame buffers */
128 atomic_t ext_flip; /* on/off flip with vsync */ 126 atomic_t ext_flip; /* on/off flip with vsync */
129 atomic_t f_count; /* fb_open count */ 127 atomic_t f_count; /* fb_open count */
130 int is_blanked; 128 int is_blanked;
@@ -133,6 +131,13 @@ struct ps3fb_priv {
133}; 131};
134static struct ps3fb_priv ps3fb; 132static struct ps3fb_priv ps3fb;
135 133
134struct ps3fb_par {
135 u32 pseudo_palette[16];
136 int mode_id, new_mode_id;
137 int res_index;
138 unsigned int num_frames; /* num of frame buffers */
139};
140
136struct ps3fb_res_table { 141struct ps3fb_res_table {
137 u32 xres; 142 u32 xres;
138 u32 yres; 143 u32 yres;
@@ -361,18 +366,17 @@ static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
361 366
362 pr_debug("ps3fb_find_mode: mode not found\n"); 367 pr_debug("ps3fb_find_mode: mode not found\n");
363 return 0; 368 return 0;
364
365} 369}
366 370
367static const struct fb_videomode *ps3fb_default_mode(void) 371static const struct fb_videomode *ps3fb_default_mode(int id)
368{ 372{
369 u32 mode = ps3fb_mode & PS3AV_MODE_MASK; 373 u32 mode = id & PS3AV_MODE_MASK;
370 u32 flags; 374 u32 flags;
371 375
372 if (mode < 1 || mode > 13) 376 if (mode < 1 || mode > 13)
373 return NULL; 377 return NULL;
374 378
375 flags = ps3fb_mode & ~PS3AV_MODE_MASK; 379 flags = id & ~PS3AV_MODE_MASK;
376 380
377 if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) { 381 if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
378 /* Full broadcast mode */ 382 /* Full broadcast mode */
@@ -384,18 +388,22 @@ static const struct fb_videomode *ps3fb_default_mode(void)
384 388
385static int ps3fb_sync(struct fb_info *info, u32 frame) 389static int ps3fb_sync(struct fb_info *info, u32 frame)
386{ 390{
387 int i, status; 391 struct ps3fb_par *par = info->par;
392 int i, status, error = 0;
388 u32 xres, yres; 393 u32 xres, yres;
389 u64 fb_ioif, offset; 394 u64 fb_ioif, offset;
390 395
391 i = ps3fb.res_index; 396 acquire_console_sem();
397
398 i = par->res_index;
392 xres = ps3fb_res[i].xres; 399 xres = ps3fb_res[i].xres;
393 yres = ps3fb_res[i].yres; 400 yres = ps3fb_res[i].yres;
394 401
395 if (frame > ps3fb.num_frames - 1) { 402 if (frame > par->num_frames - 1) {
396 dev_dbg(info->device, "%s: invalid frame number (%u)\n", 403 dev_dbg(info->device, "%s: invalid frame number (%u)\n",
397 __func__, frame); 404 __func__, frame);
398 return -EINVAL; 405 error = -EINVAL;
406 goto out;
399 } 407 }
400 offset = xres * yres * BPP * frame; 408 offset = xres * yres * BPP * frame;
401 409
@@ -428,7 +436,10 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
428 "%s: lv1_gpu_context_attribute FLIP failed: %d\n", 436 "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
429 __func__, status); 437 __func__, status);
430#endif 438#endif
431 return 0; 439
440out:
441 release_console_sem();
442 return error;
432} 443}
433 444
434 445
@@ -547,6 +558,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
547 558
548static int ps3fb_set_par(struct fb_info *info) 559static int ps3fb_set_par(struct fb_info *info)
549{ 560{
561 struct ps3fb_par *par = info->par;
550 unsigned int mode; 562 unsigned int mode;
551 int i; 563 int i;
552 unsigned long offset; 564 unsigned long offset;
@@ -560,7 +572,7 @@ static int ps3fb_set_par(struct fb_info *info)
560 return -EINVAL; 572 return -EINVAL;
561 573
562 i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode); 574 i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
563 ps3fb.res_index = i; 575 par->res_index = i;
564 576
565 offset = VFB_OFF(i); 577 offset = VFB_OFF(i);
566 info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset; 578 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 info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset; 580 info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
569 memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size); 581 memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
570 582
571 ps3fb.num_frames = info->fix.smem_len/ 583 par->num_frames = info->fix.smem_len/
572 (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP); 584 (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP);
573 585
574 /* Keep the special bits we cannot set using fb_var_screeninfo */ 586 /* Keep the special bits we cannot set using fb_var_screeninfo */
575 ps3fb_mode = (ps3fb_mode & ~PS3AV_MODE_MASK) | mode; 587 par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
576 588
577 if (ps3av_set_video_mode(ps3fb_mode)) 589 if (par->new_mode_id != par->mode_id) {
578 return -EINVAL; 590 if (ps3av_set_video_mode(par->new_mode_id)) {
591 par->new_mode_id = par->mode_id;
592 return -EINVAL;
593 }
594 par->mode_id = par->new_mode_id;
595 }
579 596
580 return 0; 597 return 0;
581} 598}
@@ -694,7 +711,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
694 unsigned long arg) 711 unsigned long arg)
695{ 712{
696 void __user *argp = (void __user *)arg; 713 void __user *argp = (void __user *)arg;
697 u32 val, old_mode; 714 u32 val;
698 int retval = -EFAULT; 715 int retval = -EFAULT;
699 716
700 switch (cmd) { 717 switch (cmd) {
@@ -724,6 +741,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
724 741
725 case PS3FB_IOCTL_SETMODE: 742 case PS3FB_IOCTL_SETMODE:
726 { 743 {
744 struct ps3fb_par *par = info->par;
727 const struct fb_videomode *mode; 745 const struct fb_videomode *mode;
728 struct fb_var_screeninfo var; 746 struct fb_var_screeninfo var;
729 747
@@ -737,9 +755,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
737 } 755 }
738 dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val); 756 dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
739 retval = -EINVAL; 757 retval = -EINVAL;
740 old_mode = ps3fb_mode; 758 mode = ps3fb_default_mode(val);
741 ps3fb_mode = val;
742 mode = ps3fb_default_mode();
743 if (mode) { 759 if (mode) {
744 var = info->var; 760 var = info->var;
745 fb_videomode_to_var(&var, mode); 761 fb_videomode_to_var(&var, mode);
@@ -747,12 +763,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
747 info->flags |= FBINFO_MISC_USEREVENT; 763 info->flags |= FBINFO_MISC_USEREVENT;
748 /* Force, in case only special bits changed */ 764 /* Force, in case only special bits changed */
749 var.activate |= FB_ACTIVATE_FORCE; 765 var.activate |= FB_ACTIVATE_FORCE;
766 par->new_mode_id = val;
750 retval = fb_set_var(info, &var); 767 retval = fb_set_var(info, &var);
751 info->flags &= ~FBINFO_MISC_USEREVENT; 768 info->flags &= ~FBINFO_MISC_USEREVENT;
752 release_console_sem(); 769 release_console_sem();
753 } 770 }
754 if (retval)
755 ps3fb_mode = old_mode;
756 break; 771 break;
757 } 772 }
758 773
@@ -765,14 +780,15 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
765 780
766 case PS3FB_IOCTL_SCREENINFO: 781 case PS3FB_IOCTL_SCREENINFO:
767 { 782 {
783 struct ps3fb_par *par = info->par;
768 struct ps3fb_ioctl_res res; 784 struct ps3fb_ioctl_res res;
769 int i = ps3fb.res_index; 785 int i = par->res_index;
770 dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n"); 786 dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n");
771 res.xres = ps3fb_res[i].xres; 787 res.xres = ps3fb_res[i].xres;
772 res.yres = ps3fb_res[i].yres; 788 res.yres = ps3fb_res[i].yres;
773 res.xoff = ps3fb_res[i].xoff; 789 res.xoff = ps3fb_res[i].xoff;
774 res.yoff = ps3fb_res[i].yoff; 790 res.yoff = ps3fb_res[i].yoff;
775 res.num_frames = ps3fb.num_frames; 791 res.num_frames = par->num_frames;
776 if (!copy_to_user(argp, &res, sizeof(res))) 792 if (!copy_to_user(argp, &res, sizeof(res)))
777 retval = 0; 793 retval = 0;
778 break; 794 break;
@@ -979,6 +995,7 @@ static int ps3fb_set_sync(struct device *dev)
979static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) 995static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
980{ 996{
981 struct fb_info *info; 997 struct fb_info *info;
998 struct ps3fb_par *par;
982 int retval = -ENOMEM; 999 int retval = -ENOMEM;
983 u32 xres, yres; 1000 u32 xres, yres;
984 u64 ddr_lpar = 0; 1001 u64 ddr_lpar = 0;
@@ -987,7 +1004,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
987 u64 lpar_reports = 0; 1004 u64 lpar_reports = 0;
988 u64 lpar_reports_size = 0; 1005 u64 lpar_reports_size = 0;
989 u64 xdr_lpar; 1006 u64 xdr_lpar;
990 int status; 1007 int status, res_index;
991 unsigned long offset; 1008 unsigned long offset;
992 struct task_struct *task; 1009 struct task_struct *task;
993 1010
@@ -1004,15 +1021,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
1004 1021
1005 if (ps3fb_mode > 0 && 1022 if (ps3fb_mode > 0 &&
1006 !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { 1023 !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
1007 ps3fb.res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode); 1024 res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
1008 dev_dbg(&dev->core, "res_index:%d\n", ps3fb.res_index); 1025 dev_dbg(&dev->core, "res_index:%d\n", res_index);
1009 } else 1026 } else
1010 ps3fb.res_index = GPU_RES_INDEX; 1027 res_index = GPU_RES_INDEX;
1011 1028
1012 atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ 1029 atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
1013 atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ 1030 atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
1014 init_waitqueue_head(&ps3fb.wait_vsync); 1031 init_waitqueue_head(&ps3fb.wait_vsync);
1015 ps3fb.num_frames = 1;
1016 1032
1017 ps3fb_set_sync(&dev->core); 1033 ps3fb_set_sync(&dev->core);
1018 1034
@@ -1062,19 +1078,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
1062 if (retval) 1078 if (retval)
1063 goto err_free_irq; 1079 goto err_free_irq;
1064 1080
1065 info = framebuffer_alloc(sizeof(u32) * 16, &dev->core); 1081 info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
1066 if (!info) 1082 if (!info)
1067 goto err_free_irq; 1083 goto err_free_irq;
1068 1084
1069 offset = VFB_OFF(ps3fb.res_index); 1085 par = info->par;
1086 par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
1087 par->new_mode_id = ps3fb_mode;
1088 par->res_index = res_index;
1089 par->num_frames = 1;
1090
1091 offset = VFB_OFF(res_index);
1070 info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset; 1092 info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
1071 info->fbops = &ps3fb_ops; 1093 info->fbops = &ps3fb_ops;
1072 1094
1073 info->fix = ps3fb_fix; 1095 info->fix = ps3fb_fix;
1074 info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset; 1096 info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset;
1075 info->fix.smem_len = ps3fb.xdr_size - offset; 1097 info->fix.smem_len = ps3fb.xdr_size - offset;
1076 info->pseudo_palette = info->par; 1098 info->pseudo_palette = par->pseudo_palette;
1077 info->par = NULL;
1078 info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST; 1099 info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
1079 1100
1080 retval = fb_alloc_cmap(&info->cmap, 256, 0); 1101 retval = fb_alloc_cmap(&info->cmap, 256, 0);
@@ -1082,7 +1103,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
1082 goto err_framebuffer_release; 1103 goto err_framebuffer_release;
1083 1104
1084 if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb, 1105 if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
1085 ARRAY_SIZE(ps3fb_modedb), ps3fb_default_mode(), 32)) { 1106 ARRAY_SIZE(ps3fb_modedb),
1107 ps3fb_default_mode(par->new_mode_id), 32)) {
1086 retval = -EINVAL; 1108 retval = -EINVAL;
1087 goto err_fb_dealloc; 1109 goto err_fb_dealloc;
1088 } 1110 }