xref: /openbmc/linux/arch/powerpc/platforms/pseries/dlpar.c (revision 1a8061c46c46c960f715c597b9d279ea2ba42bd9)
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 #include <linux/kernel.h>
14 #include <linux/kref.h>
15 #include <linux/notifier.h>
16 #include <linux/proc_fs.h>
17 #include <linux/spinlock.h>
18 #include <linux/cpu.h>
19 
20 #include <asm/prom.h>
21 #include <asm/machdep.h>
22 #include <asm/uaccess.h>
23 #include <asm/rtas.h>
24 #include <asm/pSeries_reconfig.h>
25 
26 struct cc_workarea {
27 	u32	drc_index;
28 	u32	zero;
29 	u32	name_offset;
30 	u32	prop_length;
31 	u32	prop_offset;
32 };
33 
34 static void dlpar_free_cc_property(struct property *prop)
35 {
36 	kfree(prop->name);
37 	kfree(prop->value);
38 	kfree(prop);
39 }
40 
41 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
42 {
43 	struct property *prop;
44 	char *name;
45 	char *value;
46 
47 	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
48 	if (!prop)
49 		return NULL;
50 
51 	name = (char *)ccwa + ccwa->name_offset;
52 	prop->name = kstrdup(name, GFP_KERNEL);
53 
54 	prop->length = ccwa->prop_length;
55 	value = (char *)ccwa + ccwa->prop_offset;
56 	prop->value = kzalloc(prop->length, GFP_KERNEL);
57 	if (!prop->value) {
58 		dlpar_free_cc_property(prop);
59 		return NULL;
60 	}
61 
62 	memcpy(prop->value, value, prop->length);
63 	return prop;
64 }
65 
66 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa)
67 {
68 	struct device_node *dn;
69 	char *name;
70 
71 	dn = kzalloc(sizeof(*dn), GFP_KERNEL);
72 	if (!dn)
73 		return NULL;
74 
75 	/* The configure connector reported name does not contain a
76 	 * preceeding '/', so we allocate a buffer large enough to
77 	 * prepend this to the full_name.
78 	 */
79 	name = (char *)ccwa + ccwa->name_offset;
80 	dn->full_name = kmalloc(strlen(name) + 2, GFP_KERNEL);
81 	if (!dn->full_name) {
82 		kfree(dn);
83 		return NULL;
84 	}
85 
86 	sprintf(dn->full_name, "/%s", name);
87 	return dn;
88 }
89 
90 static void dlpar_free_one_cc_node(struct device_node *dn)
91 {
92 	struct property *prop;
93 
94 	while (dn->properties) {
95 		prop = dn->properties;
96 		dn->properties = prop->next;
97 		dlpar_free_cc_property(prop);
98 	}
99 
100 	kfree(dn->full_name);
101 	kfree(dn);
102 }
103 
104 static void dlpar_free_cc_nodes(struct device_node *dn)
105 {
106 	if (dn->child)
107 		dlpar_free_cc_nodes(dn->child);
108 
109 	if (dn->sibling)
110 		dlpar_free_cc_nodes(dn->sibling);
111 
112 	dlpar_free_one_cc_node(dn);
113 }
114 
115 #define NEXT_SIBLING    1
116 #define NEXT_CHILD      2
117 #define NEXT_PROPERTY   3
118 #define PREV_PARENT     4
119 #define MORE_MEMORY     5
120 #define CALL_AGAIN	-2
121 #define ERR_CFG_USE     -9003
122 
123 struct device_node *dlpar_configure_connector(u32 drc_index)
124 {
125 	struct device_node *dn;
126 	struct device_node *first_dn = NULL;
127 	struct device_node *last_dn = NULL;
128 	struct property *property;
129 	struct property *last_property = NULL;
130 	struct cc_workarea *ccwa;
131 	int cc_token;
132 	int rc;
133 
134 	cc_token = rtas_token("ibm,configure-connector");
135 	if (cc_token == RTAS_UNKNOWN_SERVICE)
136 		return NULL;
137 
138 	spin_lock(&rtas_data_buf_lock);
139 	ccwa = (struct cc_workarea *)&rtas_data_buf[0];
140 	ccwa->drc_index = drc_index;
141 	ccwa->zero = 0;
142 
143 	rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL);
144 	while (rc) {
145 		switch (rc) {
146 		case NEXT_SIBLING:
147 			dn = dlpar_parse_cc_node(ccwa);
148 			if (!dn)
149 				goto cc_error;
150 
151 			dn->parent = last_dn->parent;
152 			last_dn->sibling = dn;
153 			last_dn = dn;
154 			break;
155 
156 		case NEXT_CHILD:
157 			dn = dlpar_parse_cc_node(ccwa);
158 			if (!dn)
159 				goto cc_error;
160 
161 			if (!first_dn)
162 				first_dn = dn;
163 			else {
164 				dn->parent = last_dn;
165 				if (last_dn)
166 					last_dn->child = dn;
167 			}
168 
169 			last_dn = dn;
170 			break;
171 
172 		case NEXT_PROPERTY:
173 			property = dlpar_parse_cc_property(ccwa);
174 			if (!property)
175 				goto cc_error;
176 
177 			if (!last_dn->properties)
178 				last_dn->properties = property;
179 			else
180 				last_property->next = property;
181 
182 			last_property = property;
183 			break;
184 
185 		case PREV_PARENT:
186 			last_dn = last_dn->parent;
187 			break;
188 
189 		case CALL_AGAIN:
190 			break;
191 
192 		case MORE_MEMORY:
193 		case ERR_CFG_USE:
194 		default:
195 			printk(KERN_ERR "Unexpected Error (%d) "
196 			       "returned from configure-connector\n", rc);
197 			goto cc_error;
198 		}
199 
200 		rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL);
201 	}
202 
203 	spin_unlock(&rtas_data_buf_lock);
204 	return first_dn;
205 
206 cc_error:
207 	if (first_dn)
208 		dlpar_free_cc_nodes(first_dn);
209 	spin_unlock(&rtas_data_buf_lock);
210 	return NULL;
211 }
212 
213 static struct device_node *derive_parent(const char *path)
214 {
215 	struct device_node *parent;
216 	char *last_slash;
217 
218 	last_slash = strrchr(path, '/');
219 	if (last_slash == path) {
220 		parent = of_find_node_by_path("/");
221 	} else {
222 		char *parent_path;
223 		int parent_path_len = last_slash - path + 1;
224 		parent_path = kmalloc(parent_path_len, GFP_KERNEL);
225 		if (!parent_path)
226 			return NULL;
227 
228 		strlcpy(parent_path, path, parent_path_len);
229 		parent = of_find_node_by_path(parent_path);
230 		kfree(parent_path);
231 	}
232 
233 	return parent;
234 }
235 
236 int dlpar_attach_node(struct device_node *dn)
237 {
238 	struct proc_dir_entry *ent;
239 	int rc;
240 
241 	of_node_set_flag(dn, OF_DYNAMIC);
242 	kref_init(&dn->kref);
243 	dn->parent = derive_parent(dn->full_name);
244 	if (!dn->parent)
245 		return -ENOMEM;
246 
247 	rc = blocking_notifier_call_chain(&pSeries_reconfig_chain,
248 					  PSERIES_RECONFIG_ADD, dn);
249 	if (rc == NOTIFY_BAD) {
250 		printk(KERN_ERR "Failed to add device node %s\n",
251 		       dn->full_name);
252 		return -ENOMEM; /* For now, safe to assume kmalloc failure */
253 	}
254 
255 	of_attach_node(dn);
256 
257 #ifdef CONFIG_PROC_DEVICETREE
258 	ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde);
259 	if (ent)
260 		proc_device_tree_add_node(dn, ent);
261 #endif
262 
263 	of_node_put(dn->parent);
264 	return 0;
265 }
266 
267 int dlpar_detach_node(struct device_node *dn)
268 {
269 	struct device_node *parent = dn->parent;
270 	struct property *prop = dn->properties;
271 
272 #ifdef CONFIG_PROC_DEVICETREE
273 	while (prop) {
274 		remove_proc_entry(prop->name, dn->pde);
275 		prop = prop->next;
276 	}
277 
278 	if (dn->pde)
279 		remove_proc_entry(dn->pde->name, parent->pde);
280 #endif
281 
282 	blocking_notifier_call_chain(&pSeries_reconfig_chain,
283 			    PSERIES_RECONFIG_REMOVE, dn);
284 	of_detach_node(dn);
285 	of_node_put(dn); /* Must decrement the refcount */
286 
287 	return 0;
288 }
289 
290 #define DR_ENTITY_SENSE		9003
291 #define DR_ENTITY_PRESENT	1
292 #define DR_ENTITY_UNUSABLE	2
293 #define ALLOCATION_STATE	9003
294 #define ALLOC_UNUSABLE		0
295 #define ALLOC_USABLE		1
296 #define ISOLATION_STATE		9001
297 #define ISOLATE			0
298 #define UNISOLATE		1
299 
300 int dlpar_acquire_drc(u32 drc_index)
301 {
302 	int dr_status, rc;
303 
304 	rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
305 		       DR_ENTITY_SENSE, drc_index);
306 	if (rc || dr_status != DR_ENTITY_UNUSABLE)
307 		return -1;
308 
309 	rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE);
310 	if (rc)
311 		return rc;
312 
313 	rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
314 	if (rc) {
315 		rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
316 		return rc;
317 	}
318 
319 	return 0;
320 }
321 
322 int dlpar_release_drc(u32 drc_index)
323 {
324 	int dr_status, rc;
325 
326 	rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
327 		       DR_ENTITY_SENSE, drc_index);
328 	if (rc || dr_status != DR_ENTITY_PRESENT)
329 		return -1;
330 
331 	rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE);
332 	if (rc)
333 		return rc;
334 
335 	rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
336 	if (rc) {
337 		rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
338 		return rc;
339 	}
340 
341 	return 0;
342 }
343 
344 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
345 
346 static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
347 {
348 	struct device_node *dn;
349 	unsigned long drc_index;
350 	char *cpu_name;
351 	int rc;
352 
353 	rc = strict_strtoul(buf, 0, &drc_index);
354 	if (rc)
355 		return -EINVAL;
356 
357 	dn = dlpar_configure_connector(drc_index);
358 	if (!dn)
359 		return -EINVAL;
360 
361 	/* configure-connector reports cpus as living in the base
362 	 * directory of the device tree.  CPUs actually live in the
363 	 * cpus directory so we need to fixup the full_name.
364 	 */
365 	cpu_name = kzalloc(strlen(dn->full_name) + strlen("/cpus") + 1,
366 			   GFP_KERNEL);
367 	if (!cpu_name) {
368 		dlpar_free_cc_nodes(dn);
369 		return -ENOMEM;
370 	}
371 
372 	sprintf(cpu_name, "/cpus%s", dn->full_name);
373 	kfree(dn->full_name);
374 	dn->full_name = cpu_name;
375 
376 	rc = dlpar_acquire_drc(drc_index);
377 	if (rc) {
378 		dlpar_free_cc_nodes(dn);
379 		return -EINVAL;
380 	}
381 
382 	rc = dlpar_attach_node(dn);
383 	if (rc) {
384 		dlpar_release_drc(drc_index);
385 		dlpar_free_cc_nodes(dn);
386 	}
387 
388 	return rc ? rc : count;
389 }
390 
391 static ssize_t dlpar_cpu_release(const char *buf, size_t count)
392 {
393 	struct device_node *dn;
394 	const u32 *drc_index;
395 	int rc;
396 
397 	dn = of_find_node_by_path(buf);
398 	if (!dn)
399 		return -EINVAL;
400 
401 	drc_index = of_get_property(dn, "ibm,my-drc-index", NULL);
402 	if (!drc_index) {
403 		of_node_put(dn);
404 		return -EINVAL;
405 	}
406 
407 	rc = dlpar_release_drc(*drc_index);
408 	if (rc) {
409 		of_node_put(dn);
410 		return -EINVAL;
411 	}
412 
413 	rc = dlpar_detach_node(dn);
414 	if (rc) {
415 		dlpar_acquire_drc(*drc_index);
416 		return rc;
417 	}
418 
419 	of_node_put(dn);
420 	return count;
421 }
422 
423 static int __init pseries_dlpar_init(void)
424 {
425 	ppc_md.cpu_probe = dlpar_cpu_probe;
426 	ppc_md.cpu_release = dlpar_cpu_release;
427 
428 	return 0;
429 }
430 machine_device_initcall(pseries, pseries_dlpar_init);
431 
432 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
433