0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define pr_fmt(fmt) "dlpar: " fmt
0011
0012 #include <linux/kernel.h>
0013 #include <linux/notifier.h>
0014 #include <linux/spinlock.h>
0015 #include <linux/cpu.h>
0016 #include <linux/slab.h>
0017 #include <linux/of.h>
0018
0019 #include "of_helpers.h"
0020 #include "pseries.h"
0021
0022 #include <asm/machdep.h>
0023 #include <linux/uaccess.h>
0024 #include <asm/rtas.h>
0025
0026 static struct workqueue_struct *pseries_hp_wq;
0027
0028 struct pseries_hp_work {
0029 struct work_struct work;
0030 struct pseries_hp_errorlog *errlog;
0031 };
0032
0033 struct cc_workarea {
0034 __be32 drc_index;
0035 __be32 zero;
0036 __be32 name_offset;
0037 __be32 prop_length;
0038 __be32 prop_offset;
0039 };
0040
0041 void dlpar_free_cc_property(struct property *prop)
0042 {
0043 kfree(prop->name);
0044 kfree(prop->value);
0045 kfree(prop);
0046 }
0047
0048 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
0049 {
0050 struct property *prop;
0051 char *name;
0052 char *value;
0053
0054 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
0055 if (!prop)
0056 return NULL;
0057
0058 name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
0059 prop->name = kstrdup(name, GFP_KERNEL);
0060 if (!prop->name) {
0061 dlpar_free_cc_property(prop);
0062 return NULL;
0063 }
0064
0065 prop->length = be32_to_cpu(ccwa->prop_length);
0066 value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset);
0067 prop->value = kmemdup(value, prop->length, GFP_KERNEL);
0068 if (!prop->value) {
0069 dlpar_free_cc_property(prop);
0070 return NULL;
0071 }
0072
0073 return prop;
0074 }
0075
0076 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa)
0077 {
0078 struct device_node *dn;
0079 const char *name;
0080
0081 dn = kzalloc(sizeof(*dn), GFP_KERNEL);
0082 if (!dn)
0083 return NULL;
0084
0085 name = (const char *)ccwa + be32_to_cpu(ccwa->name_offset);
0086 dn->full_name = kstrdup(name, GFP_KERNEL);
0087 if (!dn->full_name) {
0088 kfree(dn);
0089 return NULL;
0090 }
0091
0092 of_node_set_flag(dn, OF_DYNAMIC);
0093 of_node_init(dn);
0094
0095 return dn;
0096 }
0097
0098 static void dlpar_free_one_cc_node(struct device_node *dn)
0099 {
0100 struct property *prop;
0101
0102 while (dn->properties) {
0103 prop = dn->properties;
0104 dn->properties = prop->next;
0105 dlpar_free_cc_property(prop);
0106 }
0107
0108 kfree(dn->full_name);
0109 kfree(dn);
0110 }
0111
0112 void dlpar_free_cc_nodes(struct device_node *dn)
0113 {
0114 if (dn->child)
0115 dlpar_free_cc_nodes(dn->child);
0116
0117 if (dn->sibling)
0118 dlpar_free_cc_nodes(dn->sibling);
0119
0120 dlpar_free_one_cc_node(dn);
0121 }
0122
0123 #define COMPLETE 0
0124 #define NEXT_SIBLING 1
0125 #define NEXT_CHILD 2
0126 #define NEXT_PROPERTY 3
0127 #define PREV_PARENT 4
0128 #define MORE_MEMORY 5
0129 #define ERR_CFG_USE -9003
0130
0131 struct device_node *dlpar_configure_connector(__be32 drc_index,
0132 struct device_node *parent)
0133 {
0134 struct device_node *dn;
0135 struct device_node *first_dn = NULL;
0136 struct device_node *last_dn = NULL;
0137 struct property *property;
0138 struct property *last_property = NULL;
0139 struct cc_workarea *ccwa;
0140 char *data_buf;
0141 int cc_token;
0142 int rc = -1;
0143
0144 cc_token = rtas_token("ibm,configure-connector");
0145 if (cc_token == RTAS_UNKNOWN_SERVICE)
0146 return NULL;
0147
0148 data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
0149 if (!data_buf)
0150 return NULL;
0151
0152 ccwa = (struct cc_workarea *)&data_buf[0];
0153 ccwa->drc_index = drc_index;
0154 ccwa->zero = 0;
0155
0156 do {
0157
0158
0159
0160
0161 spin_lock(&rtas_data_buf_lock);
0162
0163 memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE);
0164 rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL);
0165 memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
0166
0167 spin_unlock(&rtas_data_buf_lock);
0168
0169 if (rtas_busy_delay(rc))
0170 continue;
0171
0172 switch (rc) {
0173 case COMPLETE:
0174 break;
0175
0176 case NEXT_SIBLING:
0177 dn = dlpar_parse_cc_node(ccwa);
0178 if (!dn)
0179 goto cc_error;
0180
0181 dn->parent = last_dn->parent;
0182 last_dn->sibling = dn;
0183 last_dn = dn;
0184 break;
0185
0186 case NEXT_CHILD:
0187 dn = dlpar_parse_cc_node(ccwa);
0188 if (!dn)
0189 goto cc_error;
0190
0191 if (!first_dn) {
0192 dn->parent = parent;
0193 first_dn = dn;
0194 } else {
0195 dn->parent = last_dn;
0196 if (last_dn)
0197 last_dn->child = dn;
0198 }
0199
0200 last_dn = dn;
0201 break;
0202
0203 case NEXT_PROPERTY:
0204 property = dlpar_parse_cc_property(ccwa);
0205 if (!property)
0206 goto cc_error;
0207
0208 if (!last_dn->properties)
0209 last_dn->properties = property;
0210 else
0211 last_property->next = property;
0212
0213 last_property = property;
0214 break;
0215
0216 case PREV_PARENT:
0217 last_dn = last_dn->parent;
0218 break;
0219
0220 case MORE_MEMORY:
0221 case ERR_CFG_USE:
0222 default:
0223 printk(KERN_ERR "Unexpected Error (%d) "
0224 "returned from configure-connector\n", rc);
0225 goto cc_error;
0226 }
0227 } while (rc);
0228
0229 cc_error:
0230 kfree(data_buf);
0231
0232 if (rc) {
0233 if (first_dn)
0234 dlpar_free_cc_nodes(first_dn);
0235
0236 return NULL;
0237 }
0238
0239 return first_dn;
0240 }
0241
0242 int dlpar_attach_node(struct device_node *dn, struct device_node *parent)
0243 {
0244 int rc;
0245
0246 dn->parent = parent;
0247
0248 rc = of_attach_node(dn);
0249 if (rc) {
0250 printk(KERN_ERR "Failed to add device node %pOF\n", dn);
0251 return rc;
0252 }
0253
0254 return 0;
0255 }
0256
0257 int dlpar_detach_node(struct device_node *dn)
0258 {
0259 struct device_node *child;
0260 int rc;
0261
0262 child = of_get_next_child(dn, NULL);
0263 while (child) {
0264 dlpar_detach_node(child);
0265 child = of_get_next_child(dn, child);
0266 }
0267
0268 rc = of_detach_node(dn);
0269 if (rc)
0270 return rc;
0271
0272 of_node_put(dn);
0273
0274 return 0;
0275 }
0276
0277 #define DR_ENTITY_SENSE 9003
0278 #define DR_ENTITY_PRESENT 1
0279 #define DR_ENTITY_UNUSABLE 2
0280 #define ALLOCATION_STATE 9003
0281 #define ALLOC_UNUSABLE 0
0282 #define ALLOC_USABLE 1
0283 #define ISOLATION_STATE 9001
0284 #define ISOLATE 0
0285 #define UNISOLATE 1
0286
0287 int dlpar_acquire_drc(u32 drc_index)
0288 {
0289 int dr_status, rc;
0290
0291 rc = rtas_get_sensor(DR_ENTITY_SENSE, drc_index, &dr_status);
0292 if (rc || dr_status != DR_ENTITY_UNUSABLE)
0293 return -1;
0294
0295 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE);
0296 if (rc)
0297 return rc;
0298
0299 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
0300 if (rc) {
0301 rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
0302 return rc;
0303 }
0304
0305 return 0;
0306 }
0307
0308 int dlpar_release_drc(u32 drc_index)
0309 {
0310 int dr_status, rc;
0311
0312 rc = rtas_get_sensor(DR_ENTITY_SENSE, drc_index, &dr_status);
0313 if (rc || dr_status != DR_ENTITY_PRESENT)
0314 return -1;
0315
0316 rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE);
0317 if (rc)
0318 return rc;
0319
0320 rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
0321 if (rc) {
0322 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
0323 return rc;
0324 }
0325
0326 return 0;
0327 }
0328
0329 int dlpar_unisolate_drc(u32 drc_index)
0330 {
0331 int dr_status, rc;
0332
0333 rc = rtas_get_sensor(DR_ENTITY_SENSE, drc_index, &dr_status);
0334 if (rc || dr_status != DR_ENTITY_PRESENT)
0335 return -1;
0336
0337 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
0338
0339 return 0;
0340 }
0341
0342 int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
0343 {
0344 int rc;
0345
0346
0347 switch (hp_elog->id_type) {
0348 case PSERIES_HP_ELOG_ID_DRC_COUNT:
0349 hp_elog->_drc_u.drc_count =
0350 be32_to_cpu(hp_elog->_drc_u.drc_count);
0351 break;
0352 case PSERIES_HP_ELOG_ID_DRC_INDEX:
0353 hp_elog->_drc_u.drc_index =
0354 be32_to_cpu(hp_elog->_drc_u.drc_index);
0355 break;
0356 case PSERIES_HP_ELOG_ID_DRC_IC:
0357 hp_elog->_drc_u.ic.count =
0358 be32_to_cpu(hp_elog->_drc_u.ic.count);
0359 hp_elog->_drc_u.ic.index =
0360 be32_to_cpu(hp_elog->_drc_u.ic.index);
0361 }
0362
0363 switch (hp_elog->resource) {
0364 case PSERIES_HP_ELOG_RESOURCE_MEM:
0365 rc = dlpar_memory(hp_elog);
0366 break;
0367 case PSERIES_HP_ELOG_RESOURCE_CPU:
0368 rc = dlpar_cpu(hp_elog);
0369 break;
0370 case PSERIES_HP_ELOG_RESOURCE_PMEM:
0371 rc = dlpar_hp_pmem(hp_elog);
0372 break;
0373
0374 default:
0375 pr_warn_ratelimited("Invalid resource (%d) specified\n",
0376 hp_elog->resource);
0377 rc = -EINVAL;
0378 }
0379
0380 return rc;
0381 }
0382
0383 static void pseries_hp_work_fn(struct work_struct *work)
0384 {
0385 struct pseries_hp_work *hp_work =
0386 container_of(work, struct pseries_hp_work, work);
0387
0388 handle_dlpar_errorlog(hp_work->errlog);
0389
0390 kfree(hp_work->errlog);
0391 kfree(work);
0392 }
0393
0394 void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog)
0395 {
0396 struct pseries_hp_work *work;
0397 struct pseries_hp_errorlog *hp_errlog_copy;
0398
0399 hp_errlog_copy = kmemdup(hp_errlog, sizeof(*hp_errlog), GFP_ATOMIC);
0400 if (!hp_errlog_copy)
0401 return;
0402
0403 work = kmalloc(sizeof(struct pseries_hp_work), GFP_ATOMIC);
0404 if (work) {
0405 INIT_WORK((struct work_struct *)work, pseries_hp_work_fn);
0406 work->errlog = hp_errlog_copy;
0407 queue_work(pseries_hp_wq, (struct work_struct *)work);
0408 } else {
0409 kfree(hp_errlog_copy);
0410 }
0411 }
0412
0413 static int dlpar_parse_resource(char **cmd, struct pseries_hp_errorlog *hp_elog)
0414 {
0415 char *arg;
0416
0417 arg = strsep(cmd, " ");
0418 if (!arg)
0419 return -EINVAL;
0420
0421 if (sysfs_streq(arg, "memory")) {
0422 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
0423 } else if (sysfs_streq(arg, "cpu")) {
0424 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU;
0425 } else {
0426 pr_err("Invalid resource specified.\n");
0427 return -EINVAL;
0428 }
0429
0430 return 0;
0431 }
0432
0433 static int dlpar_parse_action(char **cmd, struct pseries_hp_errorlog *hp_elog)
0434 {
0435 char *arg;
0436
0437 arg = strsep(cmd, " ");
0438 if (!arg)
0439 return -EINVAL;
0440
0441 if (sysfs_streq(arg, "add")) {
0442 hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD;
0443 } else if (sysfs_streq(arg, "remove")) {
0444 hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE;
0445 } else {
0446 pr_err("Invalid action specified.\n");
0447 return -EINVAL;
0448 }
0449
0450 return 0;
0451 }
0452
0453 static int dlpar_parse_id_type(char **cmd, struct pseries_hp_errorlog *hp_elog)
0454 {
0455 char *arg;
0456 u32 count, index;
0457
0458 arg = strsep(cmd, " ");
0459 if (!arg)
0460 return -EINVAL;
0461
0462 if (sysfs_streq(arg, "indexed-count")) {
0463 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_IC;
0464 arg = strsep(cmd, " ");
0465 if (!arg) {
0466 pr_err("No DRC count specified.\n");
0467 return -EINVAL;
0468 }
0469
0470 if (kstrtou32(arg, 0, &count)) {
0471 pr_err("Invalid DRC count specified.\n");
0472 return -EINVAL;
0473 }
0474
0475 arg = strsep(cmd, " ");
0476 if (!arg) {
0477 pr_err("No DRC Index specified.\n");
0478 return -EINVAL;
0479 }
0480
0481 if (kstrtou32(arg, 0, &index)) {
0482 pr_err("Invalid DRC Index specified.\n");
0483 return -EINVAL;
0484 }
0485
0486 hp_elog->_drc_u.ic.count = cpu_to_be32(count);
0487 hp_elog->_drc_u.ic.index = cpu_to_be32(index);
0488 } else if (sysfs_streq(arg, "index")) {
0489 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX;
0490 arg = strsep(cmd, " ");
0491 if (!arg) {
0492 pr_err("No DRC Index specified.\n");
0493 return -EINVAL;
0494 }
0495
0496 if (kstrtou32(arg, 0, &index)) {
0497 pr_err("Invalid DRC Index specified.\n");
0498 return -EINVAL;
0499 }
0500
0501 hp_elog->_drc_u.drc_index = cpu_to_be32(index);
0502 } else if (sysfs_streq(arg, "count")) {
0503 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT;
0504 arg = strsep(cmd, " ");
0505 if (!arg) {
0506 pr_err("No DRC count specified.\n");
0507 return -EINVAL;
0508 }
0509
0510 if (kstrtou32(arg, 0, &count)) {
0511 pr_err("Invalid DRC count specified.\n");
0512 return -EINVAL;
0513 }
0514
0515 hp_elog->_drc_u.drc_count = cpu_to_be32(count);
0516 } else {
0517 pr_err("Invalid id_type specified.\n");
0518 return -EINVAL;
0519 }
0520
0521 return 0;
0522 }
0523
0524 static ssize_t dlpar_store(struct class *class, struct class_attribute *attr,
0525 const char *buf, size_t count)
0526 {
0527 struct pseries_hp_errorlog hp_elog;
0528 char *argbuf;
0529 char *args;
0530 int rc;
0531
0532 args = argbuf = kstrdup(buf, GFP_KERNEL);
0533 if (!argbuf)
0534 return -ENOMEM;
0535
0536
0537
0538
0539
0540 rc = dlpar_parse_resource(&args, &hp_elog);
0541 if (rc)
0542 goto dlpar_store_out;
0543
0544 rc = dlpar_parse_action(&args, &hp_elog);
0545 if (rc)
0546 goto dlpar_store_out;
0547
0548 rc = dlpar_parse_id_type(&args, &hp_elog);
0549 if (rc)
0550 goto dlpar_store_out;
0551
0552 rc = handle_dlpar_errorlog(&hp_elog);
0553
0554 dlpar_store_out:
0555 kfree(argbuf);
0556
0557 if (rc)
0558 pr_err("Could not handle DLPAR request \"%s\"\n", buf);
0559
0560 return rc ? rc : count;
0561 }
0562
0563 static ssize_t dlpar_show(struct class *class, struct class_attribute *attr,
0564 char *buf)
0565 {
0566 return sprintf(buf, "%s\n", "memory,cpu");
0567 }
0568
0569 static CLASS_ATTR_RW(dlpar);
0570
0571 int __init dlpar_workqueue_init(void)
0572 {
0573 if (pseries_hp_wq)
0574 return 0;
0575
0576 pseries_hp_wq = alloc_workqueue("pseries hotplug workqueue",
0577 WQ_UNBOUND, 1);
0578
0579 return pseries_hp_wq ? 0 : -ENOMEM;
0580 }
0581
0582 static int __init dlpar_sysfs_init(void)
0583 {
0584 int rc;
0585
0586 rc = dlpar_workqueue_init();
0587 if (rc)
0588 return rc;
0589
0590 return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
0591 }
0592 machine_device_initcall(pseries, dlpar_sysfs_init);
0593