Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/watchdog/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 7 kB image not shown  

Quelle  keembay_wdt.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Watchdog driver for Intel Keem Bay non-secure watchdog.
 *
 * Copyright (C) 2020 Intel Corporation
 */


#include <linux/arm-smccc.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/watchdog.h>

/* Non-secure watchdog register offsets */
#define TIM_WATCHDOG  0x0
#define TIM_WATCHDOG_INT_THRES 0x4
#define TIM_WDOG_EN  0x8
#define TIM_SAFE  0xc

#define WDT_TH_INT_MASK  BIT(8)
#define WDT_TO_INT_MASK  BIT(9)
#define WDT_INT_CLEAR_SMC 0x8200ff18

#define WDT_UNLOCK  0xf1d0dead
#define WDT_DISABLE  0x0
#define WDT_ENABLE  0x1

#define WDT_LOAD_MAX  U32_MAX
#define WDT_LOAD_MIN  1

#define WDT_TIMEOUT  5
#define WDT_PRETIMEOUT  4

static unsigned int timeout = WDT_TIMEOUT;
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout period in seconds (default = "
   __MODULE_STRING(WDT_TIMEOUT) ")");

static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default = "
   __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");

struct keembay_wdt {
 struct watchdog_device wdd;
 struct clk  *clk;
 unsigned int  rate;
 int   to_irq;
 int   th_irq;
 void __iomem  *base;
};

static inline u32 keembay_wdt_readl(struct keembay_wdt *wdt, u32 offset)
{
 return readl(wdt->base + offset);
}

static inline void keembay_wdt_writel(struct keembay_wdt *wdt, u32 offset, u32 val)
{
 writel(WDT_UNLOCK, wdt->base + TIM_SAFE);
 writel(val, wdt->base + offset);
}

static void keembay_wdt_set_timeout_reg(struct watchdog_device *wdog)
{
 struct keembay_wdt *wdt = watchdog_get_drvdata(wdog);

 keembay_wdt_writel(wdt, TIM_WATCHDOG, wdog->timeout * wdt->rate);
}

static void keembay_wdt_set_pretimeout_reg(struct watchdog_device *wdog)
{
 struct keembay_wdt *wdt = watchdog_get_drvdata(wdog);
 u32 th_val = 0;

 if (wdog->pretimeout)
  th_val = wdog->timeout - wdog->pretimeout;

 keembay_wdt_writel(wdt, TIM_WATCHDOG_INT_THRES, th_val * wdt->rate);
}

static int keembay_wdt_start(struct watchdog_device *wdog)
{
 struct keembay_wdt *wdt = watchdog_get_drvdata(wdog);

 keembay_wdt_writel(wdt, TIM_WDOG_EN, WDT_ENABLE);

 return 0;
}

static int keembay_wdt_stop(struct watchdog_device *wdog)
{
 struct keembay_wdt *wdt = watchdog_get_drvdata(wdog);

 keembay_wdt_writel(wdt, TIM_WDOG_EN, WDT_DISABLE);

 return 0;
}

static int keembay_wdt_ping(struct watchdog_device *wdog)
{
 keembay_wdt_set_timeout_reg(wdog);

 return 0;
}

static int keembay_wdt_set_timeout(struct watchdog_device *wdog, u32 t)
{
 wdog->timeout = t;
 keembay_wdt_set_timeout_reg(wdog);
 keembay_wdt_set_pretimeout_reg(wdog);

 return 0;
}

static int keembay_wdt_set_pretimeout(struct watchdog_device *wdog, u32 t)
{
 if (t > wdog->timeout)
  return -EINVAL;

 wdog->pretimeout = t;
 keembay_wdt_set_pretimeout_reg(wdog);

 return 0;
}

static unsigned int keembay_wdt_get_timeleft(struct watchdog_device *wdog)
{
 struct keembay_wdt *wdt = watchdog_get_drvdata(wdog);

 return keembay_wdt_readl(wdt, TIM_WATCHDOG) / wdt->rate;
}

/*
 * SMC call is used to clear the interrupt bits, because the TIM_GEN_CONFIG
 * register is in the secure bank.
 */

static irqreturn_t keembay_wdt_to_isr(int irq, void *dev_id)
{
 struct keembay_wdt *wdt = dev_id;
 struct arm_smccc_res res;

 arm_smccc_smc(WDT_INT_CLEAR_SMC, WDT_TO_INT_MASK, 0, 0, 0, 0, 0, 0, &res);
 dev_crit(wdt->wdd.parent, "Intel Keem Bay non-secure wdt timeout.\n");
 emergency_restart();

 return IRQ_HANDLED;
}

static irqreturn_t keembay_wdt_th_isr(int irq, void *dev_id)
{
 struct keembay_wdt *wdt = dev_id;
 struct arm_smccc_res res;

 keembay_wdt_set_pretimeout(&wdt->wdd, 0x0);

 arm_smccc_smc(WDT_INT_CLEAR_SMC, WDT_TH_INT_MASK, 0, 0, 0, 0, 0, 0, &res);
 dev_crit(wdt->wdd.parent, "Intel Keem Bay non-secure wdt pre-timeout.\n");
 watchdog_notify_pretimeout(&wdt->wdd);

 return IRQ_HANDLED;
}

static const struct watchdog_info keembay_wdt_info = {
 .identity = "Intel Keem Bay Watchdog Timer",
 .options = WDIOF_SETTIMEOUT |
     WDIOF_PRETIMEOUT |
     WDIOF_MAGICCLOSE |
     WDIOF_KEEPALIVEPING,
};

static const struct watchdog_ops keembay_wdt_ops = {
 .owner  = THIS_MODULE,
 .start  = keembay_wdt_start,
 .stop  = keembay_wdt_stop,
 .ping  = keembay_wdt_ping,
 .set_timeout = keembay_wdt_set_timeout,
 .set_pretimeout = keembay_wdt_set_pretimeout,
 .get_timeleft = keembay_wdt_get_timeleft,
};

static int keembay_wdt_probe(struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 struct keembay_wdt *wdt;
 int ret;

 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
 if (!wdt)
  return -ENOMEM;

 wdt->base = devm_platform_ioremap_resource(pdev, 0);
 if (IS_ERR(wdt->base))
  return PTR_ERR(wdt->base);

 /* we do not need to enable the clock as it is enabled by default */
 wdt->clk = devm_clk_get(dev, NULL);
 if (IS_ERR(wdt->clk))
  return dev_err_probe(dev, PTR_ERR(wdt->clk), "Failed to get clock\n");

 wdt->rate = clk_get_rate(wdt->clk);
 if (!wdt->rate)
  return dev_err_probe(dev, -EINVAL, "Failed to get clock rate\n");

 wdt->th_irq = platform_get_irq_byname(pdev, "threshold");
 if (wdt->th_irq < 0)
  return dev_err_probe(dev, wdt->th_irq, "Failed to get IRQ for threshold\n");

 ret = devm_request_irq(dev, wdt->th_irq, keembay_wdt_th_isr, 0,
          "keembay-wdt", wdt);
 if (ret)
  return dev_err_probe(dev, ret, "Failed to request IRQ for threshold\n");

 wdt->to_irq = platform_get_irq_byname(pdev, "timeout");
 if (wdt->to_irq < 0)
  return dev_err_probe(dev, wdt->to_irq, "Failed to get IRQ for timeout\n");

 ret = devm_request_irq(dev, wdt->to_irq, keembay_wdt_to_isr, 0,
          "keembay-wdt", wdt);
 if (ret)
  return dev_err_probe(dev, ret, "Failed to request IRQ for timeout\n");

 wdt->wdd.parent  = dev;
 wdt->wdd.info  = &keembay_wdt_info;
 wdt->wdd.ops  = &keembay_wdt_ops;
 wdt->wdd.min_timeout = WDT_LOAD_MIN;
 wdt->wdd.max_timeout = WDT_LOAD_MAX / wdt->rate;
 wdt->wdd.timeout = WDT_TIMEOUT;
 wdt->wdd.pretimeout = WDT_PRETIMEOUT;

 watchdog_set_drvdata(&wdt->wdd, wdt);
 watchdog_set_nowayout(&wdt->wdd, nowayout);
 watchdog_init_timeout(&wdt->wdd, timeout, dev);
 keembay_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
 keembay_wdt_set_pretimeout(&wdt->wdd, wdt->wdd.pretimeout);

 ret = devm_watchdog_register_device(dev, &wdt->wdd);
 if (ret)
  return dev_err_probe(dev, ret, "Failed to register watchdog device.\n");

 platform_set_drvdata(pdev, wdt);
 dev_info(dev, "Initial timeout %d sec%s.\n",
   wdt->wdd.timeout, nowayout ? ", nowayout" : "");

 return 0;
}

static int __maybe_unused keembay_wdt_suspend(struct device *dev)
{
 struct keembay_wdt *wdt = dev_get_drvdata(dev);

 if (watchdog_active(&wdt->wdd))
  return keembay_wdt_stop(&wdt->wdd);

 return 0;
}

static int __maybe_unused keembay_wdt_resume(struct device *dev)
{
 struct keembay_wdt *wdt = dev_get_drvdata(dev);

 if (watchdog_active(&wdt->wdd))
  return keembay_wdt_start(&wdt->wdd);

 return 0;
}

static SIMPLE_DEV_PM_OPS(keembay_wdt_pm_ops, keembay_wdt_suspend,
    keembay_wdt_resume);

static const struct of_device_id keembay_wdt_match[] = {
 { .compatible = "intel,keembay-wdt" },
 { }
};
MODULE_DEVICE_TABLE(of, keembay_wdt_match);

static struct platform_driver keembay_wdt_driver = {
 .probe = keembay_wdt_probe,
 .driver = {
  .name  = "keembay_wdt",
  .of_match_table = keembay_wdt_match,
  .pm  = &keembay_wdt_pm_ops,
 },
};

module_platform_driver(keembay_wdt_driver);

MODULE_DESCRIPTION("Intel Keem Bay SoC watchdog driver");
MODULE_AUTHOR("Wan Ahmad Zainie );
MODULE_LICENSE("GPL v2");

Messung V0.5
C=97 H=95 G=95

¤ Dauer der Verarbeitung: 0.10 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.