diff options
author | Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> | 2007-10-16 04:29:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:21 -0400 |
commit | 0333d83509c7d8496c8965b5ba9bc0c98e83c259 (patch) | |
tree | a0ce0a75b5e8770f7f7c2b2b1d88ba77a56afaaa /drivers/video/ps3fb.c | |
parent | 2ce32e15a16312d2c29c8bb188bf95bc821fdab6 (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.c | 92 |
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 | }; |
134 | static struct ps3fb_priv ps3fb; | 132 | static struct ps3fb_priv ps3fb; |
135 | 133 | ||
134 | struct 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 | |||
136 | struct ps3fb_res_table { | 141 | struct 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 | ||
367 | static const struct fb_videomode *ps3fb_default_mode(void) | 371 | static 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 | ||
385 | static int ps3fb_sync(struct fb_info *info, u32 frame) | 389 | static 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 | |
440 | out: | ||
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 | ||
548 | static int ps3fb_set_par(struct fb_info *info) | 559 | static 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) | |||
979 | static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | 995 | static 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 | } |