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; + } } } _