1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Support for Partition Mobility/Migration
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2010 Nathan Fontenot
6*4882a593Smuzhiyun * Copyright (C) 2010 IBM Corporation
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define pr_fmt(fmt) "mobility: " fmt
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/cpu.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/kobject.h>
15*4882a593Smuzhiyun #include <linux/sched.h>
16*4882a593Smuzhiyun #include <linux/smp.h>
17*4882a593Smuzhiyun #include <linux/stat.h>
18*4882a593Smuzhiyun #include <linux/completion.h>
19*4882a593Smuzhiyun #include <linux/device.h>
20*4882a593Smuzhiyun #include <linux/delay.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun #include <linux/stringify.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include <asm/machdep.h>
25*4882a593Smuzhiyun #include <asm/rtas.h>
26*4882a593Smuzhiyun #include "pseries.h"
27*4882a593Smuzhiyun #include "../../kernel/cacheinfo.h"
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun static struct kobject *mobility_kobj;
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun struct update_props_workarea {
32*4882a593Smuzhiyun __be32 phandle;
33*4882a593Smuzhiyun __be32 state;
34*4882a593Smuzhiyun __be64 reserved;
35*4882a593Smuzhiyun __be32 nprops;
36*4882a593Smuzhiyun } __packed;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #define NODE_ACTION_MASK 0xff000000
39*4882a593Smuzhiyun #define NODE_COUNT_MASK 0x00ffffff
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define DELETE_DT_NODE 0x01000000
42*4882a593Smuzhiyun #define UPDATE_DT_NODE 0x02000000
43*4882a593Smuzhiyun #define ADD_DT_NODE 0x03000000
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define MIGRATION_SCOPE (1)
46*4882a593Smuzhiyun #define PRRN_SCOPE -2
47*4882a593Smuzhiyun
mobility_rtas_call(int token,char * buf,s32 scope)48*4882a593Smuzhiyun static int mobility_rtas_call(int token, char *buf, s32 scope)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun int rc;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun spin_lock(&rtas_data_buf_lock);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
55*4882a593Smuzhiyun rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope);
56*4882a593Smuzhiyun memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun spin_unlock(&rtas_data_buf_lock);
59*4882a593Smuzhiyun return rc;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
delete_dt_node(struct device_node * dn)62*4882a593Smuzhiyun static int delete_dt_node(struct device_node *dn)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun struct device_node *pdn;
65*4882a593Smuzhiyun bool is_platfac;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun pdn = of_get_parent(dn);
68*4882a593Smuzhiyun is_platfac = of_node_is_type(dn, "ibm,platform-facilities") ||
69*4882a593Smuzhiyun of_node_is_type(pdn, "ibm,platform-facilities");
70*4882a593Smuzhiyun of_node_put(pdn);
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /*
73*4882a593Smuzhiyun * The drivers that bind to nodes in the platform-facilities
74*4882a593Smuzhiyun * hierarchy don't support node removal, and the removal directive
75*4882a593Smuzhiyun * from firmware is always followed by an add of an equivalent
76*4882a593Smuzhiyun * node. The capability (e.g. RNG, encryption, compression)
77*4882a593Smuzhiyun * represented by the node is never interrupted by the migration.
78*4882a593Smuzhiyun * So ignore changes to this part of the tree.
79*4882a593Smuzhiyun */
80*4882a593Smuzhiyun if (is_platfac) {
81*4882a593Smuzhiyun pr_notice("ignoring remove operation for %pOFfp\n", dn);
82*4882a593Smuzhiyun return 0;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun pr_debug("removing node %pOFfp\n", dn);
86*4882a593Smuzhiyun dlpar_detach_node(dn);
87*4882a593Smuzhiyun return 0;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
update_dt_property(struct device_node * dn,struct property ** prop,const char * name,u32 vd,char * value)90*4882a593Smuzhiyun static int update_dt_property(struct device_node *dn, struct property **prop,
91*4882a593Smuzhiyun const char *name, u32 vd, char *value)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun struct property *new_prop = *prop;
94*4882a593Smuzhiyun int more = 0;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* A negative 'vd' value indicates that only part of the new property
97*4882a593Smuzhiyun * value is contained in the buffer and we need to call
98*4882a593Smuzhiyun * ibm,update-properties again to get the rest of the value.
99*4882a593Smuzhiyun *
100*4882a593Smuzhiyun * A negative value is also the two's compliment of the actual value.
101*4882a593Smuzhiyun */
102*4882a593Smuzhiyun if (vd & 0x80000000) {
103*4882a593Smuzhiyun vd = ~vd + 1;
104*4882a593Smuzhiyun more = 1;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (new_prop) {
108*4882a593Smuzhiyun /* partial property fixup */
109*4882a593Smuzhiyun char *new_data = kzalloc(new_prop->length + vd, GFP_KERNEL);
110*4882a593Smuzhiyun if (!new_data)
111*4882a593Smuzhiyun return -ENOMEM;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun memcpy(new_data, new_prop->value, new_prop->length);
114*4882a593Smuzhiyun memcpy(new_data + new_prop->length, value, vd);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun kfree(new_prop->value);
117*4882a593Smuzhiyun new_prop->value = new_data;
118*4882a593Smuzhiyun new_prop->length += vd;
119*4882a593Smuzhiyun } else {
120*4882a593Smuzhiyun new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
121*4882a593Smuzhiyun if (!new_prop)
122*4882a593Smuzhiyun return -ENOMEM;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun new_prop->name = kstrdup(name, GFP_KERNEL);
125*4882a593Smuzhiyun if (!new_prop->name) {
126*4882a593Smuzhiyun kfree(new_prop);
127*4882a593Smuzhiyun return -ENOMEM;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun new_prop->length = vd;
131*4882a593Smuzhiyun new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
132*4882a593Smuzhiyun if (!new_prop->value) {
133*4882a593Smuzhiyun kfree(new_prop->name);
134*4882a593Smuzhiyun kfree(new_prop);
135*4882a593Smuzhiyun return -ENOMEM;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun memcpy(new_prop->value, value, vd);
139*4882a593Smuzhiyun *prop = new_prop;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun if (!more) {
143*4882a593Smuzhiyun pr_debug("updating node %pOF property %s\n", dn, name);
144*4882a593Smuzhiyun of_update_property(dn, new_prop);
145*4882a593Smuzhiyun *prop = NULL;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
update_dt_node(struct device_node * dn,s32 scope)151*4882a593Smuzhiyun static int update_dt_node(struct device_node *dn, s32 scope)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun struct update_props_workarea *upwa;
154*4882a593Smuzhiyun struct property *prop = NULL;
155*4882a593Smuzhiyun int i, rc, rtas_rc;
156*4882a593Smuzhiyun char *prop_data;
157*4882a593Smuzhiyun char *rtas_buf;
158*4882a593Smuzhiyun int update_properties_token;
159*4882a593Smuzhiyun u32 nprops;
160*4882a593Smuzhiyun u32 vd;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun update_properties_token = rtas_token("ibm,update-properties");
163*4882a593Smuzhiyun if (update_properties_token == RTAS_UNKNOWN_SERVICE)
164*4882a593Smuzhiyun return -EINVAL;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
167*4882a593Smuzhiyun if (!rtas_buf)
168*4882a593Smuzhiyun return -ENOMEM;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun upwa = (struct update_props_workarea *)&rtas_buf[0];
171*4882a593Smuzhiyun upwa->phandle = cpu_to_be32(dn->phandle);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun do {
174*4882a593Smuzhiyun rtas_rc = mobility_rtas_call(update_properties_token, rtas_buf,
175*4882a593Smuzhiyun scope);
176*4882a593Smuzhiyun if (rtas_rc < 0)
177*4882a593Smuzhiyun break;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun prop_data = rtas_buf + sizeof(*upwa);
180*4882a593Smuzhiyun nprops = be32_to_cpu(upwa->nprops);
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* On the first call to ibm,update-properties for a node the
183*4882a593Smuzhiyun * the first property value descriptor contains an empty
184*4882a593Smuzhiyun * property name, the property value length encoded as u32,
185*4882a593Smuzhiyun * and the property value is the node path being updated.
186*4882a593Smuzhiyun */
187*4882a593Smuzhiyun if (*prop_data == 0) {
188*4882a593Smuzhiyun prop_data++;
189*4882a593Smuzhiyun vd = be32_to_cpu(*(__be32 *)prop_data);
190*4882a593Smuzhiyun prop_data += vd + sizeof(vd);
191*4882a593Smuzhiyun nprops--;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun for (i = 0; i < nprops; i++) {
195*4882a593Smuzhiyun char *prop_name;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun prop_name = prop_data;
198*4882a593Smuzhiyun prop_data += strlen(prop_name) + 1;
199*4882a593Smuzhiyun vd = be32_to_cpu(*(__be32 *)prop_data);
200*4882a593Smuzhiyun prop_data += sizeof(vd);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun switch (vd) {
203*4882a593Smuzhiyun case 0x00000000:
204*4882a593Smuzhiyun /* name only property, nothing to do */
205*4882a593Smuzhiyun break;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun case 0x80000000:
208*4882a593Smuzhiyun of_remove_property(dn, of_find_property(dn,
209*4882a593Smuzhiyun prop_name, NULL));
210*4882a593Smuzhiyun prop = NULL;
211*4882a593Smuzhiyun break;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun default:
214*4882a593Smuzhiyun rc = update_dt_property(dn, &prop, prop_name,
215*4882a593Smuzhiyun vd, prop_data);
216*4882a593Smuzhiyun if (rc) {
217*4882a593Smuzhiyun printk(KERN_ERR "Could not update %s"
218*4882a593Smuzhiyun " property\n", prop_name);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun prop_data += vd;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun cond_resched();
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun cond_resched();
228*4882a593Smuzhiyun } while (rtas_rc == 1);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun kfree(rtas_buf);
231*4882a593Smuzhiyun return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
add_dt_node(struct device_node * parent_dn,__be32 drc_index)234*4882a593Smuzhiyun static int add_dt_node(struct device_node *parent_dn, __be32 drc_index)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct device_node *dn;
237*4882a593Smuzhiyun int rc;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun dn = dlpar_configure_connector(drc_index, parent_dn);
240*4882a593Smuzhiyun if (!dn)
241*4882a593Smuzhiyun return -ENOENT;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /*
244*4882a593Smuzhiyun * Since delete_dt_node() ignores this node type, this is the
245*4882a593Smuzhiyun * necessary counterpart. We also know that a platform-facilities
246*4882a593Smuzhiyun * node returned from dlpar_configure_connector() has children
247*4882a593Smuzhiyun * attached, and dlpar_attach_node() only adds the parent, leaking
248*4882a593Smuzhiyun * the children. So ignore these on the add side for now.
249*4882a593Smuzhiyun */
250*4882a593Smuzhiyun if (of_node_is_type(dn, "ibm,platform-facilities")) {
251*4882a593Smuzhiyun pr_notice("ignoring add operation for %pOF\n", dn);
252*4882a593Smuzhiyun dlpar_free_cc_nodes(dn);
253*4882a593Smuzhiyun return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun rc = dlpar_attach_node(dn, parent_dn);
257*4882a593Smuzhiyun if (rc)
258*4882a593Smuzhiyun dlpar_free_cc_nodes(dn);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun pr_debug("added node %pOFfp\n", dn);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun return rc;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
pseries_devicetree_update(s32 scope)265*4882a593Smuzhiyun int pseries_devicetree_update(s32 scope)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun char *rtas_buf;
268*4882a593Smuzhiyun __be32 *data;
269*4882a593Smuzhiyun int update_nodes_token;
270*4882a593Smuzhiyun int rc;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun update_nodes_token = rtas_token("ibm,update-nodes");
273*4882a593Smuzhiyun if (update_nodes_token == RTAS_UNKNOWN_SERVICE)
274*4882a593Smuzhiyun return -EINVAL;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
277*4882a593Smuzhiyun if (!rtas_buf)
278*4882a593Smuzhiyun return -ENOMEM;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun do {
281*4882a593Smuzhiyun rc = mobility_rtas_call(update_nodes_token, rtas_buf, scope);
282*4882a593Smuzhiyun if (rc && rc != 1)
283*4882a593Smuzhiyun break;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun data = (__be32 *)rtas_buf + 4;
286*4882a593Smuzhiyun while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
287*4882a593Smuzhiyun int i;
288*4882a593Smuzhiyun u32 action = be32_to_cpu(*data) & NODE_ACTION_MASK;
289*4882a593Smuzhiyun u32 node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun data++;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun for (i = 0; i < node_count; i++) {
294*4882a593Smuzhiyun struct device_node *np;
295*4882a593Smuzhiyun __be32 phandle = *data++;
296*4882a593Smuzhiyun __be32 drc_index;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun np = of_find_node_by_phandle(be32_to_cpu(phandle));
299*4882a593Smuzhiyun if (!np) {
300*4882a593Smuzhiyun pr_warn("Failed lookup: phandle 0x%x for action 0x%x\n",
301*4882a593Smuzhiyun be32_to_cpu(phandle), action);
302*4882a593Smuzhiyun continue;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun switch (action) {
306*4882a593Smuzhiyun case DELETE_DT_NODE:
307*4882a593Smuzhiyun delete_dt_node(np);
308*4882a593Smuzhiyun break;
309*4882a593Smuzhiyun case UPDATE_DT_NODE:
310*4882a593Smuzhiyun update_dt_node(np, scope);
311*4882a593Smuzhiyun break;
312*4882a593Smuzhiyun case ADD_DT_NODE:
313*4882a593Smuzhiyun drc_index = *data++;
314*4882a593Smuzhiyun add_dt_node(np, drc_index);
315*4882a593Smuzhiyun break;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun of_node_put(np);
319*4882a593Smuzhiyun cond_resched();
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun cond_resched();
324*4882a593Smuzhiyun } while (rc == 1);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun kfree(rtas_buf);
327*4882a593Smuzhiyun return rc;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
post_mobility_fixup(void)330*4882a593Smuzhiyun void post_mobility_fixup(void)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun int rc;
333*4882a593Smuzhiyun int activate_fw_token;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun activate_fw_token = rtas_token("ibm,activate-firmware");
336*4882a593Smuzhiyun if (activate_fw_token == RTAS_UNKNOWN_SERVICE) {
337*4882a593Smuzhiyun printk(KERN_ERR "Could not make post-mobility "
338*4882a593Smuzhiyun "activate-fw call.\n");
339*4882a593Smuzhiyun return;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun do {
343*4882a593Smuzhiyun rc = rtas_call(activate_fw_token, 0, 1, NULL);
344*4882a593Smuzhiyun } while (rtas_busy_delay(rc));
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun if (rc)
347*4882a593Smuzhiyun printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc);
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /*
350*4882a593Smuzhiyun * We don't want CPUs to go online/offline while the device
351*4882a593Smuzhiyun * tree is being updated.
352*4882a593Smuzhiyun */
353*4882a593Smuzhiyun cpus_read_lock();
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /*
356*4882a593Smuzhiyun * It's common for the destination firmware to replace cache
357*4882a593Smuzhiyun * nodes. Release all of the cacheinfo hierarchy's references
358*4882a593Smuzhiyun * before updating the device tree.
359*4882a593Smuzhiyun */
360*4882a593Smuzhiyun cacheinfo_teardown();
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun rc = pseries_devicetree_update(MIGRATION_SCOPE);
363*4882a593Smuzhiyun if (rc)
364*4882a593Smuzhiyun printk(KERN_ERR "Post-mobility device tree update "
365*4882a593Smuzhiyun "failed: %d\n", rc);
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun cacheinfo_rebuild();
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun cpus_read_unlock();
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun /* Possibly switch to a new L1 flush type */
372*4882a593Smuzhiyun pseries_setup_security_mitigations();
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun /* Reinitialise system information for hv-24x7 */
375*4882a593Smuzhiyun read_24x7_sys_info();
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun return;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
migration_store(struct class * class,struct class_attribute * attr,const char * buf,size_t count)380*4882a593Smuzhiyun static ssize_t migration_store(struct class *class,
381*4882a593Smuzhiyun struct class_attribute *attr, const char *buf,
382*4882a593Smuzhiyun size_t count)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun u64 streamid;
385*4882a593Smuzhiyun int rc;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun rc = kstrtou64(buf, 0, &streamid);
388*4882a593Smuzhiyun if (rc)
389*4882a593Smuzhiyun return rc;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun do {
392*4882a593Smuzhiyun rc = rtas_ibm_suspend_me(streamid);
393*4882a593Smuzhiyun if (rc == -EAGAIN)
394*4882a593Smuzhiyun ssleep(1);
395*4882a593Smuzhiyun } while (rc == -EAGAIN);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun if (rc)
398*4882a593Smuzhiyun return rc;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun post_mobility_fixup();
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun return count;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun /*
406*4882a593Smuzhiyun * Used by drmgr to determine the kernel behavior of the migration interface.
407*4882a593Smuzhiyun *
408*4882a593Smuzhiyun * Version 1: Performs all PAPR requirements for migration including
409*4882a593Smuzhiyun * firmware activation and device tree update.
410*4882a593Smuzhiyun */
411*4882a593Smuzhiyun #define MIGRATION_API_VERSION 1
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun static CLASS_ATTR_WO(migration);
414*4882a593Smuzhiyun static CLASS_ATTR_STRING(api_version, 0444, __stringify(MIGRATION_API_VERSION));
415*4882a593Smuzhiyun
mobility_sysfs_init(void)416*4882a593Smuzhiyun static int __init mobility_sysfs_init(void)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun int rc;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun mobility_kobj = kobject_create_and_add("mobility", kernel_kobj);
421*4882a593Smuzhiyun if (!mobility_kobj)
422*4882a593Smuzhiyun return -ENOMEM;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun rc = sysfs_create_file(mobility_kobj, &class_attr_migration.attr);
425*4882a593Smuzhiyun if (rc)
426*4882a593Smuzhiyun pr_err("unable to create migration sysfs file (%d)\n", rc);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun rc = sysfs_create_file(mobility_kobj, &class_attr_api_version.attr.attr);
429*4882a593Smuzhiyun if (rc)
430*4882a593Smuzhiyun pr_err("unable to create api_version sysfs file (%d)\n", rc);
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun return 0;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun machine_device_initcall(pseries, mobility_sysfs_init);
435