Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Octeon Watchdog driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2007-2017 Cavium, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Converted to use WATCHDOG_CORE by Aaro Koskinen <aaro.koskinen@iki.fi>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * Some parts derived from wdt.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *	(c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  *						All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  *	warranty for any of this software. This material is provided
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  *	"AS-IS" and at no charge.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  * The OCTEON watchdog has a maximum timeout of 2^32 * io_clock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  * For most systems this is less than 10 seconds, so to allow for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  * software to request longer watchdog heartbeats, we maintain software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  * counters to count multiples of the base rate.  If the system locks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  * up in such a manner that we can not run the software counters, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25)  * only result is a watchdog reset sooner than was requested.  But
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  * that is OK, because in this case userspace would likely not be able
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  * to do anything anyhow.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  * The hardware watchdog interval we call the period.  The OCTEON
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)  * watchdog goes through several stages, after the first period an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)  * irq is asserted, then if it is not reset, after the next period NMI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32)  * is asserted, then after an additional period a chip wide soft reset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)  * So for the software counters, we reset watchdog after each period
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)  * and decrement the counter.  But for the last two periods we need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)  * let the watchdog progress to the NMI stage so we disable the irq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36)  * and let it proceed.  Once in the NMI, we print the register state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)  * to the serial port and then wait for the reset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)  * A watchdog is maintained for each CPU in the system, that way if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)  * one CPU suffers a lockup, we also get a register dump and reset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  * The userspace ping resets the watchdog on all CPUs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43)  * Before userspace opens the watchdog device, we still run the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44)  * watchdogs to catch any lockups that may be kernel related.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) #include <linux/watchdog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) #include <linux/cpumask.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) #include <asm/mipsregs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) #include <asm/uasm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) #include <asm/octeon/octeon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) #include <asm/octeon/cvmx-boot-vector.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) #include <asm/octeon/cvmx-ciu2-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) #include <asm/octeon/cvmx-rst-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) /* Watchdog interrupt major block number (8 MSBs of intsn) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) #define WD_BLOCK_NUMBER		0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) static int divisor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) /* The count needed to achieve timeout_sec. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) static unsigned int timeout_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) /* The maximum period supported. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) static unsigned int max_timeout_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) /* The current period.  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) static unsigned int timeout_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) /* Set to non-zero when userspace countdown mode active */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) static bool do_countdown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) static unsigned int countdown_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) static unsigned int per_cpu_countdown[NR_CPUS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) static cpumask_t irq_enabled_cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) #define WD_TIMO 60			/* Default heartbeat = 60 seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) #define CVMX_GSERX_SCRATCH(offset) (CVMX_ADD_IO_SEG(0x0001180090000020ull) + ((offset) & 15) * 0x1000000ull)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) static int heartbeat = WD_TIMO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) module_param(heartbeat, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) MODULE_PARM_DESC(heartbeat,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	"Watchdog heartbeat in seconds. (0 < heartbeat, default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 				__MODULE_STRING(WD_TIMO) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) static bool nowayout = WATCHDOG_NOWAYOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) module_param(nowayout, bool, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) MODULE_PARM_DESC(nowayout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	"Watchdog cannot be stopped once started (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static int disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) module_param(disable, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) MODULE_PARM_DESC(disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	"Disable the watchdog entirely (default=0)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static struct cvmx_boot_vector_element *octeon_wdt_bootvector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) void octeon_wdt_nmi_stage2(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static int cpu2core(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	return cpu_logical_map(cpu) & 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	return cvmx_get_core_num();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)  * Poke the watchdog when an interrupt is received
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)  * @cpl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)  * @dev_id:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)  * Returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	int cpu = raw_smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	unsigned int core = cpu2core(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	int node = cpu_to_node(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	if (do_countdown) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		if (per_cpu_countdown[cpu] > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 			/* We're alive, poke the watchdog */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 			cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 			per_cpu_countdown[cpu]--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 			/* Bad news, you are about to reboot. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 			disable_irq_nosync(cpl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 			cpumask_clear_cpu(cpu, &irq_enabled_cpus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 		/* Not open, just ping away... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* From setup.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) extern int prom_putchar(char c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)  * Write a string to the uart
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)  * @str:        String to write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static void octeon_wdt_write_string(const char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	/* Just loop writing one byte at a time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	while (*str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 		prom_putchar(*str++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)  * Write a hex number out of the uart
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)  * @value:      Number to display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)  * @digits:     Number of digits to print (1 to 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static void octeon_wdt_write_hex(u64 value, int digits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	int d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	int v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	for (d = 0; d < digits; d++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		v = (value >> ((digits - d - 1) * 4)) & 0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		if (v >= 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 			prom_putchar('a' + v - 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 			prom_putchar('0' + v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static const char reg_name[][3] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	"$0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	"a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)  * NMI stage 3 handler. NMIs are handled in the following manner:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)  * 1) The first NMI handler enables CVMSEG and transfers from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)  * the bootbus region into normal memory. It is careful to not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)  * destroy any registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)  * 2) The second stage handler uses CVMSEG to save the registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)  * and create a stack for C code. It then calls the third level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)  * handler with one argument, a pointer to the register values.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)  * 3) The third, and final, level handler is the following C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)  * function that prints out some useful infomration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)  * @reg:    Pointer to register state before the NMI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) void octeon_wdt_nmi_stage3(u64 reg[32])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	u64 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	unsigned int coreid = cvmx_get_core_num();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	 * Save status and cause early to get them before any changes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	 * might happen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	u64 cp0_cause = read_c0_cause();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	u64 cp0_status = read_c0_status();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	u64 cp0_error_epc = read_c0_errorepc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	u64 cp0_epc = read_c0_epc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	/* Delay so output from all cores output is not jumbled together. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	udelay(85000 * coreid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	octeon_wdt_write_string("\r\n*** NMI Watchdog interrupt on Core 0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	octeon_wdt_write_hex(coreid, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	octeon_wdt_write_string(" ***\r\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	for (i = 0; i < 32; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 		octeon_wdt_write_string("\t");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 		octeon_wdt_write_string(reg_name[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 		octeon_wdt_write_string("\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		octeon_wdt_write_hex(reg[i], 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		if (i & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 			octeon_wdt_write_string("\r\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	octeon_wdt_write_string("\terr_epc\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	octeon_wdt_write_hex(cp0_error_epc, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	octeon_wdt_write_string("\tepc\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	octeon_wdt_write_hex(cp0_epc, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	octeon_wdt_write_string("\r\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	octeon_wdt_write_string("\tstatus\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	octeon_wdt_write_hex(cp0_status, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	octeon_wdt_write_string("\tcause\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	octeon_wdt_write_hex(cp0_cause, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	octeon_wdt_write_string("\r\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	/* The CIU register is different for each Octeon model. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 		octeon_wdt_write_string("\tsrc_wd\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SRC_PPX_IP2_WDOG(coreid)), 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 		octeon_wdt_write_string("\ten_wd\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_EN_PPX_IP2_WDOG(coreid)), 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 		octeon_wdt_write_string("\r\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		octeon_wdt_write_string("\tsrc_rml\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SRC_PPX_IP2_RML(coreid)), 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 		octeon_wdt_write_string("\ten_rml\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_EN_PPX_IP2_RML(coreid)), 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 		octeon_wdt_write_string("\r\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 		octeon_wdt_write_string("\tsum\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SUM_PPX_IP2(coreid)), 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 		octeon_wdt_write_string("\r\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	} else if (!octeon_has_feature(OCTEON_FEATURE_CIU3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 		octeon_wdt_write_string("\tsum0\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_SUM0(coreid * 2)), 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 		octeon_wdt_write_string("\ten0\t0x");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)), 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		octeon_wdt_write_string("\r\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	octeon_wdt_write_string("*** Chip soft reset soon ***\r\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	 * G-30204: We must trigger a soft reset before watchdog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	 * does an incomplete job of doing it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	if (OCTEON_IS_OCTEON3() && !OCTEON_IS_MODEL(OCTEON_CN70XX)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 		u64 scr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		unsigned int node = cvmx_get_node_num();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 		unsigned int lcore = cvmx_get_local_core_num();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 		union cvmx_ciu_wdogx ciu_wdog;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		 * Wait for other cores to print out information, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 		 * not too long.  Do the soft reset before watchdog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 		 * can trigger it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 			ciu_wdog.u64 = cvmx_read_csr_node(node, CVMX_CIU_WDOGX(lcore));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 		} while (ciu_wdog.s.cnt > 0x10000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 		scr = cvmx_read_csr_node(0, CVMX_GSERX_SCRATCH(0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 		scr |= 1 << 11; /* Indicate watchdog in bit 11 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 		cvmx_write_csr_node(0, CVMX_GSERX_SCRATCH(0), scr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 		cvmx_write_csr_node(0, CVMX_RST_SOFT_RST, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static int octeon_wdt_cpu_to_irq(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	unsigned int coreid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	int node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	coreid = cpu2core(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	node = cpu_to_node(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 		struct irq_domain *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		int hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 		domain = octeon_irq_get_block_domain(node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 						     WD_BLOCK_NUMBER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 		hwirq = WD_BLOCK_NUMBER << 12 | 0x200 | coreid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 		irq = irq_find_mapping(domain, hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 		irq = OCTEON_IRQ_WDOG0 + coreid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static int octeon_wdt_cpu_pre_down(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	unsigned int core;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	int node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	union cvmx_ciu_wdogx ciu_wdog;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 	core = cpu2core(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	node = cpu_to_node(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	/* Poke the watchdog to clear out its state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	/* Disable the hardware. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	ciu_wdog.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	free_irq(octeon_wdt_cpu_to_irq(cpu), octeon_wdt_poke_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static int octeon_wdt_cpu_online(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	unsigned int core;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	unsigned int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	union cvmx_ciu_wdogx ciu_wdog;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	int node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	struct irq_domain *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	int hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	core = cpu2core(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	node = cpu_to_node(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 	octeon_wdt_bootvector[core].target_ptr = (u64)octeon_wdt_nmi_stage2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 	/* Disable it before doing anything with the interrupts. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	ciu_wdog.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	per_cpu_countdown[cpu] = countdown_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 		/* Must get the domain for the watchdog block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		domain = octeon_irq_get_block_domain(node, WD_BLOCK_NUMBER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 		/* Get a irq for the wd intsn (hardware interrupt) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		hwirq = WD_BLOCK_NUMBER << 12 | 0x200 | core;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 		irq = irq_create_mapping(domain, hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 		irqd_set_trigger_type(irq_get_irq_data(irq),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 				      IRQ_TYPE_EDGE_RISING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 		irq = OCTEON_IRQ_WDOG0 + core;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	if (request_irq(irq, octeon_wdt_poke_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 			IRQF_NO_THREAD, "octeon_wdt", octeon_wdt_poke_irq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 		panic("octeon_wdt: Couldn't obtain irq %d", irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	/* Must set the irq affinity here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 		cpumask_t mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 		cpumask_clear(&mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 		cpumask_set_cpu(cpu, &mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 		irq_set_affinity(irq, &mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	cpumask_set_cpu(cpu, &irq_enabled_cpus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 	/* Poke the watchdog to clear out its state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	/* Finally enable the watchdog now that all handlers are installed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	ciu_wdog.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	ciu_wdog.s.len = timeout_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	ciu_wdog.s.mode = 3;	/* 3 = Interrupt + NMI + Soft-Reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) static int octeon_wdt_ping(struct watchdog_device __always_unused *wdog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 	int coreid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	int node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	if (disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	for_each_online_cpu(cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 		coreid = cpu2core(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		node = cpu_to_node(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 		per_cpu_countdown[cpu] = countdown_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 		if ((countdown_reset || !do_countdown) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 		    !cpumask_test_cpu(cpu, &irq_enabled_cpus)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 			/* We have to enable the irq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 			enable_irq(octeon_wdt_cpu_to_irq(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 			cpumask_set_cpu(cpu, &irq_enabled_cpus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) static void octeon_wdt_calc_parameters(int t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 	unsigned int periods;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	timeout_sec = max_timeout_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 	 * Find the largest interrupt period, that can evenly divide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 	 * the requested heartbeat time.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	while ((t % timeout_sec) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 		timeout_sec--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 	periods = t / timeout_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 	 * The last two periods are after the irq is disabled, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 	 * then to the nmi, so we subtract them off.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	countdown_reset = periods > 2 ? periods - 2 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 	heartbeat = t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	timeout_cnt = ((octeon_get_io_clock_rate() / divisor) * timeout_sec) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 				  unsigned int t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	int coreid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	union cvmx_ciu_wdogx ciu_wdog;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 	int node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 	if (t <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	octeon_wdt_calc_parameters(t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	if (disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	for_each_online_cpu(cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 		coreid = cpu2core(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 		node = cpu_to_node(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 		ciu_wdog.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 		ciu_wdog.s.len = timeout_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 		ciu_wdog.s.mode = 3;	/* 3 = Interrupt + NMI + Soft-Reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 		cvmx_write_csr_node(node, CVMX_CIU_WDOGX(coreid), ciu_wdog.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	octeon_wdt_ping(wdog); /* Get the irqs back on. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) static int octeon_wdt_start(struct watchdog_device *wdog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 	octeon_wdt_ping(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	do_countdown = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) static int octeon_wdt_stop(struct watchdog_device *wdog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 	do_countdown = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 	octeon_wdt_ping(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static const struct watchdog_info octeon_wdt_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 	.identity = "OCTEON",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static const struct watchdog_ops octeon_wdt_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	.owner		= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 	.start		= octeon_wdt_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	.stop		= octeon_wdt_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 	.ping		= octeon_wdt_ping,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 	.set_timeout	= octeon_wdt_set_timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) static struct watchdog_device octeon_wdt = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 	.info	= &octeon_wdt_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 	.ops	= &octeon_wdt_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) static enum cpuhp_state octeon_wdt_online;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)  * Module/ driver initialization.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)  * Returns Zero on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) static int __init octeon_wdt_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 	octeon_wdt_bootvector = cvmx_boot_vector_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	if (!octeon_wdt_bootvector) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 		pr_err("Error: Cannot allocate boot vector.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	if (OCTEON_IS_MODEL(OCTEON_CN68XX))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 		divisor = 0x200;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 	else if (OCTEON_IS_MODEL(OCTEON_CN78XX))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 		divisor = 0x400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 		divisor = 0x100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	 * Watchdog time expiration length = The 16 bits of LEN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	 * represent the most significant bits of a 24 bit decrementer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	 * that decrements every divisor cycle.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	 * Try for a timeout of 5 sec, if that fails a smaller number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 	 * of even seconds,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 	max_timeout_sec = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 		max_timeout_sec--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 		timeout_cnt = ((octeon_get_io_clock_rate() / divisor) * max_timeout_sec) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 	} while (timeout_cnt > 65535);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 	BUG_ON(timeout_cnt == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 	octeon_wdt_calc_parameters(heartbeat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 	pr_info("Initial granularity %d Sec\n", timeout_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 	octeon_wdt.timeout	= timeout_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 	octeon_wdt.max_timeout	= UINT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 	watchdog_set_nowayout(&octeon_wdt, nowayout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 	ret = watchdog_register_device(&octeon_wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 		pr_err("watchdog_register_device() failed: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 	if (disable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 		pr_notice("disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 	cpumask_clear(&irq_enabled_cpus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "watchdog/octeon:online",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 				octeon_wdt_cpu_online, octeon_wdt_cpu_pre_down);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 		goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 	octeon_wdt_online = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 	watchdog_unregister_device(&octeon_wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)  * Module / driver shutdown
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) static void __exit octeon_wdt_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 	watchdog_unregister_device(&octeon_wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 	if (disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	cpuhp_remove_state(octeon_wdt_online);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 	 * Disable the boot-bus memory, the code it points to is soon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 	 * to go missing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 	cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) MODULE_AUTHOR("Cavium Inc. <support@cavium.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) MODULE_DESCRIPTION("Cavium Inc. OCTEON Watchdog driver.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) module_init(octeon_wdt_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) module_exit(octeon_wdt_cleanup);