xref: /linux/arch/powerpc/platforms/pseries/dlpar.c (revision 8d0f1e05ab16c4bd628ddaefd20b94ffb36d799c)
1 /*
2  * Support for dynamic reconfiguration for PCI, Memory, and CPU
3  * Hotplug and Dynamic Logical Partitioning on RPA platforms.
4  *
5  * Copyright (C) 2009 Nathan Fontenot
6  * Copyright (C) 2009 IBM Corporation
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version
10  * 2 as published by the Free Software Foundation.
11  */
12 
13 #define pr_fmt(fmt)	"dlpar: " fmt
14 
15 #include <linux/kernel.h>
16 #include <linux/notifier.h>
17 #include <linux/spinlock.h>
18 #include <linux/cpu.h>
19 #include <linux/slab.h>
20 #include <linux/of.h>
21 
22 #include "of_helpers.h"
23 #include "pseries.h"
24 
25 #include <asm/prom.h>
26 #include <asm/machdep.h>
27 #include <linux/uaccess.h>
28 #include <asm/rtas.h>
29 
30 static struct workqueue_struct *pseries_hp_wq;
31 
32 struct pseries_hp_work {
33 	struct work_struct work;
34 	struct pseries_hp_errorlog *errlog;
35 };
36 
37 struct cc_workarea {
38 	__be32	drc_index;
39 	__be32	zero;
40 	__be32	name_offset;
41 	__be32	prop_length;
42 	__be32	prop_offset;
43 };
44 
45 void dlpar_free_cc_property(struct property *prop)
46 {
47 	kfree(prop->name);
48 	kfree(prop->value);
49 	kfree(prop);
50 }
51 
52 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
53 {
54 	struct property *prop;
55 	char *name;
56 	char *value;
57 
58 	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
59 	if (!prop)
60 		return NULL;
61 
62 	name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
63 	prop->name = kstrdup(name, GFP_KERNEL);
64 	if (!prop->name) {
65 		dlpar_free_cc_property(prop);
66 		return NULL;
67 	}
68 
69 	prop->length = be32_to_cpu(ccwa->prop_length);
70 	value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset);
71 	prop->value = kmemdup(value, prop->length, GFP_KERNEL);
72 	if (!prop->value) {
73 		dlpar_free_cc_property(prop);
74 		return NULL;
75 	}
76 
77 	return prop;
78 }
79 
80 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa)
81 {
82 	struct device_node *dn;
83 	const char *name;
84 
85 	dn = kzalloc(sizeof(*dn), GFP_KERNEL);
86 	if (!dn)
87 		return NULL;
88 
89 	name = (const char *)ccwa + be32_to_cpu(ccwa->name_offset);
90 	dn->full_name = kstrdup(name, GFP_KERNEL);
91 	if (!dn->full_name) {
92 		kfree(dn);
93 		return NULL;
94 	}
95 
96 	of_node_set_flag(dn, OF_DYNAMIC);
97 	of_node_init(dn);
98 
99 	return dn;
100 }
101 
102 static void dlpar_free_one_cc_node(struct device_node *dn)
103 {
104 	struct property *prop;
105 
106 	while (dn->properties) {
107 		prop = dn->properties;
108 		dn->properties = prop->next;
109 		dlpar_free_cc_property(prop);
110 	}
111 
112 	kfree(dn->full_name);
113 	kfree(dn);
114 }
115 
116 void dlpar_free_cc_nodes(struct device_node *dn)
117 {
118 	if (dn->child)
119 		dlpar_free_cc_nodes(dn->child);
120 
121 	if (dn->sibling)
122 		dlpar_free_cc_nodes(dn->sibling);
123 
124 	dlpar_free_one_cc_node(dn);
125 }
126 
127 #define COMPLETE	0
128 #define NEXT_SIBLING    1
129 #define NEXT_CHILD      2
130 #define NEXT_PROPERTY   3
131 #define PREV_PARENT     4
132 #define MORE_MEMORY     5
133 #define CALL_AGAIN	-2
134 #define ERR_CFG_USE     -9003
135 
136 struct device_node *dlpar_configure_connector(__be32 drc_index,
137 					      struct device_node *parent)
138 {
139 	struct device_node *dn;
140 	struct device_node *first_dn = NULL;
141 	struct device_node *last_dn = NULL;
142 	struct property *property;
143 	struct property *last_property = NULL;
144 	struct cc_workarea *ccwa;
145 	char *data_buf;
146 	int cc_token;
147 	int rc = -1;
148 
149 	cc_token = rtas_token("ibm,configure-connector");
150 	if (cc_token == RTAS_UNKNOWN_SERVICE)
151 		return NULL;
152 
153 	data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
154 	if (!data_buf)
155 		return NULL;
156 
157 	ccwa = (struct cc_workarea *)&data_buf[0];
158 	ccwa->drc_index = drc_index;
159 	ccwa->zero = 0;
160 
161 	do {
162 		/* Since we release the rtas_data_buf lock between configure
163 		 * connector calls we want to re-populate the rtas_data_buffer
164 		 * with the contents of the previous call.
165 		 */
166 		spin_lock(&rtas_data_buf_lock);
167 
168 		memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE);
169 		rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL);
170 		memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
171 
172 		spin_unlock(&rtas_data_buf_lock);
173 
174 		switch (rc) {
175 		case COMPLETE:
176 			break;
177 
178 		case NEXT_SIBLING:
179 			dn = dlpar_parse_cc_node(ccwa);
180 			if (!dn)
181 				goto cc_error;
182 
183 			dn->parent = last_dn->parent;
184 			last_dn->sibling = dn;
185 			last_dn = dn;
186 			break;
187 
188 		case NEXT_CHILD:
189 			dn = dlpar_parse_cc_node(ccwa);
190 			if (!dn)
191 				goto cc_error;
192 
193 			if (!first_dn) {
194 				dn->parent = parent;
195 				first_dn = dn;
196 			} else {
197 				dn->parent = last_dn;
198 				if (last_dn)
199 					last_dn->child = dn;
200 			}
201 
202 			last_dn = dn;
203 			break;
204 
205 		case NEXT_PROPERTY:
206 			property = dlpar_parse_cc_property(ccwa);
207 			if (!property)
208 				goto cc_error;
209 
210 			if (!last_dn->properties)
211 				last_dn->properties = property;
212 			else
213 				last_property->next = property;
214 
215 			last_property = property;
216 			break;
217 
218 		case PREV_PARENT:
219 			last_dn = last_dn->parent;
220 			break;
221 
222 		case CALL_AGAIN:
223 			break;
224 
225 		case MORE_MEMORY:
226 		case ERR_CFG_USE:
227 		default:
228 			printk(KERN_ERR "Unexpected Error (%d) "
229 			       "returned from configure-connector\n", rc);
230 			goto cc_error;
231 		}
232 	} while (rc);
233 
234 cc_error:
235 	kfree(data_buf);
236 
237 	if (rc) {
238 		if (first_dn)
239 			dlpar_free_cc_nodes(first_dn);
240 
241 		return NULL;
242 	}
243 
244 	return first_dn;
245 }
246 
247 int dlpar_attach_node(struct device_node *dn, struct device_node *parent)
248 {
249 	int rc;
250 
251 	dn->parent = parent;
252 
253 	rc = of_attach_node(dn);
254 	if (rc) {
255 		printk(KERN_ERR "Failed to add device node %pOF\n", dn);
256 		return rc;
257 	}
258 
259 	return 0;
260 }
261 
262 int dlpar_detach_node(struct device_node *dn)
263 {
264 	struct device_node *child;
265 	int rc;
266 
267 	child = of_get_next_child(dn, NULL);
268 	while (child) {
269 		dlpar_detach_node(child);
270 		child = of_get_next_child(dn, child);
271 	}
272 
273 	rc = of_detach_node(dn);
274 	if (rc)
275 		return rc;
276 
277 	of_node_put(dn);
278 
279 	return 0;
280 }
281 
282 #define DR_ENTITY_SENSE		9003
283 #define DR_ENTITY_PRESENT	1
284 #define DR_ENTITY_UNUSABLE	2
285 #define ALLOCATION_STATE	9003
286 #define ALLOC_UNUSABLE		0
287 #define ALLOC_USABLE		1
288 #define ISOLATION_STATE		9001
289 #define ISOLATE			0
290 #define UNISOLATE		1
291 
292 int dlpar_acquire_drc(u32 drc_index)
293 {
294 	int dr_status, rc;
295 
296 	rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
297 		       DR_ENTITY_SENSE, drc_index);
298 	if (rc || dr_status != DR_ENTITY_UNUSABLE)
299 		return -1;
300 
301 	rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE);
302 	if (rc)
303 		return rc;
304 
305 	rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
306 	if (rc) {
307 		rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
308 		return rc;
309 	}
310 
311 	return 0;
312 }
313 
314 int dlpar_release_drc(u32 drc_index)
315 {
316 	int dr_status, rc;
317 
318 	rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
319 		       DR_ENTITY_SENSE, drc_index);
320 	if (rc || dr_status != DR_ENTITY_PRESENT)
321 		return -1;
322 
323 	rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE);
324 	if (rc)
325 		return rc;
326 
327 	rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
328 	if (rc) {
329 		rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
330 		return rc;
331 	}
332 
333 	return 0;
334 }
335 
336 int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
337 {
338 	int rc;
339 
340 	/* pseries error logs are in BE format, convert to cpu type */
341 	switch (hp_elog->id_type) {
342 	case PSERIES_HP_ELOG_ID_DRC_COUNT:
343 		hp_elog->_drc_u.drc_count =
344 				be32_to_cpu(hp_elog->_drc_u.drc_count);
345 		break;
346 	case PSERIES_HP_ELOG_ID_DRC_INDEX:
347 		hp_elog->_drc_u.drc_index =
348 				be32_to_cpu(hp_elog->_drc_u.drc_index);
349 		break;
350 	case PSERIES_HP_ELOG_ID_DRC_IC:
351 		hp_elog->_drc_u.ic.count =
352 				be32_to_cpu(hp_elog->_drc_u.ic.count);
353 		hp_elog->_drc_u.ic.index =
354 				be32_to_cpu(hp_elog->_drc_u.ic.index);
355 	}
356 
357 	switch (hp_elog->resource) {
358 	case PSERIES_HP_ELOG_RESOURCE_MEM:
359 		rc = dlpar_memory(hp_elog);
360 		break;
361 	case PSERIES_HP_ELOG_RESOURCE_CPU:
362 		rc = dlpar_cpu(hp_elog);
363 		break;
364 	case PSERIES_HP_ELOG_RESOURCE_PMEM:
365 		rc = dlpar_hp_pmem(hp_elog);
366 		break;
367 
368 	default:
369 		pr_warn_ratelimited("Invalid resource (%d) specified\n",
370 				    hp_elog->resource);
371 		rc = -EINVAL;
372 	}
373 
374 	return rc;
375 }
376 
377 static void pseries_hp_work_fn(struct work_struct *work)
378 {
379 	struct pseries_hp_work *hp_work =
380 			container_of(work, struct pseries_hp_work, work);
381 
382 	handle_dlpar_errorlog(hp_work->errlog);
383 
384 	kfree(hp_work->errlog);
385 	kfree((void *)work);
386 }
387 
388 void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog)
389 {
390 	struct pseries_hp_work *work;
391 	struct pseries_hp_errorlog *hp_errlog_copy;
392 
393 	hp_errlog_copy = kmalloc(sizeof(struct pseries_hp_errorlog),
394 				 GFP_KERNEL);
395 	memcpy(hp_errlog_copy, hp_errlog, sizeof(struct pseries_hp_errorlog));
396 
397 	work = kmalloc(sizeof(struct pseries_hp_work), GFP_KERNEL);
398 	if (work) {
399 		INIT_WORK((struct work_struct *)work, pseries_hp_work_fn);
400 		work->errlog = hp_errlog_copy;
401 		queue_work(pseries_hp_wq, (struct work_struct *)work);
402 	} else {
403 		kfree(hp_errlog_copy);
404 	}
405 }
406 
407 static int dlpar_parse_resource(char **cmd, struct pseries_hp_errorlog *hp_elog)
408 {
409 	char *arg;
410 
411 	arg = strsep(cmd, " ");
412 	if (!arg)
413 		return -EINVAL;
414 
415 	if (sysfs_streq(arg, "memory")) {
416 		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
417 	} else if (sysfs_streq(arg, "cpu")) {
418 		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU;
419 	} else {
420 		pr_err("Invalid resource specified.\n");
421 		return -EINVAL;
422 	}
423 
424 	return 0;
425 }
426 
427 static int dlpar_parse_action(char **cmd, struct pseries_hp_errorlog *hp_elog)
428 {
429 	char *arg;
430 
431 	arg = strsep(cmd, " ");
432 	if (!arg)
433 		return -EINVAL;
434 
435 	if (sysfs_streq(arg, "add")) {
436 		hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD;
437 	} else if (sysfs_streq(arg, "remove")) {
438 		hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE;
439 	} else {
440 		pr_err("Invalid action specified.\n");
441 		return -EINVAL;
442 	}
443 
444 	return 0;
445 }
446 
447 static int dlpar_parse_id_type(char **cmd, struct pseries_hp_errorlog *hp_elog)
448 {
449 	char *arg;
450 	u32 count, index;
451 
452 	arg = strsep(cmd, " ");
453 	if (!arg)
454 		return -EINVAL;
455 
456 	if (sysfs_streq(arg, "indexed-count")) {
457 		hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_IC;
458 		arg = strsep(cmd, " ");
459 		if (!arg) {
460 			pr_err("No DRC count specified.\n");
461 			return -EINVAL;
462 		}
463 
464 		if (kstrtou32(arg, 0, &count)) {
465 			pr_err("Invalid DRC count specified.\n");
466 			return -EINVAL;
467 		}
468 
469 		arg = strsep(cmd, " ");
470 		if (!arg) {
471 			pr_err("No DRC Index specified.\n");
472 			return -EINVAL;
473 		}
474 
475 		if (kstrtou32(arg, 0, &index)) {
476 			pr_err("Invalid DRC Index specified.\n");
477 			return -EINVAL;
478 		}
479 
480 		hp_elog->_drc_u.ic.count = cpu_to_be32(count);
481 		hp_elog->_drc_u.ic.index = cpu_to_be32(index);
482 	} else if (sysfs_streq(arg, "index")) {
483 		hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX;
484 		arg = strsep(cmd, " ");
485 		if (!arg) {
486 			pr_err("No DRC Index specified.\n");
487 			return -EINVAL;
488 		}
489 
490 		if (kstrtou32(arg, 0, &index)) {
491 			pr_err("Invalid DRC Index specified.\n");
492 			return -EINVAL;
493 		}
494 
495 		hp_elog->_drc_u.drc_index = cpu_to_be32(index);
496 	} else if (sysfs_streq(arg, "count")) {
497 		hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT;
498 		arg = strsep(cmd, " ");
499 		if (!arg) {
500 			pr_err("No DRC count specified.\n");
501 			return -EINVAL;
502 		}
503 
504 		if (kstrtou32(arg, 0, &count)) {
505 			pr_err("Invalid DRC count specified.\n");
506 			return -EINVAL;
507 		}
508 
509 		hp_elog->_drc_u.drc_count = cpu_to_be32(count);
510 	} else {
511 		pr_err("Invalid id_type specified.\n");
512 		return -EINVAL;
513 	}
514 
515 	return 0;
516 }
517 
518 static ssize_t dlpar_store(struct class *class, struct class_attribute *attr,
519 			   const char *buf, size_t count)
520 {
521 	struct pseries_hp_errorlog hp_elog;
522 	char *argbuf;
523 	char *args;
524 	int rc;
525 
526 	args = argbuf = kstrdup(buf, GFP_KERNEL);
527 	if (!argbuf) {
528 		pr_info("Could not allocate resources for DLPAR operation\n");
529 		kfree(argbuf);
530 		return -ENOMEM;
531 	}
532 
533 	/*
534 	 * Parse out the request from the user, this will be in the form:
535 	 * <resource> <action> <id_type> <id>
536 	 */
537 	rc = dlpar_parse_resource(&args, &hp_elog);
538 	if (rc)
539 		goto dlpar_store_out;
540 
541 	rc = dlpar_parse_action(&args, &hp_elog);
542 	if (rc)
543 		goto dlpar_store_out;
544 
545 	rc = dlpar_parse_id_type(&args, &hp_elog);
546 	if (rc)
547 		goto dlpar_store_out;
548 
549 	rc = handle_dlpar_errorlog(&hp_elog);
550 
551 dlpar_store_out:
552 	kfree(argbuf);
553 
554 	if (rc)
555 		pr_err("Could not handle DLPAR request \"%s\"\n", buf);
556 
557 	return rc ? rc : count;
558 }
559 
560 static ssize_t dlpar_show(struct class *class, struct class_attribute *attr,
561 			  char *buf)
562 {
563 	return sprintf(buf, "%s\n", "memory,cpu");
564 }
565 
566 static CLASS_ATTR_RW(dlpar);
567 
568 int __init dlpar_workqueue_init(void)
569 {
570 	if (pseries_hp_wq)
571 		return 0;
572 
573 	pseries_hp_wq = alloc_workqueue("pseries hotplug workqueue",
574 			WQ_UNBOUND, 1);
575 
576 	return pseries_hp_wq ? 0 : -ENOMEM;
577 }
578 
579 static int __init dlpar_sysfs_init(void)
580 {
581 	int rc;
582 
583 	rc = dlpar_workqueue_init();
584 	if (rc)
585 		return rc;
586 
587 	return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
588 }
589 machine_device_initcall(pseries, dlpar_sysfs_init);
590 
591