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

Commit 6ac26c8a authored by Manish Ahuja's avatar Manish Ahuja Committed by Paul Mackerras
Browse files

[POWERPC] pseries: phyp dump: Reserve and release memory



Initial patch for reserving memory in early boot, and freeing it
later.  If the previous boot had ended with a crash, the reserved
memory would contain a copy of the crashed kernel data.

Signed-off-by: default avatarManish Ahuja <mahuja@us.ibm.com>
Signed-off-by: default avatarLinas Vepstas <linasvepstas@gmail.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent d28a7932
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>
#include <asm/pci-bridge.h>
#include <asm/phyp_dump.h>
#include <asm/kexec.h>

#ifdef DEBUG
@@ -1040,6 +1041,51 @@ static void __init early_reserve_mem(void)
#endif
}

#ifdef CONFIG_PHYP_DUMP
/**
 * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory
 *
 * This routine may reserve memory regions in the kernel only
 * if the system is supported and a dump was taken in last
 * boot instance or if the hardware is supported and the
 * scratch area needs to be setup. In other instances it returns
 * without reserving anything. The memory in case of dump being
 * active is freed when the dump is collected (by userland tools).
 */
static void __init phyp_dump_reserve_mem(void)
{
	unsigned long base, size;
	if (!phyp_dump_info->phyp_dump_configured) {
		printk(KERN_ERR "Phyp-dump not supported on this hardware\n");
		return;
	}

	if (phyp_dump_info->phyp_dump_is_active) {
		/* Reserve *everything* above RMR.Area freed by userland tools*/
		base = PHYP_DUMP_RMR_END;
		size = lmb_end_of_DRAM() - base;

		/* XXX crashed_ram_end is wrong, since it may be beyond
		 * the memory_limit, it will need to be adjusted. */
		lmb_reserve(base, size);

		phyp_dump_info->init_reserve_start = base;
		phyp_dump_info->init_reserve_size = size;
	} else {
		size = phyp_dump_info->cpu_state_size +
			phyp_dump_info->hpte_region_size +
			PHYP_DUMP_RMR_END;
		base = lmb_end_of_DRAM() - size;
		lmb_reserve(base, size);
		phyp_dump_info->init_reserve_start = base;
		phyp_dump_info->init_reserve_size = size;
	}
}
#else
static inline void __init phyp_dump_reserve_mem(void) {}
#endif /* CONFIG_PHYP_DUMP  && CONFIG_PPC_RTAS */


void __init early_init_devtree(void *params)
{
	DBG(" -> early_init_devtree(%p)\n", params);
@@ -1052,6 +1098,11 @@ void __init early_init_devtree(void *params)
	of_scan_flat_dt(early_init_dt_scan_rtas, NULL);
#endif

#ifdef CONFIG_PHYP_DUMP
	/* scan tree to see if dump occured during last boot */
	of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL);
#endif

	/* Retrieve various informations from the /chosen node of the
	 * device-tree, including the platform type, initrd location and
	 * size, TCE reserve, and more ...
@@ -1072,6 +1123,7 @@ void __init early_init_devtree(void *params)
	reserve_kdump_trampoline();
	reserve_crashkernel();
	early_reserve_mem();
	phyp_dump_reserve_mem();

	lmb_enforce_memory_limit(memory_limit);
	lmb_analyze();
+1 −0
Original line number Diff line number Diff line
@@ -18,3 +18,4 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o
obj-$(CONFIG_HVC_CONSOLE)	+= hvconsole.o
obj-$(CONFIG_HVCS)		+= hvcserver.o
obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o
obj-$(CONFIG_PHYP_DUMP)	+= phyp_dump.o
+103 −0
Original line number Diff line number Diff line
/*
 * Hypervisor-assisted dump
 *
 * Linas Vepstas, Manish Ahuja 2008
 * Copyright 2008 IBM Corp.
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 *
 */

#include <linux/init.h>
#include <linux/mm.h>
#include <linux/pfn.h>
#include <linux/swap.h>

#include <asm/page.h>
#include <asm/phyp_dump.h>
#include <asm/machdep.h>
#include <asm/prom.h>

/* Variables, used to communicate data between early boot and late boot */
static struct phyp_dump phyp_dump_vars;
struct phyp_dump *phyp_dump_info = &phyp_dump_vars;

/**
 * release_memory_range -- release memory previously lmb_reserved
 * @start_pfn: starting physical frame number
 * @nr_pages: number of pages to free.
 *
 * This routine will release memory that had been previously
 * lmb_reserved in early boot. The released memory becomes
 * available for genreal use.
 */
static void
release_memory_range(unsigned long start_pfn, unsigned long nr_pages)
{
	struct page *rpage;
	unsigned long end_pfn;
	long i;

	end_pfn = start_pfn + nr_pages;

	for (i = start_pfn; i <= end_pfn; i++) {
		rpage = pfn_to_page(i);
		if (PageReserved(rpage)) {
			ClearPageReserved(rpage);
			init_page_count(rpage);
			__free_page(rpage);
			totalram_pages++;
		}
	}
}

static int __init phyp_dump_setup(void)
{
	unsigned long start_pfn, nr_pages;

	/* If no memory was reserved in early boot, there is nothing to do */
	if (phyp_dump_info->init_reserve_size == 0)
		return 0;

	/* Release memory that was reserved in early boot */
	start_pfn = PFN_DOWN(phyp_dump_info->init_reserve_start);
	nr_pages = PFN_DOWN(phyp_dump_info->init_reserve_size);
	release_memory_range(start_pfn, nr_pages);

	return 0;
}
machine_subsys_initcall(pseries, phyp_dump_setup);

int __init early_init_dt_scan_phyp_dump(unsigned long node,
		const char *uname, int depth, void *data)
{
	const unsigned int *sizes;

	phyp_dump_info->phyp_dump_configured = 0;
	phyp_dump_info->phyp_dump_is_active = 0;

	if (depth != 1 || strcmp(uname, "rtas") != 0)
		return 0;

	if (of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL))
		phyp_dump_info->phyp_dump_configured++;

	if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL))
		phyp_dump_info->phyp_dump_is_active++;

	sizes = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
				    NULL);
	if (!sizes)
		return 0;

	if (sizes[0] == 1)
		phyp_dump_info->cpu_state_size = *((unsigned long *)&sizes[1]);

	if (sizes[3] == 2)
		phyp_dump_info->hpte_region_size =
						*((unsigned long *)&sizes[4]);
	return 1;
}
+41 −0
Original line number Diff line number Diff line
/*
 * Hypervisor-assisted dump
 *
 * Linas Vepstas, Manish Ahuja 2008
 * Copyright 2008 IBM Corp.
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */

#ifndef _PPC64_PHYP_DUMP_H
#define _PPC64_PHYP_DUMP_H

#ifdef CONFIG_PHYP_DUMP

/* The RMR region will be saved for later dumping
 * whenever the kernel crashes. Set this to 256MB. */
#define PHYP_DUMP_RMR_START 0x0
#define PHYP_DUMP_RMR_END   (1UL<<28)

struct phyp_dump {
	/* Memory that is reserved during very early boot. */
	unsigned long init_reserve_start;
	unsigned long init_reserve_size;
	/* Check status during boot if dump supported, active & present*/
	unsigned long phyp_dump_configured;
	unsigned long phyp_dump_is_active;
	/* store cpu & hpte size */
	unsigned long cpu_state_size;
	unsigned long hpte_region_size;
};

extern struct phyp_dump *phyp_dump_info;

int early_init_dt_scan_phyp_dump(unsigned long node,
		const char *uname, int depth, void *data);

#endif /* CONFIG_PHYP_DUMP */
#endif /* _PPC64_PHYP_DUMP_H */