[PATCH] vesafb: Fix mtrr bugs

>> vesafb: mode is 800x600x16, linelength=1600, pages=16
>> vesafb: scrolling: redraw
>> vesafb: Truecolor: size=0:5:6:5, shift=0:11:5:0
>> mtrr: type mismatch for fc000000,1000000 old: write-back new: write-
>> combining

Range is already set to write-back, vesafb attempts to add a write-combining
mtrr (default for vesafb).

>> mtrr: size and base must be multiples of 4 kiB

This is a bug, vesafb attempts to add a size < PAGE_SIZE triggering
the messages below.

To eliminate the warning messages, you can add the option mtrr:2 to add a
write-back mtrr for vesafb.  Or just use nomtrr option.

1. Fix algorithm for finding the best power of 2 size with mtrr_add().

2. Add option to choose the mtrr type by extending the mtrr boot option:

   mtrr:n where n

        0 = no mtrr (equivalent to using the nomtrr option)
        1 = uncachable
        2 = write back
        3 = write combining (default)
        4 = write through

Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 9ed1a93..a272592 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -45,7 +45,7 @@
 };
 
 static int             inverse   = 0;
-static int             mtrr      = 1;
+static int             mtrr      = 3; /* default to write-combining */
 static int	       vram_remap __initdata = 0; /* Set amount of memory to be used */
 static int	       vram_total __initdata = 0; /* Set total amount of memory */
 static int             pmi_setpal = 0;	/* pmi for palette changes ??? */
@@ -204,8 +204,8 @@
 			pmi_setpal=0;
 		else if (! strcmp(this_opt, "pmipal"))
 			pmi_setpal=1;
-		else if (! strcmp(this_opt, "mtrr"))
-			mtrr=1;
+		else if (! strncmp(this_opt, "mtrr:", 5))
+			mtrr = simple_strtoul(this_opt+5, NULL, 0);
 		else if (! strcmp(this_opt, "nomtrr"))
 			mtrr=0;
 		else if (! strncmp(this_opt, "vtotal:", 7))
@@ -387,14 +387,39 @@
 
 	if (mtrr) {
 		unsigned int temp_size = size_total;
-		/* Find the largest power-of-two */
-		while (temp_size & (temp_size - 1))
-			temp_size &= (temp_size - 1);
+		unsigned int type = 0;
 
-		/* Try and find a power of two to add */
-		while (temp_size > PAGE_SIZE &&
-			mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
-			temp_size >>= 1;
+		switch (mtrr) {
+		case 1:
+			type = MTRR_TYPE_UNCACHABLE;
+			break;
+		case 2:
+			type = MTRR_TYPE_WRBACK;
+			break;
+		case 3:
+			type = MTRR_TYPE_WRCOMB;
+			break;
+		case 4:
+			type = MTRR_TYPE_WRTHROUGH;
+			break;
+		default:
+			type = 0;
+			break;
+		}
+
+		if (type) {
+			int rc;
+
+			/* Find the largest power-of-two */
+			while (temp_size & (temp_size - 1))
+				temp_size &= (temp_size - 1);
+
+			/* Try and find a power of two to add */
+			do {
+				rc = mtrr_add(vesafb_fix.smem_start, temp_size,
+					      type, 1);
+				temp_size >>= 1;
+			} while (temp_size >= PAGE_SIZE && rc == -EINVAL);
 		}
 	}