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"
26 #include <asm/machdep.h>
27 #include <asm/uaccess.h>
38 void dlpar_free_cc_property(struct property *prop)
45 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
47 struct property *prop;
51 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
55 name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
56 prop->name = kstrdup(name, GFP_KERNEL);
58 prop->length = be32_to_cpu(ccwa->prop_length);
59 value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset);
60 prop->value = kmemdup(value, prop->length, GFP_KERNEL);
62 dlpar_free_cc_property(prop);
69 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
72 struct device_node *dn;
75 /* If parent node path is "/" advance path to NULL terminator to
76 * prevent double leading slashs in full_name.
81 dn = kzalloc(sizeof(*dn), GFP_KERNEL);
85 name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
86 dn->full_name = kasprintf(GFP_KERNEL, "%s/%s", path, name);
92 of_node_set_flag(dn, OF_DYNAMIC);
98 static void dlpar_free_one_cc_node(struct device_node *dn)
100 struct property *prop;
102 while (dn->properties) {
103 prop = dn->properties;
104 dn->properties = prop->next;
105 dlpar_free_cc_property(prop);
108 kfree(dn->full_name);
112 void dlpar_free_cc_nodes(struct device_node *dn)
115 dlpar_free_cc_nodes(dn->child);
118 dlpar_free_cc_nodes(dn->sibling);
120 dlpar_free_one_cc_node(dn);
124 #define NEXT_SIBLING 1
126 #define NEXT_PROPERTY 3
127 #define PREV_PARENT 4
128 #define MORE_MEMORY 5
129 #define CALL_AGAIN -2
130 #define ERR_CFG_USE -9003
132 struct device_node *dlpar_configure_connector(__be32 drc_index,
133 struct device_node *parent)
135 struct device_node *dn;
136 struct device_node *first_dn = NULL;
137 struct device_node *last_dn = NULL;
138 struct property *property;
139 struct property *last_property = NULL;
140 struct cc_workarea *ccwa;
142 const char *parent_path = parent->full_name;
146 cc_token = rtas_token("ibm,configure-connector");
147 if (cc_token == RTAS_UNKNOWN_SERVICE)
150 data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
154 ccwa = (struct cc_workarea *)&data_buf[0];
155 ccwa->drc_index = drc_index;
159 /* Since we release the rtas_data_buf lock between configure
160 * connector calls we want to re-populate the rtas_data_buffer
161 * with the contents of the previous call.
163 spin_lock(&rtas_data_buf_lock);
165 memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE);
166 rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL);
167 memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
169 spin_unlock(&rtas_data_buf_lock);
176 dn = dlpar_parse_cc_node(ccwa, parent_path);
180 dn->parent = last_dn->parent;
181 last_dn->sibling = dn;
187 parent_path = last_dn->full_name;
189 dn = dlpar_parse_cc_node(ccwa, parent_path);
197 dn->parent = last_dn;
206 property = dlpar_parse_cc_property(ccwa);
210 if (!last_dn->properties)
211 last_dn->properties = property;
213 last_property->next = property;
215 last_property = property;
219 last_dn = last_dn->parent;
220 parent_path = last_dn->parent->full_name;
229 printk(KERN_ERR "Unexpected Error (%d) "
230 "returned from configure-connector\n", rc);
240 dlpar_free_cc_nodes(first_dn);
248 int dlpar_attach_node(struct device_node *dn)
252 dn->parent = pseries_of_derive_parent(dn->full_name);
253 if (IS_ERR(dn->parent))
254 return PTR_ERR(dn->parent);
256 rc = of_attach_node(dn);
258 printk(KERN_ERR "Failed to add device node %s\n",
263 of_node_put(dn->parent);
267 int dlpar_detach_node(struct device_node *dn)
269 struct device_node *child;
272 child = of_get_next_child(dn, NULL);
274 dlpar_detach_node(child);
275 child = of_get_next_child(dn, child);
278 rc = of_detach_node(dn);
282 of_node_put(dn); /* Must decrement the refcount */
286 #define DR_ENTITY_SENSE 9003
287 #define DR_ENTITY_PRESENT 1
288 #define DR_ENTITY_UNUSABLE 2
289 #define ALLOCATION_STATE 9003
290 #define ALLOC_UNUSABLE 0
291 #define ALLOC_USABLE 1
292 #define ISOLATION_STATE 9001
296 int dlpar_acquire_drc(u32 drc_index)
300 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
301 DR_ENTITY_SENSE, drc_index);
302 if (rc || dr_status != DR_ENTITY_UNUSABLE)
305 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE);
309 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
311 rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
318 int dlpar_release_drc(u32 drc_index)
322 rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
323 DR_ENTITY_SENSE, drc_index);
324 if (rc || dr_status != DR_ENTITY_PRESENT)
327 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE);
331 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
333 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
340 static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
344 /* pseries error logs are in BE format, convert to cpu type */
345 switch (hp_elog->id_type) {
346 case PSERIES_HP_ELOG_ID_DRC_COUNT:
347 hp_elog->_drc_u.drc_count =
348 be32_to_cpu(hp_elog->_drc_u.drc_count);
350 case PSERIES_HP_ELOG_ID_DRC_INDEX:
351 hp_elog->_drc_u.drc_index =
352 be32_to_cpu(hp_elog->_drc_u.drc_index);
355 switch (hp_elog->resource) {
356 case PSERIES_HP_ELOG_RESOURCE_MEM:
357 rc = dlpar_memory(hp_elog);
359 case PSERIES_HP_ELOG_RESOURCE_CPU:
360 rc = dlpar_cpu(hp_elog);
363 pr_warn_ratelimited("Invalid resource (%d) specified\n",
371 static ssize_t dlpar_store(struct class *class, struct class_attribute *attr,
372 const char *buf, size_t count)
374 struct pseries_hp_errorlog *hp_elog;
378 hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL);
381 goto dlpar_store_out;
384 /* Parse out the request from the user, this will be in the form
385 * <resource> <action> <id_type> <id>
388 if (!strncmp(arg, "memory", 6)) {
389 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
390 arg += strlen("memory ");
391 } else if (!strncmp(arg, "cpu", 3)) {
392 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU;
393 arg += strlen("cpu ");
395 pr_err("Invalid resource specified: \"%s\"\n", buf);
397 goto dlpar_store_out;
400 if (!strncmp(arg, "add", 3)) {
401 hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD;
402 arg += strlen("add ");
403 } else if (!strncmp(arg, "remove", 6)) {
404 hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE;
405 arg += strlen("remove ");
407 pr_err("Invalid action specified: \"%s\"\n", buf);
409 goto dlpar_store_out;
412 if (!strncmp(arg, "index", 5)) {
415 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX;
416 arg += strlen("index ");
417 if (kstrtou32(arg, 0, &index)) {
419 pr_err("Invalid drc_index specified: \"%s\"\n", buf);
420 goto dlpar_store_out;
423 hp_elog->_drc_u.drc_index = cpu_to_be32(index);
424 } else if (!strncmp(arg, "count", 5)) {
427 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT;
428 arg += strlen("count ");
429 if (kstrtou32(arg, 0, &count)) {
431 pr_err("Invalid count specified: \"%s\"\n", buf);
432 goto dlpar_store_out;
435 hp_elog->_drc_u.drc_count = cpu_to_be32(count);
437 pr_err("Invalid id_type specified: \"%s\"\n", buf);
439 goto dlpar_store_out;
442 rc = handle_dlpar_errorlog(hp_elog);
446 return rc ? rc : count;
449 static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store);
451 static int __init pseries_dlpar_init(void)
453 return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
455 machine_device_initcall(pseries, pseries_dlpar_init);