cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

it87_wdt.c (7445B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *	Watchdog Timer Driver
      4 *	   for ITE IT87xx Environment Control - Low Pin Count Input / Output
      5 *
      6 *	(c) Copyright 2007  Oliver Schuster <olivers137@aol.com>
      7 *
      8 *	Based on softdog.c	by Alan Cox,
      9 *		 83977f_wdt.c	by Jose Goncalves,
     10 *		 it87.c		by Chris Gauthron, Jean Delvare
     11 *
     12 *	Data-sheets: Publicly available at the ITE website
     13 *		    http://www.ite.com.tw/
     14 *
     15 *	Support of the watchdog timers, which are available on
     16 *	IT8607, IT8620, IT8622, IT8625, IT8628, IT8655, IT8665, IT8686,
     17 *	IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726, IT8728,
     18 *	IT8772, IT8783 and IT8784.
     19 */
     20
     21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     22
     23#include <linux/init.h>
     24#include <linux/io.h>
     25#include <linux/kernel.h>
     26#include <linux/module.h>
     27#include <linux/moduleparam.h>
     28#include <linux/types.h>
     29#include <linux/watchdog.h>
     30
     31#define WATCHDOG_NAME		"IT87 WDT"
     32
     33/* Defaults for Module Parameter */
     34#define DEFAULT_TIMEOUT		60
     35#define DEFAULT_TESTMODE	0
     36#define DEFAULT_NOWAYOUT	WATCHDOG_NOWAYOUT
     37
     38/* IO Ports */
     39#define REG		0x2e
     40#define VAL		0x2f
     41
     42/* Logical device Numbers LDN */
     43#define GPIO		0x07
     44
     45/* Configuration Registers and Functions */
     46#define LDNREG		0x07
     47#define CHIPID		0x20
     48#define CHIPREV		0x22
     49
     50/* Chip Id numbers */
     51#define NO_DEV_ID	0xffff
     52#define IT8607_ID	0x8607
     53#define IT8620_ID	0x8620
     54#define IT8622_ID	0x8622
     55#define IT8625_ID	0x8625
     56#define IT8628_ID	0x8628
     57#define IT8655_ID	0x8655
     58#define IT8665_ID	0x8665
     59#define IT8686_ID	0x8686
     60#define IT8702_ID	0x8702
     61#define IT8705_ID	0x8705
     62#define IT8712_ID	0x8712
     63#define IT8716_ID	0x8716
     64#define IT8718_ID	0x8718
     65#define IT8720_ID	0x8720
     66#define IT8721_ID	0x8721
     67#define IT8726_ID	0x8726	/* the data sheet suggest wrongly 0x8716 */
     68#define IT8728_ID	0x8728
     69#define IT8772_ID	0x8772
     70#define IT8783_ID	0x8783
     71#define IT8784_ID	0x8784
     72#define IT8786_ID	0x8786
     73
     74/* GPIO Configuration Registers LDN=0x07 */
     75#define WDTCTRL		0x71
     76#define WDTCFG		0x72
     77#define WDTVALLSB	0x73
     78#define WDTVALMSB	0x74
     79
     80/* GPIO Bits WDTCFG */
     81#define WDT_TOV1	0x80
     82#define WDT_KRST	0x40
     83#define WDT_TOVE	0x20
     84#define WDT_PWROK	0x10 /* not in it8721 */
     85#define WDT_INT_MASK	0x0f
     86
     87static unsigned int max_units, chip_type;
     88
     89static unsigned int timeout = DEFAULT_TIMEOUT;
     90static int testmode = DEFAULT_TESTMODE;
     91static bool nowayout = DEFAULT_NOWAYOUT;
     92
     93module_param(timeout, int, 0);
     94MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
     95		__MODULE_STRING(DEFAULT_TIMEOUT));
     96module_param(testmode, int, 0);
     97MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
     98		__MODULE_STRING(DEFAULT_TESTMODE));
     99module_param(nowayout, bool, 0);
    100MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
    101		__MODULE_STRING(WATCHDOG_NOWAYOUT));
    102
    103/* Superio Chip */
    104
    105static inline int superio_enter(void)
    106{
    107	/*
    108	 * Try to reserve REG and REG + 1 for exclusive access.
    109	 */
    110	if (!request_muxed_region(REG, 2, WATCHDOG_NAME))
    111		return -EBUSY;
    112
    113	outb(0x87, REG);
    114	outb(0x01, REG);
    115	outb(0x55, REG);
    116	outb(0x55, REG);
    117	return 0;
    118}
    119
    120static inline void superio_exit(void)
    121{
    122	outb(0x02, REG);
    123	outb(0x02, VAL);
    124	release_region(REG, 2);
    125}
    126
    127static inline void superio_select(int ldn)
    128{
    129	outb(LDNREG, REG);
    130	outb(ldn, VAL);
    131}
    132
    133static inline int superio_inb(int reg)
    134{
    135	outb(reg, REG);
    136	return inb(VAL);
    137}
    138
    139static inline void superio_outb(int val, int reg)
    140{
    141	outb(reg, REG);
    142	outb(val, VAL);
    143}
    144
    145static inline int superio_inw(int reg)
    146{
    147	int val;
    148	outb(reg++, REG);
    149	val = inb(VAL) << 8;
    150	outb(reg, REG);
    151	val |= inb(VAL);
    152	return val;
    153}
    154
    155/* Internal function, should be called after superio_select(GPIO) */
    156static void _wdt_update_timeout(unsigned int t)
    157{
    158	unsigned char cfg = WDT_KRST;
    159
    160	if (testmode)
    161		cfg = 0;
    162
    163	if (t <= max_units)
    164		cfg |= WDT_TOV1;
    165	else
    166		t /= 60;
    167
    168	if (chip_type != IT8721_ID)
    169		cfg |= WDT_PWROK;
    170
    171	superio_outb(cfg, WDTCFG);
    172	superio_outb(t, WDTVALLSB);
    173	if (max_units > 255)
    174		superio_outb(t >> 8, WDTVALMSB);
    175}
    176
    177static int wdt_update_timeout(unsigned int t)
    178{
    179	int ret;
    180
    181	ret = superio_enter();
    182	if (ret)
    183		return ret;
    184
    185	superio_select(GPIO);
    186	_wdt_update_timeout(t);
    187	superio_exit();
    188
    189	return 0;
    190}
    191
    192static int wdt_round_time(int t)
    193{
    194	t += 59;
    195	t -= t % 60;
    196	return t;
    197}
    198
    199/* watchdog timer handling */
    200
    201static int wdt_start(struct watchdog_device *wdd)
    202{
    203	return wdt_update_timeout(wdd->timeout);
    204}
    205
    206static int wdt_stop(struct watchdog_device *wdd)
    207{
    208	return wdt_update_timeout(0);
    209}
    210
    211/**
    212 *	wdt_set_timeout - set a new timeout value with watchdog ioctl
    213 *	@t: timeout value in seconds
    214 *
    215 *	The hardware device has a 8 or 16 bit watchdog timer (depends on
    216 *	chip version) that can be configured to count seconds or minutes.
    217 *
    218 *	Used within WDIOC_SETTIMEOUT watchdog device ioctl.
    219 */
    220
    221static int wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
    222{
    223	int ret = 0;
    224
    225	if (t > max_units)
    226		t = wdt_round_time(t);
    227
    228	wdd->timeout = t;
    229
    230	if (watchdog_hw_running(wdd))
    231		ret = wdt_update_timeout(t);
    232
    233	return ret;
    234}
    235
    236static const struct watchdog_info ident = {
    237	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
    238	.firmware_version = 1,
    239	.identity = WATCHDOG_NAME,
    240};
    241
    242static const struct watchdog_ops wdt_ops = {
    243	.owner = THIS_MODULE,
    244	.start = wdt_start,
    245	.stop = wdt_stop,
    246	.set_timeout = wdt_set_timeout,
    247};
    248
    249static struct watchdog_device wdt_dev = {
    250	.info = &ident,
    251	.ops = &wdt_ops,
    252	.min_timeout = 1,
    253};
    254
    255static int __init it87_wdt_init(void)
    256{
    257	u8  chip_rev;
    258	int rc;
    259
    260	rc = superio_enter();
    261	if (rc)
    262		return rc;
    263
    264	chip_type = superio_inw(CHIPID);
    265	chip_rev  = superio_inb(CHIPREV) & 0x0f;
    266	superio_exit();
    267
    268	switch (chip_type) {
    269	case IT8702_ID:
    270		max_units = 255;
    271		break;
    272	case IT8712_ID:
    273		max_units = (chip_rev < 8) ? 255 : 65535;
    274		break;
    275	case IT8716_ID:
    276	case IT8726_ID:
    277		max_units = 65535;
    278		break;
    279	case IT8607_ID:
    280	case IT8620_ID:
    281	case IT8622_ID:
    282	case IT8625_ID:
    283	case IT8628_ID:
    284	case IT8655_ID:
    285	case IT8665_ID:
    286	case IT8686_ID:
    287	case IT8718_ID:
    288	case IT8720_ID:
    289	case IT8721_ID:
    290	case IT8728_ID:
    291	case IT8772_ID:
    292	case IT8783_ID:
    293	case IT8784_ID:
    294	case IT8786_ID:
    295		max_units = 65535;
    296		break;
    297	case IT8705_ID:
    298		pr_err("Unsupported Chip found, Chip %04x Revision %02x\n",
    299		       chip_type, chip_rev);
    300		return -ENODEV;
    301	case NO_DEV_ID:
    302		pr_err("no device\n");
    303		return -ENODEV;
    304	default:
    305		pr_err("Unknown Chip found, Chip %04x Revision %04x\n",
    306		       chip_type, chip_rev);
    307		return -ENODEV;
    308	}
    309
    310	rc = superio_enter();
    311	if (rc)
    312		return rc;
    313
    314	superio_select(GPIO);
    315	superio_outb(WDT_TOV1, WDTCFG);
    316	superio_outb(0x00, WDTCTRL);
    317	superio_exit();
    318
    319	if (timeout < 1 || timeout > max_units * 60) {
    320		timeout = DEFAULT_TIMEOUT;
    321		pr_warn("Timeout value out of range, use default %d sec\n",
    322			DEFAULT_TIMEOUT);
    323	}
    324
    325	if (timeout > max_units)
    326		timeout = wdt_round_time(timeout);
    327
    328	wdt_dev.timeout = timeout;
    329	wdt_dev.max_timeout = max_units * 60;
    330
    331	watchdog_stop_on_reboot(&wdt_dev);
    332	rc = watchdog_register_device(&wdt_dev);
    333	if (rc) {
    334		pr_err("Cannot register watchdog device (err=%d)\n", rc);
    335		return rc;
    336	}
    337
    338	pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
    339		chip_type, chip_rev, timeout, nowayout, testmode);
    340
    341	return 0;
    342}
    343
    344static void __exit it87_wdt_exit(void)
    345{
    346	watchdog_unregister_device(&wdt_dev);
    347}
    348
    349module_init(it87_wdt_init);
    350module_exit(it87_wdt_exit);
    351
    352MODULE_AUTHOR("Oliver Schuster");
    353MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O");
    354MODULE_LICENSE("GPL");