2 * pseries Memory Hotplug infrastructure.
4 * Copyright (C) 2008 Badari Pulavarty, IBM Corporation
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #define pr_fmt(fmt) "pseries-hotplug-mem: " fmt
15 #include <linux/of_address.h>
16 #include <linux/memblock.h>
17 #include <linux/memory.h>
18 #include <linux/memory_hotplug.h>
19 #include <linux/slab.h>
21 #include <asm/firmware.h>
22 #include <asm/machdep.h>
24 #include <asm/sparsemem.h>
25 #include <asm/fadump.h>
26 #include <asm/drmem.h>
29 static bool rtas_hp_event
;
31 unsigned long pseries_memory_block_size(void)
33 struct device_node
*np
;
34 unsigned int memblock_size
= MIN_MEMORY_BLOCK_SIZE
;
37 np
= of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
41 size
= of_get_property(np
, "ibm,lmb-size", NULL
);
43 memblock_size
= be64_to_cpup(size
);
45 } else if (machine_is(pseries
)) {
46 /* This fallback really only applies to pseries */
47 unsigned int memzero_size
= 0;
49 np
= of_find_node_by_path("/memory@0");
51 if (!of_address_to_resource(np
, 0, &r
))
52 memzero_size
= resource_size(&r
);
57 /* We now know the size of memory@0, use this to find
58 * the first memoryblock and get its size.
62 sprintf(buf
, "/memory@%x", memzero_size
);
63 np
= of_find_node_by_path(buf
);
65 if (!of_address_to_resource(np
, 0, &r
))
66 memblock_size
= resource_size(&r
);
74 static void dlpar_free_property(struct property
*prop
)
81 static struct property
*dlpar_clone_property(struct property
*prop
,
84 struct property
*new_prop
;
86 new_prop
= kzalloc(sizeof(*new_prop
), GFP_KERNEL
);
90 new_prop
->name
= kstrdup(prop
->name
, GFP_KERNEL
);
91 new_prop
->value
= kzalloc(prop_size
, GFP_KERNEL
);
92 if (!new_prop
->name
|| !new_prop
->value
) {
93 dlpar_free_property(new_prop
);
97 memcpy(new_prop
->value
, prop
->value
, prop
->length
);
98 new_prop
->length
= prop_size
;
100 of_property_set_flag(new_prop
, OF_DYNAMIC
);
104 static u32
find_aa_index(struct device_node
*dr_node
,
105 struct property
*ala_prop
, const u32
*lmb_assoc
)
109 int aa_arrays
, aa_array_entries
, aa_array_sz
;
113 * The ibm,associativity-lookup-arrays property is defined to be
114 * a 32-bit value specifying the number of associativity arrays
115 * followed by a 32-bitvalue specifying the number of entries per
116 * array, followed by the associativity arrays.
118 assoc_arrays
= ala_prop
->value
;
120 aa_arrays
= be32_to_cpu(assoc_arrays
[0]);
121 aa_array_entries
= be32_to_cpu(assoc_arrays
[1]);
122 aa_array_sz
= aa_array_entries
* sizeof(u32
);
125 for (i
= 0; i
< aa_arrays
; i
++) {
126 index
= (i
* aa_array_entries
) + 2;
128 if (memcmp(&assoc_arrays
[index
], &lmb_assoc
[1], aa_array_sz
))
135 if (aa_index
== -1) {
136 struct property
*new_prop
;
139 new_prop_size
= ala_prop
->length
+ aa_array_sz
;
140 new_prop
= dlpar_clone_property(ala_prop
, new_prop_size
);
144 assoc_arrays
= new_prop
->value
;
146 /* increment the number of entries in the lookup array */
147 assoc_arrays
[0] = cpu_to_be32(aa_arrays
+ 1);
149 /* copy the new associativity into the lookup array */
150 index
= aa_arrays
* aa_array_entries
+ 2;
151 memcpy(&assoc_arrays
[index
], &lmb_assoc
[1], aa_array_sz
);
153 of_update_property(dr_node
, new_prop
);
156 * The associativity lookup array index for this lmb is
157 * number of entries - 1 since we added its associativity
158 * to the end of the lookup array.
160 aa_index
= be32_to_cpu(assoc_arrays
[0]) - 1;
166 static u32
lookup_lmb_associativity_index(struct drmem_lmb
*lmb
)
168 struct device_node
*parent
, *lmb_node
, *dr_node
;
169 struct property
*ala_prop
;
170 const u32
*lmb_assoc
;
173 parent
= of_find_node_by_path("/");
177 lmb_node
= dlpar_configure_connector(cpu_to_be32(lmb
->drc_index
),
183 lmb_assoc
= of_get_property(lmb_node
, "ibm,associativity", NULL
);
185 dlpar_free_cc_nodes(lmb_node
);
189 dr_node
= of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
191 dlpar_free_cc_nodes(lmb_node
);
195 ala_prop
= of_find_property(dr_node
, "ibm,associativity-lookup-arrays",
198 of_node_put(dr_node
);
199 dlpar_free_cc_nodes(lmb_node
);
203 aa_index
= find_aa_index(dr_node
, ala_prop
, lmb_assoc
);
205 dlpar_free_cc_nodes(lmb_node
);
209 static int dlpar_add_device_tree_lmb(struct drmem_lmb
*lmb
)
213 lmb
->flags
|= DRCONF_MEM_ASSIGNED
;
215 aa_index
= lookup_lmb_associativity_index(lmb
);
217 pr_err("Couldn't find associativity index for drc index %x\n",
222 lmb
->aa_index
= aa_index
;
224 rtas_hp_event
= true;
225 rc
= drmem_update_dt();
226 rtas_hp_event
= false;
231 static int dlpar_remove_device_tree_lmb(struct drmem_lmb
*lmb
)
235 lmb
->flags
&= ~DRCONF_MEM_ASSIGNED
;
236 lmb
->aa_index
= 0xffffffff;
238 rtas_hp_event
= true;
239 rc
= drmem_update_dt();
240 rtas_hp_event
= false;
245 static struct memory_block
*lmb_to_memblock(struct drmem_lmb
*lmb
)
247 unsigned long section_nr
;
248 struct mem_section
*mem_sect
;
249 struct memory_block
*mem_block
;
251 section_nr
= pfn_to_section_nr(PFN_DOWN(lmb
->base_addr
));
252 mem_sect
= __nr_to_section(section_nr
);
254 mem_block
= find_memory_block(mem_sect
);
258 static int get_lmb_range(u32 drc_index
, int n_lmbs
,
259 struct drmem_lmb
**start_lmb
,
260 struct drmem_lmb
**end_lmb
)
262 struct drmem_lmb
*lmb
, *start
, *end
;
263 struct drmem_lmb
*last_lmb
;
266 for_each_drmem_lmb(lmb
) {
267 if (lmb
->drc_index
== drc_index
) {
276 end
= &start
[n_lmbs
- 1];
278 last_lmb
= &drmem_info
->lmbs
[drmem_info
->n_lmbs
- 1];
287 static int dlpar_change_lmb_state(struct drmem_lmb
*lmb
, bool online
)
289 struct memory_block
*mem_block
;
292 mem_block
= lmb_to_memblock(lmb
);
296 if (online
&& mem_block
->dev
.offline
)
297 rc
= device_online(&mem_block
->dev
);
298 else if (!online
&& !mem_block
->dev
.offline
)
299 rc
= device_offline(&mem_block
->dev
);
303 put_device(&mem_block
->dev
);
308 static int dlpar_online_lmb(struct drmem_lmb
*lmb
)
310 return dlpar_change_lmb_state(lmb
, true);
313 #ifdef CONFIG_MEMORY_HOTREMOVE
314 static int dlpar_offline_lmb(struct drmem_lmb
*lmb
)
316 return dlpar_change_lmb_state(lmb
, false);
319 static int pseries_remove_memblock(unsigned long base
, unsigned int memblock_size
)
321 unsigned long block_sz
, start_pfn
;
322 int sections_per_block
;
325 start_pfn
= base
>> PAGE_SHIFT
;
327 lock_device_hotplug();
329 if (!pfn_valid(start_pfn
))
332 block_sz
= pseries_memory_block_size();
333 sections_per_block
= block_sz
/ MIN_MEMORY_BLOCK_SIZE
;
334 nid
= memory_add_physaddr_to_nid(base
);
336 for (i
= 0; i
< sections_per_block
; i
++) {
337 remove_memory(nid
, base
, MIN_MEMORY_BLOCK_SIZE
);
338 base
+= MIN_MEMORY_BLOCK_SIZE
;
342 /* Update memory regions for memory remove */
343 memblock_remove(base
, memblock_size
);
344 unlock_device_hotplug();
348 static int pseries_remove_mem_node(struct device_node
*np
)
353 unsigned int lmb_size
;
357 * Check to see if we are actually removing memory
359 type
= of_get_property(np
, "device_type", NULL
);
360 if (type
== NULL
|| strcmp(type
, "memory") != 0)
364 * Find the base address and size of the memblock
366 regs
= of_get_property(np
, "reg", NULL
);
370 base
= be64_to_cpu(*(unsigned long *)regs
);
371 lmb_size
= be32_to_cpu(regs
[3]);
373 pseries_remove_memblock(base
, lmb_size
);
377 static bool lmb_is_removable(struct drmem_lmb
*lmb
)
379 int i
, scns_per_block
;
381 unsigned long pfn
, block_sz
;
384 if (!(lmb
->flags
& DRCONF_MEM_ASSIGNED
))
387 block_sz
= memory_block_size_bytes();
388 scns_per_block
= block_sz
/ MIN_MEMORY_BLOCK_SIZE
;
389 phys_addr
= lmb
->base_addr
;
391 #ifdef CONFIG_FA_DUMP
392 /* Don't hot-remove memory that falls in fadump boot memory area */
393 if (is_fadump_boot_memory_area(phys_addr
, block_sz
))
397 for (i
= 0; i
< scns_per_block
; i
++) {
398 pfn
= PFN_DOWN(phys_addr
);
399 if (!pfn_present(pfn
))
402 rc
&= is_mem_section_removable(pfn
, PAGES_PER_SECTION
);
403 phys_addr
+= MIN_MEMORY_BLOCK_SIZE
;
406 return rc
? true : false;
409 static int dlpar_add_lmb(struct drmem_lmb
*);
411 static int dlpar_remove_lmb(struct drmem_lmb
*lmb
)
413 unsigned long block_sz
;
416 if (!lmb_is_removable(lmb
))
419 rc
= dlpar_offline_lmb(lmb
);
423 block_sz
= pseries_memory_block_size();
424 nid
= memory_add_physaddr_to_nid(lmb
->base_addr
);
426 remove_memory(nid
, lmb
->base_addr
, block_sz
);
428 /* Update memory regions for memory remove */
429 memblock_remove(lmb
->base_addr
, block_sz
);
431 dlpar_remove_device_tree_lmb(lmb
);
435 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove
)
437 struct drmem_lmb
*lmb
;
438 int lmbs_removed
= 0;
439 int lmbs_available
= 0;
442 pr_info("Attempting to hot-remove %d LMB(s)\n", lmbs_to_remove
);
444 if (lmbs_to_remove
== 0)
447 /* Validate that there are enough LMBs to satisfy the request */
448 for_each_drmem_lmb(lmb
) {
449 if (lmb_is_removable(lmb
))
452 if (lmbs_available
== lmbs_to_remove
)
456 if (lmbs_available
< lmbs_to_remove
) {
457 pr_info("Not enough LMBs available (%d of %d) to satisfy request\n",
458 lmbs_available
, lmbs_to_remove
);
462 for_each_drmem_lmb(lmb
) {
463 rc
= dlpar_remove_lmb(lmb
);
467 /* Mark this lmb so we can add it later if all of the
468 * requested LMBs cannot be removed.
470 drmem_mark_lmb_reserved(lmb
);
473 if (lmbs_removed
== lmbs_to_remove
)
477 if (lmbs_removed
!= lmbs_to_remove
) {
478 pr_err("Memory hot-remove failed, adding LMB's back\n");
480 for_each_drmem_lmb(lmb
) {
481 if (!drmem_lmb_reserved(lmb
))
484 rc
= dlpar_add_lmb(lmb
);
486 pr_err("Failed to add LMB back, drc index %x\n",
489 drmem_remove_lmb_reservation(lmb
);
494 for_each_drmem_lmb(lmb
) {
495 if (!drmem_lmb_reserved(lmb
))
498 dlpar_release_drc(lmb
->drc_index
);
499 pr_info("Memory at %llx was hot-removed\n",
502 drmem_remove_lmb_reservation(lmb
);
510 static int dlpar_memory_remove_by_index(u32 drc_index
)
512 struct drmem_lmb
*lmb
;
516 pr_info("Attempting to hot-remove LMB, drc index %x\n", drc_index
);
519 for_each_drmem_lmb(lmb
) {
520 if (lmb
->drc_index
== drc_index
) {
522 rc
= dlpar_remove_lmb(lmb
);
524 dlpar_release_drc(lmb
->drc_index
);
534 pr_info("Failed to hot-remove memory at %llx\n",
537 pr_info("Memory at %llx was hot-removed\n", lmb
->base_addr
);
542 static int dlpar_memory_readd_by_index(u32 drc_index
)
544 struct drmem_lmb
*lmb
;
548 pr_info("Attempting to update LMB, drc index %x\n", drc_index
);
551 for_each_drmem_lmb(lmb
) {
552 if (lmb
->drc_index
== drc_index
) {
554 rc
= dlpar_remove_lmb(lmb
);
556 rc
= dlpar_add_lmb(lmb
);
558 dlpar_release_drc(lmb
->drc_index
);
568 pr_info("Failed to update memory at %llx\n",
571 pr_info("Memory at %llx was updated\n", lmb
->base_addr
);
576 static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove
, u32 drc_index
)
578 struct drmem_lmb
*lmb
, *start_lmb
, *end_lmb
;
579 int lmbs_available
= 0;
582 pr_info("Attempting to hot-remove %u LMB(s) at %x\n",
583 lmbs_to_remove
, drc_index
);
585 if (lmbs_to_remove
== 0)
588 rc
= get_lmb_range(drc_index
, lmbs_to_remove
, &start_lmb
, &end_lmb
);
592 /* Validate that there are enough LMBs to satisfy the request */
593 for_each_drmem_lmb_in_range(lmb
, start_lmb
, end_lmb
) {
594 if (lmb
->flags
& DRCONF_MEM_RESERVED
)
600 if (lmbs_available
< lmbs_to_remove
)
603 for_each_drmem_lmb_in_range(lmb
, start_lmb
, end_lmb
) {
604 if (!(lmb
->flags
& DRCONF_MEM_ASSIGNED
))
607 rc
= dlpar_remove_lmb(lmb
);
611 drmem_mark_lmb_reserved(lmb
);
615 pr_err("Memory indexed-count-remove failed, adding any removed LMBs\n");
618 for_each_drmem_lmb_in_range(lmb
, start_lmb
, end_lmb
) {
619 if (!drmem_lmb_reserved(lmb
))
622 rc
= dlpar_add_lmb(lmb
);
624 pr_err("Failed to add LMB, drc index %x\n",
627 drmem_remove_lmb_reservation(lmb
);
631 for_each_drmem_lmb_in_range(lmb
, start_lmb
, end_lmb
) {
632 if (!drmem_lmb_reserved(lmb
))
635 dlpar_release_drc(lmb
->drc_index
);
636 pr_info("Memory at %llx (drc index %x) was hot-removed\n",
637 lmb
->base_addr
, lmb
->drc_index
);
639 drmem_remove_lmb_reservation(lmb
);
647 static inline int pseries_remove_memblock(unsigned long base
,
648 unsigned int memblock_size
)
652 static inline int pseries_remove_mem_node(struct device_node
*np
)
656 static inline int dlpar_memory_remove(struct pseries_hp_errorlog
*hp_elog
)
660 static int dlpar_remove_lmb(struct drmem_lmb
*lmb
)
664 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove
)
668 static int dlpar_memory_remove_by_index(u32 drc_index
)
672 static int dlpar_memory_readd_by_index(u32 drc_index
)
677 static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove
, u32 drc_index
)
681 #endif /* CONFIG_MEMORY_HOTREMOVE */
683 static int dlpar_add_lmb(struct drmem_lmb
*lmb
)
685 unsigned long block_sz
;
688 if (lmb
->flags
& DRCONF_MEM_ASSIGNED
)
691 rc
= dlpar_add_device_tree_lmb(lmb
);
693 pr_err("Couldn't update device tree for drc index %x\n",
695 dlpar_release_drc(lmb
->drc_index
);
699 block_sz
= memory_block_size_bytes();
701 /* Find the node id for this address */
702 nid
= memory_add_physaddr_to_nid(lmb
->base_addr
);
705 rc
= add_memory(nid
, lmb
->base_addr
, block_sz
);
707 dlpar_remove_device_tree_lmb(lmb
);
711 rc
= dlpar_online_lmb(lmb
);
713 remove_memory(nid
, lmb
->base_addr
, block_sz
);
714 dlpar_remove_device_tree_lmb(lmb
);
716 lmb
->flags
|= DRCONF_MEM_ASSIGNED
;
722 static int dlpar_memory_add_by_count(u32 lmbs_to_add
)
724 struct drmem_lmb
*lmb
;
725 int lmbs_available
= 0;
729 pr_info("Attempting to hot-add %d LMB(s)\n", lmbs_to_add
);
731 if (lmbs_to_add
== 0)
734 /* Validate that there are enough LMBs to satisfy the request */
735 for_each_drmem_lmb(lmb
) {
736 if (!(lmb
->flags
& DRCONF_MEM_ASSIGNED
))
739 if (lmbs_available
== lmbs_to_add
)
743 if (lmbs_available
< lmbs_to_add
)
746 for_each_drmem_lmb(lmb
) {
747 if (lmb
->flags
& DRCONF_MEM_ASSIGNED
)
750 rc
= dlpar_acquire_drc(lmb
->drc_index
);
754 rc
= dlpar_add_lmb(lmb
);
756 dlpar_release_drc(lmb
->drc_index
);
760 /* Mark this lmb so we can remove it later if all of the
761 * requested LMBs cannot be added.
763 drmem_mark_lmb_reserved(lmb
);
766 if (lmbs_added
== lmbs_to_add
)
770 if (lmbs_added
!= lmbs_to_add
) {
771 pr_err("Memory hot-add failed, removing any added LMBs\n");
773 for_each_drmem_lmb(lmb
) {
774 if (!drmem_lmb_reserved(lmb
))
777 rc
= dlpar_remove_lmb(lmb
);
779 pr_err("Failed to remove LMB, drc index %x\n",
782 dlpar_release_drc(lmb
->drc_index
);
784 drmem_remove_lmb_reservation(lmb
);
788 for_each_drmem_lmb(lmb
) {
789 if (!drmem_lmb_reserved(lmb
))
792 pr_info("Memory at %llx (drc index %x) was hot-added\n",
793 lmb
->base_addr
, lmb
->drc_index
);
794 drmem_remove_lmb_reservation(lmb
);
802 static int dlpar_memory_add_by_index(u32 drc_index
)
804 struct drmem_lmb
*lmb
;
807 pr_info("Attempting to hot-add LMB, drc index %x\n", drc_index
);
810 for_each_drmem_lmb(lmb
) {
811 if (lmb
->drc_index
== drc_index
) {
813 rc
= dlpar_acquire_drc(lmb
->drc_index
);
815 rc
= dlpar_add_lmb(lmb
);
817 dlpar_release_drc(lmb
->drc_index
);
828 pr_info("Failed to hot-add memory, drc index %x\n", drc_index
);
830 pr_info("Memory at %llx (drc index %x) was hot-added\n",
831 lmb
->base_addr
, drc_index
);
836 static int dlpar_memory_add_by_ic(u32 lmbs_to_add
, u32 drc_index
)
838 struct drmem_lmb
*lmb
, *start_lmb
, *end_lmb
;
839 int lmbs_available
= 0;
842 pr_info("Attempting to hot-add %u LMB(s) at index %x\n",
843 lmbs_to_add
, drc_index
);
845 if (lmbs_to_add
== 0)
848 rc
= get_lmb_range(drc_index
, lmbs_to_add
, &start_lmb
, &end_lmb
);
852 /* Validate that the LMBs in this range are not reserved */
853 for_each_drmem_lmb_in_range(lmb
, start_lmb
, end_lmb
) {
854 if (lmb
->flags
& DRCONF_MEM_RESERVED
)
860 if (lmbs_available
< lmbs_to_add
)
863 for_each_drmem_lmb_in_range(lmb
, start_lmb
, end_lmb
) {
864 if (lmb
->flags
& DRCONF_MEM_ASSIGNED
)
867 rc
= dlpar_acquire_drc(lmb
->drc_index
);
871 rc
= dlpar_add_lmb(lmb
);
873 dlpar_release_drc(lmb
->drc_index
);
877 drmem_mark_lmb_reserved(lmb
);
881 pr_err("Memory indexed-count-add failed, removing any added LMBs\n");
883 for_each_drmem_lmb_in_range(lmb
, start_lmb
, end_lmb
) {
884 if (!drmem_lmb_reserved(lmb
))
887 rc
= dlpar_remove_lmb(lmb
);
889 pr_err("Failed to remove LMB, drc index %x\n",
892 dlpar_release_drc(lmb
->drc_index
);
894 drmem_remove_lmb_reservation(lmb
);
898 for_each_drmem_lmb_in_range(lmb
, start_lmb
, end_lmb
) {
899 if (!drmem_lmb_reserved(lmb
))
902 pr_info("Memory at %llx (drc index %x) was hot-added\n",
903 lmb
->base_addr
, lmb
->drc_index
);
904 drmem_remove_lmb_reservation(lmb
);
911 int dlpar_memory(struct pseries_hp_errorlog
*hp_elog
)
913 u32 count
, drc_index
;
916 lock_device_hotplug();
918 switch (hp_elog
->action
) {
919 case PSERIES_HP_ELOG_ACTION_ADD
:
920 if (hp_elog
->id_type
== PSERIES_HP_ELOG_ID_DRC_COUNT
) {
921 count
= hp_elog
->_drc_u
.drc_count
;
922 rc
= dlpar_memory_add_by_count(count
);
923 } else if (hp_elog
->id_type
== PSERIES_HP_ELOG_ID_DRC_INDEX
) {
924 drc_index
= hp_elog
->_drc_u
.drc_index
;
925 rc
= dlpar_memory_add_by_index(drc_index
);
926 } else if (hp_elog
->id_type
== PSERIES_HP_ELOG_ID_DRC_IC
) {
927 count
= hp_elog
->_drc_u
.ic
.count
;
928 drc_index
= hp_elog
->_drc_u
.ic
.index
;
929 rc
= dlpar_memory_add_by_ic(count
, drc_index
);
935 case PSERIES_HP_ELOG_ACTION_REMOVE
:
936 if (hp_elog
->id_type
== PSERIES_HP_ELOG_ID_DRC_COUNT
) {
937 count
= hp_elog
->_drc_u
.drc_count
;
938 rc
= dlpar_memory_remove_by_count(count
);
939 } else if (hp_elog
->id_type
== PSERIES_HP_ELOG_ID_DRC_INDEX
) {
940 drc_index
= hp_elog
->_drc_u
.drc_index
;
941 rc
= dlpar_memory_remove_by_index(drc_index
);
942 } else if (hp_elog
->id_type
== PSERIES_HP_ELOG_ID_DRC_IC
) {
943 count
= hp_elog
->_drc_u
.ic
.count
;
944 drc_index
= hp_elog
->_drc_u
.ic
.index
;
945 rc
= dlpar_memory_remove_by_ic(count
, drc_index
);
951 case PSERIES_HP_ELOG_ACTION_READD
:
952 drc_index
= hp_elog
->_drc_u
.drc_index
;
953 rc
= dlpar_memory_readd_by_index(drc_index
);
956 pr_err("Invalid action (%d) specified\n", hp_elog
->action
);
961 unlock_device_hotplug();
965 static int pseries_add_mem_node(struct device_node
*np
)
970 unsigned int lmb_size
;
974 * Check to see if we are actually adding memory
976 type
= of_get_property(np
, "device_type", NULL
);
977 if (type
== NULL
|| strcmp(type
, "memory") != 0)
981 * Find the base and size of the memblock
983 regs
= of_get_property(np
, "reg", NULL
);
987 base
= be64_to_cpu(*(unsigned long *)regs
);
988 lmb_size
= be32_to_cpu(regs
[3]);
991 * Update memory region to represent the memory add
993 ret
= memblock_add(base
, lmb_size
);
994 return (ret
< 0) ? -EINVAL
: 0;
997 static int pseries_update_drconf_memory(struct of_reconfig_data
*pr
)
999 struct of_drconf_cell_v1
*new_drmem
, *old_drmem
;
1000 unsigned long memblock_size
;
1003 int i
, rc
= -EINVAL
;
1008 memblock_size
= pseries_memory_block_size();
1012 p
= (__be32
*) pr
->old_prop
->value
;
1016 /* The first int of the property is the number of lmb's described
1017 * by the property. This is followed by an array of of_drconf_cell
1018 * entries. Get the number of entries and skip to the array of
1021 entries
= be32_to_cpu(*p
++);
1022 old_drmem
= (struct of_drconf_cell_v1
*)p
;
1024 p
= (__be32
*)pr
->prop
->value
;
1026 new_drmem
= (struct of_drconf_cell_v1
*)p
;
1028 for (i
= 0; i
< entries
; i
++) {
1029 if ((be32_to_cpu(old_drmem
[i
].flags
) & DRCONF_MEM_ASSIGNED
) &&
1030 (!(be32_to_cpu(new_drmem
[i
].flags
) & DRCONF_MEM_ASSIGNED
))) {
1031 rc
= pseries_remove_memblock(
1032 be64_to_cpu(old_drmem
[i
].base_addr
),
1035 } else if ((!(be32_to_cpu(old_drmem
[i
].flags
) &
1036 DRCONF_MEM_ASSIGNED
)) &&
1037 (be32_to_cpu(new_drmem
[i
].flags
) &
1038 DRCONF_MEM_ASSIGNED
)) {
1039 rc
= memblock_add(be64_to_cpu(old_drmem
[i
].base_addr
),
1041 rc
= (rc
< 0) ? -EINVAL
: 0;
1048 static int pseries_memory_notifier(struct notifier_block
*nb
,
1049 unsigned long action
, void *data
)
1051 struct of_reconfig_data
*rd
= data
;
1055 case OF_RECONFIG_ATTACH_NODE
:
1056 err
= pseries_add_mem_node(rd
->dn
);
1058 case OF_RECONFIG_DETACH_NODE
:
1059 err
= pseries_remove_mem_node(rd
->dn
);
1061 case OF_RECONFIG_UPDATE_PROPERTY
:
1062 if (!strcmp(rd
->prop
->name
, "ibm,dynamic-memory"))
1063 err
= pseries_update_drconf_memory(rd
);
1066 return notifier_from_errno(err
);
1069 static struct notifier_block pseries_mem_nb
= {
1070 .notifier_call
= pseries_memory_notifier
,
1073 static int __init
pseries_memory_hotplug_init(void)
1075 if (firmware_has_feature(FW_FEATURE_LPAR
))
1076 of_reconfig_notifier_register(&pseries_mem_nb
);
1080 machine_device_initcall(pseries
, pseries_memory_hotplug_init
);