sm501: fixup allocation code to be 64bit resource compliant
authorBen Dooks <ben-linux@fluff.org>
Thu, 24 Jul 2008 04:31:37 +0000 (21:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 24 Jul 2008 17:47:40 +0000 (10:47 -0700)
As pointed out by Andrew Morton, we have a problem when setting the 64bit
resources option.  Alter the allocation routines to remove the need to use
the start and end fields, use the proper HEAD_PANEL/HEAD_CRT and update
the comments.

Note, we also fix the bug where we failed to check the size of the
CRT memory allocation.

[akpm@linux-foundation.org: cleanup]
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/video/sm501fb.c

index b473cf665d834fbddf1374d8eb6b9a236edf0e7d..f94ae84a58cd54eabd267a9e4d33384b346755ec 100644 (file)
@@ -48,10 +48,15 @@ enum sm501_controller {
        HEAD_PANEL      = 1,
 };
 
-/* SM501 memory address */
+/* SM501 memory address.
+ *
+ * This structure is used to track memory usage within the SM501 framebuffer
+ * allocation. The sm_addr field is stored as an offset as it is often used
+ * against both the physical and mapped addresses.
+ */
 struct sm501_mem {
        unsigned long    size;
-       unsigned long    sm_addr;
+       unsigned long    sm_addr;       /* offset from base of sm501 fb. */
        void __iomem    *k_addr;
 };
 
@@ -142,37 +147,63 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
 static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
                           unsigned int why, size_t size)
 {
-       unsigned int ptr = 0;
-       unsigned int end;
+       struct sm501fb_par *par;
        struct fb_info *fbi;
+       unsigned int ptr;
+       unsigned int end;
 
        switch (why) {
        case SM501_MEMF_CURSOR:
                ptr = inf->fbmem_len - size;
-               inf->fbmem_len = ptr;
+               inf->fbmem_len = ptr;   /* adjust available memory. */
                break;
 
        case SM501_MEMF_PANEL:
                ptr = inf->fbmem_len - size;
-               fbi = inf->fb[0];
+               fbi = inf->fb[HEAD_CRT];
+
+               /* round down, some programs such as directfb do not draw
+                * 0,0 correctly unless the start is aligned to a page start.
+                */
+
+               if (ptr > 0)
+                       ptr &= ~(PAGE_SIZE - 1);
 
                if (fbi && ptr < fbi->fix.smem_len)
                        return -ENOMEM;
 
+               if (ptr < 0)
+                       return -ENOMEM;
+
                break;
 
        case SM501_MEMF_CRT:
                ptr = 0;
+
+               /* check to see if we have panel memory allocated
+                * which would put an limit on available memory. */
+
+               fbi = inf->fb[HEAD_PANEL];
+               if (fbi) {
+                       par = fbi->par;
+                       end = par->screen.k_addr ? par->screen.sm_addr : inf->fbmem_len;
+               } else
+                       end = inf->fbmem_len;
+
+               if ((ptr + size) > end)
+                       return -ENOMEM;
+
                break;
 
        case SM501_MEMF_ACCEL:
-               fbi = inf->fb[0];
+               fbi = inf->fb[HEAD_CRT];
                ptr = fbi ? fbi->fix.smem_len : 0;
 
-               fbi = inf->fb[1];
-               if (fbi)
-                       end = (fbi->fix.smem_start - inf->fbmem_res->start);
-               else
+               fbi = inf->fb[HEAD_PANEL];
+               if (fbi) {
+                       par = fbi->par;
+                       end = par->screen.sm_addr;
+               } else
                        end = inf->fbmem_len;
 
                if ((ptr + size) > end)