1 /* 2 * Support for Partition Mobility/Migration 3 * 4 * Copyright (C) 2010 Nathan Fontenot 5 * Copyright (C) 2010 IBM Corporation 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License version 9 * 2 as published by the Free Software Foundation. 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/kobject.h> 14 #include <linux/smp.h> 15 #include <linux/stat.h> 16 #include <linux/completion.h> 17 #include <linux/device.h> 18 #include <linux/delay.h> 19 #include <linux/slab.h> 20 21 #include <asm/rtas.h> 22 #include "pseries.h" 23 24 static struct kobject *mobility_kobj; 25 26 struct update_props_workarea { 27 u32 phandle; 28 u32 state; 29 u64 reserved; 30 u32 nprops; 31 } __packed; 32 33 #define NODE_ACTION_MASK 0xff000000 34 #define NODE_COUNT_MASK 0x00ffffff 35 36 #define DELETE_DT_NODE 0x01000000 37 #define UPDATE_DT_NODE 0x02000000 38 #define ADD_DT_NODE 0x03000000 39 40 #define MIGRATION_SCOPE (1) 41 42 static int mobility_rtas_call(int token, char *buf, s32 scope) 43 { 44 int rc; 45 46 spin_lock(&rtas_data_buf_lock); 47 48 memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE); 49 rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope); 50 memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); 51 52 spin_unlock(&rtas_data_buf_lock); 53 return rc; 54 } 55 56 static int delete_dt_node(u32 phandle) 57 { 58 struct device_node *dn; 59 60 dn = of_find_node_by_phandle(phandle); 61 if (!dn) 62 return -ENOENT; 63 64 dlpar_detach_node(dn); 65 of_node_put(dn); 66 return 0; 67 } 68 69 static int update_dt_property(struct device_node *dn, struct property **prop, 70 const char *name, u32 vd, char *value) 71 { 72 struct property *new_prop = *prop; 73 int more = 0; 74 75 /* A negative 'vd' value indicates that only part of the new property 76 * value is contained in the buffer and we need to call 77 * ibm,update-properties again to get the rest of the value. 78 * 79 * A negative value is also the two's compliment of the actual value. 80 */ 81 if (vd & 0x80000000) { 82 vd = ~vd + 1; 83 more = 1; 84 } 85 86 if (new_prop) { 87 /* partial property fixup */ 88 char *new_data = kzalloc(new_prop->length + vd, GFP_KERNEL); 89 if (!new_data) 90 return -ENOMEM; 91 92 memcpy(new_data, new_prop->value, new_prop->length); 93 memcpy(new_data + new_prop->length, value, vd); 94 95 kfree(new_prop->value); 96 new_prop->value = new_data; 97 new_prop->length += vd; 98 } else { 99 new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); 100 if (!new_prop) 101 return -ENOMEM; 102 103 new_prop->name = kstrdup(name, GFP_KERNEL); 104 if (!new_prop->name) { 105 kfree(new_prop); 106 return -ENOMEM; 107 } 108 109 new_prop->length = vd; 110 new_prop->value = kzalloc(new_prop->length, GFP_KERNEL); 111 if (!new_prop->value) { 112 kfree(new_prop->name); 113 kfree(new_prop); 114 return -ENOMEM; 115 } 116 117 memcpy(new_prop->value, value, vd); 118 *prop = new_prop; 119 } 120 121 if (!more) { 122 of_update_property(dn, new_prop); 123 *prop = NULL; 124 } 125 126 return 0; 127 } 128 129 static int update_dt_node(u32 phandle, s32 scope) 130 { 131 struct update_props_workarea *upwa; 132 struct device_node *dn; 133 struct property *prop = NULL; 134 int i, rc, rtas_rc; 135 char *prop_data; 136 char *rtas_buf; 137 int update_properties_token; 138 u32 vd; 139 140 update_properties_token = rtas_token("ibm,update-properties"); 141 if (update_properties_token == RTAS_UNKNOWN_SERVICE) 142 return -EINVAL; 143 144 rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); 145 if (!rtas_buf) 146 return -ENOMEM; 147 148 dn = of_find_node_by_phandle(phandle); 149 if (!dn) { 150 kfree(rtas_buf); 151 return -ENOENT; 152 } 153 154 upwa = (struct update_props_workarea *)&rtas_buf[0]; 155 upwa->phandle = phandle; 156 157 do { 158 rtas_rc = mobility_rtas_call(update_properties_token, rtas_buf, 159 scope); 160 if (rtas_rc < 0) 161 break; 162 163 prop_data = rtas_buf + sizeof(*upwa); 164 165 /* On the first call to ibm,update-properties for a node the 166 * the first property value descriptor contains an empty 167 * property name, the property value length encoded as u32, 168 * and the property value is the node path being updated. 169 */ 170 if (*prop_data == 0) { 171 prop_data++; 172 vd = *(u32 *)prop_data; 173 prop_data += vd + sizeof(vd); 174 upwa->nprops--; 175 } 176 177 for (i = 0; i < upwa->nprops; i++) { 178 char *prop_name; 179 180 prop_name = prop_data; 181 prop_data += strlen(prop_name) + 1; 182 vd = *(u32 *)prop_data; 183 prop_data += sizeof(vd); 184 185 switch (vd) { 186 case 0x00000000: 187 /* name only property, nothing to do */ 188 break; 189 190 case 0x80000000: 191 prop = of_find_property(dn, prop_name, NULL); 192 of_remove_property(dn, prop); 193 prop = NULL; 194 break; 195 196 default: 197 rc = update_dt_property(dn, &prop, prop_name, 198 vd, prop_data); 199 if (rc) { 200 printk(KERN_ERR "Could not update %s" 201 " property\n", prop_name); 202 } 203 204 prop_data += vd; 205 } 206 } 207 } while (rtas_rc == 1); 208 209 of_node_put(dn); 210 kfree(rtas_buf); 211 return 0; 212 } 213 214 static int add_dt_node(u32 parent_phandle, u32 drc_index) 215 { 216 struct device_node *dn; 217 struct device_node *parent_dn; 218 int rc; 219 220 parent_dn = of_find_node_by_phandle(parent_phandle); 221 if (!parent_dn) 222 return -ENOENT; 223 224 dn = dlpar_configure_connector(drc_index, parent_dn); 225 if (!dn) 226 return -ENOENT; 227 228 rc = dlpar_attach_node(dn); 229 if (rc) 230 dlpar_free_cc_nodes(dn); 231 232 of_node_put(parent_dn); 233 return rc; 234 } 235 236 int pseries_devicetree_update(s32 scope) 237 { 238 char *rtas_buf; 239 u32 *data; 240 int update_nodes_token; 241 int rc; 242 243 update_nodes_token = rtas_token("ibm,update-nodes"); 244 if (update_nodes_token == RTAS_UNKNOWN_SERVICE) 245 return -EINVAL; 246 247 rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); 248 if (!rtas_buf) 249 return -ENOMEM; 250 251 do { 252 rc = mobility_rtas_call(update_nodes_token, rtas_buf, scope); 253 if (rc && rc != 1) 254 break; 255 256 data = (u32 *)rtas_buf + 4; 257 while (*data & NODE_ACTION_MASK) { 258 int i; 259 u32 action = *data & NODE_ACTION_MASK; 260 int node_count = *data & NODE_COUNT_MASK; 261 262 data++; 263 264 for (i = 0; i < node_count; i++) { 265 u32 phandle = *data++; 266 u32 drc_index; 267 268 switch (action) { 269 case DELETE_DT_NODE: 270 delete_dt_node(phandle); 271 break; 272 case UPDATE_DT_NODE: 273 update_dt_node(phandle, scope); 274 break; 275 case ADD_DT_NODE: 276 drc_index = *data++; 277 add_dt_node(phandle, drc_index); 278 break; 279 } 280 } 281 } 282 } while (rc == 1); 283 284 kfree(rtas_buf); 285 return rc; 286 } 287 288 void post_mobility_fixup(void) 289 { 290 int rc; 291 int activate_fw_token; 292 293 activate_fw_token = rtas_token("ibm,activate-firmware"); 294 if (activate_fw_token == RTAS_UNKNOWN_SERVICE) { 295 printk(KERN_ERR "Could not make post-mobility " 296 "activate-fw call.\n"); 297 return; 298 } 299 300 do { 301 rc = rtas_call(activate_fw_token, 0, 1, NULL); 302 } while (rtas_busy_delay(rc)); 303 304 if (rc) 305 printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc); 306 307 rc = pseries_devicetree_update(MIGRATION_SCOPE); 308 if (rc) 309 printk(KERN_ERR "Post-mobility device tree update " 310 "failed: %d\n", rc); 311 312 return; 313 } 314 315 static ssize_t migrate_store(struct class *class, struct class_attribute *attr, 316 const char *buf, size_t count) 317 { 318 struct rtas_args args; 319 u64 streamid; 320 int rc; 321 322 rc = strict_strtoull(buf, 0, &streamid); 323 if (rc) 324 return rc; 325 326 memset(&args, 0, sizeof(args)); 327 args.token = rtas_token("ibm,suspend-me"); 328 args.nargs = 2; 329 args.nret = 1; 330 331 args.args[0] = streamid >> 32 ; 332 args.args[1] = streamid & 0xffffffff; 333 args.rets = &args.args[args.nargs]; 334 335 do { 336 args.rets[0] = 0; 337 rc = rtas_ibm_suspend_me(&args); 338 if (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE) 339 ssleep(1); 340 } while (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE); 341 342 if (rc) 343 return rc; 344 else if (args.rets[0]) 345 return args.rets[0]; 346 347 post_mobility_fixup(); 348 return count; 349 } 350 351 static CLASS_ATTR(migration, S_IWUSR, NULL, migrate_store); 352 353 static int __init mobility_sysfs_init(void) 354 { 355 int rc; 356 357 mobility_kobj = kobject_create_and_add("mobility", kernel_kobj); 358 if (!mobility_kobj) 359 return -ENOMEM; 360 361 rc = sysfs_create_file(mobility_kobj, &class_attr_migration.attr); 362 363 return rc; 364 } 365 device_initcall(mobility_sysfs_init); 366