treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 500
[linux-2.6-block.git] / arch / powerpc / platforms / pseries / dlpar.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Support for dynamic reconfiguration for PCI, Memory, and CPU
4  * Hotplug and Dynamic Logical Partitioning on RPA platforms.
5  *
6  * Copyright (C) 2009 Nathan Fontenot
7  * Copyright (C) 2009 IBM Corporation
8  */
9
10 #define pr_fmt(fmt)     "dlpar: " fmt
11
12 #include <linux/kernel.h>
13 #include <linux/notifier.h>
14 #include <linux/spinlock.h>
15 #include <linux/cpu.h>
16 #include <linux/slab.h>
17 #include <linux/of.h>
18
19 #include "of_helpers.h"
20 #include "pseries.h"
21
22 #include <asm/prom.h>
23 #include <asm/machdep.h>
24 #include <linux/uaccess.h>
25 #include <asm/rtas.h>
26
27 static struct workqueue_struct *pseries_hp_wq;
28
29 struct pseries_hp_work {
30         struct work_struct work;
31         struct pseries_hp_errorlog *errlog;
32 };
33
34 struct cc_workarea {
35         __be32  drc_index;
36         __be32  zero;
37         __be32  name_offset;
38         __be32  prop_length;
39         __be32  prop_offset;
40 };
41
42 void dlpar_free_cc_property(struct property *prop)
43 {
44         kfree(prop->name);
45         kfree(prop->value);
46         kfree(prop);
47 }
48
49 static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
50 {
51         struct property *prop;
52         char *name;
53         char *value;
54
55         prop = kzalloc(sizeof(*prop), GFP_KERNEL);
56         if (!prop)
57                 return NULL;
58
59         name = (char *)ccwa + be32_to_cpu(ccwa->name_offset);
60         prop->name = kstrdup(name, GFP_KERNEL);
61
62         prop->length = be32_to_cpu(ccwa->prop_length);
63         value = (char *)ccwa + be32_to_cpu(ccwa->prop_offset);
64         prop->value = kmemdup(value, prop->length, GFP_KERNEL);
65         if (!prop->value) {
66                 dlpar_free_cc_property(prop);
67                 return NULL;
68         }
69
70         return prop;
71 }
72
73 static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa)
74 {
75         struct device_node *dn;
76         const char *name;
77
78         dn = kzalloc(sizeof(*dn), GFP_KERNEL);
79         if (!dn)
80                 return NULL;
81
82         name = (const char *)ccwa + be32_to_cpu(ccwa->name_offset);
83         dn->full_name = kstrdup(name, GFP_KERNEL);
84         if (!dn->full_name) {
85                 kfree(dn);
86                 return NULL;
87         }
88
89         of_node_set_flag(dn, OF_DYNAMIC);
90         of_node_init(dn);
91
92         return dn;
93 }
94
95 static void dlpar_free_one_cc_node(struct device_node *dn)
96 {
97         struct property *prop;
98
99         while (dn->properties) {
100                 prop = dn->properties;
101                 dn->properties = prop->next;
102                 dlpar_free_cc_property(prop);
103         }
104
105         kfree(dn->full_name);
106         kfree(dn);
107 }
108
109 void dlpar_free_cc_nodes(struct device_node *dn)
110 {
111         if (dn->child)
112                 dlpar_free_cc_nodes(dn->child);
113
114         if (dn->sibling)
115                 dlpar_free_cc_nodes(dn->sibling);
116
117         dlpar_free_one_cc_node(dn);
118 }
119
120 #define COMPLETE        0
121 #define NEXT_SIBLING    1
122 #define NEXT_CHILD      2
123 #define NEXT_PROPERTY   3
124 #define PREV_PARENT     4
125 #define MORE_MEMORY     5
126 #define CALL_AGAIN      -2
127 #define ERR_CFG_USE     -9003
128
129 struct device_node *dlpar_configure_connector(__be32 drc_index,
130                                               struct device_node *parent)
131 {
132         struct device_node *dn;
133         struct device_node *first_dn = NULL;
134         struct device_node *last_dn = NULL;
135         struct property *property;
136         struct property *last_property = NULL;
137         struct cc_workarea *ccwa;
138         char *data_buf;
139         int cc_token;
140         int rc = -1;
141
142         cc_token = rtas_token("ibm,configure-connector");
143         if (cc_token == RTAS_UNKNOWN_SERVICE)
144                 return NULL;
145
146         data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
147         if (!data_buf)
148                 return NULL;
149
150         ccwa = (struct cc_workarea *)&data_buf[0];
151         ccwa->drc_index = drc_index;
152         ccwa->zero = 0;
153
154         do {
155                 /* Since we release the rtas_data_buf lock between configure
156                  * connector calls we want to re-populate the rtas_data_buffer
157                  * with the contents of the previous call.
158                  */
159                 spin_lock(&rtas_data_buf_lock);
160
161                 memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE);
162                 rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL);
163                 memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
164
165                 spin_unlock(&rtas_data_buf_lock);
166
167                 switch (rc) {
168                 case COMPLETE:
169                         break;
170
171                 case NEXT_SIBLING:
172                         dn = dlpar_parse_cc_node(ccwa);
173                         if (!dn)
174                                 goto cc_error;
175
176                         dn->parent = last_dn->parent;
177                         last_dn->sibling = dn;
178                         last_dn = dn;
179                         break;
180
181                 case NEXT_CHILD:
182                         dn = dlpar_parse_cc_node(ccwa);
183                         if (!dn)
184                                 goto cc_error;
185
186                         if (!first_dn) {
187                                 dn->parent = parent;
188                                 first_dn = dn;
189                         } else {
190                                 dn->parent = last_dn;
191                                 if (last_dn)
192                                         last_dn->child = dn;
193                         }
194
195                         last_dn = dn;
196                         break;
197
198                 case NEXT_PROPERTY:
199                         property = dlpar_parse_cc_property(ccwa);
200                         if (!property)
201                                 goto cc_error;
202
203                         if (!last_dn->properties)
204                                 last_dn->properties = property;
205                         else
206                                 last_property->next = property;
207
208                         last_property = property;
209                         break;
210
211                 case PREV_PARENT:
212                         last_dn = last_dn->parent;
213                         break;
214
215                 case CALL_AGAIN:
216                         break;
217
218                 case MORE_MEMORY:
219                 case ERR_CFG_USE:
220                 default:
221                         printk(KERN_ERR "Unexpected Error (%d) "
222                                "returned from configure-connector\n", rc);
223                         goto cc_error;
224                 }
225         } while (rc);
226
227 cc_error:
228         kfree(data_buf);
229
230         if (rc) {
231                 if (first_dn)
232                         dlpar_free_cc_nodes(first_dn);
233
234                 return NULL;
235         }
236
237         return first_dn;
238 }
239
240 int dlpar_attach_node(struct device_node *dn, struct device_node *parent)
241 {
242         int rc;
243
244         dn->parent = parent;
245
246         rc = of_attach_node(dn);
247         if (rc) {
248                 printk(KERN_ERR "Failed to add device node %pOF\n", dn);
249                 return rc;
250         }
251
252         return 0;
253 }
254
255 int dlpar_detach_node(struct device_node *dn)
256 {
257         struct device_node *child;
258         int rc;
259
260         child = of_get_next_child(dn, NULL);
261         while (child) {
262                 dlpar_detach_node(child);
263                 child = of_get_next_child(dn, child);
264         }
265
266         rc = of_detach_node(dn);
267         if (rc)
268                 return rc;
269
270         of_node_put(dn);
271
272         return 0;
273 }
274
275 #define DR_ENTITY_SENSE         9003
276 #define DR_ENTITY_PRESENT       1
277 #define DR_ENTITY_UNUSABLE      2
278 #define ALLOCATION_STATE        9003
279 #define ALLOC_UNUSABLE          0
280 #define ALLOC_USABLE            1
281 #define ISOLATION_STATE         9001
282 #define ISOLATE                 0
283 #define UNISOLATE               1
284
285 int dlpar_acquire_drc(u32 drc_index)
286 {
287         int dr_status, rc;
288
289         rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
290                        DR_ENTITY_SENSE, drc_index);
291         if (rc || dr_status != DR_ENTITY_UNUSABLE)
292                 return -1;
293
294         rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE);
295         if (rc)
296                 return rc;
297
298         rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
299         if (rc) {
300                 rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
301                 return rc;
302         }
303
304         return 0;
305 }
306
307 int dlpar_release_drc(u32 drc_index)
308 {
309         int dr_status, rc;
310
311         rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
312                        DR_ENTITY_SENSE, drc_index);
313         if (rc || dr_status != DR_ENTITY_PRESENT)
314                 return -1;
315
316         rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE);
317         if (rc)
318                 return rc;
319
320         rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
321         if (rc) {
322                 rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
323                 return rc;
324         }
325
326         return 0;
327 }
328
329 int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
330 {
331         int rc;
332
333         /* pseries error logs are in BE format, convert to cpu type */
334         switch (hp_elog->id_type) {
335         case PSERIES_HP_ELOG_ID_DRC_COUNT:
336                 hp_elog->_drc_u.drc_count =
337                                 be32_to_cpu(hp_elog->_drc_u.drc_count);
338                 break;
339         case PSERIES_HP_ELOG_ID_DRC_INDEX:
340                 hp_elog->_drc_u.drc_index =
341                                 be32_to_cpu(hp_elog->_drc_u.drc_index);
342                 break;
343         case PSERIES_HP_ELOG_ID_DRC_IC:
344                 hp_elog->_drc_u.ic.count =
345                                 be32_to_cpu(hp_elog->_drc_u.ic.count);
346                 hp_elog->_drc_u.ic.index =
347                                 be32_to_cpu(hp_elog->_drc_u.ic.index);
348         }
349
350         switch (hp_elog->resource) {
351         case PSERIES_HP_ELOG_RESOURCE_MEM:
352                 rc = dlpar_memory(hp_elog);
353                 break;
354         case PSERIES_HP_ELOG_RESOURCE_CPU:
355                 rc = dlpar_cpu(hp_elog);
356                 break;
357         case PSERIES_HP_ELOG_RESOURCE_PMEM:
358                 rc = dlpar_hp_pmem(hp_elog);
359                 break;
360
361         default:
362                 pr_warn_ratelimited("Invalid resource (%d) specified\n",
363                                     hp_elog->resource);
364                 rc = -EINVAL;
365         }
366
367         return rc;
368 }
369
370 static void pseries_hp_work_fn(struct work_struct *work)
371 {
372         struct pseries_hp_work *hp_work =
373                         container_of(work, struct pseries_hp_work, work);
374
375         handle_dlpar_errorlog(hp_work->errlog);
376
377         kfree(hp_work->errlog);
378         kfree((void *)work);
379 }
380
381 void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog)
382 {
383         struct pseries_hp_work *work;
384         struct pseries_hp_errorlog *hp_errlog_copy;
385
386         hp_errlog_copy = kmalloc(sizeof(struct pseries_hp_errorlog),
387                                  GFP_KERNEL);
388         memcpy(hp_errlog_copy, hp_errlog, sizeof(struct pseries_hp_errorlog));
389
390         work = kmalloc(sizeof(struct pseries_hp_work), GFP_KERNEL);
391         if (work) {
392                 INIT_WORK((struct work_struct *)work, pseries_hp_work_fn);
393                 work->errlog = hp_errlog_copy;
394                 queue_work(pseries_hp_wq, (struct work_struct *)work);
395         } else {
396                 kfree(hp_errlog_copy);
397         }
398 }
399
400 static int dlpar_parse_resource(char **cmd, struct pseries_hp_errorlog *hp_elog)
401 {
402         char *arg;
403
404         arg = strsep(cmd, " ");
405         if (!arg)
406                 return -EINVAL;
407
408         if (sysfs_streq(arg, "memory")) {
409                 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
410         } else if (sysfs_streq(arg, "cpu")) {
411                 hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU;
412         } else {
413                 pr_err("Invalid resource specified.\n");
414                 return -EINVAL;
415         }
416
417         return 0;
418 }
419
420 static int dlpar_parse_action(char **cmd, struct pseries_hp_errorlog *hp_elog)
421 {
422         char *arg;
423
424         arg = strsep(cmd, " ");
425         if (!arg)
426                 return -EINVAL;
427
428         if (sysfs_streq(arg, "add")) {
429                 hp_elog->action = PSERIES_HP_ELOG_ACTION_ADD;
430         } else if (sysfs_streq(arg, "remove")) {
431                 hp_elog->action = PSERIES_HP_ELOG_ACTION_REMOVE;
432         } else {
433                 pr_err("Invalid action specified.\n");
434                 return -EINVAL;
435         }
436
437         return 0;
438 }
439
440 static int dlpar_parse_id_type(char **cmd, struct pseries_hp_errorlog *hp_elog)
441 {
442         char *arg;
443         u32 count, index;
444
445         arg = strsep(cmd, " ");
446         if (!arg)
447                 return -EINVAL;
448
449         if (sysfs_streq(arg, "indexed-count")) {
450                 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_IC;
451                 arg = strsep(cmd, " ");
452                 if (!arg) {
453                         pr_err("No DRC count specified.\n");
454                         return -EINVAL;
455                 }
456
457                 if (kstrtou32(arg, 0, &count)) {
458                         pr_err("Invalid DRC count specified.\n");
459                         return -EINVAL;
460                 }
461
462                 arg = strsep(cmd, " ");
463                 if (!arg) {
464                         pr_err("No DRC Index specified.\n");
465                         return -EINVAL;
466                 }
467
468                 if (kstrtou32(arg, 0, &index)) {
469                         pr_err("Invalid DRC Index specified.\n");
470                         return -EINVAL;
471                 }
472
473                 hp_elog->_drc_u.ic.count = cpu_to_be32(count);
474                 hp_elog->_drc_u.ic.index = cpu_to_be32(index);
475         } else if (sysfs_streq(arg, "index")) {
476                 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_INDEX;
477                 arg = strsep(cmd, " ");
478                 if (!arg) {
479                         pr_err("No DRC Index specified.\n");
480                         return -EINVAL;
481                 }
482
483                 if (kstrtou32(arg, 0, &index)) {
484                         pr_err("Invalid DRC Index specified.\n");
485                         return -EINVAL;
486                 }
487
488                 hp_elog->_drc_u.drc_index = cpu_to_be32(index);
489         } else if (sysfs_streq(arg, "count")) {
490                 hp_elog->id_type = PSERIES_HP_ELOG_ID_DRC_COUNT;
491                 arg = strsep(cmd, " ");
492                 if (!arg) {
493                         pr_err("No DRC count specified.\n");
494                         return -EINVAL;
495                 }
496
497                 if (kstrtou32(arg, 0, &count)) {
498                         pr_err("Invalid DRC count specified.\n");
499                         return -EINVAL;
500                 }
501
502                 hp_elog->_drc_u.drc_count = cpu_to_be32(count);
503         } else {
504                 pr_err("Invalid id_type specified.\n");
505                 return -EINVAL;
506         }
507
508         return 0;
509 }
510
511 static ssize_t dlpar_store(struct class *class, struct class_attribute *attr,
512                            const char *buf, size_t count)
513 {
514         struct pseries_hp_errorlog hp_elog;
515         char *argbuf;
516         char *args;
517         int rc;
518
519         args = argbuf = kstrdup(buf, GFP_KERNEL);
520         if (!argbuf) {
521                 pr_info("Could not allocate resources for DLPAR operation\n");
522                 kfree(argbuf);
523                 return -ENOMEM;
524         }
525
526         /*
527          * Parse out the request from the user, this will be in the form:
528          * <resource> <action> <id_type> <id>
529          */
530         rc = dlpar_parse_resource(&args, &hp_elog);
531         if (rc)
532                 goto dlpar_store_out;
533
534         rc = dlpar_parse_action(&args, &hp_elog);
535         if (rc)
536                 goto dlpar_store_out;
537
538         rc = dlpar_parse_id_type(&args, &hp_elog);
539         if (rc)
540                 goto dlpar_store_out;
541
542         rc = handle_dlpar_errorlog(&hp_elog);
543
544 dlpar_store_out:
545         kfree(argbuf);
546
547         if (rc)
548                 pr_err("Could not handle DLPAR request \"%s\"\n", buf);
549
550         return rc ? rc : count;
551 }
552
553 static ssize_t dlpar_show(struct class *class, struct class_attribute *attr,
554                           char *buf)
555 {
556         return sprintf(buf, "%s\n", "memory,cpu");
557 }
558
559 static CLASS_ATTR_RW(dlpar);
560
561 int __init dlpar_workqueue_init(void)
562 {
563         if (pseries_hp_wq)
564                 return 0;
565
566         pseries_hp_wq = alloc_workqueue("pseries hotplug workqueue",
567                         WQ_UNBOUND, 1);
568
569         return pseries_hp_wq ? 0 : -ENOMEM;
570 }
571
572 static int __init dlpar_sysfs_init(void)
573 {
574         int rc;
575
576         rc = dlpar_workqueue_init();
577         if (rc)
578                 return rc;
579
580         return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
581 }
582 machine_device_initcall(pseries, dlpar_sysfs_init);
583