Commit eee85114 authored by Michael Shych's avatar Michael Shych Committed by Wim Van Sebroeck

watchdog: mlx-wdt: support new watchdog type with longer timeout period

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: default avatarMichael Shych <michaelsh@mellanox.com>
Reviewed-by: default avatarVadim Pasternak <vadimp@mellanox.com>
Acked-by: default avatarGuenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20200504141427.17685-4-michaelsh@mellanox.comSigned-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarWim Van Sebroeck <wim@linux-watchdog.org>
parent 7772b993
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define MLXREG_WDT_CLOCK_SCALE 1000 #define MLXREG_WDT_CLOCK_SCALE 1000
#define MLXREG_WDT_MAX_TIMEOUT_TYPE1 32 #define MLXREG_WDT_MAX_TIMEOUT_TYPE1 32
#define MLXREG_WDT_MAX_TIMEOUT_TYPE2 255 #define MLXREG_WDT_MAX_TIMEOUT_TYPE2 255
#define MLXREG_WDT_MAX_TIMEOUT_TYPE3 65535
#define MLXREG_WDT_MIN_TIMEOUT 1 #define MLXREG_WDT_MIN_TIMEOUT 1
#define MLXREG_WDT_OPTIONS_BASE (WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | \ #define MLXREG_WDT_OPTIONS_BASE (WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | \
WDIOF_SETTIMEOUT) WDIOF_SETTIMEOUT)
...@@ -49,6 +50,7 @@ struct mlxreg_wdt { ...@@ -49,6 +50,7 @@ struct mlxreg_wdt {
int tleft_idx; int tleft_idx;
int ping_idx; int ping_idx;
int reset_idx; int reset_idx;
int regmap_val_sz;
enum mlxreg_wdt_type wdt_type; enum mlxreg_wdt_type wdt_type;
}; };
...@@ -111,7 +113,8 @@ static int mlxreg_wdt_set_timeout(struct watchdog_device *wdd, ...@@ -111,7 +113,8 @@ static int mlxreg_wdt_set_timeout(struct watchdog_device *wdd,
u32 regval, set_time, hw_timeout; u32 regval, set_time, hw_timeout;
int rc; 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, &regval); rc = regmap_read(wdt->regmap, reg_data->reg, &regval);
if (rc) if (rc)
return rc; return rc;
...@@ -120,14 +123,32 @@ static int mlxreg_wdt_set_timeout(struct watchdog_device *wdd, ...@@ -120,14 +123,32 @@ static int mlxreg_wdt_set_timeout(struct watchdog_device *wdd,
regval = (regval & reg_data->mask) | hw_timeout; regval = (regval & reg_data->mask) | hw_timeout;
/* Rowndown to actual closest number of sec. */ /* Rowndown to actual closest number of sec. */
set_time = BIT(hw_timeout) / MLXREG_WDT_CLOCK_SCALE; set_time = BIT(hw_timeout) / MLXREG_WDT_CLOCK_SCALE;
} else { 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 */
set_time = timeout; set_time = timeout;
regval = timeout; 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) { if (!rc) {
/* /*
* Restart watchdog with new timeout period * Restart watchdog with new timeout period
...@@ -147,10 +168,25 @@ static unsigned int mlxreg_wdt_get_timeleft(struct watchdog_device *wdd) ...@@ -147,10 +168,25 @@ static unsigned int mlxreg_wdt_get_timeleft(struct watchdog_device *wdd)
{ {
struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd);
struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->tleft_idx]; struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->tleft_idx];
u32 regval; u32 regval, msb, lsb;
int rc; int rc;
rc = regmap_read(wdt->regmap, reg_data->reg, &regval); if (wdt->wdt_type == MLX_WDT_TYPE2) {
rc = regmap_read(wdt->regmap, reg_data->reg, &regval);
} 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, &regval);
}
}
/* Return 0 timeleft in case of failure register read. */ /* Return 0 timeleft in case of failure register read. */
return rc == 0 ? regval : 0; return rc == 0 ? regval : 0;
} }
...@@ -212,13 +248,23 @@ static void mlxreg_wdt_config(struct mlxreg_wdt *wdt, ...@@ -212,13 +248,23 @@ static void mlxreg_wdt_config(struct mlxreg_wdt *wdt,
wdt->wdd.info = &mlxreg_wdt_aux_info; wdt->wdd.info = &mlxreg_wdt_aux_info;
wdt->wdt_type = pdata->version; wdt->wdt_type = pdata->version;
if (wdt->wdt_type == MLX_WDT_TYPE2) { switch (wdt->wdt_type) {
wdt->wdd.ops = &mlxreg_wdt_ops_type2; case MLX_WDT_TYPE1:
wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE2;
} else {
wdt->wdd.ops = &mlxreg_wdt_ops_type1; wdt->wdd.ops = &mlxreg_wdt_ops_type1;
wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_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;
} }
...@@ -249,6 +295,11 @@ static int mlxreg_wdt_probe(struct platform_device *pdev) ...@@ -249,6 +295,11 @@ static int mlxreg_wdt_probe(struct platform_device *pdev)
wdt->wdd.parent = dev; wdt->wdd.parent = dev;
wdt->regmap = pdata->regmap; 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); mlxreg_wdt_config(wdt, pdata);
if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOWAYOUT)) if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOWAYOUT))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment