^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Intel_SCU 0.2: An Intel SCU IOH Based Watchdog Device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * for Intel part #(s):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * - AF82MP20 PCH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/miscdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/watchdog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/sfi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <asm/intel_scu_ipc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/apb_timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <asm/intel-mid.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include "intel_scu_watchdog.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /* Bounds number of times we will retry loading time count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* This retry is a work around for a silicon bug. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define MAX_RETRY 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define IPC_SET_WATCHDOG_TIMER 0xF8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static int timer_margin = DEFAULT_SOFT_TO_HARD_MARGIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) module_param(timer_margin, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) MODULE_PARM_DESC(timer_margin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) "Watchdog timer margin"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) "Time between interrupt and resetting the system"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) "The range is from 1 to 160"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) "This is the time for all keep alives to arrive");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int timer_set = DEFAULT_TIME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) module_param(timer_set, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) MODULE_PARM_DESC(timer_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) "Default Watchdog timer setting"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) "Complete cycle time"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) "The range is from 1 to 170"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) "This is the time for all keep alives to arrive");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* After watchdog device is closed, check force_boot. If:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * force_boot == 0, then force boot on next watchdog interrupt after close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * force_boot == 1, then force boot immediately when device is closed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int force_boot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) module_param(force_boot, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) MODULE_PARM_DESC(force_boot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) "A value of 1 means that the driver will reboot"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) "the system immediately if the /dev/watchdog device is closed"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) "A value of 0 means that when /dev/watchdog device is closed"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) "the watchdog timer will be refreshed for one more interval"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) "of length: timer_set. At the end of this interval, the"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) "watchdog timer will reset the system."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* there is only one device in the system now; this can be made into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * an array in the future if we have more than one device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static struct intel_scu_watchdog_dev watchdog_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* Forces restart, if force_reboot is set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static void watchdog_fire(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (force_boot) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) pr_crit("Initiating system reboot\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) emergency_restart();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) pr_crit("Reboot didn't ?????\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) pr_crit("Immediate Reboot Disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) pr_crit("System will reset when watchdog timer times out!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static int check_timer_margin(int new_margin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if ((new_margin < MIN_TIME_CYCLE) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) (new_margin > MAX_TIME - timer_set)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) pr_debug("value of new_margin %d is out of the range %d to %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * IPC operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static int watchdog_set_ipc(int soft_threshold, int threshold)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) u32 *ipc_wbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) u8 cbuf[16] = { '\0' };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int ipc_ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) ipc_wbuf = (u32 *)&cbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) ipc_wbuf[0] = soft_threshold;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ipc_wbuf[1] = threshold;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) ipc_ret = intel_scu_ipc_command(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) IPC_SET_WATCHDOG_TIMER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) ipc_wbuf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (ipc_ret != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return ipc_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * Intel_SCU operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* timer interrupt handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) int int_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) pr_debug("irq, int_status: %x\n", int_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (int_status != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /* has the timer been started? If not, then this is spurious */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (watchdog_device.timer_started == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) pr_debug("spurious interrupt received\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* temporarily disable the timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) iowrite32(0x00000002, watchdog_device.timer_control_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* set the timer to the threshold */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) iowrite32(watchdog_device.threshold,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) watchdog_device.timer_load_count_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* allow the timer to run */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) iowrite32(0x00000003, watchdog_device.timer_control_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return IRQ_HANDLED;
^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) static int intel_scu_keepalive(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* read eoi register - clears interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) ioread32(watchdog_device.timer_clear_interrupt_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /* temporarily disable the timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) iowrite32(0x00000002, watchdog_device.timer_control_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) /* set the timer to the soft_threshold */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) iowrite32(watchdog_device.soft_threshold,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) watchdog_device.timer_load_count_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /* allow the timer to run */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) iowrite32(0x00000003, watchdog_device.timer_control_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return 0;
^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 int intel_scu_stop(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) iowrite32(0, watchdog_device.timer_control_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static int intel_scu_set_heartbeat(u32 t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) int ipc_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) int retry_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) u32 soft_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) u32 hw_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) watchdog_device.timer_set = t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) watchdog_device.threshold =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) watchdog_device.soft_threshold =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) (watchdog_device.timer_set - timer_margin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * watchdog_device.timer_tbl_ptr->freq_hz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) pr_debug("set_heartbeat: timer freq is %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) watchdog_device.timer_tbl_ptr->freq_hz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) pr_debug("set_heartbeat: timer_set is %x (hex)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) watchdog_device.timer_set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) pr_debug("set_heartbeat: timer_margin is %x (hex)\n", timer_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) pr_debug("set_heartbeat: threshold is %x (hex)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) watchdog_device.threshold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) pr_debug("set_heartbeat: soft_threshold is %x (hex)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) watchdog_device.soft_threshold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /* watchdog timing come out right. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) watchdog_device.threshold =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) watchdog_device.threshold / FREQ_ADJUSTMENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) watchdog_device.soft_threshold =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) watchdog_device.soft_threshold / FREQ_ADJUSTMENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /* temporarily disable the timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) iowrite32(0x00000002, watchdog_device.timer_control_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /* send the threshold and soft_threshold via IPC to the processor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) ipc_ret = watchdog_set_ipc(watchdog_device.soft_threshold,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) watchdog_device.threshold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (ipc_ret != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /* Make sure the watchdog timer is stopped */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) intel_scu_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return ipc_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /* Soft Threshold set loop. Early versions of silicon did */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* not always set this count correctly. This loop checks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) /* the value and retries if it was not set correctly. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) retry_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) soft_value = watchdog_device.soft_threshold & 0xFFFF0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /* Make sure timer is stopped */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) intel_scu_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (MAX_RETRY < retry_count++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /* Unable to set timer value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) pr_err("Unable to set timer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /* set the timer to the soft threshold */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) iowrite32(watchdog_device.soft_threshold,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) watchdog_device.timer_load_count_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* read count value before starting timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) ioread32(watchdog_device.timer_load_count_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* Start the timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) iowrite32(0x00000003, watchdog_device.timer_control_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /* read the value the time loaded into its count reg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) hw_value = ioread32(watchdog_device.timer_load_count_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) hw_value = hw_value & 0xFFFF0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) } while (soft_value != hw_value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) watchdog_device.timer_started = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * /dev/watchdog handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) static int intel_scu_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /* Set flag to indicate that watchdog device is open */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (test_and_set_bit(0, &watchdog_device.driver_open))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /* Check for reopen of driver. Reopens are not allowed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (watchdog_device.driver_closed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return stream_open(inode, file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static int intel_scu_release(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * This watchdog should not be closed, after the timer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * is started with the WDIPC_SETTIMEOUT ioctl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * If force_boot is set watchdog_fire() will cause an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * immediate reset. If force_boot is not set, the watchdog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) * timer is refreshed for one more interval. At the end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) * of that interval, the watchdog timer will reset the system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (!test_and_clear_bit(0, &watchdog_device.driver_open)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) pr_debug("intel_scu_release, without open\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (!watchdog_device.timer_started) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* Just close, since timer has not been started */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) pr_debug("closed, without starting timer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) pr_crit("Unexpected close of /dev/watchdog!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) /* Since the timer was started, prevent future reopens */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) watchdog_device.driver_closed = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* Refresh the timer for one more interval */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) intel_scu_keepalive();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* Reboot system (if force_boot is set) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) watchdog_fire();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) /* We should only reach this point if force_boot is not set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static ssize_t intel_scu_write(struct file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) char const *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (watchdog_device.timer_started)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) /* Watchdog already started, keep it alive */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) intel_scu_keepalive();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) /* Start watchdog with timer value set by init */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) intel_scu_set_heartbeat(watchdog_device.timer_set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static long intel_scu_ioctl(struct file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) unsigned int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) void __user *argp = (void __user *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) u32 __user *p = argp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) u32 new_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) static const struct watchdog_info ident = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) .options = WDIOF_SETTIMEOUT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) | WDIOF_KEEPALIVEPING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) .firmware_version = 0, /* @todo Get from SCU via
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ipc_get_scu_fw_version()? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) .identity = "Intel_SCU IOH Watchdog" /* len < 32 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) case WDIOC_GETSUPPORT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return copy_to_user(argp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) &ident,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) sizeof(ident)) ? -EFAULT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) case WDIOC_GETSTATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) case WDIOC_GETBOOTSTATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) return put_user(0, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) case WDIOC_KEEPALIVE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) intel_scu_keepalive();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) case WDIOC_SETTIMEOUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (get_user(new_margin, p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (check_timer_margin(new_margin))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (intel_scu_set_heartbeat(new_margin))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) case WDIOC_GETTIMEOUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return put_user(watchdog_device.soft_threshold, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * Notifier for system down
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static int intel_scu_notify_sys(struct notifier_block *this,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) unsigned long code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) void *another_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (code == SYS_DOWN || code == SYS_HALT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* Turn off the watchdog timer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) intel_scu_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) * Kernel Interfaces
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) static const struct file_operations intel_scu_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) .llseek = no_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) .write = intel_scu_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) .unlocked_ioctl = intel_scu_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) .compat_ioctl = compat_ptr_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) .open = intel_scu_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) .release = intel_scu_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static int __init intel_scu_watchdog_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) u32 __iomem *tmp_addr;
^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) * We don't really need to check this as the SFI timer get will fail
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * but if we do so we can exit with a clearer reason and no noise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * If it isn't an intel MID device then it doesn't have this watchdog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (!intel_mid_identify_cpu())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) /* Check boot parameters to verify that their initial values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* are in range. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) /* Check value of timer_set boot parameter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) if ((timer_set < MIN_TIME_CYCLE) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) (timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) pr_err("value of timer_set %x (hex) is out of range from %x to %x (hex)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) /* Check value of timer_margin boot parameter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (check_timer_margin(timer_margin))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (watchdog_device.timer_tbl_ptr == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) pr_debug("timer is not available\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) /* make sure the timer exists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (watchdog_device.timer_tbl_ptr->phys_addr == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) pr_debug("timer %d does not have valid physical memory\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) sfi_mtimer_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (watchdog_device.timer_tbl_ptr->irq == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) pr_debug("timer %d invalid irq\n", sfi_mtimer_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) tmp_addr = ioremap(watchdog_device.timer_tbl_ptr->phys_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (tmp_addr == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) pr_debug("timer unable to ioremap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) watchdog_device.timer_load_count_addr = tmp_addr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) watchdog_device.timer_current_value_addr = tmp_addr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) watchdog_device.timer_control_addr = tmp_addr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) watchdog_device.timer_clear_interrupt_addr = tmp_addr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) watchdog_device.timer_interrupt_status_addr = tmp_addr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) /* Set the default time values in device structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) watchdog_device.timer_set = timer_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) watchdog_device.threshold =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) watchdog_device.soft_threshold =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) (watchdog_device.timer_set - timer_margin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) * watchdog_device.timer_tbl_ptr->freq_hz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) watchdog_device.intel_scu_notifier.notifier_call =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) intel_scu_notify_sys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) pr_err("cannot register notifier %d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) goto register_reboot_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) watchdog_device.miscdev.minor = WATCHDOG_MINOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) watchdog_device.miscdev.name = "watchdog";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) watchdog_device.miscdev.fops = &intel_scu_fops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) ret = misc_register(&watchdog_device.miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) pr_err("cannot register miscdev %d err =%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) WATCHDOG_MINOR, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) goto misc_register_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) ret = request_irq((unsigned int)watchdog_device.timer_tbl_ptr->irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) watchdog_timer_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) IRQF_SHARED, "watchdog",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) &watchdog_device.timer_load_count_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) pr_err("error requesting irq %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) goto request_irq_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /* Make sure timer is disabled before returning */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) intel_scu_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /* error cleanup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) request_irq_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) misc_deregister(&watchdog_device.miscdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) misc_register_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) register_reboot_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) intel_scu_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) iounmap(watchdog_device.timer_load_count_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) late_initcall(intel_scu_watchdog_init);