diff options
author | Paul Mackerras <paulus@samba.org> | 2007-05-08 13:37:51 +1000 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-05-08 13:37:51 +1000 |
commit | 02bbc0f09c90cefdb2837605c96a66c5ce4ba2e1 (patch) | |
tree | 04ef573cd4de095c500c9fc3477f4278c0b36300 /drivers/video/ps3fb.c | |
parent | 7487a2245b8841c77ba9db406cf99a483b9334e9 (diff) | |
parent | 5b94f675f57e4ff16c8fda09088d7480a84dcd91 (diff) | |
download | linux-02bbc0f09c90cefdb2837605c96a66c5ce4ba2e1.tar.bz2 |
Merge branch 'linux-2.6'
Diffstat (limited to 'drivers/video/ps3fb.c')
-rw-r--r-- | drivers/video/ps3fb.c | 116 |
1 files changed, 73 insertions, 43 deletions
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index a9ca4986645c..9756a728b74f 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -32,6 +32,8 @@ #include <linux/ioctl.h> #include <linux/notifier.h> #include <linux/reboot.h> +#include <linux/kthread.h> +#include <linux/freezer.h> #include <asm/uaccess.h> #include <linux/fb.h> @@ -45,7 +47,7 @@ #include <asm/ps3.h> #ifdef PS3FB_DEBUG -#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args) +#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) #else #define DPRINTK(fmt, args...) #endif @@ -129,7 +131,6 @@ struct ps3fb_priv { u64 context_handle, memory_handle; void *xdr_ea; struct gpu_driver_info *dinfo; - struct semaphore sem; u32 res_index; u64 vblank_count; /* frame count */ @@ -139,6 +140,8 @@ struct ps3fb_priv { atomic_t ext_flip; /* on/off flip with vsync */ atomic_t f_count; /* fb_open count */ int is_blanked; + int is_kicked; + struct task_struct *task; }; static struct ps3fb_priv ps3fb; @@ -294,10 +297,10 @@ static const struct fb_videomode ps3fb_modedb[] = { #define VP_OFF(i) (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP) #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) -static int ps3fb_mode = 0; +static int ps3fb_mode; module_param(ps3fb_mode, bool, 0); -static char *mode_option __initdata = NULL; +static char *mode_option __initdata; static int ps3fb_get_res_table(u32 xres, u32 yres) @@ -393,7 +396,7 @@ static int ps3fb_sync(u32 frame) if (frame > ps3fb.num_frames - 1) { printk(KERN_WARNING "%s: invalid frame number (%u)\n", - __FUNCTION__, frame); + __func__, frame); return -EINVAL; } offset = xres * yres * BPP * frame; @@ -406,23 +409,26 @@ static int ps3fb_sync(u32 frame) (xres << 16) | yres, xres * BPP); /* line_length */ if (status) - printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", + __func__, status); #ifdef HEAD_A status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 0, offset, 0, 0); if (status) - printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute FLIP failed: %d\n", + __func__, status); #endif #ifdef HEAD_B status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 1, offset, 0, 0); if (status) - printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute FLIP failed: %d\n", + __func__, status); #endif return 0; } @@ -631,7 +637,7 @@ static int ps3fb_blank(int blank, struct fb_info *info) { int retval; - DPRINTK("%s: blank:%d\n", __FUNCTION__, blank); + DPRINTK("%s: blank:%d\n", __func__, blank); switch (blank) { case FB_BLANK_POWERDOWN: case FB_BLANK_HSYNC_SUSPEND: @@ -677,13 +683,10 @@ EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); void ps3fb_flip_ctl(int on) { - if (on) { - if (atomic_read(&ps3fb.ext_flip) > 0) { - atomic_dec(&ps3fb.ext_flip); - } - } else { + if (on) + atomic_dec_if_positive(&ps3fb.ext_flip); + else atomic_inc(&ps3fb.ext_flip); - } } EXPORT_SYMBOL_GPL(ps3fb_flip_ctl); @@ -732,6 +735,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, if (copy_from_user(&val, argp, sizeof(val))) break; + if (!(val & PS3AV_MODE_MASK)) { + u32 id = ps3av_get_auto_mode(0); + if (id > 0) + val = (val & ~PS3AV_MODE_MASK) | id; + } DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val); retval = -EINVAL; old_mode = ps3fb_mode; @@ -783,8 +791,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, case PS3FB_IOCTL_OFF: DPRINTK("PS3FB_IOCTL_OFF:\n"); - if (atomic_read(&ps3fb.ext_flip) > 0) - atomic_dec(&ps3fb.ext_flip); + atomic_dec_if_positive(&ps3fb.ext_flip); retval = 0; break; @@ -805,11 +812,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, static int ps3fbd(void *arg) { - daemonize("ps3fbd"); - for (;;) { - down(&ps3fb.sem); - if (atomic_read(&ps3fb.ext_flip) == 0) + while (!kthread_should_stop()) { + try_to_freeze(); + set_current_state(TASK_INTERRUPTIBLE); + if (ps3fb.is_kicked) { + ps3fb.is_kicked = 0; ps3fb_sync(0); /* single buffer */ + } + schedule(); } return 0; } @@ -823,15 +833,18 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) status = lv1_gpu_context_intr(ps3fb.context_handle, &v1); if (status) { printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n", - __FUNCTION__, status); + __func__, status); return IRQ_NONE; } if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) { /* VSYNC */ ps3fb.vblank_count = head->vblank_count; - if (!ps3fb.is_blanked) - up(&ps3fb.sem); + if (ps3fb.task && !ps3fb.is_blanked && + !atomic_read(&ps3fb.ext_flip)) { + ps3fb.is_kicked = 1; + wake_up_process(ps3fb.task); + } wake_up_interruptible(&ps3fb.wait_vsync); } @@ -879,7 +892,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { - printk(KERN_ERR "%s: version_driver err:%x\n", __FUNCTION__, + printk(KERN_ERR "%s: version_driver err:%x\n", __func__, dinfo->version_driver); return -EINVAL; } @@ -888,7 +901,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, &ps3fb.irq_no); if (error) { - printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __FUNCTION__, + printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__, error); return error; } @@ -896,7 +909,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, "ps3fb vsync", ps3fb.dev); if (error) { - printk(KERN_ERR "%s: request_irq failed %d\n", __FUNCTION__, + printk(KERN_ERR "%s: request_irq failed %d\n", __func__, error); ps3_irq_plug_destroy(ps3fb.irq_no); return error; @@ -915,7 +928,7 @@ static int ps3fb_xdr_settings(u64 xdr_lpar) xdr_lpar, ps3fb_videomemory.size, 0); if (status) { printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n", - __FUNCTION__, status); + __func__, status); return -ENXIO; } DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", @@ -927,8 +940,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar) xdr_lpar, ps3fb_videomemory.size, GPU_IOIF, 0); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", + __func__, status); return -ENXIO; } return 0; @@ -968,13 +982,14 @@ static int __init ps3fb_probe(struct platform_device *dev) u64 xdr_lpar; int status; unsigned long offset; + struct task_struct *task; /* get gpu context handle */ status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, &ps3fb.memory_handle, &ddr_lpar); if (status) { printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n", - __FUNCTION__, status); + __func__, status); goto err; } DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar); @@ -985,14 +1000,14 @@ static int __init ps3fb_probe(struct platform_device *dev) &lpar_reports, &lpar_reports_size); if (status) { printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n", - __FUNCTION__, status); + __func__, status); goto err_gpu_memory_free; } /* vsync interrupt */ ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024); if (!ps3fb.dinfo) { - printk(KERN_ERR "%s: ioremap failed\n", __FUNCTION__); + printk(KERN_ERR "%s: ioremap failed\n", __func__); goto err_gpu_context_free; } @@ -1050,9 +1065,18 @@ static int __init ps3fb_probe(struct platform_device *dev) "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", info->node, ps3fb_videomemory.size >> 10); - kernel_thread(ps3fbd, info, CLONE_KERNEL); + task = kthread_run(ps3fbd, info, "ps3fbd"); + if (IS_ERR(task)) { + retval = PTR_ERR(task); + goto err_unregister_framebuffer; + } + + ps3fb.task = task; + return 0; +err_unregister_framebuffer: + unregister_framebuffer(info); err_fb_dealloc: fb_dealloc_cmap(&info->cmap); err_framebuffer_release: @@ -1083,6 +1107,11 @@ void ps3fb_cleanup(void) { int status; + if (ps3fb.task) { + struct task_struct *task = ps3fb.task; + ps3fb.task = NULL; + kthread_stop(task); + } if (ps3fb.irq_no) { free_irq(ps3fb.irq_no, ps3fb.dev); ps3_irq_plug_destroy(ps3fb.irq_no); @@ -1137,8 +1166,9 @@ int ps3fb_set_sync(void) L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n", + __func__, status); return -1; } #endif @@ -1148,8 +1178,9 @@ int ps3fb_set_sync(void) 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n", + __func__, status); return -1; } #endif @@ -1174,7 +1205,7 @@ static int __init ps3fb_init(void) error = ps3av_dev_open(); if (error) { - printk(KERN_ERR "%s: ps3av_dev_open failed\n", __FUNCTION__); + printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__); goto err; } @@ -1195,7 +1226,6 @@ static int __init ps3fb_init(void) atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ - init_MUTEX(&ps3fb.sem); init_waitqueue_head(&ps3fb.wait_vsync); ps3fb.num_frames = 1; |