2.5.22: new xpram driver 2nd try.
PATCH 1/1 2.5.22: new xpram driver 2nd try.
Hi Linus,
forget the first try of the xpram driver for 2.5.22. I added some suggestions from Christoph Hellwig. One of them was to remove the xpram_release function since it is not needed. I removed the function but not the reference in the block device operations structure. Oh, well, its late. Here is the working version.
blue skies,
Martin.
drivers/s390/block/xpram.c +384 -935
@@ -1,4 +1,3 @@ -/* * Xpram.c -- the S/390 expanded memory RAM-disk *
@@ -8,137 +7,66 @@* * Author of XPRAM specific coding: Reinhard Buendgen * [email protected] +* Rewrite for 2.5: Martin Schwidefsky <[email protected]> * * External interfaces: * Interfaces to linux kernel -* xpram_setup: read kernel parameters (see init/main.c) -* xpram_init: initialize device driver (see drivers/block/ll_rw_blk.c) -* Module interfaces -* init_module -* cleanup_module +* xpram_setup: read kernel parameters * Device specific file operations * xpram_iotcl * xpram_open -* xpram_release * -* "ad-hoc" partitioning: +* "ad-hoc" partitioning: * the expanded memory can be partitioned among several devices * (with different minors). The partitioning set up can be * set by kernel or module parameters (int devs & int sizes[]) * -* module parameters: devs= and sizes= -* kernel parameters: xpram_parts= -* note: I did not succeed in parsing numbers -* for module parameters of type string "s" ?!? -* -* Other kenel files/modules affected(gerp for "xpram" or "XPRAM": -* drivers/s390/Config.in -* drivers/s390/block/Makefile -* include/linux/blk.h -* include/linux/major.h -* init/main.c -* drivers/block//ll_rw_blk.c -* -* * Potential future improvements: -* request clustering: first coding started not yet tested or integrated -* I doubt that it really pays off * generic hard disk support to replace ad-hoc partitioning -* -* Tested with 2.2.14 (under VM) */ -#ifdef MODULE -# ifndef __KERNEL__ -# define __KERNEL__ -# endif -# define __NO_VERSION__/* don't define kernel_version in module.h */ -#endif /* MODULE */ -#include <linux/module.h> #include <linux/version.h> - -#ifdef MODULE -char kernel_version [] =UTS_RELEASE ; -#endif - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/kernel.h> /* printk() */ -#include <linux/slab.h> /* kmalloc() */ -#include <linux/devfs_fs_kernel.h> -#include <linux/fs.h> /* everything... */ -#include <linux/errno.h> /* error codes */ -#include <linux/timer.h> -#include <linux/types.h> /* size_t */ #include <linux/ctype.h> /* isdigit, isxdigit */ -#include <linux/fcntl.h> /* O_ACCMODE */ -#include <linux/hdreg.h> /* HDIO_GETGEO */ - -#include <asm/system.h> /* cli(), *_flags */ -#include <asm/uaccess.h> /* put_user */ - -#define MAJOR_NR xpram_major/* force definitions on in blk.h */ -int xpram_major;/* must be declared before including blk.h */ -devfs_handle_t xpram_devfs_handle; - -#define DEVICE_NR (device) MINOR(device)/* xpram has no partition bits */ -#define DEVICE_NO_RANDOM /* no entropy to contribute */ -#define DEVICE_OFF (d)/* do-nothing */ - +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> #include <linux/blk.h> +#include <linux/blkpg.h> +#include <linux/hdreg.h> /* HDIO_GETGEO */ +#include <linux/device.h> +#include <asm/uaccess.h> -#include "xpram.h" /* local definitions */ - -__setup ("xpram_parts=" , xpram_setup); - -/* -define the debug levels: -- 0 No debugging output to console or syslog -- 1 Log internal errors to syslog, ignore check conditions -- 2 Log internal errors and check conditions to syslog -- 3 Log internal errors to console, log check conditions to syslog -- 4 Log internal errors and check conditions to console -- 5 panic on internal errors, log check conditions to console -- 6 panic on both, internal errors and check conditions -*/ -#define XPRAM_DEBUG 4 +#define XPRAM_NAME "xpram" +#define XPRAM_DEVS 1/* one partition */ +#define XPRAM_MAX_DEVS 32/* maximal number of devices (partitions) */ + +#define PRINT_DEBUG(x...) printk(KERN_DEBUG XPRAM_NAME " debug:" x) +#define PRINT_INFO(x...) printk(KERN_INFO XPRAM_NAME " info:" x) +#define PRINT_WARN(x...) printk(KERN_WARNING XPRAM_NAME " warning:" x) +#define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) + +static struct device xpram_sys_device = { + name:"S/390 expanded memory RAM disk" , + bus_id:"xpram" , +}; -#define PRINTK_HEADER XPRAM_NAME - -#if XPRAM_DEBUG >0 -#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:" x ) -#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER "info:" x ) -#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER "warning:" x ) -#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER "error:" x ) -#define PRINT_FATAL(x...) panic ( PRINTK_HEADER "panic:"x ) -#else -#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:" x ) -#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER "info:" x ) -#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER "warning:" x ) -#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER "error:" x ) -#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER "panic:" x ) -#endif +typedef struct { +unsigned long size;/* size of xpram segment in pages */ +unsigned long offset;/* start page of xpram segment */ +}xpram_device_t ; + +static xpram_device_t xpram_devices[XPRAM_MAX_DEVS ]; +static int xpram_sizes[XPRAM_MAX_DEVS ]; +static unsigned long xpram_pages; +static int xpram_devs; +static devfs_handle_t xpram_devfs_handle;/* -* Non-prefixed symbols are static. They are meant to be assigned at -* load time. Prefixed symbols are not static, so they can be used in -* debugging. They are hidden anyways by register_symtab() unless -* XPRAM_DEBUG is defined. +* Parameter parsing functions. */ - -static int major =XPRAM_MAJOR ; -static int devs =XPRAM_DEVS ; -static int sizes[XPRAM_MAX_DEVS ] = {0 , }; -static int blksize =XPRAM_BLKSIZE ; -static int hardsect =XPRAM_HARDSECT ; - -int xpram_devs; -int xpram_blksize, xpram_hardsect; -int xpram_mem_avail =0 ; -unsigned long xpram_sizes[XPRAM_MAX_DEVS ]; - +static int devs =XPRAM_DEVS ; +static unsigned long sizes[XPRAM_MAX_DEVS ];MODULE_PARM (devs,"i" ); MODULE_PARM(sizes,"1-" __MODULE_STRING(XPRAM_MAX_DEVS) "i");
@@ -150,930 +78,451 @@"All devices with size 0 equally partition the " "remaining space on the expanded strorage not " "claimed by explicit sizes\n"); +MODULE_LICENSE ("GPL" ); - - -/* The following items are obtained through kmalloc() in init_module() */ - -Xpram_Dev *xpram_devices =NULL ; -int *xpram_offsets =NULL ;/* partition offsets */ - -#define MIN (x,y) ((x) < (y) ? (x) : (y)) -#define MAX (x,y) ((x) > (y) ? (x) : (y)) - -/* -* compute nearest multiple of 4 , argument must be non-negative -* the macros used depends on XPRAM_KB_IN_PG = 4 -*/ - -#define NEXT4 (x) ((x & 0x3) ? (x+4-(x &0x3)) : (x))/* increment if needed */ -#define LAST4 (x) ((x & 0x3) ? (x-4+(x & 0x3)) : (x))/* decrement if needed */ - -#if 0 /* this is probably not faster than the previous code */ -#define NEXT4 (x) ((((x-1)>>2)>>2)+4)/* increment if needed */ -#define LAST4 (x) (((x+3)>>2)<<2)/* decrement if needed */ -#endif - -/* integer formats */ -#define XPRAM_INVALF -1/* invalid */ -#define XPRAM_HEXF 0/* hexadecimal */ -#define XPRAM_DECF 1/* decimal */ - -/* -* parsing operations (needed for kernel parameter parsing) -*/ - -/* ------------------------------------------------------------------------- -* sets the string pointer after the next comma -* -* argument: strptr pointer to string -* side effect: strptr points to endof string or to position of the next -* comma -* ------------------------------------------------------------------------*/ -static void -xpram_scan_to_next_comma (char **strptr) -{ -while ( ((**strptr) !=',' ) && (**strptr) ) - (*strptr)++; -} - -/* ------------------------------------------------------------------------- -* interpret character as hex-digit +#ifndef MODULE +/* +* Parses the kernel parameters given in the kernel parameter line. +* The expected format is +* <number_of_partitions>[","<partition_size>]* +* where +* devices is a positive integer that initializes xpram_devs +* each size is a non-negative integer possibly followed by a +* magnitude (k,K,m,M,g,G), the list of sizes initialises +* xpram_sizes * -* argument: c charcter -* result: c interpreted as hex-digit -* note: can be used to read digits for any base <= 16 -* ------------------------------------------------------------------------*/ -static int -xpram_get_hexdigit (char c) -{ -if ((c >='0' ) && (c <='9' )) -return c -'0' ; -if ((c >='a' ) && (c <='f' )) -return c +10 -'a' ; -if ((c >='A' ) && (c <='F' )) -return c +10 -'A' ; -return -1 ; -} - -/*-------------------------------------------------------------------------- -* Check format of unsigned integer +* Arguments +* str: substring of kernel parameter line that contains xprams +* kernel parameters. * -* Argument: strptr pointer to string -* result: -1 if strptr does not start with a digit -* (does not start an integer) -* 0 if strptr starts a positive hex-integer with "0x" -* 1 if strptr start a positive decimal integer +* Result 0 on success, -EINVAL else -- only for Version > 2.3 * -* side effect: if strptr start a positive hex-integer then strptr is -* set to the character after the "0x" -*-------------------------------------------------------------------------*/ -static int -xpram_int_format (char **strptr) +* Side effects +* the global variabls devs is set to the value of +* <number_of_partitions> and sizes[i] is set to the i-th +* partition size (if provided). A parsing error of a value +* results in this value being set to -EINVAL. +*/ +static int __init xpram_setup (char *str) { -if ( !isdigit (**strptr) ) -return XPRAM_INVALF ; -if ( (**strptr =='0' ) - && ( (*((*strptr)+1 ) =='x' ) || (*((*strptr) +1 ) =='X' ) ) - &&isdigit (*((*strptr)+3 )) ) { - *strptr=(*strptr)+2 ; -return XPRAM_HEXF ; - }else return XPRAM_DECF ; -} - -/*-------------------------------------------------------------------------- -* Read non-negative decimal integer -* -* Argument: strptr pointer to string starting with a non-negative integer -* in decimal format -* result: the value of theinitial integer pointed to by strptr -* -* side effect: strptr is set to the first character following the integer -*-------------------------------------------------------------------------*/ +char *cp; +int i; -static int -xpram_read_decint (char ** strptr) -{ -int res=0 ; -while (isdigit (**strptr) ) { - res = (res*10 ) +xpram_get_hexdigit (**strptr); - (*strptr)++; - } -return res; + devs =simple_strtoul (str, &cp,10 ); +if (cp <= str || devs >XPRAM_MAX_DEVS ) +return 0 ; +for (i =0 ; (i < devs) && (*cp++ ==',' ); i++) { + sizes[i] =simple_strtoul (cp, &cp,10 ); +if (*cp =='g' || *cp =='G' ) { + sizes[i] <<=20 ; + cp++; + }else if (*cp =='m' || *cp =='M' ) { + sizes[i] <<=10 ; + cp++; + }else if (*cp =='k' || *cp =='K' ) + cp++; +while (isspace (*cp)) cp++; + } +if (*cp ==',' && i >= devs) +PRINT_WARN ("partition sizes list has too many entries.\n" ); +else if (*cp !=0 ) +PRINT_WARN ("ignored '%s' at end of parameter string.\n" , cp); +return 1 ; } -/*-------------------------------------------------------------------------- -* Read non-negative hex-integer -* -* Argument: strptr pointer to string starting with a non-negative integer -* in hexformat (without "0x" prefix) -* result: the value of the initial integer pointed to by strptr -* -* side effect: strptr is set to the first character following the integer -*-------------------------------------------------------------------------*/ +__setup ("xpram_parts=" , xpram_setup); +#endif -static int -xpram_read_hexint (char ** strptr) -{ -int res=0 ; -while (isxdigit (**strptr) ) { - res = (res<<4 ) +xpram_get_hexdigit (**strptr); - (*strptr)++; - } -return res; +/* +* Copy expanded memory page (4kB) into main memory +* Arguments +* page_addr: address of target page +* xpage_index: index of expandeded memory page +* Return value +* 0: if operation succeeds +* -EIO: if pgin failed +* -ENXIO: if xpram has vanished +*/ +static int xpram_page_in (unsigned long page_addr,unsigned long xpage_index) +{ +int cc; + + __asm__ __volatile( + " lhi %0,2\n" /* return unused cc 2 if pgin traps */ + " .insn rre,0xb22e0000,%1,%2\n" /* pgin %1,%2 */ + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" +#ifndef CONFIG_ARCH_S390X + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,1b\n" + ".previous" +#else + ".section __ex_table,\"a\"\n" + " .align 8\n" + " .quad 0b,1b\n" + ".previous" +#endif + : "=&d" (cc) + : "a" (__pa(page_addr)), "a" (xpage_index) + : "cc" ); +if (cc ==3 ) +return -ENXIO ; +if (cc ==2 ) { +PRINT_ERR ("expanded storage lost!\n" ); +return -ENXIO ; + } +if (cc ==1 ) { +PRINT_ERR ("page in failed for page index %ld.\n" , + xpage_index); +return -EIO ; + } +return 0 ; } -/*-------------------------------------------------------------------------- -* Read non-negative integer -* -* Argument: strptr pointer to string starting with a non-negative integer -(either in decimal- or in hex-format -* result: the value of the initial integer pointed to by strptr -* in case of a parsing error the result is -EINVAL -* -* side effect: strptr is set to the first character following the integer -*-------------------------------------------------------------------------*/ -static int -xpram_read_int (char ** strptr) -{ -switch (xpram_int_format (strptr) ) { -case XPRAM_INVALF :return -EINVAL ; -case XPRAM_HEXF :return xpram_read_hexint (strptr); -case XPRAM_DECF :return xpram_read_decint (strptr); -default :return -EINVAL ; +/* +* Copy a 4kB page of main memory to an expanded memory page +* Arguments +* page_addr: address of source page +* xpage_index: index of expandeded memory page +* Return value +* 0: if operation succeeds +* -EIO: if pgout failed +* -ENXIO: if xpram has vanished +*/ +static long xpram_page_out (unsigned long page_addr,unsigned long xpage_index) +{ +int cc; + + __asm__ __volatile( + " lhi %0,2\n" /* return unused cc 2 if pgout traps */ + " .insn rre,0xb22f0000,%1,%2\n" /* pgout %1,%2 */ + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" +#ifndef CONFIG_ARCH_S390X + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,1b\n" + ".previous" +#else + ".section __ex_table,\"a\"\n" + " .align 8\n" + " .quad 0b,1b\n" + ".previous" +#endif + : "=&d" (cc) + : "a" (__pa(page_addr)), "a" (xpage_index) + : "cc" ); +if (cc ==3 ) +return -ENXIO ; +if (cc ==2 ) { +PRINT_ERR ("expanded storage lost!\n" ); +return -ENXIO ; } -} - -/*-------------------------------------------------------------------------- -* Read size -* -* Argument: strptr pointer to string starting with a non-negative integer -* followed optionally by a size modifier: -* k or K for kilo (default), -* m or M for mega -* g or G for giga -* result: the value of the initial integer pointed to by strptr -* multiplied by the modifier value devided by 1024 -* in case of a parsing error the result is -EINVAL -* -* side effect: strptr is set to the first character following the size -*-------------------------------------------------------------------------*/ - -static int -xpram_read_size (char ** strptr) -{ -int res; - - res=xpram_read_int (strptr); -if ( res <0 )return res; -switch ( **strptr ) { -case 'g' : -case 'G' : res=res*1024 ; -case 'm' : -case 'M' : res=res*1024 ; -case 'k' : -case 'K' : (* strptr)++; +if (cc ==1 ) { +PRINT_ERR ("page out failed for page index %ld.\n" , + xpage_index); +return -EIO ; } - -return res; +return 0 ; } +/* +* Check if xpram is available. +*/ +static int __init xpram_present (void ) +{ +unsigned long mem_page; +int rc; -/*-------------------------------------------------------------------------- -* Read tail of comma separated size list ",i1,i2,...,in" -* -* Arguments:strptr pointer to string. It is assumed that the string has -* the format (","<size>)* -* maxl integer describing the maximal number of elements in the -list pointed to by strptr, max must be > 0. -* ilist array of dimension >= maxl of integers to be modified -* -* result: -EINVAL if the list is longer than maxl -* 0 otherwise -* -* side effects: for j=1,...,n ilist[ij] is set to the value of ij if it is -* a valid non-negative integer and to -EINVAL otherwise -* if no comma is found where it is expected an entry in -* ilist is set to -EINVAL -*-------------------------------------------------------------------------*/ -static int -xpram_read_size_list_tail (char ** strptr,int maxl,int * ilist) -{ -int i=0 ; -char *str = *strptr; -int res=0 ; - -while ( (*str ==',' ) && (i < maxl) ) { - str++; - ilist[i] =xpram_read_size (&str); -if ( ilist[i] == -EINVAL ) { -xpram_scan_to_next_comma (&str); - res = -EINVAL ; - } - i++; - } -return res; -#if 0 /* be lenient about trailing stuff */ -if ( *str !=0 && *str !=' ' ) { - ilist[MAX (i-1 ,0 )] = -EINVAL ; -return -EINVAL ; - }else return 0 ; -#endif + mem_page = (unsigned long )__get_free_page (GFP_KERNEL ); + rc =xpram_page_in (mem_page,0 ); +free_page (mem_page); +return rc ? -ENXIO :0 ; } -/* -* expanded memory operations +* Return index of the last available xpram page. */ - - -/*--------------------------------------------------------------------*/ -/* Copy expanded memory page (4kB) into main memory */ -/* Arguments */ -/* page_addr: address of target page */ -/* xpage_index: index of expandeded memory page */ -/* Return value */ -/* 0: if operation succeeds */ -/* non-0: otherwise */ -/*--------------------------------------------------------------------*/ -long xpram_page_in (unsigned long page_addr,unsigned long xpage_index) +static unsigned long __init xpram_highest_page_index (void ) { -int cc=0 ; -unsigned long real_page_addr =__pa (page_addr); -#ifndef CONFIG_ARCH_S390X - __asm__ __volatile__ ( -" lr 1,%1 \n" /* r1 = real_page_addr */ -" lr 2,%2 \n" /* r2 = xpage_index */ -" .long 0xb22e0012 \n" /* pgin r1,r2 */ -/* copy page from expanded memory */ -"0: ipm %0 \n" /* save status (cc & program mask */ -" srl %0,28 \n" /* cc into least significant bits */ -"1: \n" /* we are done */ -".section .fixup,\"ax\"\n" /* start of fix up section */ -"2: lhi %0,2 \n" /* return unused condition code 2 */ -" bras 1,3f \n" /* safe label 1: in r1 and goto 3 */ -" .long 1b \n" /* literal containing label 1 */ -"3: l 1,0(1) \n" /* load label 1 address into r1 */ -" br 1 \n" /* goto label 1 (across sections) */ -".previous \n" /* back in text section */ -".section __ex_table,\"a\"\n" /* start __extable */ -" .align 4 \n" -" .long 0b,2b \n" /* failure point 0, fixup code 2 */ -".previous \n" - :"=d" (cc) :"d" (real_page_addr),"d" (xpage_index) :"cc" ,"1" ,"2" - ); -#else /* CONFIG_ARCH_S390X */ - __asm__ __volatile__ ( -" lgr 1,%1 \n" /* r1 = real_page_addr */ -" lgr 2,%2 \n" /* r2 = xpage_index */ -" .long 0xb22e0012 \n" /* pgin r1,r2 */ -/* copy page from expanded memory */ -"0: ipm %0 \n" /* save status (cc & program mask */ -" srl %0,28 \n" /* cc into least significant bits */ -"1: \n" /* we are done */ -".section .fixup,\"ax\"\n" /* start of fix up section */ -"2: lghi %0,2 \n" /* return unused condition code 2 */ -" jg 1b \n" /* goto label 1 above */ -".previous \n" /* back in text section */ -".section __ex_table,\"a\"\n" /* start __extable */ -" .align 8 \n" -" .quad 0b,2b \n" /* failure point 0, fixup code 2 */ -".previous \n" - :"=d" (cc) :"d" (real_page_addr),"d" (xpage_index) :"cc" ,"1" ,"2" - ); -#endif /* CONFIG_ARCH_S390X */ -switch (cc) { -case 0 :return 0 ; -case 1 :return -EIO ; -case 2 :return -ENXIO ; -case 3 :return -ENXIO ; -default :return -EIO ;/* should not happen */ - }; -} +unsigned long page_index, add_bit; +unsigned long mem_page; -/*--------------------------------------------------------------------*/ -/* Copy a 4kB page of main memory to an expanded memory page */ -/* Arguments */ -/* page_addr: address of source page */ -/* xpage_index: index of expandeded memory page */ -/* Return value */ -/* 0: if operation succeeds */ -/* non-0: otherwise */ -/*--------------------------------------------------------------------*/ -long xpram_page_out (unsigned long page_addr,unsigned long xpage_index) -{ -int cc=0 ; -unsigned long real_page_addr =__pa (page_addr); -#ifndef CONFIG_ARCH_S390X - __asm__ __volatile__ ( -" lr 1,%1 \n" /* r1 = mem_page */ -" lr 2,%2 \n" /* r2 = rpi */ -" .long 0xb22f0012 \n" /* pgout r1,r2 */ -/* copy page from expanded memory */ -"0: ipm %0 \n" /* save status (cc & program mask */ -" srl %0,28 \n" /* cc into least significant bits */ -"1: \n" /* we are done */ -".section .fixup,\"ax\"\n" /* start of fix up section */ -"2: lhi %0,2 \n" /* return unused condition code 2 */ -" bras 1,3f \n" /* safe label 1: in r1 and goto 3 */ -" .long 1b \n" /* literal containing label 1 */ -"3: l 1,0(1) \n" /* load label 1 address into r1 */ -" br 1 \n" /* goto label 1 (across sections) */ -".previous \n" /* back in text section */ -".section __ex_table,\"a\"\n" /* start __extable */ -" .align 4 \n" -" .long 0b,2b \n" /* failure point 0, fixup code 2 */ -".previous \n" - :"=d" (cc) :"d" (real_page_addr),"d" (xpage_index) :"cc" ,"1" ,"2" - ); -#else /* CONFIG_ARCH_S390X */ - __asm__ __volatile__ ( -" lgr 1,%1 \n" /* r1 = mem_page */ -" lgr 2,%2 \n" /* r2 = rpi */ -" .long 0xb22f0012 \n" /* pgout r1,r2 */ -/* copy page from expanded memory */ -"0: ipm %0 \n" /* save status (cc & program mask */ -" srl %0,28 \n" /* cc into least significant bits */ -"1: \n" /* we are done */ -".section .fixup,\"ax\"\n" /* start of fix up section */ -"2: lghi %0,2 \n" /* return unused condition code 2 */ -" jg 1b \n" /* goto label 1 above */ -".previous \n" /* back in text section */ -".section __ex_table,\"a\"\n" /* start __extable */ -" .align 8 \n" -" .quad 0b,2b \n" /* failure point 0, fixup code 2 */ -".previous \n" - :"=d" (cc) :"d" (real_page_addr),"d" (xpage_index) :"cc" ,"1" ,"2" - ); -#endif /* CONFIG_ARCH_S390X */ -switch (cc) { -case 0 :return 0 ; -case 1 :return -EIO ; -case 2 : {PRINT_ERR ("expanded storage lost!\n" );return -ENXIO ; } -case 3 :return -ENXIO ; -default :return -EIO ;/* should not happen */ - } -} + mem_page = (unsigned long )__get_free_page (GFP_KERNEL ); -/*--------------------------------------------------------------------*/ -/* Measure expanded memory */ -/* Return value */ -/* size of expanded memory in kB (must be a multipe of 4) */ -/*--------------------------------------------------------------------*/ -int xpram_size (void ) -{ -int cc=0 ; -unsigned long base=0 ; -unsigned long po, pi, rpi;/* page index order, page index */ - -unsigned long mem_page =__get_free_page (GFP_KERNEL ); - -/* for po=0,1,2,... try to move in page number base+(2^po)-1 */ - pi=1 ; -for (po=0 ; po <=32 ; po++) {/* pi = 2^po */ - cc=xpram_page_in (mem_page,base+pi-1 ); -if ( cc )break ; - pi <<=1 ; - } -if ( cc && (po <31 ) ) { - pi >>=1 ; - base += pi; - pi >>=1 ; -for ( ; pi >0 ; pi >>=1 ) { - rpi = pi -1 ; - cc=xpram_page_in (mem_page,base+rpi); -if ( !cc ) base += pi; - } + page_index =0 ; + add_bit =1ULL << (sizeof (unsigned long )*8 -1 ); +while (add_bit >0 ) { +if (xpram_page_in (mem_page, page_index | add_bit) ==0 ) + page_index |= add_bit; + add_bit >>=1 ; } - +free_page (mem_page); -if ( cc && (po <31 ) ) -return (XPRAM_KB_IN_PG * base); -else /* return maximal value possible */ -return INT_MAX ; +return page_index; }/* -* Open and close +* Block device make request function. */ - -int xpram_open (struct inode *inode,struct file *filp) +static int xpram_make_request (request_queue_t *q,struct bio *bio) { -Xpram_Dev *dev;/* device information */ -int num =MINOR (inode->i_rdev); - - -if (num >= xpram_devs)return -ENODEV ; - dev = xpram_devices + num; - -PRINT_DEBUG ("calling xpram_open for device %d\n" ,num); -PRINT_DEBUG (" size %dkB, name %s, usage: %d\n" , - dev->size,dev->device_name,atomic_read (&(dev->usage))); +xpram_device_t *xdev; +struct bio_vec *bvec; +unsigned long index; +unsigned long page_addr; +unsigned long bytes; +int i; -atomic_inc (&(dev->usage)); -return 0 ;/* success */ +if (MINOR (bio->bi_bdev->bd_dev) > xpram_devs) +/* No such device. */ + goto fail; + xdev = xpram_devices +MINOR (bio->bi_bdev->bd_dev); +if ((bio->bi_sector &3 ) !=0 || (bio->bi_size &4095 ) !=0 ) +/* Request is not page-aligned. */ + goto fail; +if ((bio->bi_size >>12 ) > xdev->size) +/* Request size is no page-aligned. */ + goto fail; + index = (bio->bi_sector >>3 ) + xdev->offset; +bio_for_each_segment (bvec, bio, i) { + page_addr = (unsigned long ) +kmap (bvec->bv_page) + bvec->bv_offset; + bytes = bvec->bv_len; +if ((page_addr &4095 ) !=0 || (bytes &4095 ) !=0 ) +/* More paranoia. */ + goto fail; +while (bytes >0 ) { +if (bio_data_dir (bio) ==READ ) { +if (xpram_page_in (page_addr, index) !=0 ) + goto fail; + }else { +if (xpram_page_out (page_addr, index) !=0 ) + goto fail; + } + page_addr +=4096 ; + bytes -=4096 ; + index++; + } + } +set_bit (BIO_UPTODATE , &bio->bi_flags); + bio->bi_end_io (bio); +return 0 ; +fail: +bio_io_error (bio); +return 0 ; } -int xpram_release (struct inode *inode,struct file *filp) +/* +* The file operations +*/ +static int xpram_open (struct inode *inode,struct file *filp) { -Xpram_Dev *dev = xpram_devices +MINOR (inode->i_rdev); - -PRINT_DEBUG ("calling xpram_release for device %d (size %dkB, usage: %d)\n" ,MINOR (inode->i_rdev) ,dev->size,atomic_read (&(dev->usage))); - -/* -* If the device is closed for the last time, start a timer -* to release RAM in half a minute. The function and argument -* for the timer have been setup in init_module() -*/ -if (!atomic_dec_return (&(dev->usage))) { -/* but flush it right now */ -/* Everything is already flushed by caller -- AV */ - } -return (0 ); +if (minor (inode->i_rdev) >= xpram_devs) +return -ENODEV ; +return 0 ; } -/* -* The ioctl() implementation -*/ - -int xpram_ioctl (struct inode *inode,struct file *filp, +static int xpram_ioctl (struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg) { -int err, size; -struct hd_geometry *geo = (struct hd_geometry *)arg; +struct hd_geometry *geo; +unsigned long size; +int idx; -PRINT_DEBUG ("ioctl 0x%x 0x%lx\n" , cmd, arg); -switch (cmd) { - -case BLKGETSIZE :/* 0x1260 */ +if ((!inode) ||kdev_none (inode->i_rdev)) +return -EINVAL ; + idx =minor (inode->i_rdev); +if (idx >= xpram_devs) +return -ENODEV ; +switch (cmd) { +case BLKGETSIZE :/* Return the device size, expressed in sectors */ -return put_user (1024 * xpram_sizes[MINOR (inode->i_rdev)] - /XPRAM_SOFTSECT , - (unsigned long *) arg); - +return put_user (xpram_sizes[idx] <<1 , (unsigned long *) arg);case BLKGETSIZE64 : -return put_user ( (u64)(1024 * xpram_sizes[MINOR (inode->i_rdev)] - /XPRAM_SOFTSECT ) <<9 , - (u64 *) arg); - -case BLKFLSBUF :/* flush, 0x1261 */ -fsync_bdev (inode->i_bdev); -if (capable (CAP_SYS_ADMIN ) )invalidate_bdev (inode->i_bdev,0 ); -return 0 ; - -case BLKRRPART :/* re-read partition table: can't do it, 0x1259 */ +/* Return the device size, expressed in bytes */ +return put_user ((u64 ) xpram_sizes[idx] <<10 , (u64 *) arg); +case BLKFLSBUF : +return blk_ioctl (((struct inode *) inode)->i_bdev, cmd, arg); +case BLKRRPART : +/* re-read partition table: can't do it */ return -EINVAL ; -case HDIO_GETGEO :/* * get geometry: we have to fake one... trim the size to a * multiple of 64 (32k): tell we have 16 sectors, 4 heads, * whatever cylinders. Tell also that data starts at sector. 4. */ - size = xpram_mem_avail *1024 /XPRAM_SOFTSECT ; -/* size = xpram_mem_avail * 1024 / xpram_hardsect; */ - size &= ~0x3f ;/* multiple of 64 */ -if (geo==NULL )return -EINVAL ; -/* -* err=verify_area_20(VERIFY_WRITE, geo, sizeof(*geo)); -* if (err) return err; -*/ - + geo = (struct hd_geometry *) arg; +if (geo ==NULL ) +return -EINVAL ; + size = (xpram_pages *8 ) & ~0x3f ;put_user (size >>6 , &geo->cylinders); -put_user (4 , &geo->heads); -put_user (16 , &geo->sectors); -put_user (4 , &geo->start); - +put_user (4 , &geo->heads); +put_user (16 , &geo->sectors); +put_user (4 , &geo->start);return 0 ; +default : +return -EINVAL ; } - -return -EINVAL ;/* unknown command */ } -/* -* The file operations -*/ -struct block_device_operations xpram_devops = +static struct block_device_operations xpram_devops = { owner:THIS_MODULE , ioctl: xpram_ioctl, open: xpram_open, - release: xpram_release, };/* -* Block-driver specific functions -*/ - -void xpram_request (request_queue_t * queue) -{ -Xpram_Dev *device; -/* u8 *ptr; */ -/* int size; */ - -unsigned long page_no;/* expanded memory page number */ -unsigned long sects_to_copy;/* number of sectors to be copied */ -char * buffer;/* local pointer into buffer cache */ -int dev_no;/* device number of request */ -int fault;/* faulty access to expanded memory */ -struct request * current_req;/* working request */ - -while (1 ) { -if (blk_queue_empty (QUEUE )) -return ; - - fault=0 ; - current_req =CURRENT ; - dev_no =DEVICE_NR (current_req->rq_dev); -/* Check if the minor number is in range */ -if ( dev_no > xpram_devs ) { -static int count =0 ; -if (count++ <5 )/* print the message at most five times */ -PRINT_WARN (" request for unknown device\n" ); -end_request (CURRENT ,0 ); -continue ; - } - -/* pointer to device structure, from the global array */ - device = xpram_devices + dev_no; - sects_to_copy = current_req->current_nr_sectors; -/* does request exceed size of device ? */ -if (XPRAM_SEC2KB (sects_to_copy) > xpram_sizes[dev_no] ) { -PRINT_WARN (" request past end of device\n" ); -end_request (CURRENT ,0 ); -continue ; - } - -/* Does request start at page boundery? -- paranoia */ -#if 0 -PRINT_DEBUG (" req %lx, sect %lx, to copy %lx, buf addr %lx\n" , (unsigned long ) current_req, current_req->sector, sects_to_copy, (unsigned long ) current_req->buffer); -#endif - buffer = current_req->buffer; -#if XPRAM_SEC_IN_PG !=1 -/* Does request start at an expanded storage page boundery? */ -if ( current_req->sector & (XPRAM_SEC_IN_PG -1 ) ) { -PRINT_WARN (" request does not start at an expanded storage page boundery\n" ); -PRINT_WARN (" referenced sector: %ld\n" ,current_req->sector); -end_request (CURRENT ,0 ); -continue ; - } -/* Does request refere to partial expanded storage pages? */ -if ( sects_to_copy & (XPRAM_SEC_IN_PG -1 ) ) { -PRINT_WARN (" request referes to a partial expanded storage page\n" ); -end_request (CURRENT ,0 ); -continue ; - } -#endif /* XPRAM_SEC_IN_PG != 1 */ -/* Is request buffer aligned with kernel pages? */ -if ( ((unsigned long )buffer) & (XPRAM_PGSIZE -1 ) ) { -PRINT_WARN (" request buffer is not aligned with kernel pages\n" ); -end_request (CURRENT ,0 ); -continue ; - } - -/* which page of expanded storage is affected first? */ - page_no = (xpram_offsets[dev_no] >>XPRAM_KB_IN_PG_ORDER ) - + (current_req->sector >>XPRAM_SEC_IN_PG_ORDER ); - -#if 0 -PRINT_DEBUG ("request: %d ( dev %d, copy %d sectors, at page %d ) \n" , current_req->cmd,dev_no,sects_to_copy,page_no); -#endif - -switch (current_req->cmd) { -case READ : -do { -if ( (fault=xpram_page_in ((unsigned long )buffer,page_no)) ) { -PRINT_WARN ("xpram(dev %d): page in failed for page %ld.\n" ,dev_no,page_no); -break ; - } - sects_to_copy -=XPRAM_SEC_IN_PG ; - buffer +=XPRAM_PGSIZE ; - page_no++; - }while ( sects_to_copy >0 ); -break ; -case WRITE : -do { -if ( (fault=xpram_page_out ((unsigned long )buffer,page_no)) - ) { -PRINT_WARN ("xpram(dev %d): page out failed for page %ld.\n" ,dev_no,page_no); -break ; - } - sects_to_copy -=XPRAM_SEC_IN_PG ; - buffer +=XPRAM_PGSIZE ; - page_no++; - }while ( sects_to_copy >0 ); -break ; -default : -/* can't happen */ -end_request (CURRENT ,0 ); -continue ; - } -if ( fault )end_request (CURRENT ,0 ); -else end_request (CURRENT ,1 );/* success */ - } -} - -/* -* Kernel interfaces +* Setup xpram_sizes array. */ - -/* -* Parses the kernel parameters given in the kernel parameter line. -* The expected format is -* <number_of_partitions>[","<partition_size>]* -* where -* devices is a positive integer that initializes xpram_devs -* each size is a non-negative integer possibly followed by a -* magnitude (k,K,m,M,g,G), the list of sizes initialises -* xpram_sizes -* -* Arguments -* str: substring of kernel parameter line that contains xprams -* kernel parameters. -* ints: not used -- not in Version > 2.3 any more -* -* Result 0 on success, -EINVAl else -- only for Version > 2.3 -* -* Side effects -* the global variabls devs is set to the value of -* <number_of_partitions> and sizes[i] is set to the i-th -* partition size (if provided). A parsing error of a value -* results in this value being set to -EINVAL. -*/ -int xpram_setup (char *str) +static int __init xpram_setup_sizes (unsigned long pages) { - devs =xpram_read_int (&str); -if ( devs != -EINVAL ) -if (xpram_read_size_list_tail (&str,devs,sizes) <0 ) { -PRINT_ERR ("error while reading xpram parameters.\n" ); -return -EINVAL ; - } -else -return 0 ; -else -return -EINVAL ; -} - -/* -* initialize xpram device driver -* -* Result: 0 ok -* negative number: negative error code -*/ +unsigned long mem_needed; +unsigned long mem_auto; +int mem_auto_no; +int i; -int xpram_init (void ) -{ -int result, i; -int mem_usable;/* net size of expanded memory */ -int mem_needed=0 ;/* size of expanded memory needed to fullfill -* requirements of non-zero parameters in sizes -*/ - -int mem_auto_no=0 ;/* number of (implicit) zero parameters in sizes */ -int mem_auto;/* automatically determined device size */ -int minor_length;/* store the length of a minor (w/o '\0') */ -int minor_thresh;/* threshhold for minor lenght */ - -request_queue_t *q;/* request queue */ - -/* -* Copy the (static) cfg variables to public prefixed ones to allow -* snoozing with a debugger. -*/ - - xpram_blksize = blksize; - xpram_hardsect = hardsect; - -PRINT_INFO ("initializing: %s\n" ,"" ); -/* check arguments */ - xpram_major = major; -if ( (devs <=0 ) || (devs >XPRAM_MAX_DEVS ) ) { +/* Check number of devices. */ +if (devs <=0 || devs >XPRAM_MAX_DEVS ) {PRINT_ERR ("invalid number %d of devices\n" ,devs); -PRINT_ERR ("Giving up xpram\n" );return -EINVAL ; } - xpram_devs = devs; -for (i=0 ; i < xpram_devs; i++) { -if ( sizes[i] <0 ) { -PRINT_ERR ("Invalid partition size %d kB\n" ,xpram_sizes[i]); -PRINT_ERR ("Giving up xpram\n" ); -return -EINVAL ; - }else { - xpram_sizes[i] =NEXT4 (sizes[i]);/* page align */ -if ( sizes[i] ) mem_needed += xpram_sizes[i]; -else mem_auto_no++; - } - } - -PRINT_DEBUG (" major %d \n" , xpram_major); -PRINT_INFO (" number of devices (partitions): %d \n" , xpram_devs); -for (i=0 ; i < xpram_devs; i++) { -if ( sizes[i] ) -PRINT_INFO (" size of partition %d: %d kB\n" , i, xpram_sizes[i]); -else -PRINT_INFO (" size of partition %d to be set automatically\n" ,i); - } -PRINT_DEBUG (" memory needed (for sized partitions): %d kB\n" , mem_needed); -PRINT_DEBUG (" partitions to be sized automatically: %d\n" , mem_auto_no); - -#if 0 -/* Hardsect can't be changed :( */ -/* I try it any way. Yet I must distinguish -* between hardsects (to be changed to 4096) -* and soft sectors, hard-coded for buffer -* sizes within the requests -*/ -if (hardsect !=512 ) { -PRINT_ERR ("Can't change hardsect size\n" ); - hardsect = xpram_hardsect =512 ; - } -#endif -PRINT_INFO (" hardsector size: %dB \n" ,xpram_hardsect); + xpram_devs = devs;/* -* Register your major, and accept a dynamic number +* Copy sizes array to xpram_sizes and align partition +* sizes to page boundary. */ - result =devfs_register_blkdev (xpram_major,"xpram" , &xpram_devops); -if (result <0 ) { -PRINT_ERR ("Can't get major %d\n" ,xpram_major); -PRINT_ERR ("Giving up xpram\n" ); -return result; + mem_needed =0 ; + mem_auto_no =0 ; +for (i =0 ; i < xpram_devs; i++) { + xpram_sizes[i] = (sizes[i] +3 ) &-4UL ; +if (xpram_sizes[i]) + mem_needed += xpram_sizes[i]; +else + mem_auto_no++; } - xpram_devfs_handle =devfs_mk_dir (NULL ,"slram" ,NULL ); -devfs_register_series (xpram_devfs_handle,"%u" ,XPRAM_MAX_DEVS , -DEVFS_FL_DEFAULT ,XPRAM_MAJOR ,0 , -S_IFBLK |S_IRUSR |S_IWUSR , - &xpram_devops,NULL ); -if (xpram_major ==0 ) xpram_major = result;/* dynamic */ - major = xpram_major;/* Use `major' later on to save typing */ - - result = -ENOMEM ;/* for the possible errors */ - -/* -* measure expanded memory -*/ - - xpram_mem_avail =xpram_size (); -if (!xpram_mem_avail) { -PRINT_ERR ("No or not enough expanded memory available\n" ); -PRINT_ERR ("Giving up xpram\n" ); - result = -ENODEV ; - goto fail_malloc; + +PRINT_INFO (" number of devices (partitions): %d \n" , xpram_devs); +for (i =0 ; i < xpram_devs; i++) { +if (xpram_sizes[i]) +PRINT_INFO (" size of partition %d: %d kB\n" , + i, xpram_sizes[i]); +else +PRINT_INFO (" size of partition %d to be set " +"automatically\n" ,i); } -PRINT_INFO (" %d kB expanded memory found.\n" ,xpram_mem_avail ); +PRINT_DEBUG (" memory needed (for sized partitions): %ld kB\n" , + mem_needed); +PRINT_DEBUG (" partitions to be sized automatically: %d\n" , + mem_auto_no); -/* -* Assign the other needed values: request, size, blksize, -* hardsect. All the minor devices feature the same value. -* Note that `xpram' defines all of them to allow testing non-default -* values. A real device could well avoid setting values in global -* arrays if it uses the default values. -*/ - - q =BLK_DEFAULT_QUEUE (major); -blk_init_queue (q, xpram_request); -blk_queue_hardsect_size (q, xpram_hardsect); - -/* we want to have XPRAM_UNUSED blocks security buffer between devices */ - mem_usable=xpram_mem_avail-(XPRAM_UNUSED *(xpram_devs-1 )); -if ( mem_needed > mem_usable ) { +if (mem_needed > pages *4 ) {PRINT_ERR ("Not enough expanded memory available\n" ); -PRINT_ERR ("Giving up xpram\n" ); - goto fail_malloc; +return -EINVAL ; }/* * partitioning: * xpram_sizes[i] != 0; partition i has size xpram_sizes[i] kB -* else: ; all partitions i with xpram_sizesxpram_size[i] +* else: ; all partitions with zero xpram_sizes[i] * partition equally the remaining space */ +if (mem_auto_no) { + mem_auto = ((pages - mem_needed /4 ) / mem_auto_no) *4 ; +PRINT_INFO (" automatically determined " +"partition size: %ld kB\n" , mem_auto); +for (i =0 ; i < xpram_devs; i++) +if (xpram_sizes[i] ==0 ) + xpram_sizes[i] = mem_auto; + } +return 0 ; +} + +static int __init xpram_setup_blkdev (void ) +{ +request_queue_t *q; +unsigned long offset; +int i, rc; -if ( mem_auto_no ) { - mem_auto=LAST4 ((mem_usable-mem_needed)/mem_auto_no); -PRINT_INFO (" automatically determined partition size: %d kB\n" , mem_auto); -for (i=0 ; i < xpram_devs; i++) -if (xpram_sizes[i] ==0 ) xpram_sizes[i] = mem_auto; +/* +* Register xpram major. +*/ + rc =devfs_register_blkdev (XPRAM_MAJOR ,XPRAM_NAME , &xpram_devops); +if (rc <0 ) { +PRINT_ERR ("Can't get xpram major %d\n" ,XPRAM_MAJOR ); +return rc; } - blk_size[major] = xpram_sizes; - xpram_offsets =kmalloc (xpram_devs *sizeof (int ),GFP_KERNEL ); -if (!xpram_offsets) { -PRINT_ERR ("Not enough memory for xpram_offsets\n" ); -PRINT_ERR ("Giving up xpram\n" ); - goto fail_malloc; - } - xpram_offsets[0 ] =0 ; -for (i=1 ; i < xpram_devs; i++) - xpram_offsets[i] = xpram_offsets[i-1 ] + xpram_sizes[i-1 ] +XPRAM_UNUSED ; - -#if 0 -for (i=0 ; i < xpram_devs; i++) -PRINT_DEBUG (" device(%d) offset = %d kB, size = %d kB\n" ,i, xpram_offsets[i], xpram_sizes[i]); -#endif + xpram_devfs_handle =devfs_mk_dir (NULL ,"slram" ,NULL ); +devfs_register_series (xpram_devfs_handle,"%u" , xpram_devs, +DEVFS_FL_DEFAULT ,XPRAM_MAJOR ,0 , +S_IFBLK |S_IRUSR |S_IWUSR , + &xpram_devops,NULL ); -/* -* allocate the devices -- we can't have them static, as the number -* can be specified at load time +/* +* Assign the other needed values: make request function, sizes and +* hardsect size. All the minor devices feature the same value. */ + q =BLK_DEFAULT_QUEUE (XPRAM_MAJOR ); +blk_queue_make_request (q,xpram_make_request); +blk_queue_hardsect_size (q,4096 ); + blk_size[XPRAM_MAJOR ] = xpram_sizes; - xpram_devices =kmalloc (xpram_devs *sizeof (Xpram_Dev),GFP_KERNEL ); -if (!xpram_devices) { -PRINT_ERR ("Not enough memory for xpram_devices\n" ); -PRINT_ERR ("Giving up xpram\n" ); - goto fail_malloc_devices; - } -memset (xpram_devices,0 , xpram_devs *sizeof (Xpram_Dev)); - minor_length =1 ; - minor_thresh =10 ; -for (i=0 ; i < xpram_devs; i++) { -/* data and usage remain zeroed */ - xpram_devices[i].size = xpram_sizes[i];/* size in kB not in bytes */ -atomic_set (&(xpram_devices[i].usage),0 ); -if (i == minor_thresh) { - minor_length++; - minor_thresh *=10 ; - } - xpram_devices[i].device_name = -kmalloc (1 +strlen (XPRAM_DEVICE_NAME_PREFIX ) + minor_length,GFP_KERNEL ); -if ( xpram_devices[i].device_name ==NULL ) { -PRINT_ERR ("Not enough memory for xpram_devices[%d].device_name\n" ,i); -PRINT_ERR ("Giving up xpram\n" ); - goto fail_devfs_register; - } -sprintf (xpram_devices[i].device_name,XPRAM_DEVICE_NAME_PREFIX "%d" ,i); - -PRINT_DEBUG ("initializing xpram_open for device %d\n" ,i); -PRINT_DEBUG (" size %dkB, name %s, usage: %d\n" , - xpram_devices[i].size,xpram_devices[i].device_name,atomic_read (&(xpram_devices[i].usage))); - -#if 0 /* WHY? */ - xpram_devices[i].devfs_entry = -devfs_register (NULL /* devfs root dir */ , - xpram_devices[i].device_name,0 , -0 /* flags */ , -XPRAM_MAJOR ,i, -0755 /* access mode */ , -0 /* uid */ ,0 /* gid */ , - &xpram_devops, - (void *) &(xpram_devices[i]) - ); -if ( xpram_devices[i].devfs_entry ==NULL ) { -PRINT_ERR ("devfs system registry failed\n" ); -PRINT_ERR ("Giving up xpram\n" ); - goto fail_devfs_register; - } -#endif /* WHY? */ +/* +* Setup device structures. +*/ + offset =0 ; +for (i =0 ; i < xpram_devs; i++) { + xpram_devices[i].size = xpram_sizes[i] /4 ; + xpram_devices[i].offset = offset; + offset += xpram_devices[i].size; } -return 0 ;/* succeed */ - -/* clean up memory in case of failures */ - fail_devfs_register: -for (i=0 ; i < xpram_devs; i++) { -if ( xpram_devices[i].device_name ) -kfree (xpram_devices[i].device_name); - } -kfree (xpram_devices); -kfree (xpram_offsets); - fail_malloc_devices: - fail_malloc: -/* ??? unregister_chrdev(major, "xpram"); */ -unregister_blkdev (major,"xpram" ); -return result; +return 0 ; }/* -* Finally, the module stuff +* Finally, the init/exit functions. */ - -int init_module (void ) +static void __exit xpram_exit(void) { -int rc =0 ; - -PRINT_INFO ("trying to load module\n" ); - rc =xpram_init (); -if (rc ==0 ) { -PRINT_INFO ("Module loaded successfully\n" ); - }else { -PRINT_WARN ("Module load returned rc=%d\n" , rc); - } -return rc; +blk_clear (XPRAM_MAJOR ); +devfs_unregister_blkdev (XPRAM_MAJOR ,XPRAM_NAME ); +devfs_unregister (xpram_devfs_handle); +unregister_sys_device (&xpram_sys_device); } -void cleanup_module (void ) +static int __init xpram_init (void ) { -int i; - -/* first of all, reset all the data structures */ -kfree (xpram_offsets); -blk_clear (major); +int rc; -/* finally, the usual cleanup */ -devfs_unregister (xpram_devfs_handle); -if (devfs_unregister_blkdev (MAJOR_NR ,"xpram" )) -printk (KERN_WARNING "xpram: cannot unregister blkdev\n" ); -kfree (xpram_devices); +/* Find out size of expanded memory. */ +if (xpram_present () !=0 ) { +PRINT_WARN ("No expanded memory available\n" ); +return -ENODEV ; + } + xpram_pages =xpram_highest_page_index (); +PRINT_INFO (" %li pages expanded memory found (%li KB).\n" , + xpram_pages, xpram_pages*4 ); + rc =xpram_setup_sizes (xpram_pages); +if (rc) +return rc; + rc =register_sys_device (&xpram_sys_device); +if (rc) +return rc; + rc =xpram_setup_blkdev (); +if (rc) +unregister_sys_device (&xpram_sys_device); +return rc; } + +module_init (xpram_init); +module_exit (xpram_exit);
drivers/s390/block/xpram.h +0 -70
70 lines not on this page · raw message