⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stram.c

📁 该文件是rt_linux
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * arch/m68k/atari/stram.c: Functions for ST-RAM allocations * * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file COPYING in the main directory of this archive * for more details. */#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/kdev_t.h>#include <linux/major.h>#include <linux/init.h>#include <linux/swap.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/pagemap.h>#include <linux/shm.h>#include <linux/bootmem.h>#include <asm/setup.h>#include <asm/machdep.h>#include <asm/page.h>#include <asm/pgtable.h>#include <asm/atarihw.h>#include <asm/atari_stram.h>#include <asm/io.h>#include <asm/semaphore.h>#ifdef CONFIG_STRAM_SWAP#define MAJOR_NR    Z2RAM_MAJOR#define do_z2_request do_stram_request#include <linux/blk.h>#undef DEVICE_NAME#define DEVICE_NAME	"stram"#endif#undef DEBUG#ifdef DEBUG#define	DPRINTK(fmt,args...) printk( fmt, ##args )#else#define DPRINTK(fmt,args...)#endif#if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC)/* abbrev for the && above... */#define DO_PROC#include <linux/proc_fs.h>#endif/* Pre-swapping comments: * * ++roman: *  * New version of ST-Ram buffer allocation. Instead of using the * 1 MB - 4 KB that remain when the ST-Ram chunk starts at $1000 * (1 MB granularity!), such buffers are reserved like this: * *  - If the kernel resides in ST-Ram anyway, we can take the buffer *    from behind the current kernel data space the normal way *    (incrementing start_mem). *     *  - If the kernel is in TT-Ram, stram_init() initializes start and *    end of the available region. Buffers are allocated from there *    and mem_init() later marks the such used pages as reserved. *    Since each TT-Ram chunk is at least 4 MB in size, I hope there *    won't be an overrun of the ST-Ram region by normal kernel data *    space. *     * For that, ST-Ram may only be allocated while kernel initialization * is going on, or exactly: before mem_init() is called. There is also * no provision now for freeing ST-Ram buffers. It seems that isn't * really needed. * *//* * New Nov 1997: Use ST-RAM as swap space! * * In the past, there were often problems with modules that require ST-RAM * buffers. Such drivers have to use __get_dma_pages(), which unfortunately * often isn't very successful in allocating more than 1 page :-( [1] The net * result was that most of the time you couldn't insmod such modules (ataflop, * ACSI, SCSI on Falcon, Atari internal framebuffer, not to speak of acsi_slm, * which needs a 1 MB buffer... :-). * * To overcome this limitation, ST-RAM can now be turned into a very * high-speed swap space. If a request for an ST-RAM buffer comes, the kernel * now tries to unswap some pages on that swap device to make some free (and * contiguous) space. This works much better in comparison to * __get_dma_pages(), since used swap pages can be selectively freed by either * moving them to somewhere else in swap space, or by reading them back into * system memory. Ok, there operation of unswapping isn't really cheap (for * each page, one has to go through the page tables of all processes), but it * doesn't happen that often (only when allocation ST-RAM, i.e. when loading a * module that needs ST-RAM). But it at least makes it possible to load such * modules! * * It could also be that overall system performance increases a bit due to * ST-RAM swapping, since slow ST-RAM isn't used anymore for holding data or * executing code in. It's then just a (very fast, compared to disk) back * storage for not-so-often needed data. (But this effect must be compared * with the loss of total memory...) Don't know if the effect is already * visible on a TT, where the speed difference between ST- and TT-RAM isn't * that dramatic, but it should on machines where TT-RAM is really much faster * (e.g. Afterburner). *  *   [1]: __get_free_pages() does a fine job if you only want one page, but if * you want more (contiguous) pages, it can give you such a block only if * there's already a free one. The algorithm can't try to free buffers or swap * out something in order to make more free space, since all that page-freeing * mechanisms work "target-less", i.e. they just free something, but not in a * specific place. I.e., __get_free_pages() can't do anything to free * *adjacent* pages :-( This situation becomes even worse for DMA memory, * since the freeing algorithms are also blind to DMA capability of pages. *//* 1998-10-20: ++andreas   unswap_by_move disabled because it does not handle swapped shm pages.*//* 2000-05-01: ++andreas   Integrated with bootmem.  Remove all traces of unswap_by_move.*/#ifdef CONFIG_STRAM_SWAP#define ALIGN_IF_SWAP(x)	PAGE_ALIGN(x)#else#define ALIGN_IF_SWAP(x)	(x)#endif/* get index of swap page at address 'addr' */#define SWAP_NR(addr)		(((addr) - swap_start) >> PAGE_SHIFT)/* get address of swap page #'nr' */#define SWAP_ADDR(nr)		(swap_start + ((nr) << PAGE_SHIFT))/* get number of pages for 'n' bytes (already page-aligned) */#define N_PAGES(n)			((n) >> PAGE_SHIFT)/* The following two numbers define the maximum fraction of ST-RAM in total * memory, below that the kernel would automatically use ST-RAM as swap * space. This decision can be overriden with stram_swap= */#define MAX_STRAM_FRACTION_NOM		1#define MAX_STRAM_FRACTION_DENOM	3/* Start and end (virtual) of ST-RAM */static void *stram_start, *stram_end;/* set after memory_init() executed and allocations via start_mem aren't * possible anymore */static int mem_init_done = 0;/* set if kernel is in ST-RAM */static int kernel_in_stram;typedef struct stram_block {	struct stram_block *next;	void *start;	unsigned long size;	unsigned flags;	const char *owner;} BLOCK;/* values for flags field */#define BLOCK_FREE		0x01	/* free structure in the BLOCKs pool */#define BLOCK_KMALLOCED	0x02	/* structure allocated by kmalloc() */#define BLOCK_GFP		0x08	/* block allocated with __get_dma_pages() */#define BLOCK_INSWAP	0x10	/* block allocated in swap space *//* list of allocated blocks */static BLOCK *alloc_list = NULL;/* We can't always use kmalloc() to allocate BLOCK structures, since * stram_alloc() can be called rather early. So we need some pool of * statically allocated structures. 20 of them is more than enough, so in most * cases we never should need to call kmalloc(). */#define N_STATIC_BLOCKS	20static BLOCK static_blocks[N_STATIC_BLOCKS];#ifdef CONFIG_STRAM_SWAP/* max. number of bytes to use for swapping *  0 = no ST-RAM swapping * -1 = do swapping (to whole ST-RAM) if it's less than MAX_STRAM_FRACTION of *      total memory */static int max_swap_size = -1;/* start and end of swapping area */static void *swap_start, *swap_end;/* The ST-RAM's swap info structure */static struct swap_info_struct *stram_swap_info;/* The ST-RAM's swap type */static int stram_swap_type;/* Semaphore for get_stram_region.  */static DECLARE_MUTEX(stram_swap_sem);/* major and minor device number of the ST-RAM device; for the major, we use * the same as Amiga z2ram, which is really similar and impossible on Atari, * and for the minor a relatively odd number to avoid the user creating and * using that device. */#define	STRAM_MAJOR		Z2RAM_MAJOR#define	STRAM_MINOR		13/* Some impossible pointer value */#define MAGIC_FILE_P	(struct file *)0xffffdead#ifdef DO_PROCstatic unsigned stat_swap_read = 0;static unsigned stat_swap_write = 0;static unsigned stat_swap_force = 0;#endif /* DO_PROC */#endif /* CONFIG_STRAM_SWAP *//***************************** Prototypes *****************************/#ifdef CONFIG_STRAM_SWAPstatic int swap_init(void *start_mem, void *swap_data);static void *get_stram_region( unsigned long n_pages );static void free_stram_region( unsigned long offset, unsigned long n_pages			       );static int in_some_region(void *addr);static unsigned long find_free_region( unsigned long n_pages, unsigned long				       *total_free, unsigned long				       *region_free );static void do_stram_request(request_queue_t *);static int stram_open( struct inode *inode, struct file *filp );static int stram_release( struct inode *inode, struct file *filp );static void reserve_region(void *start, void *end);#endifstatic BLOCK *add_region( void *addr, unsigned long size );static BLOCK *find_region( void *addr );static int remove_region( BLOCK *block );/************************* End of Prototypes **************************//* ------------------------------------------------------------------------ *//*							   Public Interface								*//* ------------------------------------------------------------------------ *//* * This init function is called very early by atari/config.c * It initializes some internal variables needed for stram_alloc() */void __init atari_stram_init(void){	int i;	/* initialize static blocks */	for( i = 0; i < N_STATIC_BLOCKS; ++i )		static_blocks[i].flags = BLOCK_FREE;	/* determine whether kernel code resides in ST-RAM (then ST-RAM is the	 * first memory block at virtual 0x0) */	stram_start = phys_to_virt(0);	kernel_in_stram = (stram_start == 0);	for( i = 0; i < m68k_num_memory; ++i ) {		if (m68k_memory[i].addr == 0) {			/* skip first 2kB or page (supervisor-only!) */			stram_end = stram_start + m68k_memory[i].size;			return;		}	}	/* Should never come here! (There is always ST-Ram!) */	panic( "atari_stram_init: no ST-RAM found!" );}/* * This function is called from setup_arch() to reserve the pages needed for * ST-RAM management. */void __init atari_stram_reserve_pages(void *start_mem){#ifdef CONFIG_STRAM_SWAP	/* if max_swap_size is negative (i.e. no stram_swap= option given),	 * determine at run time whether to use ST-RAM swapping */	if (max_swap_size < 0)		/* Use swapping if ST-RAM doesn't make up more than MAX_STRAM_FRACTION		 * of total memory. In that case, the max. size is set to 16 MB,		 * because ST-RAM can never be bigger than that.		 * Also, never use swapping on a Hades, there's no separate ST-RAM in		 * that machine. */		max_swap_size =			(!MACH_IS_HADES &&			 (N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <=			  ((unsigned long)high_memory>>PAGE_SHIFT)*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0;	DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size );#endif	/* always reserve first page of ST-RAM, the first 2 kB are	 * supervisor-only! */	if (!kernel_in_stram)		reserve_bootmem (0, PAGE_SIZE);#ifdef CONFIG_STRAM_SWAP	{		void *swap_data;		start_mem = (void *) PAGE_ALIGN ((unsigned long) start_mem);		/* determine first page to use as swap: if the kernel is		   in TT-RAM, this is the first page of (usable) ST-RAM;		   otherwise just use the end of kernel data (= start_mem) */		swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE : start_mem;		/* decrement by one page, rest of kernel assumes that first swap page		 * is always reserved and maybe doesn't handle SWP_ENTRY == 0		 * correctly */		swap_start -= PAGE_SIZE;		swap_end = stram_end;		if (swap_end-swap_start > max_swap_size)			swap_end =  swap_start + max_swap_size;		DPRINTK( "atari_stram_reserve_pages: swapping enabled; "				 "swap=%p-%p\n", swap_start, swap_end);				/* reserve some amount of memory for maintainance of		 * swapping itself: one page for each 2048 (PAGE_SIZE/2)		 * swap pages. (2 bytes for each page) */		swap_data = start_mem;		start_mem += ((SWAP_NR(swap_end) + PAGE_SIZE/2 - 1)			      >> (PAGE_SHIFT-1)) << PAGE_SHIFT;		/* correct swap_start if necessary */		if (swap_start + PAGE_SIZE == swap_data)			swap_start = start_mem - PAGE_SIZE;				if (!swap_init( start_mem, swap_data )) {			printk( KERN_ERR "ST-RAM swap space initialization failed\n" );			max_swap_size = 0;			return;		}		/* reserve region for swapping meta-data */		reserve_region(swap_data, start_mem);		/* reserve swapping area itself */		reserve_region(swap_start + PAGE_SIZE, swap_end);		/*		 * If the whole ST-RAM is used for swapping, there are no allocatable		 * dma pages left. But unfortunately, some shared parts of the kernel		 * (particularily the SCSI mid-level) call __get_dma_pages()		 * unconditionally :-( These calls then fail, and scsi.c even doesn't		 * check for NULL return values and just crashes. The quick fix for		 * this (instead of doing much clean up work in the SCSI code) is to		 * pretend all pages are DMA-able by setting mach_max_dma_address to		 * ULONG_MAX. This doesn't change any functionality so far, since		 * get_dma_pages() shouldn't be used on Atari anyway anymore (better		 * use atari_stram_alloc()), and the Atari SCSI drivers don't need DMA		 * memory. But unfortunately there's now no kind of warning (even not		 * a NULL return value) if you use get_dma_pages() nevertheless :-(		 * You just will get non-DMA-able memory...		 */		mach_max_dma_address = 0xffffffff;	}#endif}void atari_stram_mem_init_hook (void){	mem_init_done = 1;}/* * This is main public interface: somehow allocate a ST-RAM block * There are three strategies: *  *  - If we're before mem_init(), we have to make a static allocation. The *    region is taken in the kernel data area (if the kernel is in ST-RAM) or *    from the start of ST-RAM (if the kernel is in TT-RAM) and added to the *    rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel *    address space in the latter case. *  *  - If mem_init() already has been called and ST-RAM swapping is enabled, *    try to get the memory from the (pseudo) swap-space, either free already *    or by moving some other pages out of the swap. * *  - If mem_init() already has been called, and ST-RAM swapping is not *    enabled, the only possibility is to try with __get_dma_pages(). This has *    the disadvantage that it's very hard to get more than 1 page, and it is *    likely to fail :-( *  */void *atari_stram_alloc(long size, const char *owner){	void *addr = NULL;	BLOCK *block;	int flags;	DPRINTK("atari_stram_alloc(size=%08lx,owner=%s)\n", size, owner);	size = ALIGN_IF_SWAP(size);	DPRINTK( "atari_stram_alloc: rounded size = %08lx\n", size );#ifdef CONFIG_STRAM_SWAP	if (max_swap_size) {		/* If swapping is active: make some free space in the swap		   "device". */		DPRINTK( "atari_stram_alloc: after mem_init, swapping ok, "				 "calling get_region\n" );		addr = get_stram_region( N_PAGES(size) );		flags = BLOCK_INSWAP;	}	else#endif	if (!mem_init_done)		return alloc_bootmem_low(size);	else {		/* After mem_init() and no swapping: can only resort to

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -