aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@de.ibm.com>2009-06-16 04:30:27 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-06-16 04:31:11 -0400
commit14532095dfe9e8faf2d314d9c2170f64737c7dff (patch)
tree12435ebeb365a709daa199f9af8ae24753bde6dc /drivers/s390/block
parent7db11a363fc41cec170a94a3542031e5e64bb333 (diff)
[S390] pm: xpram driver power management callbacks
Signed-off-by: Michael Holzheu <holzheu@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block')
-rw-r--r--drivers/s390/block/xpram.c129
1 files changed, 126 insertions, 3 deletions
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 0ae0c83ef879..2e9e1ecd6d82 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -39,7 +39,10 @@
39#include <linux/hdreg.h> /* HDIO_GETGEO */ 39#include <linux/hdreg.h> /* HDIO_GETGEO */
40#include <linux/sysdev.h> 40#include <linux/sysdev.h>
41#include <linux/bio.h> 41#include <linux/bio.h>
42#include <linux/suspend.h>
43#include <linux/platform_device.h>
42#include <asm/uaccess.h> 44#include <asm/uaccess.h>
45#include <asm/checksum.h>
43 46
44#define XPRAM_NAME "xpram" 47#define XPRAM_NAME "xpram"
45#define XPRAM_DEVS 1 /* one partition */ 48#define XPRAM_DEVS 1 /* one partition */
@@ -48,6 +51,7 @@
48typedef struct { 51typedef struct {
49 unsigned int size; /* size of xpram segment in pages */ 52 unsigned int size; /* size of xpram segment in pages */
50 unsigned int offset; /* start page of xpram segment */ 53 unsigned int offset; /* start page of xpram segment */
54 unsigned int csum; /* partition checksum for suspend */
51} xpram_device_t; 55} xpram_device_t;
52 56
53static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; 57static xpram_device_t xpram_devices[XPRAM_MAX_DEVS];
@@ -138,7 +142,7 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index)
138/* 142/*
139 * Check if xpram is available. 143 * Check if xpram is available.
140 */ 144 */
141static int __init xpram_present(void) 145static int xpram_present(void)
142{ 146{
143 unsigned long mem_page; 147 unsigned long mem_page;
144 int rc; 148 int rc;
@@ -154,7 +158,7 @@ static int __init xpram_present(void)
154/* 158/*
155 * Return index of the last available xpram page. 159 * Return index of the last available xpram page.
156 */ 160 */
157static unsigned long __init xpram_highest_page_index(void) 161static unsigned long xpram_highest_page_index(void)
158{ 162{
159 unsigned int page_index, add_bit; 163 unsigned int page_index, add_bit;
160 unsigned long mem_page; 164 unsigned long mem_page;
@@ -383,6 +387,106 @@ out:
383} 387}
384 388
385/* 389/*
390 * Save checksums for all partitions.
391 */
392static int xpram_save_checksums(void)
393{
394 unsigned long mem_page;
395 int rc, i;
396
397 rc = 0;
398 mem_page = (unsigned long) __get_free_page(GFP_KERNEL);
399 if (!mem_page)
400 return -ENOMEM;
401 for (i = 0; i < xpram_devs; i++) {
402 rc = xpram_page_in(mem_page, xpram_devices[i].offset);
403 if (rc)
404 goto fail;
405 xpram_devices[i].csum = csum_partial((const void *) mem_page,
406 PAGE_SIZE, 0);
407 }
408fail:
409 free_page(mem_page);
410 return rc ? -ENXIO : 0;
411}
412
413/*
414 * Verify checksums for all partitions.
415 */
416static int xpram_validate_checksums(void)
417{
418 unsigned long mem_page;
419 unsigned int csum;
420 int rc, i;
421
422 rc = 0;
423 mem_page = (unsigned long) __get_free_page(GFP_KERNEL);
424 if (!mem_page)
425 return -ENOMEM;
426 for (i = 0; i < xpram_devs; i++) {
427 rc = xpram_page_in(mem_page, xpram_devices[i].offset);
428 if (rc)
429 goto fail;
430 csum = csum_partial((const void *) mem_page, PAGE_SIZE, 0);
431 if (xpram_devices[i].csum != csum) {
432 rc = -EINVAL;
433 goto fail;
434 }
435 }
436fail:
437 free_page(mem_page);
438 return rc ? -ENXIO : 0;
439}
440
441/*
442 * Resume failed: Print error message and call panic.
443 */
444static void xpram_resume_error(const char *message)
445{
446 pr_err("Resume error: %s\n", message);
447 panic("xpram resume error\n");
448}
449
450/*
451 * Check if xpram setup changed between suspend and resume.
452 */
453static int xpram_restore(struct device *dev)
454{
455 if (!xpram_pages)
456 return 0;
457 if (xpram_present() != 0)
458 xpram_resume_error("xpram disappeared");
459 if (xpram_pages != xpram_highest_page_index() + 1)
460 xpram_resume_error("Size of xpram changed");
461 if (xpram_validate_checksums())
462 xpram_resume_error("Data of xpram changed");
463 return 0;
464}
465
466/*
467 * Save necessary state in suspend.
468 */
469static int xpram_freeze(struct device *dev)
470{
471 return xpram_save_checksums();
472}
473
474static struct dev_pm_ops xpram_pm_ops = {
475 .freeze = xpram_freeze,
476 .restore = xpram_restore,
477};
478
479static struct platform_driver xpram_pdrv = {
480 .driver = {
481 .name = XPRAM_NAME,
482 .owner = THIS_MODULE,
483 .pm = &xpram_pm_ops,
484 },
485};
486
487static struct platform_device *xpram_pdev;
488
489/*
386 * Finally, the init/exit functions. 490 * Finally, the init/exit functions.
387 */ 491 */
388static void __exit xpram_exit(void) 492static void __exit xpram_exit(void)
@@ -394,6 +498,8 @@ static void __exit xpram_exit(void)
394 put_disk(xpram_disks[i]); 498 put_disk(xpram_disks[i]);
395 } 499 }
396 unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); 500 unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
501 platform_device_unregister(xpram_pdev);
502 platform_driver_unregister(&xpram_pdrv);
397} 503}
398 504
399static int __init xpram_init(void) 505static int __init xpram_init(void)
@@ -411,7 +517,24 @@ static int __init xpram_init(void)
411 rc = xpram_setup_sizes(xpram_pages); 517 rc = xpram_setup_sizes(xpram_pages);
412 if (rc) 518 if (rc)
413 return rc; 519 return rc;
414 return xpram_setup_blkdev(); 520 rc = platform_driver_register(&xpram_pdrv);
521 if (rc)
522 return rc;
523 xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0);
524 if (IS_ERR(xpram_pdev)) {
525 rc = PTR_ERR(xpram_pdev);
526 goto fail_platform_driver_unregister;
527 }
528 rc = xpram_setup_blkdev();
529 if (rc)
530 goto fail_platform_device_unregister;
531 return 0;
532
533fail_platform_device_unregister:
534 platform_device_unregister(xpram_pdev);
535fail_platform_driver_unregister:
536 platform_driver_unregister(&xpram_pdrv);
537 return rc;
415} 538}
416 539
417module_init(xpram_init); 540module_init(xpram_init);