memblock: make memblock_set_node() support different memblock_type
[platform/adaptation/renesas_rcar/renesas_kernel.git] / mm / memblock.c
index 53e477b..d568100 100644 (file)
@@ -255,6 +255,7 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u
                type->cnt = 1;
                type->regions[0].base = 0;
                type->regions[0].size = 0;
+               type->regions[0].flags = 0;
                memblock_set_region_node(&type->regions[0], MAX_NUMNODES);
        }
 }
@@ -405,7 +406,8 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type)
 
                if (this->base + this->size != next->base ||
                    memblock_get_region_node(this) !=
-                   memblock_get_region_node(next)) {
+                   memblock_get_region_node(next) ||
+                   this->flags != next->flags) {
                        BUG_ON(this->base + this->size > next->base);
                        i++;
                        continue;
@@ -425,13 +427,15 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type)
  * @base:      base address of the new region
  * @size:      size of the new region
  * @nid:       node id of the new region
+ * @flags:     flags of the new region
  *
  * Insert new memblock region [@base,@base+@size) into @type at @idx.
  * @type must already have extra room to accomodate the new region.
  */
 static void __init_memblock memblock_insert_region(struct memblock_type *type,
                                                   int idx, phys_addr_t base,
-                                                  phys_addr_t size, int nid)
+                                                  phys_addr_t size,
+                                                  int nid, unsigned long flags)
 {
        struct memblock_region *rgn = &type->regions[idx];
 
@@ -439,6 +443,7 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type,
        memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn));
        rgn->base = base;
        rgn->size = size;
+       rgn->flags = flags;
        memblock_set_region_node(rgn, nid);
        type->cnt++;
        type->total_size += size;
@@ -450,6 +455,7 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type,
  * @base: base address of the new region
  * @size: size of the new region
  * @nid: nid of the new region
+ * @flags: flags of the new region
  *
  * Add new memblock region [@base,@base+@size) into @type.  The new region
  * is allowed to overlap with existing ones - overlaps don't affect already
@@ -460,7 +466,8 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type,
  * 0 on success, -errno on failure.
  */
 static int __init_memblock memblock_add_region(struct memblock_type *type,
-                               phys_addr_t base, phys_addr_t size, int nid)
+                               phys_addr_t base, phys_addr_t size,
+                               int nid, unsigned long flags)
 {
        bool insert = false;
        phys_addr_t obase = base;
@@ -475,6 +482,7 @@ static int __init_memblock memblock_add_region(struct memblock_type *type,
                WARN_ON(type->cnt != 1 || type->total_size);
                type->regions[0].base = base;
                type->regions[0].size = size;
+               type->regions[0].flags = flags;
                memblock_set_region_node(&type->regions[0], nid);
                type->total_size = size;
                return 0;
@@ -505,7 +513,8 @@ repeat:
                        nr_new++;
                        if (insert)
                                memblock_insert_region(type, i++, base,
-                                                      rbase - base, nid);
+                                                      rbase - base, nid,
+                                                      flags);
                }
                /* area below @rend is dealt with, forget about it */
                base = min(rend, end);
@@ -515,7 +524,8 @@ repeat:
        if (base < end) {
                nr_new++;
                if (insert)
-                       memblock_insert_region(type, i, base, end - base, nid);
+                       memblock_insert_region(type, i, base, end - base,
+                                              nid, flags);
        }
 
        /*
@@ -537,12 +547,13 @@ repeat:
 int __init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size,
                                       int nid)
 {
-       return memblock_add_region(&memblock.memory, base, size, nid);
+       return memblock_add_region(&memblock.memory, base, size, nid, 0);
 }
 
 int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
 {
-       return memblock_add_region(&memblock.memory, base, size, MAX_NUMNODES);
+       return memblock_add_region(&memblock.memory, base, size,
+                                  MAX_NUMNODES, 0);
 }
 
 /**
@@ -597,7 +608,8 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type,
                        rgn->size -= base - rbase;
                        type->total_size -= base - rbase;
                        memblock_insert_region(type, i, rbase, base - rbase,
-                                              memblock_get_region_node(rgn));
+                                              memblock_get_region_node(rgn),
+                                              rgn->flags);
                } else if (rend > end) {
                        /*
                         * @rgn intersects from above.  Split and redo the
@@ -607,7 +619,8 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type,
                        rgn->size -= end - rbase;
                        type->total_size -= end - rbase;
                        memblock_insert_region(type, i--, rbase, end - rbase,
-                                              memblock_get_region_node(rgn));
+                                              memblock_get_region_node(rgn),
+                                              rgn->flags);
                } else {
                        /* @rgn is fully contained, record it */
                        if (!*end_rgn)
@@ -643,22 +656,83 @@ int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size)
 {
        memblock_dbg("   memblock_free: [%#016llx-%#016llx] %pF\n",
                     (unsigned long long)base,
-                    (unsigned long long)base + size,
+                    (unsigned long long)base + size - 1,
                     (void *)_RET_IP_);
 
        return __memblock_remove(&memblock.reserved, base, size);
 }
 
-int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
+static int __init_memblock memblock_reserve_region(phys_addr_t base,
+                                                  phys_addr_t size,
+                                                  int nid,
+                                                  unsigned long flags)
 {
        struct memblock_type *_rgn = &memblock.reserved;
 
-       memblock_dbg("memblock_reserve: [%#016llx-%#016llx] %pF\n",
+       memblock_dbg("memblock_reserve: [%#016llx-%#016llx] flags %#02lx %pF\n",
                     (unsigned long long)base,
-                    (unsigned long long)base + size,
-                    (void *)_RET_IP_);
+                    (unsigned long long)base + size - 1,
+                    flags, (void *)_RET_IP_);
+
+       return memblock_add_region(_rgn, base, size, nid, flags);
+}
 
-       return memblock_add_region(_rgn, base, size, MAX_NUMNODES);
+int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
+{
+       return memblock_reserve_region(base, size, MAX_NUMNODES, 0);
+}
+
+/**
+ * memblock_mark_hotplug - Mark hotpluggable memory with flag MEMBLOCK_HOTPLUG.
+ * @base: the base phys addr of the region
+ * @size: the size of the region
+ *
+ * This function isolates region [@base, @base + @size), and mark it with flag
+ * MEMBLOCK_HOTPLUG.
+ *
+ * Return 0 on succees, -errno on failure.
+ */
+int __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size)
+{
+       struct memblock_type *type = &memblock.memory;
+       int i, ret, start_rgn, end_rgn;
+
+       ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn);
+       if (ret)
+               return ret;
+
+       for (i = start_rgn; i < end_rgn; i++)
+               memblock_set_region_flags(&type->regions[i], MEMBLOCK_HOTPLUG);
+
+       memblock_merge_regions(type);
+       return 0;
+}
+
+/**
+ * memblock_clear_hotplug - Clear flag MEMBLOCK_HOTPLUG for a specified region.
+ * @base: the base phys addr of the region
+ * @size: the size of the region
+ *
+ * This function isolates region [@base, @base + @size), and clear flag
+ * MEMBLOCK_HOTPLUG for the isolated regions.
+ *
+ * Return 0 on succees, -errno on failure.
+ */
+int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size)
+{
+       struct memblock_type *type = &memblock.memory;
+       int i, ret, start_rgn, end_rgn;
+
+       ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn);
+       if (ret)
+               return ret;
+
+       for (i = start_rgn; i < end_rgn; i++)
+               memblock_clear_region_flags(&type->regions[i],
+                                           MEMBLOCK_HOTPLUG);
+
+       memblock_merge_regions(type);
+       return 0;
 }
 
 /**
@@ -837,18 +911,18 @@ void __init_memblock __next_mem_pfn_range(int *idx, int nid,
  * memblock_set_node - set node ID on memblock regions
  * @base: base of area to set node ID for
  * @size: size of area to set node ID for
+ * @type: memblock type to set node ID for
  * @nid: node ID to set
  *
- * Set the nid of memblock memory regions in [@base,@base+@size) to @nid.
+ * Set the nid of memblock @type regions in [@base,@base+@size) to @nid.
  * Regions which cross the area boundaries are split as necessary.
  *
  * RETURNS:
  * 0 on success, -errno on failure.
  */
 int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
-                                     int nid)
+                                     struct memblock_type *type, int nid)
 {
-       struct memblock_type *type = &memblock.memory;
        int start_rgn, end_rgn;
        int i, ret;
 
@@ -1101,6 +1175,7 @@ void __init_memblock memblock_set_current_limit(phys_addr_t limit)
 static void __init_memblock memblock_dump(struct memblock_type *type, char *name)
 {
        unsigned long long base, size;
+       unsigned long flags;
        int i;
 
        pr_info(" %s.cnt  = 0x%lx\n", name, type->cnt);
@@ -1111,13 +1186,14 @@ static void __init_memblock memblock_dump(struct memblock_type *type, char *name
 
                base = rgn->base;
                size = rgn->size;
+               flags = rgn->flags;
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
                if (memblock_get_region_node(rgn) != MAX_NUMNODES)
                        snprintf(nid_buf, sizeof(nid_buf), " on node %d",
                                 memblock_get_region_node(rgn));
 #endif
-               pr_info(" %s[%#x]\t[%#016llx-%#016llx], %#llx bytes%s\n",
-                       name, i, base, base + size - 1, size, nid_buf);
+               pr_info(" %s[%#x]\t[%#016llx-%#016llx], %#llx bytes%s flags: %#lx\n",
+                       name, i, base, base + size - 1, size, nid_buf, flags);
        }
 }