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