spnego: add missing OID to oid registry
[sfrench/cifs-2.6.git] / arch / powerpc / platforms / pseries / hotplug-memory.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * pseries Memory Hotplug infrastructure.
4  *
5  * Copyright (C) 2008 Badari Pulavarty, IBM Corporation
6  */
7
8 #define pr_fmt(fmt)     "pseries-hotplug-mem: " fmt
9
10 #include <linux/of.h>
11 #include <linux/of_address.h>
12 #include <linux/memblock.h>
13 #include <linux/memory.h>
14 #include <linux/memory_hotplug.h>
15 #include <linux/slab.h>
16
17 #include <asm/firmware.h>
18 #include <asm/machdep.h>
19 #include <asm/sparsemem.h>
20 #include <asm/fadump.h>
21 #include <asm/drmem.h>
22 #include "pseries.h"
23
24 unsigned long pseries_memory_block_size(void)
25 {
26         struct device_node *np;
27         u64 memblock_size = MIN_MEMORY_BLOCK_SIZE;
28         struct resource r;
29
30         np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
31         if (np) {
32                 int len;
33                 int size_cells;
34                 const __be32 *prop;
35
36                 size_cells = of_n_size_cells(np);
37
38                 prop = of_get_property(np, "ibm,lmb-size", &len);
39                 if (prop && len >= size_cells * sizeof(__be32))
40                         memblock_size = of_read_number(prop, size_cells);
41                 of_node_put(np);
42
43         } else  if (machine_is(pseries)) {
44                 /* This fallback really only applies to pseries */
45                 unsigned int memzero_size = 0;
46
47                 np = of_find_node_by_path("/memory@0");
48                 if (np) {
49                         if (!of_address_to_resource(np, 0, &r))
50                                 memzero_size = resource_size(&r);
51                         of_node_put(np);
52                 }
53
54                 if (memzero_size) {
55                         /* We now know the size of memory@0, use this to find
56                          * the first memoryblock and get its size.
57                          */
58                         char buf[64];
59
60                         sprintf(buf, "/memory@%x", memzero_size);
61                         np = of_find_node_by_path(buf);
62                         if (np) {
63                                 if (!of_address_to_resource(np, 0, &r))
64                                         memblock_size = resource_size(&r);
65                                 of_node_put(np);
66                         }
67                 }
68         }
69         return memblock_size;
70 }
71
72 static void dlpar_free_property(struct property *prop)
73 {
74         kfree(prop->name);
75         kfree(prop->value);
76         kfree(prop);
77 }
78
79 static struct property *dlpar_clone_property(struct property *prop,
80                                              u32 prop_size)
81 {
82         struct property *new_prop;
83
84         new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
85         if (!new_prop)
86                 return NULL;
87
88         new_prop->name = kstrdup(prop->name, GFP_KERNEL);
89         new_prop->value = kzalloc(prop_size, GFP_KERNEL);
90         if (!new_prop->name || !new_prop->value) {
91                 dlpar_free_property(new_prop);
92                 return NULL;
93         }
94
95         memcpy(new_prop->value, prop->value, prop->length);
96         new_prop->length = prop_size;
97
98         of_property_set_flag(new_prop, OF_DYNAMIC);
99         return new_prop;
100 }
101
102 static bool find_aa_index(struct device_node *dr_node,
103                          struct property *ala_prop,
104                          const u32 *lmb_assoc, u32 *aa_index)
105 {
106         u32 *assoc_arrays, new_prop_size;
107         struct property *new_prop;
108         int aa_arrays, aa_array_entries, aa_array_sz;
109         int i, index;
110
111         /*
112          * The ibm,associativity-lookup-arrays property is defined to be
113          * a 32-bit value specifying the number of associativity arrays
114          * followed by a 32-bitvalue specifying the number of entries per
115          * array, followed by the associativity arrays.
116          */
117         assoc_arrays = ala_prop->value;
118
119         aa_arrays = be32_to_cpu(assoc_arrays[0]);
120         aa_array_entries = be32_to_cpu(assoc_arrays[1]);
121         aa_array_sz = aa_array_entries * sizeof(u32);
122
123         for (i = 0; i < aa_arrays; i++) {
124                 index = (i * aa_array_entries) + 2;
125
126                 if (memcmp(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz))
127                         continue;
128
129                 *aa_index = i;
130                 return true;
131         }
132
133         new_prop_size = ala_prop->length + aa_array_sz;
134         new_prop = dlpar_clone_property(ala_prop, new_prop_size);
135         if (!new_prop)
136                 return false;
137
138         assoc_arrays = new_prop->value;
139
140         /* increment the number of entries in the lookup array */
141         assoc_arrays[0] = cpu_to_be32(aa_arrays + 1);
142
143         /* copy the new associativity into the lookup array */
144         index = aa_arrays * aa_array_entries + 2;
145         memcpy(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz);
146
147         of_update_property(dr_node, new_prop);
148
149         /*
150          * The associativity lookup array index for this lmb is
151          * number of entries - 1 since we added its associativity
152          * to the end of the lookup array.
153          */
154         *aa_index = be32_to_cpu(assoc_arrays[0]) - 1;
155         return true;
156 }
157
158 static int update_lmb_associativity_index(struct drmem_lmb *lmb)
159 {
160         struct device_node *parent, *lmb_node, *dr_node;
161         struct property *ala_prop;
162         const u32 *lmb_assoc;
163         u32 aa_index;
164         bool found;
165
166         parent = of_find_node_by_path("/");
167         if (!parent)
168                 return -ENODEV;
169
170         lmb_node = dlpar_configure_connector(cpu_to_be32(lmb->drc_index),
171                                              parent);
172         of_node_put(parent);
173         if (!lmb_node)
174                 return -EINVAL;
175
176         lmb_assoc = of_get_property(lmb_node, "ibm,associativity", NULL);
177         if (!lmb_assoc) {
178                 dlpar_free_cc_nodes(lmb_node);
179                 return -ENODEV;
180         }
181
182         update_numa_distance(lmb_node);
183
184         dr_node = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
185         if (!dr_node) {
186                 dlpar_free_cc_nodes(lmb_node);
187                 return -ENODEV;
188         }
189
190         ala_prop = of_find_property(dr_node, "ibm,associativity-lookup-arrays",
191                                     NULL);
192         if (!ala_prop) {
193                 of_node_put(dr_node);
194                 dlpar_free_cc_nodes(lmb_node);
195                 return -ENODEV;
196         }
197
198         found = find_aa_index(dr_node, ala_prop, lmb_assoc, &aa_index);
199
200         of_node_put(dr_node);
201         dlpar_free_cc_nodes(lmb_node);
202
203         if (!found) {
204                 pr_err("Could not find LMB associativity\n");
205                 return -1;
206         }
207
208         lmb->aa_index = aa_index;
209         return 0;
210 }
211
212 static struct memory_block *lmb_to_memblock(struct drmem_lmb *lmb)
213 {
214         unsigned long section_nr;
215         struct memory_block *mem_block;
216
217         section_nr = pfn_to_section_nr(PFN_DOWN(lmb->base_addr));
218
219         mem_block = find_memory_block(section_nr);
220         return mem_block;
221 }
222
223 static int get_lmb_range(u32 drc_index, int n_lmbs,
224                          struct drmem_lmb **start_lmb,
225                          struct drmem_lmb **end_lmb)
226 {
227         struct drmem_lmb *lmb, *start, *end;
228         struct drmem_lmb *limit;
229
230         start = NULL;
231         for_each_drmem_lmb(lmb) {
232                 if (lmb->drc_index == drc_index) {
233                         start = lmb;
234                         break;
235                 }
236         }
237
238         if (!start)
239                 return -EINVAL;
240
241         end = &start[n_lmbs];
242
243         limit = &drmem_info->lmbs[drmem_info->n_lmbs];
244         if (end > limit)
245                 return -EINVAL;
246
247         *start_lmb = start;
248         *end_lmb = end;
249         return 0;
250 }
251
252 static int dlpar_change_lmb_state(struct drmem_lmb *lmb, bool online)
253 {
254         struct memory_block *mem_block;
255         int rc;
256
257         mem_block = lmb_to_memblock(lmb);
258         if (!mem_block)
259                 return -EINVAL;
260
261         if (online && mem_block->dev.offline)
262                 rc = device_online(&mem_block->dev);
263         else if (!online && !mem_block->dev.offline)
264                 rc = device_offline(&mem_block->dev);
265         else
266                 rc = 0;
267
268         put_device(&mem_block->dev);
269
270         return rc;
271 }
272
273 static int dlpar_online_lmb(struct drmem_lmb *lmb)
274 {
275         return dlpar_change_lmb_state(lmb, true);
276 }
277
278 #ifdef CONFIG_MEMORY_HOTREMOVE
279 static int dlpar_offline_lmb(struct drmem_lmb *lmb)
280 {
281         return dlpar_change_lmb_state(lmb, false);
282 }
283
284 static int pseries_remove_memblock(unsigned long base, unsigned long memblock_size)
285 {
286         unsigned long block_sz, start_pfn;
287         int sections_per_block;
288         int i;
289
290         start_pfn = base >> PAGE_SHIFT;
291
292         lock_device_hotplug();
293
294         if (!pfn_valid(start_pfn))
295                 goto out;
296
297         block_sz = pseries_memory_block_size();
298         sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
299
300         for (i = 0; i < sections_per_block; i++) {
301                 __remove_memory(base, MIN_MEMORY_BLOCK_SIZE);
302                 base += MIN_MEMORY_BLOCK_SIZE;
303         }
304
305 out:
306         /* Update memory regions for memory remove */
307         memblock_remove(base, memblock_size);
308         unlock_device_hotplug();
309         return 0;
310 }
311
312 static int pseries_remove_mem_node(struct device_node *np)
313 {
314         int ret;
315         struct resource res;
316
317         /*
318          * Check to see if we are actually removing memory
319          */
320         if (!of_node_is_type(np, "memory"))
321                 return 0;
322
323         /*
324          * Find the base address and size of the memblock
325          */
326         ret = of_address_to_resource(np, 0, &res);
327         if (ret)
328                 return ret;
329
330         pseries_remove_memblock(res.start, resource_size(&res));
331         return 0;
332 }
333
334 static bool lmb_is_removable(struct drmem_lmb *lmb)
335 {
336         if ((lmb->flags & DRCONF_MEM_RESERVED) ||
337                 !(lmb->flags & DRCONF_MEM_ASSIGNED))
338                 return false;
339
340 #ifdef CONFIG_FA_DUMP
341         /*
342          * Don't hot-remove memory that falls in fadump boot memory area
343          * and memory that is reserved for capturing old kernel memory.
344          */
345         if (is_fadump_memory_area(lmb->base_addr, memory_block_size_bytes()))
346                 return false;
347 #endif
348         /* device_offline() will determine if we can actually remove this lmb */
349         return true;
350 }
351
352 static int dlpar_add_lmb(struct drmem_lmb *);
353
354 static int dlpar_remove_lmb(struct drmem_lmb *lmb)
355 {
356         struct memory_block *mem_block;
357         unsigned long block_sz;
358         int rc;
359
360         if (!lmb_is_removable(lmb))
361                 return -EINVAL;
362
363         mem_block = lmb_to_memblock(lmb);
364         if (mem_block == NULL)
365                 return -EINVAL;
366
367         rc = dlpar_offline_lmb(lmb);
368         if (rc) {
369                 put_device(&mem_block->dev);
370                 return rc;
371         }
372
373         block_sz = pseries_memory_block_size();
374
375         __remove_memory(lmb->base_addr, block_sz);
376         put_device(&mem_block->dev);
377
378         /* Update memory regions for memory remove */
379         memblock_remove(lmb->base_addr, block_sz);
380
381         invalidate_lmb_associativity_index(lmb);
382         lmb->flags &= ~DRCONF_MEM_ASSIGNED;
383
384         return 0;
385 }
386
387 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove)
388 {
389         struct drmem_lmb *lmb;
390         int lmbs_reserved = 0;
391         int lmbs_available = 0;
392         int rc;
393
394         pr_info("Attempting to hot-remove %d LMB(s)\n", lmbs_to_remove);
395
396         if (lmbs_to_remove == 0)
397                 return -EINVAL;
398
399         /* Validate that there are enough LMBs to satisfy the request */
400         for_each_drmem_lmb(lmb) {
401                 if (lmb_is_removable(lmb))
402                         lmbs_available++;
403
404                 if (lmbs_available == lmbs_to_remove)
405                         break;
406         }
407
408         if (lmbs_available < lmbs_to_remove) {
409                 pr_info("Not enough LMBs available (%d of %d) to satisfy request\n",
410                         lmbs_available, lmbs_to_remove);
411                 return -EINVAL;
412         }
413
414         for_each_drmem_lmb(lmb) {
415                 rc = dlpar_remove_lmb(lmb);
416                 if (rc)
417                         continue;
418
419                 /* Mark this lmb so we can add it later if all of the
420                  * requested LMBs cannot be removed.
421                  */
422                 drmem_mark_lmb_reserved(lmb);
423
424                 lmbs_reserved++;
425                 if (lmbs_reserved == lmbs_to_remove)
426                         break;
427         }
428
429         if (lmbs_reserved != lmbs_to_remove) {
430                 pr_err("Memory hot-remove failed, adding LMB's back\n");
431
432                 for_each_drmem_lmb(lmb) {
433                         if (!drmem_lmb_reserved(lmb))
434                                 continue;
435
436                         rc = dlpar_add_lmb(lmb);
437                         if (rc)
438                                 pr_err("Failed to add LMB back, drc index %x\n",
439                                        lmb->drc_index);
440
441                         drmem_remove_lmb_reservation(lmb);
442
443                         lmbs_reserved--;
444                         if (lmbs_reserved == 0)
445                                 break;
446                 }
447
448                 rc = -EINVAL;
449         } else {
450                 for_each_drmem_lmb(lmb) {
451                         if (!drmem_lmb_reserved(lmb))
452                                 continue;
453
454                         dlpar_release_drc(lmb->drc_index);
455                         pr_info("Memory at %llx was hot-removed\n",
456                                 lmb->base_addr);
457
458                         drmem_remove_lmb_reservation(lmb);
459
460                         lmbs_reserved--;
461                         if (lmbs_reserved == 0)
462                                 break;
463                 }
464                 rc = 0;
465         }
466
467         return rc;
468 }
469
470 static int dlpar_memory_remove_by_index(u32 drc_index)
471 {
472         struct drmem_lmb *lmb;
473         int lmb_found;
474         int rc;
475
476         pr_debug("Attempting to hot-remove LMB, drc index %x\n", drc_index);
477
478         lmb_found = 0;
479         for_each_drmem_lmb(lmb) {
480                 if (lmb->drc_index == drc_index) {
481                         lmb_found = 1;
482                         rc = dlpar_remove_lmb(lmb);
483                         if (!rc)
484                                 dlpar_release_drc(lmb->drc_index);
485
486                         break;
487                 }
488         }
489
490         if (!lmb_found)
491                 rc = -EINVAL;
492
493         if (rc)
494                 pr_debug("Failed to hot-remove memory at %llx\n",
495                          lmb->base_addr);
496         else
497                 pr_debug("Memory at %llx was hot-removed\n", lmb->base_addr);
498
499         return rc;
500 }
501
502 static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)
503 {
504         struct drmem_lmb *lmb, *start_lmb, *end_lmb;
505         int rc;
506
507         pr_info("Attempting to hot-remove %u LMB(s) at %x\n",
508                 lmbs_to_remove, drc_index);
509
510         if (lmbs_to_remove == 0)
511                 return -EINVAL;
512
513         rc = get_lmb_range(drc_index, lmbs_to_remove, &start_lmb, &end_lmb);
514         if (rc)
515                 return -EINVAL;
516
517         /*
518          * Validate that all LMBs in range are not reserved. Note that it
519          * is ok if they are !ASSIGNED since our goal here is to remove the
520          * LMB range, regardless of whether some LMBs were already removed
521          * by any other reason.
522          *
523          * This is a contrast to what is done in remove_by_count() where we
524          * check for both RESERVED and !ASSIGNED (via lmb_is_removable()),
525          * because we want to remove a fixed amount of LMBs in that function.
526          */
527         for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
528                 if (lmb->flags & DRCONF_MEM_RESERVED) {
529                         pr_err("Memory at %llx (drc index %x) is reserved\n",
530                                 lmb->base_addr, lmb->drc_index);
531                         return -EINVAL;
532                 }
533         }
534
535         for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
536                 /*
537                  * dlpar_remove_lmb() will error out if the LMB is already
538                  * !ASSIGNED, but this case is a no-op for us.
539                  */
540                 if (!(lmb->flags & DRCONF_MEM_ASSIGNED))
541                         continue;
542
543                 rc = dlpar_remove_lmb(lmb);
544                 if (rc)
545                         break;
546
547                 drmem_mark_lmb_reserved(lmb);
548         }
549
550         if (rc) {
551                 pr_err("Memory indexed-count-remove failed, adding any removed LMBs\n");
552
553
554                 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
555                         if (!drmem_lmb_reserved(lmb))
556                                 continue;
557
558                         /*
559                          * Setting the isolation state of an UNISOLATED/CONFIGURED
560                          * device to UNISOLATE is a no-op, but the hypervisor can
561                          * use it as a hint that the LMB removal failed.
562                          */
563                         dlpar_unisolate_drc(lmb->drc_index);
564
565                         rc = dlpar_add_lmb(lmb);
566                         if (rc)
567                                 pr_err("Failed to add LMB, drc index %x\n",
568                                        lmb->drc_index);
569
570                         drmem_remove_lmb_reservation(lmb);
571                 }
572                 rc = -EINVAL;
573         } else {
574                 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
575                         if (!drmem_lmb_reserved(lmb))
576                                 continue;
577
578                         dlpar_release_drc(lmb->drc_index);
579                         pr_info("Memory at %llx (drc index %x) was hot-removed\n",
580                                 lmb->base_addr, lmb->drc_index);
581
582                         drmem_remove_lmb_reservation(lmb);
583                 }
584         }
585
586         return rc;
587 }
588
589 #else
590 static inline int pseries_remove_memblock(unsigned long base,
591                                           unsigned long memblock_size)
592 {
593         return -EOPNOTSUPP;
594 }
595 static inline int pseries_remove_mem_node(struct device_node *np)
596 {
597         return 0;
598 }
599 static int dlpar_remove_lmb(struct drmem_lmb *lmb)
600 {
601         return -EOPNOTSUPP;
602 }
603 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove)
604 {
605         return -EOPNOTSUPP;
606 }
607 static int dlpar_memory_remove_by_index(u32 drc_index)
608 {
609         return -EOPNOTSUPP;
610 }
611
612 static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)
613 {
614         return -EOPNOTSUPP;
615 }
616 #endif /* CONFIG_MEMORY_HOTREMOVE */
617
618 static int dlpar_add_lmb(struct drmem_lmb *lmb)
619 {
620         unsigned long block_sz;
621         int nid, rc;
622
623         if (lmb->flags & DRCONF_MEM_ASSIGNED)
624                 return -EINVAL;
625
626         rc = update_lmb_associativity_index(lmb);
627         if (rc) {
628                 dlpar_release_drc(lmb->drc_index);
629                 return rc;
630         }
631
632         block_sz = memory_block_size_bytes();
633
634         /* Find the node id for this LMB.  Fake one if necessary. */
635         nid = of_drconf_to_nid_single(lmb);
636         if (nid < 0 || !node_possible(nid))
637                 nid = first_online_node;
638
639         /* Add the memory */
640         rc = __add_memory(nid, lmb->base_addr, block_sz, MHP_MEMMAP_ON_MEMORY);
641         if (rc) {
642                 invalidate_lmb_associativity_index(lmb);
643                 return rc;
644         }
645
646         rc = dlpar_online_lmb(lmb);
647         if (rc) {
648                 __remove_memory(lmb->base_addr, block_sz);
649                 invalidate_lmb_associativity_index(lmb);
650         } else {
651                 lmb->flags |= DRCONF_MEM_ASSIGNED;
652         }
653
654         return rc;
655 }
656
657 static int dlpar_memory_add_by_count(u32 lmbs_to_add)
658 {
659         struct drmem_lmb *lmb;
660         int lmbs_available = 0;
661         int lmbs_reserved = 0;
662         int rc;
663
664         pr_info("Attempting to hot-add %d LMB(s)\n", lmbs_to_add);
665
666         if (lmbs_to_add == 0)
667                 return -EINVAL;
668
669         /* Validate that there are enough LMBs to satisfy the request */
670         for_each_drmem_lmb(lmb) {
671                 if (lmb->flags & DRCONF_MEM_RESERVED)
672                         continue;
673
674                 if (!(lmb->flags & DRCONF_MEM_ASSIGNED))
675                         lmbs_available++;
676
677                 if (lmbs_available == lmbs_to_add)
678                         break;
679         }
680
681         if (lmbs_available < lmbs_to_add)
682                 return -EINVAL;
683
684         for_each_drmem_lmb(lmb) {
685                 if (lmb->flags & DRCONF_MEM_ASSIGNED)
686                         continue;
687
688                 rc = dlpar_acquire_drc(lmb->drc_index);
689                 if (rc)
690                         continue;
691
692                 rc = dlpar_add_lmb(lmb);
693                 if (rc) {
694                         dlpar_release_drc(lmb->drc_index);
695                         continue;
696                 }
697
698                 /* Mark this lmb so we can remove it later if all of the
699                  * requested LMBs cannot be added.
700                  */
701                 drmem_mark_lmb_reserved(lmb);
702                 lmbs_reserved++;
703                 if (lmbs_reserved == lmbs_to_add)
704                         break;
705         }
706
707         if (lmbs_reserved != lmbs_to_add) {
708                 pr_err("Memory hot-add failed, removing any added LMBs\n");
709
710                 for_each_drmem_lmb(lmb) {
711                         if (!drmem_lmb_reserved(lmb))
712                                 continue;
713
714                         rc = dlpar_remove_lmb(lmb);
715                         if (rc)
716                                 pr_err("Failed to remove LMB, drc index %x\n",
717                                        lmb->drc_index);
718                         else
719                                 dlpar_release_drc(lmb->drc_index);
720
721                         drmem_remove_lmb_reservation(lmb);
722                         lmbs_reserved--;
723
724                         if (lmbs_reserved == 0)
725                                 break;
726                 }
727                 rc = -EINVAL;
728         } else {
729                 for_each_drmem_lmb(lmb) {
730                         if (!drmem_lmb_reserved(lmb))
731                                 continue;
732
733                         pr_debug("Memory at %llx (drc index %x) was hot-added\n",
734                                  lmb->base_addr, lmb->drc_index);
735                         drmem_remove_lmb_reservation(lmb);
736                         lmbs_reserved--;
737
738                         if (lmbs_reserved == 0)
739                                 break;
740                 }
741                 rc = 0;
742         }
743
744         return rc;
745 }
746
747 static int dlpar_memory_add_by_index(u32 drc_index)
748 {
749         struct drmem_lmb *lmb;
750         int rc, lmb_found;
751
752         pr_info("Attempting to hot-add LMB, drc index %x\n", drc_index);
753
754         lmb_found = 0;
755         for_each_drmem_lmb(lmb) {
756                 if (lmb->drc_index == drc_index) {
757                         lmb_found = 1;
758                         rc = dlpar_acquire_drc(lmb->drc_index);
759                         if (!rc) {
760                                 rc = dlpar_add_lmb(lmb);
761                                 if (rc)
762                                         dlpar_release_drc(lmb->drc_index);
763                         }
764
765                         break;
766                 }
767         }
768
769         if (!lmb_found)
770                 rc = -EINVAL;
771
772         if (rc)
773                 pr_info("Failed to hot-add memory, drc index %x\n", drc_index);
774         else
775                 pr_info("Memory at %llx (drc index %x) was hot-added\n",
776                         lmb->base_addr, drc_index);
777
778         return rc;
779 }
780
781 static int dlpar_memory_add_by_ic(u32 lmbs_to_add, u32 drc_index)
782 {
783         struct drmem_lmb *lmb, *start_lmb, *end_lmb;
784         int rc;
785
786         pr_info("Attempting to hot-add %u LMB(s) at index %x\n",
787                 lmbs_to_add, drc_index);
788
789         if (lmbs_to_add == 0)
790                 return -EINVAL;
791
792         rc = get_lmb_range(drc_index, lmbs_to_add, &start_lmb, &end_lmb);
793         if (rc)
794                 return -EINVAL;
795
796         /* Validate that the LMBs in this range are not reserved */
797         for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
798                 /* Fail immediately if the whole range can't be hot-added */
799                 if (lmb->flags & DRCONF_MEM_RESERVED) {
800                         pr_err("Memory at %llx (drc index %x) is reserved\n",
801                                         lmb->base_addr, lmb->drc_index);
802                         return -EINVAL;
803                 }
804         }
805
806         for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
807                 if (lmb->flags & DRCONF_MEM_ASSIGNED)
808                         continue;
809
810                 rc = dlpar_acquire_drc(lmb->drc_index);
811                 if (rc)
812                         break;
813
814                 rc = dlpar_add_lmb(lmb);
815                 if (rc) {
816                         dlpar_release_drc(lmb->drc_index);
817                         break;
818                 }
819
820                 drmem_mark_lmb_reserved(lmb);
821         }
822
823         if (rc) {
824                 pr_err("Memory indexed-count-add failed, removing any added LMBs\n");
825
826                 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
827                         if (!drmem_lmb_reserved(lmb))
828                                 continue;
829
830                         rc = dlpar_remove_lmb(lmb);
831                         if (rc)
832                                 pr_err("Failed to remove LMB, drc index %x\n",
833                                        lmb->drc_index);
834                         else
835                                 dlpar_release_drc(lmb->drc_index);
836
837                         drmem_remove_lmb_reservation(lmb);
838                 }
839                 rc = -EINVAL;
840         } else {
841                 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
842                         if (!drmem_lmb_reserved(lmb))
843                                 continue;
844
845                         pr_info("Memory at %llx (drc index %x) was hot-added\n",
846                                 lmb->base_addr, lmb->drc_index);
847                         drmem_remove_lmb_reservation(lmb);
848                 }
849         }
850
851         return rc;
852 }
853
854 int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
855 {
856         u32 count, drc_index;
857         int rc;
858
859         lock_device_hotplug();
860
861         switch (hp_elog->action) {
862         case PSERIES_HP_ELOG_ACTION_ADD:
863                 switch (hp_elog->id_type) {
864                 case PSERIES_HP_ELOG_ID_DRC_COUNT:
865                         count = hp_elog->_drc_u.drc_count;
866                         rc = dlpar_memory_add_by_count(count);
867                         break;
868                 case PSERIES_HP_ELOG_ID_DRC_INDEX:
869                         drc_index = hp_elog->_drc_u.drc_index;
870                         rc = dlpar_memory_add_by_index(drc_index);
871                         break;
872                 case PSERIES_HP_ELOG_ID_DRC_IC:
873                         count = hp_elog->_drc_u.ic.count;
874                         drc_index = hp_elog->_drc_u.ic.index;
875                         rc = dlpar_memory_add_by_ic(count, drc_index);
876                         break;
877                 default:
878                         rc = -EINVAL;
879                         break;
880                 }
881
882                 break;
883         case PSERIES_HP_ELOG_ACTION_REMOVE:
884                 switch (hp_elog->id_type) {
885                 case PSERIES_HP_ELOG_ID_DRC_COUNT:
886                         count = hp_elog->_drc_u.drc_count;
887                         rc = dlpar_memory_remove_by_count(count);
888                         break;
889                 case PSERIES_HP_ELOG_ID_DRC_INDEX:
890                         drc_index = hp_elog->_drc_u.drc_index;
891                         rc = dlpar_memory_remove_by_index(drc_index);
892                         break;
893                 case PSERIES_HP_ELOG_ID_DRC_IC:
894                         count = hp_elog->_drc_u.ic.count;
895                         drc_index = hp_elog->_drc_u.ic.index;
896                         rc = dlpar_memory_remove_by_ic(count, drc_index);
897                         break;
898                 default:
899                         rc = -EINVAL;
900                         break;
901                 }
902
903                 break;
904         default:
905                 pr_err("Invalid action (%d) specified\n", hp_elog->action);
906                 rc = -EINVAL;
907                 break;
908         }
909
910         if (!rc)
911                 rc = drmem_update_dt();
912
913         unlock_device_hotplug();
914         return rc;
915 }
916
917 static int pseries_add_mem_node(struct device_node *np)
918 {
919         int ret;
920         struct resource res;
921
922         /*
923          * Check to see if we are actually adding memory
924          */
925         if (!of_node_is_type(np, "memory"))
926                 return 0;
927
928         /*
929          * Find the base and size of the memblock
930          */
931         ret = of_address_to_resource(np, 0, &res);
932         if (ret)
933                 return ret;
934
935         /*
936          * Update memory region to represent the memory add
937          */
938         ret = memblock_add(res.start, resource_size(&res));
939         return (ret < 0) ? -EINVAL : 0;
940 }
941
942 static int pseries_memory_notifier(struct notifier_block *nb,
943                                    unsigned long action, void *data)
944 {
945         struct of_reconfig_data *rd = data;
946         int err = 0;
947
948         switch (action) {
949         case OF_RECONFIG_ATTACH_NODE:
950                 err = pseries_add_mem_node(rd->dn);
951                 break;
952         case OF_RECONFIG_DETACH_NODE:
953                 err = pseries_remove_mem_node(rd->dn);
954                 break;
955         case OF_RECONFIG_UPDATE_PROPERTY:
956                 if (!strcmp(rd->dn->name,
957                             "ibm,dynamic-reconfiguration-memory"))
958                         drmem_update_lmbs(rd->prop);
959         }
960         return notifier_from_errno(err);
961 }
962
963 static struct notifier_block pseries_mem_nb = {
964         .notifier_call = pseries_memory_notifier,
965 };
966
967 static int __init pseries_memory_hotplug_init(void)
968 {
969         if (firmware_has_feature(FW_FEATURE_LPAR))
970                 of_reconfig_notifier_register(&pseries_mem_nb);
971
972         return 0;
973 }
974 machine_device_initcall(pseries, pseries_memory_hotplug_init);