Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Mon, 17 Jun 2002 17:25:36 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Mon, 17 Jun 2002 17:25:35 -0400 Received: from psmtp1.dnsg.net ([193.168.128.41]:30111 "HELO psmtp1.dnsg.net") by vger.kernel.org with SMTP id ; Mon, 17 Jun 2002 17:23:44 -0400 Subject: [PATCH] 2.5.22: new xpram driver 2nd try. To: linux-kernel@vger.kernel.org Date: Tue, 18 Jun 2002 01:22:20 +0200 (CEST) CC: torvalds@transmeta.com X-Mailer: ELM [version 2.4ME+ PL66 (25)] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Message-Id: From: Martin Schwidefsky Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 53517 Lines: 1550 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. diff -urN linux-2.5.22/drivers/s390/block/xpram.c linux-2.5.22-s390/drivers/s390/block/xpram.c --- linux-2.5.22/drivers/s390/block/xpram.c Mon Jun 17 04:31:35 2002 +++ linux-2.5.22-s390/drivers/s390/block/xpram.c Mon Jun 17 22:54:15 2002 @@ -1,4 +1,3 @@ - /* * Xpram.c -- the S/390 expanded memory RAM-disk * @@ -8,137 +7,66 @@ * * Author of XPRAM specific coding: Reinhard Buendgen * buendgen@de.ibm.com + * Rewrite for 2.5: Martin Schwidefsky * * 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 #include - -#ifdef MODULE -char kernel_version [] = UTS_RELEASE; -#endif - -#include -#include -#include -#include /* printk() */ -#include /* kmalloc() */ -#include -#include /* everything... */ -#include /* error codes */ -#include -#include /* size_t */ #include /* isdigit, isxdigit */ -#include /* O_ACCMODE */ -#include /* HDIO_GETGEO */ - -#include /* cli(), *_flags */ -#include /* 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 +#include +#include #include +#include +#include /* HDIO_GETGEO */ +#include +#include -#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 + * [","]* + * 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 + * 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 (",")* - * 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 - * [","]* - * 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 - * 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); diff -urN linux-2.5.22/drivers/s390/block/xpram.h linux-2.5.22-s390/drivers/s390/block/xpram.h --- linux-2.5.22/drivers/s390/block/xpram.h Mon Jun 17 04:31:32 2002 +++ linux-2.5.22-s390/drivers/s390/block/xpram.h Thu Jan 1 01:00:00 1970 @@ -1,70 +0,0 @@ - -/* - * xpram.h -- definitions for the char module - * - *********/ - - -#include -#include -#include - -/* version dependencies have been confined to a separate file */ - -/* - * Macros to help debugging - */ - -#define XPRAM_NAME "xpram" /* name of device/module */ -#define XPRAM_DEVICE_NAME_PREFIX "slram" /* Prefix device name for major 35 */ -#define XPRAM_DEVS 1 /* one partition */ -#define XPRAM_RAHEAD 8 /* no real read ahead */ -#define XPRAM_PGSIZE 4096 /* page size of (expanded) mememory pages - * according to S/390 architecture - */ -#define XPRAM_BLKSIZE XPRAM_PGSIZE /* must be equalt to page size ! */ -#define XPRAM_HARDSECT XPRAM_PGSIZE /* FIXME -- we have to deal with both - * this hard sect size and in some cases - * hard coded 512 bytes which I call - * soft sects: - */ -#define XPRAM_SOFTSECT 512 -#define XPRAM_MAX_DEVS 32 /* maximal number of devices (partitions) */ -#define XPRAM_MAX_DEVS1 33 /* maximal number of devices (partitions) +1 */ - -/* The following macros depend on the sizes above */ - -#define XPRAM_KB_IN_PG 4 /* 4 kBs per page */ -#define XPRAM_KB_IN_PG_ORDER 2 /* 2^? kBs per page */ - -/* Eventhough XPRAM_HARDSECT is set to 4k some data structures use hard - * coded 512 byte sa sector size - */ -#define XPRAM_SEC2KB(x) ((x >> 1) + (x & 1)) /* modifier used to compute size - in kB from number of sectors */ -#define XPRAM_SEC_IN_PG 8 /* 8 sectors per page */ -#define XPRAM_SEC_IN_PG_ORDER 3 /* 2^? sectors per page */ - -#define XPRAM_UNUSED 40 /* unused space between devices, - * in kB, i.e. - * must be a multiple of 4 - */ -/* - * The xpram device is removable: if it is left closed for more than - * half a minute, it is removed. Thus use a usage count and a - * kernel timer - */ - -typedef struct Xpram_Dev { - int size; /* size in KB not in Byte - RB - */ - atomic_t usage; - char * device_name; /* device name prefix in devfs */ - devfs_handle_t devfs_entry; /* handle needed to unregister dev from devfs */ - u8 *data; -} Xpram_Dev; - -/* 2.2: void xpram_setup (char *, int *); */ -/* begin 2.3 */ -int xpram_setup (char *); -/* end 2.3 */ -int xpram_init(void); - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/