.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Support for Partition Mobility/Migration |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2010 Nathan Fontenot |
---|
5 | 6 | * 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 | 7 | */ |
---|
| 8 | + |
---|
| 9 | + |
---|
| 10 | +#define pr_fmt(fmt) "mobility: " fmt |
---|
11 | 11 | |
---|
12 | 12 | #include <linux/cpu.h> |
---|
13 | 13 | #include <linux/kernel.h> |
---|
.. | .. |
---|
59 | 59 | return rc; |
---|
60 | 60 | } |
---|
61 | 61 | |
---|
62 | | -static int delete_dt_node(__be32 phandle) |
---|
| 62 | +static int delete_dt_node(struct device_node *dn) |
---|
63 | 63 | { |
---|
64 | | - struct device_node *dn; |
---|
| 64 | + struct device_node *pdn; |
---|
| 65 | + bool is_platfac; |
---|
65 | 66 | |
---|
66 | | - dn = of_find_node_by_phandle(be32_to_cpu(phandle)); |
---|
67 | | - if (!dn) |
---|
68 | | - return -ENOENT; |
---|
| 67 | + pdn = of_get_parent(dn); |
---|
| 68 | + is_platfac = of_node_is_type(dn, "ibm,platform-facilities") || |
---|
| 69 | + of_node_is_type(pdn, "ibm,platform-facilities"); |
---|
| 70 | + of_node_put(pdn); |
---|
69 | 71 | |
---|
| 72 | + /* |
---|
| 73 | + * The drivers that bind to nodes in the platform-facilities |
---|
| 74 | + * hierarchy don't support node removal, and the removal directive |
---|
| 75 | + * from firmware is always followed by an add of an equivalent |
---|
| 76 | + * node. The capability (e.g. RNG, encryption, compression) |
---|
| 77 | + * represented by the node is never interrupted by the migration. |
---|
| 78 | + * So ignore changes to this part of the tree. |
---|
| 79 | + */ |
---|
| 80 | + if (is_platfac) { |
---|
| 81 | + pr_notice("ignoring remove operation for %pOFfp\n", dn); |
---|
| 82 | + return 0; |
---|
| 83 | + } |
---|
| 84 | + |
---|
| 85 | + pr_debug("removing node %pOFfp\n", dn); |
---|
70 | 86 | dlpar_detach_node(dn); |
---|
71 | | - of_node_put(dn); |
---|
72 | 87 | return 0; |
---|
73 | 88 | } |
---|
74 | 89 | |
---|
.. | .. |
---|
125 | 140 | } |
---|
126 | 141 | |
---|
127 | 142 | if (!more) { |
---|
| 143 | + pr_debug("updating node %pOF property %s\n", dn, name); |
---|
128 | 144 | of_update_property(dn, new_prop); |
---|
129 | 145 | *prop = NULL; |
---|
130 | 146 | } |
---|
.. | .. |
---|
132 | 148 | return 0; |
---|
133 | 149 | } |
---|
134 | 150 | |
---|
135 | | -static int update_dt_node(__be32 phandle, s32 scope) |
---|
| 151 | +static int update_dt_node(struct device_node *dn, s32 scope) |
---|
136 | 152 | { |
---|
137 | 153 | struct update_props_workarea *upwa; |
---|
138 | | - struct device_node *dn; |
---|
139 | 154 | struct property *prop = NULL; |
---|
140 | 155 | int i, rc, rtas_rc; |
---|
141 | 156 | char *prop_data; |
---|
.. | .. |
---|
152 | 167 | if (!rtas_buf) |
---|
153 | 168 | return -ENOMEM; |
---|
154 | 169 | |
---|
155 | | - dn = of_find_node_by_phandle(be32_to_cpu(phandle)); |
---|
156 | | - if (!dn) { |
---|
157 | | - kfree(rtas_buf); |
---|
158 | | - return -ENOENT; |
---|
159 | | - } |
---|
160 | | - |
---|
161 | 170 | upwa = (struct update_props_workarea *)&rtas_buf[0]; |
---|
162 | | - upwa->phandle = phandle; |
---|
| 171 | + upwa->phandle = cpu_to_be32(dn->phandle); |
---|
163 | 172 | |
---|
164 | 173 | do { |
---|
165 | 174 | rtas_rc = mobility_rtas_call(update_properties_token, rtas_buf, |
---|
.. | .. |
---|
218 | 227 | cond_resched(); |
---|
219 | 228 | } while (rtas_rc == 1); |
---|
220 | 229 | |
---|
221 | | - of_node_put(dn); |
---|
222 | 230 | kfree(rtas_buf); |
---|
223 | 231 | return 0; |
---|
224 | 232 | } |
---|
225 | 233 | |
---|
226 | | -static int add_dt_node(__be32 parent_phandle, __be32 drc_index) |
---|
| 234 | +static int add_dt_node(struct device_node *parent_dn, __be32 drc_index) |
---|
227 | 235 | { |
---|
228 | 236 | struct device_node *dn; |
---|
229 | | - struct device_node *parent_dn; |
---|
230 | 237 | int rc; |
---|
231 | 238 | |
---|
232 | | - parent_dn = of_find_node_by_phandle(be32_to_cpu(parent_phandle)); |
---|
233 | | - if (!parent_dn) |
---|
| 239 | + dn = dlpar_configure_connector(drc_index, parent_dn); |
---|
| 240 | + if (!dn) |
---|
234 | 241 | return -ENOENT; |
---|
235 | 242 | |
---|
236 | | - dn = dlpar_configure_connector(drc_index, parent_dn); |
---|
237 | | - if (!dn) { |
---|
238 | | - of_node_put(parent_dn); |
---|
239 | | - return -ENOENT; |
---|
| 243 | + /* |
---|
| 244 | + * Since delete_dt_node() ignores this node type, this is the |
---|
| 245 | + * necessary counterpart. We also know that a platform-facilities |
---|
| 246 | + * node returned from dlpar_configure_connector() has children |
---|
| 247 | + * attached, and dlpar_attach_node() only adds the parent, leaking |
---|
| 248 | + * the children. So ignore these on the add side for now. |
---|
| 249 | + */ |
---|
| 250 | + if (of_node_is_type(dn, "ibm,platform-facilities")) { |
---|
| 251 | + pr_notice("ignoring add operation for %pOF\n", dn); |
---|
| 252 | + dlpar_free_cc_nodes(dn); |
---|
| 253 | + return 0; |
---|
240 | 254 | } |
---|
241 | 255 | |
---|
242 | 256 | rc = dlpar_attach_node(dn, parent_dn); |
---|
243 | 257 | if (rc) |
---|
244 | 258 | dlpar_free_cc_nodes(dn); |
---|
245 | 259 | |
---|
246 | | - of_node_put(parent_dn); |
---|
| 260 | + pr_debug("added node %pOFfp\n", dn); |
---|
| 261 | + |
---|
247 | 262 | return rc; |
---|
248 | | -} |
---|
249 | | - |
---|
250 | | -static void prrn_update_node(__be32 phandle) |
---|
251 | | -{ |
---|
252 | | - struct pseries_hp_errorlog *hp_elog; |
---|
253 | | - struct device_node *dn; |
---|
254 | | - |
---|
255 | | - /* |
---|
256 | | - * If a node is found from a the given phandle, the phandle does not |
---|
257 | | - * represent the drc index of an LMB and we can ignore. |
---|
258 | | - */ |
---|
259 | | - dn = of_find_node_by_phandle(be32_to_cpu(phandle)); |
---|
260 | | - if (dn) { |
---|
261 | | - of_node_put(dn); |
---|
262 | | - return; |
---|
263 | | - } |
---|
264 | | - |
---|
265 | | - hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL); |
---|
266 | | - if(!hp_elog) |
---|
267 | | - return; |
---|
268 | | - |
---|
269 | | - hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM; |
---|
270 | | - hp_elog->action = PSERIES_HP_ELOG_ACTION_READD; |
---|
271 | | - hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX; |
---|
272 | | - hp_elog->_drc_u.drc_index = phandle; |
---|
273 | | - |
---|
274 | | - queue_hotplug_event(hp_elog, NULL, NULL); |
---|
275 | | - |
---|
276 | | - kfree(hp_elog); |
---|
277 | 263 | } |
---|
278 | 264 | |
---|
279 | 265 | int pseries_devicetree_update(s32 scope) |
---|
.. | .. |
---|
305 | 291 | data++; |
---|
306 | 292 | |
---|
307 | 293 | for (i = 0; i < node_count; i++) { |
---|
| 294 | + struct device_node *np; |
---|
308 | 295 | __be32 phandle = *data++; |
---|
309 | 296 | __be32 drc_index; |
---|
310 | 297 | |
---|
| 298 | + np = of_find_node_by_phandle(be32_to_cpu(phandle)); |
---|
| 299 | + if (!np) { |
---|
| 300 | + pr_warn("Failed lookup: phandle 0x%x for action 0x%x\n", |
---|
| 301 | + be32_to_cpu(phandle), action); |
---|
| 302 | + continue; |
---|
| 303 | + } |
---|
| 304 | + |
---|
311 | 305 | switch (action) { |
---|
312 | 306 | case DELETE_DT_NODE: |
---|
313 | | - delete_dt_node(phandle); |
---|
| 307 | + delete_dt_node(np); |
---|
314 | 308 | break; |
---|
315 | 309 | case UPDATE_DT_NODE: |
---|
316 | | - update_dt_node(phandle, scope); |
---|
317 | | - |
---|
318 | | - if (scope == PRRN_SCOPE) |
---|
319 | | - prrn_update_node(phandle); |
---|
320 | | - |
---|
| 310 | + update_dt_node(np, scope); |
---|
321 | 311 | break; |
---|
322 | 312 | case ADD_DT_NODE: |
---|
323 | 313 | drc_index = *data++; |
---|
324 | | - add_dt_node(phandle, drc_index); |
---|
| 314 | + add_dt_node(np, drc_index); |
---|
325 | 315 | break; |
---|
326 | 316 | } |
---|
327 | 317 | |
---|
| 318 | + of_node_put(np); |
---|
328 | 319 | cond_resched(); |
---|
329 | 320 | } |
---|
330 | 321 | } |
---|
.. | .. |
---|
377 | 368 | |
---|
378 | 369 | cpus_read_unlock(); |
---|
379 | 370 | |
---|
380 | | - /* Possibly switch to a new RFI flush type */ |
---|
381 | | - pseries_setup_rfi_flush(); |
---|
| 371 | + /* Possibly switch to a new L1 flush type */ |
---|
| 372 | + pseries_setup_security_mitigations(); |
---|
| 373 | + |
---|
| 374 | + /* Reinitialise system information for hv-24x7 */ |
---|
| 375 | + read_24x7_sys_info(); |
---|
382 | 376 | |
---|
383 | 377 | return; |
---|
384 | 378 | } |
---|
.. | .. |
---|
404 | 398 | return rc; |
---|
405 | 399 | |
---|
406 | 400 | post_mobility_fixup(); |
---|
| 401 | + |
---|
407 | 402 | return count; |
---|
408 | 403 | } |
---|
409 | 404 | |
---|
.. | .. |
---|
428 | 423 | |
---|
429 | 424 | rc = sysfs_create_file(mobility_kobj, &class_attr_migration.attr); |
---|
430 | 425 | if (rc) |
---|
431 | | - pr_err("mobility: unable to create migration sysfs file (%d)\n", rc); |
---|
| 426 | + pr_err("unable to create migration sysfs file (%d)\n", rc); |
---|
432 | 427 | |
---|
433 | 428 | rc = sysfs_create_file(mobility_kobj, &class_attr_api_version.attr.attr); |
---|
434 | 429 | if (rc) |
---|
435 | | - pr_err("mobility: unable to create api_version sysfs file (%d)\n", rc); |
---|
| 430 | + pr_err("unable to create api_version sysfs file (%d)\n", rc); |
---|
436 | 431 | |
---|
437 | 432 | return 0; |
---|
438 | 433 | } |
---|