11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Xpram.c -- the S/390 expanded memory RAM-disk 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * significant parts of this code are based on 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the sbull device driver presented in 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A. Rubini: Linux Device Drivers 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author of XPRAM specific coding: Reinhard Buendgen 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buendgen@de.ibm.com 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Rewrite for 2.5: Martin Schwidefsky <schwidefsky@de.ibm.com> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * External interfaces: 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interfaces to linux kernel 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xpram_setup: read kernel parameters 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Device specific file operations 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xpram_iotcl 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xpram_open 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "ad-hoc" partitioning: 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the expanded memory can be partitioned among several devices 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (with different minors). The partitioning set up can be 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set by kernel or module parameters (int devs & int sizes[]) 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Potential future improvements: 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * generic hard disk support to replace ad-hoc partitioning 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky#define KMSG_COMPONENT "xpram" 29d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 30d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ctype.h> /* isdigit, isxdigit */ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkpg.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdreg.h> /* HDIO_GETGEO */ 39edbaa603eb801655e80808a9cf3d3b622e8ac66bKay Sievers#include <linux/device.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bio.h> 4114532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu#include <linux/suspend.h> 4214532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu#include <linux/platform_device.h> 435a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XPRAM_NAME "xpram" 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XPRAM_DEVS 1 /* one partition */ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define XPRAM_MAX_DEVS 32 /* maximal number of devices (partitions) */ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct { 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int size; /* size of xpram segment in pages */ 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int offset; /* start page of xpram segment */ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} xpram_device_t; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int xpram_sizes[XPRAM_MAX_DEVS]; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct gendisk *xpram_disks[XPRAM_MAX_DEVS]; 583ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefskystatic struct request_queue *xpram_queues[XPRAM_MAX_DEVS]; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int xpram_pages; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int xpram_devs; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parameter parsing functions. 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 650c0db0355bc070b4c623622248d3f577642536b9Martin Schwidefskystatic int devs = XPRAM_DEVS; 660c0db0355bc070b4c623622248d3f577642536b9Martin Schwidefskystatic char *sizes[XPRAM_MAX_DEVS]; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(devs, int, 0); 695c898ba9d4b6c14fdd367b96e3641c2508b4a4a9Heiko Carstensmodule_param_array(sizes, charp, NULL, 0); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \ 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "the default is " __MODULE_STRING(XPRAM_DEVS) "\n"); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(sizes, "list of device (partition) sizes " \ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "the defaults are 0s \n" \ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "All devices with size 0 equally partition the " 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "remaining space on the expanded strorage not " 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "claimed by explicit sizes\n"); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy expanded memory page (4kB) into main memory 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * page_addr: address of target page 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xpage_index: index of expandeded memory page 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return value 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0: if operation succeeds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -EIO: if pgin failed 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -ENXIO: if xpram has vanished 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int xpram_page_in (unsigned long page_addr, unsigned int xpage_index) 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9294c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky int cc = 2; /* return unused cc 2 if pgin traps */ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9494c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky asm volatile( 9594c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky " .insn rre,0xb22e0000,%1,%2\n" /* pgin %1,%2 */ 9694c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky "0: ipm %0\n" 9794c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky " srl %0,28\n" 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "1:\n" 9994c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky EX_TABLE(0b,1b) 10094c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc"); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cc == 3) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 1038df22b4b39c6a1679f471bd68f97cf6f6819571aMartin Schwidefsky if (cc == 2) 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 1058df22b4b39c6a1679f471bd68f97cf6f6819571aMartin Schwidefsky if (cc == 1) 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy a 4kB page of main memory to an expanded memory page 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Arguments 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * page_addr: address of source page 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xpage_index: index of expandeded memory page 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return value 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0: if operation succeeds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -EIO: if pgout failed 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -ENXIO: if xpram has vanished 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic long xpram_page_out (unsigned long page_addr, unsigned int xpage_index) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12294c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky int cc = 2; /* return unused cc 2 if pgin traps */ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12494c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky asm volatile( 12594c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky " .insn rre,0xb22f0000,%1,%2\n" /* pgout %1,%2 */ 12694c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky "0: ipm %0\n" 12794c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky " srl %0,28\n" 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "1:\n" 12994c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky EX_TABLE(0b,1b) 13094c12cc7d196bab34aaa98d38521549fa1e5ef76Martin Schwidefsky : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc"); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cc == 3) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 1338df22b4b39c6a1679f471bd68f97cf6f6819571aMartin Schwidefsky if (cc == 2) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 1358df22b4b39c6a1679f471bd68f97cf6f6819571aMartin Schwidefsky if (cc == 1) 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check if xpram is available. 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14314532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheustatic int xpram_present(void) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long mem_page; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem_page = (unsigned long) __get_free_page(GFP_KERNEL); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mem_page) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = xpram_page_in(mem_page, 0); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_page(mem_page); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc ? -ENXIO : 0; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return index of the last available xpram page. 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15914532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheustatic unsigned long xpram_highest_page_index(void) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int page_index, add_bit; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long mem_page; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem_page = (unsigned long) __get_free_page(GFP_KERNEL); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mem_page) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page_index = 0; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_bit = 1ULL << (sizeof(unsigned int)*8 - 1); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (add_bit > 0) { 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xpram_page_in(mem_page, page_index | add_bit) == 0) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page_index |= add_bit; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_bit >>= 1; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_page (mem_page); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return page_index; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Block device make request function. 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1845a7bbad27a410350e64a2d7f5ec18fc73836c14fChristoph Hellwigstatic void xpram_make_request(struct request_queue *q, struct bio *bio) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio_vec *bvec; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int index; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long page_addr; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long bytes; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Request is not page-aligned. */ 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((bio->bi_size >> 12) > xdev->size) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Request size is no page-aligned. */ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((bio->bi_sector >> 3) > 0xffffffffU - xdev->offset) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = (bio->bi_sector >> 3) + xdev->offset; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_for_each_segment(bvec, bio, i) { 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page_addr = (unsigned long) 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kmap(bvec->bv_page) + bvec->bv_offset; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytes = bvec->bv_len; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((page_addr & 4095) != 0 || (bytes & 4095) != 0) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* More paranoia. */ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bytes > 0) { 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bio_data_dir(bio) == READ) { 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xpram_page_in(page_addr, index) != 0) 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xpram_page_out(page_addr, index) != 0) 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page_addr += 4096; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytes -= 4096; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index++; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(BIO_UPTODATE, &bio->bi_flags); 2231462222b76a09a24b240563a51d5f9fbea8bd3e1Martin Schwidefsky bio_endio(bio, 0); 2245a7bbad27a410350e64a2d7f5ec18fc73836c14fChristoph Hellwig return; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail: 2266712ecf8f648118c3363c142196418f89a510b90NeilBrown bio_io_error(bio); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 229a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwigstatic int xpram_getgeo(struct block_device *bdev, struct hd_geometry *geo) 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long size; 232a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get geometry: we have to fake one... trim the size to a 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multiple of 64 (32k): tell we have 16 sectors, 4 heads, 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * whatever cylinders. Tell also that data starts at sector. 4. 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = (xpram_pages * 8) & ~0x3f; 239a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig geo->cylinders = size >> 6; 240a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig geo->heads = 4; 241a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig geo->sectors = 16; 242a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig geo->start = 4; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24683d5cde47dedf01b6a4a4331882cbc0a7eea3c2eAlexey Dobriyanstatic const struct block_device_operations xpram_devops = 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 249a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig .getgeo = xpram_getgeo, 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup xpram_sizes array. 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init xpram_setup_sizes(unsigned long pages) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long mem_needed; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long mem_auto; 259f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens unsigned long long size; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mem_auto_no; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check number of devices. */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devs <= 0 || devs > XPRAM_MAX_DEVS) { 265d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_err("%d is not a valid number of XPRAM devices\n",devs); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpram_devs = devs; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy sizes array to xpram_sizes and align partition 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sizes to page boundary. 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem_needed = 0; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem_auto_no = 0; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < xpram_devs; i++) { 277f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens if (sizes[i]) { 278f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens size = simple_strtoull(sizes[i], &sizes[i], 0); 279f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens switch (sizes[i][0]) { 280f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens case 'g': 281f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens case 'G': 282f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens size <<= 20; 283f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens break; 284f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens case 'm': 285f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens case 'M': 286f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens size <<= 10; 287f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens } 288f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens xpram_sizes[i] = (size + 3) & -4UL; 289f257b06322c8a30c050a286c45fda68f23b9bc44Heiko Carstens } 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xpram_sizes[i]) 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem_needed += xpram_sizes[i]; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem_auto_no++; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 296d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_info(" number of devices (partitions): %d \n", xpram_devs); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < xpram_devs; i++) { 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xpram_sizes[i]) 299d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_info(" size of partition %d: %u kB\n", 300d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky i, xpram_sizes[i]); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 302d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_info(" size of partition %d to be set " 303d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky "automatically\n",i); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 305d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_info(" memory needed (for sized partitions): %lu kB\n", 306d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky mem_needed); 307d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_info(" partitions to be sized automatically: %d\n", 308d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky mem_auto_no); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem_needed > pages * 4) { 311d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_err("Not enough expanded memory available\n"); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * partitioning: 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xpram_sizes[i] != 0; partition i has size xpram_sizes[i] kB 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * else: ; all partitions with zero xpram_sizes[i] 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * partition equally the remaining space 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem_auto_no) { 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem_auto = ((pages - mem_needed / 4) / mem_auto_no) * 4; 323d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_info(" automatically determined " 324d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky "partition size: %lu kB\n", mem_auto); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < xpram_devs; i++) 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xpram_sizes[i] == 0) 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpram_sizes[i] = mem_auto; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init xpram_setup_blkdev(void) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long offset; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, rc = -ENOMEM; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < xpram_devs; i++) { 3383ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky xpram_disks[i] = alloc_disk(1); 3393ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky if (!xpram_disks[i]) 3403ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky goto out; 3413ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky xpram_queues[i] = blk_alloc_queue(GFP_KERNEL); 3423ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky if (!xpram_queues[i]) { 3433ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky put_disk(xpram_disks[i]); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3453ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky } 3463ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky blk_queue_make_request(xpram_queues[i], xpram_make_request); 347e1defc4ff0cf57aca6c5e3ff99fa503f5943c1f1Martin K. Petersen blk_queue_logical_block_size(xpram_queues[i], 4096); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Register xpram major. 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = register_blkdev(XPRAM_MAJOR, XPRAM_NAME); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc < 0) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup device structures. 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = 0; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < xpram_devs; i++) { 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gendisk *disk = xpram_disks[i]; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpram_devices[i].size = xpram_sizes[i] / 4; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xpram_devices[i].offset = offset; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset += xpram_devices[i].size; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->major = XPRAM_MAJOR; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->first_minor = i; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->fops = &xpram_devops; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->private_data = &xpram_devices[i]; 3713ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky disk->queue = xpram_queues[i]; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(disk->disk_name, "slram%d", i); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_capacity(disk, xpram_sizes[i] << 1); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_disk(disk); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 3793ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky while (i--) { 3803ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky blk_cleanup_queue(xpram_queues[i]); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_disk(xpram_disks[i]); 3823ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky } 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 38714532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu * Resume failed: Print error message and call panic. 38814532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu */ 38914532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheustatic void xpram_resume_error(const char *message) 39014532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu{ 3912c48c4d631970b70d60a4f926b0f68f194a0d559Christian Borntraeger pr_err("Resuming the system failed: %s\n", message); 39214532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu panic("xpram resume error\n"); 39314532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu} 39414532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu 39514532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu/* 39614532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu * Check if xpram setup changed between suspend and resume. 39714532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu */ 39814532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheustatic int xpram_restore(struct device *dev) 39914532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu{ 40014532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu if (!xpram_pages) 40114532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu return 0; 40214532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu if (xpram_present() != 0) 40314532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu xpram_resume_error("xpram disappeared"); 40414532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu if (xpram_pages != xpram_highest_page_index() + 1) 40514532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu xpram_resume_error("Size of xpram changed"); 40614532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu return 0; 40714532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu} 40814532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu 409471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops xpram_pm_ops = { 41014532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu .restore = xpram_restore, 41114532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu}; 41214532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu 41314532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheustatic struct platform_driver xpram_pdrv = { 41414532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu .driver = { 41514532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu .name = XPRAM_NAME, 41614532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu .owner = THIS_MODULE, 41714532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu .pm = &xpram_pm_ops, 41814532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu }, 41914532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu}; 42014532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu 42114532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheustatic struct platform_device *xpram_pdev; 42214532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu 42314532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu/* 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finally, the init/exit functions. 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit xpram_exit(void) 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < xpram_devs; i++) { 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_gendisk(xpram_disks[i]); 4313ce66093f5ec5a6ae0ca90c79d81eee15e842293Martin Schwidefsky blk_cleanup_queue(xpram_queues[i]); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_disk(xpram_disks[i]); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); 43514532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu platform_device_unregister(xpram_pdev); 43614532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu platform_driver_unregister(&xpram_pdrv); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init xpram_init(void) 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find out size of expanded memory. */ 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xpram_present() != 0) { 445d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_err("No expanded memory available\n"); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 448e620c4940002348417e8d317d65bc7b152646493Christian Borntraeger xpram_pages = xpram_highest_page_index() + 1; 449d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky pr_info(" %u pages expanded memory found (%lu KB).\n", 450d1c2f8928a2feab56a181bb7e9afe8f804fd26cdMartin Schwidefsky xpram_pages, (unsigned long) xpram_pages*4); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = xpram_setup_sizes(xpram_pages); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 45414532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu rc = platform_driver_register(&xpram_pdrv); 45514532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu if (rc) 45614532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu return rc; 45714532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0); 45814532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu if (IS_ERR(xpram_pdev)) { 45914532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu rc = PTR_ERR(xpram_pdev); 46014532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu goto fail_platform_driver_unregister; 46114532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu } 46214532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu rc = xpram_setup_blkdev(); 46314532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu if (rc) 46414532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu goto fail_platform_device_unregister; 46514532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu return 0; 46614532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu 46714532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheufail_platform_device_unregister: 46814532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu platform_device_unregister(xpram_pdev); 46914532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheufail_platform_driver_unregister: 47014532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu platform_driver_unregister(&xpram_pdrv); 47114532095dfe9e8faf2d314d9c2170f64737c7dffMichael Holzheu return rc; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(xpram_init); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(xpram_exit); 476