watchdog: octeon-wdt: Remove old boot vector code.

Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
Acked-by: David Daney <david.daney@cavium.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Cc: linux-mips@linux-mips.org
Cc: linux-watchdog@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/17209/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Steven J. Hill 2017-08-29 10:40:32 -05:00 committed by Ralf Baechle
parent 9438a86a07
commit 49d148b4e5
2 changed files with 44 additions and 132 deletions

View File

@ -73,6 +73,7 @@
#include <asm/uasm.h>
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-boot-vector.h>
/* The count needed to achieve timeout_sec. */
static unsigned int timeout_cnt;
@ -104,122 +105,10 @@ MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static u32 nmi_stage1_insns[64] __initdata;
/* We need one branch and therefore one relocation per target label. */
static struct uasm_label labels[5] __initdata;
static struct uasm_reloc relocs[5] __initdata;
enum lable_id {
label_enter_bootloader = 1
};
/* Some CP0 registers */
#define K0 26
#define C0_CVMMEMCTL 11, 7
#define C0_STATUS 12, 0
#define C0_EBASE 15, 1
#define C0_DESAVE 31, 0
static struct cvmx_boot_vector_element *octeon_wdt_bootvector;
void octeon_wdt_nmi_stage2(void);
static void __init octeon_wdt_build_stage1(void)
{
int i;
int len;
u32 *p = nmi_stage1_insns;
#ifdef CONFIG_HOTPLUG_CPU
struct uasm_label *l = labels;
struct uasm_reloc *r = relocs;
#endif
/*
* For the next few instructions running the debugger may
* cause corruption of k0 in the saved registers. Since we're
* about to crash, nobody probably cares.
*
* Save K0 into the debug scratch register
*/
uasm_i_dmtc0(&p, K0, C0_DESAVE);
uasm_i_mfc0(&p, K0, C0_STATUS);
#ifdef CONFIG_HOTPLUG_CPU
if (octeon_bootloader_entry_addr)
uasm_il_bbit0(&p, &r, K0, ilog2(ST0_NMI),
label_enter_bootloader);
#endif
/* Force 64-bit addressing enabled */
uasm_i_ori(&p, K0, K0, ST0_UX | ST0_SX | ST0_KX);
uasm_i_mtc0(&p, K0, C0_STATUS);
#ifdef CONFIG_HOTPLUG_CPU
if (octeon_bootloader_entry_addr) {
uasm_i_mfc0(&p, K0, C0_EBASE);
/* Coreid number in K0 */
uasm_i_andi(&p, K0, K0, 0xf);
/* 8 * coreid in bits 16-31 */
uasm_i_dsll_safe(&p, K0, K0, 3 + 16);
uasm_i_ori(&p, K0, K0, 0x8001);
uasm_i_dsll_safe(&p, K0, K0, 16);
uasm_i_ori(&p, K0, K0, 0x0700);
uasm_i_drotr_safe(&p, K0, K0, 32);
/*
* Should result in: 0x8001,0700,0000,8*coreid which is
* CVMX_CIU_WDOGX(coreid) - 0x0500
*
* Now ld K0, CVMX_CIU_WDOGX(coreid)
*/
uasm_i_ld(&p, K0, 0x500, K0);
/*
* If bit one set handle the NMI as a watchdog event.
* otherwise transfer control to bootloader.
*/
uasm_il_bbit0(&p, &r, K0, 1, label_enter_bootloader);
uasm_i_nop(&p);
}
#endif
/* Clear Dcache so cvmseg works right. */
uasm_i_cache(&p, 1, 0, 0);
/* Use K0 to do a read/modify/write of CVMMEMCTL */
uasm_i_dmfc0(&p, K0, C0_CVMMEMCTL);
/* Clear out the size of CVMSEG */
uasm_i_dins(&p, K0, 0, 0, 6);
/* Set CVMSEG to its largest value */
uasm_i_ori(&p, K0, K0, 0x1c0 | 54);
/* Store the CVMMEMCTL value */
uasm_i_dmtc0(&p, K0, C0_CVMMEMCTL);
/* Load the address of the second stage handler */
UASM_i_LA(&p, K0, (long)octeon_wdt_nmi_stage2);
uasm_i_jr(&p, K0);
uasm_i_dmfc0(&p, K0, C0_DESAVE);
#ifdef CONFIG_HOTPLUG_CPU
if (octeon_bootloader_entry_addr) {
uasm_build_label(&l, p, label_enter_bootloader);
/* Jump to the bootloader and restore K0 */
UASM_i_LA(&p, K0, (long)octeon_bootloader_entry_addr);
uasm_i_jr(&p, K0);
uasm_i_dmfc0(&p, K0, C0_DESAVE);
}
#endif
uasm_resolve_relocs(relocs, labels);
len = (int)(p - nmi_stage1_insns);
pr_debug("Synthesized NMI stage 1 handler (%d instructions)\n", len);
pr_debug("\t.set push\n");
pr_debug("\t.set noreorder\n");
for (i = 0; i < len; i++)
pr_debug("\t.word 0x%08x\n", nmi_stage1_insns[i]);
pr_debug("\t.set pop\n");
if (len > 32)
panic("NMI stage 1 handler exceeds 32 instructions, was %d\n",
len);
}
static int cpu2core(int cpu)
{
#ifdef CONFIG_SMP
@ -402,6 +291,8 @@ static int octeon_wdt_cpu_online(unsigned int cpu)
core = cpu2core(cpu);
octeon_wdt_bootvector[core].target_ptr = (u64)octeon_wdt_nmi_stage2;
/* Disable it before doing anything with the interrupts. */
ciu_wdog.u64 = 0;
cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
@ -544,6 +435,12 @@ static int __init octeon_wdt_init(void)
int ret;
u64 *ptr;
octeon_wdt_bootvector = cvmx_boot_vector_get();
if (!octeon_wdt_bootvector) {
pr_err("Error: Cannot allocate boot vector.\n");
return -ENOMEM;
}
/*
* Watchdog time expiration length = The 16 bits of LEN
* represent the most significant bits of a 24 bit decrementer
@ -576,17 +473,6 @@ static int __init octeon_wdt_init(void)
return ret;
}
/* Build the NMI handler ... */
octeon_wdt_build_stage1();
/* ... and install it. */
ptr = (u64 *) nmi_stage1_insns;
for (i = 0; i < 16; i++) {
cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8);
cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, ptr[i]);
}
cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0x81fc0000);
cpumask_clear(&irq_enabled_cpus);
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "watchdog/octeon:online",

View File

@ -3,20 +3,40 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2007 Cavium Networks
* Copyright (C) 2007-2017 Cavium, Inc.
*/
#include <asm/asm.h>
#include <asm/regdef.h>
#define SAVE_REG(r) sd $r, -32768+6912-(32-r)*8($0)
#define CVMSEG_BASE -32768
#define CVMSEG_SIZE 6912
#define SAVE_REG(r) sd $r, CVMSEG_BASE + CVMSEG_SIZE - ((32 - r) * 8)($0)
NESTED(octeon_wdt_nmi_stage2, 0, sp)
.set push
.set noreorder
.set noat
/* Save all registers to the top CVMSEG. This shouldn't
/* Clear Dcache so cvmseg works right. */
cache 1,0($0)
/* Use K0 to do a read/modify/write of CVMMEMCTL */
dmfc0 k0, $11, 7
/* Clear out the size of CVMSEG */
dins k0, $0, 0, 6
/* Set CVMSEG to its largest value */
ori k0, k0, 0x1c0 | 54
/* Store the CVMMEMCTL value */
dmtc0 k0, $11, 7
/*
* Restore K0 from the debug scratch register, it was saved in
* the boot-vector code.
*/
dmfc0 k0, $31
/*
* Save all registers to the top CVMSEG. This shouldn't
* corrupt any state used by the kernel. Also all registers
* should have the value right before the NMI. */
* should have the value right before the NMI.
*/
SAVE_REG(0)
SAVE_REG(1)
SAVE_REG(2)
@ -49,16 +69,22 @@
SAVE_REG(29)
SAVE_REG(30)
SAVE_REG(31)
/* Write zero to all CVMSEG locations per Core-15169 */
dli a0, CVMSEG_SIZE - (33 * 8)
1: sd zero, CVMSEG_BASE(a0)
daddiu a0, a0, -8
bgez a0, 1b
nop
/* Set the stack to begin right below the registers */
li sp, -32768+6912-32*8
dli sp, CVMSEG_BASE + CVMSEG_SIZE - (32 * 8)
/* Load the address of the third stage handler */
dla a0, octeon_wdt_nmi_stage3
dla $25, octeon_wdt_nmi_stage3
/* Call the third stage handler */
jal a0
jal $25
/* a0 is the address of the saved registers */
move a0, sp
/* Loop forvever if we get here. */
1: b 1b
2: b 2b
nop
.set pop
END(octeon_wdt_nmi_stage2)