suspend.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2010 Brian King IBM Corporation
  4. */
  5. #include <linux/cpu.h>
  6. #include <linux/delay.h>
  7. #include <linux/suspend.h>
  8. #include <linux/stat.h>
  9. #include <asm/firmware.h>
  10. #include <asm/hvcall.h>
  11. #include <asm/machdep.h>
  12. #include <asm/mmu.h>
  13. #include <asm/rtas.h>
  14. #include <asm/topology.h>
  15. static struct device suspend_dev;
  16. /**
  17. * pseries_suspend_begin - First phase of hibernation
  18. *
  19. * Check to ensure we are in a valid state to hibernate
  20. *
  21. * Return value:
  22. * 0 on success / other on failure
  23. **/
  24. static int pseries_suspend_begin(u64 stream_id)
  25. {
  26. long vasi_state, rc;
  27. unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
  28. /* Make sure the state is valid */
  29. rc = plpar_hcall(H_VASI_STATE, retbuf, stream_id);
  30. vasi_state = retbuf[0];
  31. if (rc) {
  32. pr_err("pseries_suspend_begin: vasi_state returned %ld\n",rc);
  33. return rc;
  34. } else if (vasi_state == H_VASI_ENABLED) {
  35. return -EAGAIN;
  36. } else if (vasi_state != H_VASI_SUSPENDING) {
  37. pr_err("pseries_suspend_begin: vasi_state returned state %ld\n",
  38. vasi_state);
  39. return -EIO;
  40. }
  41. return 0;
  42. }
  43. /**
  44. * pseries_suspend_enter - Final phase of hibernation
  45. *
  46. * Return value:
  47. * 0 on success / other on failure
  48. **/
  49. static int pseries_suspend_enter(suspend_state_t state)
  50. {
  51. return rtas_ibm_suspend_me(NULL);
  52. }
  53. /**
  54. * store_hibernate - Initiate partition hibernation
  55. * @dev: subsys root device
  56. * @attr: device attribute struct
  57. * @buf: buffer
  58. * @count: buffer size
  59. *
  60. * Write the stream ID received from the HMC to this file
  61. * to trigger hibernating the partition
  62. *
  63. * Return value:
  64. * number of bytes printed to buffer / other on failure
  65. **/
  66. static ssize_t store_hibernate(struct device *dev,
  67. struct device_attribute *attr,
  68. const char *buf, size_t count)
  69. {
  70. u64 stream_id;
  71. int rc;
  72. if (!capable(CAP_SYS_ADMIN))
  73. return -EPERM;
  74. stream_id = simple_strtoul(buf, NULL, 16);
  75. do {
  76. rc = pseries_suspend_begin(stream_id);
  77. if (rc == -EAGAIN)
  78. ssleep(1);
  79. } while (rc == -EAGAIN);
  80. if (!rc)
  81. rc = pm_suspend(PM_SUSPEND_MEM);
  82. if (!rc) {
  83. rc = count;
  84. post_mobility_fixup();
  85. }
  86. return rc;
  87. }
  88. #define USER_DT_UPDATE 0
  89. #define KERN_DT_UPDATE 1
  90. /**
  91. * show_hibernate - Report device tree update responsibilty
  92. * @dev: subsys root device
  93. * @attr: device attribute struct
  94. * @buf: buffer
  95. *
  96. * Report whether a device tree update is performed by the kernel after a
  97. * resume, or if drmgr must coordinate the update from user space.
  98. *
  99. * Return value:
  100. * 0 if drmgr is to initiate update, and 1 otherwise
  101. **/
  102. static ssize_t show_hibernate(struct device *dev,
  103. struct device_attribute *attr,
  104. char *buf)
  105. {
  106. return sprintf(buf, "%d\n", KERN_DT_UPDATE);
  107. }
  108. static DEVICE_ATTR(hibernate, 0644, show_hibernate, store_hibernate);
  109. static struct bus_type suspend_subsys = {
  110. .name = "power",
  111. .dev_name = "power",
  112. };
  113. static const struct platform_suspend_ops pseries_suspend_ops = {
  114. .valid = suspend_valid_only_mem,
  115. .enter = pseries_suspend_enter,
  116. };
  117. /**
  118. * pseries_suspend_sysfs_register - Register with sysfs
  119. *
  120. * Return value:
  121. * 0 on success / other on failure
  122. **/
  123. static int pseries_suspend_sysfs_register(struct device *dev)
  124. {
  125. int rc;
  126. if ((rc = subsys_system_register(&suspend_subsys, NULL)))
  127. return rc;
  128. dev->id = 0;
  129. dev->bus = &suspend_subsys;
  130. if ((rc = device_create_file(suspend_subsys.dev_root, &dev_attr_hibernate)))
  131. goto subsys_unregister;
  132. return 0;
  133. subsys_unregister:
  134. bus_unregister(&suspend_subsys);
  135. return rc;
  136. }
  137. /**
  138. * pseries_suspend_init - initcall for pSeries suspend
  139. *
  140. * Return value:
  141. * 0 on success / other on failure
  142. **/
  143. static int __init pseries_suspend_init(void)
  144. {
  145. int rc;
  146. if (!firmware_has_feature(FW_FEATURE_LPAR))
  147. return 0;
  148. if ((rc = pseries_suspend_sysfs_register(&suspend_dev)))
  149. return rc;
  150. suspend_set_ops(&pseries_suspend_ops);
  151. return 0;
  152. }
  153. machine_device_initcall(pseries, pseries_suspend_init);