xref: /linux/arch/powerpc/platforms/pseries/dlpar.c (revision ea8b474b5550d353a02f25a5813cb1682509d5e6)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Support for dynamic reconfiguration for PCI, Memory, and CPU
4  * Hotplug and Dynamic Logical Partitioning on RPA platforms.
5  *
6  * Copyright (C) 2009 Nathan Fontenot
7  * Copyright (C) 2009 IBM Corporation
8  */
9 
10 #define pr_fmt(fmt)	"dlpar: " fmt
11 
12 #include <linux/kernel.h>
13 #include <linux/notifier.h>
14 #include <linux/spinlock.h>
15 #include <linux/cpu.h>
16 #include <linux/slab.h>
17 #include <linux/sysfs.h>
18 #include <linux/of.h>
19 
20 #include "of_helpers.h"
21 #include "pseries.h"
22 
23 #include <asm/machdep.h>
24 #include <linux/uaccess.h>
25 #include <asm/rtas.h>
26 #include <asm/rtas-work-area.h>
27 #include <asm/prom.h>
28 
29 static struct workqueue_struct *pseries_hp_wq;
30 
31 struct pseries_hp_work {
32 	struct work_struct work;
33 	struct pseries_hp_errorlog *errlog;
34 };
35 
36 struct cc_workarea {
37 	__be32	drc_index;
38 	__be32	zero;
39 	__be32	name_offset;
40 	__be32	prop_length;
41 	__be32	prop_offset;
42 };
43 
44 void dlpar_free_cc_property(struct property *prop)
45 {
46 	kfree(prop->name);
47 	kfree(prop->value);
48 	kfree(prop);
49 }
50 
51 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
52 {
53 	struct property *prop;
54 	char *name;
55 	char *value;
56 
57 	prop = kzalloc_obj(*prop);
58 	if (!prop)
59 		return NULL;
60 
61 	name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
62 	prop->name = kstrdup(name, GFP_KERNEL);
63 	if (!prop->name) {
64 		dlpar_free_cc_property(prop);
65 		return NULL;
66 	}
67 
68 	prop->length = be32_to_cpu(ccwa->prop_length);
69 	value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset);
70 	prop->value = kmemdup(value, prop->length, GFP_KERNEL);
71 	if (!prop->value) {
72 		dlpar_free_cc_property(prop);
73 		return NULL;
74 	}
75 
76 	return prop;
77 }
78 
79 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa)
80 {
81 	struct device_node *dn;
82 	const char *name;
83 
84 	dn = kzalloc_obj(*dn);
85 	if (!dn)
86 		return NULL;
87 
88 	name = (const char *)ccwa + be32_to_cpu(ccwa->name_offset);
89 	dn->full_name = kstrdup(name, GFP_KERNEL);
90 	if (!dn->full_name) {
91 		kfree(dn);
92 		return NULL;
93 	}
94 
95 	of_node_set_flag(dn, OF_DYNAMIC);
96 	of_node_init(dn);
97 
98 	return dn;
99 }
100 
101 static void dlpar_free_one_cc_node(struct device_node *dn)
102 {
103 	struct property *prop;
104 
105 	while (dn->properties) {
106 		prop = dn->properties;
107 		dn->properties = prop->next;
108 		dlpar_free_cc_property(prop);
109 	}
110 
111 	kfree(dn->full_name);
112 	kfree(dn);
113 }
114 
115 void dlpar_free_cc_nodes(struct device_node *dn)
116 {
117 	if (dn->child)
118 		dlpar_free_cc_nodes(dn->child);
119 
120 	if (dn->sibling)
121 		dlpar_free_cc_nodes(dn->sibling);
122 
123 	dlpar_free_one_cc_node(dn);
124 }
125 
126 #define COMPLETE	0
127 #define NEXT_SIBLING    1
128 #define NEXT_CHILD      2
129 #define NEXT_PROPERTY   3
130 #define PREV_PARENT     4
131 #define MORE_MEMORY     5
132 #define ERR_CFG_USE     -9003
133 
134 struct device_node *dlpar_configure_connector(__be32 drc_index,
135 					      struct device_node *parent)
136 {
137 	struct device_node *dn;
138 	struct device_node *first_dn = NULL;
139 	struct device_node *last_dn = NULL;
140 	struct property *property;
141 	struct property *last_property = NULL;
142 	struct cc_workarea *ccwa;
143 	struct rtas_work_area *work_area;
144 	char *data_buf;
145 	int cc_token;
146 	int rc = -1;
147 
148 	cc_token = rtas_function_token(RTAS_FN_IBM_CONFIGURE_CONNECTOR);
149 	if (cc_token == RTAS_UNKNOWN_SERVICE)
150 		return NULL;
151 
152 	work_area = rtas_work_area_alloc(SZ_4K);
153 	data_buf = rtas_work_area_raw_buf(work_area);
154 
155 	ccwa = (struct cc_workarea *)&data_buf[0];
156 	ccwa->drc_index = drc_index;
157 	ccwa->zero = 0;
158 
159 	do {
160 		do {
161 			rc = rtas_call(cc_token, 2, 1, NULL,
162 				       rtas_work_area_phys(work_area), NULL);
163 		} while (rtas_busy_delay(rc));
164 
165 		switch (rc) {
166 		case COMPLETE:
167 			break;
168 
169 		case NEXT_SIBLING:
170 			dn = dlpar_parse_cc_node(ccwa);
171 			if (!dn)
172 				goto cc_error;
173 
174 			dn->parent = last_dn->parent;
175 			last_dn->sibling = dn;
176 			last_dn = dn;
177 			break;
178 
179 		case NEXT_CHILD:
180 			dn = dlpar_parse_cc_node(ccwa);
181 			if (!dn)
182 				goto cc_error;
183 
184 			if (!first_dn) {
185 				dn->parent = parent;
186 				first_dn = dn;
187 			} else {
188 				dn->parent = last_dn;
189 				if (last_dn)
190 					last_dn->child = dn;
191 			}
192 
193 			last_dn = dn;
194 			break;
195 
196 		case NEXT_PROPERTY:
197 			property = dlpar_parse_cc_property(ccwa);
198 			if (!property)
199 				goto cc_error;
200 
201 			if (!last_dn->properties)
202 				last_dn->properties = property;
203 			else
204 				last_property->next = property;
205 
206 			last_property = property;
207 			break;
208 
209 		case PREV_PARENT:
210 			last_dn = last_dn->parent;
211 			break;
212 
213 		case MORE_MEMORY:
214 		case ERR_CFG_USE:
215 		default:
216 			printk(KERN_ERR "Unexpected Error (%d) "
217 			       "returned from configure-connector\n", rc);
218 			goto cc_error;
219 		}
220 	} while (rc);
221 
222 cc_error:
223 	rtas_work_area_free(work_area);
224 
225 	if (rc) {
226 		if (first_dn)
227 			dlpar_free_cc_nodes(first_dn);
228 
229 		return NULL;
230 	}
231 
232 	return first_dn;
233 }
234 
235 int dlpar_attach_node(struct device_node *dn, struct device_node *parent)
236 {
237 	int rc;
238 
239 	dn->parent = parent;
240 
241 	rc = of_attach_node(dn);
242 	if (rc) {
243 		printk(KERN_ERR "Failed to add device node %pOF\n", dn);
244 		return rc;
245 	}
246 
247 	return 0;
248 }
249 
250 int dlpar_detach_node(struct device_node *dn)
251 {
252 	struct device_node *child;
253 	int rc;
254 
255 	for_each_child_of_node(dn, child)
256 		dlpar_detach_node(child);
257 
258 	rc = of_detach_node(dn);
259 	if (rc)
260 		return rc;
261 
262 	of_node_put(dn);
263 
264 	return 0;
265 }
266 static int dlpar_changeset_attach_cc_nodes(struct of_changeset *ocs,
267 					struct device_node *dn)
268 {
269 	int rc;
270 
271 	rc = of_changeset_attach_node(ocs, dn);
272 
273 	if (!rc && dn->child)
274 		rc = dlpar_changeset_attach_cc_nodes(ocs, dn->child);
275 	if (!rc && dn->sibling)
276 		rc = dlpar_changeset_attach_cc_nodes(ocs, dn->sibling);
277 
278 	return rc;
279 }
280 
281 #define DR_ENTITY_SENSE		9003
282 #define DR_ENTITY_PRESENT	1
283 #define DR_ENTITY_UNUSABLE	2
284 #define ALLOCATION_STATE	9003
285 #define ALLOC_UNUSABLE		0
286 #define ALLOC_USABLE		1
287 #define ISOLATION_STATE		9001
288 #define ISOLATE			0
289 #define UNISOLATE		1
290 
291 int dlpar_acquire_drc(u32 drc_index)
292 {
293 	int dr_status, rc;
294 
295 	rc = rtas_get_sensor(DR_ENTITY_SENSE, drc_index, &dr_status);
296 	if (rc || dr_status != DR_ENTITY_UNUSABLE)
297 		return -1;
298 
299 	rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE);
300 	if (rc)
301 		return rc;
302 
303 	rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
304 	if (rc) {
305 		rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
306 		return rc;
307 	}
308 
309 	return 0;
310 }
311 
312 int dlpar_release_drc(u32 drc_index)
313 {
314 	int dr_status, rc;
315 
316 	rc = rtas_get_sensor(DR_ENTITY_SENSE, drc_index, &dr_status);
317 	if (rc || dr_status != DR_ENTITY_PRESENT)
318 		return -1;
319 
320 	rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE);
321 	if (rc)
322 		return rc;
323 
324 	rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
325 	if (rc) {
326 		rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
327 		return rc;
328 	}
329 
330 	return 0;
331 }
332 
333 int dlpar_unisolate_drc(u32 drc_index)
334 {
335 	int dr_status, rc;
336 
337 	rc = rtas_get_sensor(DR_ENTITY_SENSE, drc_index, &dr_status);
338 	if (rc || dr_status != DR_ENTITY_PRESENT)
339 		return -1;
340 
341 	rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
342 
343 	return 0;
344 }
345 
346 static struct device_node *
347 get_device_node_with_drc_index(u32 index)
348 {
349 	struct device_node *np = NULL;
350 	u32 node_index;
351 	int rc;
352 
353 	for_each_node_with_property(np, "ibm,my-drc-index") {
354 		rc = of_property_read_u32(np, "ibm,my-drc-index",
355 					     &node_index);
356 		if (rc) {
357 			pr_err("%s: %pOF: of_property_read_u32 %s: %d\n",
358 			       __func__, np, "ibm,my-drc-index", rc);
359 			of_node_put(np);
360 			return NULL;
361 		}
362 
363 		if (index == node_index)
364 			break;
365 	}
366 
367 	return np;
368 }
369 
370 static struct device_node *
371 get_device_node_with_drc_info(u32 index)
372 {
373 	struct device_node *np = NULL;
374 	struct of_drc_info drc;
375 	struct property *info;
376 	const __be32 *value;
377 	u32 node_index;
378 	int i, j, count;
379 
380 	for_each_node_with_property(np, "ibm,drc-info") {
381 		info = of_find_property(np, "ibm,drc-info", NULL);
382 		if (info == NULL) {
383 			/* XXX can this happen? */
384 			of_node_put(np);
385 			return NULL;
386 		}
387 		value = of_prop_next_u32(info, NULL, &count);
388 		if (value == NULL)
389 			continue;
390 		value++;
391 		for (i = 0; i < count; i++) {
392 			if (of_read_drc_info_cell(&info, &value, &drc))
393 				break;
394 			if (index > drc.last_drc_index)
395 				continue;
396 			node_index = drc.drc_index_start;
397 			for (j = 0; j < drc.num_sequential_elems; j++) {
398 				if (index == node_index)
399 					return np;
400 				node_index += drc.sequential_inc;
401 			}
402 		}
403 	}
404 
405 	return NULL;
406 }
407 
408 static struct device_node *
409 get_device_node_with_drc_indexes(u32 drc_index)
410 {
411 	struct device_node *np = NULL;
412 	u32 nr_indexes, index;
413 	int i, rc;
414 
415 	for_each_node_with_property(np, "ibm,drc-indexes") {
416 		/*
417 		 * First element in the array is the total number of
418 		 * DRC indexes returned.
419 		 */
420 		rc = of_property_read_u32_index(np, "ibm,drc-indexes",
421 				0, &nr_indexes);
422 		if (rc)
423 			goto out_put_np;
424 
425 		/*
426 		 * Retrieve DRC index from the list and return the
427 		 * device node if matched with the specified index.
428 		 */
429 		for (i = 0; i < nr_indexes; i++) {
430 			rc = of_property_read_u32_index(np, "ibm,drc-indexes",
431 							i+1, &index);
432 			if (rc)
433 				goto out_put_np;
434 
435 			if (drc_index == index)
436 				return np;
437 		}
438 	}
439 
440 	return NULL;
441 
442 out_put_np:
443 	of_node_put(np);
444 	return NULL;
445 }
446 
447 static int dlpar_hp_dt_add(u32 index)
448 {
449 	struct device_node *np, *nodes;
450 	struct of_changeset ocs;
451 	int rc;
452 
453 	/*
454 	 * Do not add device node(s) if already exists in the
455 	 * device tree.
456 	 */
457 	np = get_device_node_with_drc_index(index);
458 	if (np) {
459 		pr_err("%s: Adding device node for index (%d), but "
460 				"already exists in the device tree\n",
461 				__func__, index);
462 		rc = -EINVAL;
463 		goto out;
464 	}
465 
466 	/*
467 	 * Recent FW provides ibm,drc-info property. So search
468 	 * for the user specified DRC index from ibm,drc-info
469 	 * property. If this property is not available, search
470 	 * in the indexes array from ibm,drc-indexes property.
471 	 */
472 	np = get_device_node_with_drc_info(index);
473 
474 	if (!np) {
475 		np = get_device_node_with_drc_indexes(index);
476 		if (!np)
477 			return -EIO;
478 	}
479 
480 	/* Next, configure the connector. */
481 	nodes = dlpar_configure_connector(cpu_to_be32(index), np);
482 	if (!nodes) {
483 		rc = -EIO;
484 		goto out;
485 	}
486 
487 	/*
488 	 * Add the new nodes from dlpar_configure_connector() onto
489 	 * the device-tree.
490 	 */
491 	of_changeset_init(&ocs);
492 	rc = dlpar_changeset_attach_cc_nodes(&ocs, nodes);
493 
494 	if (!rc)
495 		rc = of_changeset_apply(&ocs);
496 	else
497 		dlpar_free_cc_nodes(nodes);
498 
499 	of_changeset_destroy(&ocs);
500 
501 out:
502 	of_node_put(np);
503 	return rc;
504 }
505 
506 static int changeset_detach_node_recursive(struct of_changeset *ocs,
507 					struct device_node *node)
508 {
509 	struct device_node *child;
510 	int rc;
511 
512 	for_each_child_of_node(node, child) {
513 		rc = changeset_detach_node_recursive(ocs, child);
514 		if (rc) {
515 			of_node_put(child);
516 			return rc;
517 		}
518 	}
519 
520 	return of_changeset_detach_node(ocs, node);
521 }
522 
523 static int dlpar_hp_dt_remove(u32 drc_index)
524 {
525 	struct device_node *np;
526 	struct of_changeset ocs;
527 	u32 index;
528 	int rc = 0;
529 
530 	/*
531 	 * Prune all nodes with a matching index.
532 	 */
533 	of_changeset_init(&ocs);
534 
535 	for_each_node_with_property(np, "ibm,my-drc-index") {
536 		rc = of_property_read_u32(np, "ibm,my-drc-index", &index);
537 		if (rc) {
538 			pr_err("%s: %pOF: of_property_read_u32 %s: %d\n",
539 				__func__, np, "ibm,my-drc-index", rc);
540 			of_node_put(np);
541 			goto out;
542 		}
543 
544 		if (index == drc_index) {
545 			rc = changeset_detach_node_recursive(&ocs, np);
546 			if (rc) {
547 				of_node_put(np);
548 				goto out;
549 			}
550 		}
551 	}
552 
553 	rc = of_changeset_apply(&ocs);
554 
555 out:
556 	of_changeset_destroy(&ocs);
557 	return rc;
558 }
559 
560 static int dlpar_hp_dt(struct pseries_hp_errorlog *phpe)
561 {
562 	u32 drc_index;
563 	int rc;
564 
565 	if (phpe->id_type != PSERIES_HP_ELOG_ID_DRC_INDEX)
566 		return -EINVAL;
567 
568 	drc_index = be32_to_cpu(phpe->_drc_u.drc_index);
569 
570 	lock_device_hotplug();
571 
572 	switch (phpe->action) {
573 	case PSERIES_HP_ELOG_ACTION_ADD:
574 		rc = dlpar_hp_dt_add(drc_index);
575 		break;
576 	case PSERIES_HP_ELOG_ACTION_REMOVE:
577 		rc = dlpar_hp_dt_remove(drc_index);
578 		break;
579 	default:
580 		pr_err("Invalid action (%d) specified\n", phpe->action);
581 		rc = -EINVAL;
582 		break;
583 	}
584 
585 	unlock_device_hotplug();
586 
587 	return rc;
588 }
589 
590 int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
591 {
592 	int rc;
593 
594 	switch (hp_elog->resource) {
595 	case PSERIES_HP_ELOG_RESOURCE_MEM:
596 		rc = dlpar_memory(hp_elog);
597 		break;
598 	case PSERIES_HP_ELOG_RESOURCE_CPU:
599 		rc = dlpar_cpu(hp_elog);
600 		break;
601 	case PSERIES_HP_ELOG_RESOURCE_PMEM:
602 		rc = dlpar_hp_pmem(hp_elog);
603 		break;
604 	case PSERIES_HP_ELOG_RESOURCE_DT:
605 		rc = dlpar_hp_dt(hp_elog);
606 		break;
607 
608 	default:
609 		pr_warn_ratelimited("Invalid resource (%d) specified\n",
610 				    hp_elog->resource);
611 		rc = -EINVAL;
612 	}
613 
614 	return rc;
615 }
616 
617 static void pseries_hp_work_fn(struct work_struct *work)
618 {
619 	struct pseries_hp_work *hp_work =
620 			container_of(work, struct pseries_hp_work, work);
621 
622 	handle_dlpar_errorlog(hp_work->errlog);
623 
624 	kfree(hp_work->errlog);
625 	kfree(work);
626 }
627 
628 void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog)
629 {
630 	struct pseries_hp_work *work;
631 	struct pseries_hp_errorlog *hp_errlog_copy;
632 
633 	hp_errlog_copy = kmemdup(hp_errlog, sizeof(*hp_errlog), GFP_ATOMIC);
634 	if (!hp_errlog_copy)
635 		return;
636 
637 	work = kmalloc_obj(struct pseries_hp_work, GFP_ATOMIC);
638 	if (work) {
639 		INIT_WORK((struct work_struct *)work, pseries_hp_work_fn);
640 		work->errlog = hp_errlog_copy;
641 		queue_work(pseries_hp_wq, (struct work_struct *)work);
642 	} else {
643 		kfree(hp_errlog_copy);
644 	}
645 }
646 
647 static int dlpar_parse_resource(char **cmd, struct pseries_hp_errorlog *hp_elog)
648 {
649 	char *arg;
650 
651 	arg = strsep(cmd, " ");
652 	if (!arg)
653 		return -EINVAL;
654 
655 	if (sysfs_streq(arg, "memory")) {
656 		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
657 	} else if (sysfs_streq(arg, "cpu")) {
658 		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU;
659 	} else if (sysfs_streq(arg, "dt")) {
660 		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_DT;
661 	} else {
662 		pr_err("Invalid resource specified.\n");
663 		return -EINVAL;
664 	}
665 
666 	return 0;
667 }
668 
669 static int dlpar_parse_action(char **cmd, struct pseries_hp_errorlog *hp_elog)
670 {
671 	char *arg;
672 
673 	arg = strsep(cmd, " ");
674 	if (!arg)
675 		return -EINVAL;
676 
677 	if (sysfs_streq(arg, "add")) {
678 		hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD;
679 	} else if (sysfs_streq(arg, "remove")) {
680 		hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE;
681 	} else {
682 		pr_err("Invalid action specified.\n");
683 		return -EINVAL;
684 	}
685 
686 	return 0;
687 }
688 
689 static int dlpar_parse_id_type(char **cmd, struct pseries_hp_errorlog *hp_elog)
690 {
691 	char *arg;
692 	u32 count, index;
693 
694 	arg = strsep(cmd, " ");
695 	if (!arg)
696 		return -EINVAL;
697 
698 	if (sysfs_streq(arg, "indexed-count")) {
699 		hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_IC;
700 		arg = strsep(cmd, " ");
701 		if (!arg) {
702 			pr_err("No DRC count specified.\n");
703 			return -EINVAL;
704 		}
705 
706 		if (kstrtou32(arg, 0, &count)) {
707 			pr_err("Invalid DRC count specified.\n");
708 			return -EINVAL;
709 		}
710 
711 		arg = strsep(cmd, " ");
712 		if (!arg) {
713 			pr_err("No DRC Index specified.\n");
714 			return -EINVAL;
715 		}
716 
717 		if (kstrtou32(arg, 0, &index)) {
718 			pr_err("Invalid DRC Index specified.\n");
719 			return -EINVAL;
720 		}
721 
722 		hp_elog->_drc_u.ic.count = cpu_to_be32(count);
723 		hp_elog->_drc_u.ic.index = cpu_to_be32(index);
724 	} else if (sysfs_streq(arg, "index")) {
725 		hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX;
726 		arg = strsep(cmd, " ");
727 		if (!arg) {
728 			pr_err("No DRC Index specified.\n");
729 			return -EINVAL;
730 		}
731 
732 		if (kstrtou32(arg, 0, &index)) {
733 			pr_err("Invalid DRC Index specified.\n");
734 			return -EINVAL;
735 		}
736 
737 		hp_elog->_drc_u.drc_index = cpu_to_be32(index);
738 	} else if (sysfs_streq(arg, "count")) {
739 		hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT;
740 		arg = strsep(cmd, " ");
741 		if (!arg) {
742 			pr_err("No DRC count specified.\n");
743 			return -EINVAL;
744 		}
745 
746 		if (kstrtou32(arg, 0, &count)) {
747 			pr_err("Invalid DRC count specified.\n");
748 			return -EINVAL;
749 		}
750 
751 		hp_elog->_drc_u.drc_count = cpu_to_be32(count);
752 	} else {
753 		pr_err("Invalid id_type specified.\n");
754 		return -EINVAL;
755 	}
756 
757 	return 0;
758 }
759 
760 static ssize_t dlpar_store(const struct class *class, const struct class_attribute *attr,
761 			   const char *buf, size_t count)
762 {
763 	struct pseries_hp_errorlog hp_elog;
764 	char *argbuf;
765 	char *args;
766 	int rc;
767 
768 	args = argbuf = kstrdup(buf, GFP_KERNEL);
769 	if (!argbuf)
770 		return -ENOMEM;
771 
772 	/*
773 	 * Parse out the request from the user, this will be in the form:
774 	 * <resource> <action> <id_type> <id>
775 	 */
776 	rc = dlpar_parse_resource(&args, &hp_elog);
777 	if (rc)
778 		goto dlpar_store_out;
779 
780 	rc = dlpar_parse_action(&args, &hp_elog);
781 	if (rc)
782 		goto dlpar_store_out;
783 
784 	rc = dlpar_parse_id_type(&args, &hp_elog);
785 	if (rc)
786 		goto dlpar_store_out;
787 
788 	rc = handle_dlpar_errorlog(&hp_elog);
789 
790 dlpar_store_out:
791 	kfree(argbuf);
792 
793 	if (rc)
794 		pr_err("Could not handle DLPAR request \"%s\"\n", buf);
795 
796 	return rc ? rc : count;
797 }
798 
799 static ssize_t dlpar_show(const struct class *class, const struct class_attribute *attr,
800 			  char *buf)
801 {
802 	return sysfs_emit(buf, "%s\n", "memory,cpu,dt");
803 }
804 
805 static CLASS_ATTR_RW(dlpar);
806 
807 int __init dlpar_workqueue_init(void)
808 {
809 	if (pseries_hp_wq)
810 		return 0;
811 
812 	pseries_hp_wq = alloc_ordered_workqueue("pseries hotplug workqueue", 0);
813 
814 	return pseries_hp_wq ? 0 : -ENOMEM;
815 }
816 
817 static int __init dlpar_sysfs_init(void)
818 {
819 	int rc;
820 
821 	rc = dlpar_workqueue_init();
822 	if (rc)
823 		return rc;
824 
825 	return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
826 }
827 machine_device_initcall(pseries, dlpar_sysfs_init);
828 
829