forked from luck/tmp_suning_uos_patched
linux-watchdog 5.1-rc1 tag
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iEYEABECAAYFAlyFIfgACgkQ+iyteGJfRsqt4gCgrgwSrDhwW+u7NjyY48KGAPgt xM8AoM31H9C2HrT2IJuKa3FjIawceUfw =wj0o -----END PGP SIGNATURE----- Merge tag 'linux-watchdog-5.1-rc1' of git://www.linux-watchdog.org/linux-watchdog Pull watchdog updates from Wim Van Sebroeck: - a new watchdog driver for the Mellanox systems - renesas-wdt: Document r8a77470 support - numerous 'Mark expected switch fall-throughs' - qcom: Add suspend/resume support - some small fixes and documentation updates * tag 'linux-watchdog-5.1-rc1' of git://www.linux-watchdog.org/linux-watchdog: watchdog: w83877f_wdt: Mark expected switch fall-through watchdog: sc520_wdt: Mark expected switch fall-through watchdog: sbc60xxwdt: Mark expected switch fall-through watchdog: smsc37b787_wdt: Mark expected switch fall-through watchdog: sc1200: Mark expected switch fall-through watchdog: pc87413: Mark expected switch fall-through Documentation/watchdog: Add documentation mlx-wdt driver watchdog: mlx-wdt: introduce a watchdog driver for Mellanox systems. platform_data/mlxreg: additions for Mellanox watchdog driver. watchdog: Update sysfs documentation. watchdog: dw: remove useless pr_fmt watchdog: pika_wdt: drop pointless static qualifier in pikawdt_init watchdog/hpwdt: Update Kconfig documentation dt-bindings: watchdog: renesas-wdt: Document r8a77470 support watchdog: qcom: Add suspend/resume support
This commit is contained in:
commit
a089e4fed5
|
@ -49,3 +49,26 @@ Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||||
Description:
|
Description:
|
||||||
It is a read only file. It is read to know about current
|
It is a read only file. It is read to know about current
|
||||||
value of timeout programmed.
|
value of timeout programmed.
|
||||||
|
|
||||||
|
What: /sys/class/watchdog/watchdogn/pretimeout
|
||||||
|
Date: December 2016
|
||||||
|
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||||
|
Description:
|
||||||
|
It is a read only file. It specifies the time in seconds before
|
||||||
|
timeout when the pretimeout interrupt is delivered. Pretimeout
|
||||||
|
is an optional feature.
|
||||||
|
|
||||||
|
What: /sys/class/watchdog/watchdogn/pretimeout_avaialable_governors
|
||||||
|
Date: February 2017
|
||||||
|
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||||
|
Description:
|
||||||
|
It is a read only file. It shows the pretimeout governors
|
||||||
|
available for this watchdog.
|
||||||
|
|
||||||
|
What: /sys/class/watchdog/watchdogn/pretimeout_governor
|
||||||
|
Date: February 2017
|
||||||
|
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||||
|
Description:
|
||||||
|
It is a read/write file. When read, the currently assigned
|
||||||
|
pretimeout governor is returned. When written, it sets
|
||||||
|
the pretimeout governor.
|
||||||
|
|
|
@ -8,6 +8,7 @@ Required properties:
|
||||||
- "renesas,r8a7743-wdt" (RZ/G1M)
|
- "renesas,r8a7743-wdt" (RZ/G1M)
|
||||||
- "renesas,r8a7744-wdt" (RZ/G1N)
|
- "renesas,r8a7744-wdt" (RZ/G1N)
|
||||||
- "renesas,r8a7745-wdt" (RZ/G1E)
|
- "renesas,r8a7745-wdt" (RZ/G1E)
|
||||||
|
- "renesas,r8a77470-wdt" (RZ/G1C)
|
||||||
- "renesas,r8a774a1-wdt" (RZ/G2M)
|
- "renesas,r8a774a1-wdt" (RZ/G2M)
|
||||||
- "renesas,r8a774c0-wdt" (RZ/G2E)
|
- "renesas,r8a774c0-wdt" (RZ/G2E)
|
||||||
- "renesas,r8a7790-wdt" (R-Car H2)
|
- "renesas,r8a7790-wdt" (R-Car H2)
|
||||||
|
|
52
Documentation/watchdog/mlx-wdt.txt
Normal file
52
Documentation/watchdog/mlx-wdt.txt
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
Mellanox watchdog drivers
|
||||||
|
for x86 based system switches
|
||||||
|
|
||||||
|
This driver provides watchdog functionality for various Mellanox
|
||||||
|
Ethernet and Infiniband switch systems.
|
||||||
|
|
||||||
|
Mellanox watchdog device is implemented in a programmable logic device.
|
||||||
|
|
||||||
|
There are 2 types of HW watchdog implementations.
|
||||||
|
|
||||||
|
Type 1:
|
||||||
|
Actual HW timeout can be defined as a power of 2 msec.
|
||||||
|
e.g. timeout 20 sec will be rounded up to 32768 msec.
|
||||||
|
The maximum timeout period is 32 sec (32768 msec.),
|
||||||
|
Get time-left isn't supported
|
||||||
|
|
||||||
|
Type 2:
|
||||||
|
Actual HW timeout is defined in sec. and it's the same as
|
||||||
|
a user-defined timeout.
|
||||||
|
Maximum timeout is 255 sec.
|
||||||
|
Get time-left is supported.
|
||||||
|
|
||||||
|
Type 1 HW watchdog implementation exist in old systems and
|
||||||
|
all new systems have type 2 HW watchdog.
|
||||||
|
Two types of HW implementation have also different register map.
|
||||||
|
|
||||||
|
Mellanox system can have 2 watchdogs: main and auxiliary.
|
||||||
|
Main and auxiliary watchdog devices can be enabled together
|
||||||
|
on the same system.
|
||||||
|
There are several actions that can be defined in the watchdog:
|
||||||
|
system reset, start fans on full speed and increase register counter.
|
||||||
|
The last 2 actions are performed without a system reset.
|
||||||
|
Actions without reset are provided for auxiliary watchdog device,
|
||||||
|
which is optional.
|
||||||
|
Watchdog can be started during a probe, in this case it will be
|
||||||
|
pinged by watchdog core before watchdog device will be opened by
|
||||||
|
user space application.
|
||||||
|
Watchdog can be initialised in nowayout way, i.e. oncse started
|
||||||
|
it can't be stopped.
|
||||||
|
|
||||||
|
This mlx-wdt driver supports both HW watchdog implementations.
|
||||||
|
|
||||||
|
Watchdog driver is probed from the common mlx_platform driver.
|
||||||
|
Mlx_platform driver provides an appropriate set of registers for
|
||||||
|
Mellanox watchdog device, identity name (mlx-wdt-main or mlx-wdt-aux),
|
||||||
|
initial timeout, performed action in expiration and configuration flags.
|
||||||
|
watchdog configuration flags: nowayout and start_at_boot, hw watchdog
|
||||||
|
version - type1 or type2.
|
||||||
|
The driver checks during initialization if the previous system reset
|
||||||
|
was done by the watchdog. If yes, it makes a notification about this event.
|
||||||
|
|
||||||
|
Access to HW registers is performed through a generic regmap interface.
|
|
@ -241,6 +241,22 @@ config RAVE_SP_WATCHDOG
|
||||||
help
|
help
|
||||||
Support for the watchdog on RAVE SP device.
|
Support for the watchdog on RAVE SP device.
|
||||||
|
|
||||||
|
config MLX_WDT
|
||||||
|
tristate "Mellanox Watchdog"
|
||||||
|
depends on MELLANOX_PLATFORM
|
||||||
|
select WATCHDOG_CORE
|
||||||
|
select REGMAP
|
||||||
|
help
|
||||||
|
This is the driver for the hardware watchdog on Mellanox systems.
|
||||||
|
If you are going to use it, say Y here, otherwise N.
|
||||||
|
This driver can be used together with the watchdog daemon.
|
||||||
|
It can also watch your kernel to make sure it doesn't freeze,
|
||||||
|
and if it does, it reboots your system after a certain amount of
|
||||||
|
time.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called mlx-wdt.
|
||||||
|
|
||||||
# ALPHA Architecture
|
# ALPHA Architecture
|
||||||
|
|
||||||
# ARM Architecture
|
# ARM Architecture
|
||||||
|
@ -1157,7 +1173,7 @@ config HP_WATCHDOG
|
||||||
select WATCHDOG_CORE
|
select WATCHDOG_CORE
|
||||||
depends on X86 && PCI
|
depends on X86 && PCI
|
||||||
help
|
help
|
||||||
A software monitoring watchdog and NMI sourcing driver. This driver
|
A software monitoring watchdog and NMI handling driver. This driver
|
||||||
will detect lockups and provide a stack trace. This is a driver that
|
will detect lockups and provide a stack trace. This is a driver that
|
||||||
will only load on an HP ProLiant system with a minimum of iLO2 support.
|
will only load on an HP ProLiant system with a minimum of iLO2 support.
|
||||||
To compile this driver as a module, choose M here: the module will be
|
To compile this driver as a module, choose M here: the module will be
|
||||||
|
@ -1175,12 +1191,13 @@ config KEMPLD_WDT
|
||||||
called kempld_wdt.
|
called kempld_wdt.
|
||||||
|
|
||||||
config HPWDT_NMI_DECODING
|
config HPWDT_NMI_DECODING
|
||||||
bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer"
|
bool "NMI support for the HP ProLiant iLO2+ Hardware Watchdog Timer"
|
||||||
depends on HP_WATCHDOG
|
depends on HP_WATCHDOG
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
When an NMI occurs this feature will make the necessary BIOS calls to
|
Enables the NMI handler for the watchdog pretimeout NMI and the iLO
|
||||||
log the cause of the NMI.
|
"Generate NMI to System" virtual button. When an NMI is claimed
|
||||||
|
by the driver, panic is called.
|
||||||
|
|
||||||
config SC1200_WDT
|
config SC1200_WDT
|
||||||
tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
|
tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
|
||||||
|
|
|
@ -142,6 +142,7 @@ obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o
|
||||||
obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o
|
obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o
|
||||||
obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o
|
obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o
|
||||||
obj-$(CONFIG_NIC7018_WDT) += nic7018_wdt.o
|
obj-$(CONFIG_NIC7018_WDT) += nic7018_wdt.o
|
||||||
|
obj-$(CONFIG_MLX_WDT) += mlx_wdt.o
|
||||||
|
|
||||||
# M68K Architecture
|
# M68K Architecture
|
||||||
obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o
|
obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
* heartbeat requests after the watchdog device has been closed.
|
* heartbeat requests after the watchdog device has been closed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
||||||
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
290
drivers/watchdog/mlx_wdt.c
Normal file
290
drivers/watchdog/mlx_wdt.c
Normal file
|
@ -0,0 +1,290 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Mellanox watchdog driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Mellanox Technologies
|
||||||
|
* Copyright (C) 2019 Michael Shych <mshych@mellanox.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/log2.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_data/mlxreg.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/watchdog.h>
|
||||||
|
|
||||||
|
#define MLXREG_WDT_CLOCK_SCALE 1000
|
||||||
|
#define MLXREG_WDT_MAX_TIMEOUT_TYPE1 32
|
||||||
|
#define MLXREG_WDT_MAX_TIMEOUT_TYPE2 255
|
||||||
|
#define MLXREG_WDT_MIN_TIMEOUT 1
|
||||||
|
#define MLXREG_WDT_OPTIONS_BASE (WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | \
|
||||||
|
WDIOF_SETTIMEOUT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct mlxreg_wdt - wd private data:
|
||||||
|
*
|
||||||
|
* @wdd: watchdog device;
|
||||||
|
* @device: basic device;
|
||||||
|
* @pdata: data received from platform driver;
|
||||||
|
* @regmap: register map of parent device;
|
||||||
|
* @timeout: defined timeout in sec.;
|
||||||
|
* @action_idx: index for direct access to action register;
|
||||||
|
* @timeout_idx:index for direct access to TO register;
|
||||||
|
* @tleft_idx: index for direct access to time left register;
|
||||||
|
* @ping_idx: index for direct access to ping register;
|
||||||
|
* @reset_idx: index for direct access to reset cause register;
|
||||||
|
* @wd_type: watchdog HW type;
|
||||||
|
*/
|
||||||
|
struct mlxreg_wdt {
|
||||||
|
struct watchdog_device wdd;
|
||||||
|
struct mlxreg_core_platform_data *pdata;
|
||||||
|
void *regmap;
|
||||||
|
int action_idx;
|
||||||
|
int timeout_idx;
|
||||||
|
int tleft_idx;
|
||||||
|
int ping_idx;
|
||||||
|
int reset_idx;
|
||||||
|
enum mlxreg_wdt_type wdt_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mlxreg_wdt_check_card_reset(struct mlxreg_wdt *wdt)
|
||||||
|
{
|
||||||
|
struct mlxreg_core_data *reg_data;
|
||||||
|
u32 regval;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (wdt->reset_idx == -EINVAL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(wdt->wdd.info->options & WDIOF_CARDRESET))
|
||||||
|
return;
|
||||||
|
|
||||||
|
reg_data = &wdt->pdata->data[wdt->reset_idx];
|
||||||
|
rc = regmap_read(wdt->regmap, reg_data->reg, ®val);
|
||||||
|
if (!rc) {
|
||||||
|
if (regval & ~reg_data->mask) {
|
||||||
|
wdt->wdd.bootstatus = WDIOF_CARDRESET;
|
||||||
|
dev_info(wdt->wdd.parent,
|
||||||
|
"watchdog previously reset the CPU\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxreg_wdt_start(struct watchdog_device *wdd)
|
||||||
|
{
|
||||||
|
struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||||
|
struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx];
|
||||||
|
|
||||||
|
return regmap_update_bits(wdt->regmap, reg_data->reg, ~reg_data->mask,
|
||||||
|
BIT(reg_data->bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxreg_wdt_stop(struct watchdog_device *wdd)
|
||||||
|
{
|
||||||
|
struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||||
|
struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx];
|
||||||
|
|
||||||
|
return regmap_update_bits(wdt->regmap, reg_data->reg, ~reg_data->mask,
|
||||||
|
~BIT(reg_data->bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxreg_wdt_ping(struct watchdog_device *wdd)
|
||||||
|
{
|
||||||
|
struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||||
|
struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->ping_idx];
|
||||||
|
|
||||||
|
return regmap_update_bits_base(wdt->regmap, reg_data->reg,
|
||||||
|
~reg_data->mask, BIT(reg_data->bit),
|
||||||
|
NULL, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxreg_wdt_set_timeout(struct watchdog_device *wdd,
|
||||||
|
unsigned int timeout)
|
||||||
|
{
|
||||||
|
struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||||
|
struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->timeout_idx];
|
||||||
|
u32 regval, set_time, hw_timeout;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (wdt->wdt_type == MLX_WDT_TYPE1) {
|
||||||
|
rc = regmap_read(wdt->regmap, reg_data->reg, ®val);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
hw_timeout = order_base_2(timeout * MLXREG_WDT_CLOCK_SCALE);
|
||||||
|
regval = (regval & reg_data->mask) | hw_timeout;
|
||||||
|
/* Rowndown to actual closest number of sec. */
|
||||||
|
set_time = BIT(hw_timeout) / MLXREG_WDT_CLOCK_SCALE;
|
||||||
|
} else {
|
||||||
|
set_time = timeout;
|
||||||
|
regval = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdd->timeout = set_time;
|
||||||
|
rc = regmap_write(wdt->regmap, reg_data->reg, regval);
|
||||||
|
|
||||||
|
if (!rc) {
|
||||||
|
/*
|
||||||
|
* Restart watchdog with new timeout period
|
||||||
|
* if watchdog is already started.
|
||||||
|
*/
|
||||||
|
if (watchdog_active(wdd)) {
|
||||||
|
rc = mlxreg_wdt_stop(wdd);
|
||||||
|
if (!rc)
|
||||||
|
rc = mlxreg_wdt_start(wdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int mlxreg_wdt_get_timeleft(struct watchdog_device *wdd)
|
||||||
|
{
|
||||||
|
struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||||
|
struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->tleft_idx];
|
||||||
|
u32 regval;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = regmap_read(wdt->regmap, reg_data->reg, ®val);
|
||||||
|
/* Return 0 timeleft in case of failure register read. */
|
||||||
|
return rc == 0 ? regval : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct watchdog_ops mlxreg_wdt_ops_type1 = {
|
||||||
|
.start = mlxreg_wdt_start,
|
||||||
|
.stop = mlxreg_wdt_stop,
|
||||||
|
.ping = mlxreg_wdt_ping,
|
||||||
|
.set_timeout = mlxreg_wdt_set_timeout,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct watchdog_ops mlxreg_wdt_ops_type2 = {
|
||||||
|
.start = mlxreg_wdt_start,
|
||||||
|
.stop = mlxreg_wdt_stop,
|
||||||
|
.ping = mlxreg_wdt_ping,
|
||||||
|
.set_timeout = mlxreg_wdt_set_timeout,
|
||||||
|
.get_timeleft = mlxreg_wdt_get_timeleft,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct watchdog_info mlxreg_wdt_main_info = {
|
||||||
|
.options = MLXREG_WDT_OPTIONS_BASE
|
||||||
|
| WDIOF_CARDRESET,
|
||||||
|
.identity = "mlx-wdt-main",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct watchdog_info mlxreg_wdt_aux_info = {
|
||||||
|
.options = MLXREG_WDT_OPTIONS_BASE
|
||||||
|
| WDIOF_ALARMONLY,
|
||||||
|
.identity = "mlx-wdt-aux",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mlxreg_wdt_config(struct mlxreg_wdt *wdt,
|
||||||
|
struct mlxreg_core_platform_data *pdata)
|
||||||
|
{
|
||||||
|
struct mlxreg_core_data *data = pdata->data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
wdt->reset_idx = -EINVAL;
|
||||||
|
for (i = 0; i < pdata->counter; i++, data++) {
|
||||||
|
if (strnstr(data->label, "action", sizeof(data->label)))
|
||||||
|
wdt->action_idx = i;
|
||||||
|
else if (strnstr(data->label, "timeout", sizeof(data->label)))
|
||||||
|
wdt->timeout_idx = i;
|
||||||
|
else if (strnstr(data->label, "timeleft", sizeof(data->label)))
|
||||||
|
wdt->tleft_idx = i;
|
||||||
|
else if (strnstr(data->label, "ping", sizeof(data->label)))
|
||||||
|
wdt->ping_idx = i;
|
||||||
|
else if (strnstr(data->label, "reset", sizeof(data->label)))
|
||||||
|
wdt->reset_idx = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdt->pdata = pdata;
|
||||||
|
if (strnstr(pdata->identity, mlxreg_wdt_main_info.identity,
|
||||||
|
sizeof(mlxreg_wdt_main_info.identity)))
|
||||||
|
wdt->wdd.info = &mlxreg_wdt_main_info;
|
||||||
|
else
|
||||||
|
wdt->wdd.info = &mlxreg_wdt_aux_info;
|
||||||
|
|
||||||
|
wdt->wdt_type = pdata->version;
|
||||||
|
if (wdt->wdt_type == MLX_WDT_TYPE2) {
|
||||||
|
wdt->wdd.ops = &mlxreg_wdt_ops_type2;
|
||||||
|
wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE2;
|
||||||
|
} else {
|
||||||
|
wdt->wdd.ops = &mlxreg_wdt_ops_type1;
|
||||||
|
wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE1;
|
||||||
|
}
|
||||||
|
wdt->wdd.min_timeout = MLXREG_WDT_MIN_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxreg_wdt_init_timeout(struct mlxreg_wdt *wdt,
|
||||||
|
struct mlxreg_core_platform_data *pdata)
|
||||||
|
{
|
||||||
|
u32 timeout;
|
||||||
|
|
||||||
|
timeout = pdata->data[wdt->timeout_idx].health_cntr;
|
||||||
|
return mlxreg_wdt_set_timeout(&wdt->wdd, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlxreg_wdt_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct mlxreg_core_platform_data *pdata;
|
||||||
|
struct mlxreg_wdt *wdt;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
pdata = dev_get_platdata(&pdev->dev);
|
||||||
|
if (!pdata) {
|
||||||
|
dev_err(&pdev->dev, "Failed to get platform data.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
|
||||||
|
if (!wdt)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
wdt->wdd.parent = &pdev->dev;
|
||||||
|
wdt->regmap = pdata->regmap;
|
||||||
|
mlxreg_wdt_config(wdt, pdata);
|
||||||
|
|
||||||
|
if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOWAYOUT))
|
||||||
|
watchdog_set_nowayout(&wdt->wdd, WATCHDOG_NOWAYOUT);
|
||||||
|
watchdog_stop_on_reboot(&wdt->wdd);
|
||||||
|
watchdog_stop_on_unregister(&wdt->wdd);
|
||||||
|
watchdog_set_drvdata(&wdt->wdd, wdt);
|
||||||
|
rc = mlxreg_wdt_init_timeout(wdt, pdata);
|
||||||
|
if (rc)
|
||||||
|
goto register_error;
|
||||||
|
|
||||||
|
if ((pdata->features & MLXREG_CORE_WD_FEATURE_START_AT_BOOT)) {
|
||||||
|
rc = mlxreg_wdt_start(&wdt->wdd);
|
||||||
|
if (rc)
|
||||||
|
goto register_error;
|
||||||
|
set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
|
||||||
|
}
|
||||||
|
mlxreg_wdt_check_card_reset(wdt);
|
||||||
|
rc = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);
|
||||||
|
|
||||||
|
register_error:
|
||||||
|
if (rc)
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Cannot register watchdog device (err=%d)\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver mlxreg_wdt_driver = {
|
||||||
|
.probe = mlxreg_wdt_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "mlx-wdt",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(mlxreg_wdt_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Michael Shych <michaelsh@mellanox.com>");
|
||||||
|
MODULE_DESCRIPTION("Mellanox watchdog driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:mlx-wdt");
|
|
@ -437,7 +437,7 @@ static long pc87413_ioctl(struct file *file, unsigned int cmd,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
timeout = new_timeout;
|
timeout = new_timeout;
|
||||||
pc87413_refresh();
|
pc87413_refresh();
|
||||||
/* fall through and return the new timeout... */
|
/* fall through - and return the new timeout... */
|
||||||
case WDIOC_GETTIMEOUT:
|
case WDIOC_GETTIMEOUT:
|
||||||
new_timeout = timeout * 60;
|
new_timeout = timeout * 60;
|
||||||
return put_user(new_timeout, uarg.i);
|
return put_user(new_timeout, uarg.i);
|
||||||
|
|
|
@ -225,7 +225,7 @@ static int __init pikawdt_init(void)
|
||||||
{
|
{
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
void __iomem *fpga;
|
void __iomem *fpga;
|
||||||
static u32 post1;
|
u32 post1;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
np = of_find_compatible_node(NULL, NULL, "pika,fpga");
|
np = of_find_compatible_node(NULL, NULL, "pika,fpga");
|
||||||
|
|
|
@ -245,6 +245,28 @@ static int qcom_wdt_remove(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused qcom_wdt_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct qcom_wdt *wdt = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (watchdog_active(&wdt->wdd))
|
||||||
|
qcom_wdt_stop(&wdt->wdd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused qcom_wdt_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct qcom_wdt *wdt = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (watchdog_active(&wdt->wdd))
|
||||||
|
qcom_wdt_start(&wdt->wdd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(qcom_wdt_pm_ops, qcom_wdt_suspend, qcom_wdt_resume);
|
||||||
|
|
||||||
static const struct of_device_id qcom_wdt_of_table[] = {
|
static const struct of_device_id qcom_wdt_of_table[] = {
|
||||||
{ .compatible = "qcom,kpss-timer", .data = reg_offset_data_apcs_tmr },
|
{ .compatible = "qcom,kpss-timer", .data = reg_offset_data_apcs_tmr },
|
||||||
{ .compatible = "qcom,scss-timer", .data = reg_offset_data_apcs_tmr },
|
{ .compatible = "qcom,scss-timer", .data = reg_offset_data_apcs_tmr },
|
||||||
|
@ -259,6 +281,7 @@ static struct platform_driver qcom_watchdog_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = KBUILD_MODNAME,
|
.name = KBUILD_MODNAME,
|
||||||
.of_match_table = qcom_wdt_of_table,
|
.of_match_table = qcom_wdt_of_table,
|
||||||
|
.pm = &qcom_wdt_pm_ops,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
module_platform_driver(qcom_watchdog_driver);
|
module_platform_driver(qcom_watchdog_driver);
|
||||||
|
|
|
@ -270,8 +270,8 @@ static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
|
|
||||||
timeout = new_timeout;
|
timeout = new_timeout;
|
||||||
wdt_keepalive();
|
wdt_keepalive();
|
||||||
/* Fall through */
|
|
||||||
}
|
}
|
||||||
|
/* Fall through */
|
||||||
case WDIOC_GETTIMEOUT:
|
case WDIOC_GETTIMEOUT:
|
||||||
return put_user(timeout, p);
|
return put_user(timeout, p);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -239,7 +239,7 @@ static long sc1200wdt_ioctl(struct file *file, unsigned int cmd,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
timeout = new_timeout;
|
timeout = new_timeout;
|
||||||
sc1200wdt_write_data(WDTO, timeout);
|
sc1200wdt_write_data(WDTO, timeout);
|
||||||
/* fall through and return the new timeout */
|
/* fall through - and return the new timeout */
|
||||||
|
|
||||||
case WDIOC_GETTIMEOUT:
|
case WDIOC_GETTIMEOUT:
|
||||||
return put_user(timeout * 60, p);
|
return put_user(timeout * 60, p);
|
||||||
|
|
|
@ -324,8 +324,8 @@ static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
wdt_keepalive();
|
wdt_keepalive();
|
||||||
/* Fall through */
|
|
||||||
}
|
}
|
||||||
|
/* Fall through */
|
||||||
case WDIOC_GETTIMEOUT:
|
case WDIOC_GETTIMEOUT:
|
||||||
return put_user(timeout, p);
|
return put_user(timeout, p);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -478,7 +478,7 @@ static long wb_smsc_wdt_ioctl(struct file *file,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
timeout = new_timeout;
|
timeout = new_timeout;
|
||||||
wb_smsc_wdt_set_timeout(timeout);
|
wb_smsc_wdt_set_timeout(timeout);
|
||||||
/* fall through and return the new timeout... */
|
/* fall through - and return the new timeout... */
|
||||||
case WDIOC_GETTIMEOUT:
|
case WDIOC_GETTIMEOUT:
|
||||||
new_timeout = timeout;
|
new_timeout = timeout;
|
||||||
if (unit == UNIT_MINUTE)
|
if (unit == UNIT_MINUTE)
|
||||||
|
|
|
@ -292,8 +292,8 @@ static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
|
|
||||||
timeout = new_timeout;
|
timeout = new_timeout;
|
||||||
wdt_keepalive();
|
wdt_keepalive();
|
||||||
/* Fall through */
|
|
||||||
}
|
}
|
||||||
|
/* Fall through */
|
||||||
case WDIOC_GETTIMEOUT:
|
case WDIOC_GETTIMEOUT:
|
||||||
return put_user(timeout, p);
|
return put_user(timeout, p);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -35,6 +35,19 @@
|
||||||
#define __LINUX_PLATFORM_DATA_MLXREG_H
|
#define __LINUX_PLATFORM_DATA_MLXREG_H
|
||||||
|
|
||||||
#define MLXREG_CORE_LABEL_MAX_SIZE 32
|
#define MLXREG_CORE_LABEL_MAX_SIZE 32
|
||||||
|
#define MLXREG_CORE_WD_FEATURE_NOWAYOUT BIT(0)
|
||||||
|
#define MLXREG_CORE_WD_FEATURE_START_AT_BOOT BIT(1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum mlxreg_wdt_type - type of HW watchdog
|
||||||
|
*
|
||||||
|
* TYPE1 HW watchdog implementation exist in old systems.
|
||||||
|
* All new systems have TYPE2 HW watchdog.
|
||||||
|
*/
|
||||||
|
enum mlxreg_wdt_type {
|
||||||
|
MLX_WDT_TYPE1,
|
||||||
|
MLX_WDT_TYPE2,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct mlxreg_hotplug_device - I2C device data:
|
* struct mlxreg_hotplug_device - I2C device data:
|
||||||
|
@ -112,11 +125,17 @@ struct mlxreg_core_item {
|
||||||
* @data: instance private data;
|
* @data: instance private data;
|
||||||
* @regmap: register map of parent device;
|
* @regmap: register map of parent device;
|
||||||
* @counter: number of instances;
|
* @counter: number of instances;
|
||||||
|
* @features: supported features of device;
|
||||||
|
* @version: implementation version;
|
||||||
|
* @identity: device identity name;
|
||||||
*/
|
*/
|
||||||
struct mlxreg_core_platform_data {
|
struct mlxreg_core_platform_data {
|
||||||
struct mlxreg_core_data *data;
|
struct mlxreg_core_data *data;
|
||||||
void *regmap;
|
void *regmap;
|
||||||
int counter;
|
int counter;
|
||||||
|
u32 features;
|
||||||
|
u32 version;
|
||||||
|
char identity[MLXREG_CORE_LABEL_MAX_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue
Block a user