1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3   * Copyright (C) 2010 Brian King IBM Corporation
4   */
5 
6 #include <linux/cpu.h>
7 #include <linux/delay.h>
8 #include <linux/suspend.h>
9 #include <linux/stat.h>
10 #include <asm/firmware.h>
11 #include <asm/hvcall.h>
12 #include <asm/machdep.h>
13 #include <asm/mmu.h>
14 #include <asm/rtas.h>
15 #include <asm/topology.h>
16 #include "../../kernel/cacheinfo.h"
17 
18 static u64 stream_id;
19 static struct device suspend_dev;
20 static DECLARE_COMPLETION(suspend_work);
21 static struct rtas_suspend_me_data suspend_data;
22 static atomic_t suspending;
23 
24 /**
25  * pseries_suspend_begin - First phase of hibernation
26  *
27  * Check to ensure we are in a valid state to hibernate
28  *
29  * Return value:
30  * 	0 on success / other on failure
31  **/
32 static int pseries_suspend_begin(suspend_state_t state)
33 {
34 	long vasi_state, rc;
35 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
36 
37 	/* Make sure the state is valid */
38 	rc = plpar_hcall(H_VASI_STATE, retbuf, stream_id);
39 
40 	vasi_state = retbuf[0];
41 
42 	if (rc) {
43 		pr_err("pseries_suspend_begin: vasi_state returned %ld\n",rc);
44 		return rc;
45 	} else if (vasi_state == H_VASI_ENABLED) {
46 		return -EAGAIN;
47 	} else if (vasi_state != H_VASI_SUSPENDING) {
48 		pr_err("pseries_suspend_begin: vasi_state returned state %ld\n",
49 		       vasi_state);
50 		return -EIO;
51 	}
52 
53 	return 0;
54 }
55 
56 /**
57  * pseries_suspend_cpu - Suspend a single CPU
58  *
59  * Makes the H_JOIN call to suspend the CPU
60  *
61  **/
62 static int pseries_suspend_cpu(void)
63 {
64 	if (atomic_read(&suspending))
65 		return rtas_suspend_cpu(&suspend_data);
66 	return 0;
67 }
68 
69 /**
70  * pseries_suspend_enable_irqs
71  *
72  * Post suspend configuration updates
73  *
74  **/
75 static void pseries_suspend_enable_irqs(void)
76 {
77 	/*
78 	 * Update configuration which can be modified based on device tree
79 	 * changes during resume.
80 	 */
81 	cacheinfo_cpu_offline(smp_processor_id());
82 	post_mobility_fixup();
83 	cacheinfo_cpu_online(smp_processor_id());
84 }
85 
86 /**
87  * pseries_suspend_enter - Final phase of hibernation
88  *
89  * Return value:
90  * 	0 on success / other on failure
91  **/
92 static int pseries_suspend_enter(suspend_state_t state)
93 {
94 	int rc = rtas_suspend_last_cpu(&suspend_data);
95 
96 	atomic_set(&suspending, 0);
97 	atomic_set(&suspend_data.done, 1);
98 	return rc;
99 }
100 
101 /**
102  * pseries_prepare_late - Prepare to suspend all other CPUs
103  *
104  * Return value:
105  * 	0 on success / other on failure
106  **/
107 static int pseries_prepare_late(void)
108 {
109 	atomic_set(&suspending, 1);
110 	atomic_set(&suspend_data.working, 0);
111 	atomic_set(&suspend_data.done, 0);
112 	atomic_set(&suspend_data.error, 0);
113 	suspend_data.complete = &suspend_work;
114 	reinit_completion(&suspend_work);
115 	return 0;
116 }
117 
118 /**
119  * store_hibernate - Initiate partition hibernation
120  * @dev:		subsys root device
121  * @attr:		device attribute struct
122  * @buf:		buffer
123  * @count:		buffer size
124  *
125  * Write the stream ID received from the HMC to this file
126  * to trigger hibernating the partition
127  *
128  * Return value:
129  * 	number of bytes printed to buffer / other on failure
130  **/
131 static ssize_t store_hibernate(struct device *dev,
132 			       struct device_attribute *attr,
133 			       const char *buf, size_t count)
134 {
135 	cpumask_var_t offline_mask;
136 	int rc;
137 
138 	if (!capable(CAP_SYS_ADMIN))
139 		return -EPERM;
140 
141 	if (!alloc_cpumask_var(&offline_mask, GFP_KERNEL))
142 		return -ENOMEM;
143 
144 	stream_id = simple_strtoul(buf, NULL, 16);
145 
146 	do {
147 		rc = pseries_suspend_begin(PM_SUSPEND_MEM);
148 		if (rc == -EAGAIN)
149 			ssleep(1);
150 	} while (rc == -EAGAIN);
151 
152 	if (!rc) {
153 		/* All present CPUs must be online */
154 		cpumask_andnot(offline_mask, cpu_present_mask,
155 				cpu_online_mask);
156 		rc = rtas_online_cpus_mask(offline_mask);
157 		if (rc) {
158 			pr_err("%s: Could not bring present CPUs online.\n",
159 					__func__);
160 			goto out;
161 		}
162 
163 		stop_topology_update();
164 		rc = pm_suspend(PM_SUSPEND_MEM);
165 		start_topology_update();
166 
167 		/* Take down CPUs not online prior to suspend */
168 		if (!rtas_offline_cpus_mask(offline_mask))
169 			pr_warn("%s: Could not restore CPUs to offline "
170 					"state.\n", __func__);
171 	}
172 
173 	stream_id = 0;
174 
175 	if (!rc)
176 		rc = count;
177 out:
178 	free_cpumask_var(offline_mask);
179 	return rc;
180 }
181 
182 #define USER_DT_UPDATE	0
183 #define KERN_DT_UPDATE	1
184 
185 /**
186  * show_hibernate - Report device tree update responsibilty
187  * @dev:		subsys root device
188  * @attr:		device attribute struct
189  * @buf:		buffer
190  *
191  * Report whether a device tree update is performed by the kernel after a
192  * resume, or if drmgr must coordinate the update from user space.
193  *
194  * Return value:
195  *	0 if drmgr is to initiate update, and 1 otherwise
196  **/
197 static ssize_t show_hibernate(struct device *dev,
198 			      struct device_attribute *attr,
199 			      char *buf)
200 {
201 	return sprintf(buf, "%d\n", KERN_DT_UPDATE);
202 }
203 
204 static DEVICE_ATTR(hibernate, 0644, show_hibernate, store_hibernate);
205 
206 static struct bus_type suspend_subsys = {
207 	.name = "power",
208 	.dev_name = "power",
209 };
210 
211 static const struct platform_suspend_ops pseries_suspend_ops = {
212 	.valid		= suspend_valid_only_mem,
213 	.begin		= pseries_suspend_begin,
214 	.prepare_late	= pseries_prepare_late,
215 	.enter		= pseries_suspend_enter,
216 };
217 
218 /**
219  * pseries_suspend_sysfs_register - Register with sysfs
220  *
221  * Return value:
222  * 	0 on success / other on failure
223  **/
224 static int pseries_suspend_sysfs_register(struct device *dev)
225 {
226 	int rc;
227 
228 	if ((rc = subsys_system_register(&suspend_subsys, NULL)))
229 		return rc;
230 
231 	dev->id = 0;
232 	dev->bus = &suspend_subsys;
233 
234 	if ((rc = device_create_file(suspend_subsys.dev_root, &dev_attr_hibernate)))
235 		goto subsys_unregister;
236 
237 	return 0;
238 
239 subsys_unregister:
240 	bus_unregister(&suspend_subsys);
241 	return rc;
242 }
243 
244 /**
245  * pseries_suspend_init - initcall for pSeries suspend
246  *
247  * Return value:
248  * 	0 on success / other on failure
249  **/
250 static int __init pseries_suspend_init(void)
251 {
252 	int rc;
253 
254 	if (!firmware_has_feature(FW_FEATURE_LPAR))
255 		return 0;
256 
257 	suspend_data.token = rtas_token("ibm,suspend-me");
258 	if (suspend_data.token == RTAS_UNKNOWN_SERVICE)
259 		return 0;
260 
261 	if ((rc = pseries_suspend_sysfs_register(&suspend_dev)))
262 		return rc;
263 
264 	ppc_md.suspend_disable_cpu = pseries_suspend_cpu;
265 	ppc_md.suspend_enable_irqs = pseries_suspend_enable_irqs;
266 	suspend_set_ops(&pseries_suspend_ops);
267 	return 0;
268 }
269 machine_device_initcall(pseries, pseries_suspend_init);
270