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