OSDN Git Service

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