Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1130d4c2 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mm: memblock: dynamically calculate memory hotplug range"

parents 9fa33a9d 9e246344
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/mutex.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/memblock.h>

#include <linux/atomic.h>
#include <linux/uaccess.h>
@@ -494,6 +495,18 @@ static ssize_t show_allocated_bytes(struct device *dev,

	return snprintf(buf, 100, "%lu\n", used);
}

static ssize_t show_aligned_blocks_addr(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return memblock_dump_aligned_blocks_addr(buf);
}

static ssize_t show_aligned_blocks_num(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	return memblock_dump_aligned_blocks_num(buf);
}
#endif

static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL);
@@ -502,6 +515,8 @@ static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL);
static DEVICE_ATTR(removable, 0444, show_mem_removable, NULL);
#ifdef CONFIG_MEMORY_HOTPLUG
static DEVICE_ATTR(allocated_bytes, 0444, show_allocated_bytes, NULL);
static DEVICE_ATTR(aligned_blocks_addr, 0444, show_aligned_blocks_addr, NULL);
static DEVICE_ATTR(aligned_blocks_num, 0444, show_aligned_blocks_num, NULL);
#endif

/*
@@ -886,6 +901,10 @@ static struct attribute *memory_root_attrs[] = {

	&dev_attr_block_size_bytes.attr,
	&dev_attr_auto_online_blocks.attr,
#ifdef CONFIG_MEMORY_HOTPLUG
	&dev_attr_aligned_blocks_addr.attr,
	&dev_attr_aligned_blocks_num.attr,
#endif
	NULL
};

+4 −0
Original line number Diff line number Diff line
@@ -89,6 +89,10 @@ int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
int memblock_clear_nomap(phys_addr_t base, phys_addr_t size);
#ifdef CONFIG_MEMORY_HOTPLUG
int memblock_dump_aligned_blocks_addr(char *buf);
int memblock_dump_aligned_blocks_num(char *buf);
#endif
ulong choose_memblock_flags(void);

/* Low level functions */
+111 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/memblock.h>
#include <linux/memory.h>

#include <asm/sections.h>
#include <linux/io.h>
@@ -1777,6 +1778,116 @@ static int __init early_memblock(char *p)
}
early_param("memblock", early_memblock);

#ifdef CONFIG_MEMORY_HOTPLUG
static phys_addr_t no_hotplug_area[8];
static phys_addr_t aligned_blocks[32];

static int __init early_no_hotplug_area(char *p)
{
	phys_addr_t base, size;
	int idx = 0;
	char *endp = p;

	while (1) {
		base = memparse(endp, &endp);
		if (base && (*endp == ',')) {
			size = memparse(endp + 1, &endp);
			if (size) {
				no_hotplug_area[idx++] = base;
				no_hotplug_area[idx++] = base+size;

				if ((*endp == ';') && (idx <= 6))
					endp++;
				else
					break;
			} else
				break;
		} else
			break;
	}
	return 0;
}
early_param("no_hotplug_area", early_no_hotplug_area);

static bool __init memblock_in_no_hotplug_area(phys_addr_t addr)
{
	int idx = 0;

	while (idx < 8) {
		if (!no_hotplug_area[idx])
			break;

		if ((addr + MIN_MEMORY_BLOCK_SIZE <= no_hotplug_area[idx])
			|| (addr >= no_hotplug_area[idx+1])) {
			idx += 2;
			continue;
		}

		return true;
	}
	return false;
}

static int __init early_dyn_memhotplug(char *p)
{
	int idx = 0;
	phys_addr_t addr, rgn_end;
	struct memblock_region *rgn;
	int blk = 0;

	while ((idx++) < memblock.memory.cnt) {
		rgn = &memblock.memory.regions[idx];
		addr = ALIGN(rgn->base, MIN_MEMORY_BLOCK_SIZE);
		rgn_end = rgn->base + rgn->size;
		while (addr + MIN_MEMORY_BLOCK_SIZE <= rgn_end) {
			if (!memblock_in_no_hotplug_area(addr)) {
				aligned_blocks[blk++] = addr;
				memblock_remove(addr, MIN_MEMORY_BLOCK_SIZE);
			}
			addr += MIN_MEMORY_BLOCK_SIZE;
		}
	}
	return 0;
}
early_param("dyn_memhotplug", early_dyn_memhotplug);

int memblock_dump_aligned_blocks_addr(char *buf)
{
	int idx = 0;
	int size = 0;

	if (aligned_blocks[idx]) {
		size += snprintf(buf+size, 32, "0x%llx", aligned_blocks[idx]);
		idx++;
	}

	while (aligned_blocks[idx]) {
		size += snprintf(buf+size, 32, ",0x%llx", aligned_blocks[idx]);
		idx++;
	}
	return size;
}

int memblock_dump_aligned_blocks_num(char *buf)
{
	int idx = 0;
	int size = 0;

	if (aligned_blocks[idx]) {
		size += snprintf(buf+size, 16, "%d",
			(int)(aligned_blocks[idx] >> SECTION_SIZE_BITS));
		idx++;
	}

	while (aligned_blocks[idx]) {
		size += snprintf(buf+size, 16, ",%d",
			(int)(aligned_blocks[idx] >> SECTION_SIZE_BITS));
		idx++;
	}
	return size;
}
#endif

#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_ARCH_DISCARD_MEMBLOCK)

static int memblock_debug_show(struct seq_file *m, void *private)