diff -u -p -L linux-2.4.18/Documentation/Configure.help.orig linux-2.4.18/Documentation/Configure.help
--- linux-2.4.18/Documentation/Configure.help
+++ linux-2.4.18/Documentation/Configure.help	Tue Mar 19 13:27:44 2002
@@ -266,6 +266,18 @@ CONFIG_X86_UP_APIC
   If you have a system with several CPUs, you do not need to say Y
   here: the local APIC will be used automatically.
 
+Bigphysarea support
+CONFIG_BIGPHYSAREA
+  The bigphysarea patch allows a large amount of contiguous physical
+  memory to be reserved at boot time.  This is generally useful to
+  video grabbers, high-speed A/D converters and scatter/gather NICs.
+
+  See also: Documentation/bigphysarea.txt, and the home web site at
+  http://www.uni-paderborn.de/fachbereich/AG/heiss/linux/bigphysarea.html
+
+  To reserve memory, specify bigphysarea=<pages> in the kernel boot
+  parameters.  The usage can be monitored through /proc/bigphysarea.
+
 Kernel math emulation
 CONFIG_MATH_EMULATION
   Linux can emulate a math coprocessor (used for floating point
diff -u -p -L linux-2.4.18/Documentation/bigphysarea.txt.orig linux-2.4.18/Documentation/bigphysarea.txt
--- linux-2.4.18/Documentation/bigphysarea.txt
+++ linux-2.4.18/Documentation/bigphysarea.txt	Tue Mar 19 13:27:44 2002
@@ -0,0 +1,38 @@
+Big physical area patch
+=======================
+
+This is a patch against Linux 2.3.36 for the `bigphysarea' memory
+allocation routines. This code allows you to reserve a large portion
+of contiguous physical memory at boot time which can be
+allocated/deallocated by kernel drivers.
+
+This sort of hack is necessary for devices such as RAM-less video
+framegrabbers which need a big chunk of contiguous physical RAM,
+larger than whatever get_free_pages or kmalloc can provide. Also, this
+memory is safe to remap_page_range() into user space, e.g., for
+mmap().
+
+To use:
+	Use the boot option
+		bigphysarea=<number of pages>
+	e.g. by adding a line
+	append="bigphysarea=1024"
+	to your /etc/lilo.conf to specify the number of pages to
+	reserve. If you don't use this option then no pages will
+	be reserved. Usage can be monitored through the proc
+	filesystem, just type 'cat /proc/bigphysarea'
+
+This code is based on code from M. Welsh (mdw@cs.cornell.edu).
+
+Questions, comments, bug reports? Mail butenuth@uni-paderborn.de or
+look at 
+
+http://www.uni-paderborn.de/fachbereich/AG/heiss/linux/bigphysarea.html
+
+for a new version.
+
+Happy hacking!
+Roger Butenuth
+
+2.3.36,2.4.7 hacks by Fred Barnes (frmb2@ukc.ac.uk)
+
diff -u -p -L linux-2.4.18/arch/i386/config.in.orig linux-2.4.18/arch/i386/config.in
--- linux-2.4.18/arch/i386/config.in
+++ linux-2.4.18/arch/i386/config.in	Tue Mar 19 13:27:44 2002
@@ -201,6 +201,7 @@ fi
 if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
    define_bool CONFIG_HAVE_DEC_LOCK y
 fi
+bool 'Bigphysarea support' CONFIG_BIGPHYSAREA
 endmenu
 
 mainmenu_option next_comment
diff -u -p -L linux-2.4.18/fs/proc/proc_misc.c.orig linux-2.4.18/fs/proc/proc_misc.c
--- linux-2.4.18/fs/proc/proc_misc.c
+++ linux-2.4.18/fs/proc/proc_misc.c	Tue Mar 19 13:48:55 2002
@@ -64,6 +64,9 @@ extern int get_swaparea_info (char *);
 #ifdef CONFIG_SGI_DS1286
 extern int get_ds1286_status(char *);
 #endif
+#ifdef CONFIG_BIGPHYSAREA
+extern int get_bigphysarea_info (char *);
+#endif
 
 static int proc_calc_metrics(char *page, char **start, off_t off,
 				 int count, int *eof, int len)
@@ -410,6 +413,15 @@ static int memory_read_proc(char *page, 
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
+#ifdef CONFIG_BIGPHYSAREA
+static int bigphysarea_read_proc (char *page, char **start, off_t off,
+				int count, int *eof, void *data)
+{
+	int len = get_bigphysarea_info (page);
+	return proc_calc_metrics (page, start, off, count, eof, len);
+}
+#endif	/* CONFIG_BIGPHYSAREA */
+
 /*
  * This function accesses profiling information. The returned data is
  * binary: the sampling step and the actual contents of the profile
@@ -526,6 +538,9 @@ void __init proc_misc_init(void)
 		{"swaps",	swaps_read_proc},
 		{"iomem",	memory_read_proc},
 		{"execdomains",	execdomains_read_proc},
+#ifdef CONFIG_BIGPHYSAREA
+		{"bigphysarea",	bigphysarea_read_proc},
+#endif
 		{NULL,}
 	};
 	for (p = simple_ones; p->name; p++)
diff -u -p -L linux-2.4.18/include/linux/bigphysarea.h.orig linux-2.4.18/include/linux/bigphysarea.h
--- linux-2.4.18/include/linux/bigphysarea.h
+++ linux-2.4.18/include/linux/bigphysarea.h	Tue Mar 19 13:27:44 2002
@@ -0,0 +1,33 @@
+/* linux/mm/bigphysarea.h, M. Welsh (mdw@cs.cornell.edu)
+ * Copyright (c) 1996 by Matt Welsh.
+ * Extended by Roger Butenuth (butenuth@uni-paderborn.de), October 1997
+ *
+ * This is a set of routines which allow you to reserve a large (?)
+ * amount of physical memory at boot-time, which can be allocated/deallocated
+ * by drivers. This memory is intended to be used for devices such as
+ * video framegrabbers which need a lot of physical RAM (above the amount
+ * allocated by kmalloc). This is by no means efficient or recommended;
+ * to be used only in extreme circumstances.
+ *
+ */
+
+#ifndef __LINUX_BIGPHYSAREA_H
+#define __LINUX_BIGPHYSAREA_H
+
+#include <linux/types.h>
+
+extern caddr_t bigphysarea;
+
+/* original interface */
+extern void bigphysarea_setup(int pages);
+extern void bigphysarea_init(void);
+extern caddr_t bigphysarea_alloc(int size);
+extern void bigphysarea_free(caddr_t addr, int size);
+
+/* new interface */
+extern caddr_t bigphysarea_alloc_pages(int count, int align, int priority);
+extern void bigphysarea_free_pages(caddr_t base);
+
+#endif __LINUX_BIGPHYSAREA_H
+
+
diff -u -p -L linux-2.4.18/init/main.c.orig linux-2.4.18/init/main.c
--- linux-2.4.18/init/main.c
+++ linux-2.4.18/init/main.c	Tue Mar 19 13:27:44 2002
@@ -7,6 +7,8 @@
  *  Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96
  *  Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96
  *  Simplified starting of init:  Michael A. Griffith <grif@acm.org> 
+ *  Added bigphysarea support - Roger Butenuth <butenuth@uni-paderborn.de> Jan 2000
+ *  Bigphysarea for newer (2.3, 2.4) kernels - Fred Barnes <frmb2@ukc.ac.uk> Jul 2001
  */
 
 #define __KERNEL_SYSCALLS__
@@ -69,6 +71,10 @@ extern int irda_device_init(void);
 #include <asm/smp.h>
 #endif
 
+#ifdef CONFIG_BIGPHYSAREA
+#include <linux/bigphysarea.h>
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -142,6 +148,19 @@ static int __init profile_setup(char *st
 
 __setup("profile=", profile_setup);
 
+#ifdef CONFIG_BIGPHYSAREA
+
+static int __init own_bigphysarea_setup(char *str)
+{
+	int par;
+	if (get_option(&str,&par)) {
+		bigphysarea_setup(par);
+	}
+	return 1;
+}
+
+__setup("bigphysarea=", own_bigphysarea_setup);
+#endif
 
 static struct dev_name_struct {
 	const char *name;
@@ -591,6 +610,10 @@ asmlinkage void __init start_kernel(void
 		    "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
 		initrd_start = 0;
 	}
+#endif
+#ifdef CONFIG_BIGPHYSAREA
+	/* Using the bootmem interface for getting the pages */
+	bigphysarea_init();     
 #endif
 	mem_init();
 	kmem_cache_sizes_init();
diff -u -p -L linux-2.4.18/mm/Makefile.orig linux-2.4.18/mm/Makefile
--- linux-2.4.18/mm/Makefile
+++ linux-2.4.18/mm/Makefile	Tue Mar 19 20:49:57 2002
@@ -9,12 +9,12 @@
 
 O_TARGET := mm.o
 
-export-objs := shmem.o filemap.o
+export-objs := shmem.o filemap.o bigphysarea.o
 
 obj-y	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
 	    vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
 	    page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
-	    shmem.o
+	    shmem.o bigphysarea.o
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
 
diff -u -p -L linux-2.4.18/mm/bigphysarea.c.orig linux-2.4.18/mm/bigphysarea.c
--- linux-2.4.18/mm/bigphysarea.c
+++ linux-2.4.18/mm/bigphysarea.c	Fri Mar 22 11:19:14 2002
@@ -0,0 +1,356 @@
+/* linux/mm/bigphysarea.c, M. Welsh (mdw@cs.cornell.edu)
+ * Copyright (c) 1996 by Matt Welsh.
+ * Extended by Roger Butenuth (butenuth@uni-paderborn.de), October 1997
+ * Modified for 2.3.x and 2.4.x kernels by Fred Barnes (frmb2@ukc.ac.uk),
+ *   January 2000, Febuary/March 2002
+ *
+ * This is a set of routines which allow you to reserve a large (?) 
+ * amount of physical memory at boot-time, which can be allocated/deallocated
+ * by drivers. This memory is intended to be used for devices such as 
+ * video framegrabbers which need a lot of physical RAM (above the amount
+ * allocated by kmalloc). This is by no means efficient or recommended;
+ * to be used only in extreme circumstances.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+
+/* this is really just to help export-objs in the Makefile */
+#if defined(CONFIG_BIGPHYSAREA)
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/bootmem.h>
+#include <linux/bigphysarea.h>
+
+typedef struct range_struct {
+  struct range_struct *next;
+  caddr_t base;			/* base of allocated block */
+  size_t  size;			/* size in bytes */
+} range_t;
+
+static int bigphysarea_pages = 0;
+/*
+ * 0: nothing initialized
+ * 1: bigphysarea_pages initialized
+ * 2: free list initialized
+ */
+static int init_level = 0;
+
+/*
+ * The free list and the used list are protected by one lock.
+ */
+static spinlock_t big_lock = SPIN_LOCK_UNLOCKED;
+static range_t *free_list = NULL;
+static range_t *used_list = NULL;
+
+caddr_t bigphysarea = 0;
+
+void bigphysarea_setup(int pages)
+{
+	bigphysarea_pages = pages;
+	return;
+}
+
+
+void bigphysarea_init(void) {
+	if (bigphysarea_pages == 0)
+	{
+		printk("bigphysarea: No pages requested.\n");
+		return;
+	}
+
+	bigphysarea = (caddr_t)alloc_bootmem_low_pages(bigphysarea_pages * PAGE_SIZE);
+	if( bigphysarea == (caddr_t)0 ) {
+		printk("bigphysarea: Unable to allocate %d pages.\n", bigphysarea_pages);
+		return;
+	}
+	
+	init_level = 1;
+
+	printk("bigphysarea: Allocated %d pages (%lu bytes) at 0x%08lx.\n",
+	       bigphysarea_pages, (unsigned long)(bigphysarea_pages * PAGE_SIZE), (unsigned long)bigphysarea);
+
+	return;
+}
+
+/*
+ * When we have pages but don't have a freelist, put all pages in
+ * one free list entry. Return 0 on success, 1 on error.
+ */
+static int init2(int priority)
+{
+	int res;
+
+	spin_lock(&big_lock);	/* >>>>>>>>>> */
+	if (init_level == 1) {
+		free_list = kmalloc(sizeof(range_t), priority);
+		if (free_list != NULL) {
+			free_list->next = NULL;
+			free_list->base = bigphysarea;
+			free_list->size = bigphysarea_pages * PAGE_SIZE;
+			init_level = 2;
+			res = 0;
+		} else 
+			res = 1;
+	} else
+		res = 1;
+
+	spin_unlock(&big_lock);	/* <<<<<<<<<< */
+	return res;
+}
+
+
+/*
+ * Allocate `count' pages from the big physical area. Pages are aligned to
+ * a multiple of `align'. `priority' has the same meaning in kmalloc, it
+ * is needed for management information.
+ * This function may not be called from an interrupt, this is the reason
+ * we can use lock functions without disabling all interrupts.
+ */
+caddr_t bigphysarea_alloc_pages(int count, int align, int priority)
+{
+	range_t *range, **range_ptr, *new_range, *align_range;
+	caddr_t aligned_base;
+	caddr_t res = 0;
+
+	if (init_level < 2)
+		if (init2(priority))
+			return 0;
+	new_range   = NULL;
+	align_range = NULL;
+
+	if (align == 0)
+		align = PAGE_SIZE;
+	else
+		align = align * PAGE_SIZE;
+
+	spin_lock(&big_lock);	/* >>>>>>>>>> */
+	/*
+	 * Search a free block which is large enough, even with alignment.
+	 */
+	range_ptr = &free_list;
+	while (*range_ptr != NULL) {
+		range = *range_ptr;
+		aligned_base =
+		  (caddr_t)((((long)range->base + align - 1) / align) * align);
+		if (aligned_base + count * PAGE_SIZE <= 
+		    range->base + range->size)
+			break;
+	     range_ptr = &range->next;
+	}
+	if (*range_ptr == NULL) {
+		res = 0;
+		goto ret_label;
+	}
+	range = *range_ptr;
+	/*
+	 * When we have to align, the pages needed for alignment can
+	 * be put back to the free pool.
+	 * We check here if we need a second range data structure later
+	 * and allocate it now, so that we don't have to check for a
+	 * failed kmalloc later.
+	 */
+	if (aligned_base - range->base + count * PAGE_SIZE < range->size) {
+		new_range = kmalloc(sizeof(range_t), priority);
+		if (new_range == NULL) {
+			res = 0;
+			goto ret_label;
+		}
+	}
+	if (aligned_base != range->base) {
+		align_range = kmalloc(sizeof(range_t), priority);
+		if (align_range == NULL) {
+			if (new_range != NULL)
+				kfree(new_range);
+			res = 0;
+			goto ret_label;
+		}
+		align_range->base = range->base;
+		align_range->size = aligned_base - range->base;
+		range->base = aligned_base;
+		range->size -= align_range->size;
+		align_range->next = range;
+		*range_ptr = align_range;
+		range_ptr = &align_range->next;
+	}
+	if (new_range != NULL) {
+		/*
+		 * Range is larger than needed, create a new list element for
+		 * the used list and shrink the element in the free list.
+		 */
+		new_range->base        = range->base;
+		new_range->size        = count * PAGE_SIZE;
+		range->base = new_range->base + new_range->size;
+		range->size = range->size - new_range->size;
+	} else {
+		/*
+		 * Range fits perfectly, remove it from free list.
+		 */
+		*range_ptr = range->next;
+		new_range = range;
+	}
+	/*
+	 * Insert block into used list
+	 */
+	new_range->next = used_list;
+	used_list = new_range;
+
+	res = new_range->base;
+ ret_label:
+	spin_unlock(&big_lock);	/* <<<<<<<<<< */
+	return res;
+
+}
+
+
+/*
+ * Free pages allocated with `bigphysarea_alloc_pages'. `base' must be an
+ * address returned by `bigphysarea_alloc_pages'.
+ * This function my not be called from an interrupt, for this reason we 
+ * can use a lock without interrupt disabling.
+ */
+void bigphysarea_free_pages(caddr_t base)
+{
+	range_t *prev, *next, *range, **range_ptr;
+  
+	spin_lock(&big_lock);	/* >>>>>>>>>> */
+	/*
+	 * Search the block in the used list.
+	 */
+	for (range_ptr = &used_list;
+	     *range_ptr != NULL;
+	     range_ptr = &(*range_ptr)->next)
+		if ((*range_ptr)->base == base)
+			break;
+	if (*range_ptr == NULL) {
+		printk("bigphysarea_free_pages(0x%08x), not allocated!\n",
+		       (unsigned)base);
+		goto ret_label;
+	}
+	range = *range_ptr;
+	/*
+	 * Remove range from the used list:
+	 */
+	*range_ptr = (*range_ptr)->next;
+	/*
+	 * The free-list is sorted by address, search insertion point
+	 * and insert block in free list.
+	 */
+	for (range_ptr = &free_list, prev = NULL;
+	     *range_ptr != NULL;
+	     prev = *range_ptr, range_ptr = &(*range_ptr)->next)
+		if ((*range_ptr)->base >= base)
+			break;
+	range->next  = *range_ptr;
+	*range_ptr   = range;
+	/*
+	 * Concatenate free range with neighbors, if possible.
+	 * Try for upper neighbor (next in list) first, then
+	 * for lower neighbor (predecessor in list).
+	 */
+	if (range->next != NULL &&
+	    range->base + range->size == range->next->base) {
+		next = range->next;
+		range->size += range->next->size;
+		range->next = next->next;
+		kfree(next);
+	}
+	if (prev != NULL &&
+	    prev->base + prev->size == range->base) {
+		prev->size += prev->next->size;
+		prev->next = range->next;
+		kfree(range);
+	}
+ ret_label:
+	spin_unlock(&big_lock);	/* <<<<<<<<<< */
+}
+
+caddr_t bigphysarea_alloc(int size)
+{
+	int pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+
+	return bigphysarea_alloc_pages(pages, 1, GFP_KERNEL);
+}
+
+void bigphysarea_free(caddr_t addr, int size)
+{
+	(void)size;
+	bigphysarea_free_pages(addr);
+}
+
+int get_bigphysarea_info(char *buf)
+{
+	char    *p = buf;
+	range_t *ptr;
+	int     free_count, free_total, free_max;
+	int     used_count, used_total, used_max;
+
+	if (init_level == 1)
+	  init2(GFP_KERNEL);
+
+	spin_lock(&big_lock);	/* >>>>>>>>>> */
+	free_count = 0;
+	free_total = 0;
+	free_max   = 0;
+	for (ptr = free_list; ptr != NULL; ptr = ptr->next) {
+		free_count++;
+		free_total += ptr->size;
+		if (ptr->size > free_max)
+			free_max = ptr->size;
+	}
+
+	used_count = 0;
+	used_total = 0;
+	used_max   = 0;
+	for (ptr = used_list; ptr != NULL; ptr = ptr->next) {
+		used_count++;
+		used_total += ptr->size;
+		if (ptr->size > used_max)
+			used_max = ptr->size;
+	}
+	spin_unlock(&big_lock);	/* <<<<<<<<<< */
+
+	if (bigphysarea_pages == 0) {
+		p += sprintf(p, "No big physical area allocated!\n");
+		return  p - buf;
+	}
+	  
+	p += sprintf(p, "Big physical area, size %ld kB\n",
+		     bigphysarea_pages * PAGE_SIZE / 1024);
+	p += sprintf(p, "                       free list:             used list:\n");
+	p += sprintf(p, "number of blocks:      %8d               %8d\n",
+		     free_count, used_count);
+	p += sprintf(p, "size of largest block: %8d kB            %8d kB\n",
+		     free_max / 1024, used_max / 1024);
+	p += sprintf(p, "total:                 %8d kB            %8d kB\n",
+		     free_total / 1024, used_total /1024);
+
+	return  p - buf;
+}
+
+EXPORT_SYMBOL(bigphysarea_alloc);
+EXPORT_SYMBOL(bigphysarea_free);
+
+#endif	/* defined(CONFIG_BIGPHYSAREA) */

