MIPS: Octeon: Add kexec and kdump support
[ralf@linux-mips.org: Original patch by Maxim Uvarov <muvarov@gmail.com> with plenty of further shining, polishing, debugging and testing by me.] Signed-off-by: Maxim Uvarov <muvarov@gmail.com> Cc: linux-mips@linux-mips.org Cc: kexec@lists.infradead.org Cc: horms@verge.net.au Patchwork: https://patchwork.linux-mips.org/patch/1026/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Родитель
7aa1c8f47e
Коммит
abe77f90dc
|
@ -192,6 +192,10 @@ endif
|
||||||
#
|
#
|
||||||
include $(srctree)/arch/mips/Kbuild.platforms
|
include $(srctree)/arch/mips/Kbuild.platforms
|
||||||
|
|
||||||
|
ifdef CONFIG_PHYSICAL_START
|
||||||
|
load-y = $(CONFIG_PHYSICAL_START)
|
||||||
|
endif
|
||||||
|
|
||||||
cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
|
cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
|
||||||
drivers-$(CONFIG_PCI) += arch/mips/pci/
|
drivers-$(CONFIG_PCI) += arch/mips/pci/
|
||||||
|
|
||||||
|
|
|
@ -688,3 +688,8 @@ int64_t cvmx_bootmem_phy_named_block_alloc(uint64_t size, uint64_t min_addr,
|
||||||
cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock));
|
cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock));
|
||||||
return addr_allocated;
|
return addr_allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cvmx_bootmem_desc *cvmx_bootmem_get_desc(void)
|
||||||
|
{
|
||||||
|
return cvmx_bootmem_desc;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <linux/serial_8250.h>
|
#include <linux/serial_8250.h>
|
||||||
#include <linux/of_fdt.h>
|
#include <linux/of_fdt.h>
|
||||||
#include <linux/libfdt.h>
|
#include <linux/libfdt.h>
|
||||||
|
#include <linux/kexec.h>
|
||||||
|
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/reboot.h>
|
#include <asm/reboot.h>
|
||||||
|
@ -58,11 +59,208 @@ struct octeon_boot_descriptor *octeon_boot_desc_ptr;
|
||||||
struct cvmx_bootinfo *octeon_bootinfo;
|
struct cvmx_bootinfo *octeon_bootinfo;
|
||||||
EXPORT_SYMBOL(octeon_bootinfo);
|
EXPORT_SYMBOL(octeon_bootinfo);
|
||||||
|
|
||||||
|
static unsigned long long RESERVE_LOW_MEM = 0ull;
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/*
|
||||||
|
* Wait for relocation code is prepared and send
|
||||||
|
* secondary CPUs to spin until kernel is relocated.
|
||||||
|
*/
|
||||||
|
static void octeon_kexec_smp_down(void *ignored)
|
||||||
|
{
|
||||||
|
int cpu = smp_processor_id();
|
||||||
|
|
||||||
|
local_irq_disable();
|
||||||
|
set_cpu_online(cpu, false);
|
||||||
|
while (!atomic_read(&kexec_ready_to_reboot))
|
||||||
|
cpu_relax();
|
||||||
|
|
||||||
|
asm volatile (
|
||||||
|
" sync \n"
|
||||||
|
" synci ($0) \n");
|
||||||
|
|
||||||
|
relocated_kexec_smp_wait(NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OCTEON_DDR0_BASE (0x0ULL)
|
||||||
|
#define OCTEON_DDR0_SIZE (0x010000000ULL)
|
||||||
|
#define OCTEON_DDR1_BASE (0x410000000ULL)
|
||||||
|
#define OCTEON_DDR1_SIZE (0x010000000ULL)
|
||||||
|
#define OCTEON_DDR2_BASE (0x020000000ULL)
|
||||||
|
#define OCTEON_DDR2_SIZE (0x3e0000000ULL)
|
||||||
|
#define OCTEON_MAX_PHY_MEM_SIZE (16*1024*1024*1024ULL)
|
||||||
|
|
||||||
|
static struct kimage *kimage_ptr;
|
||||||
|
|
||||||
|
static void kexec_bootmem_init(uint64_t mem_size, uint32_t low_reserved_bytes)
|
||||||
|
{
|
||||||
|
int64_t addr;
|
||||||
|
struct cvmx_bootmem_desc *bootmem_desc;
|
||||||
|
|
||||||
|
bootmem_desc = cvmx_bootmem_get_desc();
|
||||||
|
|
||||||
|
if (mem_size > OCTEON_MAX_PHY_MEM_SIZE) {
|
||||||
|
mem_size = OCTEON_MAX_PHY_MEM_SIZE;
|
||||||
|
pr_err("Error: requested memory too large,"
|
||||||
|
"truncating to maximum size\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bootmem_desc->major_version = CVMX_BOOTMEM_DESC_MAJ_VER;
|
||||||
|
bootmem_desc->minor_version = CVMX_BOOTMEM_DESC_MIN_VER;
|
||||||
|
|
||||||
|
addr = (OCTEON_DDR0_BASE + RESERVE_LOW_MEM + low_reserved_bytes);
|
||||||
|
bootmem_desc->head_addr = 0;
|
||||||
|
|
||||||
|
if (mem_size <= OCTEON_DDR0_SIZE) {
|
||||||
|
__cvmx_bootmem_phy_free(addr,
|
||||||
|
mem_size - RESERVE_LOW_MEM -
|
||||||
|
low_reserved_bytes, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__cvmx_bootmem_phy_free(addr,
|
||||||
|
OCTEON_DDR0_SIZE - RESERVE_LOW_MEM -
|
||||||
|
low_reserved_bytes, 0);
|
||||||
|
|
||||||
|
mem_size -= OCTEON_DDR0_SIZE;
|
||||||
|
|
||||||
|
if (mem_size > OCTEON_DDR1_SIZE) {
|
||||||
|
__cvmx_bootmem_phy_free(OCTEON_DDR1_BASE, OCTEON_DDR1_SIZE, 0);
|
||||||
|
__cvmx_bootmem_phy_free(OCTEON_DDR2_BASE,
|
||||||
|
mem_size - OCTEON_DDR1_SIZE, 0);
|
||||||
|
} else
|
||||||
|
__cvmx_bootmem_phy_free(OCTEON_DDR1_BASE, mem_size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int octeon_kexec_prepare(struct kimage *image)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *bootloader = "kexec";
|
||||||
|
|
||||||
|
octeon_boot_desc_ptr->argc = 0;
|
||||||
|
for (i = 0; i < image->nr_segments; i++) {
|
||||||
|
if (!strncmp(bootloader, (char *)image->segment[i].buf,
|
||||||
|
strlen(bootloader))) {
|
||||||
|
/*
|
||||||
|
* convert command line string to array
|
||||||
|
* of parameters (as bootloader does).
|
||||||
|
*/
|
||||||
|
int argc = 0, offt;
|
||||||
|
char *str = (char *)image->segment[i].buf;
|
||||||
|
char *ptr = strchr(str, ' ');
|
||||||
|
while (ptr && (OCTEON_ARGV_MAX_ARGS > argc)) {
|
||||||
|
*ptr = '\0';
|
||||||
|
if (ptr[1] != ' ') {
|
||||||
|
offt = (int)(ptr - str + 1);
|
||||||
|
octeon_boot_desc_ptr->argv[argc] =
|
||||||
|
image->segment[i].mem + offt;
|
||||||
|
argc++;
|
||||||
|
}
|
||||||
|
ptr = strchr(ptr + 1, ' ');
|
||||||
|
}
|
||||||
|
octeon_boot_desc_ptr->argc = argc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Information about segments will be needed during pre-boot memory
|
||||||
|
* initialization.
|
||||||
|
*/
|
||||||
|
kimage_ptr = image;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void octeon_generic_shutdown(void)
|
||||||
|
{
|
||||||
|
int cpu, i;
|
||||||
|
struct cvmx_bootmem_desc *bootmem_desc;
|
||||||
|
void *named_block_array_ptr;
|
||||||
|
|
||||||
|
bootmem_desc = cvmx_bootmem_get_desc();
|
||||||
|
named_block_array_ptr =
|
||||||
|
cvmx_phys_to_ptr(bootmem_desc->named_block_array_addr);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* disable watchdogs */
|
||||||
|
for_each_online_cpu(cpu)
|
||||||
|
cvmx_write_csr(CVMX_CIU_WDOGX(cpu_logical_map(cpu)), 0);
|
||||||
|
#else
|
||||||
|
cvmx_write_csr(CVMX_CIU_WDOGX(cvmx_get_core_num()), 0);
|
||||||
|
#endif
|
||||||
|
if (kimage_ptr != kexec_crash_image) {
|
||||||
|
memset(named_block_array_ptr,
|
||||||
|
0x0,
|
||||||
|
CVMX_BOOTMEM_NUM_NAMED_BLOCKS *
|
||||||
|
sizeof(struct cvmx_bootmem_named_block_desc));
|
||||||
|
/*
|
||||||
|
* Mark all memory (except low 0x100000 bytes) as free.
|
||||||
|
* It is the same thing that bootloader does.
|
||||||
|
*/
|
||||||
|
kexec_bootmem_init(octeon_bootinfo->dram_size*1024ULL*1024ULL,
|
||||||
|
0x100000);
|
||||||
|
/*
|
||||||
|
* Allocate all segments to avoid their corruption during boot.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < kimage_ptr->nr_segments; i++)
|
||||||
|
cvmx_bootmem_alloc_address(
|
||||||
|
kimage_ptr->segment[i].memsz + 2*PAGE_SIZE,
|
||||||
|
kimage_ptr->segment[i].mem - PAGE_SIZE,
|
||||||
|
PAGE_SIZE);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Do not mark all memory as free. Free only named sections
|
||||||
|
* leaving the rest of memory unchanged.
|
||||||
|
*/
|
||||||
|
struct cvmx_bootmem_named_block_desc *ptr =
|
||||||
|
(struct cvmx_bootmem_named_block_desc *)
|
||||||
|
named_block_array_ptr;
|
||||||
|
|
||||||
|
for (i = 0; i < bootmem_desc->named_block_num_blocks; i++)
|
||||||
|
if (ptr[i].size)
|
||||||
|
cvmx_bootmem_free_named(ptr[i].name);
|
||||||
|
}
|
||||||
|
kexec_args[2] = 1UL; /* running on octeon_main_processor */
|
||||||
|
kexec_args[3] = (unsigned long)octeon_boot_desc_ptr;
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
secondary_kexec_args[2] = 0UL; /* running on secondary cpu */
|
||||||
|
secondary_kexec_args[3] = (unsigned long)octeon_boot_desc_ptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void octeon_shutdown(void)
|
||||||
|
{
|
||||||
|
octeon_generic_shutdown();
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
smp_call_function(octeon_kexec_smp_down, NULL, 0);
|
||||||
|
smp_wmb();
|
||||||
|
while (num_online_cpus() > 1) {
|
||||||
|
cpu_relax();
|
||||||
|
mdelay(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void octeon_crash_shutdown(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
octeon_generic_shutdown();
|
||||||
|
default_machine_crash_shutdown(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_KEXEC */
|
||||||
|
|
||||||
#ifdef CONFIG_CAVIUM_RESERVE32
|
#ifdef CONFIG_CAVIUM_RESERVE32
|
||||||
uint64_t octeon_reserve32_memory;
|
uint64_t octeon_reserve32_memory;
|
||||||
EXPORT_SYMBOL(octeon_reserve32_memory);
|
EXPORT_SYMBOL(octeon_reserve32_memory);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
/* crashkernel cmdline parameter is parsed _after_ memory setup
|
||||||
|
* we also parse it here (workaround for EHB5200) */
|
||||||
|
static uint64_t crashk_size, crashk_base;
|
||||||
|
#endif
|
||||||
|
|
||||||
static int octeon_uart;
|
static int octeon_uart;
|
||||||
|
|
||||||
extern asmlinkage void handle_int(void);
|
extern asmlinkage void handle_int(void);
|
||||||
|
@ -417,6 +615,8 @@ void octeon_user_io_init(void)
|
||||||
void __init prom_init(void)
|
void __init prom_init(void)
|
||||||
{
|
{
|
||||||
struct cvmx_sysinfo *sysinfo;
|
struct cvmx_sysinfo *sysinfo;
|
||||||
|
const char *arg;
|
||||||
|
char *p;
|
||||||
int i;
|
int i;
|
||||||
int argc;
|
int argc;
|
||||||
#ifdef CONFIG_CAVIUM_RESERVE32
|
#ifdef CONFIG_CAVIUM_RESERVE32
|
||||||
|
@ -568,6 +768,15 @@ void __init prom_init(void)
|
||||||
if (octeon_is_simulation())
|
if (octeon_is_simulation())
|
||||||
MAX_MEMORY = 64ull << 20;
|
MAX_MEMORY = 64ull << 20;
|
||||||
|
|
||||||
|
arg = strstr(arcs_cmdline, "mem=");
|
||||||
|
if (arg) {
|
||||||
|
MAX_MEMORY = memparse(arg + 4, &p);
|
||||||
|
if (MAX_MEMORY == 0)
|
||||||
|
MAX_MEMORY = 32ull << 30;
|
||||||
|
if (*p == '@')
|
||||||
|
RESERVE_LOW_MEM = memparse(p + 1, &p);
|
||||||
|
}
|
||||||
|
|
||||||
arcs_cmdline[0] = 0;
|
arcs_cmdline[0] = 0;
|
||||||
argc = octeon_boot_desc_ptr->argc;
|
argc = octeon_boot_desc_ptr->argc;
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
|
@ -575,15 +784,29 @@ void __init prom_init(void)
|
||||||
cvmx_phys_to_ptr(octeon_boot_desc_ptr->argv[i]);
|
cvmx_phys_to_ptr(octeon_boot_desc_ptr->argv[i]);
|
||||||
if ((strncmp(arg, "MEM=", 4) == 0) ||
|
if ((strncmp(arg, "MEM=", 4) == 0) ||
|
||||||
(strncmp(arg, "mem=", 4) == 0)) {
|
(strncmp(arg, "mem=", 4) == 0)) {
|
||||||
sscanf(arg + 4, "%llu", &MAX_MEMORY);
|
MAX_MEMORY = memparse(arg + 4, &p);
|
||||||
MAX_MEMORY <<= 20;
|
|
||||||
if (MAX_MEMORY == 0)
|
if (MAX_MEMORY == 0)
|
||||||
MAX_MEMORY = 32ull << 30;
|
MAX_MEMORY = 32ull << 30;
|
||||||
|
if (*p == '@')
|
||||||
|
RESERVE_LOW_MEM = memparse(p + 1, &p);
|
||||||
} else if (strcmp(arg, "ecc_verbose") == 0) {
|
} else if (strcmp(arg, "ecc_verbose") == 0) {
|
||||||
#ifdef CONFIG_CAVIUM_REPORT_SINGLE_BIT_ECC
|
#ifdef CONFIG_CAVIUM_REPORT_SINGLE_BIT_ECC
|
||||||
__cvmx_interrupt_ecc_report_single_bit_errors = 1;
|
__cvmx_interrupt_ecc_report_single_bit_errors = 1;
|
||||||
pr_notice("Reporting of single bit ECC errors is "
|
pr_notice("Reporting of single bit ECC errors is "
|
||||||
"turned on\n");
|
"turned on\n");
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
} else if (strncmp(arg, "crashkernel=", 12) == 0) {
|
||||||
|
crashk_size = memparse(arg+12, &p);
|
||||||
|
if (*p == '@')
|
||||||
|
crashk_base = memparse(p+1, &p);
|
||||||
|
strcat(arcs_cmdline, " ");
|
||||||
|
strcat(arcs_cmdline, arg);
|
||||||
|
/*
|
||||||
|
* To do: switch parsing to new style, something like:
|
||||||
|
* parse_crashkernel(arg, sysinfo->system_dram_size,
|
||||||
|
* &crashk_size, &crashk_base);
|
||||||
|
*/
|
||||||
#endif
|
#endif
|
||||||
} else if (strlen(arcs_cmdline) + strlen(arg) + 1 <
|
} else if (strlen(arcs_cmdline) + strlen(arg) + 1 <
|
||||||
sizeof(arcs_cmdline) - 1) {
|
sizeof(arcs_cmdline) - 1) {
|
||||||
|
@ -619,11 +842,18 @@ void __init prom_init(void)
|
||||||
_machine_restart = octeon_restart;
|
_machine_restart = octeon_restart;
|
||||||
_machine_halt = octeon_halt;
|
_machine_halt = octeon_halt;
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
_machine_kexec_shutdown = octeon_shutdown;
|
||||||
|
_machine_crash_shutdown = octeon_crash_shutdown;
|
||||||
|
_machine_kexec_prepare = octeon_kexec_prepare;
|
||||||
|
#endif
|
||||||
|
|
||||||
octeon_user_io_init();
|
octeon_user_io_init();
|
||||||
register_smp_ops(&octeon_smp_ops);
|
register_smp_ops(&octeon_smp_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exclude a single page from the regions obtained in plat_mem_setup. */
|
/* Exclude a single page from the regions obtained in plat_mem_setup. */
|
||||||
|
#ifndef CONFIG_CRASH_DUMP
|
||||||
static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size)
|
static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size)
|
||||||
{
|
{
|
||||||
if (addr > *mem && addr < *mem + *size) {
|
if (addr > *mem && addr < *mem + *size) {
|
||||||
|
@ -638,14 +868,21 @@ static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size)
|
||||||
*size -= PAGE_SIZE;
|
*size -= PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_CRASH_DUMP */
|
||||||
|
|
||||||
void __init plat_mem_setup(void)
|
void __init plat_mem_setup(void)
|
||||||
{
|
{
|
||||||
uint64_t mem_alloc_size;
|
uint64_t mem_alloc_size;
|
||||||
uint64_t total;
|
uint64_t total;
|
||||||
|
uint64_t crashk_end;
|
||||||
|
#ifndef CONFIG_CRASH_DUMP
|
||||||
int64_t memory;
|
int64_t memory;
|
||||||
|
uint64_t kernel_start;
|
||||||
|
uint64_t kernel_size;
|
||||||
|
#endif
|
||||||
|
|
||||||
total = 0;
|
total = 0;
|
||||||
|
crashk_end = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The Mips memory init uses the first memory location for
|
* The Mips memory init uses the first memory location for
|
||||||
|
@ -658,6 +895,17 @@ void __init plat_mem_setup(void)
|
||||||
if (mem_alloc_size > MAX_MEMORY)
|
if (mem_alloc_size > MAX_MEMORY)
|
||||||
mem_alloc_size = MAX_MEMORY;
|
mem_alloc_size = MAX_MEMORY;
|
||||||
|
|
||||||
|
/* Crashkernel ignores bootmem list. It relies on mem=X@Y option */
|
||||||
|
#ifdef CONFIG_CRASH_DUMP
|
||||||
|
add_memory_region(RESERVE_LOW_MEM, MAX_MEMORY, BOOT_MEM_RAM);
|
||||||
|
total += MAX_MEMORY;
|
||||||
|
#else
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
if (crashk_size > 0) {
|
||||||
|
add_memory_region(crashk_base, crashk_size, BOOT_MEM_RAM);
|
||||||
|
crashk_end = crashk_base + crashk_size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* When allocating memory, we want incrementing addresses from
|
* When allocating memory, we want incrementing addresses from
|
||||||
* bootmem_alloc so the code in add_memory_region can merge
|
* bootmem_alloc so the code in add_memory_region can merge
|
||||||
|
@ -672,6 +920,9 @@ void __init plat_mem_setup(void)
|
||||||
CVMX_BOOTMEM_FLAG_NO_LOCKING);
|
CVMX_BOOTMEM_FLAG_NO_LOCKING);
|
||||||
if (memory >= 0) {
|
if (memory >= 0) {
|
||||||
u64 size = mem_alloc_size;
|
u64 size = mem_alloc_size;
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
uint64_t end;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* exclude a page at the beginning and end of
|
* exclude a page at the beginning and end of
|
||||||
|
@ -684,20 +935,67 @@ void __init plat_mem_setup(void)
|
||||||
memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE +
|
memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE +
|
||||||
CVMX_PCIE_BAR1_PHYS_SIZE,
|
CVMX_PCIE_BAR1_PHYS_SIZE,
|
||||||
&memory, &size);
|
&memory, &size);
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
end = memory + mem_alloc_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function automatically merges address
|
* This function automatically merges address regions
|
||||||
* regions next to each other if they are
|
* next to each other if they are received in
|
||||||
* received in incrementing order.
|
* incrementing order
|
||||||
*/
|
*/
|
||||||
if (size)
|
if (memory < crashk_base && end > crashk_end) {
|
||||||
add_memory_region(memory, size, BOOT_MEM_RAM);
|
/* region is fully in */
|
||||||
|
add_memory_region(memory,
|
||||||
|
crashk_base - memory,
|
||||||
|
BOOT_MEM_RAM);
|
||||||
|
total += crashk_base - memory;
|
||||||
|
add_memory_region(crashk_end,
|
||||||
|
end - crashk_end,
|
||||||
|
BOOT_MEM_RAM);
|
||||||
|
total += end - crashk_end;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memory >= crashk_base && end <= crashk_end)
|
||||||
|
/*
|
||||||
|
* Entire memory region is within the new
|
||||||
|
* kernel's memory, ignore it.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (memory > crashk_base && memory < crashk_end &&
|
||||||
|
end > crashk_end) {
|
||||||
|
/*
|
||||||
|
* Overlap with the beginning of the region,
|
||||||
|
* reserve the beginning.
|
||||||
|
*/
|
||||||
|
mem_alloc_size -= crashk_end - memory;
|
||||||
|
memory = crashk_end;
|
||||||
|
} else if (memory < crashk_base && end > crashk_base &&
|
||||||
|
end < crashk_end)
|
||||||
|
/*
|
||||||
|
* Overlap with the beginning of the region,
|
||||||
|
* chop of end.
|
||||||
|
*/
|
||||||
|
mem_alloc_size -= end - crashk_base;
|
||||||
|
#endif
|
||||||
|
add_memory_region(memory, mem_alloc_size, BOOT_MEM_RAM);
|
||||||
total += mem_alloc_size;
|
total += mem_alloc_size;
|
||||||
|
/* Recovering mem_alloc_size */
|
||||||
|
mem_alloc_size = 4 << 20;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cvmx_bootmem_unlock();
|
cvmx_bootmem_unlock();
|
||||||
|
/* Add the memory region for the kernel. */
|
||||||
|
kernel_start = (unsigned long) _text;
|
||||||
|
kernel_size = ALIGN(_end - _text, 0x100000);
|
||||||
|
|
||||||
|
/* Adjust for physical offset. */
|
||||||
|
kernel_start &= ~0xffffffff80000000ULL;
|
||||||
|
add_memory_region(kernel_start, kernel_size, BOOT_MEM_RAM);
|
||||||
|
#endif /* CONFIG_CRASH_DUMP */
|
||||||
|
|
||||||
#ifdef CONFIG_CAVIUM_RESERVE32
|
#ifdef CONFIG_CAVIUM_RESERVE32
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -370,4 +370,6 @@ void cvmx_bootmem_lock(void);
|
||||||
*/
|
*/
|
||||||
void cvmx_bootmem_unlock(void);
|
void cvmx_bootmem_unlock(void);
|
||||||
|
|
||||||
|
extern struct cvmx_bootmem_desc *cvmx_bootmem_get_desc(void);
|
||||||
|
|
||||||
#endif /* __CVMX_BOOTMEM_H__ */
|
#endif /* __CVMX_BOOTMEM_H__ */
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
#include <linux/crash_dump.h>
|
#include <linux/crash_dump.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
|
|
||||||
|
|
||||||
static int __init parse_savemaxmem(char *p)
|
static int __init parse_savemaxmem(char *p)
|
||||||
{
|
{
|
||||||
if (p)
|
if (p)
|
||||||
|
|
|
@ -78,7 +78,19 @@ done:
|
||||||
LONG_S zero,(t0)
|
LONG_S zero,(t0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_CPU_CAVIUM_OCTEON
|
||||||
|
/* We need to flush I-cache before jumping to new kernel.
|
||||||
|
* Unfortunatelly, this code is cpu-specific.
|
||||||
|
*/
|
||||||
|
.set push
|
||||||
|
.set noreorder
|
||||||
|
syncw
|
||||||
|
syncw
|
||||||
|
synci 0($0)
|
||||||
|
.set pop
|
||||||
|
#else
|
||||||
sync
|
sync
|
||||||
|
#endif
|
||||||
/* jump to kexec_start_address */
|
/* jump to kexec_start_address */
|
||||||
j s1
|
j s1
|
||||||
END(relocate_new_kernel)
|
END(relocate_new_kernel)
|
||||||
|
@ -110,7 +122,14 @@ LEAF(kexec_smp_wait)
|
||||||
1: LONG_L s0, (t0)
|
1: LONG_L s0, (t0)
|
||||||
bne s0, zero,1b
|
bne s0, zero,1b
|
||||||
|
|
||||||
|
#ifdef CONFIG_CPU_CAVIUM_OCTEON
|
||||||
|
.set push
|
||||||
|
.set noreorder
|
||||||
|
synci 0($0)
|
||||||
|
.set pop
|
||||||
|
#else
|
||||||
sync
|
sync
|
||||||
|
#endif
|
||||||
j s1
|
j s1
|
||||||
END(kexec_smp_wait)
|
END(kexec_smp_wait)
|
||||||
#endif
|
#endif
|
||||||
|
|
Загрузка…
Ссылка в новой задаче