From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S261419AbUKOVzC (ORCPT ); Mon, 15 Nov 2004 16:55:02 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S261395AbUKOVzC (ORCPT ); Mon, 15 Nov 2004 16:55:02 -0500 Received: from tim.nimlabs.org ([69.25.196.37]:42185 "EHLO tim.nimlabs.org") by vger.kernel.org with ESMTP id S261419AbUKOVyM (ORCPT ); Mon, 15 Nov 2004 16:54:12 -0500 Date: Mon, 15 Nov 2004 16:54:11 -0500 From: Nick Martin To: linux-kernel@vger.kernel.org Subject: [PATCH] bigphysarea for 2.6.9 Message-ID: <20041115215411.GA12610@mit.edu> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.6+20040907i Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org I've pulled the bigphysarea patch[1] foward to 2.6.9. Maybe someone here will find it useful. I've only tested on i386, but I don't see why it shouldn't work on other architectures. Enjoy, -- Nick [1]: from http://www.polyware.nl/~middelink/En/hob-v4l.html --------- diff -urN linux-2.6.9.orig/Documentation/bigphysarea.txt linux-2.6.9.bigphys/Documentation/bigphysarea.txt --- linux-2.6.9.orig/Documentation/bigphysarea.txt Wed Dec 31 19:00:00 1969 +++ linux-2.6.9.bigphys/Documentation/bigphysarea.txt Mon Nov 15 15:34:58 2004 @@ -0,0 +1,64 @@ +Bigphysarea +=========== + +This set of functions give you the ability to allocate big +contineous (DMAable) memory for the entire runtime of Linux. +Big meaning here more than 128KB, the maximum allocation +limit of kmalloc(). Due to fragmentation reasons kmalloc() +is unable to garantee allocs of this order during a prolonged +run of the kernel. This new pool of memory blob can be used +during the initialization or use of soundcards of framegrabbers +which are designed without DMA scatter-gatter capabilities. + +For a sample use, see the zoran driver in drivers/char/zr36120_mem.c + +Enjoy, + Pauline Middelink + +How to start +============ +First add bigphysarea= to the +commandline of your kernel. Either do this by adding an +append= line to your /etc/lilo/conf setup or use some +magic marker... +After booting the new kernel there should be a /proc/bigphysarea +file telling your how many blocks/bytes are available. + +The interface description +========================= +The big physical area is mainly managed by two functions. The first one, + +caddr_t bigphysarea_alloc_pages(int count, int align, int priority) + +allocates 'count' pages. The pages are aligned so that there base +address is a multiple of 'PAGE_SIZE * align'. If you don't need more +than page alignment, set 'align' to 0 or 1. 'priority' has the same +meaning as in kmalloc, it can be GFP_ATOMIC (for calls from interrupt +handlers) or GFP_KERNEL (for usual calls). The base address of the +allocated area is returned. + +Allocation can fail for two reasons, in both cases NULL is +returned. First, the physical area is scattered too much or there is +not enough memory, second it is not possible to allocate some memory +with kmalloc for administration of the physical area (very unlikely). + +To free an allocated area, just call + +void bigphysarea_free_pages(caddr_t base) + +with 'base' set to the value returned by 'bigphysarea_alloc_pages'. + +An example how to use this functions can be found in 'module.c'. + +There is still the old interface introduced by M. Welsh: + +caddr_t bigphysarea_alloc(int size) +void bigphysarea_free(caddr_t addr, int size) + +The first function allocates 'size' bytes physically continous +memory. To free the area, bigphysarea_free with a pointer to the area +and its size has to be called. Due to a new allocation algorithm, the +size parameter is no longer really needed when freeing an area. + +In the current version it is not safe to call any of the functions +from an interrupt handler. diff -urN linux-2.6.9.orig/Makefile linux-2.6.9.bigphys/Makefile --- linux-2.6.9.orig/Makefile Mon Oct 18 17:54:38 2004 +++ linux-2.6.9.bigphys/Makefile Mon Nov 15 15:34:58 2004 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 9 -EXTRAVERSION = +EXTRAVERSION = -bigphys NAME=Zonked Quokka # *DOCUMENTATION* diff -urN linux-2.6.9.orig/arch/i386/Kconfig linux-2.6.9.bigphys/arch/i386/Kconfig --- linux-2.6.9.orig/arch/i386/Kconfig Mon Oct 18 17:53:22 2004 +++ linux-2.6.9.bigphys/arch/i386/Kconfig Mon Nov 15 15:46:59 2004 @@ -816,6 +816,18 @@ See for more information. +config BIGPHYS_AREA + bool "Big Physical Area" + ---help--- + Enables kernel support for reserving large areas of physical + memory at boot-time for use by certain device drivers (such as + video framegrabbers, etc.) which require it. To use this + feature, boot the kernel with the boot-time option + 'bigphysarea=nnn' where 'nnn' is the number of pages (a page + is usually 4K) to reserve. + + See for more information. + config EFI bool "Boot from EFI support (EXPERIMENTAL)" depends on ACPI diff -urN linux-2.6.9.orig/arch/i386/defconfig linux-2.6.9.bigphys/arch/i386/defconfig --- linux-2.6.9.orig/arch/i386/defconfig Mon Oct 18 17:54:38 2004 +++ linux-2.6.9.bigphys/arch/i386/defconfig Mon Nov 15 15:34:58 2004 @@ -115,6 +115,8 @@ # CONFIG_HIGHMEM64G is not set # CONFIG_MATH_EMULATION is not set CONFIG_MTRR=y +CONFIG_BIGPHYS_AREA=y + # CONFIG_EFI is not set CONFIG_IRQBALANCE=y CONFIG_HAVE_DEC_LOCK=y diff -urN linux-2.6.9.orig/include/linux/bigphysarea.h linux-2.6.9.bigphys/include/linux/bigphysarea.h --- linux-2.6.9.orig/include/linux/bigphysarea.h Wed Dec 31 19:00:00 1969 +++ linux-2.6.9.bigphys/include/linux/bigphysarea.h Mon Nov 15 15:45:22 2004 @@ -0,0 +1,31 @@ +/* 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 + * Extended for linux-2.1.121 till 2.4.0 (June 2000) + * by Pauline Middelink + * Extended for linux-2.6.9 (November 2004) + * by Nick Martin + * + * 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 + +/* original interface */ +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 -urN linux-2.6.9.orig/mm/Makefile linux-2.6.9.bigphys/mm/Makefile --- linux-2.6.9.orig/mm/Makefile Mon Oct 18 17:54:37 2004 +++ linux-2.6.9.bigphys/mm/Makefile Mon Nov 15 15:34:58 2004 @@ -17,4 +17,5 @@ obj-$(CONFIG_NUMA) += mempolicy.o obj-$(CONFIG_SHMEM) += shmem.o obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o +obj-$(CONFIG_BIGPHYS_AREA) += bigphysarea.o diff -urN linux-2.6.9.orig/mm/bigphysarea.c linux-2.6.9.bigphys/mm/bigphysarea.c --- linux-2.6.9.orig/mm/bigphysarea.c Wed Dec 31 19:00:00 1969 +++ linux-2.6.9.bigphys/mm/bigphysarea.c Mon Nov 15 15:49:01 2004 @@ -0,0 +1,353 @@ +/* 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 + * Extended for linux-2.1.121 till 2.4.0 (June 2000) + * by Pauline Middelink + * Extended for linux-2.6.9 (November 2004) + * by Nick Martin + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int get_info(char* buf, char**, off_t, int); + +typedef struct range_struct { + struct range_struct *next; + caddr_t base; /* base of allocated block */ + size_t size; /* size in bytes */ +} range_t; + +/* + * 0: nothing initialized + * 1: bigphysarea_pages initialized + * 2: free list initialized + */ +static int init_level = 0; +static int bigphysarea_pages = 0; +static caddr_t bigphysarea = 0; +static range_t *free_list = NULL; +static range_t *used_list = NULL; +static struct resource mem_resource = { "Bigphysarea", 0, 0, IORESOURCE_MEM|IORESOURCE_BUSY }; + +static +int __init bigphysarea_init(void) +{ + if (bigphysarea_pages == 0 || bigphysarea == 0) + return -EINVAL; + + /* create to /proc entry for it */ + if (!create_proc_info_entry("bigphysarea",0444,NULL,get_info)) { + // ohoh, no way to free the allocated memory! + // continue without proc support, it not fatal in itself +// free_bootmem((unsigned long)bigphysarea>>PAGE_SHIFT,bigphysarea_pages<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); + } +} +EXPORT_SYMBOL(bigphysarea_free_pages); + +caddr_t bigphysarea_alloc(int size) +{ + int pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; + + return bigphysarea_alloc_pages(pages, 1, GFP_KERNEL); +} +EXPORT_SYMBOL(bigphysarea_alloc); + + +void bigphysarea_free(caddr_t addr, int size) +{ + (void)size; + bigphysarea_free_pages(addr); +} +EXPORT_SYMBOL(bigphysarea_free); + +static +int get_info(char *buf, char **a, off_t b, int c) +{ + 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); + + 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; + } + + 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; +}