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