summaryrefslogtreecommitdiffstats
path: root/arch/mips/cavium-octeon
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2013-01-29 10:48:30 +0100
committerJiri Kosina <jkosina@suse.cz>2013-01-29 10:48:30 +0100
commit617677295b53a40d0e54aac4cbbc216ffbc755dd (patch)
tree51b9e87213243ed5efff252c8e8d8fec4eebc588 /arch/mips/cavium-octeon
parent5c8d1b68e01a144813e38795fe6dbe7ebb506131 (diff)
parent6abb7c25775b7fb2225ad0508236d63ca710e65f (diff)
downloadlinux-617677295b53a40d0e54aac4cbbc216ffbc755dd.tar.bz2
Merge branch 'master' into for-next
Conflicts: drivers/devfreq/exynos4_bus.c Sync with Linus' tree to be able to apply patches that are against newer code (mvneta).
Diffstat (limited to 'arch/mips/cavium-octeon')
-rw-r--r--arch/mips/cavium-octeon/Makefile3
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-bootmem.c5
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-l2c.c1
-rw-r--r--arch/mips/cavium-octeon/flash_setup.c3
-rw-r--r--arch/mips/cavium-octeon/octeon-irq.c1
-rw-r--r--arch/mips/cavium-octeon/octeon-memcpy.S27
-rw-r--r--arch/mips/cavium-octeon/octeon-platform.c102
-rw-r--r--arch/mips/cavium-octeon/serial.c2
-rw-r--r--arch/mips/cavium-octeon/setup.c374
9 files changed, 365 insertions, 153 deletions
diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index bc96e2908f14..6e927cf20df2 100644
--- a/arch/mips/cavium-octeon/Makefile
+++ b/arch/mips/cavium-octeon/Makefile
@@ -24,9 +24,6 @@ DTB_FILES = $(patsubst %.dts, %.dtb, $(DTS_FILES))
obj-y += $(patsubst %.dts, %.dtb.o, $(DTS_FILES))
-$(obj)/%.dtb: $(src)/%.dts FORCE
- $(call if_changed_dep,dtc)
-
# Let's keep the .dtb files around in case we want to look at them.
.SECONDARY: $(addprefix $(obj)/, $(DTB_FILES))
diff --git a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
index fdf5f19bfdb0..6d5ddbc112cc 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
@@ -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));
return addr_allocated;
}
+
+struct cvmx_bootmem_desc *cvmx_bootmem_get_desc(void)
+{
+ return cvmx_bootmem_desc;
+}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-l2c.c b/arch/mips/cavium-octeon/executive/cvmx-l2c.c
index d38246e33ddb..9f883bf76953 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-l2c.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-l2c.c
@@ -30,6 +30,7 @@
* measurement, and debugging facilities.
*/
+#include <linux/irqflags.h>
#include <asm/octeon/cvmx.h>
#include <asm/octeon/cvmx-l2c.h>
#include <asm/octeon/cvmx-spinlock.h>
diff --git a/arch/mips/cavium-octeon/flash_setup.c b/arch/mips/cavium-octeon/flash_setup.c
index e44a55bc7f0d..237e5b1a72d8 100644
--- a/arch/mips/cavium-octeon/flash_setup.c
+++ b/arch/mips/cavium-octeon/flash_setup.c
@@ -51,7 +51,8 @@ static int __init flash_init(void)
flash_map.name = "phys_mapped_flash";
flash_map.phys = region_cfg.s.base << 16;
flash_map.size = 0x1fc00000 - flash_map.phys;
- flash_map.bankwidth = 1;
+ /* 8-bit bus (0 + 1) or 16-bit bus (1 + 1) */
+ flash_map.bankwidth = region_cfg.s.width + 1;
flash_map.virt = ioremap(flash_map.phys, flash_map.size);
pr_notice("Bootbus flash: Setting flash for %luMB flash at "
"0x%08llx\n", flash_map.size >> 20, flash_map.phys);
diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index 02b15eed4bcd..46f5dbceeecc 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -1266,7 +1266,6 @@ static void __init octeon_irq_init_ciu(void)
octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_TIMER0, 0, i + 52);
octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB0, 0, 56);
- octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_BOOTDMA, 0, 63);
/* CIU_1 */
for (i = 0; i < 16; i++)
diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S
index db478dbb9c7b..0ba0eb96d9ac 100644
--- a/arch/mips/cavium-octeon/octeon-memcpy.S
+++ b/arch/mips/cavium-octeon/octeon-memcpy.S
@@ -79,11 +79,6 @@
/*
* Only on the 64-bit kernel we can made use of 64-bit registers.
*/
-#ifdef CONFIG_64BIT
-#define USE_DOUBLE
-#endif
-
-#ifdef USE_DOUBLE
#define LOAD ld
#define LOADL ldl
@@ -119,26 +114,6 @@
#define t6 $14
#define t7 $15
-#else
-
-#define LOAD lw
-#define LOADL lwl
-#define LOADR lwr
-#define STOREL swl
-#define STORER swr
-#define STORE sw
-#define ADD addu
-#define SUB subu
-#define SRL srl
-#define SLL sll
-#define SRA sra
-#define SLLV sllv
-#define SRLV srlv
-#define NBYTES 4
-#define LOG_NBYTES 2
-
-#endif /* USE_DOUBLE */
-
#ifdef CONFIG_CPU_LITTLE_ENDIAN
#define LDFIRST LOADR
#define LDREST LOADL
@@ -395,12 +370,10 @@ EXC( sb t0, N(dst), s_exc_p1)
COPY_BYTE(0)
COPY_BYTE(1)
-#ifdef USE_DOUBLE
COPY_BYTE(2)
COPY_BYTE(3)
COPY_BYTE(4)
COPY_BYTE(5)
-#endif
EXC( lb t0, NBYTES-2(src), l_exc)
SUB len, len, 1
jr ra
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c
index 0938df10a71c..3c1b625a5859 100644
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -24,108 +24,6 @@
#include <asm/octeon/cvmx-helper.h>
#include <asm/octeon/cvmx-helper-board.h>
-static struct octeon_cf_data octeon_cf_data;
-
-static int __init octeon_cf_device_init(void)
-{
- union cvmx_mio_boot_reg_cfgx mio_boot_reg_cfg;
- unsigned long base_ptr, region_base, region_size;
- struct platform_device *pd;
- struct resource cf_resources[3];
- unsigned int num_resources;
- int i;
- int ret = 0;
-
- /* Setup octeon-cf platform device if present. */
- base_ptr = 0;
- if (octeon_bootinfo->major_version == 1
- && octeon_bootinfo->minor_version >= 1) {
- if (octeon_bootinfo->compact_flash_common_base_addr)
- base_ptr =
- octeon_bootinfo->compact_flash_common_base_addr;
- } else {
- base_ptr = 0x1d000800;
- }
-
- if (!base_ptr)
- return ret;
-
- /* Find CS0 region. */
- for (i = 0; i < 8; i++) {
- mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i));
- region_base = mio_boot_reg_cfg.s.base << 16;
- region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
- if (mio_boot_reg_cfg.s.en && base_ptr >= region_base
- && base_ptr < region_base + region_size)
- break;
- }
- if (i >= 7) {
- /* i and i + 1 are CS0 and CS1, both must be less than 8. */
- goto out;
- }
- octeon_cf_data.base_region = i;
- octeon_cf_data.is16bit = mio_boot_reg_cfg.s.width;
- octeon_cf_data.base_region_bias = base_ptr - region_base;
- memset(cf_resources, 0, sizeof(cf_resources));
- num_resources = 0;
- cf_resources[num_resources].flags = IORESOURCE_MEM;
- cf_resources[num_resources].start = region_base;
- cf_resources[num_resources].end = region_base + region_size - 1;
- num_resources++;
-
-
- if (!(base_ptr & 0xfffful)) {
- /*
- * Boot loader signals availability of DMA (true_ide
- * mode) by setting low order bits of base_ptr to
- * zero.
- */
-
- /* Assume that CS1 immediately follows. */
- mio_boot_reg_cfg.u64 =
- cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(i + 1));
- region_base = mio_boot_reg_cfg.s.base << 16;
- region_size = (mio_boot_reg_cfg.s.size + 1) << 16;
- if (!mio_boot_reg_cfg.s.en)
- goto out;
-
- cf_resources[num_resources].flags = IORESOURCE_MEM;
- cf_resources[num_resources].start = region_base;
- cf_resources[num_resources].end = region_base + region_size - 1;
- num_resources++;
-
- octeon_cf_data.dma_engine = 0;
- cf_resources[num_resources].flags = IORESOURCE_IRQ;
- cf_resources[num_resources].start = OCTEON_IRQ_BOOTDMA;
- cf_resources[num_resources].end = OCTEON_IRQ_BOOTDMA;
- num_resources++;
- } else {
- octeon_cf_data.dma_engine = -1;
- }
-
- pd = platform_device_alloc("pata_octeon_cf", -1);
- if (!pd) {
- ret = -ENOMEM;
- goto out;
- }
- pd->dev.platform_data = &octeon_cf_data;
-
- ret = platform_device_add_resources(pd, cf_resources, num_resources);
- if (ret)
- goto fail;
-
- ret = platform_device_add(pd);
- if (ret)
- goto fail;
-
- return ret;
-fail:
- platform_device_put(pd);
-out:
- return ret;
-}
-device_initcall(octeon_cf_device_init);
-
/* Octeon Random Number Generator. */
static int __init octeon_rng_device_init(void)
{
diff --git a/arch/mips/cavium-octeon/serial.c b/arch/mips/cavium-octeon/serial.c
index 569f41bdcc46..f393f65f3923 100644
--- a/arch/mips/cavium-octeon/serial.c
+++ b/arch/mips/cavium-octeon/serial.c
@@ -43,7 +43,7 @@ void octeon_serial_out(struct uart_port *up, int offset, int value)
cvmx_write_csr((uint64_t)(up->membase + (offset << 3)), (u8)value);
}
-static int __devinit octeon_serial_probe(struct platform_device *pdev)
+static int octeon_serial_probe(struct platform_device *pdev)
{
int irq, res;
struct resource *res_mem;
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index 04dd8ff0e0d8..d7e0a09f77c2 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -4,9 +4,11 @@
* for more details.
*
* Copyright (C) 2004-2007 Cavium Networks
- * Copyright (C) 2008 Wind River Systems
+ * Copyright (C) 2008, 2009 Wind River Systems
+ * written by Ralf Baechle <ralf@linux-mips.org>
*/
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/export.h>
@@ -23,6 +25,7 @@
#include <linux/serial_8250.h>
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
+#include <linux/kexec.h>
#include <asm/processor.h>
#include <asm/reboot.h>
@@ -56,11 +59,208 @@ struct octeon_boot_descriptor *octeon_boot_desc_ptr;
struct cvmx_bootinfo *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
uint64_t octeon_reserve32_memory;
EXPORT_SYMBOL(octeon_reserve32_memory);
#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;
extern asmlinkage void handle_int(void);
@@ -415,6 +615,8 @@ void octeon_user_io_init(void)
void __init prom_init(void)
{
struct cvmx_sysinfo *sysinfo;
+ const char *arg;
+ char *p;
int i;
int argc;
#ifdef CONFIG_CAVIUM_RESERVE32
@@ -566,6 +768,15 @@ void __init prom_init(void)
if (octeon_is_simulation())
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;
argc = octeon_boot_desc_ptr->argc;
for (i = 0; i < argc; i++) {
@@ -573,16 +784,30 @@ void __init prom_init(void)
cvmx_phys_to_ptr(octeon_boot_desc_ptr->argv[i]);
if ((strncmp(arg, "MEM=", 4) == 0) ||
(strncmp(arg, "mem=", 4) == 0)) {
- sscanf(arg + 4, "%llu", &MAX_MEMORY);
- MAX_MEMORY <<= 20;
+ MAX_MEMORY = memparse(arg + 4, &p);
if (MAX_MEMORY == 0)
MAX_MEMORY = 32ull << 30;
+ if (*p == '@')
+ RESERVE_LOW_MEM = memparse(p + 1, &p);
} else if (strcmp(arg, "ecc_verbose") == 0) {
#ifdef CONFIG_CAVIUM_REPORT_SINGLE_BIT_ECC
__cvmx_interrupt_ecc_report_single_bit_errors = 1;
pr_notice("Reporting of single bit ECC errors is "
"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
} else if (strlen(arcs_cmdline) + strlen(arg) + 1 <
sizeof(arcs_cmdline) - 1) {
strcat(arcs_cmdline, " ");
@@ -617,11 +842,18 @@ void __init prom_init(void)
_machine_restart = octeon_restart;
_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();
register_smp_ops(&octeon_smp_ops);
}
/* 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)
{
if (addr > *mem && addr < *mem + *size) {
@@ -636,14 +868,21 @@ static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size)
*size -= PAGE_SIZE;
}
}
+#endif /* CONFIG_CRASH_DUMP */
void __init plat_mem_setup(void)
{
uint64_t mem_alloc_size;
uint64_t total;
+ uint64_t crashk_end;
+#ifndef CONFIG_CRASH_DUMP
int64_t memory;
+ uint64_t kernel_start;
+ uint64_t kernel_size;
+#endif
total = 0;
+ crashk_end = 0;
/*
* The Mips memory init uses the first memory location for
@@ -656,6 +895,17 @@ void __init plat_mem_setup(void)
if (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
* bootmem_alloc so the code in add_memory_region can merge
@@ -664,22 +914,15 @@ void __init plat_mem_setup(void)
cvmx_bootmem_lock();
while ((boot_mem_map.nr_map < BOOT_MEM_MAP_MAX)
&& (total < MAX_MEMORY)) {
-#if defined(CONFIG_64BIT) || defined(CONFIG_64BIT_PHYS_ADDR)
memory = cvmx_bootmem_phy_alloc(mem_alloc_size,
__pa_symbol(&__init_end), -1,
0x100000,
CVMX_BOOTMEM_FLAG_NO_LOCKING);
-#elif defined(CONFIG_HIGHMEM)
- memory = cvmx_bootmem_phy_alloc(mem_alloc_size, 0, 1ull << 31,
- 0x100000,
- CVMX_BOOTMEM_FLAG_NO_LOCKING);
-#else
- memory = cvmx_bootmem_phy_alloc(mem_alloc_size, 0, 512 << 20,
- 0x100000,
- CVMX_BOOTMEM_FLAG_NO_LOCKING);
-#endif
if (memory >= 0) {
u64 size = mem_alloc_size;
+#ifdef CONFIG_KEXEC
+ uint64_t end;
+#endif
/*
* exclude a page at the beginning and end of
@@ -692,20 +935,67 @@ void __init plat_mem_setup(void)
memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE +
CVMX_PCIE_BAR1_PHYS_SIZE,
&memory, &size);
+#ifdef CONFIG_KEXEC
+ end = memory + mem_alloc_size;
/*
- * This function automatically merges address
- * regions next to each other if they are
- * received in incrementing order.
+ * This function automatically merges address regions
+ * next to each other if they are received in
+ * incrementing order
*/
- if (size)
- add_memory_region(memory, size, BOOT_MEM_RAM);
+ if (memory < crashk_base && end > crashk_end) {
+ /* 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;
+ /* Recovering mem_alloc_size */
+ mem_alloc_size = 4 << 20;
} else {
break;
}
}
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
/*
@@ -821,3 +1111,51 @@ void __init device_tree_init(void)
}
unflatten_device_tree();
}
+
+static int __initdata disable_octeon_edac_p;
+
+static int __init disable_octeon_edac(char *str)
+{
+ disable_octeon_edac_p = 1;
+ return 0;
+}
+early_param("disable_octeon_edac", disable_octeon_edac);
+
+static char *edac_device_names[] = {
+ "octeon_l2c_edac",
+ "octeon_pc_edac",
+};
+
+static int __init edac_devinit(void)
+{
+ struct platform_device *dev;
+ int i, err = 0;
+ int num_lmc;
+ char *name;
+
+ if (disable_octeon_edac_p)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(edac_device_names); i++) {
+ name = edac_device_names[i];
+ dev = platform_device_register_simple(name, -1, NULL, 0);
+ if (IS_ERR(dev)) {
+ pr_err("Registation of %s failed!\n", name);
+ err = PTR_ERR(dev);
+ }
+ }
+
+ num_lmc = OCTEON_IS_MODEL(OCTEON_CN68XX) ? 4 :
+ (OCTEON_IS_MODEL(OCTEON_CN56XX) ? 2 : 1);
+ for (i = 0; i < num_lmc; i++) {
+ dev = platform_device_register_simple("octeon_lmc_edac",
+ i, NULL, 0);
+ if (IS_ERR(dev)) {
+ pr_err("Registation of octeon_lmc_edac %d failed!\n", i);
+ err = PTR_ERR(dev);
+ }
+ }
+
+ return err;
+}
+device_initcall(edac_devinit);