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

retu_wdt.c (4013B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Retu watchdog driver
      4 *
      5 * Copyright (C) 2004, 2005 Nokia Corporation
      6 *
      7 * Based on code written by Amit Kucheria and Michael Buesch.
      8 * Rewritten by Aaro Koskinen.
      9 */
     10
     11#include <linux/devm-helpers.h>
     12#include <linux/slab.h>
     13#include <linux/errno.h>
     14#include <linux/device.h>
     15#include <linux/kernel.h>
     16#include <linux/module.h>
     17#include <linux/mfd/retu.h>
     18#include <linux/watchdog.h>
     19#include <linux/platform_device.h>
     20
     21/* Watchdog timer values in seconds */
     22#define RETU_WDT_MAX_TIMER	63
     23
     24struct retu_wdt_dev {
     25	struct retu_dev		*rdev;
     26	struct device		*dev;
     27	struct delayed_work	ping_work;
     28};
     29
     30/*
     31 * Since Retu watchdog cannot be disabled in hardware, we must kick it
     32 * with a timer until userspace watchdog software takes over. If
     33 * CONFIG_WATCHDOG_NOWAYOUT is set, we never start the feeding.
     34 */
     35static void retu_wdt_ping_enable(struct retu_wdt_dev *wdev)
     36{
     37	retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER);
     38	schedule_delayed_work(&wdev->ping_work,
     39			round_jiffies_relative(RETU_WDT_MAX_TIMER * HZ / 2));
     40}
     41
     42static void retu_wdt_ping_disable(struct retu_wdt_dev *wdev)
     43{
     44	retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER);
     45	cancel_delayed_work_sync(&wdev->ping_work);
     46}
     47
     48static void retu_wdt_ping_work(struct work_struct *work)
     49{
     50	struct retu_wdt_dev *wdev = container_of(to_delayed_work(work),
     51						struct retu_wdt_dev, ping_work);
     52	retu_wdt_ping_enable(wdev);
     53}
     54
     55static int retu_wdt_start(struct watchdog_device *wdog)
     56{
     57	struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
     58
     59	retu_wdt_ping_disable(wdev);
     60
     61	return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
     62}
     63
     64static int retu_wdt_stop(struct watchdog_device *wdog)
     65{
     66	struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
     67
     68	retu_wdt_ping_enable(wdev);
     69
     70	return 0;
     71}
     72
     73static int retu_wdt_ping(struct watchdog_device *wdog)
     74{
     75	struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
     76
     77	return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
     78}
     79
     80static int retu_wdt_set_timeout(struct watchdog_device *wdog,
     81				unsigned int timeout)
     82{
     83	struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
     84
     85	wdog->timeout = timeout;
     86	return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
     87}
     88
     89static const struct watchdog_info retu_wdt_info = {
     90	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
     91	.identity = "Retu watchdog",
     92};
     93
     94static const struct watchdog_ops retu_wdt_ops = {
     95	.owner		= THIS_MODULE,
     96	.start		= retu_wdt_start,
     97	.stop		= retu_wdt_stop,
     98	.ping		= retu_wdt_ping,
     99	.set_timeout	= retu_wdt_set_timeout,
    100};
    101
    102static int retu_wdt_probe(struct platform_device *pdev)
    103{
    104	struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent);
    105	bool nowayout = WATCHDOG_NOWAYOUT;
    106	struct watchdog_device *retu_wdt;
    107	struct retu_wdt_dev *wdev;
    108	int ret;
    109
    110	retu_wdt = devm_kzalloc(&pdev->dev, sizeof(*retu_wdt), GFP_KERNEL);
    111	if (!retu_wdt)
    112		return -ENOMEM;
    113
    114	wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
    115	if (!wdev)
    116		return -ENOMEM;
    117
    118	retu_wdt->info		= &retu_wdt_info;
    119	retu_wdt->ops		= &retu_wdt_ops;
    120	retu_wdt->timeout	= RETU_WDT_MAX_TIMER;
    121	retu_wdt->min_timeout	= 0;
    122	retu_wdt->max_timeout	= RETU_WDT_MAX_TIMER;
    123	retu_wdt->parent	= &pdev->dev;
    124
    125	watchdog_set_drvdata(retu_wdt, wdev);
    126	watchdog_set_nowayout(retu_wdt, nowayout);
    127
    128	wdev->rdev		= rdev;
    129	wdev->dev		= &pdev->dev;
    130
    131	ret = devm_delayed_work_autocancel(&pdev->dev, &wdev->ping_work,
    132					   retu_wdt_ping_work);
    133	if (ret)
    134		return ret;
    135
    136	ret = devm_watchdog_register_device(&pdev->dev, retu_wdt);
    137	if (ret < 0)
    138		return ret;
    139
    140	if (nowayout)
    141		retu_wdt_ping(retu_wdt);
    142	else
    143		retu_wdt_ping_enable(wdev);
    144
    145	return 0;
    146}
    147
    148static struct platform_driver retu_wdt_driver = {
    149	.probe		= retu_wdt_probe,
    150	.driver		= {
    151		.name	= "retu-wdt",
    152	},
    153};
    154module_platform_driver(retu_wdt_driver);
    155
    156MODULE_ALIAS("platform:retu-wdt");
    157MODULE_DESCRIPTION("Retu watchdog");
    158MODULE_AUTHOR("Amit Kucheria");
    159MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
    160MODULE_LICENSE("GPL");