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-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);