1ab519a01SNathan Fontenot /* 2ab519a01SNathan Fontenot * Support for dynamic reconfiguration for PCI, Memory, and CPU 3ab519a01SNathan Fontenot * Hotplug and Dynamic Logical Partitioning on RPA platforms. 4ab519a01SNathan Fontenot * 5ab519a01SNathan Fontenot * Copyright (C) 2009 Nathan Fontenot 6ab519a01SNathan Fontenot * Copyright (C) 2009 IBM Corporation 7ab519a01SNathan Fontenot * 8ab519a01SNathan Fontenot * This program is free software; you can redistribute it and/or 9ab519a01SNathan Fontenot * modify it under the terms of the GNU General Public License version 10ab519a01SNathan Fontenot * 2 as published by the Free Software Foundation. 11ab519a01SNathan Fontenot */ 12ab519a01SNathan Fontenot 13999e2dadSNathan Fontenot #define pr_fmt(fmt) "dlpar: " fmt 14999e2dadSNathan Fontenot 15ab519a01SNathan Fontenot #include <linux/kernel.h> 16ab519a01SNathan Fontenot #include <linux/notifier.h> 17ab519a01SNathan Fontenot #include <linux/spinlock.h> 18ab519a01SNathan Fontenot #include <linux/cpu.h> 195a0e3ad6STejun Heo #include <linux/slab.h> 201cf3d8b3SNathan Fontenot #include <linux/of.h> 2106bacefcSAndy Shevchenko 2206bacefcSAndy Shevchenko #include "of_helpers.h" 231217d34bSAnton Blanchard #include "pseries.h" 24ab519a01SNathan Fontenot 25ab519a01SNathan Fontenot #include <asm/prom.h> 26ab519a01SNathan Fontenot #include <asm/machdep.h> 27ab519a01SNathan Fontenot #include <asm/uaccess.h> 28ab519a01SNathan Fontenot #include <asm/rtas.h> 29ab519a01SNathan Fontenot 30ab519a01SNathan Fontenot struct cc_workarea { 31d6f1e7abSBharata B Rao __be32 drc_index; 32d6f1e7abSBharata B Rao __be32 zero; 33d6f1e7abSBharata B Rao __be32 name_offset; 34d6f1e7abSBharata B Rao __be32 prop_length; 35d6f1e7abSBharata B Rao __be32 prop_offset; 36ab519a01SNathan Fontenot }; 37ab519a01SNathan Fontenot 3820648974SNathan Fontenot void dlpar_free_cc_property(struct property *prop) 39ab519a01SNathan Fontenot { 40ab519a01SNathan Fontenot kfree(prop->name); 41ab519a01SNathan Fontenot kfree(prop->value); 42ab519a01SNathan Fontenot kfree(prop); 43ab519a01SNathan Fontenot } 44ab519a01SNathan Fontenot 45ab519a01SNathan Fontenot static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa) 46ab519a01SNathan Fontenot { 47ab519a01SNathan Fontenot struct property *prop; 48ab519a01SNathan Fontenot char *name; 49ab519a01SNathan Fontenot char *value; 50ab519a01SNathan Fontenot 51ab519a01SNathan Fontenot prop = kzalloc(sizeof(*prop), GFP_KERNEL); 52ab519a01SNathan Fontenot if (!prop) 53ab519a01SNathan Fontenot return NULL; 54ab519a01SNathan Fontenot 55d6f1e7abSBharata B Rao name = (char *)ccwa + be32_to_cpu(ccwa->name_offset); 56ab519a01SNathan Fontenot prop->name = kstrdup(name, GFP_KERNEL); 57ab519a01SNathan Fontenot 58d6f1e7abSBharata B Rao prop->length = be32_to_cpu(ccwa->prop_length); 59d6f1e7abSBharata B Rao value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset); 60e72ed6b5SNishanth Aravamudan prop->value = kmemdup(value, prop->length, GFP_KERNEL); 61ab519a01SNathan Fontenot if (!prop->value) { 62ab519a01SNathan Fontenot dlpar_free_cc_property(prop); 63ab519a01SNathan Fontenot return NULL; 64ab519a01SNathan Fontenot } 65ab519a01SNathan Fontenot 66ab519a01SNathan Fontenot return prop; 67ab519a01SNathan Fontenot } 68ab519a01SNathan Fontenot 698d5ff320STyrel Datwyler static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa, 708d5ff320STyrel Datwyler const char *path) 71ab519a01SNathan Fontenot { 72ab519a01SNathan Fontenot struct device_node *dn; 73ab519a01SNathan Fontenot char *name; 74ab519a01SNathan Fontenot 758d5ff320STyrel Datwyler /* If parent node path is "/" advance path to NULL terminator to 768d5ff320STyrel Datwyler * prevent double leading slashs in full_name. 778d5ff320STyrel Datwyler */ 788d5ff320STyrel Datwyler if (!path[1]) 798d5ff320STyrel Datwyler path++; 808d5ff320STyrel Datwyler 81ab519a01SNathan Fontenot dn = kzalloc(sizeof(*dn), GFP_KERNEL); 82ab519a01SNathan Fontenot if (!dn) 83ab519a01SNathan Fontenot return NULL; 84ab519a01SNathan Fontenot 85d6f1e7abSBharata B Rao name = (char *)ccwa + be32_to_cpu(ccwa->name_offset); 868d5ff320STyrel Datwyler dn->full_name = kasprintf(GFP_KERNEL, "%s/%s", path, name); 87ab519a01SNathan Fontenot if (!dn->full_name) { 88ab519a01SNathan Fontenot kfree(dn); 89ab519a01SNathan Fontenot return NULL; 90ab519a01SNathan Fontenot } 91ab519a01SNathan Fontenot 921578cb76STyrel Datwyler of_node_set_flag(dn, OF_DYNAMIC); 9397a9a717STyrel Datwyler of_node_init(dn); 941578cb76STyrel Datwyler 95ab519a01SNathan Fontenot return dn; 96ab519a01SNathan Fontenot } 97ab519a01SNathan Fontenot 98ab519a01SNathan Fontenot static void dlpar_free_one_cc_node(struct device_node *dn) 99ab519a01SNathan Fontenot { 100ab519a01SNathan Fontenot struct property *prop; 101ab519a01SNathan Fontenot 102ab519a01SNathan Fontenot while (dn->properties) { 103ab519a01SNathan Fontenot prop = dn->properties; 104ab519a01SNathan Fontenot dn->properties = prop->next; 105ab519a01SNathan Fontenot dlpar_free_cc_property(prop); 106ab519a01SNathan Fontenot } 107ab519a01SNathan Fontenot 108ab519a01SNathan Fontenot kfree(dn->full_name); 109ab519a01SNathan Fontenot kfree(dn); 110ab519a01SNathan Fontenot } 111ab519a01SNathan Fontenot 11220648974SNathan Fontenot void dlpar_free_cc_nodes(struct device_node *dn) 113ab519a01SNathan Fontenot { 114ab519a01SNathan Fontenot if (dn->child) 115ab519a01SNathan Fontenot dlpar_free_cc_nodes(dn->child); 116ab519a01SNathan Fontenot 117ab519a01SNathan Fontenot if (dn->sibling) 118ab519a01SNathan Fontenot dlpar_free_cc_nodes(dn->sibling); 119ab519a01SNathan Fontenot 120ab519a01SNathan Fontenot dlpar_free_one_cc_node(dn); 121ab519a01SNathan Fontenot } 122ab519a01SNathan Fontenot 1239c740025SAnton Blanchard #define COMPLETE 0 124ab519a01SNathan Fontenot #define NEXT_SIBLING 1 125ab519a01SNathan Fontenot #define NEXT_CHILD 2 126ab519a01SNathan Fontenot #define NEXT_PROPERTY 3 127ab519a01SNathan Fontenot #define PREV_PARENT 4 128ab519a01SNathan Fontenot #define MORE_MEMORY 5 129ab519a01SNathan Fontenot #define CALL_AGAIN -2 130ab519a01SNathan Fontenot #define ERR_CFG_USE -9003 131ab519a01SNathan Fontenot 132d6f1e7abSBharata B Rao struct device_node *dlpar_configure_connector(__be32 drc_index, 1338d5ff320STyrel Datwyler struct device_node *parent) 134ab519a01SNathan Fontenot { 135ab519a01SNathan Fontenot struct device_node *dn; 136ab519a01SNathan Fontenot struct device_node *first_dn = NULL; 137ab519a01SNathan Fontenot struct device_node *last_dn = NULL; 138ab519a01SNathan Fontenot struct property *property; 139ab519a01SNathan Fontenot struct property *last_property = NULL; 140ab519a01SNathan Fontenot struct cc_workarea *ccwa; 14193f68f1eSNathan Fontenot char *data_buf; 1428d5ff320STyrel Datwyler const char *parent_path = parent->full_name; 143ab519a01SNathan Fontenot int cc_token; 14493f68f1eSNathan Fontenot int rc = -1; 145ab519a01SNathan Fontenot 146ab519a01SNathan Fontenot cc_token = rtas_token("ibm,configure-connector"); 147ab519a01SNathan Fontenot if (cc_token == RTAS_UNKNOWN_SERVICE) 148ab519a01SNathan Fontenot return NULL; 149ab519a01SNathan Fontenot 15093f68f1eSNathan Fontenot data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); 15193f68f1eSNathan Fontenot if (!data_buf) 15293f68f1eSNathan Fontenot return NULL; 15393f68f1eSNathan Fontenot 15493f68f1eSNathan Fontenot ccwa = (struct cc_workarea *)&data_buf[0]; 155ab519a01SNathan Fontenot ccwa->drc_index = drc_index; 156ab519a01SNathan Fontenot ccwa->zero = 0; 157ab519a01SNathan Fontenot 15893f68f1eSNathan Fontenot do { 15993f68f1eSNathan Fontenot /* Since we release the rtas_data_buf lock between configure 16093f68f1eSNathan Fontenot * connector calls we want to re-populate the rtas_data_buffer 16193f68f1eSNathan Fontenot * with the contents of the previous call. 16293f68f1eSNathan Fontenot */ 16393f68f1eSNathan Fontenot spin_lock(&rtas_data_buf_lock); 16493f68f1eSNathan Fontenot 16593f68f1eSNathan Fontenot memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE); 166ab519a01SNathan Fontenot rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); 16793f68f1eSNathan Fontenot memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); 16893f68f1eSNathan Fontenot 16993f68f1eSNathan Fontenot spin_unlock(&rtas_data_buf_lock); 17093f68f1eSNathan Fontenot 171ab519a01SNathan Fontenot switch (rc) { 1729c740025SAnton Blanchard case COMPLETE: 1739c740025SAnton Blanchard break; 1749c740025SAnton Blanchard 175ab519a01SNathan Fontenot case NEXT_SIBLING: 1768d5ff320STyrel Datwyler dn = dlpar_parse_cc_node(ccwa, parent_path); 177ab519a01SNathan Fontenot if (!dn) 178ab519a01SNathan Fontenot goto cc_error; 179ab519a01SNathan Fontenot 180ab519a01SNathan Fontenot dn->parent = last_dn->parent; 181ab519a01SNathan Fontenot last_dn->sibling = dn; 182ab519a01SNathan Fontenot last_dn = dn; 183ab519a01SNathan Fontenot break; 184ab519a01SNathan Fontenot 185ab519a01SNathan Fontenot case NEXT_CHILD: 1868d5ff320STyrel Datwyler if (first_dn) 1878d5ff320STyrel Datwyler parent_path = last_dn->full_name; 1888d5ff320STyrel Datwyler 1898d5ff320STyrel Datwyler dn = dlpar_parse_cc_node(ccwa, parent_path); 190ab519a01SNathan Fontenot if (!dn) 191ab519a01SNathan Fontenot goto cc_error; 192ab519a01SNathan Fontenot 1938d5ff320STyrel Datwyler if (!first_dn) { 1948d5ff320STyrel Datwyler dn->parent = parent; 195ab519a01SNathan Fontenot first_dn = dn; 1968d5ff320STyrel Datwyler } else { 197ab519a01SNathan Fontenot dn->parent = last_dn; 198ab519a01SNathan Fontenot if (last_dn) 199ab519a01SNathan Fontenot last_dn->child = dn; 200ab519a01SNathan Fontenot } 201ab519a01SNathan Fontenot 202ab519a01SNathan Fontenot last_dn = dn; 203ab519a01SNathan Fontenot break; 204ab519a01SNathan Fontenot 205ab519a01SNathan Fontenot case NEXT_PROPERTY: 206ab519a01SNathan Fontenot property = dlpar_parse_cc_property(ccwa); 207ab519a01SNathan Fontenot if (!property) 208ab519a01SNathan Fontenot goto cc_error; 209ab519a01SNathan Fontenot 210ab519a01SNathan Fontenot if (!last_dn->properties) 211ab519a01SNathan Fontenot last_dn->properties = property; 212ab519a01SNathan Fontenot else 213ab519a01SNathan Fontenot last_property->next = property; 214ab519a01SNathan Fontenot 215ab519a01SNathan Fontenot last_property = property; 216ab519a01SNathan Fontenot break; 217ab519a01SNathan Fontenot 218ab519a01SNathan Fontenot case PREV_PARENT: 219ab519a01SNathan Fontenot last_dn = last_dn->parent; 2208d5ff320STyrel Datwyler parent_path = last_dn->parent->full_name; 221ab519a01SNathan Fontenot break; 222ab519a01SNathan Fontenot 223ab519a01SNathan Fontenot case CALL_AGAIN: 224ab519a01SNathan Fontenot break; 225ab519a01SNathan Fontenot 226ab519a01SNathan Fontenot case MORE_MEMORY: 227ab519a01SNathan Fontenot case ERR_CFG_USE: 228ab519a01SNathan Fontenot default: 229ab519a01SNathan Fontenot printk(KERN_ERR "Unexpected Error (%d) " 230ab519a01SNathan Fontenot "returned from configure-connector\n", rc); 231ab519a01SNathan Fontenot goto cc_error; 232ab519a01SNathan Fontenot } 23393f68f1eSNathan Fontenot } while (rc); 234ab519a01SNathan Fontenot 235ab519a01SNathan Fontenot cc_error: 23693f68f1eSNathan Fontenot kfree(data_buf); 23793f68f1eSNathan Fontenot 23893f68f1eSNathan Fontenot if (rc) { 239ab519a01SNathan Fontenot if (first_dn) 240ab519a01SNathan Fontenot dlpar_free_cc_nodes(first_dn); 24193f68f1eSNathan Fontenot 242ab519a01SNathan Fontenot return NULL; 243ab519a01SNathan Fontenot } 244ab519a01SNathan Fontenot 24593f68f1eSNathan Fontenot return first_dn; 24693f68f1eSNathan Fontenot } 24793f68f1eSNathan Fontenot 248ab519a01SNathan Fontenot int dlpar_attach_node(struct device_node *dn) 249ab519a01SNathan Fontenot { 250ab519a01SNathan Fontenot int rc; 251ab519a01SNathan Fontenot 25206bacefcSAndy Shevchenko dn->parent = pseries_of_derive_parent(dn->full_name); 25306bacefcSAndy Shevchenko if (IS_ERR(dn->parent)) 25406bacefcSAndy Shevchenko return PTR_ERR(dn->parent); 255ab519a01SNathan Fontenot 2561cf3d8b3SNathan Fontenot rc = of_attach_node(dn); 2573aef19f0SAkinobu Mita if (rc) { 258ab519a01SNathan Fontenot printk(KERN_ERR "Failed to add device node %s\n", 259ab519a01SNathan Fontenot dn->full_name); 2603aef19f0SAkinobu Mita return rc; 261ab519a01SNathan Fontenot } 262ab519a01SNathan Fontenot 263ab519a01SNathan Fontenot of_node_put(dn->parent); 264ab519a01SNathan Fontenot return 0; 265ab519a01SNathan Fontenot } 266ab519a01SNathan Fontenot 267ab519a01SNathan Fontenot int dlpar_detach_node(struct device_node *dn) 268ab519a01SNathan Fontenot { 2695935ff43STyrel Datwyler struct device_node *child; 2701cf3d8b3SNathan Fontenot int rc; 271ab519a01SNathan Fontenot 2725935ff43STyrel Datwyler child = of_get_next_child(dn, NULL); 2735935ff43STyrel Datwyler while (child) { 2745935ff43STyrel Datwyler dlpar_detach_node(child); 2755935ff43STyrel Datwyler child = of_get_next_child(dn, child); 2765935ff43STyrel Datwyler } 2775935ff43STyrel Datwyler 2781cf3d8b3SNathan Fontenot rc = of_detach_node(dn); 2791cf3d8b3SNathan Fontenot if (rc) 2801cf3d8b3SNathan Fontenot return rc; 2811cf3d8b3SNathan Fontenot 2821cf3d8b3SNathan Fontenot of_node_put(dn); /* Must decrement the refcount */ 283ab519a01SNathan Fontenot return 0; 284ab519a01SNathan Fontenot } 285ab519a01SNathan Fontenot 286ab519a01SNathan Fontenot #define DR_ENTITY_SENSE 9003 287ab519a01SNathan Fontenot #define DR_ENTITY_PRESENT 1 288ab519a01SNathan Fontenot #define DR_ENTITY_UNUSABLE 2 289ab519a01SNathan Fontenot #define ALLOCATION_STATE 9003 290ab519a01SNathan Fontenot #define ALLOC_UNUSABLE 0 291ab519a01SNathan Fontenot #define ALLOC_USABLE 1 292ab519a01SNathan Fontenot #define ISOLATION_STATE 9001 293ab519a01SNathan Fontenot #define ISOLATE 0 294ab519a01SNathan Fontenot #define UNISOLATE 1 295ab519a01SNathan Fontenot 296ab519a01SNathan Fontenot int dlpar_acquire_drc(u32 drc_index) 297ab519a01SNathan Fontenot { 298ab519a01SNathan Fontenot int dr_status, rc; 299ab519a01SNathan Fontenot 300ab519a01SNathan Fontenot rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, 301ab519a01SNathan Fontenot DR_ENTITY_SENSE, drc_index); 302ab519a01SNathan Fontenot if (rc || dr_status != DR_ENTITY_UNUSABLE) 303ab519a01SNathan Fontenot return -1; 304ab519a01SNathan Fontenot 305ab519a01SNathan Fontenot rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE); 306ab519a01SNathan Fontenot if (rc) 307ab519a01SNathan Fontenot return rc; 308ab519a01SNathan Fontenot 309ab519a01SNathan Fontenot rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 310ab519a01SNathan Fontenot if (rc) { 311ab519a01SNathan Fontenot rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 312ab519a01SNathan Fontenot return rc; 313ab519a01SNathan Fontenot } 314ab519a01SNathan Fontenot 315ab519a01SNathan Fontenot return 0; 316ab519a01SNathan Fontenot } 317ab519a01SNathan Fontenot 318ab519a01SNathan Fontenot int dlpar_release_drc(u32 drc_index) 319ab519a01SNathan Fontenot { 320ab519a01SNathan Fontenot int dr_status, rc; 321ab519a01SNathan Fontenot 322ab519a01SNathan Fontenot rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, 323ab519a01SNathan Fontenot DR_ENTITY_SENSE, drc_index); 324ab519a01SNathan Fontenot if (rc || dr_status != DR_ENTITY_PRESENT) 325ab519a01SNathan Fontenot return -1; 326ab519a01SNathan Fontenot 327ab519a01SNathan Fontenot rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE); 328ab519a01SNathan Fontenot if (rc) 329ab519a01SNathan Fontenot return rc; 330ab519a01SNathan Fontenot 331ab519a01SNathan Fontenot rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); 332ab519a01SNathan Fontenot if (rc) { 333ab519a01SNathan Fontenot rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); 334ab519a01SNathan Fontenot return rc; 335ab519a01SNathan Fontenot } 336ab519a01SNathan Fontenot 337ab519a01SNathan Fontenot return 0; 338ab519a01SNathan Fontenot } 339ab519a01SNathan Fontenot 340999e2dadSNathan Fontenot static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) 341999e2dadSNathan Fontenot { 342999e2dadSNathan Fontenot int rc; 343999e2dadSNathan Fontenot 344999e2dadSNathan Fontenot /* pseries error logs are in BE format, convert to cpu type */ 345999e2dadSNathan Fontenot switch (hp_elog->id_type) { 346999e2dadSNathan Fontenot case PSERIES_HP_ELOG_ID_DRC_COUNT: 347999e2dadSNathan Fontenot hp_elog->_drc_u.drc_count = 348999e2dadSNathan Fontenot be32_to_cpu(hp_elog->_drc_u.drc_count); 349999e2dadSNathan Fontenot break; 350999e2dadSNathan Fontenot case PSERIES_HP_ELOG_ID_DRC_INDEX: 351999e2dadSNathan Fontenot hp_elog->_drc_u.drc_index = 352999e2dadSNathan Fontenot be32_to_cpu(hp_elog->_drc_u.drc_index); 353999e2dadSNathan Fontenot } 354999e2dadSNathan Fontenot 355999e2dadSNathan Fontenot switch (hp_elog->resource) { 356999e2dadSNathan Fontenot case PSERIES_HP_ELOG_RESOURCE_MEM: 357999e2dadSNathan Fontenot rc = dlpar_memory(hp_elog); 358999e2dadSNathan Fontenot break; 359*e9d764f8SNathan Fontenot case PSERIES_HP_ELOG_RESOURCE_CPU: 360*e9d764f8SNathan Fontenot rc = dlpar_cpu(hp_elog); 361*e9d764f8SNathan Fontenot break; 362999e2dadSNathan Fontenot default: 363999e2dadSNathan Fontenot pr_warn_ratelimited("Invalid resource (%d) specified\n", 364999e2dadSNathan Fontenot hp_elog->resource); 365999e2dadSNathan Fontenot rc = -EINVAL; 366999e2dadSNathan Fontenot } 367999e2dadSNathan Fontenot 368999e2dadSNathan Fontenot return rc; 369999e2dadSNathan Fontenot } 370999e2dadSNathan Fontenot 371999e2dadSNathan Fontenot static ssize_t dlpar_store(struct class *class, struct class_attribute *attr, 372999e2dadSNathan Fontenot const char *buf, size_t count) 373999e2dadSNathan Fontenot { 374999e2dadSNathan Fontenot struct pseries_hp_errorlog *hp_elog; 375999e2dadSNathan Fontenot const char *arg; 376999e2dadSNathan Fontenot int rc; 377999e2dadSNathan Fontenot 378999e2dadSNathan Fontenot hp_elog = kzalloc(sizeof(*hp_elog), GFP_KERNEL); 379999e2dadSNathan Fontenot if (!hp_elog) { 380999e2dadSNathan Fontenot rc = -ENOMEM; 381999e2dadSNathan Fontenot goto dlpar_store_out; 382999e2dadSNathan Fontenot } 383999e2dadSNathan Fontenot 384999e2dadSNathan Fontenot /* Parse out the request from the user, this will be in the form 385999e2dadSNathan Fontenot * <resource> <action> <id_type> <id> 386999e2dadSNathan Fontenot */ 387999e2dadSNathan Fontenot arg = buf; 388999e2dadSNathan Fontenot if (!strncmp(arg, "memory", 6)) { 389999e2dadSNathan Fontenot hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM; 390999e2dadSNathan Fontenot arg += strlen("memory "); 391*e9d764f8SNathan Fontenot } else if (!strncmp(arg, "cpu", 3)) { 392*e9d764f8SNathan Fontenot hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU; 393*e9d764f8SNathan Fontenot arg += strlen("cpu "); 394999e2dadSNathan Fontenot } else { 395999e2dadSNathan Fontenot pr_err("Invalid resource specified: \"%s\"\n", buf); 396999e2dadSNathan Fontenot rc = -EINVAL; 397999e2dadSNathan Fontenot goto dlpar_store_out; 398999e2dadSNathan Fontenot } 399999e2dadSNathan Fontenot 400999e2dadSNathan Fontenot if (!strncmp(arg, "add", 3)) { 401999e2dadSNathan Fontenot hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD; 402999e2dadSNathan Fontenot arg += strlen("add "); 403999e2dadSNathan Fontenot } else if (!strncmp(arg, "remove", 6)) { 404999e2dadSNathan Fontenot hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE; 405999e2dadSNathan Fontenot arg += strlen("remove "); 406999e2dadSNathan Fontenot } else { 407999e2dadSNathan Fontenot pr_err("Invalid action specified: \"%s\"\n", buf); 408999e2dadSNathan Fontenot rc = -EINVAL; 409999e2dadSNathan Fontenot goto dlpar_store_out; 410999e2dadSNathan Fontenot } 411999e2dadSNathan Fontenot 412999e2dadSNathan Fontenot if (!strncmp(arg, "index", 5)) { 413999e2dadSNathan Fontenot u32 index; 414999e2dadSNathan Fontenot 415999e2dadSNathan Fontenot hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX; 416999e2dadSNathan Fontenot arg += strlen("index "); 417999e2dadSNathan Fontenot if (kstrtou32(arg, 0, &index)) { 418999e2dadSNathan Fontenot rc = -EINVAL; 419999e2dadSNathan Fontenot pr_err("Invalid drc_index specified: \"%s\"\n", buf); 420999e2dadSNathan Fontenot goto dlpar_store_out; 421999e2dadSNathan Fontenot } 422999e2dadSNathan Fontenot 423999e2dadSNathan Fontenot hp_elog->_drc_u.drc_index = cpu_to_be32(index); 424999e2dadSNathan Fontenot } else if (!strncmp(arg, "count", 5)) { 425999e2dadSNathan Fontenot u32 count; 426999e2dadSNathan Fontenot 427999e2dadSNathan Fontenot hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT; 428999e2dadSNathan Fontenot arg += strlen("count "); 429999e2dadSNathan Fontenot if (kstrtou32(arg, 0, &count)) { 430999e2dadSNathan Fontenot rc = -EINVAL; 431999e2dadSNathan Fontenot pr_err("Invalid count specified: \"%s\"\n", buf); 432999e2dadSNathan Fontenot goto dlpar_store_out; 433999e2dadSNathan Fontenot } 434999e2dadSNathan Fontenot 435999e2dadSNathan Fontenot hp_elog->_drc_u.drc_count = cpu_to_be32(count); 436999e2dadSNathan Fontenot } else { 437999e2dadSNathan Fontenot pr_err("Invalid id_type specified: \"%s\"\n", buf); 438999e2dadSNathan Fontenot rc = -EINVAL; 439999e2dadSNathan Fontenot goto dlpar_store_out; 440999e2dadSNathan Fontenot } 441999e2dadSNathan Fontenot 442999e2dadSNathan Fontenot rc = handle_dlpar_errorlog(hp_elog); 443999e2dadSNathan Fontenot 444999e2dadSNathan Fontenot dlpar_store_out: 445999e2dadSNathan Fontenot kfree(hp_elog); 446999e2dadSNathan Fontenot return rc ? rc : count; 447999e2dadSNathan Fontenot } 448999e2dadSNathan Fontenot 449999e2dadSNathan Fontenot static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store); 450999e2dadSNathan Fontenot 4511a8061c4SNathan Fontenot static int __init pseries_dlpar_init(void) 4521a8061c4SNathan Fontenot { 453183deeeaSNathan Fontenot return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr); 4541a8061c4SNathan Fontenot } 4551a8061c4SNathan Fontenot machine_device_initcall(pseries, pseries_dlpar_init); 4561a8061c4SNathan Fontenot 457