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

at91sam9_wdt.c (10662B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Watchdog driver for Atmel AT91SAM9x processors.
      4 *
      5 * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr
      6 *
      7 */
      8
      9/*
     10 * The Watchdog Timer Mode Register can be only written to once. If the
     11 * timeout need to be set from Linux, be sure that the bootstrap or the
     12 * bootloader doesn't write to this register.
     13 */
     14
     15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     16
     17#include <linux/clk.h>
     18#include <linux/errno.h>
     19#include <linux/init.h>
     20#include <linux/interrupt.h>
     21#include <linux/io.h>
     22#include <linux/kernel.h>
     23#include <linux/module.h>
     24#include <linux/moduleparam.h>
     25#include <linux/platform_device.h>
     26#include <linux/reboot.h>
     27#include <linux/types.h>
     28#include <linux/watchdog.h>
     29#include <linux/jiffies.h>
     30#include <linux/timer.h>
     31#include <linux/bitops.h>
     32#include <linux/uaccess.h>
     33#include <linux/of.h>
     34#include <linux/of_irq.h>
     35
     36#include "at91sam9_wdt.h"
     37
     38#define DRV_NAME "AT91SAM9 Watchdog"
     39
     40#define wdt_read(wdt, field) \
     41	readl_relaxed((wdt)->base + (field))
     42#define wdt_write(wtd, field, val) \
     43	writel_relaxed((val), (wdt)->base + (field))
     44
     45/* AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
     46 * use this to convert a watchdog
     47 * value from/to milliseconds.
     48 */
     49#define ticks_to_hz_rounddown(t)	((((t) + 1) * HZ) >> 8)
     50#define ticks_to_hz_roundup(t)		(((((t) + 1) * HZ) + 255) >> 8)
     51#define ticks_to_secs(t)		(((t) + 1) >> 8)
     52#define secs_to_ticks(s)		((s) ? (((s) << 8) - 1) : 0)
     53
     54#define WDT_MR_RESET	0x3FFF2FFF
     55
     56/* Watchdog max counter value in ticks */
     57#define WDT_COUNTER_MAX_TICKS	0xFFF
     58
     59/* Watchdog max delta/value in secs */
     60#define WDT_COUNTER_MAX_SECS	ticks_to_secs(WDT_COUNTER_MAX_TICKS)
     61
     62/* Hardware timeout in seconds */
     63#define WDT_HW_TIMEOUT 2
     64
     65/* Timer heartbeat (500ms) */
     66#define WDT_TIMEOUT	(HZ/2)
     67
     68/* User land timeout */
     69#define WDT_HEARTBEAT 15
     70static int heartbeat;
     71module_param(heartbeat, int, 0);
     72MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
     73	"(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
     74
     75static bool nowayout = WATCHDOG_NOWAYOUT;
     76module_param(nowayout, bool, 0);
     77MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
     78	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
     79
     80#define to_wdt(wdd) container_of(wdd, struct at91wdt, wdd)
     81struct at91wdt {
     82	struct watchdog_device wdd;
     83	void __iomem *base;
     84	unsigned long next_heartbeat;	/* the next_heartbeat for the timer */
     85	struct timer_list timer;	/* The timer that pings the watchdog */
     86	u32 mr;
     87	u32 mr_mask;
     88	unsigned long heartbeat;	/* WDT heartbeat in jiffies */
     89	bool nowayout;
     90	unsigned int irq;
     91	struct clk *sclk;
     92};
     93
     94/* ......................................................................... */
     95
     96static irqreturn_t wdt_interrupt(int irq, void *dev_id)
     97{
     98	struct at91wdt *wdt = (struct at91wdt *)dev_id;
     99
    100	if (wdt_read(wdt, AT91_WDT_SR)) {
    101		pr_crit("at91sam9 WDT software reset\n");
    102		emergency_restart();
    103		pr_crit("Reboot didn't ?????\n");
    104	}
    105
    106	return IRQ_HANDLED;
    107}
    108
    109/*
    110 * Reload the watchdog timer.  (ie, pat the watchdog)
    111 */
    112static inline void at91_wdt_reset(struct at91wdt *wdt)
    113{
    114	wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
    115}
    116
    117/*
    118 * Timer tick
    119 */
    120static void at91_ping(struct timer_list *t)
    121{
    122	struct at91wdt *wdt = from_timer(wdt, t, timer);
    123	if (time_before(jiffies, wdt->next_heartbeat) ||
    124	    !watchdog_active(&wdt->wdd)) {
    125		at91_wdt_reset(wdt);
    126		mod_timer(&wdt->timer, jiffies + wdt->heartbeat);
    127	} else {
    128		pr_crit("I will reset your machine !\n");
    129	}
    130}
    131
    132static int at91_wdt_start(struct watchdog_device *wdd)
    133{
    134	struct at91wdt *wdt = to_wdt(wdd);
    135	/* calculate when the next userspace timeout will be */
    136	wdt->next_heartbeat = jiffies + wdd->timeout * HZ;
    137	return 0;
    138}
    139
    140static int at91_wdt_stop(struct watchdog_device *wdd)
    141{
    142	/* The watchdog timer hardware can not be stopped... */
    143	return 0;
    144}
    145
    146static int at91_wdt_set_timeout(struct watchdog_device *wdd, unsigned int new_timeout)
    147{
    148	wdd->timeout = new_timeout;
    149	return at91_wdt_start(wdd);
    150}
    151
    152static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
    153{
    154	u32 tmp;
    155	u32 delta;
    156	u32 value;
    157	int err;
    158	u32 mask = wdt->mr_mask;
    159	unsigned long min_heartbeat = 1;
    160	unsigned long max_heartbeat;
    161	struct device *dev = &pdev->dev;
    162
    163	tmp = wdt_read(wdt, AT91_WDT_MR);
    164	if ((tmp & mask) != (wdt->mr & mask)) {
    165		if (tmp == WDT_MR_RESET) {
    166			wdt_write(wdt, AT91_WDT_MR, wdt->mr);
    167			tmp = wdt_read(wdt, AT91_WDT_MR);
    168		}
    169	}
    170
    171	if (tmp & AT91_WDT_WDDIS) {
    172		if (wdt->mr & AT91_WDT_WDDIS)
    173			return 0;
    174		dev_err(dev, "watchdog is disabled\n");
    175		return -EINVAL;
    176	}
    177
    178	value = tmp & AT91_WDT_WDV;
    179	delta = (tmp & AT91_WDT_WDD) >> 16;
    180
    181	if (delta < value)
    182		min_heartbeat = ticks_to_hz_roundup(value - delta);
    183
    184	max_heartbeat = ticks_to_hz_rounddown(value);
    185	if (!max_heartbeat) {
    186		dev_err(dev,
    187			"heartbeat is too small for the system to handle it correctly\n");
    188		return -EINVAL;
    189	}
    190
    191	/*
    192	 * Try to reset the watchdog counter 4 or 2 times more often than
    193	 * actually requested, to avoid spurious watchdog reset.
    194	 * If this is not possible because of the min_heartbeat value, reset
    195	 * it at the min_heartbeat period.
    196	 */
    197	if ((max_heartbeat / 4) >= min_heartbeat)
    198		wdt->heartbeat = max_heartbeat / 4;
    199	else if ((max_heartbeat / 2) >= min_heartbeat)
    200		wdt->heartbeat = max_heartbeat / 2;
    201	else
    202		wdt->heartbeat = min_heartbeat;
    203
    204	if (max_heartbeat < min_heartbeat + 4)
    205		dev_warn(dev,
    206			 "min heartbeat and max heartbeat might be too close for the system to handle it correctly\n");
    207
    208	if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) {
    209		err = request_irq(wdt->irq, wdt_interrupt,
    210				  IRQF_SHARED | IRQF_IRQPOLL |
    211				  IRQF_NO_SUSPEND,
    212				  pdev->name, wdt);
    213		if (err)
    214			return err;
    215	}
    216
    217	if ((tmp & wdt->mr_mask) != (wdt->mr & wdt->mr_mask))
    218		dev_warn(dev,
    219			 "watchdog already configured differently (mr = %x expecting %x)\n",
    220			 tmp & wdt->mr_mask, wdt->mr & wdt->mr_mask);
    221
    222	timer_setup(&wdt->timer, at91_ping, 0);
    223
    224	/*
    225	 * Use min_heartbeat the first time to avoid spurious watchdog reset:
    226	 * we don't know for how long the watchdog counter is running, and
    227	 *  - resetting it right now might trigger a watchdog fault reset
    228	 *  - waiting for heartbeat time might lead to a watchdog timeout
    229	 *    reset
    230	 */
    231	mod_timer(&wdt->timer, jiffies + min_heartbeat);
    232
    233	/* Try to set timeout from device tree first */
    234	if (watchdog_init_timeout(&wdt->wdd, 0, dev))
    235		watchdog_init_timeout(&wdt->wdd, heartbeat, dev);
    236	watchdog_set_nowayout(&wdt->wdd, wdt->nowayout);
    237	err = watchdog_register_device(&wdt->wdd);
    238	if (err)
    239		goto out_stop_timer;
    240
    241	wdt->next_heartbeat = jiffies + wdt->wdd.timeout * HZ;
    242
    243	return 0;
    244
    245out_stop_timer:
    246	del_timer(&wdt->timer);
    247	return err;
    248}
    249
    250/* ......................................................................... */
    251
    252static const struct watchdog_info at91_wdt_info = {
    253	.identity	= DRV_NAME,
    254	.options	= WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
    255						WDIOF_MAGICCLOSE,
    256};
    257
    258static const struct watchdog_ops at91_wdt_ops = {
    259	.owner =	THIS_MODULE,
    260	.start =	at91_wdt_start,
    261	.stop =		at91_wdt_stop,
    262	.set_timeout =	at91_wdt_set_timeout,
    263};
    264
    265#if defined(CONFIG_OF)
    266static int of_at91wdt_init(struct device_node *np, struct at91wdt *wdt)
    267{
    268	u32 min = 0;
    269	u32 max = WDT_COUNTER_MAX_SECS;
    270	const char *tmp;
    271
    272	/* Get the interrupts property */
    273	wdt->irq = irq_of_parse_and_map(np, 0);
    274	if (!wdt->irq)
    275		dev_warn(wdt->wdd.parent, "failed to get IRQ from DT\n");
    276
    277	if (!of_property_read_u32_index(np, "atmel,max-heartbeat-sec", 0,
    278					&max)) {
    279		if (!max || max > WDT_COUNTER_MAX_SECS)
    280			max = WDT_COUNTER_MAX_SECS;
    281
    282		if (!of_property_read_u32_index(np, "atmel,min-heartbeat-sec",
    283						0, &min)) {
    284			if (min >= max)
    285				min = max - 1;
    286		}
    287	}
    288
    289	min = secs_to_ticks(min);
    290	max = secs_to_ticks(max);
    291
    292	wdt->mr_mask = 0x3FFFFFFF;
    293	wdt->mr = 0;
    294	if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) &&
    295	    !strcmp(tmp, "software")) {
    296		wdt->mr |= AT91_WDT_WDFIEN;
    297		wdt->mr_mask &= ~AT91_WDT_WDRPROC;
    298	} else {
    299		wdt->mr |= AT91_WDT_WDRSTEN;
    300	}
    301
    302	if (!of_property_read_string(np, "atmel,reset-type", &tmp) &&
    303	    !strcmp(tmp, "proc"))
    304		wdt->mr |= AT91_WDT_WDRPROC;
    305
    306	if (of_property_read_bool(np, "atmel,disable")) {
    307		wdt->mr |= AT91_WDT_WDDIS;
    308		wdt->mr_mask &= AT91_WDT_WDDIS;
    309	}
    310
    311	if (of_property_read_bool(np, "atmel,idle-halt"))
    312		wdt->mr |= AT91_WDT_WDIDLEHLT;
    313
    314	if (of_property_read_bool(np, "atmel,dbg-halt"))
    315		wdt->mr |= AT91_WDT_WDDBGHLT;
    316
    317	wdt->mr |= max | ((max - min) << 16);
    318
    319	return 0;
    320}
    321#else
    322static inline int of_at91wdt_init(struct device_node *np, struct at91wdt *wdt)
    323{
    324	return 0;
    325}
    326#endif
    327
    328static int __init at91wdt_probe(struct platform_device *pdev)
    329{
    330	int err;
    331	struct at91wdt *wdt;
    332
    333	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
    334	if (!wdt)
    335		return -ENOMEM;
    336
    337	wdt->mr = (WDT_HW_TIMEOUT * 256) | AT91_WDT_WDRSTEN | AT91_WDT_WDD |
    338		  AT91_WDT_WDDBGHLT | AT91_WDT_WDIDLEHLT;
    339	wdt->mr_mask = 0x3FFFFFFF;
    340	wdt->nowayout = nowayout;
    341	wdt->wdd.parent = &pdev->dev;
    342	wdt->wdd.info = &at91_wdt_info;
    343	wdt->wdd.ops = &at91_wdt_ops;
    344	wdt->wdd.timeout = WDT_HEARTBEAT;
    345	wdt->wdd.min_timeout = 1;
    346	wdt->wdd.max_timeout = 0xFFFF;
    347
    348	wdt->base = devm_platform_ioremap_resource(pdev, 0);
    349	if (IS_ERR(wdt->base))
    350		return PTR_ERR(wdt->base);
    351
    352	wdt->sclk = devm_clk_get(&pdev->dev, NULL);
    353	if (IS_ERR(wdt->sclk))
    354		return PTR_ERR(wdt->sclk);
    355
    356	err = clk_prepare_enable(wdt->sclk);
    357	if (err) {
    358		dev_err(&pdev->dev, "Could not enable slow clock\n");
    359		return err;
    360	}
    361
    362	if (pdev->dev.of_node) {
    363		err = of_at91wdt_init(pdev->dev.of_node, wdt);
    364		if (err)
    365			goto err_clk;
    366	}
    367
    368	err = at91_wdt_init(pdev, wdt);
    369	if (err)
    370		goto err_clk;
    371
    372	platform_set_drvdata(pdev, wdt);
    373
    374	pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n",
    375		wdt->wdd.timeout, wdt->nowayout);
    376
    377	return 0;
    378
    379err_clk:
    380	clk_disable_unprepare(wdt->sclk);
    381
    382	return err;
    383}
    384
    385static int __exit at91wdt_remove(struct platform_device *pdev)
    386{
    387	struct at91wdt *wdt = platform_get_drvdata(pdev);
    388	watchdog_unregister_device(&wdt->wdd);
    389
    390	pr_warn("I quit now, hardware will probably reboot!\n");
    391	del_timer(&wdt->timer);
    392	clk_disable_unprepare(wdt->sclk);
    393
    394	return 0;
    395}
    396
    397#if defined(CONFIG_OF)
    398static const struct of_device_id at91_wdt_dt_ids[] = {
    399	{ .compatible = "atmel,at91sam9260-wdt" },
    400	{ /* sentinel */ }
    401};
    402
    403MODULE_DEVICE_TABLE(of, at91_wdt_dt_ids);
    404#endif
    405
    406static struct platform_driver at91wdt_driver = {
    407	.remove		= __exit_p(at91wdt_remove),
    408	.driver		= {
    409		.name	= "at91_wdt",
    410		.of_match_table = of_match_ptr(at91_wdt_dt_ids),
    411	},
    412};
    413
    414module_platform_driver_probe(at91wdt_driver, at91wdt_probe);
    415
    416MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>");
    417MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
    418MODULE_LICENSE("GPL");