0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) "pseries-hotplug-mem: " fmt
0009
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 #include <linux/memblock.h>
0013 #include <linux/memory.h>
0014 #include <linux/memory_hotplug.h>
0015 #include <linux/slab.h>
0016
0017 #include <asm/firmware.h>
0018 #include <asm/machdep.h>
0019 #include <asm/sparsemem.h>
0020 #include <asm/fadump.h>
0021 #include <asm/drmem.h>
0022 #include "pseries.h"
0023
0024 unsigned long pseries_memory_block_size(void)
0025 {
0026 struct device_node *np;
0027 u64 memblock_size = MIN_MEMORY_BLOCK_SIZE;
0028 struct resource r;
0029
0030 np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
0031 if (np) {
0032 int len;
0033 int size_cells;
0034 const __be32 *prop;
0035
0036 size_cells = of_n_size_cells(np);
0037
0038 prop = of_get_property(np, "ibm,lmb-size", &len);
0039 if (prop && len >= size_cells * sizeof(__be32))
0040 memblock_size = of_read_number(prop, size_cells);
0041 of_node_put(np);
0042
0043 } else if (machine_is(pseries)) {
0044
0045 unsigned int memzero_size = 0;
0046
0047 np = of_find_node_by_path("/memory@0");
0048 if (np) {
0049 if (!of_address_to_resource(np, 0, &r))
0050 memzero_size = resource_size(&r);
0051 of_node_put(np);
0052 }
0053
0054 if (memzero_size) {
0055
0056
0057
0058 char buf[64];
0059
0060 sprintf(buf, "/memory@%x", memzero_size);
0061 np = of_find_node_by_path(buf);
0062 if (np) {
0063 if (!of_address_to_resource(np, 0, &r))
0064 memblock_size = resource_size(&r);
0065 of_node_put(np);
0066 }
0067 }
0068 }
0069 return memblock_size;
0070 }
0071
0072 static void dlpar_free_property(struct property *prop)
0073 {
0074 kfree(prop->name);
0075 kfree(prop->value);
0076 kfree(prop);
0077 }
0078
0079 static struct property *dlpar_clone_property(struct property *prop,
0080 u32 prop_size)
0081 {
0082 struct property *new_prop;
0083
0084 new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
0085 if (!new_prop)
0086 return NULL;
0087
0088 new_prop->name = kstrdup(prop->name, GFP_KERNEL);
0089 new_prop->value = kzalloc(prop_size, GFP_KERNEL);
0090 if (!new_prop->name || !new_prop->value) {
0091 dlpar_free_property(new_prop);
0092 return NULL;
0093 }
0094
0095 memcpy(new_prop->value, prop->value, prop->length);
0096 new_prop->length = prop_size;
0097
0098 of_property_set_flag(new_prop, OF_DYNAMIC);
0099 return new_prop;
0100 }
0101
0102 static bool find_aa_index(struct device_node *dr_node,
0103 struct property *ala_prop,
0104 const u32 *lmb_assoc, u32 *aa_index)
0105 {
0106 u32 *assoc_arrays, new_prop_size;
0107 struct property *new_prop;
0108 int aa_arrays, aa_array_entries, aa_array_sz;
0109 int i, index;
0110
0111
0112
0113
0114
0115
0116
0117 assoc_arrays = ala_prop->value;
0118
0119 aa_arrays = be32_to_cpu(assoc_arrays[0]);
0120 aa_array_entries = be32_to_cpu(assoc_arrays[1]);
0121 aa_array_sz = aa_array_entries * sizeof(u32);
0122
0123 for (i = 0; i < aa_arrays; i++) {
0124 index = (i * aa_array_entries) + 2;
0125
0126 if (memcmp(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz))
0127 continue;
0128
0129 *aa_index = i;
0130 return true;
0131 }
0132
0133 new_prop_size = ala_prop->length + aa_array_sz;
0134 new_prop = dlpar_clone_property(ala_prop, new_prop_size);
0135 if (!new_prop)
0136 return false;
0137
0138 assoc_arrays = new_prop->value;
0139
0140
0141 assoc_arrays[0] = cpu_to_be32(aa_arrays + 1);
0142
0143
0144 index = aa_arrays * aa_array_entries + 2;
0145 memcpy(&assoc_arrays[index], &lmb_assoc[1], aa_array_sz);
0146
0147 of_update_property(dr_node, new_prop);
0148
0149
0150
0151
0152
0153
0154 *aa_index = be32_to_cpu(assoc_arrays[0]) - 1;
0155 return true;
0156 }
0157
0158 static int update_lmb_associativity_index(struct drmem_lmb *lmb)
0159 {
0160 struct device_node *parent, *lmb_node, *dr_node;
0161 struct property *ala_prop;
0162 const u32 *lmb_assoc;
0163 u32 aa_index;
0164 bool found;
0165
0166 parent = of_find_node_by_path("/");
0167 if (!parent)
0168 return -ENODEV;
0169
0170 lmb_node = dlpar_configure_connector(cpu_to_be32(lmb->drc_index),
0171 parent);
0172 of_node_put(parent);
0173 if (!lmb_node)
0174 return -EINVAL;
0175
0176 lmb_assoc = of_get_property(lmb_node, "ibm,associativity", NULL);
0177 if (!lmb_assoc) {
0178 dlpar_free_cc_nodes(lmb_node);
0179 return -ENODEV;
0180 }
0181
0182 update_numa_distance(lmb_node);
0183
0184 dr_node = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
0185 if (!dr_node) {
0186 dlpar_free_cc_nodes(lmb_node);
0187 return -ENODEV;
0188 }
0189
0190 ala_prop = of_find_property(dr_node, "ibm,associativity-lookup-arrays",
0191 NULL);
0192 if (!ala_prop) {
0193 of_node_put(dr_node);
0194 dlpar_free_cc_nodes(lmb_node);
0195 return -ENODEV;
0196 }
0197
0198 found = find_aa_index(dr_node, ala_prop, lmb_assoc, &aa_index);
0199
0200 of_node_put(dr_node);
0201 dlpar_free_cc_nodes(lmb_node);
0202
0203 if (!found) {
0204 pr_err("Could not find LMB associativity\n");
0205 return -1;
0206 }
0207
0208 lmb->aa_index = aa_index;
0209 return 0;
0210 }
0211
0212 static struct memory_block *lmb_to_memblock(struct drmem_lmb *lmb)
0213 {
0214 unsigned long section_nr;
0215 struct memory_block *mem_block;
0216
0217 section_nr = pfn_to_section_nr(PFN_DOWN(lmb->base_addr));
0218
0219 mem_block = find_memory_block(section_nr);
0220 return mem_block;
0221 }
0222
0223 static int get_lmb_range(u32 drc_index, int n_lmbs,
0224 struct drmem_lmb **start_lmb,
0225 struct drmem_lmb **end_lmb)
0226 {
0227 struct drmem_lmb *lmb, *start, *end;
0228 struct drmem_lmb *limit;
0229
0230 start = NULL;
0231 for_each_drmem_lmb(lmb) {
0232 if (lmb->drc_index == drc_index) {
0233 start = lmb;
0234 break;
0235 }
0236 }
0237
0238 if (!start)
0239 return -EINVAL;
0240
0241 end = &start[n_lmbs];
0242
0243 limit = &drmem_info->lmbs[drmem_info->n_lmbs];
0244 if (end > limit)
0245 return -EINVAL;
0246
0247 *start_lmb = start;
0248 *end_lmb = end;
0249 return 0;
0250 }
0251
0252 static int dlpar_change_lmb_state(struct drmem_lmb *lmb, bool online)
0253 {
0254 struct memory_block *mem_block;
0255 int rc;
0256
0257 mem_block = lmb_to_memblock(lmb);
0258 if (!mem_block)
0259 return -EINVAL;
0260
0261 if (online && mem_block->dev.offline)
0262 rc = device_online(&mem_block->dev);
0263 else if (!online && !mem_block->dev.offline)
0264 rc = device_offline(&mem_block->dev);
0265 else
0266 rc = 0;
0267
0268 put_device(&mem_block->dev);
0269
0270 return rc;
0271 }
0272
0273 static int dlpar_online_lmb(struct drmem_lmb *lmb)
0274 {
0275 return dlpar_change_lmb_state(lmb, true);
0276 }
0277
0278 #ifdef CONFIG_MEMORY_HOTREMOVE
0279 static int dlpar_offline_lmb(struct drmem_lmb *lmb)
0280 {
0281 return dlpar_change_lmb_state(lmb, false);
0282 }
0283
0284 static int pseries_remove_memblock(unsigned long base, unsigned long memblock_size)
0285 {
0286 unsigned long block_sz, start_pfn;
0287 int sections_per_block;
0288 int i;
0289
0290 start_pfn = base >> PAGE_SHIFT;
0291
0292 lock_device_hotplug();
0293
0294 if (!pfn_valid(start_pfn))
0295 goto out;
0296
0297 block_sz = pseries_memory_block_size();
0298 sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
0299
0300 for (i = 0; i < sections_per_block; i++) {
0301 __remove_memory(base, MIN_MEMORY_BLOCK_SIZE);
0302 base += MIN_MEMORY_BLOCK_SIZE;
0303 }
0304
0305 out:
0306
0307 memblock_remove(base, memblock_size);
0308 unlock_device_hotplug();
0309 return 0;
0310 }
0311
0312 static int pseries_remove_mem_node(struct device_node *np)
0313 {
0314 const __be32 *prop;
0315 unsigned long base;
0316 unsigned long lmb_size;
0317 int ret = -EINVAL;
0318 int addr_cells, size_cells;
0319
0320
0321
0322
0323 if (!of_node_is_type(np, "memory"))
0324 return 0;
0325
0326
0327
0328
0329 prop = of_get_property(np, "reg", NULL);
0330 if (!prop)
0331 return ret;
0332
0333 addr_cells = of_n_addr_cells(np);
0334 size_cells = of_n_size_cells(np);
0335
0336
0337
0338
0339 base = of_read_number(prop, addr_cells);
0340 prop += addr_cells;
0341 lmb_size = of_read_number(prop, size_cells);
0342
0343 pseries_remove_memblock(base, lmb_size);
0344 return 0;
0345 }
0346
0347 static bool lmb_is_removable(struct drmem_lmb *lmb)
0348 {
0349 if ((lmb->flags & DRCONF_MEM_RESERVED) ||
0350 !(lmb->flags & DRCONF_MEM_ASSIGNED))
0351 return false;
0352
0353 #ifdef CONFIG_FA_DUMP
0354
0355
0356
0357
0358 if (is_fadump_memory_area(lmb->base_addr, memory_block_size_bytes()))
0359 return false;
0360 #endif
0361
0362 return true;
0363 }
0364
0365 static int dlpar_add_lmb(struct drmem_lmb *);
0366
0367 static int dlpar_remove_lmb(struct drmem_lmb *lmb)
0368 {
0369 struct memory_block *mem_block;
0370 unsigned long block_sz;
0371 int rc;
0372
0373 if (!lmb_is_removable(lmb))
0374 return -EINVAL;
0375
0376 mem_block = lmb_to_memblock(lmb);
0377 if (mem_block == NULL)
0378 return -EINVAL;
0379
0380 rc = dlpar_offline_lmb(lmb);
0381 if (rc) {
0382 put_device(&mem_block->dev);
0383 return rc;
0384 }
0385
0386 block_sz = pseries_memory_block_size();
0387
0388 __remove_memory(lmb->base_addr, block_sz);
0389 put_device(&mem_block->dev);
0390
0391
0392 memblock_remove(lmb->base_addr, block_sz);
0393
0394 invalidate_lmb_associativity_index(lmb);
0395 lmb->flags &= ~DRCONF_MEM_ASSIGNED;
0396
0397 return 0;
0398 }
0399
0400 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove)
0401 {
0402 struct drmem_lmb *lmb;
0403 int lmbs_reserved = 0;
0404 int lmbs_available = 0;
0405 int rc;
0406
0407 pr_info("Attempting to hot-remove %d LMB(s)\n", lmbs_to_remove);
0408
0409 if (lmbs_to_remove == 0)
0410 return -EINVAL;
0411
0412
0413 for_each_drmem_lmb(lmb) {
0414 if (lmb_is_removable(lmb))
0415 lmbs_available++;
0416
0417 if (lmbs_available == lmbs_to_remove)
0418 break;
0419 }
0420
0421 if (lmbs_available < lmbs_to_remove) {
0422 pr_info("Not enough LMBs available (%d of %d) to satisfy request\n",
0423 lmbs_available, lmbs_to_remove);
0424 return -EINVAL;
0425 }
0426
0427 for_each_drmem_lmb(lmb) {
0428 rc = dlpar_remove_lmb(lmb);
0429 if (rc)
0430 continue;
0431
0432
0433
0434
0435 drmem_mark_lmb_reserved(lmb);
0436
0437 lmbs_reserved++;
0438 if (lmbs_reserved == lmbs_to_remove)
0439 break;
0440 }
0441
0442 if (lmbs_reserved != lmbs_to_remove) {
0443 pr_err("Memory hot-remove failed, adding LMB's back\n");
0444
0445 for_each_drmem_lmb(lmb) {
0446 if (!drmem_lmb_reserved(lmb))
0447 continue;
0448
0449 rc = dlpar_add_lmb(lmb);
0450 if (rc)
0451 pr_err("Failed to add LMB back, drc index %x\n",
0452 lmb->drc_index);
0453
0454 drmem_remove_lmb_reservation(lmb);
0455
0456 lmbs_reserved--;
0457 if (lmbs_reserved == 0)
0458 break;
0459 }
0460
0461 rc = -EINVAL;
0462 } else {
0463 for_each_drmem_lmb(lmb) {
0464 if (!drmem_lmb_reserved(lmb))
0465 continue;
0466
0467 dlpar_release_drc(lmb->drc_index);
0468 pr_info("Memory at %llx was hot-removed\n",
0469 lmb->base_addr);
0470
0471 drmem_remove_lmb_reservation(lmb);
0472
0473 lmbs_reserved--;
0474 if (lmbs_reserved == 0)
0475 break;
0476 }
0477 rc = 0;
0478 }
0479
0480 return rc;
0481 }
0482
0483 static int dlpar_memory_remove_by_index(u32 drc_index)
0484 {
0485 struct drmem_lmb *lmb;
0486 int lmb_found;
0487 int rc;
0488
0489 pr_debug("Attempting to hot-remove LMB, drc index %x\n", drc_index);
0490
0491 lmb_found = 0;
0492 for_each_drmem_lmb(lmb) {
0493 if (lmb->drc_index == drc_index) {
0494 lmb_found = 1;
0495 rc = dlpar_remove_lmb(lmb);
0496 if (!rc)
0497 dlpar_release_drc(lmb->drc_index);
0498
0499 break;
0500 }
0501 }
0502
0503 if (!lmb_found)
0504 rc = -EINVAL;
0505
0506 if (rc)
0507 pr_debug("Failed to hot-remove memory at %llx\n",
0508 lmb->base_addr);
0509 else
0510 pr_debug("Memory at %llx was hot-removed\n", lmb->base_addr);
0511
0512 return rc;
0513 }
0514
0515 static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)
0516 {
0517 struct drmem_lmb *lmb, *start_lmb, *end_lmb;
0518 int rc;
0519
0520 pr_info("Attempting to hot-remove %u LMB(s) at %x\n",
0521 lmbs_to_remove, drc_index);
0522
0523 if (lmbs_to_remove == 0)
0524 return -EINVAL;
0525
0526 rc = get_lmb_range(drc_index, lmbs_to_remove, &start_lmb, &end_lmb);
0527 if (rc)
0528 return -EINVAL;
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
0541 if (lmb->flags & DRCONF_MEM_RESERVED) {
0542 pr_err("Memory at %llx (drc index %x) is reserved\n",
0543 lmb->base_addr, lmb->drc_index);
0544 return -EINVAL;
0545 }
0546 }
0547
0548 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
0549
0550
0551
0552
0553 if (!(lmb->flags & DRCONF_MEM_ASSIGNED))
0554 continue;
0555
0556 rc = dlpar_remove_lmb(lmb);
0557 if (rc)
0558 break;
0559
0560 drmem_mark_lmb_reserved(lmb);
0561 }
0562
0563 if (rc) {
0564 pr_err("Memory indexed-count-remove failed, adding any removed LMBs\n");
0565
0566
0567 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
0568 if (!drmem_lmb_reserved(lmb))
0569 continue;
0570
0571
0572
0573
0574
0575
0576 dlpar_unisolate_drc(lmb->drc_index);
0577
0578 rc = dlpar_add_lmb(lmb);
0579 if (rc)
0580 pr_err("Failed to add LMB, drc index %x\n",
0581 lmb->drc_index);
0582
0583 drmem_remove_lmb_reservation(lmb);
0584 }
0585 rc = -EINVAL;
0586 } else {
0587 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
0588 if (!drmem_lmb_reserved(lmb))
0589 continue;
0590
0591 dlpar_release_drc(lmb->drc_index);
0592 pr_info("Memory at %llx (drc index %x) was hot-removed\n",
0593 lmb->base_addr, lmb->drc_index);
0594
0595 drmem_remove_lmb_reservation(lmb);
0596 }
0597 }
0598
0599 return rc;
0600 }
0601
0602 #else
0603 static inline int pseries_remove_memblock(unsigned long base,
0604 unsigned long memblock_size)
0605 {
0606 return -EOPNOTSUPP;
0607 }
0608 static inline int pseries_remove_mem_node(struct device_node *np)
0609 {
0610 return 0;
0611 }
0612 static int dlpar_remove_lmb(struct drmem_lmb *lmb)
0613 {
0614 return -EOPNOTSUPP;
0615 }
0616 static int dlpar_memory_remove_by_count(u32 lmbs_to_remove)
0617 {
0618 return -EOPNOTSUPP;
0619 }
0620 static int dlpar_memory_remove_by_index(u32 drc_index)
0621 {
0622 return -EOPNOTSUPP;
0623 }
0624
0625 static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)
0626 {
0627 return -EOPNOTSUPP;
0628 }
0629 #endif
0630
0631 static int dlpar_add_lmb(struct drmem_lmb *lmb)
0632 {
0633 unsigned long block_sz;
0634 int nid, rc;
0635
0636 if (lmb->flags & DRCONF_MEM_ASSIGNED)
0637 return -EINVAL;
0638
0639 rc = update_lmb_associativity_index(lmb);
0640 if (rc) {
0641 dlpar_release_drc(lmb->drc_index);
0642 return rc;
0643 }
0644
0645 block_sz = memory_block_size_bytes();
0646
0647
0648 nid = of_drconf_to_nid_single(lmb);
0649 if (nid < 0 || !node_possible(nid))
0650 nid = first_online_node;
0651
0652
0653 rc = __add_memory(nid, lmb->base_addr, block_sz, MHP_NONE);
0654 if (rc) {
0655 invalidate_lmb_associativity_index(lmb);
0656 return rc;
0657 }
0658
0659 rc = dlpar_online_lmb(lmb);
0660 if (rc) {
0661 __remove_memory(lmb->base_addr, block_sz);
0662 invalidate_lmb_associativity_index(lmb);
0663 } else {
0664 lmb->flags |= DRCONF_MEM_ASSIGNED;
0665 }
0666
0667 return rc;
0668 }
0669
0670 static int dlpar_memory_add_by_count(u32 lmbs_to_add)
0671 {
0672 struct drmem_lmb *lmb;
0673 int lmbs_available = 0;
0674 int lmbs_reserved = 0;
0675 int rc;
0676
0677 pr_info("Attempting to hot-add %d LMB(s)\n", lmbs_to_add);
0678
0679 if (lmbs_to_add == 0)
0680 return -EINVAL;
0681
0682
0683 for_each_drmem_lmb(lmb) {
0684 if (lmb->flags & DRCONF_MEM_RESERVED)
0685 continue;
0686
0687 if (!(lmb->flags & DRCONF_MEM_ASSIGNED))
0688 lmbs_available++;
0689
0690 if (lmbs_available == lmbs_to_add)
0691 break;
0692 }
0693
0694 if (lmbs_available < lmbs_to_add)
0695 return -EINVAL;
0696
0697 for_each_drmem_lmb(lmb) {
0698 if (lmb->flags & DRCONF_MEM_ASSIGNED)
0699 continue;
0700
0701 rc = dlpar_acquire_drc(lmb->drc_index);
0702 if (rc)
0703 continue;
0704
0705 rc = dlpar_add_lmb(lmb);
0706 if (rc) {
0707 dlpar_release_drc(lmb->drc_index);
0708 continue;
0709 }
0710
0711
0712
0713
0714 drmem_mark_lmb_reserved(lmb);
0715 lmbs_reserved++;
0716 if (lmbs_reserved == lmbs_to_add)
0717 break;
0718 }
0719
0720 if (lmbs_reserved != lmbs_to_add) {
0721 pr_err("Memory hot-add failed, removing any added LMBs\n");
0722
0723 for_each_drmem_lmb(lmb) {
0724 if (!drmem_lmb_reserved(lmb))
0725 continue;
0726
0727 rc = dlpar_remove_lmb(lmb);
0728 if (rc)
0729 pr_err("Failed to remove LMB, drc index %x\n",
0730 lmb->drc_index);
0731 else
0732 dlpar_release_drc(lmb->drc_index);
0733
0734 drmem_remove_lmb_reservation(lmb);
0735 lmbs_reserved--;
0736
0737 if (lmbs_reserved == 0)
0738 break;
0739 }
0740 rc = -EINVAL;
0741 } else {
0742 for_each_drmem_lmb(lmb) {
0743 if (!drmem_lmb_reserved(lmb))
0744 continue;
0745
0746 pr_debug("Memory at %llx (drc index %x) was hot-added\n",
0747 lmb->base_addr, lmb->drc_index);
0748 drmem_remove_lmb_reservation(lmb);
0749 lmbs_reserved--;
0750
0751 if (lmbs_reserved == 0)
0752 break;
0753 }
0754 rc = 0;
0755 }
0756
0757 return rc;
0758 }
0759
0760 static int dlpar_memory_add_by_index(u32 drc_index)
0761 {
0762 struct drmem_lmb *lmb;
0763 int rc, lmb_found;
0764
0765 pr_info("Attempting to hot-add LMB, drc index %x\n", drc_index);
0766
0767 lmb_found = 0;
0768 for_each_drmem_lmb(lmb) {
0769 if (lmb->drc_index == drc_index) {
0770 lmb_found = 1;
0771 rc = dlpar_acquire_drc(lmb->drc_index);
0772 if (!rc) {
0773 rc = dlpar_add_lmb(lmb);
0774 if (rc)
0775 dlpar_release_drc(lmb->drc_index);
0776 }
0777
0778 break;
0779 }
0780 }
0781
0782 if (!lmb_found)
0783 rc = -EINVAL;
0784
0785 if (rc)
0786 pr_info("Failed to hot-add memory, drc index %x\n", drc_index);
0787 else
0788 pr_info("Memory at %llx (drc index %x) was hot-added\n",
0789 lmb->base_addr, drc_index);
0790
0791 return rc;
0792 }
0793
0794 static int dlpar_memory_add_by_ic(u32 lmbs_to_add, u32 drc_index)
0795 {
0796 struct drmem_lmb *lmb, *start_lmb, *end_lmb;
0797 int rc;
0798
0799 pr_info("Attempting to hot-add %u LMB(s) at index %x\n",
0800 lmbs_to_add, drc_index);
0801
0802 if (lmbs_to_add == 0)
0803 return -EINVAL;
0804
0805 rc = get_lmb_range(drc_index, lmbs_to_add, &start_lmb, &end_lmb);
0806 if (rc)
0807 return -EINVAL;
0808
0809
0810 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
0811
0812 if (lmb->flags & DRCONF_MEM_RESERVED) {
0813 pr_err("Memory at %llx (drc index %x) is reserved\n",
0814 lmb->base_addr, lmb->drc_index);
0815 return -EINVAL;
0816 }
0817 }
0818
0819 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
0820 if (lmb->flags & DRCONF_MEM_ASSIGNED)
0821 continue;
0822
0823 rc = dlpar_acquire_drc(lmb->drc_index);
0824 if (rc)
0825 break;
0826
0827 rc = dlpar_add_lmb(lmb);
0828 if (rc) {
0829 dlpar_release_drc(lmb->drc_index);
0830 break;
0831 }
0832
0833 drmem_mark_lmb_reserved(lmb);
0834 }
0835
0836 if (rc) {
0837 pr_err("Memory indexed-count-add failed, removing any added LMBs\n");
0838
0839 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
0840 if (!drmem_lmb_reserved(lmb))
0841 continue;
0842
0843 rc = dlpar_remove_lmb(lmb);
0844 if (rc)
0845 pr_err("Failed to remove LMB, drc index %x\n",
0846 lmb->drc_index);
0847 else
0848 dlpar_release_drc(lmb->drc_index);
0849
0850 drmem_remove_lmb_reservation(lmb);
0851 }
0852 rc = -EINVAL;
0853 } else {
0854 for_each_drmem_lmb_in_range(lmb, start_lmb, end_lmb) {
0855 if (!drmem_lmb_reserved(lmb))
0856 continue;
0857
0858 pr_info("Memory at %llx (drc index %x) was hot-added\n",
0859 lmb->base_addr, lmb->drc_index);
0860 drmem_remove_lmb_reservation(lmb);
0861 }
0862 }
0863
0864 return rc;
0865 }
0866
0867 int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
0868 {
0869 u32 count, drc_index;
0870 int rc;
0871
0872 lock_device_hotplug();
0873
0874 switch (hp_elog->action) {
0875 case PSERIES_HP_ELOG_ACTION_ADD:
0876 switch (hp_elog->id_type) {
0877 case PSERIES_HP_ELOG_ID_DRC_COUNT:
0878 count = hp_elog->_drc_u.drc_count;
0879 rc = dlpar_memory_add_by_count(count);
0880 break;
0881 case PSERIES_HP_ELOG_ID_DRC_INDEX:
0882 drc_index = hp_elog->_drc_u.drc_index;
0883 rc = dlpar_memory_add_by_index(drc_index);
0884 break;
0885 case PSERIES_HP_ELOG_ID_DRC_IC:
0886 count = hp_elog->_drc_u.ic.count;
0887 drc_index = hp_elog->_drc_u.ic.index;
0888 rc = dlpar_memory_add_by_ic(count, drc_index);
0889 break;
0890 default:
0891 rc = -EINVAL;
0892 break;
0893 }
0894
0895 break;
0896 case PSERIES_HP_ELOG_ACTION_REMOVE:
0897 switch (hp_elog->id_type) {
0898 case PSERIES_HP_ELOG_ID_DRC_COUNT:
0899 count = hp_elog->_drc_u.drc_count;
0900 rc = dlpar_memory_remove_by_count(count);
0901 break;
0902 case PSERIES_HP_ELOG_ID_DRC_INDEX:
0903 drc_index = hp_elog->_drc_u.drc_index;
0904 rc = dlpar_memory_remove_by_index(drc_index);
0905 break;
0906 case PSERIES_HP_ELOG_ID_DRC_IC:
0907 count = hp_elog->_drc_u.ic.count;
0908 drc_index = hp_elog->_drc_u.ic.index;
0909 rc = dlpar_memory_remove_by_ic(count, drc_index);
0910 break;
0911 default:
0912 rc = -EINVAL;
0913 break;
0914 }
0915
0916 break;
0917 default:
0918 pr_err("Invalid action (%d) specified\n", hp_elog->action);
0919 rc = -EINVAL;
0920 break;
0921 }
0922
0923 if (!rc)
0924 rc = drmem_update_dt();
0925
0926 unlock_device_hotplug();
0927 return rc;
0928 }
0929
0930 static int pseries_add_mem_node(struct device_node *np)
0931 {
0932 const __be32 *prop;
0933 unsigned long base;
0934 unsigned long lmb_size;
0935 int ret = -EINVAL;
0936 int addr_cells, size_cells;
0937
0938
0939
0940
0941 if (!of_node_is_type(np, "memory"))
0942 return 0;
0943
0944
0945
0946
0947 prop = of_get_property(np, "reg", NULL);
0948 if (!prop)
0949 return ret;
0950
0951 addr_cells = of_n_addr_cells(np);
0952 size_cells = of_n_size_cells(np);
0953
0954
0955
0956 base = of_read_number(prop, addr_cells);
0957 prop += addr_cells;
0958 lmb_size = of_read_number(prop, size_cells);
0959
0960
0961
0962
0963 ret = memblock_add(base, lmb_size);
0964 return (ret < 0) ? -EINVAL : 0;
0965 }
0966
0967 static int pseries_memory_notifier(struct notifier_block *nb,
0968 unsigned long action, void *data)
0969 {
0970 struct of_reconfig_data *rd = data;
0971 int err = 0;
0972
0973 switch (action) {
0974 case OF_RECONFIG_ATTACH_NODE:
0975 err = pseries_add_mem_node(rd->dn);
0976 break;
0977 case OF_RECONFIG_DETACH_NODE:
0978 err = pseries_remove_mem_node(rd->dn);
0979 break;
0980 case OF_RECONFIG_UPDATE_PROPERTY:
0981 if (!strcmp(rd->dn->name,
0982 "ibm,dynamic-reconfiguration-memory"))
0983 drmem_update_lmbs(rd->prop);
0984 }
0985 return notifier_from_errno(err);
0986 }
0987
0988 static struct notifier_block pseries_mem_nb = {
0989 .notifier_call = pseries_memory_notifier,
0990 };
0991
0992 static int __init pseries_memory_hotplug_init(void)
0993 {
0994 if (firmware_has_feature(FW_FEATURE_LPAR))
0995 of_reconfig_notifier_register(&pseries_mem_nb);
0996
0997 return 0;
0998 }
0999 machine_device_initcall(pseries, pseries_memory_hotplug_init);