This source file includes following definitions.
- pseries_memory_block_size
- dlpar_free_property
- dlpar_clone_property
- find_aa_index
- update_lmb_associativity_index
- lmb_to_memblock
- get_lmb_range
- dlpar_change_lmb_state
- dlpar_online_lmb
- dlpar_offline_lmb
- pseries_remove_memblock
- pseries_remove_mem_node
- lmb_is_removable
- dlpar_remove_lmb
- dlpar_memory_remove_by_count
- dlpar_memory_remove_by_index
- dlpar_memory_readd_by_index
- dlpar_memory_remove_by_ic
- pseries_remove_memblock
- pseries_remove_mem_node
- dlpar_memory_remove
- dlpar_remove_lmb
- dlpar_memory_remove_by_count
- dlpar_memory_remove_by_index
- dlpar_memory_readd_by_index
- dlpar_memory_remove_by_ic
- dlpar_add_lmb
- dlpar_memory_add_by_count
- dlpar_memory_add_by_index
- dlpar_memory_add_by_ic
- dlpar_memory
- pseries_add_mem_node
- pseries_update_drconf_memory
- pseries_memory_notifier
- pseries_memory_hotplug_init
1
2
3
4
5
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/prom.h>
20 #include <asm/sparsemem.h>
21 #include <asm/fadump.h>
22 #include <asm/drmem.h>
23 #include "pseries.h"
24
25 static bool rtas_hp_event;
26
27 unsigned long pseries_memory_block_size(void)
28 {
29 struct device_node *np;
30 unsigned int memblock_size = MIN_MEMORY_BLOCK_SIZE;
31 struct resource r;
32
33 np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
34 if (np) {
35 const __be64 *size;
36
37 size = of_get_property(np, "ibm,lmb-size", NULL);
38 if (size)
39 memblock_size = be64_to_cpup(size);
40 of_node_put(np);
41 } else if (machine_is(pseries)) {
42
43 unsigned int memzero_size = 0;
44
45 np = of_find_node_by_path("/memory@0");
46 if (np) {
47 if (!of_address_to_resource(np, 0, &r))
48 memzero_size = resource_size(&r);
49 of_node_put(np);
50 }
51
52 if (memzero_size) {
53
54
55
56 char buf[64];
57
58 sprintf(buf, "/memory@%x", memzero_size);
59 np = of_find_node_by_path(buf);
60 if (np) {
61 if (!of_address_to_resource(np, 0, &r))
62 memblock_size = resource_size(&r);
63 of_node_put(np);
64 }
65 }
66 }
67 return memblock_size;
68 }
69
70 static void dlpar_free_property(struct property *prop)
71 {
72 kfree(prop->name);
73 kfree(prop->value);
74 kfree(prop);
75 }
76
77 static struct property *dlpar_clone_property(struct property *prop,
78 u32 prop_size)
79 {
80 struct property *new_prop;
81
82 new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
83 if (!new_prop)
84 return NULL;
85
86 new_prop->name = kstrdup(prop->name, GFP_KERNEL);
87 new_prop->value = kzalloc(prop_size, GFP_KERNEL);
88 if (!new_prop->name || !new_prop->value) {
89 dlpar_free_property(new_prop);
90 return NULL;
91 }
92
93 memcpy(new_prop->value, prop->value, prop->length);
94 new_prop->length = prop_size;
95
96 of_property_set_flag(new_prop, OF_DYNAMIC);
97 return new_prop;
98 }
99
100 static bool find_aa_index(struct device_node *dr_node,
101 struct property *ala_prop,
102 const u32 *lmb_assoc, u32 *aa_index)
103 {
104 u32 *assoc_arrays, new_prop_size;
105 struct property *new_prop;
106 int aa_arrays, aa_array_entries, aa_array_sz;
107 int i, index;
108
109
110
111
112
113
114
115 assoc_arrays = ala_prop->value;
116
117 aa_arrays = be32_to_cpu(assoc_arrays[0]);
118 aa_array_entries = be32_to_cpu(assoc_arrays[1]);
119 aa_array_sz = aa_array_entries * sizeof(u32);
120
121 for (i = 0; i < aa_arrays; i++) {
122 index = (i * aa_array_entries) + 2;
123
124 if (memcmp(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz))
125 continue;
126
127 *aa_index = i;
128 return true;
129 }
130
131 new_prop_size = ala_prop->length + aa_array_sz;
132 new_prop = dlpar_clone_property(ala_prop, new_prop_size);
133 if (!new_prop)
134 return false;
135
136 assoc_arrays = new_prop->value;
137
138
139 assoc_arrays[0] = cpu_to_be32(aa_arrays + 1);
140
141
142 index = aa_arrays * aa_array_entries + 2;
143 memcpy(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz);
144
145 of_update_property(dr_node, new_prop);
146
147
148
149
150
151
152 *aa_index = be32_to_cpu(assoc_arrays[0]) - 1;
153 return true;
154 }
155
156 static int update_lmb_associativity_index(struct drmem_lmb *lmb)
157 {
158 struct device_node *parent, *lmb_node, *dr_node;
159 struct property *ala_prop;
160 const u32 *lmb_assoc;
161 u32 aa_index;
162 bool found;
163
164 parent = of_find_node_by_path("/");
165 if (!parent)
166 return -ENODEV;
167
168 lmb_node = dlpar_configure_connector(cpu_to_be32(lmb->drc_index),
169 parent);
170 of_node_put(parent);
171 if (!lmb_node)
172 return -EINVAL;
173
174 lmb_assoc = of_get_property(lmb_node, "ibm,associativity", NULL);
175 if (!lmb_assoc) {
176 dlpar_free_cc_nodes(lmb_node);
177 return -ENODEV;
178 }
179
180 dr_node = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
181 if (!dr_node) {
182 dlpar_free_cc_nodes(lmb_node);
183 return -ENODEV;
184 }
185
186 ala_prop = of_find_property(dr_node, "ibm,associativity-lookup-arrays",
187 NULL);
188 if (!ala_prop) {
189 of_node_put(dr_node);
190 dlpar_free_cc_nodes(lmb_node);
191 return -ENODEV;
192 }
193
194 found = find_aa_index(dr_node, ala_prop, lmb_assoc, &aa_index);
195
196 of_node_put(dr_node);
197 dlpar_free_cc_nodes(lmb_node);
198
199 if (!found) {
200 pr_err("Could not find LMB associativity\n");
201 return -1;
202 }
203
204 lmb->aa_index = aa_index;
205 return 0;
206 }
207
208 static struct memory_block *lmb_to_memblock(struct drmem_lmb *lmb)
209 {
210 unsigned long section_nr;
211 struct mem_section *mem_sect;
212 struct memory_block *mem_block;
213
214 section_nr = pfn_to_section_nr(PFN_DOWN(lmb->base_addr));
215 mem_sect = __nr_to_section(section_nr);
216
217 mem_block = find_memory_block(mem_sect);
218 return mem_block;
219 }
220
221 static int get_lmb_range(u32 drc_index, int n_lmbs,
222 struct drmem_lmb **start_lmb,
223 struct drmem_lmb **end_lmb)
224 {
225 struct drmem_lmb *lmb, *start, *end;
226 struct drmem_lmb *limit;
227
228 start = NULL;
229 for_each_drmem_lmb(lmb) {
230 if (lmb->drc_index == drc_index) {
231 start = lmb;
232 break;
233 }
234 }
235
236 if (!start)
237 return -EINVAL;
238
239 end = &start[n_lmbs];
240
241 limit = &drmem_info->lmbs[drmem_info->n_lmbs];
242 if (end > limit)
243 return -EINVAL;
244
245 *start_lmb = start;
246 *end_lmb = end;
247 return 0;
248 }
249
250 static int dlpar_change_lmb_state(struct drmem_lmb *lmb, bool online)
251 {
252 struct memory_block *mem_block;
253 int rc;
254
255 mem_block = lmb_to_memblock(lmb);
256 if (!mem_block)
257 return -EINVAL;
258
259 if (online && mem_block->dev.offline)
260 rc = device_online(&mem_block->dev);
261 else if (!online && !mem_block->dev.offline)
262 rc = device_offline(&mem_block->dev);
263 else
264 rc = 0;
265
266 put_device(&mem_block->dev);
267
268 return rc;
269 }
270
271 static int dlpar_online_lmb(struct drmem_lmb *lmb)
272 {
273 return dlpar_change_lmb_state(lmb, true);
274 }
275
276 #ifdef CONFIG_MEMORY_HOTREMOVE
277 static int dlpar_offline_lmb(struct drmem_lmb *lmb)
278 {
279 return dlpar_change_lmb_state(lmb, false);
280 }
281
282 static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
283 {
284 unsigned long block_sz, start_pfn;
285 int sections_per_block;
286 int i, nid;
287
288 start_pfn = base >> PAGE_SHIFT;
289
290 lock_device_hotplug();
291
292 if (!pfn_valid(start_pfn))
293 goto out;
294
295 block_sz = pseries_memory_block_size();
296 sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
297 nid = memory_add_physaddr_to_nid(base);
298
299 for (i = 0; i < sections_per_block; i++) {
300 __remove_memory(nid, base, MIN_MEMORY_BLOCK_SIZE);
301 base += MIN_MEMORY_BLOCK_SIZE;
302 }
303
304 out:
305
306 memblock_remove(base, memblock_size);
307 unlock_device_hotplug();
308 return 0;
309 }
310
311 static int pseries_remove_mem_node(struct device_node *np)
312 {
313 const __be32 *regs;
314 unsigned long base;
315 unsigned int lmb_size;
316 int ret = -EINVAL;
317
318
319
320
321 if (!of_node_is_type(np, "memory"))
322 return 0;
323
324
325
326
327 regs = of_get_property(np, "reg", NULL);
328 if (!regs)
329 return ret;
330
331 base = be64_to_cpu(*(unsigned long *)regs);
332 lmb_size = be32_to_cpu(regs[3]);
333
334 pseries_remove_memblock(base, lmb_size);
335 return 0;
336 }
337
338 static bool lmb_is_removable(struct drmem_lmb *lmb)
339 {
340 int i, scns_per_block;
341 int rc = 1;
342 unsigned long pfn, block_sz;
343 u64 phys_addr;
344
345 if (!(lmb->flags & DRCONF_MEM_ASSIGNED))
346 return false;
347
348 block_sz = memory_block_size_bytes();
349 scns_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
350 phys_addr = lmb->base_addr;
351
352 #ifdef CONFIG_FA_DUMP
353
354
355
356
357 if (is_fadump_memory_area(phys_addr, block_sz))
358 return false;
359 #endif
360
361 for (i = 0; i < scns_per_block; i++) {
362 pfn = PFN_DOWN(phys_addr);
363 if (!pfn_present(pfn)) {
364 phys_addr += MIN_MEMORY_BLOCK_SIZE;
365 continue;
366 }
367
368 rc &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
369 phys_addr += MIN_MEMORY_BLOCK_SIZE;
370 }
371
372 return rc ? true : false;
373 }
374
375 static int dlpar_add_lmb(struct drmem_lmb *);
376
377 static int dlpar_remove_lmb(struct drmem_lmb *lmb)
378 {
379 unsigned long block_sz;
380 int rc;
381
382 if (!lmb_is_removable(lmb))
383 return -EINVAL;
384
385 rc = dlpar_offline_lmb(lmb);
386 if (rc)
387 return rc;
388
389 block_sz = pseries_memory_block_size();
390
391 __remove_memory(lmb->nid, lmb->base_addr, block_sz);
392
393
394 memblock_remove(lmb->base_addr, block_sz);
395
396 invalidate_lmb_associativity_index(lmb);
397 lmb_clear_nid(lmb);
398 lmb->flags &= ~DRCONF_MEM_ASSIGNED;
399
400 return 0;
401 }
402
403 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove)
404 {
405 struct drmem_lmb *lmb;
406 int lmbs_removed = 0;
407 int lmbs_available = 0;
408 int rc;
409
410 pr_info("Attempting to hot-remove %d LMB(s)\n", lmbs_to_remove);
411
412 if (lmbs_to_remove == 0)
413 return -EINVAL;
414
415
416 for_each_drmem_lmb(lmb) {
417 if (lmb_is_removable(lmb))
418 lmbs_available++;
419
420 if (lmbs_available == lmbs_to_remove)
421 break;
422 }
423
424 if (lmbs_available < lmbs_to_remove) {
425 pr_info("Not enough LMBs available (%d of %d) to satisfy request\n",
426 lmbs_available, lmbs_to_remove);
427 return -EINVAL;
428 }
429
430 for_each_drmem_lmb(lmb) {
431 rc = dlpar_remove_lmb(lmb);
432 if (rc)
433 continue;
434
435
436
437
438 drmem_mark_lmb_reserved(lmb);
439
440 lmbs_removed++;
441 if (lmbs_removed == lmbs_to_remove)
442 break;
443 }
444
445 if (lmbs_removed != lmbs_to_remove) {
446 pr_err("Memory hot-remove failed, adding LMB's back\n");
447
448 for_each_drmem_lmb(lmb) {
449 if (!drmem_lmb_reserved(lmb))
450 continue;
451
452 rc = dlpar_add_lmb(lmb);
453 if (rc)
454 pr_err("Failed to add LMB back, drc index %x\n",
455 lmb->drc_index);
456
457 drmem_remove_lmb_reservation(lmb);
458 }
459
460 rc = -EINVAL;
461 } else {
462 for_each_drmem_lmb(lmb) {
463 if (!drmem_lmb_reserved(lmb))
464 continue;
465
466 dlpar_release_drc(lmb->drc_index);
467 pr_info("Memory at %llx was hot-removed\n",
468 lmb->base_addr);
469
470 drmem_remove_lmb_reservation(lmb);
471 }
472 rc = 0;
473 }
474
475 return rc;
476 }
477
478 static int dlpar_memory_remove_by_index(u32 drc_index)
479 {
480 struct drmem_lmb *lmb;
481 int lmb_found;
482 int rc;
483
484 pr_info("Attempting to hot-remove LMB, drc index %x\n", drc_index);
485
486 lmb_found = 0;
487 for_each_drmem_lmb(lmb) {
488 if (lmb->drc_index == drc_index) {
489 lmb_found = 1;
490 rc = dlpar_remove_lmb(lmb);
491 if (!rc)
492 dlpar_release_drc(lmb->drc_index);
493
494 break;
495 }
496 }
497
498 if (!lmb_found)
499 rc = -EINVAL;
500
501 if (rc)
502 pr_info("Failed to hot-remove memory at %llx\n",
503 lmb->base_addr);
504 else
505 pr_info("Memory at %llx was hot-removed\n", lmb->base_addr);
506
507 return rc;
508 }
509
510 static int dlpar_memory_readd_by_index(u32 drc_index)
511 {
512 struct drmem_lmb *lmb;
513 int lmb_found;
514 int rc;
515
516 pr_info("Attempting to update LMB, drc index %x\n", drc_index);
517
518 lmb_found = 0;
519 for_each_drmem_lmb(lmb) {
520 if (lmb->drc_index == drc_index) {
521 lmb_found = 1;
522 rc = dlpar_remove_lmb(lmb);
523 if (!rc) {
524 rc = dlpar_add_lmb(lmb);
525 if (rc)
526 dlpar_release_drc(lmb->drc_index);
527 }
528 break;
529 }
530 }
531
532 if (!lmb_found)
533 rc = -EINVAL;
534
535 if (rc)
536 pr_info("Failed to update memory at %llx\n",
537 lmb->base_addr);
538 else
539 pr_info("Memory at %llx was updated\n", lmb->base_addr);
540
541 return rc;
542 }
543
544 static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)
545 {
546 struct drmem_lmb *lmb, *start_lmb, *end_lmb;
547 int lmbs_available = 0;
548 int rc;
549
550 pr_info("Attempting to hot-remove %u LMB(s) at %x\n",
551 lmbs_to_remove, drc_index);
552
553 if (lmbs_to_remove == 0)
554 return -EINVAL;
555
556 rc = get_lmb_range(drc_index, lmbs_to_remove, &start_lmb, &end_lmb);
557 if (rc)
558 return -EINVAL;
559
560
561 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
562 if (lmb->flags & DRCONF_MEM_RESERVED)
563 break;
564
565 lmbs_available++;
566 }
567
568 if (lmbs_available < lmbs_to_remove)
569 return -EINVAL;
570
571 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
572 if (!(lmb->flags & DRCONF_MEM_ASSIGNED))
573 continue;
574
575 rc = dlpar_remove_lmb(lmb);
576 if (rc)
577 break;
578
579 drmem_mark_lmb_reserved(lmb);
580 }
581
582 if (rc) {
583 pr_err("Memory indexed-count-remove failed, adding any removed LMBs\n");
584
585
586 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
587 if (!drmem_lmb_reserved(lmb))
588 continue;
589
590 rc = dlpar_add_lmb(lmb);
591 if (rc)
592 pr_err("Failed to add LMB, drc index %x\n",
593 lmb->drc_index);
594
595 drmem_remove_lmb_reservation(lmb);
596 }
597 rc = -EINVAL;
598 } else {
599 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
600 if (!drmem_lmb_reserved(lmb))
601 continue;
602
603 dlpar_release_drc(lmb->drc_index);
604 pr_info("Memory at %llx (drc index %x) was hot-removed\n",
605 lmb->base_addr, lmb->drc_index);
606
607 drmem_remove_lmb_reservation(lmb);
608 }
609 }
610
611 return rc;
612 }
613
614 #else
615 static inline int pseries_remove_memblock(unsigned long base,
616 unsigned int memblock_size)
617 {
618 return -EOPNOTSUPP;
619 }
620 static inline int pseries_remove_mem_node(struct device_node *np)
621 {
622 return 0;
623 }
624 static inline int dlpar_memory_remove(struct pseries_hp_errorlog *hp_elog)
625 {
626 return -EOPNOTSUPP;
627 }
628 static int dlpar_remove_lmb(struct drmem_lmb *lmb)
629 {
630 return -EOPNOTSUPP;
631 }
632 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove)
633 {
634 return -EOPNOTSUPP;
635 }
636 static int dlpar_memory_remove_by_index(u32 drc_index)
637 {
638 return -EOPNOTSUPP;
639 }
640 static int dlpar_memory_readd_by_index(u32 drc_index)
641 {
642 return -EOPNOTSUPP;
643 }
644
645 static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)
646 {
647 return -EOPNOTSUPP;
648 }
649 #endif
650
651 static int dlpar_add_lmb(struct drmem_lmb *lmb)
652 {
653 unsigned long block_sz;
654 int rc;
655
656 if (lmb->flags & DRCONF_MEM_ASSIGNED)
657 return -EINVAL;
658
659 rc = update_lmb_associativity_index(lmb);
660 if (rc) {
661 dlpar_release_drc(lmb->drc_index);
662 return rc;
663 }
664
665 lmb_set_nid(lmb);
666 block_sz = memory_block_size_bytes();
667
668
669 rc = __add_memory(lmb->nid, lmb->base_addr, block_sz);
670 if (rc) {
671 invalidate_lmb_associativity_index(lmb);
672 return rc;
673 }
674
675 rc = dlpar_online_lmb(lmb);
676 if (rc) {
677 __remove_memory(lmb->nid, lmb->base_addr, block_sz);
678 invalidate_lmb_associativity_index(lmb);
679 lmb_clear_nid(lmb);
680 } else {
681 lmb->flags |= DRCONF_MEM_ASSIGNED;
682 }
683
684 return rc;
685 }
686
687 static int dlpar_memory_add_by_count(u32 lmbs_to_add)
688 {
689 struct drmem_lmb *lmb;
690 int lmbs_available = 0;
691 int lmbs_added = 0;
692 int rc;
693
694 pr_info("Attempting to hot-add %d LMB(s)\n", lmbs_to_add);
695
696 if (lmbs_to_add == 0)
697 return -EINVAL;
698
699
700 for_each_drmem_lmb(lmb) {
701 if (!(lmb->flags & DRCONF_MEM_ASSIGNED))
702 lmbs_available++;
703
704 if (lmbs_available == lmbs_to_add)
705 break;
706 }
707
708 if (lmbs_available < lmbs_to_add)
709 return -EINVAL;
710
711 for_each_drmem_lmb(lmb) {
712 if (lmb->flags & DRCONF_MEM_ASSIGNED)
713 continue;
714
715 rc = dlpar_acquire_drc(lmb->drc_index);
716 if (rc)
717 continue;
718
719 rc = dlpar_add_lmb(lmb);
720 if (rc) {
721 dlpar_release_drc(lmb->drc_index);
722 continue;
723 }
724
725
726
727
728 drmem_mark_lmb_reserved(lmb);
729
730 lmbs_added++;
731 if (lmbs_added == lmbs_to_add)
732 break;
733 }
734
735 if (lmbs_added != lmbs_to_add) {
736 pr_err("Memory hot-add failed, removing any added LMBs\n");
737
738 for_each_drmem_lmb(lmb) {
739 if (!drmem_lmb_reserved(lmb))
740 continue;
741
742 rc = dlpar_remove_lmb(lmb);
743 if (rc)
744 pr_err("Failed to remove LMB, drc index %x\n",
745 lmb->drc_index);
746 else
747 dlpar_release_drc(lmb->drc_index);
748
749 drmem_remove_lmb_reservation(lmb);
750 }
751 rc = -EINVAL;
752 } else {
753 for_each_drmem_lmb(lmb) {
754 if (!drmem_lmb_reserved(lmb))
755 continue;
756
757 pr_info("Memory at %llx (drc index %x) was hot-added\n",
758 lmb->base_addr, lmb->drc_index);
759 drmem_remove_lmb_reservation(lmb);
760 }
761 rc = 0;
762 }
763
764 return rc;
765 }
766
767 static int dlpar_memory_add_by_index(u32 drc_index)
768 {
769 struct drmem_lmb *lmb;
770 int rc, lmb_found;
771
772 pr_info("Attempting to hot-add LMB, drc index %x\n", drc_index);
773
774 lmb_found = 0;
775 for_each_drmem_lmb(lmb) {
776 if (lmb->drc_index == drc_index) {
777 lmb_found = 1;
778 rc = dlpar_acquire_drc(lmb->drc_index);
779 if (!rc) {
780 rc = dlpar_add_lmb(lmb);
781 if (rc)
782 dlpar_release_drc(lmb->drc_index);
783 }
784
785 break;
786 }
787 }
788
789 if (!lmb_found)
790 rc = -EINVAL;
791
792 if (rc)
793 pr_info("Failed to hot-add memory, drc index %x\n", drc_index);
794 else
795 pr_info("Memory at %llx (drc index %x) was hot-added\n",
796 lmb->base_addr, drc_index);
797
798 return rc;
799 }
800
801 static int dlpar_memory_add_by_ic(u32 lmbs_to_add, u32 drc_index)
802 {
803 struct drmem_lmb *lmb, *start_lmb, *end_lmb;
804 int lmbs_available = 0;
805 int rc;
806
807 pr_info("Attempting to hot-add %u LMB(s) at index %x\n",
808 lmbs_to_add, drc_index);
809
810 if (lmbs_to_add == 0)
811 return -EINVAL;
812
813 rc = get_lmb_range(drc_index, lmbs_to_add, &start_lmb, &end_lmb);
814 if (rc)
815 return -EINVAL;
816
817
818 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
819 if (lmb->flags & DRCONF_MEM_RESERVED)
820 break;
821
822 lmbs_available++;
823 }
824
825 if (lmbs_available < lmbs_to_add)
826 return -EINVAL;
827
828 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
829 if (lmb->flags & DRCONF_MEM_ASSIGNED)
830 continue;
831
832 rc = dlpar_acquire_drc(lmb->drc_index);
833 if (rc)
834 break;
835
836 rc = dlpar_add_lmb(lmb);
837 if (rc) {
838 dlpar_release_drc(lmb->drc_index);
839 break;
840 }
841
842 drmem_mark_lmb_reserved(lmb);
843 }
844
845 if (rc) {
846 pr_err("Memory indexed-count-add failed, removing any added LMBs\n");
847
848 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
849 if (!drmem_lmb_reserved(lmb))
850 continue;
851
852 rc = dlpar_remove_lmb(lmb);
853 if (rc)
854 pr_err("Failed to remove LMB, drc index %x\n",
855 lmb->drc_index);
856 else
857 dlpar_release_drc(lmb->drc_index);
858
859 drmem_remove_lmb_reservation(lmb);
860 }
861 rc = -EINVAL;
862 } else {
863 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
864 if (!drmem_lmb_reserved(lmb))
865 continue;
866
867 pr_info("Memory at %llx (drc index %x) was hot-added\n",
868 lmb->base_addr, lmb->drc_index);
869 drmem_remove_lmb_reservation(lmb);
870 }
871 }
872
873 return rc;
874 }
875
876 int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
877 {
878 u32 count, drc_index;
879 int rc;
880
881 lock_device_hotplug();
882
883 switch (hp_elog->action) {
884 case PSERIES_HP_ELOG_ACTION_ADD:
885 switch (hp_elog->id_type) {
886 case PSERIES_HP_ELOG_ID_DRC_COUNT:
887 count = hp_elog->_drc_u.drc_count;
888 rc = dlpar_memory_add_by_count(count);
889 break;
890 case PSERIES_HP_ELOG_ID_DRC_INDEX:
891 drc_index = hp_elog->_drc_u.drc_index;
892 rc = dlpar_memory_add_by_index(drc_index);
893 break;
894 case PSERIES_HP_ELOG_ID_DRC_IC:
895 count = hp_elog->_drc_u.ic.count;
896 drc_index = hp_elog->_drc_u.ic.index;
897 rc = dlpar_memory_add_by_ic(count, drc_index);
898 break;
899 default:
900 rc = -EINVAL;
901 break;
902 }
903
904 break;
905 case PSERIES_HP_ELOG_ACTION_REMOVE:
906 switch (hp_elog->id_type) {
907 case PSERIES_HP_ELOG_ID_DRC_COUNT:
908 count = hp_elog->_drc_u.drc_count;
909 rc = dlpar_memory_remove_by_count(count);
910 break;
911 case PSERIES_HP_ELOG_ID_DRC_INDEX:
912 drc_index = hp_elog->_drc_u.drc_index;
913 rc = dlpar_memory_remove_by_index(drc_index);
914 break;
915 case PSERIES_HP_ELOG_ID_DRC_IC:
916 count = hp_elog->_drc_u.ic.count;
917 drc_index = hp_elog->_drc_u.ic.index;
918 rc = dlpar_memory_remove_by_ic(count, drc_index);
919 break;
920 default:
921 rc = -EINVAL;
922 break;
923 }
924
925 break;
926 case PSERIES_HP_ELOG_ACTION_READD:
927 drc_index = hp_elog->_drc_u.drc_index;
928 rc = dlpar_memory_readd_by_index(drc_index);
929 break;
930 default:
931 pr_err("Invalid action (%d) specified\n", hp_elog->action);
932 rc = -EINVAL;
933 break;
934 }
935
936 if (!rc) {
937 rtas_hp_event = true;
938 rc = drmem_update_dt();
939 rtas_hp_event = false;
940 }
941
942 unlock_device_hotplug();
943 return rc;
944 }
945
946 static int pseries_add_mem_node(struct device_node *np)
947 {
948 const __be32 *regs;
949 unsigned long base;
950 unsigned int lmb_size;
951 int ret = -EINVAL;
952
953
954
955
956 if (!of_node_is_type(np, "memory"))
957 return 0;
958
959
960
961
962 regs = of_get_property(np, "reg", NULL);
963 if (!regs)
964 return ret;
965
966 base = be64_to_cpu(*(unsigned long *)regs);
967 lmb_size = be32_to_cpu(regs[3]);
968
969
970
971
972 ret = memblock_add(base, lmb_size);
973 return (ret < 0) ? -EINVAL : 0;
974 }
975
976 static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
977 {
978 struct of_drconf_cell_v1 *new_drmem, *old_drmem;
979 unsigned long memblock_size;
980 u32 entries;
981 __be32 *p;
982 int i, rc = -EINVAL;
983
984 if (rtas_hp_event)
985 return 0;
986
987 memblock_size = pseries_memory_block_size();
988 if (!memblock_size)
989 return -EINVAL;
990
991 if (!pr->old_prop)
992 return 0;
993
994 p = (__be32 *) pr->old_prop->value;
995 if (!p)
996 return -EINVAL;
997
998
999
1000
1001
1002
1003 entries = be32_to_cpu(*p++);
1004 old_drmem = (struct of_drconf_cell_v1 *)p;
1005
1006 p = (__be32 *)pr->prop->value;
1007 p++;
1008 new_drmem = (struct of_drconf_cell_v1 *)p;
1009
1010 for (i = 0; i < entries; i++) {
1011 if ((be32_to_cpu(old_drmem[i].flags) & DRCONF_MEM_ASSIGNED) &&
1012 (!(be32_to_cpu(new_drmem[i].flags) & DRCONF_MEM_ASSIGNED))) {
1013 rc = pseries_remove_memblock(
1014 be64_to_cpu(old_drmem[i].base_addr),
1015 memblock_size);
1016 break;
1017 } else if ((!(be32_to_cpu(old_drmem[i].flags) &
1018 DRCONF_MEM_ASSIGNED)) &&
1019 (be32_to_cpu(new_drmem[i].flags) &
1020 DRCONF_MEM_ASSIGNED)) {
1021 rc = memblock_add(be64_to_cpu(old_drmem[i].base_addr),
1022 memblock_size);
1023 rc = (rc < 0) ? -EINVAL : 0;
1024 break;
1025 }
1026 }
1027 return rc;
1028 }
1029
1030 static int pseries_memory_notifier(struct notifier_block *nb,
1031 unsigned long action, void *data)
1032 {
1033 struct of_reconfig_data *rd = data;
1034 int err = 0;
1035
1036 switch (action) {
1037 case OF_RECONFIG_ATTACH_NODE:
1038 err = pseries_add_mem_node(rd->dn);
1039 break;
1040 case OF_RECONFIG_DETACH_NODE:
1041 err = pseries_remove_mem_node(rd->dn);
1042 break;
1043 case OF_RECONFIG_UPDATE_PROPERTY:
1044 if (!strcmp(rd->prop->name, "ibm,dynamic-memory"))
1045 err = pseries_update_drconf_memory(rd);
1046 break;
1047 }
1048 return notifier_from_errno(err);
1049 }
1050
1051 static struct notifier_block pseries_mem_nb = {
1052 .notifier_call = pseries_memory_notifier,
1053 };
1054
1055 static int __init pseries_memory_hotplug_init(void)
1056 {
1057 if (firmware_has_feature(FW_FEATURE_LPAR))
1058 of_reconfig_notifier_register(&pseries_mem_nb);
1059
1060 return 0;
1061 }
1062 machine_device_initcall(pseries, pseries_memory_hotplug_init);