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 27static bool rtas_hp_event; 28 29unsigned 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 72static void dlpar_free_drconf_property(struct property *prop) 73{ 74 kfree(prop->name); 75 kfree(prop->value); 76 kfree(prop); 77} 78 79static 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 119static struct memory_block *lmb_to_memblock(struct of_drconf_cell *lmb) 120{ 121 unsigned long section_nr; 122 struct mem_section *mem_sect; 123 struct memory_block *mem_block; 124 125 section_nr = pfn_to_section_nr(PFN_DOWN(lmb->base_addr)); 126 mem_sect = __nr_to_section(section_nr); 127 128 mem_block = find_memory_block(mem_sect); 129 return mem_block; 130} 131 132#ifdef CONFIG_MEMORY_HOTREMOVE 133static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size) 134{ 135 unsigned long block_sz, start_pfn; 136 int sections_per_block; 137 int i, nid; 138 139 start_pfn = base >> PAGE_SHIFT; 140 141 lock_device_hotplug(); 142 143 if (!pfn_valid(start_pfn)) 144 goto out; 145 146 block_sz = pseries_memory_block_size(); 147 sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; 148 nid = memory_add_physaddr_to_nid(base); 149 150 for (i = 0; i < sections_per_block; i++) { 151 remove_memory(nid, base, MIN_MEMORY_BLOCK_SIZE); 152 base += MIN_MEMORY_BLOCK_SIZE; 153 } 154 155out: 156 /* Update memory regions for memory remove */ 157 memblock_remove(base, memblock_size); 158 unlock_device_hotplug(); 159 return 0; 160} 161 162static int pseries_remove_mem_node(struct device_node *np) 163{ 164 const char *type; 165 const __be32 *regs; 166 unsigned long base; 167 unsigned int lmb_size; 168 int ret = -EINVAL; 169 170 /* 171 * Check to see if we are actually removing memory 172 */ 173 type = of_get_property(np, "device_type", NULL); 174 if (type == NULL || strcmp(type, "memory") != 0) 175 return 0; 176 177 /* 178 * Find the base address and size of the memblock 179 */ 180 regs = of_get_property(np, "reg", NULL); 181 if (!regs) 182 return ret; 183 184 base = be64_to_cpu(*(unsigned long *)regs); 185 lmb_size = be32_to_cpu(regs[3]); 186 187 pseries_remove_memblock(base, lmb_size); 188 return 0; 189} 190 191static bool lmb_is_removable(struct of_drconf_cell *lmb) 192{ 193 int i, scns_per_block; 194 int rc = 1; 195 unsigned long pfn, block_sz; 196 u64 phys_addr; 197 198 if (!(lmb->flags & DRCONF_MEM_ASSIGNED)) 199 return false; 200 201 block_sz = memory_block_size_bytes(); 202 scns_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; 203 phys_addr = lmb->base_addr; 204 205 for (i = 0; i < scns_per_block; i++) { 206 pfn = PFN_DOWN(phys_addr); 207 if (!pfn_present(pfn)) 208 continue; 209 210 rc &= is_mem_section_removable(pfn, PAGES_PER_SECTION); 211 phys_addr += MIN_MEMORY_BLOCK_SIZE; 212 } 213 214 return rc ? true : false; 215} 216 217static int dlpar_add_lmb(struct of_drconf_cell *); 218 219static int dlpar_remove_lmb(struct of_drconf_cell *lmb) 220{ 221 struct memory_block *mem_block; 222 unsigned long block_sz; 223 int nid, rc; 224 225 if (!lmb_is_removable(lmb)) 226 return -EINVAL; 227 228 mem_block = lmb_to_memblock(lmb); 229 if (!mem_block) 230 return -EINVAL; 231 232 rc = device_offline(&mem_block->dev); 233 put_device(&mem_block->dev); 234 if (rc) 235 return rc; 236 237 block_sz = pseries_memory_block_size(); 238 nid = memory_add_physaddr_to_nid(lmb->base_addr); 239 240 remove_memory(nid, lmb->base_addr, block_sz); 241 242 /* Update memory regions for memory remove */ 243 memblock_remove(lmb->base_addr, block_sz); 244 245 dlpar_release_drc(lmb->drc_index); 246 247 lmb->flags &= ~DRCONF_MEM_ASSIGNED; 248 return 0; 249} 250 251static int dlpar_memory_remove_by_count(u32 lmbs_to_remove, 252 struct property *prop) 253{ 254 struct of_drconf_cell *lmbs; 255 int lmbs_removed = 0; 256 int lmbs_available = 0; 257 u32 num_lmbs, *p; 258 int i, rc; 259 260 pr_info("Attempting to hot-remove %d LMB(s)\n", lmbs_to_remove); 261 262 if (lmbs_to_remove == 0) 263 return -EINVAL; 264 265 p = prop->value; 266 num_lmbs = *p++; 267 lmbs = (struct of_drconf_cell *)p; 268 269 /* Validate that there are enough LMBs to satisfy the request */ 270 for (i = 0; i < num_lmbs; i++) { 271 if (lmbs[i].flags & DRCONF_MEM_ASSIGNED) 272 lmbs_available++; 273 } 274 275 if (lmbs_available < lmbs_to_remove) 276 return -EINVAL; 277 278 for (i = 0; i < num_lmbs && lmbs_removed < lmbs_to_remove; i++) { 279 rc = dlpar_remove_lmb(&lmbs[i]); 280 if (rc) 281 continue; 282 283 lmbs_removed++; 284 285 /* Mark this lmb so we can add it later if all of the 286 * requested LMBs cannot be removed. 287 */ 288 lmbs[i].reserved = 1; 289 } 290 291 if (lmbs_removed != lmbs_to_remove) { 292 pr_err("Memory hot-remove failed, adding LMB's back\n"); 293 294 for (i = 0; i < num_lmbs; i++) { 295 if (!lmbs[i].reserved) 296 continue; 297 298 rc = dlpar_add_lmb(&lmbs[i]); 299 if (rc) 300 pr_err("Failed to add LMB back, drc index %x\n", 301 lmbs[i].drc_index); 302 303 lmbs[i].reserved = 0; 304 } 305 306 rc = -EINVAL; 307 } else { 308 for (i = 0; i < num_lmbs; i++) { 309 if (!lmbs[i].reserved) 310 continue; 311 312 pr_info("Memory at %llx was hot-removed\n", 313 lmbs[i].base_addr); 314 315 lmbs[i].reserved = 0; 316 } 317 rc = 0; 318 } 319 320 return rc; 321} 322 323static int dlpar_memory_remove_by_index(u32 drc_index, struct property *prop) 324{ 325 struct of_drconf_cell *lmbs; 326 u32 num_lmbs, *p; 327 int lmb_found; 328 int i, rc; 329 330 pr_info("Attempting to hot-remove LMB, drc index %x\n", drc_index); 331 332 p = prop->value; 333 num_lmbs = *p++; 334 lmbs = (struct of_drconf_cell *)p; 335 336 lmb_found = 0; 337 for (i = 0; i < num_lmbs; i++) { 338 if (lmbs[i].drc_index == drc_index) { 339 lmb_found = 1; 340 rc = dlpar_remove_lmb(&lmbs[i]); 341 break; 342 } 343 } 344 345 if (!lmb_found) 346 rc = -EINVAL; 347 348 if (rc) 349 pr_info("Failed to hot-remove memory at %llx\n", 350 lmbs[i].base_addr); 351 else 352 pr_info("Memory at %llx was hot-removed\n", lmbs[i].base_addr); 353 354 return rc; 355} 356 357#else 358static inline int pseries_remove_memblock(unsigned long base, 359 unsigned int memblock_size) 360{ 361 return -EOPNOTSUPP; 362} 363static inline int pseries_remove_mem_node(struct device_node *np) 364{ 365 return 0; 366} 367static inline int dlpar_memory_remove(struct pseries_hp_errorlog *hp_elog) 368{ 369 return -EOPNOTSUPP; 370} 371static int dlpar_remove_lmb(struct of_drconf_cell *lmb) 372{ 373 return -EOPNOTSUPP; 374} 375static int dlpar_memory_remove_by_count(u32 lmbs_to_remove, 376 struct property *prop) 377{ 378 return -EOPNOTSUPP; 379} 380static int dlpar_memory_remove_by_index(u32 drc_index, struct property *prop) 381{ 382 return -EOPNOTSUPP; 383} 384 385#endif /* CONFIG_MEMORY_HOTREMOVE */ 386 387static int dlpar_add_lmb(struct of_drconf_cell *lmb) 388{ 389 struct memory_block *mem_block; 390 unsigned long block_sz; 391 int nid, rc; 392 393 if (lmb->flags & DRCONF_MEM_ASSIGNED) 394 return -EINVAL; 395 396 block_sz = memory_block_size_bytes(); 397 398 rc = dlpar_acquire_drc(lmb->drc_index); 399 if (rc) 400 return rc; 401 402 /* Find the node id for this address */ 403 nid = memory_add_physaddr_to_nid(lmb->base_addr); 404 405 /* Add the memory */ 406 rc = add_memory(nid, lmb->base_addr, block_sz); 407 if (rc) { 408 dlpar_release_drc(lmb->drc_index); 409 return rc; 410 } 411 412 /* Register this block of memory */ 413 rc = memblock_add(lmb->base_addr, block_sz); 414 if (rc) { 415 remove_memory(nid, lmb->base_addr, block_sz); 416 dlpar_release_drc(lmb->drc_index); 417 return rc; 418 } 419 420 mem_block = lmb_to_memblock(lmb); 421 if (!mem_block) { 422 remove_memory(nid, lmb->base_addr, block_sz); 423 dlpar_release_drc(lmb->drc_index); 424 return -EINVAL; 425 } 426 427 rc = device_online(&mem_block->dev); 428 put_device(&mem_block->dev); 429 if (rc) { 430 remove_memory(nid, lmb->base_addr, block_sz); 431 dlpar_release_drc(lmb->drc_index); 432 return rc; 433 } 434 435 lmb->flags |= DRCONF_MEM_ASSIGNED; 436 return 0; 437} 438 439static int dlpar_memory_add_by_count(u32 lmbs_to_add, struct property *prop) 440{ 441 struct of_drconf_cell *lmbs; 442 u32 num_lmbs, *p; 443 int lmbs_available = 0; 444 int lmbs_added = 0; 445 int i, rc; 446 447 pr_info("Attempting to hot-add %d LMB(s)\n", lmbs_to_add); 448 449 if (lmbs_to_add == 0) 450 return -EINVAL; 451 452 p = prop->value; 453 num_lmbs = *p++; 454 lmbs = (struct of_drconf_cell *)p; 455 456 /* Validate that there are enough LMBs to satisfy the request */ 457 for (i = 0; i < num_lmbs; i++) { 458 if (!(lmbs[i].flags & DRCONF_MEM_ASSIGNED)) 459 lmbs_available++; 460 } 461 462 if (lmbs_available < lmbs_to_add) 463 return -EINVAL; 464 465 for (i = 0; i < num_lmbs && lmbs_to_add != lmbs_added; i++) { 466 rc = dlpar_add_lmb(&lmbs[i]); 467 if (rc) 468 continue; 469 470 lmbs_added++; 471 472 /* Mark this lmb so we can remove it later if all of the 473 * requested LMBs cannot be added. 474 */ 475 lmbs[i].reserved = 1; 476 } 477 478 if (lmbs_added != lmbs_to_add) { 479 pr_err("Memory hot-add failed, removing any added LMBs\n"); 480 481 for (i = 0; i < num_lmbs; i++) { 482 if (!lmbs[i].reserved) 483 continue; 484 485 rc = dlpar_remove_lmb(&lmbs[i]); 486 if (rc) 487 pr_err("Failed to remove LMB, drc index %x\n", 488 be32_to_cpu(lmbs[i].drc_index)); 489 } 490 rc = -EINVAL; 491 } else { 492 for (i = 0; i < num_lmbs; i++) { 493 if (!lmbs[i].reserved) 494 continue; 495 496 pr_info("Memory at %llx (drc index %x) was hot-added\n", 497 lmbs[i].base_addr, lmbs[i].drc_index); 498 lmbs[i].reserved = 0; 499 } 500 } 501 502 return rc; 503} 504 505static int dlpar_memory_add_by_index(u32 drc_index, struct property *prop) 506{ 507 struct of_drconf_cell *lmbs; 508 u32 num_lmbs, *p; 509 int i, lmb_found; 510 int rc; 511 512 pr_info("Attempting to hot-add LMB, drc index %x\n", drc_index); 513 514 p = prop->value; 515 num_lmbs = *p++; 516 lmbs = (struct of_drconf_cell *)p; 517 518 lmb_found = 0; 519 for (i = 0; i < num_lmbs; i++) { 520 if (lmbs[i].drc_index == drc_index) { 521 lmb_found = 1; 522 rc = dlpar_add_lmb(&lmbs[i]); 523 break; 524 } 525 } 526 527 if (!lmb_found) 528 rc = -EINVAL; 529 530 if (rc) 531 pr_info("Failed to hot-add memory, drc index %x\n", drc_index); 532 else 533 pr_info("Memory at %llx (drc index %x) was hot-added\n", 534 lmbs[i].base_addr, drc_index); 535 536 return rc; 537} 538 539static void dlpar_update_drconf_property(struct device_node *dn, 540 struct property *prop) 541{ 542 struct of_drconf_cell *lmbs; 543 u32 num_lmbs, *p; 544 int i; 545 546 /* Convert the property back to BE */ 547 p = prop->value; 548 num_lmbs = *p; 549 *p = cpu_to_be32(*p); 550 p++; 551 552 lmbs = (struct of_drconf_cell *)p; 553 for (i = 0; i < num_lmbs; i++) { 554 lmbs[i].base_addr = cpu_to_be64(lmbs[i].base_addr); 555 lmbs[i].drc_index = cpu_to_be32(lmbs[i].drc_index); 556 lmbs[i].flags = cpu_to_be32(lmbs[i].flags); 557 } 558 559 rtas_hp_event = true; 560 of_update_property(dn, prop); 561 rtas_hp_event = false; 562} 563 564int dlpar_memory(struct pseries_hp_errorlog *hp_elog) 565{ 566 struct device_node *dn; 567 struct property *prop; 568 u32 count, drc_index; 569 int rc; 570 571 count = hp_elog->_drc_u.drc_count; 572 drc_index = hp_elog->_drc_u.drc_index; 573 574 lock_device_hotplug(); 575 576 dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); 577 if (!dn) { 578 rc = -EINVAL; 579 goto dlpar_memory_out; 580 } 581 582 prop = dlpar_clone_drconf_property(dn); 583 if (!prop) { 584 rc = -EINVAL; 585 goto dlpar_memory_out; 586 } 587 588 switch (hp_elog->action) { 589 case PSERIES_HP_ELOG_ACTION_ADD: 590 if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) 591 rc = dlpar_memory_add_by_count(count, prop); 592 else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) 593 rc = dlpar_memory_add_by_index(drc_index, prop); 594 else 595 rc = -EINVAL; 596 break; 597 case PSERIES_HP_ELOG_ACTION_REMOVE: 598 if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) 599 rc = dlpar_memory_remove_by_count(count, prop); 600 else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) 601 rc = dlpar_memory_remove_by_index(drc_index, prop); 602 else 603 rc = -EINVAL; 604 break; 605 default: 606 pr_err("Invalid action (%d) specified\n", hp_elog->action); 607 rc = -EINVAL; 608 break; 609 } 610 611 if (rc) 612 dlpar_free_drconf_property(prop); 613 else 614 dlpar_update_drconf_property(dn, prop); 615 616dlpar_memory_out: 617 of_node_put(dn); 618 unlock_device_hotplug(); 619 return rc; 620} 621 622static int pseries_add_mem_node(struct device_node *np) 623{ 624 const char *type; 625 const __be32 *regs; 626 unsigned long base; 627 unsigned int lmb_size; 628 int ret = -EINVAL; 629 630 /* 631 * Check to see if we are actually adding memory 632 */ 633 type = of_get_property(np, "device_type", NULL); 634 if (type == NULL || strcmp(type, "memory") != 0) 635 return 0; 636 637 /* 638 * Find the base and size of the memblock 639 */ 640 regs = of_get_property(np, "reg", NULL); 641 if (!regs) 642 return ret; 643 644 base = be64_to_cpu(*(unsigned long *)regs); 645 lmb_size = be32_to_cpu(regs[3]); 646 647 /* 648 * Update memory region to represent the memory add 649 */ 650 ret = memblock_add(base, lmb_size); 651 return (ret < 0) ? -EINVAL : 0; 652} 653 654static int pseries_update_drconf_memory(struct of_reconfig_data *pr) 655{ 656 struct of_drconf_cell *new_drmem, *old_drmem; 657 unsigned long memblock_size; 658 u32 entries; 659 __be32 *p; 660 int i, rc = -EINVAL; 661 662 if (rtas_hp_event) 663 return 0; 664 665 memblock_size = pseries_memory_block_size(); 666 if (!memblock_size) 667 return -EINVAL; 668 669 p = (__be32 *) pr->old_prop->value; 670 if (!p) 671 return -EINVAL; 672 673 /* The first int of the property is the number of lmb's described 674 * by the property. This is followed by an array of of_drconf_cell 675 * entries. Get the number of entries and skip to the array of 676 * of_drconf_cell's. 677 */ 678 entries = be32_to_cpu(*p++); 679 old_drmem = (struct of_drconf_cell *)p; 680 681 p = (__be32 *)pr->prop->value; 682 p++; 683 new_drmem = (struct of_drconf_cell *)p; 684 685 for (i = 0; i < entries; i++) { 686 if ((be32_to_cpu(old_drmem[i].flags) & DRCONF_MEM_ASSIGNED) && 687 (!(be32_to_cpu(new_drmem[i].flags) & DRCONF_MEM_ASSIGNED))) { 688 rc = pseries_remove_memblock( 689 be64_to_cpu(old_drmem[i].base_addr), 690 memblock_size); 691 break; 692 } else if ((!(be32_to_cpu(old_drmem[i].flags) & 693 DRCONF_MEM_ASSIGNED)) && 694 (be32_to_cpu(new_drmem[i].flags) & 695 DRCONF_MEM_ASSIGNED)) { 696 rc = memblock_add(be64_to_cpu(old_drmem[i].base_addr), 697 memblock_size); 698 rc = (rc < 0) ? -EINVAL : 0; 699 break; 700 } 701 } 702 return rc; 703} 704 705static int pseries_memory_notifier(struct notifier_block *nb, 706 unsigned long action, void *data) 707{ 708 struct of_reconfig_data *rd = data; 709 int err = 0; 710 711 switch (action) { 712 case OF_RECONFIG_ATTACH_NODE: 713 err = pseries_add_mem_node(rd->dn); 714 break; 715 case OF_RECONFIG_DETACH_NODE: 716 err = pseries_remove_mem_node(rd->dn); 717 break; 718 case OF_RECONFIG_UPDATE_PROPERTY: 719 if (!strcmp(rd->prop->name, "ibm,dynamic-memory")) 720 err = pseries_update_drconf_memory(rd); 721 break; 722 } 723 return notifier_from_errno(err); 724} 725 726static struct notifier_block pseries_mem_nb = { 727 .notifier_call = pseries_memory_notifier, 728}; 729 730static int __init pseries_memory_hotplug_init(void) 731{ 732 if (firmware_has_feature(FW_FEATURE_LPAR)) 733 of_reconfig_notifier_register(&pseries_mem_nb); 734 735 return 0; 736} 737machine_device_initcall(pseries, pseries_memory_hotplug_init); 738