]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/video/ps3fb.c
pata_serverworks: Fix cable types and cosmetics
[linux-2.6-omap-h63xx.git] / drivers / video / ps3fb.c
index 9c56c492a6939b6dda69fc454299dbb134771343..044a423a72cbe406e0a5811796b246cb788f1ec3 100644 (file)
@@ -51,7 +51,8 @@
 #define L1GPU_DISPLAY_SYNC_HSYNC               1
 #define L1GPU_DISPLAY_SYNC_VSYNC               2
 
-#define GPU_CMD_BUF_SIZE                       (64 * 1024)
+#define GPU_CMD_BUF_SIZE                       (2 * 1024 * 1024)
+#define GPU_FB_START                           (64 * 1024)
 #define GPU_IOIF                               (0x0d000000UL)
 #define GPU_ALIGN_UP(x)                                _ALIGN_UP((x), 64)
 #define GPU_MAX_LINE_LENGTH                    (65536 - 64)
@@ -406,6 +407,7 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
        if (src_line_length != dst_line_length)
                line_length |= (u64)src_line_length << 32;
 
+       src_offset += GPU_FB_START;
        status = lv1_gpu_context_attribute(ps3fb.context_handle,
                                           L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
                                           dst_offset, GPU_IOIF + src_offset,
@@ -441,8 +443,6 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
        u32 ddr_line_length, xdr_line_length;
        u64 ddr_base, xdr_base;
 
-       acquire_console_sem();
-
        if (frame > par->num_frames - 1) {
                dev_dbg(info->device, "%s: invalid frame number (%u)\n",
                        __func__, frame);
@@ -462,7 +462,6 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
                         xdr_line_length);
 
 out:
-       release_console_sem();
        return error;
 }
 
@@ -477,7 +476,10 @@ static int ps3fb_release(struct fb_info *info, int user)
        if (atomic_dec_and_test(&ps3fb.f_count)) {
                if (atomic_read(&ps3fb.ext_flip)) {
                        atomic_set(&ps3fb.ext_flip, 0);
-                       ps3fb_sync(info, 0);    /* single buffer */
+                       if (!try_acquire_console_sem()) {
+                               ps3fb_sync(info, 0);    /* single buffer */
+                               release_console_sem();
+                       }
                }
        }
        return 0;
@@ -863,7 +865,9 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
                        break;
 
                dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val);
+               acquire_console_sem();
                retval = ps3fb_sync(info, val);
+               release_console_sem();
                break;
 
        default:
@@ -883,7 +887,9 @@ static int ps3fbd(void *arg)
                set_current_state(TASK_INTERRUPTIBLE);
                if (ps3fb.is_kicked) {
                        ps3fb.is_kicked = 0;
+                       acquire_console_sem();
                        ps3fb_sync(info, 0);    /* single buffer */
+                       release_console_sem();
                }
                schedule();
        }
@@ -976,9 +982,8 @@ static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
 
        status = lv1_gpu_context_attribute(ps3fb.context_handle,
                                           L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
-                                          xdr_lpar + ps3fb.xdr_size,
-                                          GPU_CMD_BUF_SIZE,
-                                          GPU_IOIF + ps3fb.xdr_size, 0);
+                                          xdr_lpar, GPU_CMD_BUF_SIZE,
+                                          GPU_IOIF, 0);
        if (status) {
                dev_err(dev,
                        "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
@@ -1061,6 +1066,11 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        struct task_struct *task;
        unsigned long max_ps3fb_size;
 
+       if (ps3fb_videomemory.size < GPU_CMD_BUF_SIZE) {
+               dev_err(&dev->core, "%s: Not enough video memory\n", __func__);
+               return -ENOMEM;
+       }
+
        status = ps3_open_hv_device(dev);
        if (status) {
                dev_err(&dev->core, "%s: ps3_open_hv_device failed\n",
@@ -1131,8 +1141,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        /* Clear memory to prevent kernel info leakage into userspace */
        memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
 
-       /* The GPU command buffer is at the end of video memory */
-       ps3fb.xdr_size = ps3fb_videomemory.size - GPU_CMD_BUF_SIZE;
+       /*
+        * The GPU command buffer is at the start of video memory
+        * As we don't use the full command buffer, we can put the actual
+        * frame buffer at offset GPU_FB_START and save some precious XDR
+        * memory
+        */
+       ps3fb.xdr_ea += GPU_FB_START;
+       ps3fb.xdr_size = ps3fb_videomemory.size - GPU_FB_START;
 
        retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
        if (retval)
@@ -1200,7 +1216,7 @@ err_fb_dealloc:
 err_framebuffer_release:
        framebuffer_release(info);
 err_free_irq:
-       free_irq(ps3fb.irq_no, dev);
+       free_irq(ps3fb.irq_no, &dev->core);
        ps3_irq_plug_destroy(ps3fb.irq_no);
 err_iounmap_dinfo:
        iounmap((u8 __iomem *)ps3fb.dinfo);
@@ -1222,12 +1238,6 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
        ps3fb_flip_ctl(0, &ps3fb);      /* flip off */
        ps3fb.dinfo->irq.mask = 0;
 
-       if (info) {
-               unregister_framebuffer(info);
-               fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
-
        ps3av_register_flip_ctl(NULL, NULL);
        if (ps3fb.task) {
                struct task_struct *task = ps3fb.task;
@@ -1235,9 +1245,15 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
                kthread_stop(task);
        }
        if (ps3fb.irq_no) {
-               free_irq(ps3fb.irq_no, dev);
+               free_irq(ps3fb.irq_no, &dev->core);
                ps3_irq_plug_destroy(ps3fb.irq_no);
        }
+       if (info) {
+               unregister_framebuffer(info);
+               fb_dealloc_cmap(&info->cmap);
+               framebuffer_release(info);
+               info = dev->core.driver_data = NULL;
+       }
        iounmap((u8 __iomem *)ps3fb.dinfo);
 
        status = lv1_gpu_context_free(ps3fb.context_handle);