📄 stram.c
字号:
/* * 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 );#endifstatic void reserve_region(void *start, void *end);static 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 <= (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 + -