From: Michael Frank <mhf@linuxmail.org>

Enclosed is a patch for x86 to make highmem= option easier to use.

- Automates alignment of highmem zone

- Fixes invalid highmem settings whether too small or to large

- Adds entry in kernel-parameters.txt

- Permits highmem emulation, so people with less than 896MB of memory can
  test CONFIG_HIGHMEM.  Highmem emulation can be used on any machine with at
  least 72MB RAM.

The patch does not add to bloat as it is part of __init code.




---

 Documentation/kernel-parameters.txt |    8 +++
 arch/i386/kernel/setup.c            |   91 +++++++++++++++++++++++++++---------
 2 files changed, 77 insertions(+), 22 deletions(-)

diff -puN arch/i386/kernel/setup.c~highmem-equals-user-friendliness arch/i386/kernel/setup.c
--- 25/arch/i386/kernel/setup.c~highmem-equals-user-friendliness	2004-02-09 00:14:08.000000000 -0800
+++ 25-akpm/arch/i386/kernel/setup.c	2004-02-09 00:14:08.000000000 -0800
@@ -588,9 +588,12 @@ static void __init parse_cmdline_early (
 #endif /* CONFIG_ACPI_BOOT */
 
 		/*
-		 * highmem=size forces highmem to be exactly 'size' bytes.
+		 * highmem=size forces highmem to be at most 'size' bytes.
 		 * This works even on boxes that have no highmem otherwise.
 		 * This also works to reduce highmem size on bigger boxes.
+		 *
+		 * Note: highmem sise is adjusted downward for proper zone
+		 *       alignment of the highmem physical start address.
 		 */
 		if (c == ' ' && !memcmp(from, "highmem=", 8))
 			highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;
@@ -657,6 +660,11 @@ void __init find_max_pfn(void)
 /*
  * Determine low and high memory ranges:
  */
+
+#define ZONE_REQUIRED_PAGE_ALIGNMENT (1UL << (MAX_ORDER-1))
+#define ZONE_REQUIRED_PAGE_ALIGNMENT_MASK (ZONE_REQUIRED_PAGE_ALIGNMENT-1)
+#define PAGES_FOR_64MB (64*1024*1024/PAGE_SIZE)
+
 unsigned long __init find_max_low_pfn(void)
 {
 	unsigned long max_low_pfn;
@@ -668,14 +676,16 @@ unsigned long __init find_max_low_pfn(vo
 		if (highmem_pages + MAXMEM_PFN < max_pfn)
 			max_pfn = MAXMEM_PFN + highmem_pages;
 		if (highmem_pages + MAXMEM_PFN > max_pfn) {
-			printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages));
-			highmem_pages = 0;
+			printk("Warning reducing highmem=%uMB to: %luMB.\n",
+				pages_to_mb(highmem_pages),
+				pages_to_mb((max_pfn - MAXMEM_PFN)));
+			highmem_pages = max_pfn - MAXMEM_PFN;
 		}
 		max_low_pfn = MAXMEM_PFN;
 #ifndef CONFIG_HIGHMEM
 		/* Maximum memory usable is what is directly addressable */
-		printk(KERN_WARNING "Warning only %ldMB will be used.\n",
-					MAXMEM>>20);
+		printk(KERN_WARNING "Warning only %luMB will be used.\n",
+			MAXMEM >> 20);
 		if (max_pfn > MAX_NONPAE_PFN)
 			printk(KERN_WARNING "Use a PAE enabled kernel.\n");
 		else
@@ -690,26 +700,63 @@ unsigned long __init find_max_low_pfn(vo
 		}
 #endif /* !CONFIG_X86_PAE */
 #endif /* !CONFIG_HIGHMEM */
-	} else {
-		if (highmem_pages == -1)
-			highmem_pages = 0;
+	} else if (highmem_pages == -1)
+		highmem_pages = 0;
 #ifdef CONFIG_HIGHMEM
-		if (highmem_pages >= max_pfn) {
-			printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn));
-			highmem_pages = 0;
-		}
-		if (highmem_pages) {
-			if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){
-				printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages));
-				highmem_pages = 0;
-			}
-			max_low_pfn -= highmem_pages;
-		}
+	if (!highmem_pages)
+		goto out;
+	if (max_pfn < PAGES_FOR_64MB + ZONE_REQUIRED_PAGE_ALIGNMENT * 2) {
+		printk(KERN_ERR "Error highmem support requires at least %luMB "
+			"but only %luMB are available.\n",
+			pages_to_mb(PAGES_FOR_64MB +
+					ZONE_REQUIRED_PAGE_ALIGNMENT * 2),
+			pages_to_mb(max_pfn));
+		highmem_pages = 0;
+		goto out;
+	}
+	if (highmem_pages > max_pfn) {
+		printk(KERN_WARNING "Warning highmem=%uMB is bigger than "
+				"available %luMB and will be adjusted.\n",
+		pages_to_mb(highmem_pages), pages_to_mb(max_pfn));
+	}
+	if (highmem_pages <= ZONE_REQUIRED_PAGE_ALIGNMENT) {
+		printk(KERN_WARNING "Warning highmem=%uMB is too small and has "
+			"been adjusted to: %luMB.\n",
+			pages_to_mb(highmem_pages),
+			pages_to_mb(ZONE_REQUIRED_PAGE_ALIGNMENT * 2));
+		highmem_pages = ZONE_REQUIRED_PAGE_ALIGNMENT * 2;
+	}
+	if (max_low_pfn < highmem_pages ||
+			max_low_pfn-highmem_pages < PAGES_FOR_64MB){
+		highmem_pages = max_low_pfn - PAGES_FOR_64MB;
+		printk(KERN_WARNING "Warning highmem size adjusted for a "
+				"minimum of 64MB lowmem to: %uMB.\n",
+			pages_to_mb(highmem_pages));
+	}
+	max_low_pfn -= highmem_pages;
+
+	if (max_low_pfn & ZONE_REQUIRED_PAGE_ALIGNMENT_MASK) {
+		printk(KERN_WARNING "Warning bad highmem zone alignment 0x%lx, "
+			"highmem size will be adjusted.\n",
+			(max_low_pfn & ZONE_REQUIRED_PAGE_ALIGNMENT_MASK) <<
+					PAGE_SHIFT);
+		highmem_pages -= ZONE_REQUIRED_PAGE_ALIGNMENT -
+			(max_low_pfn & ZONE_REQUIRED_PAGE_ALIGNMENT_MASK);
+		max_low_pfn &= ~ZONE_REQUIRED_PAGE_ALIGNMENT_MASK;
+		max_low_pfn += ZONE_REQUIRED_PAGE_ALIGNMENT;
+		printk(KERN_WARNING "Warning lowmem size adjusted for zone "
+			"alignment to: %luMB.\n",
+			pages_to_mb(max_low_pfn));
+		printk(KERN_WARNING "Warning highmem size adjusted for zone "
+				"alignment to: %uMB.\n",
+			pages_to_mb(highmem_pages));
+	}
+out:
 #else
-		if (highmem_pages)
-			printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n");
+	if (highmem_pages)
+		printk(KERN_ERR "ignoring highmem size on non-highmem "
+					"kernel!\n");
 #endif
-	}
 	return max_low_pfn;
 }
 
diff -puN Documentation/kernel-parameters.txt~highmem-equals-user-friendliness Documentation/kernel-parameters.txt
--- 25/Documentation/kernel-parameters.txt~highmem-equals-user-friendliness	2004-02-09 00:14:08.000000000 -0800
+++ 25-akpm/Documentation/kernel-parameters.txt	2004-02-09 00:14:08.000000000 -0800
@@ -394,6 +394,14 @@ running once the system is up.
 	hd?=		[HW] (E)IDE subsystem
 	hd?lun=		See Documentation/ide.txt.
 
+	highmem=size[KMG] [IA32,KNL,BOOT] forces highmem to be at most 'size' bytes.
+			This works even on boxes with at least 72MB RAM that have no
+                        highmem otherwise. This also works to reduce highmem size on
+                        bigger boxes.
+
+                        Note: highmem is adjusted downward for proper zone alignment
+                        of  the highmem physical start address
+
 	hisax=		[HW,ISDN]
 			See Documentation/isdn/README.HiSax.
 

_