1 /*
2  * pseries Memory Hotplug infrastructure.
3  *
4  * Copyright (C) 2008 Badari Pulavarty, IBM Corporation
5  *
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.
10  */
11 
12 #define pr_fmt(fmt)	"pseries-hotplug-mem: " fmt
13 
14 #include <linux/of.h>
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>
20 
21 #include <asm/firmware.h>
22 #include <asm/machdep.h>
23 #include <asm/prom.h>
24 #include <asm/sparsemem.h>
25 #include "pseries.h"
26 
27 static bool rtas_hp_event;
28 
29 unsigned long pseries_memory_block_size(void)
30 {
31 	struct device_node *np;
32 	unsigned int memblock_size = MIN_MEMORY_BLOCK_SIZE;
33 	struct resource r;
34 
35 	np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
36 	if (np) {
37 		const __be64 *size;
38 
39 		size = of_get_property(np, "ibm,lmb-size", NULL);
40 		if (size)
41 			memblock_size = be64_to_cpup(size);
42 		of_node_put(np);
43 	} else  if (machine_is(pseries)) {
44 		/* This fallback really only applies to pseries */
45 		unsigned int memzero_size = 0;
46 
47 		np = of_find_node_by_path("/memory@0");
48 		if (np) {
49 			if (!of_address_to_resource(np, 0, &r))
50 				memzero_size = resource_size(&r);
51 			of_node_put(np);
52 		}
53 
54 		if (memzero_size) {
55 			/* We now know the size of memory@0, use this to find
56 			 * the first memoryblock and get its size.
57 			 */
58 			char buf[64];
59 
60 			sprintf(buf, "/memory@%x", memzero_size);
61 			np = of_find_node_by_path(buf);
62 			if (np) {
63 				if (!of_address_to_resource(np, 0, &r))
64 					memblock_size = resource_size(&r);
65 				of_node_put(np);
66 			}
67 		}
68 	}
69 	return memblock_size;
70 }
71 
72 static void dlpar_free_drconf_property(struct property *prop)
73 {
74 	kfree(prop->name);
75 	kfree(prop->value);
76 	kfree(prop);
77 }
78 
79 static struct property *dlpar_clone_drconf_property(struct device_node *dn)
80 {
81 	struct property *prop, *new_prop;
82 	struct of_drconf_cell *lmbs;
83 	u32 num_lmbs, *p;
84 	int i;
85 
86 	prop = of_find_property(dn, "ibm,dynamic-memory", NULL);
87 	if (!prop)
88 		return NULL;
89 
90 	new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
91 	if (!new_prop)
92 		return NULL;
93 
94 	new_prop->name = kstrdup(prop->name, GFP_KERNEL);
95 	new_prop->value = kmemdup(prop->value, prop->length, GFP_KERNEL);
96 	if (!new_prop->name || !new_prop->value) {
97 		dlpar_free_drconf_property(new_prop);
98 		return NULL;
99 	}
100 
101 	new_prop->length = prop->length;
102 
103 	/* Convert the property to cpu endian-ness */
104 	p = new_prop->value;
105 	*p = be32_to_cpu(*p);
106 
107 	num_lmbs = *p++;
108 	lmbs = (struct of_drconf_cell *)p;
109 
110 	for (i = 0; i < num_lmbs; i++) {
111 		lmbs[i].base_addr = be64_to_cpu(lmbs[i].base_addr);
112 		lmbs[i].drc_index = be32_to_cpu(lmbs[i].drc_index);
113 		lmbs[i].flags = be32_to_cpu(lmbs[i].flags);
114 	}
115 
116 	return new_prop;
117 }
118 
119 static void dlpar_update_drconf_property(struct device_node *dn,
120 					 struct property *prop)
121 {
122 	struct of_drconf_cell *lmbs;
123 	u32 num_lmbs, *p;
124 	int i;
125 
126 	/* Convert the property back to BE */
127 	p = prop->value;
128 	num_lmbs = *p;
129 	*p = cpu_to_be32(*p);
130 	p++;
131 
132 	lmbs = (struct of_drconf_cell *)p;
133 	for (i = 0; i < num_lmbs; i++) {
134 		lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr);
135 		lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index);
136 		lmbs[i].flags = cpu_to_be32(lmbs[i].flags);
137 	}
138 
139 	rtas_hp_event = true;
140 	of_update_property(dn, prop);
141 	rtas_hp_event = false;
142 }
143 
144 static int dlpar_update_device_tree_lmb(struct of_drconf_cell *lmb)
145 {
146 	struct device_node *dn;
147 	struct property *prop;
148 	struct of_drconf_cell *lmbs;
149 	u32 *p, num_lmbs;
150 	int i;
151 
152 	dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
153 	if (!dn)
154 		return -ENODEV;
155 
156 	prop = dlpar_clone_drconf_property(dn);
157 	if (!prop) {
158 		of_node_put(dn);
159 		return -ENODEV;
160 	}
161 
162 	p = prop->value;
163 	num_lmbs = *p++;
164 	lmbs = (struct of_drconf_cell *)p;
165 
166 	for (i = 0; i < num_lmbs; i++) {
167 		if (lmbs[i].drc_index == lmb->drc_index) {
168 			lmbs[i].flags = lmb->flags;
169 			lmbs[i].aa_index = lmb->aa_index;
170 
171 			dlpar_update_drconf_property(dn, prop);
172 			break;
173 		}
174 	}
175 
176 	of_node_put(dn);
177 	return 0;
178 }
179 
180 static u32 lookup_lmb_associativity_index(struct of_drconf_cell *lmb)
181 {
182 	struct device_node *parent, *lmb_node, *dr_node;
183 	const u32 *lmb_assoc;
184 	const u32 *assoc_arrays;
185 	u32 aa_index;
186 	int aa_arrays, aa_array_entries, aa_array_sz;
187 	int i;
188 
189 	parent = of_find_node_by_path("/");
190 	if (!parent)
191 		return -ENODEV;
192 
193 	lmb_node = dlpar_configure_connector(cpu_to_be32(lmb->drc_index),
194 					     parent);
195 	of_node_put(parent);
196 	if (!lmb_node)
197 		return -EINVAL;
198 
199 	lmb_assoc = of_get_property(lmb_node, "ibm,associativity", NULL);
200 	if (!lmb_assoc) {
201 		dlpar_free_cc_nodes(lmb_node);
202 		return -ENODEV;
203 	}
204 
205 	dr_node = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
206 	if (!dr_node) {
207 		dlpar_free_cc_nodes(lmb_node);
208 		return -ENODEV;
209 	}
210 
211 	assoc_arrays = of_get_property(dr_node,
212 				       "ibm,associativity-lookup-arrays",
213 				       NULL);
214 	of_node_put(dr_node);
215 	if (!assoc_arrays) {
216 		dlpar_free_cc_nodes(lmb_node);
217 		return -ENODEV;
218 	}
219 
220 	/* The ibm,associativity-lookup-arrays property is defined to be
221 	 * a 32-bit value specifying the number of associativity arrays
222 	 * followed by a 32-bitvalue specifying the number of entries per
223 	 * array, followed by the associativity arrays.
224 	 */
225 	aa_arrays = be32_to_cpu(assoc_arrays[0]);
226 	aa_array_entries = be32_to_cpu(assoc_arrays[1]);
227 	aa_array_sz = aa_array_entries * sizeof(u32);
228 
229 	aa_index = -1;
230 	for (i = 0; i < aa_arrays; i++) {
231 		int indx = (i * aa_array_entries) + 2;
232 
233 		if (memcmp(&assoc_arrays[indx], &lmb_assoc[1], aa_array_sz))
234 			continue;
235 
236 		aa_index = i;
237 		break;
238 	}
239 
240 	dlpar_free_cc_nodes(lmb_node);
241 	return aa_index;
242 }
243 
244 static int dlpar_add_device_tree_lmb(struct of_drconf_cell *lmb)
245 {
246 	int aa_index;
247 
248 	lmb->flags |= DRCONF_MEM_ASSIGNED;
249 
250 	aa_index = lookup_lmb_associativity_index(lmb);
251 	if (aa_index < 0) {
252 		pr_err("Couldn't find associativity index for drc index %x\n",
253 		       lmb->drc_index);
254 		return aa_index;
255 	}
256 
257 	lmb->aa_index = aa_index;
258 	return dlpar_update_device_tree_lmb(lmb);
259 }
260 
261 static int dlpar_remove_device_tree_lmb(struct of_drconf_cell *lmb)
262 {
263 	lmb->flags &= ~DRCONF_MEM_ASSIGNED;
264 	lmb->aa_index = 0xffffffff;
265 	return dlpar_update_device_tree_lmb(lmb);
266 }
267 
268 static struct memory_block *lmb_to_memblock(struct of_drconf_cell *lmb)
269 {
270 	unsigned long section_nr;
271 	struct mem_section *mem_sect;
272 	struct memory_block *mem_block;
273 
274 	section_nr = pfn_to_section_nr(PFN_DOWN(lmb->base_addr));
275 	mem_sect = __nr_to_section(section_nr);
276 
277 	mem_block = find_memory_block(mem_sect);
278 	return mem_block;
279 }
280 
281 #ifdef CONFIG_MEMORY_HOTREMOVE
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 	/* Update memory regions for memory remove */
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 char *type;
314 	const __be32 *regs;
315 	unsigned long base;
316 	unsigned int lmb_size;
317 	int ret = -EINVAL;
318 
319 	/*
320 	 * Check to see if we are actually removing memory
321 	 */
322 	type = of_get_property(np, "device_type", NULL);
323 	if (type == NULL || strcmp(type, "memory") != 0)
324 		return 0;
325 
326 	/*
327 	 * Find the base address and size of the memblock
328 	 */
329 	regs = of_get_property(np, "reg", NULL);
330 	if (!regs)
331 		return ret;
332 
333 	base = be64_to_cpu(*(unsigned long *)regs);
334 	lmb_size = be32_to_cpu(regs[3]);
335 
336 	pseries_remove_memblock(base, lmb_size);
337 	return 0;
338 }
339 
340 static bool lmb_is_removable(struct of_drconf_cell *lmb)
341 {
342 	int i, scns_per_block;
343 	int rc = 1;
344 	unsigned long pfn, block_sz;
345 	u64 phys_addr;
346 
347 	if (!(lmb->flags & DRCONF_MEM_ASSIGNED))
348 		return false;
349 
350 	block_sz = memory_block_size_bytes();
351 	scns_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
352 	phys_addr = lmb->base_addr;
353 
354 	for (i = 0; i < scns_per_block; i++) {
355 		pfn = PFN_DOWN(phys_addr);
356 		if (!pfn_present(pfn))
357 			continue;
358 
359 		rc &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
360 		phys_addr += MIN_MEMORY_BLOCK_SIZE;
361 	}
362 
363 	return rc ? true : false;
364 }
365 
366 static int dlpar_add_lmb(struct of_drconf_cell *);
367 
368 static int dlpar_remove_lmb(struct of_drconf_cell *lmb)
369 {
370 	struct memory_block *mem_block;
371 	unsigned long block_sz;
372 	int nid, rc;
373 
374 	if (!lmb_is_removable(lmb))
375 		return -EINVAL;
376 
377 	mem_block = lmb_to_memblock(lmb);
378 	if (!mem_block)
379 		return -EINVAL;
380 
381 	rc = device_offline(&mem_block->dev);
382 	put_device(&mem_block->dev);
383 	if (rc)
384 		return rc;
385 
386 	block_sz = pseries_memory_block_size();
387 	nid = memory_add_physaddr_to_nid(lmb->base_addr);
388 
389 	remove_memory(nid, lmb->base_addr, block_sz);
390 
391 	/* Update memory regions for memory remove */
392 	memblock_remove(lmb->base_addr, block_sz);
393 
394 	dlpar_release_drc(lmb->drc_index);
395 	dlpar_remove_device_tree_lmb(lmb);
396 
397 	return 0;
398 }
399 
400 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove,
401 					struct property *prop)
402 {
403 	struct of_drconf_cell *lmbs;
404 	int lmbs_removed = 0;
405 	int lmbs_available = 0;
406 	u32 num_lmbs, *p;
407 	int i, rc;
408 
409 	pr_info("Attempting to hot-remove %d LMB(s)\n", lmbs_to_remove);
410 
411 	if (lmbs_to_remove == 0)
412 		return -EINVAL;
413 
414 	p = prop->value;
415 	num_lmbs = *p++;
416 	lmbs = (struct of_drconf_cell *)p;
417 
418 	/* Validate that there are enough LMBs to satisfy the request */
419 	for (i = 0; i < num_lmbs; i++) {
420 		if (lmbs[i].flags & DRCONF_MEM_ASSIGNED)
421 			lmbs_available++;
422 	}
423 
424 	if (lmbs_available < lmbs_to_remove)
425 		return -EINVAL;
426 
427 	for (i = 0; i < num_lmbs && lmbs_removed < lmbs_to_remove; i++) {
428 		rc = dlpar_remove_lmb(&lmbs[i]);
429 		if (rc)
430 			continue;
431 
432 		lmbs_removed++;
433 
434 		/* Mark this lmb so we can add it later if all of the
435 		 * requested LMBs cannot be removed.
436 		 */
437 		lmbs[i].reserved = 1;
438 	}
439 
440 	if (lmbs_removed != lmbs_to_remove) {
441 		pr_err("Memory hot-remove failed, adding LMB's back\n");
442 
443 		for (i = 0; i < num_lmbs; i++) {
444 			if (!lmbs[i].reserved)
445 				continue;
446 
447 			rc = dlpar_add_lmb(&lmbs[i]);
448 			if (rc)
449 				pr_err("Failed to add LMB back, drc index %x\n",
450 				       lmbs[i].drc_index);
451 
452 			lmbs[i].reserved = 0;
453 		}
454 
455 		rc = -EINVAL;
456 	} else {
457 		for (i = 0; i < num_lmbs; i++) {
458 			if (!lmbs[i].reserved)
459 				continue;
460 
461 			pr_info("Memory at %llx was hot-removed\n",
462 				lmbs[i].base_addr);
463 
464 			lmbs[i].reserved = 0;
465 		}
466 		rc = 0;
467 	}
468 
469 	return rc;
470 }
471 
472 static int dlpar_memory_remove_by_index(u32 drc_index, struct property *prop)
473 {
474 	struct of_drconf_cell *lmbs;
475 	u32 num_lmbs, *p;
476 	int lmb_found;
477 	int i, rc;
478 
479 	pr_info("Attempting to hot-remove LMB, drc index %x\n", drc_index);
480 
481 	p = prop->value;
482 	num_lmbs = *p++;
483 	lmbs = (struct of_drconf_cell *)p;
484 
485 	lmb_found = 0;
486 	for (i = 0; i < num_lmbs; i++) {
487 		if (lmbs[i].drc_index == drc_index) {
488 			lmb_found = 1;
489 			rc = dlpar_remove_lmb(&lmbs[i]);
490 			break;
491 		}
492 	}
493 
494 	if (!lmb_found)
495 		rc = -EINVAL;
496 
497 	if (rc)
498 		pr_info("Failed to hot-remove memory at %llx\n",
499 			lmbs[i].base_addr);
500 	else
501 		pr_info("Memory at %llx was hot-removed\n", lmbs[i].base_addr);
502 
503 	return rc;
504 }
505 
506 #else
507 static inline int pseries_remove_memblock(unsigned long base,
508 					  unsigned int memblock_size)
509 {
510 	return -EOPNOTSUPP;
511 }
512 static inline int pseries_remove_mem_node(struct device_node *np)
513 {
514 	return 0;
515 }
516 static inline int dlpar_memory_remove(struct pseries_hp_errorlog *hp_elog)
517 {
518 	return -EOPNOTSUPP;
519 }
520 static int dlpar_remove_lmb(struct of_drconf_cell *lmb)
521 {
522 	return -EOPNOTSUPP;
523 }
524 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove,
525 					struct property *prop)
526 {
527 	return -EOPNOTSUPP;
528 }
529 static int dlpar_memory_remove_by_index(u32 drc_index, struct property *prop)
530 {
531 	return -EOPNOTSUPP;
532 }
533 
534 #endif /* CONFIG_MEMORY_HOTREMOVE */
535 
536 static int dlpar_add_lmb_memory(struct of_drconf_cell *lmb)
537 {
538 	struct memory_block *mem_block;
539 	unsigned long block_sz;
540 	int nid, rc;
541 
542 	block_sz = memory_block_size_bytes();
543 
544 	/* Find the node id for this address */
545 	nid = memory_add_physaddr_to_nid(lmb->base_addr);
546 
547 	/* Add the memory */
548 	rc = add_memory(nid, lmb->base_addr, block_sz);
549 	if (rc)
550 		return rc;
551 
552 	/* Register this block of memory */
553 	rc = memblock_add(lmb->base_addr, block_sz);
554 	if (rc) {
555 		remove_memory(nid, lmb->base_addr, block_sz);
556 		return rc;
557 	}
558 
559 	mem_block = lmb_to_memblock(lmb);
560 	if (!mem_block) {
561 		remove_memory(nid, lmb->base_addr, block_sz);
562 		return -EINVAL;
563 	}
564 
565 	rc = device_online(&mem_block->dev);
566 	put_device(&mem_block->dev);
567 	if (rc) {
568 		remove_memory(nid, lmb->base_addr, block_sz);
569 		return rc;
570 	}
571 
572 	lmb->flags |= DRCONF_MEM_ASSIGNED;
573 	return 0;
574 }
575 
576 static int dlpar_add_lmb(struct of_drconf_cell *lmb)
577 {
578 	int rc;
579 
580 	if (lmb->flags & DRCONF_MEM_ASSIGNED)
581 		return -EINVAL;
582 
583 	rc = dlpar_acquire_drc(lmb->drc_index);
584 	if (rc)
585 		return rc;
586 
587 	rc = dlpar_add_device_tree_lmb(lmb);
588 	if (rc) {
589 		pr_err("Couldn't update device tree for drc index %x\n",
590 		       lmb->drc_index);
591 		dlpar_release_drc(lmb->drc_index);
592 		return rc;
593 	}
594 
595 	rc = dlpar_add_lmb_memory(lmb);
596 	if (rc) {
597 		dlpar_remove_device_tree_lmb(lmb);
598 		dlpar_release_drc(lmb->drc_index);
599 	}
600 
601 	return rc;
602 }
603 
604 static int dlpar_memory_add_by_count(u32 lmbs_to_add, struct property *prop)
605 {
606 	struct of_drconf_cell *lmbs;
607 	u32 num_lmbs, *p;
608 	int lmbs_available = 0;
609 	int lmbs_added = 0;
610 	int i, 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 	p = prop->value;
618 	num_lmbs = *p++;
619 	lmbs = (struct of_drconf_cell *)p;
620 
621 	/* Validate that there are enough LMBs to satisfy the request */
622 	for (i = 0; i < num_lmbs; i++) {
623 		if (!(lmbs[i].flags & DRCONF_MEM_ASSIGNED))
624 			lmbs_available++;
625 	}
626 
627 	if (lmbs_available < lmbs_to_add)
628 		return -EINVAL;
629 
630 	for (i = 0; i < num_lmbs && lmbs_to_add != lmbs_added; i++) {
631 		rc = dlpar_add_lmb(&lmbs[i]);
632 		if (rc)
633 			continue;
634 
635 		lmbs_added++;
636 
637 		/* Mark this lmb so we can remove it later if all of the
638 		 * requested LMBs cannot be added.
639 		 */
640 		lmbs[i].reserved = 1;
641 	}
642 
643 	if (lmbs_added != lmbs_to_add) {
644 		pr_err("Memory hot-add failed, removing any added LMBs\n");
645 
646 		for (i = 0; i < num_lmbs; i++) {
647 			if (!lmbs[i].reserved)
648 				continue;
649 
650 			rc = dlpar_remove_lmb(&lmbs[i]);
651 			if (rc)
652 				pr_err("Failed to remove LMB, drc index %x\n",
653 				       be32_to_cpu(lmbs[i].drc_index));
654 		}
655 		rc = -EINVAL;
656 	} else {
657 		for (i = 0; i < num_lmbs; i++) {
658 			if (!lmbs[i].reserved)
659 				continue;
660 
661 			pr_info("Memory at %llx (drc index %x) was hot-added\n",
662 				lmbs[i].base_addr, lmbs[i].drc_index);
663 			lmbs[i].reserved = 0;
664 		}
665 	}
666 
667 	return rc;
668 }
669 
670 static int dlpar_memory_add_by_index(u32 drc_index, struct property *prop)
671 {
672 	struct of_drconf_cell *lmbs;
673 	u32 num_lmbs, *p;
674 	int i, lmb_found;
675 	int rc;
676 
677 	pr_info("Attempting to hot-add LMB, drc index %x\n", drc_index);
678 
679 	p = prop->value;
680 	num_lmbs = *p++;
681 	lmbs = (struct of_drconf_cell *)p;
682 
683 	lmb_found = 0;
684 	for (i = 0; i < num_lmbs; i++) {
685 		if (lmbs[i].drc_index == drc_index) {
686 			lmb_found = 1;
687 			rc = dlpar_add_lmb(&lmbs[i]);
688 			break;
689 		}
690 	}
691 
692 	if (!lmb_found)
693 		rc = -EINVAL;
694 
695 	if (rc)
696 		pr_info("Failed to hot-add memory, drc index %x\n", drc_index);
697 	else
698 		pr_info("Memory at %llx (drc index %x) was hot-added\n",
699 			lmbs[i].base_addr, drc_index);
700 
701 	return rc;
702 }
703 
704 int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
705 {
706 	struct device_node *dn;
707 	struct property *prop;
708 	u32 count, drc_index;
709 	int rc;
710 
711 	count = hp_elog->_drc_u.drc_count;
712 	drc_index = hp_elog->_drc_u.drc_index;
713 
714 	lock_device_hotplug();
715 
716 	dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
717 	if (!dn) {
718 		rc = -EINVAL;
719 		goto dlpar_memory_out;
720 	}
721 
722 	prop = dlpar_clone_drconf_property(dn);
723 	if (!prop) {
724 		rc = -EINVAL;
725 		goto dlpar_memory_out;
726 	}
727 
728 	switch (hp_elog->action) {
729 	case PSERIES_HP_ELOG_ACTION_ADD:
730 		if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT)
731 			rc = dlpar_memory_add_by_count(count, prop);
732 		else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX)
733 			rc = dlpar_memory_add_by_index(drc_index, prop);
734 		else
735 			rc = -EINVAL;
736 		break;
737 	case PSERIES_HP_ELOG_ACTION_REMOVE:
738 		if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT)
739 			rc = dlpar_memory_remove_by_count(count, prop);
740 		else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX)
741 			rc = dlpar_memory_remove_by_index(drc_index, prop);
742 		else
743 			rc = -EINVAL;
744 		break;
745 	default:
746 		pr_err("Invalid action (%d) specified\n", hp_elog->action);
747 		rc = -EINVAL;
748 		break;
749 	}
750 
751 	dlpar_free_drconf_property(prop);
752 
753 dlpar_memory_out:
754 	of_node_put(dn);
755 	unlock_device_hotplug();
756 	return rc;
757 }
758 
759 static int pseries_add_mem_node(struct device_node *np)
760 {
761 	const char *type;
762 	const __be32 *regs;
763 	unsigned long base;
764 	unsigned int lmb_size;
765 	int ret = -EINVAL;
766 
767 	/*
768 	 * Check to see if we are actually adding memory
769 	 */
770 	type = of_get_property(np, "device_type", NULL);
771 	if (type == NULL || strcmp(type, "memory") != 0)
772 		return 0;
773 
774 	/*
775 	 * Find the base and size of the memblock
776 	 */
777 	regs = of_get_property(np, "reg", NULL);
778 	if (!regs)
779 		return ret;
780 
781 	base = be64_to_cpu(*(unsigned long *)regs);
782 	lmb_size = be32_to_cpu(regs[3]);
783 
784 	/*
785 	 * Update memory region to represent the memory add
786 	 */
787 	ret = memblock_add(base, lmb_size);
788 	return (ret < 0) ? -EINVAL : 0;
789 }
790 
791 static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
792 {
793 	struct of_drconf_cell *new_drmem, *old_drmem;
794 	unsigned long memblock_size;
795 	u32 entries;
796 	__be32 *p;
797 	int i, rc = -EINVAL;
798 
799 	if (rtas_hp_event)
800 		return 0;
801 
802 	memblock_size = pseries_memory_block_size();
803 	if (!memblock_size)
804 		return -EINVAL;
805 
806 	p = (__be32 *) pr->old_prop->value;
807 	if (!p)
808 		return -EINVAL;
809 
810 	/* The first int of the property is the number of lmb's described
811 	 * by the property. This is followed by an array of of_drconf_cell
812 	 * entries. Get the number of entries and skip to the array of
813 	 * of_drconf_cell's.
814 	 */
815 	entries = be32_to_cpu(*p++);
816 	old_drmem = (struct of_drconf_cell *)p;
817 
818 	p = (__be32 *)pr->prop->value;
819 	p++;
820 	new_drmem = (struct of_drconf_cell *)p;
821 
822 	for (i = 0; i < entries; i++) {
823 		if ((be32_to_cpu(old_drmem[i].flags) & DRCONF_MEM_ASSIGNED) &&
824 		    (!(be32_to_cpu(new_drmem[i].flags) & DRCONF_MEM_ASSIGNED))) {
825 			rc = pseries_remove_memblock(
826 				be64_to_cpu(old_drmem[i].base_addr),
827 						     memblock_size);
828 			break;
829 		} else if ((!(be32_to_cpu(old_drmem[i].flags) &
830 			    DRCONF_MEM_ASSIGNED)) &&
831 			    (be32_to_cpu(new_drmem[i].flags) &
832 			    DRCONF_MEM_ASSIGNED)) {
833 			rc = memblock_add(be64_to_cpu(old_drmem[i].base_addr),
834 					  memblock_size);
835 			rc = (rc < 0) ? -EINVAL : 0;
836 			break;
837 		}
838 	}
839 	return rc;
840 }
841 
842 static int pseries_memory_notifier(struct notifier_block *nb,
843 				   unsigned long action, void *data)
844 {
845 	struct of_reconfig_data *rd = data;
846 	int err = 0;
847 
848 	switch (action) {
849 	case OF_RECONFIG_ATTACH_NODE:
850 		err = pseries_add_mem_node(rd->dn);
851 		break;
852 	case OF_RECONFIG_DETACH_NODE:
853 		err = pseries_remove_mem_node(rd->dn);
854 		break;
855 	case OF_RECONFIG_UPDATE_PROPERTY:
856 		if (!strcmp(rd->prop->name, "ibm,dynamic-memory"))
857 			err = pseries_update_drconf_memory(rd);
858 		break;
859 	}
860 	return notifier_from_errno(err);
861 }
862 
863 static struct notifier_block pseries_mem_nb = {
864 	.notifier_call = pseries_memory_notifier,
865 };
866 
867 static int __init pseries_memory_hotplug_init(void)
868 {
869 	if (firmware_has_feature(FW_FEATURE_LPAR))
870 		of_reconfig_notifier_register(&pseries_mem_nb);
871 
872 	return 0;
873 }
874 machine_device_initcall(pseries, pseries_memory_hotplug_init);
875