|
@@ -422,6 +422,34 @@ static void __init reserve_setup_data(void)
|
|
|
*/
|
|
|
|
|
|
#ifdef CONFIG_KEXEC
|
|
|
+
|
|
|
+/**
|
|
|
+ * Reserve @size bytes of crashkernel memory at any suitable offset.
|
|
|
+ *
|
|
|
+ * @size: Size of the crashkernel memory to reserve.
|
|
|
+ * Returns the base address on success, and -1ULL on failure.
|
|
|
+ */
|
|
|
+unsigned long long find_and_reserve_crashkernel(unsigned long long size)
|
|
|
+{
|
|
|
+ const unsigned long long alignment = 16<<20; /* 16M */
|
|
|
+ unsigned long long start = 0LL;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ start = find_e820_area(start, ULONG_MAX, size, alignment);
|
|
|
+ if (start == -1ULL)
|
|
|
+ return start;
|
|
|
+
|
|
|
+ /* try to reserve it */
|
|
|
+ ret = reserve_bootmem_generic(start, size, BOOTMEM_EXCLUSIVE);
|
|
|
+ if (ret >= 0)
|
|
|
+ return start;
|
|
|
+
|
|
|
+ start += alignment;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static inline unsigned long long get_total_mem(void)
|
|
|
{
|
|
|
unsigned long long total;
|
|
@@ -444,30 +472,36 @@ static void __init reserve_crashkernel(void)
|
|
|
|
|
|
ret = parse_crashkernel(boot_command_line, total_mem,
|
|
|
&crash_size, &crash_base);
|
|
|
- if (ret == 0 && crash_size > 0) {
|
|
|
- if (crash_base <= 0) {
|
|
|
- printk(KERN_INFO "crashkernel reservation failed - "
|
|
|
- "you have to specify a base address\n");
|
|
|
+ if (ret != 0 || crash_size <= 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* 0 means: find the address automatically */
|
|
|
+ if (crash_base <= 0) {
|
|
|
+ crash_base = find_and_reserve_crashkernel(crash_size);
|
|
|
+ if (crash_base == -1ULL) {
|
|
|
+ pr_info("crashkernel reservation failed. "
|
|
|
+ "No suitable area found.\n");
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
- if (reserve_bootmem_generic(crash_base, crash_size,
|
|
|
- BOOTMEM_EXCLUSIVE) < 0) {
|
|
|
- printk(KERN_INFO "crashkernel reservation failed - "
|
|
|
- "memory is in use\n");
|
|
|
+ } else {
|
|
|
+ ret = reserve_bootmem_generic(crash_base, crash_size,
|
|
|
+ BOOTMEM_EXCLUSIVE);
|
|
|
+ if (ret < 0) {
|
|
|
+ pr_info("crashkernel reservation failed - "
|
|
|
+ "memory is in use\n");
|
|
|
return;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
|
|
|
- "for crashkernel (System RAM: %ldMB)\n",
|
|
|
- (unsigned long)(crash_size >> 20),
|
|
|
- (unsigned long)(crash_base >> 20),
|
|
|
- (unsigned long)(total_mem >> 20));
|
|
|
+ printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
|
|
|
+ "for crashkernel (System RAM: %ldMB)\n",
|
|
|
+ (unsigned long)(crash_size >> 20),
|
|
|
+ (unsigned long)(crash_base >> 20),
|
|
|
+ (unsigned long)(total_mem >> 20));
|
|
|
|
|
|
- crashk_res.start = crash_base;
|
|
|
- crashk_res.end = crash_base + crash_size - 1;
|
|
|
- insert_resource(&iomem_resource, &crashk_res);
|
|
|
- }
|
|
|
+ crashk_res.start = crash_base;
|
|
|
+ crashk_res.end = crash_base + crash_size - 1;
|
|
|
+ insert_resource(&iomem_resource, &crashk_res);
|
|
|
}
|
|
|
#else
|
|
|
static void __init reserve_crashkernel(void)
|