diff options
Diffstat (limited to 'drivers/watchdog/octeon-wdt-main.c')
-rw-r--r-- | drivers/watchdog/octeon-wdt-main.c | 134 |
1 files changed, 10 insertions, 124 deletions
diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index b5cdceb36cff..fbdd48404b54 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c @@ -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", |