Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Support for dynamic reconfiguration for PCI, Memory, and CPU
0004  * Hotplug and Dynamic Logical Partitioning on RPA platforms.
0005  *
0006  * Copyright (C) 2009 Nathan Fontenot
0007  * Copyright (C) 2009 IBM Corporation
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         /* Since we release the rtas_data_buf lock between configure
0158          * connector calls we want to re-populate the rtas_data_buffer
0159          * with the contents of the previous call.
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     /* pseries error logs are in BE format, convert to cpu type */
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      * Parse out the request from the user, this will be in the form:
0538      * <resource> <action> <id_type> <id>
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