aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2012-10-25 10:23:31 -0400
committerRalf Baechle <ralf@linux-mips.org>2012-12-13 11:00:39 -0500
commitabe77f90dc9c65a7c9a4d61c2cbb8db4d5566e4f (patch)
tree69fd0cfe31a9041e8e1a881829c011892075ea2c
parent7aa1c8f47e7e792d11f898cbdddaf6fa21ff08cc (diff)
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>
-rw-r--r--arch/mips/Makefile4
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-bootmem.c5
-rw-r--r--arch/mips/cavium-octeon/setup.c312
-rw-r--r--arch/mips/include/asm/octeon/cvmx-bootmem.h2
-rw-r--r--arch/mips/kernel/crash_dump.c2
-rw-r--r--arch/mips/kernel/relocate_kernel.S19
6 files changed, 335 insertions, 9 deletions
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 654b1ad39f0..033395ec82f 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -192,6 +192,10 @@ endif
192# 192#
193include $(srctree)/arch/mips/Kbuild.platforms 193include $(srctree)/arch/mips/Kbuild.platforms
194 194
195ifdef CONFIG_PHYSICAL_START
196load-y = $(CONFIG_PHYSICAL_START)
197endif
198
195cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic 199cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
196drivers-$(CONFIG_PCI) += arch/mips/pci/ 200drivers-$(CONFIG_PCI) += arch/mips/pci/
197 201
diff --git a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
index fdf5f19bfdb..6d5ddbc112c 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,
688 cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock)); 688 cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock));
689 return addr_allocated; 689 return addr_allocated;
690} 690}
691
692struct cvmx_bootmem_desc *cvmx_bootmem_get_desc(void)
693{
694 return cvmx_bootmem_desc;
695}
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index 67aa3b942f0..7c2b7aab77b 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -25,6 +25,7 @@
25#include <linux/serial_8250.h> 25#include <linux/serial_8250.h>
26#include <linux/of_fdt.h> 26#include <linux/of_fdt.h>
27#include <linux/libfdt.h> 27#include <linux/libfdt.h>
28#include <linux/kexec.h>
28 29
29#include <asm/processor.h> 30#include <asm/processor.h>
30#include <asm/reboot.h> 31#include <asm/reboot.h>
@@ -58,11 +59,208 @@ struct octeon_boot_descriptor *octeon_boot_desc_ptr;
58struct cvmx_bootinfo *octeon_bootinfo; 59struct cvmx_bootinfo *octeon_bootinfo;
59EXPORT_SYMBOL(octeon_bootinfo); 60EXPORT_SYMBOL(octeon_bootinfo);
60 61
62static unsigned long long RESERVE_LOW_MEM = 0ull;
63#ifdef CONFIG_KEXEC
64#ifdef CONFIG_SMP
65/*
66 * Wait for relocation code is prepared and send
67 * secondary CPUs to spin until kernel is relocated.
68 */
69static void octeon_kexec_smp_down(void *ignored)
70{
71 int cpu = smp_processor_id();
72
73 local_irq_disable();
74 set_cpu_online(cpu, false);
75 while (!atomic_read(&kexec_ready_to_reboot))
76 cpu_relax();
77
78 asm volatile (
79 " sync \n"
80 " synci ($0) \n");
81
82 relocated_kexec_smp_wait(NULL);
83}
84#endif
85
86#define OCTEON_DDR0_BASE (0x0ULL)
87#define OCTEON_DDR0_SIZE (0x010000000ULL)
88#define OCTEON_DDR1_BASE (0x410000000ULL)
89#define OCTEON_DDR1_SIZE (0x010000000ULL)
90#define OCTEON_DDR2_BASE (0x020000000ULL)
91#define OCTEON_DDR2_SIZE (0x3e0000000ULL)
92#define OCTEON_MAX_PHY_MEM_SIZE (16*1024*1024*1024ULL)
93
94static struct kimage *kimage_ptr;
95
96static void kexec_bootmem_init(uint64_t mem_size, uint32_t low_reserved_bytes)
97{
98 int64_t addr;
99 struct cvmx_bootmem_desc *bootmem_desc;
100
101 bootmem_desc = cvmx_bootmem_get_desc();
102
103 if (mem_size > OCTEON_MAX_PHY_MEM_SIZE) {
104 mem_size = OCTEON_MAX_PHY_MEM_SIZE;
105 pr_err("Error: requested memory too large,"
106 "truncating to maximum size\n");
107 }
108
109 bootmem_desc->major_version = CVMX_BOOTMEM_DESC_MAJ_VER;
110 bootmem_desc->minor_version = CVMX_BOOTMEM_DESC_MIN_VER;
111
112 addr = (OCTEON_DDR0_BASE + RESERVE_LOW_MEM + low_reserved_bytes);
113 bootmem_desc->head_addr = 0;
114
115 if (mem_size <= OCTEON_DDR0_SIZE) {
116 __cvmx_bootmem_phy_free(addr,
117 mem_size - RESERVE_LOW_MEM -
118 low_reserved_bytes, 0);
119 return;
120 }
121
122 __cvmx_bootmem_phy_free(addr,
123 OCTEON_DDR0_SIZE - RESERVE_LOW_MEM -
124 low_reserved_bytes, 0);
125
126 mem_size -= OCTEON_DDR0_SIZE;
127
128 if (mem_size > OCTEON_DDR1_SIZE) {
129 __cvmx_bootmem_phy_free(OCTEON_DDR1_BASE, OCTEON_DDR1_SIZE, 0);
130 __cvmx_bootmem_phy_free(OCTEON_DDR2_BASE,
131 mem_size - OCTEON_DDR1_SIZE, 0);
132 } else
133 __cvmx_bootmem_phy_free(OCTEON_DDR1_BASE, mem_size, 0);
134}
135
136static int octeon_kexec_prepare(struct kimage *image)
137{
138 int i;
139 char *bootloader = "kexec";
140
141 octeon_boot_desc_ptr->argc = 0;
142 for (i = 0; i < image->nr_segments; i++) {
143 if (!strncmp(bootloader, (char *)image->segment[i].buf,
144 strlen(bootloader))) {
145 /*
146 * convert command line string to array
147 * of parameters (as bootloader does).
148 */
149 int argc = 0, offt;
150 char *str = (char *)image->segment[i].buf;
151 char *ptr = strchr(str, ' ');
152 while (ptr && (OCTEON_ARGV_MAX_ARGS > argc)) {
153 *ptr = '\0';
154 if (ptr[1] != ' ') {
155 offt = (int)(ptr - str + 1);
156 octeon_boot_desc_ptr->argv[argc] =
157 image->segment[i].mem + offt;
158 argc++;
159 }
160 ptr = strchr(ptr + 1, ' ');
161 }
162 octeon_boot_desc_ptr->argc = argc;
163 break;
164 }
165 }
166
167 /*
168 * Information about segments will be needed during pre-boot memory
169 * initialization.
170 */
171 kimage_ptr = image;
172 return 0;
173}
174
175static void octeon_generic_shutdown(void)
176{
177 int cpu, i;
178 struct cvmx_bootmem_desc *bootmem_desc;
179 void *named_block_array_ptr;
180
181 bootmem_desc = cvmx_bootmem_get_desc();
182 named_block_array_ptr =
183 cvmx_phys_to_ptr(bootmem_desc->named_block_array_addr);
184
185#ifdef CONFIG_SMP
186 /* disable watchdogs */
187 for_each_online_cpu(cpu)
188 cvmx_write_csr(CVMX_CIU_WDOGX(cpu_logical_map(cpu)), 0);
189#else
190 cvmx_write_csr(CVMX_CIU_WDOGX(cvmx_get_core_num()), 0);
191#endif
192 if (kimage_ptr != kexec_crash_image) {
193 memset(named_block_array_ptr,
194 0x0,
195 CVMX_BOOTMEM_NUM_NAMED_BLOCKS *
196 sizeof(struct cvmx_bootmem_named_block_desc));
197 /*
198 * Mark all memory (except low 0x100000 bytes) as free.
199 * It is the same thing that bootloader does.
200 */
201 kexec_bootmem_init(octeon_bootinfo->dram_size*1024ULL*1024ULL,
202 0x100000);
203 /*
204 * Allocate all segments to avoid their corruption during boot.
205 */
206 for (i = 0; i < kimage_ptr->nr_segments; i++)
207 cvmx_bootmem_alloc_address(
208 kimage_ptr->segment[i].memsz + 2*PAGE_SIZE,
209 kimage_ptr->segment[i].mem - PAGE_SIZE,
210 PAGE_SIZE);
211 } else {
212 /*
213 * Do not mark all memory as free. Free only named sections
214 * leaving the rest of memory unchanged.
215 */
216 struct cvmx_bootmem_named_block_desc *ptr =
217 (struct cvmx_bootmem_named_block_desc *)