linux/drivers/s390/block/xpram.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xpram.c -- the S/390 expanded memory RAM-disk
   4 *           
   5 * significant parts of this code are based on
   6 * the sbull device driver presented in
   7 * A. Rubini: Linux Device Drivers
   8 *
   9 * Author of XPRAM specific coding: Reinhard Buendgen
  10 *                                  buendgen@de.ibm.com
  11 * Rewrite for 2.5: Martin Schwidefsky <schwidefsky@de.ibm.com>
  12 *
  13 * External interfaces:
  14 *   Interfaces to linux kernel
  15 *        xpram_setup: read kernel parameters
  16 *   Device specific file operations
  17 *        xpram_iotcl
  18 *        xpram_open
  19 *
  20 * "ad-hoc" partitioning:
  21 *    the expanded memory can be partitioned among several devices 
  22 *    (with different minors). The partitioning set up can be
  23 *    set by kernel or module parameters (int devs & int sizes[])
  24 *
  25 * Potential future improvements:
  26 *   generic hard disk support to replace ad-hoc partitioning
  27 */
  28
  29#define KMSG_COMPONENT "xpram"
  30#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  31
  32#include <linux/module.h>
  33#include <linux/moduleparam.h>
  34#include <linux/ctype.h>  /* isdigit, isxdigit */
  35#include <linux/errno.h>
  36#include <linux/init.h>
  37#include <linux/blkdev.h>
  38#include <linux/blkpg.h>
  39#include <linux/hdreg.h>  /* HDIO_GETGEO */
  40#include <linux/device.h>
  41#include <linux/bio.h>
  42#include <linux/suspend.h>
  43#include <linux/platform_device.h>
  44#include <linux/gfp.h>
  45#include <linux/uaccess.h>
  46
  47#define XPRAM_NAME      "xpram"
  48#define XPRAM_DEVS      1       /* one partition */
  49#define XPRAM_MAX_DEVS  32      /* maximal number of devices (partitions) */
  50
  51typedef struct {
  52        unsigned int    size;           /* size of xpram segment in pages */
  53        unsigned int    offset;         /* start page of xpram segment */
  54} xpram_device_t;
  55
  56static xpram_device_t xpram_devices[XPRAM_MAX_DEVS];
  57static unsigned int xpram_sizes[XPRAM_MAX_DEVS];
  58static struct gendisk *xpram_disks[XPRAM_MAX_DEVS];
  59static struct request_queue *xpram_queues[XPRAM_MAX_DEVS];
  60static unsigned int xpram_pages;
  61static int xpram_devs;
  62
  63/*
  64 * Parameter parsing functions.
  65 */
  66static int devs = XPRAM_DEVS;
  67static char *sizes[XPRAM_MAX_DEVS];
  68
  69module_param(devs, int, 0);
  70module_param_array(sizes, charp, NULL, 0);
  71
  72MODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \
  73                 "the default is " __MODULE_STRING(XPRAM_DEVS) "\n");
  74MODULE_PARM_DESC(sizes, "list of device (partition) sizes " \
  75                 "the defaults are 0s \n" \
  76                 "All devices with size 0 equally partition the "
  77                 "remaining space on the expanded strorage not "
  78                 "claimed by explicit sizes\n");
  79MODULE_LICENSE("GPL");
  80
  81/*
  82 * Copy expanded memory page (4kB) into main memory                  
  83 * Arguments                                                         
  84 *           page_addr:    address of target page                    
  85 *           xpage_index:  index of expandeded memory page           
  86 * Return value                                                      
  87 *           0:            if operation succeeds
  88 *           -EIO:         if pgin failed
  89 *           -ENXIO:       if xpram has vanished
  90 */
  91static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index)
  92{
  93        int cc = 2;     /* return unused cc 2 if pgin traps */
  94
  95        asm volatile(
  96                "       .insn   rre,0xb22e0000,%1,%2\n"  /* pgin %1,%2 */
  97                "0:     ipm     %0\n"
  98                "       srl     %0,28\n"
  99                "1:\n"
 100                EX_TABLE(0b,1b)
 101                : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
 102        if (cc == 3)
 103                return -ENXIO;
 104        if (cc == 2)
 105                return -ENXIO;
 106        if (cc == 1)
 107                return -EIO;
 108        return 0;
 109}
 110
 111/*
 112 * Copy a 4kB page of main memory to an expanded memory page          
 113 * Arguments                                                          
 114 *           page_addr:    address of source page                     
 115 *           xpage_index:  index of expandeded memory page            
 116 * Return value                                                       
 117 *           0:            if operation succeeds
 118 *           -EIO:         if pgout failed
 119 *           -ENXIO:       if xpram has vanished
 120 */
 121static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index)
 122{
 123        int cc = 2;     /* return unused cc 2 if pgin traps */
 124
 125        asm volatile(
 126                "       .insn   rre,0xb22f0000,%1,%2\n"  /* pgout %1,%2 */
 127                "0:     ipm     %0\n"
 128                "       srl     %0,28\n"
 129                "1:\n"
 130                EX_TABLE(0b,1b)
 131                : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
 132        if (cc == 3)
 133                return -ENXIO;
 134        if (cc == 2)
 135                return -ENXIO;
 136        if (cc == 1)
 137                return -EIO;
 138        return 0;
 139}
 140
 141/*
 142 * Check if xpram is available.
 143 */
 144static int xpram_present(void)
 145{
 146        unsigned long mem_page;
 147        int rc;
 148
 149        mem_page = (unsigned long) __get_free_page(GFP_KERNEL);
 150        if (!mem_page)
 151                return -ENOMEM;
 152        rc = xpram_page_in(mem_page, 0);
 153        free_page(mem_page);
 154        return rc ? -ENXIO : 0;
 155}
 156
 157/*
 158 * Return index of the last available xpram page.
 159 */
 160static unsigned long xpram_highest_page_index(void)
 161{
 162        unsigned int page_index, add_bit;
 163        unsigned long mem_page;
 164
 165        mem_page = (unsigned long) __get_free_page(GFP_KERNEL);
 166        if (!mem_page)
 167                return 0;
 168
 169        page_index = 0;
 170        add_bit = 1ULL << (sizeof(unsigned int)*8 - 1);
 171        while (add_bit > 0) {
 172                if (xpram_page_in(mem_page, page_index | add_bit) == 0)
 173                        page_index |= add_bit;
 174                add_bit >>= 1;
 175        }
 176
 177        free_page (mem_page);
 178
 179        return page_index;
 180}
 181
 182/*
 183 * Block device make request function.
 184 */
 185static blk_qc_t xpram_submit_bio(struct bio *bio)
 186{
 187        xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data;
 188        struct bio_vec bvec;
 189        struct bvec_iter iter;
 190        unsigned int index;
 191        unsigned long page_addr;
 192        unsigned long bytes;
 193
 194        blk_queue_split(&bio);
 195
 196        if ((bio->bi_iter.bi_sector & 7) != 0 ||
 197            (bio->bi_iter.bi_size & 4095) != 0)
 198                /* Request is not page-aligned. */
 199                goto fail;
 200        if ((bio->bi_iter.bi_size >> 12) > xdev->size)
 201                /* Request size is no page-aligned. */
 202                goto fail;
 203        if ((bio->bi_iter.bi_sector >> 3) > 0xffffffffU - xdev->offset)
 204                goto fail;
 205        index = (bio->bi_iter.bi_sector >> 3) + xdev->offset;
 206        bio_for_each_segment(bvec, bio, iter) {
 207                page_addr = (unsigned long)
 208                        kmap(bvec.bv_page) + bvec.bv_offset;
 209                bytes = bvec.bv_len;
 210                if ((page_addr & 4095) != 0 || (bytes & 4095) != 0)
 211                        /* More paranoia. */
 212                        goto fail;
 213                while (bytes > 0) {
 214                        if (bio_data_dir(bio) == READ) {
 215                                if (xpram_page_in(page_addr, index) != 0)
 216                                        goto fail;
 217                        } else {
 218                                if (xpram_page_out(page_addr, index) != 0)
 219                                        goto fail;
 220                        }
 221                        page_addr += 4096;
 222                        bytes -= 4096;
 223                        index++;
 224                }
 225        }
 226        bio_endio(bio);
 227        return BLK_QC_T_NONE;
 228fail:
 229        bio_io_error(bio);
 230        return BLK_QC_T_NONE;
 231}
 232
 233static int xpram_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 234{
 235        unsigned long size;
 236
 237        /*
 238         * get geometry: we have to fake one...  trim the size to a
 239         * multiple of 64 (32k): tell we have 16 sectors, 4 heads,
 240         * whatever cylinders. Tell also that data starts at sector. 4.
 241         */
 242        size = (xpram_pages * 8) & ~0x3f;
 243        geo->cylinders = size >> 6;
 244        geo->heads = 4;
 245        geo->sectors = 16;
 246        geo->start = 4;
 247        return 0;
 248}
 249
 250static const struct block_device_operations xpram_devops =
 251{
 252        .owner  = THIS_MODULE,
 253        .submit_bio = xpram_submit_bio,
 254        .getgeo = xpram_getgeo,
 255};
 256
 257/*
 258 * Setup xpram_sizes array.
 259 */
 260static int __init xpram_setup_sizes(unsigned long pages)
 261{
 262        unsigned long mem_needed;
 263        unsigned long mem_auto;
 264        unsigned long long size;
 265        char *sizes_end;
 266        int mem_auto_no;
 267        int i;
 268
 269        /* Check number of devices. */
 270        if (devs <= 0 || devs > XPRAM_MAX_DEVS) {
 271                pr_err("%d is not a valid number of XPRAM devices\n",devs);
 272                return -EINVAL;
 273        }
 274        xpram_devs = devs;
 275
 276        /*
 277         * Copy sizes array to xpram_sizes and align partition
 278         * sizes to page boundary.
 279         */
 280        mem_needed = 0;
 281        mem_auto_no = 0;
 282        for (i = 0; i < xpram_devs; i++) {
 283                if (sizes[i]) {
 284                        size = simple_strtoull(sizes[i], &sizes_end, 0);
 285                        switch (*sizes_end) {
 286                        case 'g':
 287                        case 'G':
 288                                size <<= 20;
 289                                break;
 290                        case 'm':
 291                        case 'M':
 292                                size <<= 10;
 293                        }
 294                        xpram_sizes[i] = (size + 3) & -4UL;
 295                }
 296                if (xpram_sizes[i])
 297                        mem_needed += xpram_sizes[i];
 298                else
 299                        mem_auto_no++;
 300        }
 301        
 302        pr_info("  number of devices (partitions): %d \n", xpram_devs);
 303        for (i = 0; i < xpram_devs; i++) {
 304                if (xpram_sizes[i])
 305                        pr_info("  size of partition %d: %u kB\n",
 306                                i, xpram_sizes[i]);
 307                else
 308                        pr_info("  size of partition %d to be set "
 309                                "automatically\n",i);
 310        }
 311        pr_info("  memory needed (for sized partitions): %lu kB\n",
 312                mem_needed);
 313        pr_info("  partitions to be sized automatically: %d\n",
 314                mem_auto_no);
 315
 316        if (mem_needed > pages * 4) {
 317                pr_err("Not enough expanded memory available\n");
 318                return -EINVAL;
 319        }
 320
 321        /*
 322         * partitioning:
 323         * xpram_sizes[i] != 0; partition i has size xpram_sizes[i] kB
 324         * else:             ; all partitions with zero xpram_sizes[i]
 325         *                     partition equally the remaining space
 326         */
 327        if (mem_auto_no) {
 328                mem_auto = ((pages - mem_needed / 4) / mem_auto_no) * 4;
 329                pr_info("  automatically determined "
 330                        "partition size: %lu kB\n", mem_auto);
 331                for (i = 0; i < xpram_devs; i++)
 332                        if (xpram_sizes[i] == 0)
 333                                xpram_sizes[i] = mem_auto;
 334        }
 335        return 0;
 336}
 337
 338static int __init xpram_setup_blkdev(void)
 339{
 340        unsigned long offset;
 341        int i, rc = -ENOMEM;
 342
 343        for (i = 0; i < xpram_devs; i++) {
 344                xpram_disks[i] = alloc_disk(1);
 345                if (!xpram_disks[i])
 346                        goto out;
 347                xpram_queues[i] = blk_alloc_queue(NUMA_NO_NODE);
 348                if (!xpram_queues[i]) {
 349                        put_disk(xpram_disks[i]);
 350                        goto out;
 351                }
 352                blk_queue_flag_set(QUEUE_FLAG_NONROT, xpram_queues[i]);
 353                blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, xpram_queues[i]);
 354                blk_queue_logical_block_size(xpram_queues[i], 4096);
 355        }
 356
 357        /*
 358         * Register xpram major.
 359         */
 360        rc = register_blkdev(XPRAM_MAJOR, XPRAM_NAME);
 361        if (rc < 0)
 362                goto out;
 363
 364        /*
 365         * Setup device structures.
 366         */
 367        offset = 0;
 368        for (i = 0; i < xpram_devs; i++) {
 369                struct gendisk *disk = xpram_disks[i];
 370
 371                xpram_devices[i].size = xpram_sizes[i] / 4;
 372                xpram_devices[i].offset = offset;
 373                offset += xpram_devices[i].size;
 374                disk->major = XPRAM_MAJOR;
 375                disk->first_minor = i;
 376                disk->fops = &xpram_devops;
 377                disk->private_data = &xpram_devices[i];
 378                disk->queue = xpram_queues[i];
 379                sprintf(disk->disk_name, "slram%d", i);
 380                set_capacity(disk, xpram_sizes[i] << 1);
 381                add_disk(disk);
 382        }
 383
 384        return 0;
 385out:
 386        while (i--) {
 387                blk_cleanup_queue(xpram_queues[i]);
 388                put_disk(xpram_disks[i]);
 389        }
 390        return rc;
 391}
 392
 393/*
 394 * Resume failed: Print error message and call panic.
 395 */
 396static void xpram_resume_error(const char *message)
 397{
 398        pr_err("Resuming the system failed: %s\n", message);
 399        panic("xpram resume error\n");
 400}
 401
 402/*
 403 * Check if xpram setup changed between suspend and resume.
 404 */
 405static int xpram_restore(struct device *dev)
 406{
 407        if (!xpram_pages)
 408                return 0;
 409        if (xpram_present() != 0)
 410                xpram_resume_error("xpram disappeared");
 411        if (xpram_pages != xpram_highest_page_index() + 1)
 412                xpram_resume_error("Size of xpram changed");
 413        return 0;
 414}
 415
 416static const struct dev_pm_ops xpram_pm_ops = {
 417        .restore        = xpram_restore,
 418};
 419
 420static struct platform_driver xpram_pdrv = {
 421        .driver = {
 422                .name   = XPRAM_NAME,
 423                .pm     = &xpram_pm_ops,
 424        },
 425};
 426
 427static struct platform_device *xpram_pdev;
 428
 429/*
 430 * Finally, the init/exit functions.
 431 */
 432static void __exit xpram_exit(void)
 433{
 434        int i;
 435        for (i = 0; i < xpram_devs; i++) {
 436                del_gendisk(xpram_disks[i]);
 437                blk_cleanup_queue(xpram_queues[i]);
 438                put_disk(xpram_disks[i]);
 439        }
 440        unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
 441        platform_device_unregister(xpram_pdev);
 442        platform_driver_unregister(&xpram_pdrv);
 443}
 444
 445static int __init xpram_init(void)
 446{
 447        int rc;
 448
 449        /* Find out size of expanded memory. */
 450        if (xpram_present() != 0) {
 451                pr_err("No expanded memory available\n");
 452                return -ENODEV;
 453        }
 454        xpram_pages = xpram_highest_page_index() + 1;
 455        pr_info("  %u pages expanded memory found (%lu KB).\n",
 456                xpram_pages, (unsigned long) xpram_pages*4);
 457        rc = xpram_setup_sizes(xpram_pages);
 458        if (rc)
 459                return rc;
 460        rc = platform_driver_register(&xpram_pdrv);
 461        if (rc)
 462                return rc;
 463        xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0);
 464        if (IS_ERR(xpram_pdev)) {
 465                rc = PTR_ERR(xpram_pdev);
 466                goto fail_platform_driver_unregister;
 467        }
 468        rc = xpram_setup_blkdev();
 469        if (rc)
 470                goto fail_platform_device_unregister;
 471        return 0;
 472
 473fail_platform_device_unregister:
 474        platform_device_unregister(xpram_pdev);
 475fail_platform_driver_unregister:
 476        platform_driver_unregister(&xpram_pdrv);
 477        return rc;
 478}
 479
 480module_init(xpram_init);
 481module_exit(xpram_exit);
 482