
From: "Antonino A. Daplas" <adaplas@gawab.com>

w100fb bugfix: The blanking function used vmalloc/vfree which isn't interrupt
safe.  To avoid problems, switch to kmalloc/kfree and use several buffers to
avoid kmalloc size limitations.

Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/video/w100fb.c |   59 ++++++++++++++++++++++++-----------------
 1 files changed, 35 insertions(+), 24 deletions(-)

diff -puN drivers/video/w100fb.c~w100fb-make-blanking-function-interrupt-safe drivers/video/w100fb.c
--- 25/drivers/video/w100fb.c~w100fb-make-blanking-function-interrupt-safe	Wed Feb  9 14:05:07 2005
+++ 25-akpm/drivers/video/w100fb.c	Wed Feb  9 14:05:07 2005
@@ -22,7 +22,6 @@
 #include <linux/device.h>
 #include <linux/string.h>
 #include <linux/proc_fs.h>
-#include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <video/w100fb.h>
@@ -90,8 +89,6 @@ struct w100fb_par {
 
 static struct w100fb_par *current_par;
 
-static u16 *gSaveImagePtr = NULL;
-
 /* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
 static void *remapped_base;
 static void *remapped_regs;
@@ -494,42 +491,56 @@ static void w100fb_clear_screen(u32 mode
 }
 
 
+/* Need to split up the buffers to stay within the limits of kmalloc */
+#define W100_BUF_NUM	6
+static uint32_t *gSaveImagePtr[W100_BUF_NUM] = { NULL };
+
 static void w100fb_save_buffer(void)
 {
-	int i;
+	int i, j, bufsize;
 
-	if (gSaveImagePtr != NULL) {
-		vfree(gSaveImagePtr);
-		gSaveImagePtr = NULL;
-	}
-	gSaveImagePtr = vmalloc(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8);
-	if (gSaveImagePtr != NULL) {
-		for (i = 0; i < (current_par->xres * current_par->yres); i++)
-			*(gSaveImagePtr + i) = readw(remapped_fbuf + (2*i));
-	} else {
-		printk(KERN_WARNING "can't alloc pre-off image buffer\n");
+	bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
+	for (i = 0; i < W100_BUF_NUM; i++) {
+		if (gSaveImagePtr[i] == NULL)
+			gSaveImagePtr[i] = kmalloc(bufsize, GFP_KERNEL);
+		if (gSaveImagePtr[i] == NULL) {
+			w100fb_clear_buffer();
+			printk(KERN_WARNING "can't alloc pre-off image buffer %d\n", i);
+			break;
+		}
+		for (j = 0; j < bufsize/4; j++)
+			*(gSaveImagePtr[i] + j) = readl(remapped_fbuf + (bufsize*i) + j*4);
 	}
 }
 
 
 static void w100fb_restore_buffer(void)
 {
-	int i;
+	int i, j, bufsize;
 
-	if (gSaveImagePtr != NULL) {
-		for (i = 0; i < (current_par->xres * current_par->yres); i++) {
-				writew(*(gSaveImagePtr + i),remapped_fbuf + (2*i));
-			}
-		vfree(gSaveImagePtr);
-		gSaveImagePtr = NULL;
+	bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM;
+	for (i = 0; i < W100_BUF_NUM; i++) {
+		if (gSaveImagePtr[i] == NULL) {
+			printk(KERN_WARNING "can't find pre-off image buffer %d\n", i);
+			w100fb_clear_buffer();
+			break;
+		}
+		for (j = 0; j < (bufsize/4); j++)
+			writel(*(gSaveImagePtr[i] + j),remapped_fbuf + (bufsize*i) + (j*4));
+		kfree(gSaveImagePtr[i]);
+		gSaveImagePtr[i] = NULL;
 	}
 }
 
+
 static void w100fb_clear_buffer(void)
 {
-	if (gSaveImagePtr != NULL) {
-		vfree(gSaveImagePtr);
-		gSaveImagePtr = NULL;
+	int i;
+	for (i = 0; i < W100_BUF_NUM; i++) {
+		if (gSaveImagePtr[i] != NULL) {
+			kfree(gSaveImagePtr[i]);
+			gSaveImagePtr[i] = NULL;
+		}
 	}
 }
 
_
