summaryrefslogtreecommitdiffstats
path: root/mm/memblock.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--mm/memblock.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/mm/memblock.c b/mm/memblock.c
index 33a8b6f7b626..adb5a3c4bf06 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -2242,6 +2242,123 @@ void __init memblock_free_all(void)
totalram_pages_add(pages);
}
+/* Keep a table to reserve named memory */
+#define RESERVE_MEM_MAX_ENTRIES 8
+#define RESERVE_MEM_NAME_SIZE 16
+struct reserve_mem_table {
+ char name[RESERVE_MEM_NAME_SIZE];
+ phys_addr_t start;
+ phys_addr_t size;
+};
+static struct reserve_mem_table reserved_mem_table[RESERVE_MEM_MAX_ENTRIES];
+static int reserved_mem_count;
+
+/* Add wildcard region with a lookup name */
+static void __init reserved_mem_add(phys_addr_t start, phys_addr_t size,
+ const char *name)
+{
+ struct reserve_mem_table *map;
+
+ map = &reserved_mem_table[reserved_mem_count++];
+ map->start = start;
+ map->size = size;
+ strscpy(map->name, name);
+}
+
+/**
+ * reserve_mem_find_by_name - Find reserved memory region with a given name
+ * @name: The name that is attached to a reserved memory region
+ * @start: If found, holds the start address
+ * @size: If found, holds the size of the address.
+ *
+ * @start and @size are only updated if @name is found.
+ *
+ * Returns: 1 if found or 0 if not found.
+ */
+int reserve_mem_find_by_name(const char *name, phys_addr_t *start, phys_addr_t *size)
+{
+ struct reserve_mem_table *map;
+ int i;
+
+ for (i = 0; i < reserved_mem_count; i++) {
+ map = &reserved_mem_table[i];
+ if (!map->size)
+ continue;
+ if (strcmp(name, map->name) == 0) {
+ *start = map->start;
+ *size = map->size;
+ return 1;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(reserve_mem_find_by_name);
+
+/*
+ * Parse reserve_mem=nn:align:name
+ */
+static int __init reserve_mem(char *p)
+{
+ phys_addr_t start, size, align, tmp;
+ char *name;
+ char *oldp;
+ int len;
+
+ if (!p)
+ return -EINVAL;
+
+ /* Check if there's room for more reserved memory */
+ if (reserved_mem_count >= RESERVE_MEM_MAX_ENTRIES)
+ return -EBUSY;
+
+ oldp = p;
+ size = memparse(p, &p);
+ if (!size || p == oldp)
+ return -EINVAL;
+
+ if (*p != ':')
+ return -EINVAL;
+
+ align = memparse(p+1, &p);
+ if (*p != ':')
+ return -EINVAL;
+
+ /*
+ * memblock_phys_alloc() doesn't like a zero size align,
+ * but it is OK for this command to have it.
+ */
+ if (align < SMP_CACHE_BYTES)
+ align = SMP_CACHE_BYTES;
+
+ name = p + 1;
+ len = strlen(name);
+
+ /* name needs to have length but not too big */
+ if (!len || len >= RESERVE_MEM_NAME_SIZE)
+ return -EINVAL;
+
+ /* Make sure that name has text */
+ for (p = name; *p; p++) {
+ if (!isspace(*p))
+ break;
+ }
+ if (!*p)
+ return -EINVAL;
+
+ /* Make sure the name is not already used */
+ if (reserve_mem_find_by_name(name, &start, &tmp))
+ return -EBUSY;
+
+ start = memblock_phys_alloc(size, align);
+ if (!start)
+ return -ENOMEM;
+
+ reserved_mem_add(start, size, name);
+
+ return 1;
+}
+__setup("reserve_mem=", reserve_mem);
+
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_ARCH_KEEP_MEMBLOCK)
static const char * const flagname[] = {
[ilog2(MEMBLOCK_HOTPLUG)] = "HOTPLUG",