New programmable logic device can have watchdog type 3 implementation.
It's same as Type 2 with extended maximum timeout period.
Maximum timeout is up-to 65535 sec.
Type 3 HW watchdog implementation can exist on all Mellanox systems.
It is differentiated by WD capability bit.
Signed-off-by: Michael Shych <michaelsh@mellanox.com>
Reviewed-by: Vadim Pasternak <vadimp@mellanox.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20200504141427.17685-4-michaelsh@mellanox.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
#define MLXREG_WDT_CLOCK_SCALE 1000
#define MLXREG_WDT_MAX_TIMEOUT_TYPE1 32
#define MLXREG_WDT_MAX_TIMEOUT_TYPE2 255
#define MLXREG_WDT_CLOCK_SCALE 1000
#define MLXREG_WDT_MAX_TIMEOUT_TYPE1 32
#define MLXREG_WDT_MAX_TIMEOUT_TYPE2 255
+#define MLXREG_WDT_MAX_TIMEOUT_TYPE3 65535
#define MLXREG_WDT_MIN_TIMEOUT 1
#define MLXREG_WDT_OPTIONS_BASE (WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | \
WDIOF_SETTIMEOUT)
#define MLXREG_WDT_MIN_TIMEOUT 1
#define MLXREG_WDT_OPTIONS_BASE (WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | \
WDIOF_SETTIMEOUT)
int tleft_idx;
int ping_idx;
int reset_idx;
int tleft_idx;
int ping_idx;
int reset_idx;
enum mlxreg_wdt_type wdt_type;
};
enum mlxreg_wdt_type wdt_type;
};
u32 regval, set_time, hw_timeout;
int rc;
u32 regval, set_time, hw_timeout;
int rc;
- if (wdt->wdt_type == MLX_WDT_TYPE1) {
+ switch (wdt->wdt_type) {
+ case MLX_WDT_TYPE1:
rc = regmap_read(wdt->regmap, reg_data->reg, ®val);
if (rc)
return rc;
rc = regmap_read(wdt->regmap, reg_data->reg, ®val);
if (rc)
return rc;
regval = (regval & reg_data->mask) | hw_timeout;
/* Rowndown to actual closest number of sec. */
set_time = BIT(hw_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;
+ rc = regmap_write(wdt->regmap, reg_data->reg, regval);
+ break;
+ case MLX_WDT_TYPE2:
+ set_time = timeout;
+ rc = regmap_write(wdt->regmap, reg_data->reg, timeout);
+ break;
+ case MLX_WDT_TYPE3:
+ /* WD_TYPE3 has 2B set time register */
+ if (wdt->regmap_val_sz == 1) {
+ regval = timeout & 0xff;
+ rc = regmap_write(wdt->regmap, reg_data->reg, regval);
+ if (!rc) {
+ regval = (timeout & 0xff00) >> 8;
+ rc = regmap_write(wdt->regmap,
+ reg_data->reg + 1, regval);
+ }
+ } else {
+ rc = regmap_write(wdt->regmap, reg_data->reg, timeout);
+ }
+ break;
+ default:
+ return -EINVAL;
}
wdd->timeout = set_time;
}
wdd->timeout = set_time;
- rc = regmap_write(wdt->regmap, reg_data->reg, regval);
-
if (!rc) {
/*
* Restart watchdog with new timeout period
if (!rc) {
/*
* Restart watchdog with new timeout period
{
struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd);
struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->tleft_idx];
{
struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd);
struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->tleft_idx];
- rc = regmap_read(wdt->regmap, reg_data->reg, ®val);
+ if (wdt->wdt_type == MLX_WDT_TYPE2) {
+ rc = regmap_read(wdt->regmap, reg_data->reg, ®val);
+ } else {
+ /* WD_TYPE3 has 2 byte timeleft register */
+ if (wdt->regmap_val_sz == 1) {
+ rc = regmap_read(wdt->regmap, reg_data->reg, &lsb);
+ if (!rc) {
+ rc = regmap_read(wdt->regmap,
+ reg_data->reg + 1, &msb);
+ regval = (msb & 0xff) << 8 | (lsb & 0xff);
+ }
+ } else {
+ rc = regmap_read(wdt->regmap, reg_data->reg, ®val);
+ }
+ }
+
/* Return 0 timeleft in case of failure register read. */
return rc == 0 ? regval : 0;
}
/* Return 0 timeleft in case of failure register read. */
return rc == 0 ? regval : 0;
}
wdt->wdd.info = &mlxreg_wdt_aux_info;
wdt->wdt_type = pdata->version;
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 {
+ switch (wdt->wdt_type) {
+ case MLX_WDT_TYPE1:
wdt->wdd.ops = &mlxreg_wdt_ops_type1;
wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE1;
wdt->wdd.ops = &mlxreg_wdt_ops_type1;
wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE1;
+ break;
+ case MLX_WDT_TYPE2:
+ wdt->wdd.ops = &mlxreg_wdt_ops_type2;
+ wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE2;
+ break;
+ case MLX_WDT_TYPE3:
+ wdt->wdd.ops = &mlxreg_wdt_ops_type2;
+ wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE3;
+ break;
+ default:
+ break;
wdt->wdd.min_timeout = MLXREG_WDT_MIN_TIMEOUT;
}
wdt->wdd.min_timeout = MLXREG_WDT_MIN_TIMEOUT;
}
wdt->wdd.parent = dev;
wdt->regmap = pdata->regmap;
wdt->wdd.parent = dev;
wdt->regmap = pdata->regmap;
+ rc = regmap_get_val_bytes(wdt->regmap);
+ if (rc < 0)
+ return -EINVAL;
+
+ wdt->regmap_val_sz = rc;
mlxreg_wdt_config(wdt, pdata);
if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOWAYOUT))
mlxreg_wdt_config(wdt, pdata);
if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOWAYOUT))