diff -u -p linux-2.4.7/Documentation/Configure.help.orig linux-2.4.7/Documentation/Configure.help
--- linux-2.4.7/Documentation/Configure.help.orig	Mon Aug  6 07:26:13 2001
+++ linux-2.4.7/Documentation/Configure.help	Thu Jul 26 04:27:02 2001
@@ -132,6 +132,18 @@ CONFIG_X86_UP_IOAPIC
   If you have system with several CPU's, you do not need to say Y
   here: 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 linux-2.4.7/Documentation/bigphysarea.txt.orig linux-2.4.7/Documentation/bigphysarea.txt
--- linux-2.4.7/Documentation/bigphysarea.txt.orig	Thu Jul 26 04:27:17 2001
+++ linux-2.4.7/Documentation/bigphysarea.txt	Thu Jul 26 04:29:21 2001
@@ -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 linux-2.4.7/arch/i386/config.in.orig linux-2.4.7/arch/i386/config.in
--- linux-2.4.7/arch/i386/config.in.orig	Thu Jul 26 04:32:39 2001
+++ linux-2.4.7/arch/i386/config.in	Thu Jul 26 04:33:18 2001
@@ -180,6 +180,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 linux-2.4.7/fs/proc/proc_misc.c.orig linux-2.4.7/fs/proc/proc_misc.c
--- linux-2.4.7/fs/proc/proc_misc.c.orig	Thu Jul 26 04:36:11 2001
+++ linux-2.4.7/fs/proc/proc_misc.c	Thu Jul 26 04:40:04 2001
@@ -71,6 +71,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)
@@ -217,6 +220,20 @@ static int cpuinfo_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);
+	if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+#endif
+
 #ifdef CONFIG_PROC_HARDWARE
 static int hardware_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -520,6 +537,9 @@ void __init proc_misc_init(void)
 		{"meminfo",	meminfo_read_proc},
 		{"version",	version_read_proc},
 		{"cpuinfo",	cpuinfo_read_proc},
+#ifdef CONFIG_BIGPHYSAREA
+		{"bigphysarea",	bigphysarea_read_proc},
+#endif
 #ifdef CONFIG_PROC_HARDWARE
 		{"hardware",	hardware_read_proc},
 #endif
diff -u -p linux-2.4.7/include/linux/bigphysarea.h.orig linux-2.4.7/include/linux/bigphysarea.h
--- linux-2.4.7/include/linux/bigphysarea.h.orig	Thu Jul 26 04:40:12 2001
+++ linux-2.4.7/include/linux/bigphysarea.h	Thu Jul 26 04:41:28 2001
@@ -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 linux-2.4.7/init/main.c.orig linux-2.4.7/init/main.c
--- linux-2.4.7/init/main.c.orig	Thu Jul 26 04:42:38 2001
+++ linux-2.4.7/init/main.c	Thu Jul 26 04:48:54 2001
@@ -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__
@@ -70,6 +72,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.
@@ -141,6 +147,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;
@@ -570,6 +589,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 linux-2.4.7/mm/Makefile.orig linux-2.4.7/mm/Makefile
--- linux-2.4.7/mm/Makefile.orig	Thu Jul 26 04:52:10 2001
+++ linux-2.4.7/mm/Makefile	Thu Jul 26 04:53:05 2001
@@ -17,5 +17,6 @@ obj-y	 := memory.o mmap.o filemap.o mpro
 	    shmem.o
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
+obj-$(CONFIG_BIGPHYSAREA) += bigphysarea.o
 
 include $(TOPDIR)/Rules.make
diff -u -p linux-2.4.7/mm/bigphysarea.c.orig linux-2.4.7/mm/bigphysarea.c
--- linux-2.4.7/mm/bigphysarea.c.orig	Thu Jul 26 04:53:19 2001
+++ linux-2.4.7/mm/bigphysarea.c	Thu Jul 26 04:57:06 2001
@@ -0,0 +1,344 @@
+/* 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
+ *
+ * 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>
+#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/malloc.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_pages(bigphysarea_pages);
+	if( bigphysarea == (caddr_t)0 ) {
+		printk("bigphysarea: Unable to allocate %d pages.\n", bigphysarea_pages);
+		return;
+	}
+	
+	init_level = 1;
+
+	printk("bigphysarea: Allocated %d pages at 0x%08lx.\n",
+	       bigphysarea_pages, (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;
+}

