2 * Support for dynamic reconfiguration for PCI, Memory, and CPU
3 * Hotplug and Dynamic Logical Partitioning on RPA platforms.
5 * Copyright (C) 2009 Nathan Fontenot
6 * Copyright (C) 2009 IBM Corporation
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.
13 #define pr_fmt(fmt) "dlpar: " fmt
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>
22 #include "of_helpers.h"
23 #include "offline_states.h"
27 #include <asm/machdep.h>
28 #include <asm/uaccess.h>
39 void dlpar_free_cc_property(struct property *prop)
46 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
48 struct property *prop;
52 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
56 name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
57 prop->name = kstrdup(name, GFP_KERNEL);
59 prop->length = be32_to_cpu(ccwa->prop_length);
60 value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset);
61 prop->value = kmemdup(value, prop->length, GFP_KERNEL);
63 dlpar_free_cc_property(prop);
70 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
73 struct device_node *dn;
76 /* If parent node path is "/" advance path to NULL terminator to
77 * prevent double leading slashs in full_name.
82 dn = kzalloc(sizeof(*dn), GFP_KERNEL);
86 name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
87 dn->full_name = kasprintf(GFP_KERNEL, "%s/%s", path, name);
93 of_node_set_flag(dn, OF_DYNAMIC);
99 static void dlpar_free_one_cc_node(struct device_node *dn)
101 struct property *prop;
103 while (dn->properties) {
104 prop = dn->properties;
105 dn->properties = prop->next;
106 dlpar_free_cc_property(prop);
109 kfree(dn->full_name);
113 void dlpar_free_cc_nodes(struct device_node *dn)
116 dlpar_free_cc_nodes(dn->child);
119 dlpar_free_cc_nodes(dn->sibling);
121 dlpar_free_one_cc_node(dn);
125 #define NEXT_SIBLING 1
127 #define NEXT_PROPERTY 3
128 #define PREV_PARENT 4
129 #define MORE_MEMORY 5
130 #define CALL_AGAIN -2
131 #define ERR_CFG_USE -9003
133 struct device_node *dlpar_configure_connector(__be32 drc_index,
134 struct device_node *parent)
136 struct device_node *dn;
137 struct device_node *first_dn = NULL;
138 struct device_node *last_dn = NULL;
139 struct property *property;
140 struct property *last_property = NULL;
141 struct cc_workarea *ccwa;
143 const char *parent_path = parent->full_name;
147 cc_token = rtas_token("ibm,configure-connector");
148 if (cc_token == RTAS_UNKNOWN_SERVICE)
151 data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
155 ccwa = (struct cc_workarea *)&data_buf[0];
156 ccwa->drc_index = drc_index;
160 /* Since we release the rtas_data_buf lock between configure
161 * connector calls we want to re-populate the rtas_data_buffer
162 * with the contents of the previous call.
164 spin_lock(&rtas_data_buf_lock);
166 memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE);
167 rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL);
168 memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
170 spin_unlock(&rtas_data_buf_lock);
177 dn = dlpar_parse_cc_node(ccwa, parent_path);
181 dn->parent = last_dn->parent;
182 last_dn->sibling = dn;
188 parent_path = last_dn->full_name;
190 dn = dlpar_parse_cc_node(ccwa, parent_path);
198 dn->parent = last_dn;
207 property = dlpar_parse_cc_property(ccwa);
211 if (!last_dn->properties)
212 last_dn->properties = property;
214 last_property->next = property;
216 last_property = property;
220 last_dn = last_dn->parent;
221 parent_path = last_dn->parent->full_name;
230 printk(KERN_ERR "Unexpected Error (%d) "
231 "returned from configure-connector\n", rc);
241 dlpar_free_cc_nodes(first_dn);
249 int dlpar_attach_node(struct device_node *dn)
253 dn->parent = pseries_of_derive_parent(dn->full_name);
254 if (IS_ERR(dn->parent))
255 return PTR_ERR(dn->parent);
257 rc = of_attach_node(dn);
259 printk(KERN_ERR "Failed to add device node %s\n",
264 of_node_put(dn->parent);
268 int dlpar_detach_node(struct device_node *dn)
270 struct device_node *child;
273 child = of_get_next_child(dn, NULL);
275 dlpar_detach_node(child);
276 child = of_get_next_child(dn, child);
279 rc = of_detach_node(dn);
283 of_node_put(dn); /* Must decrement the refcount */
287 #define DR_ENTITY_SENSE 9003
288 #define DR_ENTITY_PRESENT 1
289 #define DR_ENTITY_UNUSABLE 2
290 #define ALLOCATION_STATE 9003
291 #define ALLOC_UNUSABLE 0
292 #define ALLOC_USABLE 1
293 #define ISOLATION_STATE 9001
297 int dlpar_acquire_drc(u32 drc_index)
301 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
302 DR_ENTITY_SENSE, drc_index);
303 if (rc || dr_status != DR_ENTITY_UNUSABLE)
306 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE);
310 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
312 rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
319 int dlpar_release_drc(u32 drc_index)
323 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
324 DR_ENTITY_SENSE, drc_index);
325 if (rc || dr_status != DR_ENTITY_PRESENT)
328 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE);
332 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
334 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
341 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
343 static int dlpar_online_cpu(struct device_node *dn)
347 int len, nthreads, i;
348 const __be32 *intserv;
351 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
355 nthreads = len / sizeof(u32);
357 cpu_maps_update_begin();
358 for (i = 0; i < nthreads; i++) {
359 thread = be32_to_cpu(intserv[i]);
360 for_each_present_cpu(cpu) {
361 if (get_hard_smp_processor_id(cpu) != thread)
363 BUG_ON(get_cpu_current_state(cpu)
364 != CPU_STATE_OFFLINE);
365 cpu_maps_update_done();
366 rc = device_online(get_cpu_device(cpu));
369 cpu_maps_update_begin();
373 if (cpu == num_possible_cpus())
374 printk(KERN_WARNING "Could not find cpu to online "
375 "with physical id 0x%x\n", thread);
377 cpu_maps_update_done();
384 static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
386 struct device_node *dn, *parent;
390 rc = kstrtou32(buf, 0, &drc_index);
394 rc = dlpar_acquire_drc(drc_index);
398 parent = of_find_node_by_path("/cpus");
402 dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
405 dlpar_release_drc(drc_index);
409 rc = dlpar_attach_node(dn);
411 dlpar_release_drc(drc_index);
412 dlpar_free_cc_nodes(dn);
416 rc = dlpar_online_cpu(dn);
423 static int dlpar_offline_cpu(struct device_node *dn)
427 int len, nthreads, i;
428 const __be32 *intserv;
431 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
435 nthreads = len / sizeof(u32);
437 cpu_maps_update_begin();
438 for (i = 0; i < nthreads; i++) {
439 thread = be32_to_cpu(intserv[i]);
440 for_each_present_cpu(cpu) {
441 if (get_hard_smp_processor_id(cpu) != thread)
444 if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE)
447 if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
448 set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
449 cpu_maps_update_done();
450 rc = device_offline(get_cpu_device(cpu));
453 cpu_maps_update_begin();
459 * The cpu is in CPU_STATE_INACTIVE.
460 * Upgrade it's state to CPU_STATE_OFFLINE.
462 set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
463 BUG_ON(plpar_hcall_norets(H_PROD, thread)
468 if (cpu == num_possible_cpus())
469 printk(KERN_WARNING "Could not find cpu to offline "
470 "with physical id 0x%x\n", thread);
472 cpu_maps_update_done();
479 static ssize_t dlpar_cpu_release(const char *buf, size_t count)
481 struct device_node *dn;
485 dn = of_find_node_by_path(buf);
489 rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index);
495 rc = dlpar_offline_cpu(dn);
501 rc = dlpar_release_drc(drc_index);
507 rc = dlpar_detach_node(dn);
509 dlpar_acquire_drc(drc_index);
518 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
520 static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
524 /* pseries error logs are in BE format, convert to cpu type */
525 switch (hp_elog->id_type) {
526 case PSERIES_HP_ELOG_ID_DRC_COUNT:
527 hp_elog->_drc_u.drc_count =
528 be32_to_cpu(hp_elog->_drc_u.drc_count);
530 case PSERIES_HP_ELOG_ID_DRC_INDEX:
531 hp_elog->_drc_u.drc_index =
532 be32_to_cpu(hp_elog->_drc_u.drc_index);
535 switch (hp_elog->resource) {
536 case PSERIES_HP_ELOG_RESOURCE_MEM:
537 rc = dlpar_memory(hp_elog);
540 pr_warn_ratelimited("Invalid resource (%d) specified\n",
548 static ssize_t dlpar_store(struct class *class, struct class_attribute *attr,
549 const char *buf, size_t count)
551 struct pseries_hp_errorlog *hp_elog;
555 hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL);
558 goto dlpar_store_out;
561 /* Parse out the request from the user, this will be in the form
562 * <resource> <action> <id_type> <id>
565 if (!strncmp(arg, "memory", 6)) {
566 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
567 arg += strlen("memory ");
569 pr_err("Invalid resource specified: \"%s\"\n", buf);
571 goto dlpar_store_out;
574 if (!strncmp(arg, "add", 3)) {
575 hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD;
576 arg += strlen("add ");
577 } else if (!strncmp(arg, "remove", 6)) {
578 hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE;
579 arg += strlen("remove ");
581 pr_err("Invalid action specified: \"%s\"\n", buf);
583 goto dlpar_store_out;
586 if (!strncmp(arg, "index", 5)) {
589 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX;
590 arg += strlen("index ");
591 if (kstrtou32(arg, 0, &index)) {
593 pr_err("Invalid drc_index specified: \"%s\"\n", buf);
594 goto dlpar_store_out;
597 hp_elog->_drc_u.drc_index = cpu_to_be32(index);
598 } else if (!strncmp(arg, "count", 5)) {
601 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT;
602 arg += strlen("count ");
603 if (kstrtou32(arg, 0, &count)) {
605 pr_err("Invalid count specified: \"%s\"\n", buf);
606 goto dlpar_store_out;
609 hp_elog->_drc_u.drc_count = cpu_to_be32(count);
611 pr_err("Invalid id_type specified: \"%s\"\n", buf);
613 goto dlpar_store_out;
616 rc = handle_dlpar_errorlog(hp_elog);
620 return rc ? rc : count;
623 static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store);
625 static int __init pseries_dlpar_init(void)
629 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
630 ppc_md.cpu_probe = dlpar_cpu_probe;
631 ppc_md.cpu_release = dlpar_cpu_release;
632 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
634 rc = sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
638 machine_device_initcall(pseries, pseries_dlpar_init);