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