| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * pseries Memory Hotplug infrastructure. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * 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 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #define pr_fmt(fmt) "pseries-hotplug-mem: " fmt |
|---|
| .. | .. |
|---|
| 26 | 22 | #include <asm/drmem.h> |
|---|
| 27 | 23 | #include "pseries.h" |
|---|
| 28 | 24 | |
|---|
| 29 | | -static bool rtas_hp_event; |
|---|
| 30 | | - |
|---|
| 31 | 25 | unsigned long pseries_memory_block_size(void) |
|---|
| 32 | 26 | { |
|---|
| 33 | 27 | struct device_node *np; |
|---|
| .. | .. |
|---|
| 36 | 30 | |
|---|
| 37 | 31 | np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); |
|---|
| 38 | 32 | if (np) { |
|---|
| 39 | | - const __be64 *size; |
|---|
| 33 | + int len; |
|---|
| 34 | + int size_cells; |
|---|
| 35 | + const __be32 *prop; |
|---|
| 40 | 36 | |
|---|
| 41 | | - size = of_get_property(np, "ibm,lmb-size", NULL); |
|---|
| 42 | | - if (size) |
|---|
| 43 | | - memblock_size = be64_to_cpup(size); |
|---|
| 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); |
|---|
| 44 | 42 | of_node_put(np); |
|---|
| 43 | + |
|---|
| 45 | 44 | } else if (machine_is(pseries)) { |
|---|
| 46 | 45 | /* This fallback really only applies to pseries */ |
|---|
| 47 | 46 | unsigned int memzero_size = 0; |
|---|
| .. | .. |
|---|
| 181 | 180 | return -ENODEV; |
|---|
| 182 | 181 | } |
|---|
| 183 | 182 | |
|---|
| 183 | + update_numa_distance(lmb_node); |
|---|
| 184 | + |
|---|
| 184 | 185 | dr_node = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); |
|---|
| 185 | 186 | if (!dr_node) { |
|---|
| 186 | 187 | dlpar_free_cc_nodes(lmb_node); |
|---|
| .. | .. |
|---|
| 283 | 284 | return dlpar_change_lmb_state(lmb, false); |
|---|
| 284 | 285 | } |
|---|
| 285 | 286 | |
|---|
| 286 | | -static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size) |
|---|
| 287 | +static int pseries_remove_memblock(unsigned long base, unsigned long memblock_size) |
|---|
| 287 | 288 | { |
|---|
| 288 | 289 | unsigned long block_sz, start_pfn; |
|---|
| 289 | 290 | int sections_per_block; |
|---|
| .. | .. |
|---|
| 314 | 315 | |
|---|
| 315 | 316 | static int pseries_remove_mem_node(struct device_node *np) |
|---|
| 316 | 317 | { |
|---|
| 317 | | - const char *type; |
|---|
| 318 | | - const __be32 *regs; |
|---|
| 318 | + const __be32 *prop; |
|---|
| 319 | 319 | unsigned long base; |
|---|
| 320 | | - unsigned int lmb_size; |
|---|
| 320 | + unsigned long lmb_size; |
|---|
| 321 | 321 | int ret = -EINVAL; |
|---|
| 322 | + int addr_cells, size_cells; |
|---|
| 322 | 323 | |
|---|
| 323 | 324 | /* |
|---|
| 324 | 325 | * Check to see if we are actually removing memory |
|---|
| 325 | 326 | */ |
|---|
| 326 | | - type = of_get_property(np, "device_type", NULL); |
|---|
| 327 | | - if (type == NULL || strcmp(type, "memory") != 0) |
|---|
| 327 | + if (!of_node_is_type(np, "memory")) |
|---|
| 328 | 328 | return 0; |
|---|
| 329 | 329 | |
|---|
| 330 | 330 | /* |
|---|
| 331 | 331 | * Find the base address and size of the memblock |
|---|
| 332 | 332 | */ |
|---|
| 333 | | - regs = of_get_property(np, "reg", NULL); |
|---|
| 334 | | - if (!regs) |
|---|
| 333 | + prop = of_get_property(np, "reg", NULL); |
|---|
| 334 | + if (!prop) |
|---|
| 335 | 335 | return ret; |
|---|
| 336 | 336 | |
|---|
| 337 | | - base = be64_to_cpu(*(unsigned long *)regs); |
|---|
| 338 | | - lmb_size = be32_to_cpu(regs[3]); |
|---|
| 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); |
|---|
| 339 | 346 | |
|---|
| 340 | 347 | pseries_remove_memblock(base, lmb_size); |
|---|
| 341 | 348 | return 0; |
|---|
| .. | .. |
|---|
| 343 | 350 | |
|---|
| 344 | 351 | static bool lmb_is_removable(struct drmem_lmb *lmb) |
|---|
| 345 | 352 | { |
|---|
| 346 | | - int i, scns_per_block; |
|---|
| 347 | | - int rc = 1; |
|---|
| 348 | | - unsigned long pfn, block_sz; |
|---|
| 349 | | - u64 phys_addr; |
|---|
| 350 | | - |
|---|
| 351 | 353 | if (!(lmb->flags & DRCONF_MEM_ASSIGNED)) |
|---|
| 352 | 354 | return false; |
|---|
| 353 | | - |
|---|
| 354 | | - block_sz = memory_block_size_bytes(); |
|---|
| 355 | | - scns_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; |
|---|
| 356 | | - phys_addr = lmb->base_addr; |
|---|
| 357 | 355 | |
|---|
| 358 | 356 | #ifdef CONFIG_FA_DUMP |
|---|
| 359 | 357 | /* |
|---|
| 360 | 358 | * Don't hot-remove memory that falls in fadump boot memory area |
|---|
| 361 | 359 | * and memory that is reserved for capturing old kernel memory. |
|---|
| 362 | 360 | */ |
|---|
| 363 | | - if (is_fadump_memory_area(phys_addr, block_sz)) |
|---|
| 361 | + if (is_fadump_memory_area(lmb->base_addr, memory_block_size_bytes())) |
|---|
| 364 | 362 | return false; |
|---|
| 365 | 363 | #endif |
|---|
| 366 | | - |
|---|
| 367 | | - for (i = 0; i < scns_per_block; i++) { |
|---|
| 368 | | - pfn = PFN_DOWN(phys_addr); |
|---|
| 369 | | - if (!pfn_present(pfn)) { |
|---|
| 370 | | - phys_addr += MIN_MEMORY_BLOCK_SIZE; |
|---|
| 371 | | - continue; |
|---|
| 372 | | - } |
|---|
| 373 | | - |
|---|
| 374 | | - rc &= is_mem_section_removable(pfn, PAGES_PER_SECTION); |
|---|
| 375 | | - phys_addr += MIN_MEMORY_BLOCK_SIZE; |
|---|
| 376 | | - } |
|---|
| 377 | | - |
|---|
| 378 | | - return rc ? true : false; |
|---|
| 364 | + /* device_offline() will determine if we can actually remove this lmb */ |
|---|
| 365 | + return true; |
|---|
| 379 | 366 | } |
|---|
| 380 | 367 | |
|---|
| 381 | 368 | static int dlpar_add_lmb(struct drmem_lmb *); |
|---|
| 382 | 369 | |
|---|
| 383 | 370 | static int dlpar_remove_lmb(struct drmem_lmb *lmb) |
|---|
| 384 | 371 | { |
|---|
| 372 | + struct memory_block *mem_block; |
|---|
| 385 | 373 | unsigned long block_sz; |
|---|
| 386 | | - int nid, rc; |
|---|
| 374 | + int rc; |
|---|
| 387 | 375 | |
|---|
| 388 | 376 | if (!lmb_is_removable(lmb)) |
|---|
| 389 | 377 | return -EINVAL; |
|---|
| 390 | 378 | |
|---|
| 379 | + mem_block = lmb_to_memblock(lmb); |
|---|
| 380 | + if (mem_block == NULL) |
|---|
| 381 | + return -EINVAL; |
|---|
| 382 | + |
|---|
| 391 | 383 | rc = dlpar_offline_lmb(lmb); |
|---|
| 392 | | - if (rc) |
|---|
| 384 | + if (rc) { |
|---|
| 385 | + put_device(&mem_block->dev); |
|---|
| 393 | 386 | return rc; |
|---|
| 387 | + } |
|---|
| 394 | 388 | |
|---|
| 395 | 389 | block_sz = pseries_memory_block_size(); |
|---|
| 396 | | - nid = memory_add_physaddr_to_nid(lmb->base_addr); |
|---|
| 397 | 390 | |
|---|
| 398 | | - __remove_memory(nid, lmb->base_addr, block_sz); |
|---|
| 391 | + __remove_memory(mem_block->nid, lmb->base_addr, block_sz); |
|---|
| 392 | + put_device(&mem_block->dev); |
|---|
| 399 | 393 | |
|---|
| 400 | 394 | /* Update memory regions for memory remove */ |
|---|
| 401 | 395 | memblock_remove(lmb->base_addr, block_sz); |
|---|
| .. | .. |
|---|
| 513 | 507 | return rc; |
|---|
| 514 | 508 | } |
|---|
| 515 | 509 | |
|---|
| 516 | | -static int dlpar_memory_readd_by_index(u32 drc_index) |
|---|
| 517 | | -{ |
|---|
| 518 | | - struct drmem_lmb *lmb; |
|---|
| 519 | | - int lmb_found; |
|---|
| 520 | | - int rc; |
|---|
| 521 | | - |
|---|
| 522 | | - pr_info("Attempting to update LMB, drc index %x\n", drc_index); |
|---|
| 523 | | - |
|---|
| 524 | | - lmb_found = 0; |
|---|
| 525 | | - for_each_drmem_lmb(lmb) { |
|---|
| 526 | | - if (lmb->drc_index == drc_index) { |
|---|
| 527 | | - lmb_found = 1; |
|---|
| 528 | | - rc = dlpar_remove_lmb(lmb); |
|---|
| 529 | | - if (!rc) { |
|---|
| 530 | | - rc = dlpar_add_lmb(lmb); |
|---|
| 531 | | - if (rc) |
|---|
| 532 | | - dlpar_release_drc(lmb->drc_index); |
|---|
| 533 | | - } |
|---|
| 534 | | - break; |
|---|
| 535 | | - } |
|---|
| 536 | | - } |
|---|
| 537 | | - |
|---|
| 538 | | - if (!lmb_found) |
|---|
| 539 | | - rc = -EINVAL; |
|---|
| 540 | | - |
|---|
| 541 | | - if (rc) |
|---|
| 542 | | - pr_info("Failed to update memory at %llx\n", |
|---|
| 543 | | - lmb->base_addr); |
|---|
| 544 | | - else |
|---|
| 545 | | - pr_info("Memory at %llx was updated\n", lmb->base_addr); |
|---|
| 546 | | - |
|---|
| 547 | | - return rc; |
|---|
| 548 | | -} |
|---|
| 549 | | - |
|---|
| 550 | 510 | static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index) |
|---|
| 551 | 511 | { |
|---|
| 552 | 512 | struct drmem_lmb *lmb, *start_lmb, *end_lmb; |
|---|
| .. | .. |
|---|
| 619 | 579 | |
|---|
| 620 | 580 | #else |
|---|
| 621 | 581 | static inline int pseries_remove_memblock(unsigned long base, |
|---|
| 622 | | - unsigned int memblock_size) |
|---|
| 582 | + unsigned long memblock_size) |
|---|
| 623 | 583 | { |
|---|
| 624 | 584 | return -EOPNOTSUPP; |
|---|
| 625 | 585 | } |
|---|
| .. | .. |
|---|
| 640 | 600 | return -EOPNOTSUPP; |
|---|
| 641 | 601 | } |
|---|
| 642 | 602 | static int dlpar_memory_remove_by_index(u32 drc_index) |
|---|
| 643 | | -{ |
|---|
| 644 | | - return -EOPNOTSUPP; |
|---|
| 645 | | -} |
|---|
| 646 | | -static int dlpar_memory_readd_by_index(u32 drc_index) |
|---|
| 647 | 603 | { |
|---|
| 648 | 604 | return -EOPNOTSUPP; |
|---|
| 649 | 605 | } |
|---|
| .. | .. |
|---|
| 670 | 626 | |
|---|
| 671 | 627 | block_sz = memory_block_size_bytes(); |
|---|
| 672 | 628 | |
|---|
| 673 | | - /* Find the node id for this address */ |
|---|
| 674 | | - nid = memory_add_physaddr_to_nid(lmb->base_addr); |
|---|
| 629 | + /* Find the node id for this LMB. Fake one if necessary. */ |
|---|
| 630 | + nid = of_drconf_to_nid_single(lmb); |
|---|
| 631 | + if (nid < 0 || !node_possible(nid)) |
|---|
| 632 | + nid = first_online_node; |
|---|
| 675 | 633 | |
|---|
| 676 | 634 | /* Add the memory */ |
|---|
| 677 | | - rc = __add_memory(nid, lmb->base_addr, block_sz); |
|---|
| 635 | + rc = __add_memory(nid, lmb->base_addr, block_sz, MHP_NONE); |
|---|
| 678 | 636 | if (rc) { |
|---|
| 679 | 637 | invalidate_lmb_associativity_index(lmb); |
|---|
| 680 | 638 | return rc; |
|---|
| .. | .. |
|---|
| 889 | 847 | |
|---|
| 890 | 848 | switch (hp_elog->action) { |
|---|
| 891 | 849 | case PSERIES_HP_ELOG_ACTION_ADD: |
|---|
| 892 | | - if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) { |
|---|
| 850 | + switch (hp_elog->id_type) { |
|---|
| 851 | + case PSERIES_HP_ELOG_ID_DRC_COUNT: |
|---|
| 893 | 852 | count = hp_elog->_drc_u.drc_count; |
|---|
| 894 | 853 | rc = dlpar_memory_add_by_count(count); |
|---|
| 895 | | - } else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) { |
|---|
| 854 | + break; |
|---|
| 855 | + case PSERIES_HP_ELOG_ID_DRC_INDEX: |
|---|
| 896 | 856 | drc_index = hp_elog->_drc_u.drc_index; |
|---|
| 897 | 857 | rc = dlpar_memory_add_by_index(drc_index); |
|---|
| 898 | | - } else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_IC) { |
|---|
| 858 | + break; |
|---|
| 859 | + case PSERIES_HP_ELOG_ID_DRC_IC: |
|---|
| 899 | 860 | count = hp_elog->_drc_u.ic.count; |
|---|
| 900 | 861 | drc_index = hp_elog->_drc_u.ic.index; |
|---|
| 901 | 862 | rc = dlpar_memory_add_by_ic(count, drc_index); |
|---|
| 902 | | - } else { |
|---|
| 863 | + break; |
|---|
| 864 | + default: |
|---|
| 903 | 865 | rc = -EINVAL; |
|---|
| 866 | + break; |
|---|
| 904 | 867 | } |
|---|
| 905 | 868 | |
|---|
| 906 | 869 | break; |
|---|
| 907 | 870 | case PSERIES_HP_ELOG_ACTION_REMOVE: |
|---|
| 908 | | - if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT) { |
|---|
| 871 | + switch (hp_elog->id_type) { |
|---|
| 872 | + case PSERIES_HP_ELOG_ID_DRC_COUNT: |
|---|
| 909 | 873 | count = hp_elog->_drc_u.drc_count; |
|---|
| 910 | 874 | rc = dlpar_memory_remove_by_count(count); |
|---|
| 911 | | - } else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX) { |
|---|
| 875 | + break; |
|---|
| 876 | + case PSERIES_HP_ELOG_ID_DRC_INDEX: |
|---|
| 912 | 877 | drc_index = hp_elog->_drc_u.drc_index; |
|---|
| 913 | 878 | rc = dlpar_memory_remove_by_index(drc_index); |
|---|
| 914 | | - } else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_IC) { |
|---|
| 879 | + break; |
|---|
| 880 | + case PSERIES_HP_ELOG_ID_DRC_IC: |
|---|
| 915 | 881 | count = hp_elog->_drc_u.ic.count; |
|---|
| 916 | 882 | drc_index = hp_elog->_drc_u.ic.index; |
|---|
| 917 | 883 | rc = dlpar_memory_remove_by_ic(count, drc_index); |
|---|
| 918 | | - } else { |
|---|
| 884 | + break; |
|---|
| 885 | + default: |
|---|
| 919 | 886 | rc = -EINVAL; |
|---|
| 887 | + break; |
|---|
| 920 | 888 | } |
|---|
| 921 | 889 | |
|---|
| 922 | | - break; |
|---|
| 923 | | - case PSERIES_HP_ELOG_ACTION_READD: |
|---|
| 924 | | - drc_index = hp_elog->_drc_u.drc_index; |
|---|
| 925 | | - rc = dlpar_memory_readd_by_index(drc_index); |
|---|
| 926 | 890 | break; |
|---|
| 927 | 891 | default: |
|---|
| 928 | 892 | pr_err("Invalid action (%d) specified\n", hp_elog->action); |
|---|
| .. | .. |
|---|
| 930 | 894 | break; |
|---|
| 931 | 895 | } |
|---|
| 932 | 896 | |
|---|
| 933 | | - if (!rc) { |
|---|
| 934 | | - rtas_hp_event = true; |
|---|
| 897 | + if (!rc) |
|---|
| 935 | 898 | rc = drmem_update_dt(); |
|---|
| 936 | | - rtas_hp_event = false; |
|---|
| 937 | | - } |
|---|
| 938 | 899 | |
|---|
| 939 | 900 | unlock_device_hotplug(); |
|---|
| 940 | 901 | return rc; |
|---|
| .. | .. |
|---|
| 942 | 903 | |
|---|
| 943 | 904 | static int pseries_add_mem_node(struct device_node *np) |
|---|
| 944 | 905 | { |
|---|
| 945 | | - const char *type; |
|---|
| 946 | | - const __be32 *regs; |
|---|
| 906 | + const __be32 *prop; |
|---|
| 947 | 907 | unsigned long base; |
|---|
| 948 | | - unsigned int lmb_size; |
|---|
| 908 | + unsigned long lmb_size; |
|---|
| 949 | 909 | int ret = -EINVAL; |
|---|
| 910 | + int addr_cells, size_cells; |
|---|
| 950 | 911 | |
|---|
| 951 | 912 | /* |
|---|
| 952 | 913 | * Check to see if we are actually adding memory |
|---|
| 953 | 914 | */ |
|---|
| 954 | | - type = of_get_property(np, "device_type", NULL); |
|---|
| 955 | | - if (type == NULL || strcmp(type, "memory") != 0) |
|---|
| 915 | + if (!of_node_is_type(np, "memory")) |
|---|
| 956 | 916 | return 0; |
|---|
| 957 | 917 | |
|---|
| 958 | 918 | /* |
|---|
| 959 | 919 | * Find the base and size of the memblock |
|---|
| 960 | 920 | */ |
|---|
| 961 | | - regs = of_get_property(np, "reg", NULL); |
|---|
| 962 | | - if (!regs) |
|---|
| 921 | + prop = of_get_property(np, "reg", NULL); |
|---|
| 922 | + if (!prop) |
|---|
| 963 | 923 | return ret; |
|---|
| 964 | 924 | |
|---|
| 965 | | - base = be64_to_cpu(*(unsigned long *)regs); |
|---|
| 966 | | - lmb_size = be32_to_cpu(regs[3]); |
|---|
| 925 | + addr_cells = of_n_addr_cells(np); |
|---|
| 926 | + size_cells = of_n_size_cells(np); |
|---|
| 927 | + /* |
|---|
| 928 | + * "reg" property represents (addr,size) tuple. |
|---|
| 929 | + */ |
|---|
| 930 | + base = of_read_number(prop, addr_cells); |
|---|
| 931 | + prop += addr_cells; |
|---|
| 932 | + lmb_size = of_read_number(prop, size_cells); |
|---|
| 967 | 933 | |
|---|
| 968 | 934 | /* |
|---|
| 969 | 935 | * Update memory region to represent the memory add |
|---|
| 970 | 936 | */ |
|---|
| 971 | 937 | ret = memblock_add(base, lmb_size); |
|---|
| 972 | 938 | return (ret < 0) ? -EINVAL : 0; |
|---|
| 973 | | -} |
|---|
| 974 | | - |
|---|
| 975 | | -static int pseries_update_drconf_memory(struct of_reconfig_data *pr) |
|---|
| 976 | | -{ |
|---|
| 977 | | - struct of_drconf_cell_v1 *new_drmem, *old_drmem; |
|---|
| 978 | | - unsigned long memblock_size; |
|---|
| 979 | | - u32 entries; |
|---|
| 980 | | - __be32 *p; |
|---|
| 981 | | - int i, rc = -EINVAL; |
|---|
| 982 | | - |
|---|
| 983 | | - if (rtas_hp_event) |
|---|
| 984 | | - return 0; |
|---|
| 985 | | - |
|---|
| 986 | | - memblock_size = pseries_memory_block_size(); |
|---|
| 987 | | - if (!memblock_size) |
|---|
| 988 | | - return -EINVAL; |
|---|
| 989 | | - |
|---|
| 990 | | - if (!pr->old_prop) |
|---|
| 991 | | - return 0; |
|---|
| 992 | | - |
|---|
| 993 | | - p = (__be32 *) pr->old_prop->value; |
|---|
| 994 | | - if (!p) |
|---|
| 995 | | - return -EINVAL; |
|---|
| 996 | | - |
|---|
| 997 | | - /* The first int of the property is the number of lmb's described |
|---|
| 998 | | - * by the property. This is followed by an array of of_drconf_cell |
|---|
| 999 | | - * entries. Get the number of entries and skip to the array of |
|---|
| 1000 | | - * of_drconf_cell's. |
|---|
| 1001 | | - */ |
|---|
| 1002 | | - entries = be32_to_cpu(*p++); |
|---|
| 1003 | | - old_drmem = (struct of_drconf_cell_v1 *)p; |
|---|
| 1004 | | - |
|---|
| 1005 | | - p = (__be32 *)pr->prop->value; |
|---|
| 1006 | | - p++; |
|---|
| 1007 | | - new_drmem = (struct of_drconf_cell_v1 *)p; |
|---|
| 1008 | | - |
|---|
| 1009 | | - for (i = 0; i < entries; i++) { |
|---|
| 1010 | | - if ((be32_to_cpu(old_drmem[i].flags) & DRCONF_MEM_ASSIGNED) && |
|---|
| 1011 | | - (!(be32_to_cpu(new_drmem[i].flags) & DRCONF_MEM_ASSIGNED))) { |
|---|
| 1012 | | - rc = pseries_remove_memblock( |
|---|
| 1013 | | - be64_to_cpu(old_drmem[i].base_addr), |
|---|
| 1014 | | - memblock_size); |
|---|
| 1015 | | - break; |
|---|
| 1016 | | - } else if ((!(be32_to_cpu(old_drmem[i].flags) & |
|---|
| 1017 | | - DRCONF_MEM_ASSIGNED)) && |
|---|
| 1018 | | - (be32_to_cpu(new_drmem[i].flags) & |
|---|
| 1019 | | - DRCONF_MEM_ASSIGNED)) { |
|---|
| 1020 | | - rc = memblock_add(be64_to_cpu(old_drmem[i].base_addr), |
|---|
| 1021 | | - memblock_size); |
|---|
| 1022 | | - rc = (rc < 0) ? -EINVAL : 0; |
|---|
| 1023 | | - break; |
|---|
| 1024 | | - } |
|---|
| 1025 | | - } |
|---|
| 1026 | | - return rc; |
|---|
| 1027 | 939 | } |
|---|
| 1028 | 940 | |
|---|
| 1029 | 941 | static int pseries_memory_notifier(struct notifier_block *nb, |
|---|
| .. | .. |
|---|
| 1038 | 950 | break; |
|---|
| 1039 | 951 | case OF_RECONFIG_DETACH_NODE: |
|---|
| 1040 | 952 | err = pseries_remove_mem_node(rd->dn); |
|---|
| 1041 | | - break; |
|---|
| 1042 | | - case OF_RECONFIG_UPDATE_PROPERTY: |
|---|
| 1043 | | - if (!strcmp(rd->prop->name, "ibm,dynamic-memory")) |
|---|
| 1044 | | - err = pseries_update_drconf_memory(rd); |
|---|
| 1045 | 953 | break; |
|---|
| 1046 | 954 | } |
|---|
| 1047 | 955 | return notifier_from_errno(err); |
|---|