mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
msm: 8974: Add function to reserve memory from device tree
Memory reservations for memory pools or using memblock remove must happen early at bootup. Add a function at early boot to walk the flattened device tree and extract memory reservation information from appropriate bindings in device tree. To ensure that the memory is only reserved when a driver is enabled, drivers must put EXPORT_COMPAT(<compat string>) in the driver as well as adding the binding to the device tree. More documentation is available in Documentation/devicetree/bindings/arm/msm/memory-reserve.txt Change-Id: I28fa71d7a30cea9af5447acb5d2dde562fa0f6de Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
This commit is contained in:
parent
7fdf9a4be3
commit
56dec94b0a
6 changed files with 143 additions and 0 deletions
|
@ -185,6 +185,7 @@ SECTIONS
|
|||
INIT_SETUP(16)
|
||||
INIT_CALLS
|
||||
CON_INITCALL
|
||||
COMPAT_EXPORTS
|
||||
SECURITY_INITCALL
|
||||
INIT_RAM_FS
|
||||
}
|
||||
|
|
|
@ -383,6 +383,7 @@ static struct reserve_info msm_8974_reserve_info __initdata = {
|
|||
static void __init msm_8974_early_memory(void)
|
||||
{
|
||||
reserve_info = &msm_8974_reserve_info;
|
||||
of_scan_flat_dt(dt_scan_for_memory_reserve, msm_8974_reserve_table);
|
||||
}
|
||||
|
||||
void __init msm_8974_reserve(void)
|
||||
|
|
|
@ -118,6 +118,23 @@ void find_membank0_hole(void);
|
|||
(virt) - MEMBANK0_PAGE_OFFSET + MEMBANK0_PHYS_OFFSET)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Need a temporary unique variable that no one will ever see to
|
||||
* hold the compat string. Line number gives this easily.
|
||||
* Need another layer of indirection to get __LINE__ to expand
|
||||
* properly as opposed to appending and ending up with
|
||||
* __compat___LINE__
|
||||
*/
|
||||
#define __CONCAT(a, b) ___CONCAT(a, b)
|
||||
#define ___CONCAT(a, b) a ## b
|
||||
|
||||
#define EXPORT_COMPAT(com) \
|
||||
static char *__CONCAT(__compat_, __LINE__) __used \
|
||||
__attribute((__section__(".exportcompat.init"))) = com
|
||||
|
||||
extern char *__compat_exports_start[];
|
||||
extern char *__compat_exports_end[];
|
||||
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_ARCH_MSM_SCORPION || defined CONFIG_ARCH_MSM_KRAIT
|
||||
|
@ -135,4 +152,5 @@ void find_membank0_hole(void);
|
|||
|
||||
#ifndef CONFIG_ARCH_MSM7X27
|
||||
#define CONSISTENT_DMA_SIZE (SZ_1M * 14)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -66,5 +66,8 @@ struct reserve_info {
|
|||
|
||||
extern struct reserve_info *reserve_info;
|
||||
|
||||
int __init dt_scan_for_memory_reserve(unsigned long node, const char *uname,
|
||||
int depth, void *data);
|
||||
|
||||
unsigned long __init reserve_memory_for_fmem(unsigned long, unsigned long);
|
||||
#endif
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <mach/msm_iomap.h>
|
||||
#include <mach/socinfo.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/of_fdt.h>
|
||||
|
||||
/* fixme */
|
||||
#include <asm/tlbflush.h>
|
||||
|
@ -381,3 +382,117 @@ int release_fmem_c_region(void *unused)
|
|||
{
|
||||
return fmem_set_state(FMEM_T_STATE);
|
||||
}
|
||||
|
||||
static char * const memtype_names[] = {
|
||||
[MEMTYPE_SMI_KERNEL] = "SMI_KERNEL",
|
||||
[MEMTYPE_SMI] = "SMI",
|
||||
[MEMTYPE_EBI0] = "EBI0",
|
||||
[MEMTYPE_EBI1] = "EBI1",
|
||||
};
|
||||
|
||||
static int reserve_memory_type(char *mem_name,
|
||||
struct memtype_reserve *reserve_table,
|
||||
int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(memtype_names); i++) {
|
||||
if (memtype_names[i] && strcmp(mem_name,
|
||||
memtype_names[i]) == 0) {
|
||||
reserve_table[i].size += size;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pr_err("Could not find memory type %s\n", mem_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int check_for_compat(unsigned long node)
|
||||
{
|
||||
char **start = __compat_exports_start;
|
||||
|
||||
for ( ; start < __compat_exports_end; start++)
|
||||
if (of_flat_dt_is_compatible(node, *start))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init dt_scan_for_memory_reserve(unsigned long node, const char *uname,
|
||||
int depth, void *data)
|
||||
{
|
||||
char *memory_name_prop;
|
||||
unsigned int *memory_remove_prop;
|
||||
unsigned long memory_name_prop_length;
|
||||
unsigned long memory_remove_prop_length;
|
||||
unsigned long memory_size_prop_length;
|
||||
unsigned int *memory_size_prop;
|
||||
unsigned int memory_size;
|
||||
unsigned int memory_start;
|
||||
int ret;
|
||||
|
||||
memory_name_prop = of_get_flat_dt_prop(node,
|
||||
"qcom,memory-reservation-type",
|
||||
&memory_name_prop_length);
|
||||
memory_remove_prop = of_get_flat_dt_prop(node,
|
||||
"qcom,memblock-remove",
|
||||
&memory_remove_prop_length);
|
||||
|
||||
if (memory_name_prop || memory_remove_prop) {
|
||||
if (!check_for_compat(node))
|
||||
goto out;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memory_name_prop) {
|
||||
if (strnlen(memory_name_prop, memory_name_prop_length) == 0) {
|
||||
WARN(1, "Memory name was malformed\n");
|
||||
goto mem_remove;
|
||||
}
|
||||
|
||||
memory_size_prop = of_get_flat_dt_prop(node,
|
||||
"qcom,memory-reservation-size",
|
||||
&memory_size_prop_length);
|
||||
|
||||
if (memory_size_prop &&
|
||||
(memory_size_prop_length == sizeof(unsigned int))) {
|
||||
memory_size = be32_to_cpu(*memory_size_prop);
|
||||
|
||||
if (reserve_memory_type(memory_name_prop,
|
||||
data, memory_size) == 0)
|
||||
pr_info("%s reserved %s size %x\n",
|
||||
uname, memory_name_prop, memory_size);
|
||||
else
|
||||
WARN(1, "Node %s reserve failed\n",
|
||||
uname);
|
||||
} else {
|
||||
WARN(1, "Node %s specified bad/nonexistent size\n",
|
||||
uname);
|
||||
}
|
||||
}
|
||||
|
||||
mem_remove:
|
||||
|
||||
if (memory_remove_prop) {
|
||||
if (memory_remove_prop_length != (2*sizeof(unsigned int))) {
|
||||
WARN(1, "Memory remove malformed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
memory_start = be32_to_cpu(memory_remove_prop[0]);
|
||||
memory_size = be32_to_cpu(memory_remove_prop[1]);
|
||||
|
||||
ret = memblock_remove(memory_start, memory_size);
|
||||
if (ret)
|
||||
WARN(1, "Failed to remove memory %x-%x\n",
|
||||
memory_start, memory_start+memory_size);
|
||||
else
|
||||
pr_info("Node %s removed memory %x-%x\n", uname,
|
||||
memory_start, memory_start+memory_size);
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -645,6 +645,11 @@
|
|||
*(.security_initcall.init) \
|
||||
VMLINUX_SYMBOL(__security_initcall_end) = .;
|
||||
|
||||
#define COMPAT_EXPORTS \
|
||||
VMLINUX_SYMBOL(__compat_exports_start) = .; \
|
||||
*(.exportcompat.init) \
|
||||
VMLINUX_SYMBOL(__compat_exports_end) = .;
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
#define INIT_RAM_FS \
|
||||
. = ALIGN(4); \
|
||||
|
|
Loading…
Reference in a new issue