// SPDX-License-Identifier: GPL-2.0+ /* * Octeon Watchdog driver * * Copyright (C) 2007-2017 Cavium, Inc. * * Converted to use WATCHDOG_CORE by Aaro Koskinen <aaro.koskinen@iki.fi>. * * Some parts derived from wdt.c * * (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>, * All Rights Reserved. * * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide * warranty for any of this software. This material is provided * "AS-IS" and at no charge. * * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> * * The OCTEON watchdog has a maximum timeout of 2^32 * io_clock. * For most systems this is less than 10 seconds, so to allow for * software to request longer watchdog heartbeats, we maintain software * counters to count multiples of the base rate. If the system locks * up in such a manner that we can not run the software counters, the * only result is a watchdog reset sooner than was requested. But * that is OK, because in this case userspace would likely not be able * to do anything anyhow. * * The hardware watchdog interval we call the period. The OCTEON * watchdog goes through several stages, after the first period an * irq is asserted, then if it is not reset, after the next period NMI * is asserted, then after an additional period a chip wide soft reset. * So for the software counters, we reset watchdog after each period * and decrement the counter. But for the last two periods we need to * let the watchdog progress to the NMI stage so we disable the irq * and let it proceed. Once in the NMI, we print the register state * to the serial port and then wait for the reset. * * A watchdog is maintained for each CPU in the system, that way if * one CPU suffers a lockup, we also get a register dump and reset. * The userspace ping resets the watchdog on all CPUs. * * Before userspace opens the watchdog device, we still run the * watchdogs to catch any lockups that may be kernel related. *
*/
/* Watchdog interrupt major block number (8 MSBs of intsn) */ #define WD_BLOCK_NUMBER 0x01
staticint divisor;
/* The count needed to achieve timeout_sec. */ staticunsignedint timeout_cnt;
/* The maximum period supported. */ staticunsignedint max_timeout_sec;
/* The current period. */ staticunsignedint timeout_sec;
/* Set to non-zero when userspace countdown mode active */ staticbool do_countdown; staticunsignedint countdown_reset; staticunsignedint per_cpu_countdown[NR_CPUS];
/** * octeon_wdt_poke_irq - Poke the watchdog when an interrupt is received * * @cpl: * @dev_id: * * Returns
*/ static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
{ int cpu = raw_smp_processor_id(); unsignedint core = cpu2core(cpu); int node = cpu_to_node(cpu);
if (do_countdown) { if (per_cpu_countdown[cpu] > 0) { /* We're alive, poke the watchdog */
cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
per_cpu_countdown[cpu]--;
} else { /* Bad news, you are about to reboot. */
disable_irq_nosync(cpl);
cpumask_clear_cpu(cpu, &irq_enabled_cpus);
}
} else { /* Not open, just ping away... */
cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
} return IRQ_HANDLED;
}
/* From setup.c */ externint prom_putchar(char c);
/** * octeon_wdt_write_string - Write a string to the uart * * @str: String to write
*/ staticvoid octeon_wdt_write_string(constchar *str)
{ /* Just loop writing one byte at a time */ while (*str)
prom_putchar(*str++);
}
/** * octeon_wdt_write_hex() - Write a hex number out of the uart * * @value: Number to display * @digits: Number of digits to print (1 to 16)
*/ staticvoid octeon_wdt_write_hex(u64 value, int digits)
{ int d; int v;
for (d = 0; d < digits; d++) {
v = (value >> ((digits - d - 1) * 4)) & 0xf; if (v >= 10)
prom_putchar('a' + v - 10); else
prom_putchar('0' + v);
}
}
/** * octeon_wdt_nmi_stage3: * * NMI stage 3 handler. NMIs are handled in the following manner: * 1) The first NMI handler enables CVMSEG and transfers from * the bootbus region into normal memory. It is careful to not * destroy any registers. * 2) The second stage handler uses CVMSEG to save the registers * and create a stack for C code. It then calls the third level * handler with one argument, a pointer to the register values. * 3) The third, and final, level handler is the following C * function that prints out some useful infomration. * * @reg: Pointer to register state before the NMI
*/ void octeon_wdt_nmi_stage3(u64 reg[32])
{
u64 i;
unsignedint coreid = cvmx_get_core_num(); /* * Save status and cause early to get them before any changes * might happen.
*/
u64 cp0_cause = read_c0_cause();
u64 cp0_status = read_c0_status();
u64 cp0_error_epc = read_c0_errorepc();
u64 cp0_epc = read_c0_epc();
/* Delay so output from all cores output is not jumbled together. */
udelay(85000 * coreid);
octeon_wdt_write_string("\r\n*** NMI Watchdog interrupt on Core 0x");
octeon_wdt_write_hex(coreid, 2);
octeon_wdt_write_string(" ***\r\n"); for (i = 0; i < 32; i++) {
octeon_wdt_write_string("\t");
octeon_wdt_write_string(reg_name[i]);
octeon_wdt_write_string("\t0x");
octeon_wdt_write_hex(reg[i], 16); if (i & 1)
octeon_wdt_write_string("\r\n");
}
octeon_wdt_write_string("\terr_epc\t0x");
octeon_wdt_write_hex(cp0_error_epc, 16);
/* * G-30204: We must trigger a soft reset before watchdog * does an incomplete job of doing it.
*/ if (OCTEON_IS_OCTEON3() && !OCTEON_IS_MODEL(OCTEON_CN70XX)) {
u64 scr; unsignedint node = cvmx_get_node_num(); unsignedint lcore = cvmx_get_local_core_num(); union cvmx_ciu_wdogx ciu_wdog;
/* * Wait for other cores to print out information, but * not too long. Do the soft reset before watchdog * can trigger it.
*/ do {
ciu_wdog.u64 = cvmx_read_csr_node(node, CVMX_CIU_WDOGX(lcore));
} while (ciu_wdog.s.cnt > 0x10000);
/* Disable it before doing anything with the interrupts. */
ciu_wdog.u64 = 0;
cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
per_cpu_countdown[cpu] = countdown_reset;
if (octeon_has_feature(OCTEON_FEATURE_CIU3)) { /* Must get the domain for the watchdog block */
domain = octeon_irq_get_block_domain(node, WD_BLOCK_NUMBER);
/* Get a irq for the wd intsn (hardware interrupt) */
hwirq = WD_BLOCK_NUMBER << 12 | 0x200 | core;
irq = irq_create_mapping(domain, hwirq);
irqd_set_trigger_type(irq_get_irq_data(irq),
IRQ_TYPE_EDGE_RISING);
} else
irq = OCTEON_IRQ_WDOG0 + core;
/* * Watchdog time expiration length = The 16 bits of LEN * represent the most significant bits of a 24 bit decrementer * that decrements every divisor cycle. * * Try for a timeout of 5 sec, if that fails a smaller number * of even seconds,
*/
max_timeout_sec = 6; do {
max_timeout_sec--;
timeout_cnt = ((octeon_get_io_clock_rate() / divisor) * max_timeout_sec) >> 8;
} while (timeout_cnt > 65535);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.