* Use kernel module instead Big Physical Area patch
@ 2001-08-05 10:51 Constantine Gavrilov
2001-08-05 11:04 ` Pauline Middelink
0 siblings, 1 reply; 3+ messages in thread
From: Constantine Gavrilov @ 2001-08-05 10:51 UTC (permalink / raw)
To: middelink; +Cc: linux Kernel
[-- Attachment #1: Type: text/plain, Size: 1685 bytes --]
Hi,
I wrote a small kernel module that defines and exports bfree() and
bmalloc() functions. The idea is to use this kernel module as a
replacement for big physcial area kernel patch.
For example, zoran kernel driver relies on the big physical area API for
v4l (used for video-in-a-window) to work. While the driver will compile
and load with a non-patched kernel, v4l will not work reliably without
big physical area support since the chip needs about 2megs of contiguous
memory to display in a window. This means one really has to use a
patched kernel.
This module removes this requirement and allows v4l to work reliably
with a non-patched kernel. The idea is to load the module from initrd or
right after boot. I have used __get_free_pages() and mem_map_reserve()
to pre-allocate the memory.
I have left the user-mode code that I used to debug allocation and
garbage collection. Compiled into a user-space program, the code will
allocate/free random chunks from a pre-allocated space and print out the
used list.
Comments?
Questions:
1) On a 256 MB machine, I was able to pre-allocate 512 pages using
__get_free_pages(...,get_order(size)). It is enough for one card, but
not for more. Any ideas on how to pre-allocate more?
2) __get_free_pages(...,get_order(size)) can be used to pre-allocate 2^n
contiguous pages (2,4,16,...512, ...., 1024). Can I use something else
from a kernel module to request a number that is not 2^n (say 750)?
--
----------------------------------------
Constantine Gavrilov
Linux Leader
Optibase Ltd
7 Shenkar St, Herzliya 46120, Israel
Phone: (972-9)-970-9140
Fax: (972-9)-958-6099
----------------------------------------
[-- Attachment #2: memreserve.c --]
[-- Type: text/plain, Size: 8411 bytes --]
/***************************************************************************
memreserve.c - description
-------------------
begin : Tue Jul 31 2001
copyright : (C) 2001 by Optibase Ltd
email : linux@optibase.com
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifndef __KERNEL__
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
/* module stuff */
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#define EXPORT_SYMBOL(x)
#define MODULE_PARM(x,y)
#define GFP_USER
#define GFP_DMA
/* memory management stuff */
#define kmalloc(x,y) (malloc(x))
#define kfree(x) (free(x))
#define __get_free_pages(x,y) (malloc(y))
#define free_pages(x, y) (free((void *)x))
#define mem_map_reserve(x) (printf("reserve print: 0x%08lx\n",x))
#define mem_map_unreserve(x) (printf("unreserve print: 0x%08lx\n",x))
#define virt_to_page(x) (x)
#define phys_to_virt(x) (x)
#define get_order(x) (x)
/* from asm/page.h */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
/* lock stuff */
#define write_lock(x) (pthread_mutex_lock(x))
#define write_unlock(x) (pthread_mutex_unlock(x))
#define RW_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER
#define rwlock_t pthread_mutex_t
/* printk stuff */
#define printk printf
#define KERN_WARNING
#define KERN_INFO
#define KERN_ERR
#define KERN_DEBUG
#else
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <asm/page.h>
#include <asm/io.h>
#include <linux/mm.h>
#include <linux/wrapper.h>
#endif
void bfree(void*, unsigned long);
void* bmalloc(unsigned long);
EXPORT_SYMBOL(bfree);
EXPORT_SYMBOL(bmalloc);
int reserve;
static unsigned long reserve_start;
MODULE_PARM(reserve, "i");
struct reserve_list {
unsigned long mem;
unsigned long size;
struct reserve_list *next;
};
struct reserve_list *used_list=NULL;
static rwlock_t alloc_ops=RW_LOCK_UNLOCKED;
#ifdef __KERNEL__
int init_module(void)
{
unsigned long adr;
unsigned long size;
#else
int init_module(int x)
{
unsigned long adr;
unsigned long size;
reserve=x;
#endif
if (!reserve) {
printk(KERN_ERR "memreserve: Supply a positive reserve param\n");
return -EINVAL;
}
size=reserve*PAGE_SIZE;
reserve_start = (unsigned long)__get_free_pages(GFP_USER|GFP_DMA,get_order(size));
if (reserve_start) {
adr = reserve_start;
while (size > 0) {
mem_map_reserve(virt_to_page(phys_to_virt(adr)));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}
}
else {
printk(KERN_ERR "memreserve: Cannot allocate contiguous memory of %lu bytes\n", size);
return -EINVAL;
}
printk(KERN_INFO "memreserve: Allocated contiguous memory of %lu bytes\n", reserve*PAGE_SIZE);
return 0;
}
void cleanup_module(void)
{
unsigned long adr;
unsigned long size;
if(used_list != NULL) {
printk(KERN_ERR "memreserve: Memory leak somewhere -- more than zero member in the used list\n");
printk(KERN_ERR "memreserve: Check your usage count\n");
printk(KERN_ERR "memreserve: Will not free memory\n");
return;
}
if (reserve_start) {
adr = reserve_start;
size = reserve * PAGE_SIZE;
while (size > 0) {
mem_map_unreserve(virt_to_page(phys_to_virt(adr)));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}
free_pages(reserve_start,get_order(reserve * PAGE_SIZE));
}
}
void* bmalloc(unsigned long req_size)
{
/*we need a lock here against simultaneous entry*/
struct reserve_list *list, *newmember, *prevmember;
unsigned long prevaddr, size;
write_lock(&alloc_ops);
size=PAGE_ALIGN(req_size);
prevaddr=reserve_start;
prevmember=NULL;
printk(KERN_DEBUG "memreserve: Rounded requested size %lu (0x%08lx) to 0x%08lx (%lu pages)\n", req_size, req_size,size, size/PAGE_SIZE);
for(list=used_list; list != NULL; list=list->next)
{
if( (list->mem - prevaddr) >= size) {
newmember=(struct reserve_list *)kmalloc(sizeof(struct reserve_list), GFP_USER);
if (!newmember) {
printk(KERN_ERR "memreserve: Out of memory\n");
write_unlock(&alloc_ops);
return NULL;
}
newmember->next=list;
newmember->mem=prevaddr;
newmember->size=size;
if(prevmember != NULL)
prevmember->next=newmember;
else
used_list=newmember;
MOD_INC_USE_COUNT;
write_unlock(&alloc_ops);
return (void *)prevaddr; /* we got our address */
}
prevmember=list;
prevaddr=list->mem+list->size;
}
/* list is NULL here; this code both works for both first and the last list member */
if(size <= reserve_start + (PAGE_SIZE * reserve) - prevaddr) {
newmember=(struct reserve_list *)kmalloc(sizeof(struct reserve_list), GFP_USER);
if (!newmember) {
printk(KERN_ERR "memreserve: Out of memory\n");
write_unlock(&alloc_ops);
return NULL;
}
newmember->mem=prevaddr;
newmember->size=size;
if(prevmember == NULL) /* this is the first member */
used_list=newmember;
else /* this is the last member */
prevmember->next=newmember;
newmember->next=NULL;
MOD_INC_USE_COUNT;
write_unlock(&alloc_ops);
return (void *)prevaddr; /* we got our address */
}
else
printk(KERN_WARNING "memreserve: Could not find big enough region in the free list\n");
write_unlock(&alloc_ops);
return NULL;
}
void bfree(void *mem, unsigned long req_size)
{
/*we need a lock here against simultaneous entry*/
struct reserve_list *list, *prevaddr;
unsigned long size;
write_lock(&alloc_ops);
size=PAGE_ALIGN(req_size);
prevaddr=NULL;
for(list=used_list; list != NULL; list=list->next) {
if(list->mem == (unsigned long)mem && list->size == size) {
if(prevaddr == NULL)
used_list=list->next;
else
prevaddr->next=list->next;
kfree(list);
MOD_DEC_USE_COUNT;
write_unlock(&alloc_ops);
return;
}
prevaddr=list;
}
printk(KERN_WARNING "memreserve: Someone requested illegal deallocation\n");
write_unlock(&alloc_ops);
}
void print_used_list(void)
{
/*we need a lock here against simultaneous entry*/
struct reserve_list *list;
write_lock(&alloc_ops);
printk(KERN_INFO "Reserve start is 0x%08lx, reserve size is 0x%08lx\n", reserve_start, reserve*PAGE_SIZE);
for(list=used_list; list != NULL; list=list->next) {
printk(KERN_INFO "memreserve: Address is 0x%08lx (%lu pages), size is 0x%08lx (%lu pages)\n", list->mem, list->mem/PAGE_SIZE, list->size, list->size/PAGE_SIZE);
}
write_unlock(&alloc_ops);
}
#ifndef __KERNEL__
int main()
{
int n=0;
int i=0;
int k;
struct reserve_list *list;
unsigned long choose_size(unsigned long);
int choose_index(int);
int choose_bool(void);
#define MAX_ALLOC 100
if(init_module(MAX_ALLOC) != 0) {
printf("Could not get memory\n");
exit(1);
}
while(n>=0) {
if(n<=3) {
if (bmalloc(choose_size(MAX_ALLOC)/10) != NULL)
n++;
}
else {
if(choose_bool() == 0) {
if (bmalloc(choose_size(MAX_ALLOC)/10) != NULL)
n++;
}
else {
i=choose_index(n);
list=used_list;
for(k=0;k<(i-1);k++)
list=list->next;
printf("Free index %d\n", i);
bfree((void *)list->mem, list->size);
n--;
}
}
print_used_list(); getchar();
}
cleanup_module();
return 0;
}
unsigned long choose_size(unsigned long MAX_SIZE)
{
double pos;
pos=((double)MAX_SIZE*(double)PAGE_SIZE*(double)random())/(double)(RAND_MAX+1.0);
return 1+(unsigned long) pos;
}
int choose_index(int MAX_INDEX)
{
double pos;
pos=((double)MAX_INDEX*(double)random())/(double)(RAND_MAX+1.0);
return 1+(int) pos;
}
int choose_bool(void)
{
long pos;
pos=random();
if(pos <= (RAND_MAX/2))
return 0;
else
return 1;
}
#endif
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: Use kernel module instead Big Physical Area patch
2001-08-05 10:51 Use kernel module instead Big Physical Area patch Constantine Gavrilov
@ 2001-08-05 11:04 ` Pauline Middelink
2001-08-05 12:42 ` Constantine Gavrilov
0 siblings, 1 reply; 3+ messages in thread
From: Pauline Middelink @ 2001-08-05 11:04 UTC (permalink / raw)
To: Constantine Gavrilov; +Cc: middelink, linux Kernel
On Sun, 05 Aug 2001 around 13:51:37 +0300, Constantine Gavrilov wrote:
> Hi,
>
> I wrote a small kernel module that defines and exports bfree() and
> bmalloc() functions. The idea is to use this kernel module as a
> replacement for big physcial area kernel patch.
Ahum, but this is _not_ a kernel replacement for the bigphysarea
patch. If also requires the patch to be integrated in the main-stream
kernel. Following your reasoning you could just as well get Linus
to accept the bigphysarea patch and voila, all the problems you
describe are gone.
> For example, zoran kernel driver relies on the big physical area API for
> v4l (used for video-in-a-window) to work. While the driver will compile
> and load with a non-patched kernel, v4l will not work reliably without
> big physical area support since the chip needs about 2megs of contiguous
> memory to display in a window. This means one really has to use a
> patched kernel.
Check, or load the zoran module very early in the boot process.
> This module removes this requirement and allows v4l to work reliably
^^^ zoran driver
> with a non-patched kernel. The idea is to load the module from initrd or
> right after boot. I have used __get_free_pages() and mem_map_reserve()
> to pre-allocate the memory.
Wasn't it easier to just take bigphysarea and made a module out
of it? It seems you already took a lot of the code, so why not
take the last step?
> I have left the user-mode code that I used to debug allocation and
> garbage collection. Compiled into a user-space program, the code will
> allocate/free random chunks from a pre-allocated space and print out the
> used list.
/proc/bigphysarea?
> Comments?
>
> Questions:
> 1) On a 256 MB machine, I was able to pre-allocate 512 pages using
> __get_free_pages(...,get_order(size)). It is enough for one card, but
> not for more. Any ideas on how to pre-allocate more?
> 2) __get_free_pages(...,get_order(size)) can be used to pre-allocate 2^n
> contiguous pages (2,4,16,...512, ...., 1024). Can I use something else
> from a kernel module to request a number that is not 2^n (say 750)?
Congrats. Now you know why I used bootmem, which as a bad sideeffect
prevents one to make bigphysarea a module :(
On the last question: no. get_free_pages() works with _pages_. kmalloc()
works with sizes. (but you know the problems with that one.)
> /***************************************************************************
> memreserve.c - description
> -------------------
> begin : Tue Jul 31 2001
> copyright : (C) 2001 by Optibase Ltd
Eh, if you insist of using this much of the bigphysarea ideas,
you could at least give us some credit/mention?
> email : linux@optibase.com
Met vriendelijke groet,
Pauline Middelink
--
GPG Key fingerprint = 2D5B 87A7 DDA6 0378 5DEA BD3B 9A50 B416 E2D0 C3C2
For more details look at my website http://www.polyware.nl/~middelink
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: Use kernel module instead Big Physical Area patch
2001-08-05 11:04 ` Pauline Middelink
@ 2001-08-05 12:42 ` Constantine Gavrilov
0 siblings, 0 replies; 3+ messages in thread
From: Constantine Gavrilov @ 2001-08-05 12:42 UTC (permalink / raw)
To: Pauline Middelink; +Cc: linux Kernel
Pauline Middelink wrote:
>On Sun, 05 Aug 2001 around 13:51:37 +0300, Constantine Gavrilov wrote:
>
>>Hi,
>>
>>I wrote a small kernel module that defines and exports bfree() and
>>bmalloc() functions. The idea is to use this kernel module as a
>>replacement for big physcial area kernel patch.
>>
>
>Ahum, but this is _not_ a kernel replacement for the bigphysarea
>patch. If also requires the patch to be integrated in the main-stream
>kernel. Following your reasoning you could just as well get Linus
>to accept the bigphysarea patch and voila, all the problems you
>describe are gone.
>
You missed the point here. Of course big physical area is preferrable
and it is guaranteed to work for larger pre-allocations as well. If you
ask me, I am for big physical area API in the Linus kernel. It is a
clean drop-in and will not touch anything. Advantages are obvious, of
course. And no, this code does not require modifications to the kernel
source since it is a module. I do not have to re-compile the kernel with
a big physical area api, I just need to compile a module against the
kernel I have. The idea here is if I ship a 3-d party module that
requires contiguous memory support, I can add this code to the source of
the module and it will work with the distribution kernels. The idea is
to allow the 3d party (or included) modules to work with non-patched
distribution kernels.
>>For example, zoran kernel driver relies on the big physical area API for
>>v4l (used for video-in-a-window) to work. While the driver will compile
>>and load with a non-patched kernel, v4l will not work reliably without
>>big physical area support since the chip needs about 2megs of contiguous
>>memory to display in a window. This means one really has to use a
>>patched kernel.
>>
>
>Check, or load the zoran module very early in the boot process.
>
For Zoran case, loading early will not really help because memory is not
allocated unil one opens /dev/video. However, this can be easily fixed.
In any case, I want to be able to load/unload my card drivers. Our usage
of VPXpress cards based on Zoran chips requires that. So, the module
pre-allocating the ememory is more flexible.
>
>Wasn't it easier to just take bigphysarea and made a module out
>of it? It seems you already took a lot of the code, so why not
>take the last step?
>
I used some code from Zoran driver and none from the big physical area
patch (please see below). The code re-implements bfree() and balloc()
interfaces that Zoran driver uses. It is the bree() and balloc()
functions in Zoran driver that my module re-implemented that were using
the big physical area functions. I got myself confused somewhat. To
call it a big physical area replacement, I had to implement
bigphysarea_alloc, bigphysarea_free, bigphysarea_alloc_pages,
bigphysarea_free_pages and possibly add the proc support. I can still do
that.
>>I have left the user-mode code that I used to debug allocation and
>>garbage collection. Compiled into a user-space program, the code will
>>allocate/free random chunks from a pre-allocated space and print out the
>>used list.
>>
>
>/proc/bigphysarea?
>
What good does it make if you your garbage collection structures get
corrupted and kernel oopses?
>
>Eh, if you insist of using this much of the bigphysarea ideas,
>you could at least give us some credit/mention?
>
>> email : linux@optibase.com
>>
>
> Met vriendelijke groet,
> Pauline Middelink
>
Well, duly noted. Everyone knows what big physical area API is and who
supports it. Is it not so? I did not mean to rob you of credit. I do use
ideas of big physical area API, but no code was used from the patch
itself. The sample pre-allocation and release code was taken from YOUR
Zoran driver. This is what I use from your code in my init_module():
................................................
reserve_start = (unsigned
long)__get_free_pages(GFP_USER|GFP_DMA,get_order(size));
if (reserve_start) {
adr = reserve_start;
while (size > 0) {
mem_map_reserve(virt_to_page(phys_to_virt(adr)));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}
}
....................................................
And this is what I use from your code in my cleanup_module():
.....................................................
if (reserve_start) {
adr = reserve_start;
size = reserve * PAGE_SIZE;
while (size > 0) {
mem_map_unreserve(virt_to_page(phys_to_virt(adr)));
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}
free_pages(reserve_start,get_order(reserve * PAGE_SIZE));
}
.......................................................
The rest basically is the play with data structures. Yes, I do
re-implement bfree() and balloc(). In your Zoran driver, these
functions were defined to use bigphysarea_alloc_pages and
bigphysarea_free_pages interfaces from big physical area patch that you
maitain for the new kernels. I have done it in order to allow the use of
drivers that rely on this patch with non-patched kernels. I did this
work for the possible inclusion into the future drivers for our Xpress
cards. These cards use Zoran chips and we have used your driver code. We
have given you due credit in the driver source and in the documentation
(for example, see http://www.optibase.com/linux/docs.asp).
--
----------------------------------------
Constantine Gavrilov
Linux Leader
Optibase Ltd
7 Shenkar St, Herzliya 46120, Israel
Phone: (972-9)-970-9140
Fax: (972-9)-958-6099
----------------------------------------
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2001-08-05 12:41 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2001-08-05 10:51 Use kernel module instead Big Physical Area patch Constantine Gavrilov
2001-08-05 11:04 ` Pauline Middelink
2001-08-05 12:42 ` Constantine Gavrilov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox