diff options
31 files changed, 1131 insertions, 79 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt b/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt index 6d63782a7378..c6ae9c9d5e3e 100644 --- a/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt | |||
@@ -7,6 +7,8 @@ Required properties: | |||
7 | - reg : Physical base address and size | 7 | - reg : Physical base address and size |
8 | 8 | ||
9 | Optional properties: | 9 | Optional properties: |
10 | - clocks : Input clock specifier. Refer to common clock | ||
11 | bindings. | ||
10 | - clock-frequency : Frequency of clock in Hz | 12 | - clock-frequency : Frequency of clock in Hz |
11 | - xlnx,wdt-enable-once : 0 - Watchdog can be restarted | 13 | - xlnx,wdt-enable-once : 0 - Watchdog can be restarted |
12 | 1 - Watchdog can be enabled just once | 14 | 1 - Watchdog can be enabled just once |
@@ -17,6 +19,7 @@ Example: | |||
17 | axi-timebase-wdt@40100000 { | 19 | axi-timebase-wdt@40100000 { |
18 | clock-frequency = <50000000>; | 20 | clock-frequency = <50000000>; |
19 | compatible = "xlnx,xps-timebase-wdt-1.00.a"; | 21 | compatible = "xlnx,xps-timebase-wdt-1.00.a"; |
22 | clocks = <&clkc 15>; | ||
20 | reg = <0x40100000 0x10000>; | 23 | reg = <0x40100000 0x10000>; |
21 | xlnx,wdt-enable-once = <0x0>; | 24 | xlnx,wdt-enable-once = <0x0>; |
22 | xlnx,wdt-interval = <0x1b>; | 25 | xlnx,wdt-interval = <0x1b>; |
diff --git a/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt index 039c5ca45577..b949039bc502 100644 --- a/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt | |||
@@ -9,8 +9,7 @@ functionality. | |||
9 | 9 | ||
10 | Required properties | 10 | Required properties |
11 | 11 | ||
12 | - compatible : Must be one of: "st,stih407-lpc" "st,stih416-lpc" | 12 | - compatible : Should be: "st,stih407-lpc" |
13 | "st,stih415-lpc" "st,stid127-lpc" | ||
14 | - reg : LPC registers base address + size | 13 | - reg : LPC registers base address + size |
15 | - interrupts : LPC interrupt line number and associated flags | 14 | - interrupts : LPC interrupt line number and associated flags |
16 | - clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) | 15 | - clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) |
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt index 7f31125c123e..ea277478982f 100644 --- a/Documentation/watchdog/watchdog-kernel-api.txt +++ b/Documentation/watchdog/watchdog-kernel-api.txt | |||
@@ -48,8 +48,10 @@ struct watchdog_device { | |||
48 | const struct attribute_group **groups; | 48 | const struct attribute_group **groups; |
49 | const struct watchdog_info *info; | 49 | const struct watchdog_info *info; |
50 | const struct watchdog_ops *ops; | 50 | const struct watchdog_ops *ops; |
51 | const struct watchdog_governor *gov; | ||
51 | unsigned int bootstatus; | 52 | unsigned int bootstatus; |
52 | unsigned int timeout; | 53 | unsigned int timeout; |
54 | unsigned int pretimeout; | ||
53 | unsigned int min_timeout; | 55 | unsigned int min_timeout; |
54 | unsigned int max_timeout; | 56 | unsigned int max_timeout; |
55 | unsigned int min_hw_heartbeat_ms; | 57 | unsigned int min_hw_heartbeat_ms; |
@@ -74,9 +76,11 @@ It contains following fields: | |||
74 | * info: a pointer to a watchdog_info structure. This structure gives some | 76 | * info: a pointer to a watchdog_info structure. This structure gives some |
75 | additional information about the watchdog timer itself. (Like it's unique name) | 77 | additional information about the watchdog timer itself. (Like it's unique name) |
76 | * ops: a pointer to the list of watchdog operations that the watchdog supports. | 78 | * ops: a pointer to the list of watchdog operations that the watchdog supports. |
79 | * gov: a pointer to the assigned watchdog device pretimeout governor or NULL. | ||
77 | * timeout: the watchdog timer's timeout value (in seconds). | 80 | * timeout: the watchdog timer's timeout value (in seconds). |
78 | This is the time after which the system will reboot if user space does | 81 | This is the time after which the system will reboot if user space does |
79 | not send a heartbeat request if WDOG_ACTIVE is set. | 82 | not send a heartbeat request if WDOG_ACTIVE is set. |
83 | * pretimeout: the watchdog timer's pretimeout value (in seconds). | ||
80 | * min_timeout: the watchdog timer's minimum timeout value (in seconds). | 84 | * min_timeout: the watchdog timer's minimum timeout value (in seconds). |
81 | If set, the minimum configurable value for 'timeout'. | 85 | If set, the minimum configurable value for 'timeout'. |
82 | * max_timeout: the watchdog timer's maximum timeout value (in seconds), | 86 | * max_timeout: the watchdog timer's maximum timeout value (in seconds), |
@@ -121,6 +125,7 @@ struct watchdog_ops { | |||
121 | int (*ping)(struct watchdog_device *); | 125 | int (*ping)(struct watchdog_device *); |
122 | unsigned int (*status)(struct watchdog_device *); | 126 | unsigned int (*status)(struct watchdog_device *); |
123 | int (*set_timeout)(struct watchdog_device *, unsigned int); | 127 | int (*set_timeout)(struct watchdog_device *, unsigned int); |
128 | int (*set_pretimeout)(struct watchdog_device *, unsigned int); | ||
124 | unsigned int (*get_timeleft)(struct watchdog_device *); | 129 | unsigned int (*get_timeleft)(struct watchdog_device *); |
125 | int (*restart)(struct watchdog_device *); | 130 | int (*restart)(struct watchdog_device *); |
126 | void (*ref)(struct watchdog_device *) __deprecated; | 131 | void (*ref)(struct watchdog_device *) __deprecated; |
@@ -188,6 +193,23 @@ they are supported. These optional routines/operations are: | |||
188 | If set_timeout is not provided but, WDIOF_SETTIMEOUT is set, the watchdog | 193 | If set_timeout is not provided but, WDIOF_SETTIMEOUT is set, the watchdog |
189 | infrastructure updates the timeout value of the watchdog_device internally | 194 | infrastructure updates the timeout value of the watchdog_device internally |
190 | to the requested value. | 195 | to the requested value. |
196 | If the pretimeout feature is used (WDIOF_PRETIMEOUT), then set_timeout must | ||
197 | also take care of checking if pretimeout is still valid and set up the timer | ||
198 | accordingly. This can't be done in the core without races, so it is the | ||
199 | duty of the driver. | ||
200 | * set_pretimeout: this routine checks and changes the pretimeout value of | ||
201 | the watchdog. It is optional because not all watchdogs support pretimeout | ||
202 | notification. The timeout value is not an absolute time, but the number of | ||
203 | seconds before the actual timeout would happen. It returns 0 on success, | ||
204 | -EINVAL for "parameter out of range" and -EIO for "could not write value to | ||
205 | the watchdog". A value of 0 disables pretimeout notification. | ||
206 | (Note: the WDIOF_PRETIMEOUT needs to be set in the options field of the | ||
207 | watchdog's info structure). | ||
208 | If the watchdog driver does not have to perform any action but setting the | ||
209 | watchdog_device.pretimeout, this callback can be omitted. That means if | ||
210 | set_pretimeout is not provided but WDIOF_PRETIMEOUT is set, the watchdog | ||
211 | infrastructure updates the pretimeout value of the watchdog_device internally | ||
212 | to the requested value. | ||
191 | * get_timeleft: this routines returns the time that's left before a reset. | 213 | * get_timeleft: this routines returns the time that's left before a reset. |
192 | * restart: this routine restarts the machine. It returns 0 on success or a | 214 | * restart: this routine restarts the machine. It returns 0 on success or a |
193 | negative errno code for failure. | 215 | negative errno code for failure. |
@@ -268,3 +290,14 @@ User should follow the following guidelines for setting the priority: | |||
268 | * 128: default restart handler, use if no other handler is expected to be | 290 | * 128: default restart handler, use if no other handler is expected to be |
269 | available, and/or if restart is sufficient to restart the entire system | 291 | available, and/or if restart is sufficient to restart the entire system |
270 | * 255: highest priority, will preempt all other restart handlers | 292 | * 255: highest priority, will preempt all other restart handlers |
293 | |||
294 | To raise a pretimeout notification, the following function should be used: | ||
295 | |||
296 | void watchdog_notify_pretimeout(struct watchdog_device *wdd) | ||
297 | |||
298 | The function can be called in the interrupt context. If watchdog pretimeout | ||
299 | governor framework (kbuild CONFIG_WATCHDOG_PRETIMEOUT_GOV symbol) is enabled, | ||
300 | an action is taken by a preconfigured pretimeout governor preassigned to | ||
301 | the watchdog device. If watchdog pretimeout governor framework is not | ||
302 | enabled, watchdog_notify_pretimeout() prints a notification message to | ||
303 | the kernel log buffer. | ||
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 50dbaa805658..fdd3228e0678 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -1844,4 +1844,53 @@ config USBPCWATCHDOG | |||
1844 | 1844 | ||
1845 | Most people will say N. | 1845 | Most people will say N. |
1846 | 1846 | ||
1847 | comment "Watchdog Pretimeout Governors" | ||
1848 | |||
1849 | config WATCHDOG_PRETIMEOUT_GOV | ||
1850 | bool "Enable watchdog pretimeout governors" | ||
1851 | help | ||
1852 | The option allows to select watchdog pretimeout governors. | ||
1853 | |||
1854 | if WATCHDOG_PRETIMEOUT_GOV | ||
1855 | |||
1856 | choice | ||
1857 | prompt "Default Watchdog Pretimeout Governor" | ||
1858 | default WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC | ||
1859 | help | ||
1860 | This option selects a default watchdog pretimeout governor. | ||
1861 | The governor takes its action, if a watchdog is capable | ||
1862 | to report a pretimeout event. | ||
1863 | |||
1864 | config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP | ||
1865 | bool "noop" | ||
1866 | select WATCHDOG_PRETIMEOUT_GOV_NOOP | ||
1867 | help | ||
1868 | Use noop watchdog pretimeout governor by default. If noop | ||
1869 | governor is selected by a user, write a short message to | ||
1870 | the kernel log buffer and don't do any system changes. | ||
1871 | |||
1872 | config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC | ||
1873 | bool "panic" | ||
1874 | select WATCHDOG_PRETIMEOUT_GOV_PANIC | ||
1875 | help | ||
1876 | Use panic watchdog pretimeout governor by default, if | ||
1877 | a watchdog pretimeout event happens, consider that | ||
1878 | a watchdog feeder is dead and reboot is unavoidable. | ||
1879 | |||
1880 | endchoice | ||
1881 | |||
1882 | config WATCHDOG_PRETIMEOUT_GOV_NOOP | ||
1883 | tristate "Noop watchdog pretimeout governor" | ||
1884 | help | ||
1885 | Noop watchdog pretimeout governor, only an informational | ||
1886 | message is added to kernel log buffer. | ||
1887 | |||
1888 | config WATCHDOG_PRETIMEOUT_GOV_PANIC | ||
1889 | tristate "Panic watchdog pretimeout governor" | ||
1890 | help | ||
1891 | Panic watchdog pretimeout governor, on watchdog pretimeout | ||
1892 | event put the kernel into panic. | ||
1893 | |||
1894 | endif # WATCHDOG_PRETIMEOUT_GOV | ||
1895 | |||
1847 | endif # WATCHDOG | 1896 | endif # WATCHDOG |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index cba00430151b..caa9f4aa492a 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
@@ -3,9 +3,15 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # The WatchDog Timer Driver Core. | 5 | # The WatchDog Timer Driver Core. |
6 | watchdog-objs += watchdog_core.o watchdog_dev.o | ||
7 | obj-$(CONFIG_WATCHDOG_CORE) += watchdog.o | 6 | obj-$(CONFIG_WATCHDOG_CORE) += watchdog.o |
8 | 7 | ||
8 | watchdog-objs += watchdog_core.o watchdog_dev.o | ||
9 | |||
10 | watchdog-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV) += watchdog_pretimeout.o | ||
11 | |||
12 | obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP) += pretimeout_noop.o | ||
13 | obj-$(CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC) += pretimeout_panic.o | ||
14 | |||
9 | # Only one watchdog can succeed. We probe the ISA/PCI/USB based | 15 | # Only one watchdog can succeed. We probe the ISA/PCI/USB based |
10 | # watchdog-cards first, then the architecture specific watchdog | 16 | # watchdog-cards first, then the architecture specific watchdog |
11 | # drivers and then the architecture independent "softdog" driver. | 17 | # drivers and then the architecture independent "softdog" driver. |
diff --git a/drivers/watchdog/asm9260_wdt.c b/drivers/watchdog/asm9260_wdt.c index c9686b2fdafd..d0b59ba0f661 100644 --- a/drivers/watchdog/asm9260_wdt.c +++ b/drivers/watchdog/asm9260_wdt.c | |||
@@ -389,7 +389,6 @@ MODULE_DEVICE_TABLE(of, asm9260_wdt_of_match); | |||
389 | static struct platform_driver asm9260_wdt_driver = { | 389 | static struct platform_driver asm9260_wdt_driver = { |
390 | .driver = { | 390 | .driver = { |
391 | .name = "asm9260-wdt", | 391 | .name = "asm9260-wdt", |
392 | .owner = THIS_MODULE, | ||
393 | .of_match_table = asm9260_wdt_of_match, | 392 | .of_match_table = asm9260_wdt_of_match, |
394 | }, | 393 | }, |
395 | .probe = asm9260_wdt_probe, | 394 | .probe = asm9260_wdt_probe, |
diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c index 4245b65d645c..e238df4d75a2 100644 --- a/drivers/watchdog/bcm7038_wdt.c +++ b/drivers/watchdog/bcm7038_wdt.c | |||
@@ -107,7 +107,7 @@ static struct watchdog_info bcm7038_wdt_info = { | |||
107 | WDIOF_MAGICCLOSE | 107 | WDIOF_MAGICCLOSE |
108 | }; | 108 | }; |
109 | 109 | ||
110 | static struct watchdog_ops bcm7038_wdt_ops = { | 110 | static const struct watchdog_ops bcm7038_wdt_ops = { |
111 | .owner = THIS_MODULE, | 111 | .owner = THIS_MODULE, |
112 | .start = bcm7038_wdt_start, | 112 | .start = bcm7038_wdt_start, |
113 | .stop = bcm7038_wdt_stop, | 113 | .stop = bcm7038_wdt_stop, |
diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c index 4dda9024e229..98acef72334d 100644 --- a/drivers/watchdog/cadence_wdt.c +++ b/drivers/watchdog/cadence_wdt.c | |||
@@ -269,7 +269,7 @@ static struct watchdog_info cdns_wdt_info = { | |||
269 | }; | 269 | }; |
270 | 270 | ||
271 | /* Watchdog Core Ops */ | 271 | /* Watchdog Core Ops */ |
272 | static struct watchdog_ops cdns_wdt_ops = { | 272 | static const struct watchdog_ops cdns_wdt_ops = { |
273 | .owner = THIS_MODULE, | 273 | .owner = THIS_MODULE, |
274 | .start = cdns_wdt_start, | 274 | .start = cdns_wdt_start, |
275 | .stop = cdns_wdt_stop, | 275 | .stop = cdns_wdt_stop, |
@@ -424,8 +424,10 @@ static int __maybe_unused cdns_wdt_suspend(struct device *dev) | |||
424 | struct platform_device *pdev = to_platform_device(dev); | 424 | struct platform_device *pdev = to_platform_device(dev); |
425 | struct cdns_wdt *wdt = platform_get_drvdata(pdev); | 425 | struct cdns_wdt *wdt = platform_get_drvdata(pdev); |
426 | 426 | ||
427 | cdns_wdt_stop(&wdt->cdns_wdt_device); | 427 | if (watchdog_active(&wdt->cdns_wdt_device)) { |
428 | clk_disable_unprepare(wdt->clk); | 428 | cdns_wdt_stop(&wdt->cdns_wdt_device); |
429 | clk_disable_unprepare(wdt->clk); | ||
430 | } | ||
429 | 431 | ||
430 | return 0; | 432 | return 0; |
431 | } | 433 | } |
@@ -442,12 +444,14 @@ static int __maybe_unused cdns_wdt_resume(struct device *dev) | |||
442 | struct platform_device *pdev = to_platform_device(dev); | 444 | struct platform_device *pdev = to_platform_device(dev); |
443 | struct cdns_wdt *wdt = platform_get_drvdata(pdev); | 445 | struct cdns_wdt *wdt = platform_get_drvdata(pdev); |
444 | 446 | ||
445 | ret = clk_prepare_enable(wdt->clk); | 447 | if (watchdog_active(&wdt->cdns_wdt_device)) { |
446 | if (ret) { | 448 | ret = clk_prepare_enable(wdt->clk); |
447 | dev_err(dev, "unable to enable clock\n"); | 449 | if (ret) { |
448 | return ret; | 450 | dev_err(dev, "unable to enable clock\n"); |
451 | return ret; | ||
452 | } | ||
453 | cdns_wdt_start(&wdt->cdns_wdt_device); | ||
449 | } | 454 | } |
450 | cdns_wdt_start(&wdt->cdns_wdt_device); | ||
451 | 455 | ||
452 | return 0; | 456 | return 0; |
453 | } | 457 | } |
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 2acb51cf5504..3c6a3de13a1b 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c | |||
@@ -54,6 +54,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " | |||
54 | struct dw_wdt { | 54 | struct dw_wdt { |
55 | void __iomem *regs; | 55 | void __iomem *regs; |
56 | struct clk *clk; | 56 | struct clk *clk; |
57 | unsigned long rate; | ||
57 | struct notifier_block restart_handler; | 58 | struct notifier_block restart_handler; |
58 | struct watchdog_device wdd; | 59 | struct watchdog_device wdd; |
59 | }; | 60 | }; |
@@ -72,7 +73,7 @@ static inline int dw_wdt_top_in_seconds(struct dw_wdt *dw_wdt, unsigned top) | |||
72 | * There are 16 possible timeout values in 0..15 where the number of | 73 | * There are 16 possible timeout values in 0..15 where the number of |
73 | * cycles is 2 ^ (16 + i) and the watchdog counts down. | 74 | * cycles is 2 ^ (16 + i) and the watchdog counts down. |
74 | */ | 75 | */ |
75 | return (1U << (16 + top)) / clk_get_rate(dw_wdt->clk); | 76 | return (1U << (16 + top)) / dw_wdt->rate; |
76 | } | 77 | } |
77 | 78 | ||
78 | static int dw_wdt_get_top(struct dw_wdt *dw_wdt) | 79 | static int dw_wdt_get_top(struct dw_wdt *dw_wdt) |
@@ -163,7 +164,7 @@ static unsigned int dw_wdt_get_timeleft(struct watchdog_device *wdd) | |||
163 | struct dw_wdt *dw_wdt = to_dw_wdt(wdd); | 164 | struct dw_wdt *dw_wdt = to_dw_wdt(wdd); |
164 | 165 | ||
165 | return readl(dw_wdt->regs + WDOG_CURRENT_COUNT_REG_OFFSET) / | 166 | return readl(dw_wdt->regs + WDOG_CURRENT_COUNT_REG_OFFSET) / |
166 | clk_get_rate(dw_wdt->clk); | 167 | dw_wdt->rate; |
167 | } | 168 | } |
168 | 169 | ||
169 | static const struct watchdog_info dw_wdt_ident = { | 170 | static const struct watchdog_info dw_wdt_ident = { |
@@ -231,6 +232,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) | |||
231 | if (ret) | 232 | if (ret) |
232 | return ret; | 233 | return ret; |
233 | 234 | ||
235 | dw_wdt->rate = clk_get_rate(dw_wdt->clk); | ||
236 | if (dw_wdt->rate == 0) { | ||
237 | ret = -EINVAL; | ||
238 | goto out_disable_clk; | ||
239 | } | ||
240 | |||
234 | wdd = &dw_wdt->wdd; | 241 | wdd = &dw_wdt->wdd; |
235 | wdd->info = &dw_wdt_ident; | 242 | wdd->info = &dw_wdt_ident; |
236 | wdd->ops = &dw_wdt_ops; | 243 | wdd->ops = &dw_wdt_ops; |
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 8f89bd8a826a..70c7194e2810 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <asm/nmi.h> | 39 | #include <asm/nmi.h> |
40 | #include <asm/frame.h> | 40 | #include <asm/frame.h> |
41 | 41 | ||
42 | #define HPWDT_VERSION "1.3.3" | 42 | #define HPWDT_VERSION "1.4.0" |
43 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) | 43 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) |
44 | #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) | 44 | #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) |
45 | #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) | 45 | #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) |
@@ -814,7 +814,8 @@ static int hpwdt_init_one(struct pci_dev *dev, | |||
814 | * not run on a legacy ASM box. | 814 | * not run on a legacy ASM box. |
815 | * So we only support the G5 ProLiant servers and higher. | 815 | * So we only support the G5 ProLiant servers and higher. |
816 | */ | 816 | */ |
817 | if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) { | 817 | if (dev->subsystem_vendor != PCI_VENDOR_ID_HP && |
818 | dev->subsystem_vendor != PCI_VENDOR_ID_HP_3PAR) { | ||
818 | dev_warn(&dev->dev, | 819 | dev_warn(&dev->dev, |
819 | "This server does not have an iLO2+ ASIC.\n"); | 820 | "This server does not have an iLO2+ ASIC.\n"); |
820 | return -ENODEV; | 821 | return -ENODEV; |
@@ -823,7 +824,8 @@ static int hpwdt_init_one(struct pci_dev *dev, | |||
823 | /* | 824 | /* |
824 | * Ignore all auxilary iLO devices with the following PCI ID | 825 | * Ignore all auxilary iLO devices with the following PCI ID |
825 | */ | 826 | */ |
826 | if (dev->subsystem_device == 0x1979) | 827 | if (dev->subsystem_vendor == PCI_VENDOR_ID_HP && |
828 | dev->subsystem_device == 0x1979) | ||
827 | return -ENODEV; | 829 | return -ENODEV; |
828 | 830 | ||
829 | if (pci_enable_device(dev)) { | 831 | if (pci_enable_device(dev)) { |
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 54cab189a763..06fcb6c8c917 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c | |||
@@ -629,7 +629,7 @@ static int iTCO_wdt_resume_noirq(struct device *dev) | |||
629 | return 0; | 629 | return 0; |
630 | } | 630 | } |
631 | 631 | ||
632 | static struct dev_pm_ops iTCO_wdt_pm = { | 632 | static const struct dev_pm_ops iTCO_wdt_pm = { |
633 | .suspend_noirq = iTCO_wdt_suspend_noirq, | 633 | .suspend_noirq = iTCO_wdt_suspend_noirq, |
634 | .resume_noirq = iTCO_wdt_resume_noirq, | 634 | .resume_noirq = iTCO_wdt_resume_noirq, |
635 | }; | 635 | }; |
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 62f346bb4348..4874b0f18650 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/interrupt.h> | ||
27 | #include <linux/io.h> | 28 | #include <linux/io.h> |
28 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
29 | #include <linux/module.h> | 30 | #include <linux/module.h> |
@@ -37,18 +38,23 @@ | |||
37 | 38 | ||
38 | #define IMX2_WDT_WCR 0x00 /* Control Register */ | 39 | #define IMX2_WDT_WCR 0x00 /* Control Register */ |
39 | #define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */ | 40 | #define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */ |
40 | #define IMX2_WDT_WCR_WDA (1 << 5) /* -> External Reset WDOG_B */ | 41 | #define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */ |
41 | #define IMX2_WDT_WCR_SRS (1 << 4) /* -> Software Reset Signal */ | 42 | #define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */ |
42 | #define IMX2_WDT_WCR_WRE (1 << 3) /* -> WDOG Reset Enable */ | 43 | #define IMX2_WDT_WCR_WRE BIT(3) /* -> WDOG Reset Enable */ |
43 | #define IMX2_WDT_WCR_WDE (1 << 2) /* -> Watchdog Enable */ | 44 | #define IMX2_WDT_WCR_WDE BIT(2) /* -> Watchdog Enable */ |
44 | #define IMX2_WDT_WCR_WDZST (1 << 0) /* -> Watchdog timer Suspend */ | 45 | #define IMX2_WDT_WCR_WDZST BIT(0) /* -> Watchdog timer Suspend */ |
45 | 46 | ||
46 | #define IMX2_WDT_WSR 0x02 /* Service Register */ | 47 | #define IMX2_WDT_WSR 0x02 /* Service Register */ |
47 | #define IMX2_WDT_SEQ1 0x5555 /* -> service sequence 1 */ | 48 | #define IMX2_WDT_SEQ1 0x5555 /* -> service sequence 1 */ |
48 | #define IMX2_WDT_SEQ2 0xAAAA /* -> service sequence 2 */ | 49 | #define IMX2_WDT_SEQ2 0xAAAA /* -> service sequence 2 */ |
49 | 50 | ||
50 | #define IMX2_WDT_WRSR 0x04 /* Reset Status Register */ | 51 | #define IMX2_WDT_WRSR 0x04 /* Reset Status Register */ |
51 | #define IMX2_WDT_WRSR_TOUT (1 << 1) /* -> Reset due to Timeout */ | 52 | #define IMX2_WDT_WRSR_TOUT BIT(1) /* -> Reset due to Timeout */ |
53 | |||
54 | #define IMX2_WDT_WICR 0x06 /* Interrupt Control Register */ | ||
55 | #define IMX2_WDT_WICR_WIE BIT(15) /* -> Interrupt Enable */ | ||
56 | #define IMX2_WDT_WICR_WTIS BIT(14) /* -> Interrupt Status */ | ||
57 | #define IMX2_WDT_WICR_WICT 0xFF /* -> Interrupt Count Timeout */ | ||
52 | 58 | ||
53 | #define IMX2_WDT_WMCR 0x08 /* Misc Register */ | 59 | #define IMX2_WDT_WMCR 0x08 /* Misc Register */ |
54 | 60 | ||
@@ -80,6 +86,12 @@ static const struct watchdog_info imx2_wdt_info = { | |||
80 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 86 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, |
81 | }; | 87 | }; |
82 | 88 | ||
89 | static const struct watchdog_info imx2_wdt_pretimeout_info = { | ||
90 | .identity = "imx2+ watchdog", | ||
91 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | | ||
92 | WDIOF_PRETIMEOUT, | ||
93 | }; | ||
94 | |||
83 | static int imx2_wdt_restart(struct watchdog_device *wdog, unsigned long action, | 95 | static int imx2_wdt_restart(struct watchdog_device *wdog, unsigned long action, |
84 | void *data) | 96 | void *data) |
85 | { | 97 | { |
@@ -169,6 +181,35 @@ static int imx2_wdt_set_timeout(struct watchdog_device *wdog, | |||
169 | return 0; | 181 | return 0; |
170 | } | 182 | } |
171 | 183 | ||
184 | static int imx2_wdt_set_pretimeout(struct watchdog_device *wdog, | ||
185 | unsigned int new_pretimeout) | ||
186 | { | ||
187 | struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); | ||
188 | |||
189 | if (new_pretimeout >= IMX2_WDT_MAX_TIME) | ||
190 | return -EINVAL; | ||
191 | |||
192 | wdog->pretimeout = new_pretimeout; | ||
193 | |||
194 | regmap_update_bits(wdev->regmap, IMX2_WDT_WICR, | ||
195 | IMX2_WDT_WICR_WIE | IMX2_WDT_WICR_WICT, | ||
196 | IMX2_WDT_WICR_WIE | (new_pretimeout << 1)); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static irqreturn_t imx2_wdt_isr(int irq, void *wdog_arg) | ||
201 | { | ||
202 | struct watchdog_device *wdog = wdog_arg; | ||
203 | struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); | ||
204 | |||
205 | regmap_write_bits(wdev->regmap, IMX2_WDT_WICR, | ||
206 | IMX2_WDT_WICR_WTIS, IMX2_WDT_WICR_WTIS); | ||
207 | |||
208 | watchdog_notify_pretimeout(wdog); | ||
209 | |||
210 | return IRQ_HANDLED; | ||
211 | } | ||
212 | |||
172 | static int imx2_wdt_start(struct watchdog_device *wdog) | 213 | static int imx2_wdt_start(struct watchdog_device *wdog) |
173 | { | 214 | { |
174 | struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); | 215 | struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); |
@@ -188,6 +229,7 @@ static const struct watchdog_ops imx2_wdt_ops = { | |||
188 | .start = imx2_wdt_start, | 229 | .start = imx2_wdt_start, |
189 | .ping = imx2_wdt_ping, | 230 | .ping = imx2_wdt_ping, |
190 | .set_timeout = imx2_wdt_set_timeout, | 231 | .set_timeout = imx2_wdt_set_timeout, |
232 | .set_pretimeout = imx2_wdt_set_pretimeout, | ||
191 | .restart = imx2_wdt_restart, | 233 | .restart = imx2_wdt_restart, |
192 | }; | 234 | }; |
193 | 235 | ||
@@ -236,6 +278,12 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) | |||
236 | wdog->max_hw_heartbeat_ms = IMX2_WDT_MAX_TIME * 1000; | 278 | wdog->max_hw_heartbeat_ms = IMX2_WDT_MAX_TIME * 1000; |
237 | wdog->parent = &pdev->dev; | 279 | wdog->parent = &pdev->dev; |
238 | 280 | ||
281 | ret = platform_get_irq(pdev, 0); | ||
282 | if (ret > 0) | ||
283 | if (!devm_request_irq(&pdev->dev, ret, imx2_wdt_isr, 0, | ||
284 | dev_name(&pdev->dev), wdog)) | ||
285 | wdog->info = &imx2_wdt_pretimeout_info; | ||
286 | |||
239 | ret = clk_prepare_enable(wdev->clk); | 287 | ret = clk_prepare_enable(wdev->clk); |
240 | if (ret) | 288 | if (ret) |
241 | return ret; | 289 | return ret; |
diff --git a/drivers/watchdog/kempld_wdt.c b/drivers/watchdog/kempld_wdt.c index 5bf931ce1353..8e302d0e346c 100644 --- a/drivers/watchdog/kempld_wdt.c +++ b/drivers/watchdog/kempld_wdt.c | |||
@@ -430,7 +430,7 @@ static struct watchdog_info kempld_wdt_info = { | |||
430 | WDIOF_PRETIMEOUT | 430 | WDIOF_PRETIMEOUT |
431 | }; | 431 | }; |
432 | 432 | ||
433 | static struct watchdog_ops kempld_wdt_ops = { | 433 | static const struct watchdog_ops kempld_wdt_ops = { |
434 | .owner = THIS_MODULE, | 434 | .owner = THIS_MODULE, |
435 | .start = kempld_wdt_start, | 435 | .start = kempld_wdt_start, |
436 | .stop = kempld_wdt_stop, | 436 | .stop = kempld_wdt_stop, |
diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c index 4a2290f900a8..d5735c12067d 100644 --- a/drivers/watchdog/mt7621_wdt.c +++ b/drivers/watchdog/mt7621_wdt.c | |||
@@ -139,7 +139,6 @@ static int mt7621_wdt_probe(struct platform_device *pdev) | |||
139 | if (!IS_ERR(mt7621_wdt_reset)) | 139 | if (!IS_ERR(mt7621_wdt_reset)) |
140 | reset_control_deassert(mt7621_wdt_reset); | 140 | reset_control_deassert(mt7621_wdt_reset); |
141 | 141 | ||
142 | mt7621_wdt_dev.dev = &pdev->dev; | ||
143 | mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause(); | 142 | mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause(); |
144 | 143 | ||
145 | watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout, | 144 | watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout, |
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c index b2e1b4cbbdc1..fae7fe929ea3 100644 --- a/drivers/watchdog/of_xilinx_wdt.c +++ b/drivers/watchdog/of_xilinx_wdt.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/clk.h> | ||
13 | #include <linux/err.h> | 14 | #include <linux/err.h> |
14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
15 | #include <linux/types.h> | 16 | #include <linux/types.h> |
@@ -45,6 +46,7 @@ struct xwdt_device { | |||
45 | u32 wdt_interval; | 46 | u32 wdt_interval; |
46 | spinlock_t spinlock; | 47 | spinlock_t spinlock; |
47 | struct watchdog_device xilinx_wdt_wdd; | 48 | struct watchdog_device xilinx_wdt_wdd; |
49 | struct clk *clk; | ||
48 | }; | 50 | }; |
49 | 51 | ||
50 | static int xilinx_wdt_start(struct watchdog_device *wdd) | 52 | static int xilinx_wdt_start(struct watchdog_device *wdd) |
@@ -195,16 +197,30 @@ static int xwdt_probe(struct platform_device *pdev) | |||
195 | spin_lock_init(&xdev->spinlock); | 197 | spin_lock_init(&xdev->spinlock); |
196 | watchdog_set_drvdata(xilinx_wdt_wdd, xdev); | 198 | watchdog_set_drvdata(xilinx_wdt_wdd, xdev); |
197 | 199 | ||
200 | xdev->clk = devm_clk_get(&pdev->dev, NULL); | ||
201 | if (IS_ERR(xdev->clk)) { | ||
202 | if (PTR_ERR(xdev->clk) == -ENOENT) | ||
203 | xdev->clk = NULL; | ||
204 | else | ||
205 | return PTR_ERR(xdev->clk); | ||
206 | } | ||
207 | |||
208 | rc = clk_prepare_enable(xdev->clk); | ||
209 | if (rc) { | ||
210 | dev_err(&pdev->dev, "unable to enable clock\n"); | ||
211 | return rc; | ||
212 | } | ||
213 | |||
198 | rc = xwdt_selftest(xdev); | 214 | rc = xwdt_selftest(xdev); |
199 | if (rc == XWT_TIMER_FAILED) { | 215 | if (rc == XWT_TIMER_FAILED) { |
200 | dev_err(&pdev->dev, "SelfTest routine error\n"); | 216 | dev_err(&pdev->dev, "SelfTest routine error\n"); |
201 | return rc; | 217 | goto err_clk_disable; |
202 | } | 218 | } |
203 | 219 | ||
204 | rc = watchdog_register_device(xilinx_wdt_wdd); | 220 | rc = watchdog_register_device(xilinx_wdt_wdd); |
205 | if (rc) { | 221 | if (rc) { |
206 | dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc); | 222 | dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc); |
207 | return rc; | 223 | goto err_clk_disable; |
208 | } | 224 | } |
209 | 225 | ||
210 | dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n", | 226 | dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n", |
@@ -213,6 +229,10 @@ static int xwdt_probe(struct platform_device *pdev) | |||
213 | platform_set_drvdata(pdev, xdev); | 229 | platform_set_drvdata(pdev, xdev); |
214 | 230 | ||
215 | return 0; | 231 | return 0; |
232 | err_clk_disable: | ||
233 | clk_disable_unprepare(xdev->clk); | ||
234 | |||
235 | return rc; | ||
216 | } | 236 | } |
217 | 237 | ||
218 | static int xwdt_remove(struct platform_device *pdev) | 238 | static int xwdt_remove(struct platform_device *pdev) |
@@ -220,6 +240,7 @@ static int xwdt_remove(struct platform_device *pdev) | |||
220 | struct xwdt_device *xdev = platform_get_drvdata(pdev); | 240 | struct xwdt_device *xdev = platform_get_drvdata(pdev); |
221 | 241 | ||
222 | watchdog_unregister_device(&xdev->xilinx_wdt_wdd); | 242 | watchdog_unregister_device(&xdev->xilinx_wdt_wdd); |
243 | clk_disable_unprepare(xdev->clk); | ||
223 | 244 | ||
224 | return 0; | 245 | return 0; |
225 | } | 246 | } |
diff --git a/drivers/watchdog/pretimeout_noop.c b/drivers/watchdog/pretimeout_noop.c new file mode 100644 index 000000000000..85f5299d197c --- /dev/null +++ b/drivers/watchdog/pretimeout_noop.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015-2016 Mentor Graphics | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/printk.h> | ||
13 | #include <linux/watchdog.h> | ||
14 | |||
15 | #include "watchdog_pretimeout.h" | ||
16 | |||
17 | /** | ||
18 | * pretimeout_noop - No operation on watchdog pretimeout event | ||
19 | * @wdd - watchdog_device | ||
20 | * | ||
21 | * This function prints a message about pretimeout to kernel log. | ||
22 | */ | ||
23 | static void pretimeout_noop(struct watchdog_device *wdd) | ||
24 | { | ||
25 | pr_alert("watchdog%d: pretimeout event\n", wdd->id); | ||
26 | } | ||
27 | |||
28 | static struct watchdog_governor watchdog_gov_noop = { | ||
29 | .name = "noop", | ||
30 | .pretimeout = pretimeout_noop, | ||
31 | }; | ||
32 | |||
33 | static int __init watchdog_gov_noop_register(void) | ||
34 | { | ||
35 | return watchdog_register_governor(&watchdog_gov_noop); | ||
36 | } | ||
37 | |||
38 | static void __exit watchdog_gov_noop_unregister(void) | ||
39 | { | ||
40 | watchdog_unregister_governor(&watchdog_gov_noop); | ||
41 | } | ||
42 | module_init(watchdog_gov_noop_register); | ||
43 | module_exit(watchdog_gov_noop_unregister); | ||
44 | |||
45 | MODULE_AUTHOR("Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>"); | ||
46 | MODULE_DESCRIPTION("Panic watchdog pretimeout governor"); | ||
47 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/watchdog/pretimeout_panic.c b/drivers/watchdog/pretimeout_panic.c new file mode 100644 index 000000000000..0c197a1c97f4 --- /dev/null +++ b/drivers/watchdog/pretimeout_panic.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015-2016 Mentor Graphics | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/watchdog.h> | ||
14 | |||
15 | #include "watchdog_pretimeout.h" | ||
16 | |||
17 | /** | ||
18 | * pretimeout_panic - Panic on watchdog pretimeout event | ||
19 | * @wdd - watchdog_device | ||
20 | * | ||
21 | * Panic, watchdog has not been fed till pretimeout event. | ||
22 | */ | ||
23 | static void pretimeout_panic(struct watchdog_device *wdd) | ||
24 | { | ||
25 | panic("watchdog pretimeout event\n"); | ||
26 | } | ||
27 | |||
28 | static struct watchdog_governor watchdog_gov_panic = { | ||
29 | .name = "panic", | ||
30 | .pretimeout = pretimeout_panic, | ||
31 | }; | ||
32 | |||
33 | static int __init watchdog_gov_panic_register(void) | ||
34 | { | ||
35 | return watchdog_register_governor(&watchdog_gov_panic); | ||
36 | } | ||
37 | |||
38 | static void __exit watchdog_gov_panic_unregister(void) | ||
39 | { | ||
40 | watchdog_unregister_governor(&watchdog_gov_panic); | ||
41 | } | ||
42 | module_init(watchdog_gov_panic_register); | ||
43 | module_exit(watchdog_gov_panic_unregister); | ||
44 | |||
45 | MODULE_AUTHOR("Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>"); | ||
46 | MODULE_DESCRIPTION("Panic watchdog pretimeout governor"); | ||
47 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/watchdog/rn5t618_wdt.c b/drivers/watchdog/rn5t618_wdt.c index d1c12278cb6a..0805ee2acd7a 100644 --- a/drivers/watchdog/rn5t618_wdt.c +++ b/drivers/watchdog/rn5t618_wdt.c | |||
@@ -136,7 +136,7 @@ static struct watchdog_info rn5t618_wdt_info = { | |||
136 | .identity = DRIVER_NAME, | 136 | .identity = DRIVER_NAME, |
137 | }; | 137 | }; |
138 | 138 | ||
139 | static struct watchdog_ops rn5t618_wdt_ops = { | 139 | static const struct watchdog_ops rn5t618_wdt_ops = { |
140 | .owner = THIS_MODULE, | 140 | .owner = THIS_MODULE, |
141 | .start = rn5t618_wdt_start, | 141 | .start = rn5t618_wdt_start, |
142 | .stop = rn5t618_wdt_stop, | 142 | .stop = rn5t618_wdt_stop, |
diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index 1967919ae743..14b4fd428fff 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c | |||
@@ -158,7 +158,6 @@ static int rt288x_wdt_probe(struct platform_device *pdev) | |||
158 | 158 | ||
159 | rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE; | 159 | rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE; |
160 | 160 | ||
161 | rt288x_wdt_dev.dev = &pdev->dev; | ||
162 | rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); | 161 | rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); |
163 | rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); | 162 | rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); |
164 | rt288x_wdt_dev.parent = &pdev->dev; | 163 | rt288x_wdt_dev.parent = &pdev->dev; |
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c index b067edf246df..c7bdc986dca1 100644 --- a/drivers/watchdog/softdog.c +++ b/drivers/watchdog/softdog.c | |||
@@ -72,10 +72,27 @@ static void softdog_fire(unsigned long data) | |||
72 | static struct timer_list softdog_ticktock = | 72 | static struct timer_list softdog_ticktock = |
73 | TIMER_INITIALIZER(softdog_fire, 0, 0); | 73 | TIMER_INITIALIZER(softdog_fire, 0, 0); |
74 | 74 | ||
75 | static struct watchdog_device softdog_dev; | ||
76 | |||
77 | static void softdog_pretimeout(unsigned long data) | ||
78 | { | ||
79 | watchdog_notify_pretimeout(&softdog_dev); | ||
80 | } | ||
81 | |||
82 | static struct timer_list softdog_preticktock = | ||
83 | TIMER_INITIALIZER(softdog_pretimeout, 0, 0); | ||
84 | |||
75 | static int softdog_ping(struct watchdog_device *w) | 85 | static int softdog_ping(struct watchdog_device *w) |
76 | { | 86 | { |
77 | if (!mod_timer(&softdog_ticktock, jiffies + (w->timeout * HZ))) | 87 | if (!mod_timer(&softdog_ticktock, jiffies + (w->timeout * HZ))) |
78 | __module_get(THIS_MODULE); | 88 | __module_get(THIS_MODULE); |
89 | |||
90 | if (w->pretimeout) | ||
91 | mod_timer(&softdog_preticktock, jiffies + | ||
92 | (w->timeout - w->pretimeout) * HZ); | ||
93 | else | ||
94 | del_timer(&softdog_preticktock); | ||
95 | |||
79 | return 0; | 96 | return 0; |
80 | } | 97 | } |
81 | 98 | ||
@@ -84,15 +101,18 @@ static int softdog_stop(struct watchdog_device *w) | |||
84 | if (del_timer(&softdog_ticktock)) | 101 | if (del_timer(&softdog_ticktock)) |
85 | module_put(THIS_MODULE); | 102 | module_put(THIS_MODULE); |
86 | 103 | ||
104 | del_timer(&softdog_preticktock); | ||
105 | |||
87 | return 0; | 106 | return 0; |
88 | } | 107 | } |
89 | 108 | ||
90 | static struct watchdog_info softdog_info = { | 109 | static struct watchdog_info softdog_info = { |
91 | .identity = "Software Watchdog", | 110 | .identity = "Software Watchdog", |
92 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | 111 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | |
112 | WDIOF_PRETIMEOUT, | ||
93 | }; | 113 | }; |
94 | 114 | ||
95 | static struct watchdog_ops softdog_ops = { | 115 | static const struct watchdog_ops softdog_ops = { |
96 | .owner = THIS_MODULE, | 116 | .owner = THIS_MODULE, |
97 | .start = softdog_ping, | 117 | .start = softdog_ping, |
98 | .stop = softdog_stop, | 118 | .stop = softdog_stop, |
diff --git a/drivers/watchdog/st_lpc_wdt.c b/drivers/watchdog/st_lpc_wdt.c index 14e9badf2bfa..e6100e447dd8 100644 --- a/drivers/watchdog/st_lpc_wdt.c +++ b/drivers/watchdog/st_lpc_wdt.c | |||
@@ -52,27 +52,6 @@ struct st_wdog { | |||
52 | bool warm_reset; | 52 | bool warm_reset; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | static struct st_wdog_syscfg stid127_syscfg = { | ||
56 | .reset_type_reg = 0x004, | ||
57 | .reset_type_mask = BIT(2), | ||
58 | .enable_reg = 0x000, | ||
59 | .enable_mask = BIT(2), | ||
60 | }; | ||
61 | |||
62 | static struct st_wdog_syscfg stih415_syscfg = { | ||
63 | .reset_type_reg = 0x0B8, | ||
64 | .reset_type_mask = BIT(6), | ||
65 | .enable_reg = 0x0B4, | ||
66 | .enable_mask = BIT(7), | ||
67 | }; | ||
68 | |||
69 | static struct st_wdog_syscfg stih416_syscfg = { | ||
70 | .reset_type_reg = 0x88C, | ||
71 | .reset_type_mask = BIT(6), | ||
72 | .enable_reg = 0x888, | ||
73 | .enable_mask = BIT(7), | ||
74 | }; | ||
75 | |||
76 | static struct st_wdog_syscfg stih407_syscfg = { | 55 | static struct st_wdog_syscfg stih407_syscfg = { |
77 | .enable_reg = 0x204, | 56 | .enable_reg = 0x204, |
78 | .enable_mask = BIT(19), | 57 | .enable_mask = BIT(19), |
@@ -83,18 +62,6 @@ static const struct of_device_id st_wdog_match[] = { | |||
83 | .compatible = "st,stih407-lpc", | 62 | .compatible = "st,stih407-lpc", |
84 | .data = &stih407_syscfg, | 63 | .data = &stih407_syscfg, |
85 | }, | 64 | }, |
86 | { | ||
87 | .compatible = "st,stih416-lpc", | ||
88 | .data = &stih416_syscfg, | ||
89 | }, | ||
90 | { | ||
91 | .compatible = "st,stih415-lpc", | ||
92 | .data = &stih415_syscfg, | ||
93 | }, | ||
94 | { | ||
95 | .compatible = "st,stid127-lpc", | ||
96 | .data = &stid127_syscfg, | ||
97 | }, | ||
98 | {}, | 65 | {}, |
99 | }; | 66 | }; |
100 | MODULE_DEVICE_TABLE(of, st_wdog_match); | 67 | MODULE_DEVICE_TABLE(of, st_wdog_match); |
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index 9ec57608da82..2d53c3f9394f 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c | |||
@@ -178,7 +178,7 @@ static const struct watchdog_info tegra_wdt_info = { | |||
178 | .identity = "Tegra Watchdog", | 178 | .identity = "Tegra Watchdog", |
179 | }; | 179 | }; |
180 | 180 | ||
181 | static struct watchdog_ops tegra_wdt_ops = { | 181 | static const struct watchdog_ops tegra_wdt_ops = { |
182 | .owner = THIS_MODULE, | 182 | .owner = THIS_MODULE, |
183 | .start = tegra_wdt_start, | 183 | .start = tegra_wdt_start, |
184 | .stop = tegra_wdt_stop, | 184 | .stop = tegra_wdt_stop, |
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index c2da880292bc..6f7a9deb27d0 100644 --- a/drivers/watchdog/txx9wdt.c +++ b/drivers/watchdog/txx9wdt.c | |||
@@ -112,7 +112,7 @@ static int __init txx9wdt_probe(struct platform_device *dev) | |||
112 | txx9_imclk = NULL; | 112 | txx9_imclk = NULL; |
113 | goto exit; | 113 | goto exit; |
114 | } | 114 | } |
115 | ret = clk_enable(txx9_imclk); | 115 | ret = clk_prepare_enable(txx9_imclk); |
116 | if (ret) { | 116 | if (ret) { |
117 | clk_put(txx9_imclk); | 117 | clk_put(txx9_imclk); |
118 | txx9_imclk = NULL; | 118 | txx9_imclk = NULL; |
@@ -144,7 +144,7 @@ static int __init txx9wdt_probe(struct platform_device *dev) | |||
144 | return 0; | 144 | return 0; |
145 | exit: | 145 | exit: |
146 | if (txx9_imclk) { | 146 | if (txx9_imclk) { |
147 | clk_disable(txx9_imclk); | 147 | clk_disable_unprepare(txx9_imclk); |
148 | clk_put(txx9_imclk); | 148 | clk_put(txx9_imclk); |
149 | } | 149 | } |
150 | return ret; | 150 | return ret; |
@@ -153,7 +153,7 @@ exit: | |||
153 | static int __exit txx9wdt_remove(struct platform_device *dev) | 153 | static int __exit txx9wdt_remove(struct platform_device *dev) |
154 | { | 154 | { |
155 | watchdog_unregister_device(&txx9wdt); | 155 | watchdog_unregister_device(&txx9wdt); |
156 | clk_disable(txx9_imclk); | 156 | clk_disable_unprepare(txx9_imclk); |
157 | clk_put(txx9_imclk); | 157 | clk_put(txx9_imclk); |
158 | return 0; | 158 | return 0; |
159 | } | 159 | } |
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 09e8003039dc..ef2ecaf53a14 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c | |||
@@ -302,7 +302,7 @@ static struct watchdog_info wdt_info = { | |||
302 | .identity = "W83627HF Watchdog", | 302 | .identity = "W83627HF Watchdog", |
303 | }; | 303 | }; |
304 | 304 | ||
305 | static struct watchdog_ops wdt_ops = { | 305 | static const struct watchdog_ops wdt_ops = { |
306 | .owner = THIS_MODULE, | 306 | .owner = THIS_MODULE, |
307 | .start = wdt_start, | 307 | .start = wdt_start, |
308 | .stop = wdt_stop, | 308 | .stop = wdt_stop, |
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index 6abb83cd7681..74265b2f806c 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c | |||
@@ -349,7 +349,7 @@ int devm_watchdog_register_device(struct device *dev, | |||
349 | struct watchdog_device **rcwdd; | 349 | struct watchdog_device **rcwdd; |
350 | int ret; | 350 | int ret; |
351 | 351 | ||
352 | rcwdd = devres_alloc(devm_watchdog_unregister_device, sizeof(*wdd), | 352 | rcwdd = devres_alloc(devm_watchdog_unregister_device, sizeof(*rcwdd), |
353 | GFP_KERNEL); | 353 | GFP_KERNEL); |
354 | if (!rcwdd) | 354 | if (!rcwdd) |
355 | return -ENOMEM; | 355 | return -ENOMEM; |
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 040bf8382f46..32930a073a12 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | 49 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ |
50 | 50 | ||
51 | #include "watchdog_core.h" | 51 | #include "watchdog_core.h" |
52 | #include "watchdog_pretimeout.h" | ||
52 | 53 | ||
53 | /* | 54 | /* |
54 | * struct watchdog_core_data - watchdog core internal data | 55 | * struct watchdog_core_data - watchdog core internal data |
@@ -335,10 +336,14 @@ static int watchdog_set_timeout(struct watchdog_device *wdd, | |||
335 | if (watchdog_timeout_invalid(wdd, timeout)) | 336 | if (watchdog_timeout_invalid(wdd, timeout)) |
336 | return -EINVAL; | 337 | return -EINVAL; |
337 | 338 | ||
338 | if (wdd->ops->set_timeout) | 339 | if (wdd->ops->set_timeout) { |
339 | err = wdd->ops->set_timeout(wdd, timeout); | 340 | err = wdd->ops->set_timeout(wdd, timeout); |
340 | else | 341 | } else { |
341 | wdd->timeout = timeout; | 342 | wdd->timeout = timeout; |
343 | /* Disable pretimeout if it doesn't fit the new timeout */ | ||
344 | if (wdd->pretimeout >= wdd->timeout) | ||
345 | wdd->pretimeout = 0; | ||
346 | } | ||
342 | 347 | ||
343 | watchdog_update_worker(wdd); | 348 | watchdog_update_worker(wdd); |
344 | 349 | ||
@@ -346,6 +351,31 @@ static int watchdog_set_timeout(struct watchdog_device *wdd, | |||
346 | } | 351 | } |
347 | 352 | ||
348 | /* | 353 | /* |
354 | * watchdog_set_pretimeout: set the watchdog timer pretimeout | ||
355 | * @wdd: the watchdog device to set the timeout for | ||
356 | * @timeout: pretimeout to set in seconds | ||
357 | */ | ||
358 | |||
359 | static int watchdog_set_pretimeout(struct watchdog_device *wdd, | ||
360 | unsigned int timeout) | ||
361 | { | ||
362 | int err = 0; | ||
363 | |||
364 | if (!(wdd->info->options & WDIOF_PRETIMEOUT)) | ||
365 | return -EOPNOTSUPP; | ||
366 | |||
367 | if (watchdog_pretimeout_invalid(wdd, timeout)) | ||
368 | return -EINVAL; | ||
369 | |||
370 | if (wdd->ops->set_pretimeout) | ||
371 | err = wdd->ops->set_pretimeout(wdd, timeout); | ||
372 | else | ||
373 | wdd->pretimeout = timeout; | ||
374 | |||
375 | return err; | ||
376 | } | ||
377 | |||
378 | /* | ||
349 | * watchdog_get_timeleft: wrapper to get the time left before a reboot | 379 | * watchdog_get_timeleft: wrapper to get the time left before a reboot |
350 | * @wdd: the watchdog device to get the remaining time from | 380 | * @wdd: the watchdog device to get the remaining time from |
351 | * @timeleft: the time that's left | 381 | * @timeleft: the time that's left |
@@ -429,6 +459,15 @@ static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, | |||
429 | } | 459 | } |
430 | static DEVICE_ATTR_RO(timeout); | 460 | static DEVICE_ATTR_RO(timeout); |
431 | 461 | ||
462 | static ssize_t pretimeout_show(struct device *dev, | ||
463 | struct device_attribute *attr, char *buf) | ||
464 | { | ||
465 | struct watchdog_device *wdd = dev_get_drvdata(dev); | ||
466 | |||
467 | return sprintf(buf, "%u\n", wdd->pretimeout); | ||
468 | } | ||
469 | static DEVICE_ATTR_RO(pretimeout); | ||
470 | |||
432 | static ssize_t identity_show(struct device *dev, struct device_attribute *attr, | 471 | static ssize_t identity_show(struct device *dev, struct device_attribute *attr, |
433 | char *buf) | 472 | char *buf) |
434 | { | 473 | { |
@@ -450,6 +489,36 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, | |||
450 | } | 489 | } |
451 | static DEVICE_ATTR_RO(state); | 490 | static DEVICE_ATTR_RO(state); |
452 | 491 | ||
492 | static ssize_t pretimeout_available_governors_show(struct device *dev, | ||
493 | struct device_attribute *attr, char *buf) | ||
494 | { | ||
495 | return watchdog_pretimeout_available_governors_get(buf); | ||
496 | } | ||
497 | static DEVICE_ATTR_RO(pretimeout_available_governors); | ||
498 | |||
499 | static ssize_t pretimeout_governor_show(struct device *dev, | ||
500 | struct device_attribute *attr, | ||
501 | char *buf) | ||
502 | { | ||
503 | struct watchdog_device *wdd = dev_get_drvdata(dev); | ||
504 | |||
505 | return watchdog_pretimeout_governor_get(wdd, buf); | ||
506 | } | ||
507 | |||
508 | static ssize_t pretimeout_governor_store(struct device *dev, | ||
509 | struct device_attribute *attr, | ||
510 | const char *buf, size_t count) | ||
511 | { | ||
512 | struct watchdog_device *wdd = dev_get_drvdata(dev); | ||
513 | int ret = watchdog_pretimeout_governor_set(wdd, buf); | ||
514 | |||
515 | if (!ret) | ||
516 | ret = count; | ||
517 | |||
518 | return ret; | ||
519 | } | ||
520 | static DEVICE_ATTR_RW(pretimeout_governor); | ||
521 | |||
453 | static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr, | 522 | static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr, |
454 | int n) | 523 | int n) |
455 | { | 524 | { |
@@ -459,6 +528,14 @@ static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr, | |||
459 | 528 | ||
460 | if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft) | 529 | if (attr == &dev_attr_timeleft.attr && !wdd->ops->get_timeleft) |
461 | mode = 0; | 530 | mode = 0; |
531 | else if (attr == &dev_attr_pretimeout.attr && | ||
532 | !(wdd->info->options & WDIOF_PRETIMEOUT)) | ||
533 | mode = 0; | ||
534 | else if ((attr == &dev_attr_pretimeout_governor.attr || | ||
535 | attr == &dev_attr_pretimeout_available_governors.attr) && | ||
536 | (!(wdd->info->options & WDIOF_PRETIMEOUT) || | ||
537 | !IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV))) | ||
538 | mode = 0; | ||
462 | 539 | ||
463 | return mode; | 540 | return mode; |
464 | } | 541 | } |
@@ -466,10 +543,13 @@ static struct attribute *wdt_attrs[] = { | |||
466 | &dev_attr_state.attr, | 543 | &dev_attr_state.attr, |
467 | &dev_attr_identity.attr, | 544 | &dev_attr_identity.attr, |
468 | &dev_attr_timeout.attr, | 545 | &dev_attr_timeout.attr, |
546 | &dev_attr_pretimeout.attr, | ||
469 | &dev_attr_timeleft.attr, | 547 | &dev_attr_timeleft.attr, |
470 | &dev_attr_bootstatus.attr, | 548 | &dev_attr_bootstatus.attr, |
471 | &dev_attr_status.attr, | 549 | &dev_attr_status.attr, |
472 | &dev_attr_nowayout.attr, | 550 | &dev_attr_nowayout.attr, |
551 | &dev_attr_pretimeout_governor.attr, | ||
552 | &dev_attr_pretimeout_available_governors.attr, | ||
473 | NULL, | 553 | NULL, |
474 | }; | 554 | }; |
475 | 555 | ||
@@ -646,6 +726,16 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, | |||
646 | break; | 726 | break; |
647 | err = put_user(val, p); | 727 | err = put_user(val, p); |
648 | break; | 728 | break; |
729 | case WDIOC_SETPRETIMEOUT: | ||
730 | if (get_user(val, p)) { | ||
731 | err = -EFAULT; | ||
732 | break; | ||
733 | } | ||
734 | err = watchdog_set_pretimeout(wdd, val); | ||
735 | break; | ||
736 | case WDIOC_GETPRETIMEOUT: | ||
737 | err = put_user(wdd->pretimeout, p); | ||
738 | break; | ||
649 | default: | 739 | default: |
650 | err = -ENOTTY; | 740 | err = -ENOTTY; |
651 | break; | 741 | break; |
@@ -937,6 +1027,12 @@ int watchdog_dev_register(struct watchdog_device *wdd) | |||
937 | return PTR_ERR(dev); | 1027 | return PTR_ERR(dev); |
938 | } | 1028 | } |
939 | 1029 | ||
1030 | ret = watchdog_register_pretimeout(wdd); | ||
1031 | if (ret) { | ||
1032 | device_destroy(&watchdog_class, devno); | ||
1033 | watchdog_cdev_unregister(wdd); | ||
1034 | } | ||
1035 | |||
940 | return ret; | 1036 | return ret; |
941 | } | 1037 | } |
942 | 1038 | ||
@@ -950,6 +1046,7 @@ int watchdog_dev_register(struct watchdog_device *wdd) | |||
950 | 1046 | ||
951 | void watchdog_dev_unregister(struct watchdog_device *wdd) | 1047 | void watchdog_dev_unregister(struct watchdog_device *wdd) |
952 | { | 1048 | { |
1049 | watchdog_unregister_pretimeout(wdd); | ||
953 | device_destroy(&watchdog_class, wdd->wd_data->cdev.dev); | 1050 | device_destroy(&watchdog_class, wdd->wd_data->cdev.dev); |
954 | watchdog_cdev_unregister(wdd); | 1051 | watchdog_cdev_unregister(wdd); |
955 | } | 1052 | } |
diff --git a/drivers/watchdog/watchdog_pretimeout.c b/drivers/watchdog/watchdog_pretimeout.c new file mode 100644 index 000000000000..9db07bfb4334 --- /dev/null +++ b/drivers/watchdog/watchdog_pretimeout.c | |||
@@ -0,0 +1,220 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015-2016 Mentor Graphics | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/list.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <linux/watchdog.h> | ||
16 | |||
17 | #include "watchdog_pretimeout.h" | ||
18 | |||
19 | /* Default watchdog pretimeout governor */ | ||
20 | static struct watchdog_governor *default_gov; | ||
21 | |||
22 | /* The spinlock protects default_gov, wdd->gov and pretimeout_list */ | ||
23 | static DEFINE_SPINLOCK(pretimeout_lock); | ||
24 | |||
25 | /* List of watchdog devices, which can generate a pretimeout event */ | ||
26 | static LIST_HEAD(pretimeout_list); | ||
27 | |||
28 | struct watchdog_pretimeout { | ||
29 | struct watchdog_device *wdd; | ||
30 | struct list_head entry; | ||
31 | }; | ||
32 | |||
33 | /* The mutex protects governor list and serializes external interfaces */ | ||
34 | static DEFINE_MUTEX(governor_lock); | ||
35 | |||
36 | /* List of the registered watchdog pretimeout governors */ | ||
37 | static LIST_HEAD(governor_list); | ||
38 | |||
39 | struct governor_priv { | ||
40 | struct watchdog_governor *gov; | ||
41 | struct list_head entry; | ||
42 | }; | ||
43 | |||
44 | static struct governor_priv *find_governor_by_name(const char *gov_name) | ||
45 | { | ||
46 | struct governor_priv *priv; | ||
47 | |||
48 | list_for_each_entry(priv, &governor_list, entry) | ||
49 | if (sysfs_streq(gov_name, priv->gov->name)) | ||
50 | return priv; | ||
51 | |||
52 | return NULL; | ||
53 | } | ||
54 | |||
55 | int watchdog_pretimeout_available_governors_get(char *buf) | ||
56 | { | ||
57 | struct governor_priv *priv; | ||
58 | int count = 0; | ||
59 | |||
60 | mutex_lock(&governor_lock); | ||
61 | |||
62 | list_for_each_entry(priv, &governor_list, entry) | ||
63 | count += sprintf(buf + count, "%s\n", priv->gov->name); | ||
64 | |||
65 | mutex_unlock(&governor_lock); | ||
66 | |||
67 | return count; | ||
68 | } | ||
69 | |||
70 | int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf) | ||
71 | { | ||
72 | int count = 0; | ||
73 | |||
74 | spin_lock_irq(&pretimeout_lock); | ||
75 | if (wdd->gov) | ||
76 | count = sprintf(buf, "%s\n", wdd->gov->name); | ||
77 | spin_unlock_irq(&pretimeout_lock); | ||
78 | |||
79 | return count; | ||
80 | } | ||
81 | |||
82 | int watchdog_pretimeout_governor_set(struct watchdog_device *wdd, | ||
83 | const char *buf) | ||
84 | { | ||
85 | struct governor_priv *priv; | ||
86 | |||
87 | mutex_lock(&governor_lock); | ||
88 | |||
89 | priv = find_governor_by_name(buf); | ||
90 | if (!priv) { | ||
91 | mutex_unlock(&governor_lock); | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | spin_lock_irq(&pretimeout_lock); | ||
96 | wdd->gov = priv->gov; | ||
97 | spin_unlock_irq(&pretimeout_lock); | ||
98 | |||
99 | mutex_unlock(&governor_lock); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | void watchdog_notify_pretimeout(struct watchdog_device *wdd) | ||
105 | { | ||
106 | unsigned long flags; | ||
107 | |||
108 | spin_lock_irqsave(&pretimeout_lock, flags); | ||
109 | if (!wdd->gov) { | ||
110 | spin_unlock_irqrestore(&pretimeout_lock, flags); | ||
111 | return; | ||
112 | } | ||
113 | |||
114 | wdd->gov->pretimeout(wdd); | ||
115 | spin_unlock_irqrestore(&pretimeout_lock, flags); | ||
116 | } | ||
117 | EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout); | ||
118 | |||
119 | int watchdog_register_governor(struct watchdog_governor *gov) | ||
120 | { | ||
121 | struct watchdog_pretimeout *p; | ||
122 | struct governor_priv *priv; | ||
123 | |||
124 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
125 | if (!priv) | ||
126 | return -ENOMEM; | ||
127 | |||
128 | mutex_lock(&governor_lock); | ||
129 | |||
130 | if (find_governor_by_name(gov->name)) { | ||
131 | mutex_unlock(&governor_lock); | ||
132 | kfree(priv); | ||
133 | return -EBUSY; | ||
134 | } | ||
135 | |||
136 | priv->gov = gov; | ||
137 | list_add(&priv->entry, &governor_list); | ||
138 | |||
139 | if (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV, | ||
140 | WATCHDOG_GOV_NAME_MAXLEN)) { | ||
141 | spin_lock_irq(&pretimeout_lock); | ||
142 | default_gov = gov; | ||
143 | |||
144 | list_for_each_entry(p, &pretimeout_list, entry) | ||
145 | if (!p->wdd->gov) | ||
146 | p->wdd->gov = default_gov; | ||
147 | spin_unlock_irq(&pretimeout_lock); | ||
148 | } | ||
149 | |||
150 | mutex_unlock(&governor_lock); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | EXPORT_SYMBOL(watchdog_register_governor); | ||
155 | |||
156 | void watchdog_unregister_governor(struct watchdog_governor *gov) | ||
157 | { | ||
158 | struct watchdog_pretimeout *p; | ||
159 | struct governor_priv *priv, *t; | ||
160 | |||
161 | mutex_lock(&governor_lock); | ||
162 | |||
163 | list_for_each_entry_safe(priv, t, &governor_list, entry) { | ||
164 | if (priv->gov == gov) { | ||
165 | list_del(&priv->entry); | ||
166 | kfree(priv); | ||
167 | break; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | spin_lock_irq(&pretimeout_lock); | ||
172 | list_for_each_entry(p, &pretimeout_list, entry) | ||
173 | if (p->wdd->gov == gov) | ||
174 | p->wdd->gov = default_gov; | ||
175 | spin_unlock_irq(&pretimeout_lock); | ||
176 | |||
177 | mutex_unlock(&governor_lock); | ||
178 | } | ||
179 | EXPORT_SYMBOL(watchdog_unregister_governor); | ||
180 | |||
181 | int watchdog_register_pretimeout(struct watchdog_device *wdd) | ||
182 | { | ||
183 | struct watchdog_pretimeout *p; | ||
184 | |||
185 | if (!(wdd->info->options & WDIOF_PRETIMEOUT)) | ||
186 | return 0; | ||
187 | |||
188 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
189 | if (!p) | ||
190 | return -ENOMEM; | ||
191 | |||
192 | spin_lock_irq(&pretimeout_lock); | ||
193 | list_add(&p->entry, &pretimeout_list); | ||
194 | p->wdd = wdd; | ||
195 | wdd->gov = default_gov; | ||
196 | spin_unlock_irq(&pretimeout_lock); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | void watchdog_unregister_pretimeout(struct watchdog_device *wdd) | ||
202 | { | ||
203 | struct watchdog_pretimeout *p, *t; | ||
204 | |||
205 | if (!(wdd->info->options & WDIOF_PRETIMEOUT)) | ||
206 | return; | ||
207 | |||
208 | spin_lock_irq(&pretimeout_lock); | ||
209 | wdd->gov = NULL; | ||
210 | |||
211 | list_for_each_entry_safe(p, t, &pretimeout_list, entry) { | ||
212 | if (p->wdd == wdd) { | ||
213 | list_del(&p->entry); | ||
214 | break; | ||
215 | } | ||
216 | } | ||
217 | spin_unlock_irq(&pretimeout_lock); | ||
218 | |||
219 | kfree(p); | ||
220 | } | ||
diff --git a/drivers/watchdog/watchdog_pretimeout.h b/drivers/watchdog/watchdog_pretimeout.h new file mode 100644 index 000000000000..a5a32b39c56d --- /dev/null +++ b/drivers/watchdog/watchdog_pretimeout.h | |||
@@ -0,0 +1,60 @@ | |||
1 | #ifndef __WATCHDOG_PRETIMEOUT_H | ||
2 | #define __WATCHDOG_PRETIMEOUT_H | ||
3 | |||
4 | #define WATCHDOG_GOV_NAME_MAXLEN 20 | ||
5 | |||
6 | struct watchdog_device; | ||
7 | |||
8 | struct watchdog_governor { | ||
9 | const char name[WATCHDOG_GOV_NAME_MAXLEN]; | ||
10 | void (*pretimeout)(struct watchdog_device *wdd); | ||
11 | }; | ||
12 | |||
13 | #if IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV) | ||
14 | /* Interfaces to watchdog pretimeout governors */ | ||
15 | int watchdog_register_governor(struct watchdog_governor *gov); | ||
16 | void watchdog_unregister_governor(struct watchdog_governor *gov); | ||
17 | |||
18 | /* Interfaces to watchdog_dev.c */ | ||
19 | int watchdog_register_pretimeout(struct watchdog_device *wdd); | ||
20 | void watchdog_unregister_pretimeout(struct watchdog_device *wdd); | ||
21 | int watchdog_pretimeout_available_governors_get(char *buf); | ||
22 | int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf); | ||
23 | int watchdog_pretimeout_governor_set(struct watchdog_device *wdd, | ||
24 | const char *buf); | ||
25 | |||
26 | #if IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP) | ||
27 | #define WATCHDOG_PRETIMEOUT_DEFAULT_GOV "noop" | ||
28 | #elif IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC) | ||
29 | #define WATCHDOG_PRETIMEOUT_DEFAULT_GOV "panic" | ||
30 | #endif | ||
31 | |||
32 | #else | ||
33 | static inline int watchdog_register_pretimeout(struct watchdog_device *wdd) | ||
34 | { | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static inline void watchdog_unregister_pretimeout(struct watchdog_device *wdd) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | static inline int watchdog_pretimeout_available_governors_get(char *buf) | ||
43 | { | ||
44 | return -EINVAL; | ||
45 | } | ||
46 | |||
47 | static inline int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, | ||
48 | char *buf) | ||
49 | { | ||
50 | return -EINVAL; | ||
51 | } | ||
52 | |||
53 | static inline int watchdog_pretimeout_governor_set(struct watchdog_device *wdd, | ||
54 | const char *buf) | ||
55 | { | ||
56 | return -EINVAL; | ||
57 | } | ||
58 | #endif | ||
59 | |||
60 | #endif | ||
diff --git a/drivers/watchdog/ziirave_wdt.c b/drivers/watchdog/ziirave_wdt.c index fa1efef3c96e..b4e0cea5a64e 100644 --- a/drivers/watchdog/ziirave_wdt.c +++ b/drivers/watchdog/ziirave_wdt.c | |||
@@ -18,7 +18,10 @@ | |||
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/delay.h> | ||
21 | #include <linux/i2c.h> | 22 | #include <linux/i2c.h> |
23 | #include <linux/ihex.h> | ||
24 | #include <linux/firmware.h> | ||
22 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
23 | #include <linux/module.h> | 26 | #include <linux/module.h> |
24 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
@@ -36,6 +39,8 @@ | |||
36 | #define ZIIRAVE_STATE_OFF 0x1 | 39 | #define ZIIRAVE_STATE_OFF 0x1 |
37 | #define ZIIRAVE_STATE_ON 0x2 | 40 | #define ZIIRAVE_STATE_ON 0x2 |
38 | 41 | ||
42 | #define ZIIRAVE_FW_NAME "ziirave_wdt.fw" | ||
43 | |||
39 | static char *ziirave_reasons[] = {"power cycle", "hw watchdog", NULL, NULL, | 44 | static char *ziirave_reasons[] = {"power cycle", "hw watchdog", NULL, NULL, |
40 | "host request", NULL, "illegal configuration", | 45 | "host request", NULL, "illegal configuration", |
41 | "illegal instruction", "illegal trap", | 46 | "illegal instruction", "illegal trap", |
@@ -50,12 +55,35 @@ static char *ziirave_reasons[] = {"power cycle", "hw watchdog", NULL, NULL, | |||
50 | #define ZIIRAVE_WDT_PING 0x9 | 55 | #define ZIIRAVE_WDT_PING 0x9 |
51 | #define ZIIRAVE_WDT_RESET_DURATION 0xa | 56 | #define ZIIRAVE_WDT_RESET_DURATION 0xa |
52 | 57 | ||
58 | #define ZIIRAVE_FIRM_PKT_TOTAL_SIZE 20 | ||
59 | #define ZIIRAVE_FIRM_PKT_DATA_SIZE 16 | ||
60 | #define ZIIRAVE_FIRM_FLASH_MEMORY_START 0x1600 | ||
61 | #define ZIIRAVE_FIRM_FLASH_MEMORY_END 0x2bbf | ||
62 | |||
63 | /* Received and ready for next Download packet. */ | ||
64 | #define ZIIRAVE_FIRM_DOWNLOAD_ACK 1 | ||
65 | /* Currently writing to flash. Retry Download status in a moment! */ | ||
66 | #define ZIIRAVE_FIRM_DOWNLOAD_BUSY 2 | ||
67 | |||
68 | /* Wait for ACK timeout in ms */ | ||
69 | #define ZIIRAVE_FIRM_WAIT_FOR_ACK_TIMEOUT 50 | ||
70 | |||
71 | /* Firmware commands */ | ||
72 | #define ZIIRAVE_CMD_DOWNLOAD_START 0x10 | ||
73 | #define ZIIRAVE_CMD_DOWNLOAD_END 0x11 | ||
74 | #define ZIIRAVE_CMD_DOWNLOAD_SET_READ_ADDR 0x12 | ||
75 | #define ZIIRAVE_CMD_DOWNLOAD_READ_BYTE 0x13 | ||
76 | #define ZIIRAVE_CMD_RESET_PROCESSOR 0x0b | ||
77 | #define ZIIRAVE_CMD_JUMP_TO_BOOTLOADER 0x0c | ||
78 | #define ZIIRAVE_CMD_DOWNLOAD_PACKET 0x0e | ||
79 | |||
53 | struct ziirave_wdt_rev { | 80 | struct ziirave_wdt_rev { |
54 | unsigned char major; | 81 | unsigned char major; |
55 | unsigned char minor; | 82 | unsigned char minor; |
56 | }; | 83 | }; |
57 | 84 | ||
58 | struct ziirave_wdt_data { | 85 | struct ziirave_wdt_data { |
86 | struct mutex sysfs_mutex; | ||
59 | struct watchdog_device wdd; | 87 | struct watchdog_device wdd; |
60 | struct ziirave_wdt_rev bootloader_rev; | 88 | struct ziirave_wdt_rev bootloader_rev; |
61 | struct ziirave_wdt_rev firmware_rev; | 89 | struct ziirave_wdt_rev firmware_rev; |
@@ -146,6 +174,293 @@ static unsigned int ziirave_wdt_get_timeleft(struct watchdog_device *wdd) | |||
146 | return ret; | 174 | return ret; |
147 | } | 175 | } |
148 | 176 | ||
177 | static int ziirave_firm_wait_for_ack(struct watchdog_device *wdd) | ||
178 | { | ||
179 | struct i2c_client *client = to_i2c_client(wdd->parent); | ||
180 | int ret; | ||
181 | unsigned long timeout; | ||
182 | |||
183 | timeout = jiffies + msecs_to_jiffies(ZIIRAVE_FIRM_WAIT_FOR_ACK_TIMEOUT); | ||
184 | do { | ||
185 | if (time_after(jiffies, timeout)) | ||
186 | return -ETIMEDOUT; | ||
187 | |||
188 | usleep_range(5000, 10000); | ||
189 | |||
190 | ret = i2c_smbus_read_byte(client); | ||
191 | if (ret < 0) { | ||
192 | dev_err(&client->dev, "Failed to read byte\n"); | ||
193 | return ret; | ||
194 | } | ||
195 | } while (ret == ZIIRAVE_FIRM_DOWNLOAD_BUSY); | ||
196 | |||
197 | return ret == ZIIRAVE_FIRM_DOWNLOAD_ACK ? 0 : -EIO; | ||
198 | } | ||
199 | |||
200 | static int ziirave_firm_set_read_addr(struct watchdog_device *wdd, u16 addr) | ||
201 | { | ||
202 | struct i2c_client *client = to_i2c_client(wdd->parent); | ||
203 | u8 address[2]; | ||
204 | |||
205 | address[0] = addr & 0xff; | ||
206 | address[1] = (addr >> 8) & 0xff; | ||
207 | |||
208 | return i2c_smbus_write_block_data(client, | ||
209 | ZIIRAVE_CMD_DOWNLOAD_SET_READ_ADDR, | ||
210 | ARRAY_SIZE(address), address); | ||
211 | } | ||
212 | |||
213 | static int ziirave_firm_write_block_data(struct watchdog_device *wdd, | ||
214 | u8 command, u8 length, const u8 *data, | ||
215 | bool wait_for_ack) | ||
216 | { | ||
217 | struct i2c_client *client = to_i2c_client(wdd->parent); | ||
218 | int ret; | ||
219 | |||
220 | ret = i2c_smbus_write_block_data(client, command, length, data); | ||
221 | if (ret) { | ||
222 | dev_err(&client->dev, | ||
223 | "Failed to send command 0x%02x: %d\n", command, ret); | ||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | if (wait_for_ack) | ||
228 | ret = ziirave_firm_wait_for_ack(wdd); | ||
229 | |||
230 | return ret; | ||
231 | } | ||
232 | |||
233 | static int ziirave_firm_write_byte(struct watchdog_device *wdd, u8 command, | ||
234 | u8 byte, bool wait_for_ack) | ||
235 | { | ||
236 | return ziirave_firm_write_block_data(wdd, command, 1, &byte, | ||
237 | wait_for_ack); | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * ziirave_firm_write_pkt() - Build and write a firmware packet | ||
242 | * | ||
243 | * A packet to send to the firmware is composed by following bytes: | ||
244 | * Length | Addr0 | Addr1 | Data0 .. Data15 | Checksum | | ||
245 | * Where, | ||
246 | * Length: A data byte containing the length of the data. | ||
247 | * Addr0: Low byte of the address. | ||
248 | * Addr1: High byte of the address. | ||
249 | * Data0 .. Data15: Array of 16 bytes of data. | ||
250 | * Checksum: Checksum byte to verify data integrity. | ||
251 | */ | ||
252 | static int ziirave_firm_write_pkt(struct watchdog_device *wdd, | ||
253 | const struct ihex_binrec *rec) | ||
254 | { | ||
255 | struct i2c_client *client = to_i2c_client(wdd->parent); | ||
256 | u8 i, checksum = 0, packet[ZIIRAVE_FIRM_PKT_TOTAL_SIZE]; | ||
257 | int ret; | ||
258 | u16 addr; | ||
259 | |||
260 | memset(packet, 0, ARRAY_SIZE(packet)); | ||
261 | |||
262 | /* Packet length */ | ||
263 | packet[0] = (u8)be16_to_cpu(rec->len); | ||
264 | /* Packet address */ | ||
265 | addr = (be32_to_cpu(rec->addr) & 0xffff) >> 1; | ||
266 | packet[1] = addr & 0xff; | ||
267 | packet[2] = (addr & 0xff00) >> 8; | ||
268 | |||
269 | /* Packet data */ | ||
270 | if (be16_to_cpu(rec->len) > ZIIRAVE_FIRM_PKT_DATA_SIZE) | ||
271 | return -EMSGSIZE; | ||
272 | memcpy(packet + 3, rec->data, be16_to_cpu(rec->len)); | ||
273 | |||
274 | /* Packet checksum */ | ||
275 | for (i = 0; i < ZIIRAVE_FIRM_PKT_TOTAL_SIZE - 1; i++) | ||
276 | checksum += packet[i]; | ||
277 | packet[ZIIRAVE_FIRM_PKT_TOTAL_SIZE - 1] = checksum; | ||
278 | |||
279 | ret = ziirave_firm_write_block_data(wdd, ZIIRAVE_CMD_DOWNLOAD_PACKET, | ||
280 | ARRAY_SIZE(packet), packet, true); | ||
281 | if (ret) | ||
282 | dev_err(&client->dev, | ||
283 | "Failed to write firmware packet at address 0x%04x: %d\n", | ||
284 | addr, ret); | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | static int ziirave_firm_verify(struct watchdog_device *wdd, | ||
290 | const struct firmware *fw) | ||
291 | { | ||
292 | struct i2c_client *client = to_i2c_client(wdd->parent); | ||
293 | const struct ihex_binrec *rec; | ||
294 | int i, ret; | ||
295 | u8 data[ZIIRAVE_FIRM_PKT_DATA_SIZE]; | ||
296 | u16 addr; | ||
297 | |||
298 | for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { | ||
299 | /* Zero length marks end of records */ | ||
300 | if (!be16_to_cpu(rec->len)) | ||
301 | break; | ||
302 | |||
303 | addr = (be32_to_cpu(rec->addr) & 0xffff) >> 1; | ||
304 | if (addr < ZIIRAVE_FIRM_FLASH_MEMORY_START || | ||
305 | addr > ZIIRAVE_FIRM_FLASH_MEMORY_END) | ||
306 | continue; | ||
307 | |||
308 | ret = ziirave_firm_set_read_addr(wdd, addr); | ||
309 | if (ret) { | ||
310 | dev_err(&client->dev, | ||
311 | "Failed to send SET_READ_ADDR command: %d\n", | ||
312 | ret); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | for (i = 0; i < ARRAY_SIZE(data); i++) { | ||
317 | ret = i2c_smbus_read_byte_data(client, | ||
318 | ZIIRAVE_CMD_DOWNLOAD_READ_BYTE); | ||
319 | if (ret < 0) { | ||
320 | dev_err(&client->dev, | ||
321 | "Failed to READ DATA: %d\n", ret); | ||
322 | return ret; | ||
323 | } | ||
324 | data[i] = ret; | ||
325 | } | ||
326 | |||
327 | if (memcmp(data, rec->data, be16_to_cpu(rec->len))) { | ||
328 | dev_err(&client->dev, | ||
329 | "Firmware mismatch at address 0x%04x\n", addr); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int ziirave_firm_upload(struct watchdog_device *wdd, | ||
338 | const struct firmware *fw) | ||
339 | { | ||
340 | struct i2c_client *client = to_i2c_client(wdd->parent); | ||
341 | int ret, words_till_page_break; | ||
342 | const struct ihex_binrec *rec; | ||
343 | struct ihex_binrec *rec_new; | ||
344 | |||
345 | ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_JUMP_TO_BOOTLOADER, 1, | ||
346 | false); | ||
347 | if (ret) | ||
348 | return ret; | ||
349 | |||
350 | msleep(500); | ||
351 | |||
352 | ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_DOWNLOAD_START, 1, true); | ||
353 | if (ret) | ||
354 | return ret; | ||
355 | |||
356 | msleep(500); | ||
357 | |||
358 | for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { | ||
359 | /* Zero length marks end of records */ | ||
360 | if (!be16_to_cpu(rec->len)) | ||
361 | break; | ||
362 | |||
363 | /* Check max data size */ | ||
364 | if (be16_to_cpu(rec->len) > ZIIRAVE_FIRM_PKT_DATA_SIZE) { | ||
365 | dev_err(&client->dev, "Firmware packet too long (%d)\n", | ||
366 | be16_to_cpu(rec->len)); | ||
367 | return -EMSGSIZE; | ||
368 | } | ||
369 | |||
370 | /* Calculate words till page break */ | ||
371 | words_till_page_break = (64 - ((be32_to_cpu(rec->addr) >> 1) & | ||
372 | 0x3f)); | ||
373 | if ((be16_to_cpu(rec->len) >> 1) > words_till_page_break) { | ||
374 | /* | ||
375 | * Data in passes page boundary, so we need to split in | ||
376 | * two blocks of data. Create a packet with the first | ||
377 | * block of data. | ||
378 | */ | ||
379 | rec_new = kzalloc(sizeof(struct ihex_binrec) + | ||
380 | (words_till_page_break << 1), | ||
381 | GFP_KERNEL); | ||
382 | if (!rec_new) | ||
383 | return -ENOMEM; | ||
384 | |||
385 | rec_new->len = cpu_to_be16(words_till_page_break << 1); | ||
386 | rec_new->addr = rec->addr; | ||
387 | memcpy(rec_new->data, rec->data, | ||
388 | be16_to_cpu(rec_new->len)); | ||
389 | |||
390 | ret = ziirave_firm_write_pkt(wdd, rec_new); | ||
391 | kfree(rec_new); | ||
392 | if (ret) | ||
393 | return ret; | ||
394 | |||
395 | /* Create a packet with the second block of data */ | ||
396 | rec_new = kzalloc(sizeof(struct ihex_binrec) + | ||
397 | be16_to_cpu(rec->len) - | ||
398 | (words_till_page_break << 1), | ||
399 | GFP_KERNEL); | ||
400 | if (!rec_new) | ||
401 | return -ENOMEM; | ||
402 | |||
403 | /* Remaining bytes */ | ||
404 | rec_new->len = rec->len - | ||
405 | cpu_to_be16(words_till_page_break << 1); | ||
406 | |||
407 | rec_new->addr = cpu_to_be32(be32_to_cpu(rec->addr) + | ||
408 | (words_till_page_break << 1)); | ||
409 | |||
410 | memcpy(rec_new->data, | ||
411 | rec->data + (words_till_page_break << 1), | ||
412 | be16_to_cpu(rec_new->len)); | ||
413 | |||
414 | ret = ziirave_firm_write_pkt(wdd, rec_new); | ||
415 | kfree(rec_new); | ||
416 | if (ret) | ||
417 | return ret; | ||
418 | } else { | ||
419 | ret = ziirave_firm_write_pkt(wdd, rec); | ||
420 | if (ret) | ||
421 | return ret; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | /* For end of download, the length field will be set to 0 */ | ||
426 | rec_new = kzalloc(sizeof(struct ihex_binrec) + 1, GFP_KERNEL); | ||
427 | if (!rec_new) | ||
428 | return -ENOMEM; | ||
429 | |||
430 | ret = ziirave_firm_write_pkt(wdd, rec_new); | ||
431 | kfree(rec_new); | ||
432 | if (ret) { | ||
433 | dev_err(&client->dev, "Failed to send EMPTY packet: %d\n", ret); | ||
434 | return ret; | ||
435 | } | ||
436 | |||
437 | /* This sleep seems to be required */ | ||
438 | msleep(20); | ||
439 | |||
440 | /* Start firmware verification */ | ||
441 | ret = ziirave_firm_verify(wdd, fw); | ||
442 | if (ret) { | ||
443 | dev_err(&client->dev, | ||
444 | "Failed to verify firmware: %d\n", ret); | ||
445 | return ret; | ||
446 | } | ||
447 | |||
448 | /* End download operation */ | ||
449 | ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_DOWNLOAD_END, 1, false); | ||
450 | if (ret) | ||
451 | return ret; | ||
452 | |||
453 | /* Reset the processor */ | ||
454 | ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_RESET_PROCESSOR, 1, | ||
455 | false); | ||
456 | if (ret) | ||
457 | return ret; | ||
458 | |||
459 | msleep(500); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
149 | static const struct watchdog_info ziirave_wdt_info = { | 464 | static const struct watchdog_info ziirave_wdt_info = { |
150 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, | 465 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, |
151 | .identity = "Zodiac RAVE Watchdog", | 466 | .identity = "Zodiac RAVE Watchdog", |
@@ -166,9 +481,18 @@ static ssize_t ziirave_wdt_sysfs_show_firm(struct device *dev, | |||
166 | { | 481 | { |
167 | struct i2c_client *client = to_i2c_client(dev->parent); | 482 | struct i2c_client *client = to_i2c_client(dev->parent); |
168 | struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); | 483 | struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); |
484 | int ret; | ||
485 | |||
486 | ret = mutex_lock_interruptible(&w_priv->sysfs_mutex); | ||
487 | if (ret) | ||
488 | return ret; | ||
489 | |||
490 | ret = sprintf(buf, "02.%02u.%02u", w_priv->firmware_rev.major, | ||
491 | w_priv->firmware_rev.minor); | ||
169 | 492 | ||
170 | return sprintf(buf, "02.%02u.%02u", w_priv->firmware_rev.major, | 493 | mutex_unlock(&w_priv->sysfs_mutex); |
171 | w_priv->firmware_rev.minor); | 494 | |
495 | return ret; | ||
172 | } | 496 | } |
173 | 497 | ||
174 | static DEVICE_ATTR(firmware_version, S_IRUGO, ziirave_wdt_sysfs_show_firm, | 498 | static DEVICE_ATTR(firmware_version, S_IRUGO, ziirave_wdt_sysfs_show_firm, |
@@ -180,9 +504,18 @@ static ssize_t ziirave_wdt_sysfs_show_boot(struct device *dev, | |||
180 | { | 504 | { |
181 | struct i2c_client *client = to_i2c_client(dev->parent); | 505 | struct i2c_client *client = to_i2c_client(dev->parent); |
182 | struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); | 506 | struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); |
507 | int ret; | ||
183 | 508 | ||
184 | return sprintf(buf, "01.%02u.%02u", w_priv->bootloader_rev.major, | 509 | ret = mutex_lock_interruptible(&w_priv->sysfs_mutex); |
185 | w_priv->bootloader_rev.minor); | 510 | if (ret) |
511 | return ret; | ||
512 | |||
513 | ret = sprintf(buf, "01.%02u.%02u", w_priv->bootloader_rev.major, | ||
514 | w_priv->bootloader_rev.minor); | ||
515 | |||
516 | mutex_unlock(&w_priv->sysfs_mutex); | ||
517 | |||
518 | return ret; | ||
186 | } | 519 | } |
187 | 520 | ||
188 | static DEVICE_ATTR(bootloader_version, S_IRUGO, ziirave_wdt_sysfs_show_boot, | 521 | static DEVICE_ATTR(bootloader_version, S_IRUGO, ziirave_wdt_sysfs_show_boot, |
@@ -194,17 +527,81 @@ static ssize_t ziirave_wdt_sysfs_show_reason(struct device *dev, | |||
194 | { | 527 | { |
195 | struct i2c_client *client = to_i2c_client(dev->parent); | 528 | struct i2c_client *client = to_i2c_client(dev->parent); |
196 | struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); | 529 | struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); |
530 | int ret; | ||
531 | |||
532 | ret = mutex_lock_interruptible(&w_priv->sysfs_mutex); | ||
533 | if (ret) | ||
534 | return ret; | ||
535 | |||
536 | ret = sprintf(buf, "%s", ziirave_reasons[w_priv->reset_reason]); | ||
197 | 537 | ||
198 | return sprintf(buf, "%s", ziirave_reasons[w_priv->reset_reason]); | 538 | mutex_unlock(&w_priv->sysfs_mutex); |
539 | |||
540 | return ret; | ||
199 | } | 541 | } |
200 | 542 | ||
201 | static DEVICE_ATTR(reset_reason, S_IRUGO, ziirave_wdt_sysfs_show_reason, | 543 | static DEVICE_ATTR(reset_reason, S_IRUGO, ziirave_wdt_sysfs_show_reason, |
202 | NULL); | 544 | NULL); |
203 | 545 | ||
546 | static ssize_t ziirave_wdt_sysfs_store_firm(struct device *dev, | ||
547 | struct device_attribute *attr, | ||
548 | const char *buf, size_t count) | ||
549 | { | ||
550 | struct i2c_client *client = to_i2c_client(dev->parent); | ||
551 | struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client); | ||
552 | const struct firmware *fw; | ||
553 | int err; | ||
554 | |||
555 | err = request_ihex_firmware(&fw, ZIIRAVE_FW_NAME, dev); | ||
556 | if (err) { | ||
557 | dev_err(&client->dev, "Failed to request ihex firmware\n"); | ||
558 | return err; | ||
559 | } | ||
560 | |||
561 | err = mutex_lock_interruptible(&w_priv->sysfs_mutex); | ||
562 | if (err) | ||
563 | goto release_firmware; | ||
564 | |||
565 | err = ziirave_firm_upload(&w_priv->wdd, fw); | ||
566 | if (err) { | ||
567 | dev_err(&client->dev, "The firmware update failed: %d\n", err); | ||
568 | goto unlock_mutex; | ||
569 | } | ||
570 | |||
571 | /* Update firmware version */ | ||
572 | err = ziirave_wdt_revision(client, &w_priv->firmware_rev, | ||
573 | ZIIRAVE_WDT_FIRM_VER_MAJOR); | ||
574 | if (err) { | ||
575 | dev_err(&client->dev, "Failed to read firmware version: %d\n", | ||
576 | err); | ||
577 | goto unlock_mutex; | ||
578 | } | ||
579 | |||
580 | dev_info(&client->dev, "Firmware updated to version 02.%02u.%02u\n", | ||
581 | w_priv->firmware_rev.major, w_priv->firmware_rev.minor); | ||
582 | |||
583 | /* Restore the watchdog timeout */ | ||
584 | err = ziirave_wdt_set_timeout(&w_priv->wdd, w_priv->wdd.timeout); | ||
585 | if (err) | ||
586 | dev_err(&client->dev, "Failed to set timeout: %d\n", err); | ||
587 | |||
588 | unlock_mutex: | ||
589 | mutex_unlock(&w_priv->sysfs_mutex); | ||
590 | |||
591 | release_firmware: | ||
592 | release_firmware(fw); | ||
593 | |||
594 | return err ? err : count; | ||
595 | } | ||
596 | |||
597 | static DEVICE_ATTR(update_firmware, S_IWUSR, NULL, | ||
598 | ziirave_wdt_sysfs_store_firm); | ||
599 | |||
204 | static struct attribute *ziirave_wdt_attrs[] = { | 600 | static struct attribute *ziirave_wdt_attrs[] = { |
205 | &dev_attr_firmware_version.attr, | 601 | &dev_attr_firmware_version.attr, |
206 | &dev_attr_bootloader_version.attr, | 602 | &dev_attr_bootloader_version.attr, |
207 | &dev_attr_reset_reason.attr, | 603 | &dev_attr_reset_reason.attr, |
604 | &dev_attr_update_firmware.attr, | ||
208 | NULL | 605 | NULL |
209 | }; | 606 | }; |
210 | ATTRIBUTE_GROUPS(ziirave_wdt); | 607 | ATTRIBUTE_GROUPS(ziirave_wdt); |
@@ -252,6 +649,8 @@ static int ziirave_wdt_probe(struct i2c_client *client, | |||
252 | if (!w_priv) | 649 | if (!w_priv) |
253 | return -ENOMEM; | 650 | return -ENOMEM; |
254 | 651 | ||
652 | mutex_init(&w_priv->sysfs_mutex); | ||
653 | |||
255 | w_priv->wdd.info = &ziirave_wdt_info; | 654 | w_priv->wdd.info = &ziirave_wdt_info; |
256 | w_priv->wdd.ops = &ziirave_wdt_ops; | 655 | w_priv->wdd.ops = &ziirave_wdt_ops; |
257 | w_priv->wdd.min_timeout = ZIIRAVE_TIMEOUT_MIN; | 656 | w_priv->wdd.min_timeout = ZIIRAVE_TIMEOUT_MIN; |
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index c1e9f29c924c..f2d7402abe02 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -1209,6 +1209,8 @@ COMPATIBLE_IOCTL(WDIOC_SETOPTIONS) | |||
1209 | COMPATIBLE_IOCTL(WDIOC_KEEPALIVE) | 1209 | COMPATIBLE_IOCTL(WDIOC_KEEPALIVE) |
1210 | COMPATIBLE_IOCTL(WDIOC_SETTIMEOUT) | 1210 | COMPATIBLE_IOCTL(WDIOC_SETTIMEOUT) |
1211 | COMPATIBLE_IOCTL(WDIOC_GETTIMEOUT) | 1211 | COMPATIBLE_IOCTL(WDIOC_GETTIMEOUT) |
1212 | COMPATIBLE_IOCTL(WDIOC_SETPRETIMEOUT) | ||
1213 | COMPATIBLE_IOCTL(WDIOC_GETPRETIMEOUT) | ||
1212 | /* Big R */ | 1214 | /* Big R */ |
1213 | COMPATIBLE_IOCTL(RNDGETENTCNT) | 1215 | COMPATIBLE_IOCTL(RNDGETENTCNT) |
1214 | COMPATIBLE_IOCTL(RNDADDTOENTCNT) | 1216 | COMPATIBLE_IOCTL(RNDADDTOENTCNT) |
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index 7047bc7f8106..35a4d8185b51 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h | |||
@@ -19,6 +19,7 @@ | |||
19 | struct watchdog_ops; | 19 | struct watchdog_ops; |
20 | struct watchdog_device; | 20 | struct watchdog_device; |
21 | struct watchdog_core_data; | 21 | struct watchdog_core_data; |
22 | struct watchdog_governor; | ||
22 | 23 | ||
23 | /** struct watchdog_ops - The watchdog-devices operations | 24 | /** struct watchdog_ops - The watchdog-devices operations |
24 | * | 25 | * |
@@ -28,6 +29,7 @@ struct watchdog_core_data; | |||
28 | * @ping: The routine that sends a keepalive ping to the watchdog device. | 29 | * @ping: The routine that sends a keepalive ping to the watchdog device. |
29 | * @status: The routine that shows the status of the watchdog device. | 30 | * @status: The routine that shows the status of the watchdog device. |
30 | * @set_timeout:The routine for setting the watchdog devices timeout value (in seconds). | 31 | * @set_timeout:The routine for setting the watchdog devices timeout value (in seconds). |
32 | * @set_pretimeout:The routine for setting the watchdog devices pretimeout. | ||
31 | * @get_timeleft:The routine that gets the time left before a reset (in seconds). | 33 | * @get_timeleft:The routine that gets the time left before a reset (in seconds). |
32 | * @restart: The routine for restarting the machine. | 34 | * @restart: The routine for restarting the machine. |
33 | * @ioctl: The routines that handles extra ioctl calls. | 35 | * @ioctl: The routines that handles extra ioctl calls. |
@@ -46,6 +48,7 @@ struct watchdog_ops { | |||
46 | int (*ping)(struct watchdog_device *); | 48 | int (*ping)(struct watchdog_device *); |
47 | unsigned int (*status)(struct watchdog_device *); | 49 | unsigned int (*status)(struct watchdog_device *); |
48 | int (*set_timeout)(struct watchdog_device *, unsigned int); | 50 | int (*set_timeout)(struct watchdog_device *, unsigned int); |
51 | int (*set_pretimeout)(struct watchdog_device *, unsigned int); | ||
49 | unsigned int (*get_timeleft)(struct watchdog_device *); | 52 | unsigned int (*get_timeleft)(struct watchdog_device *); |
50 | int (*restart)(struct watchdog_device *, unsigned long, void *); | 53 | int (*restart)(struct watchdog_device *, unsigned long, void *); |
51 | long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); | 54 | long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); |
@@ -59,8 +62,10 @@ struct watchdog_ops { | |||
59 | * watchdog device. | 62 | * watchdog device. |
60 | * @info: Pointer to a watchdog_info structure. | 63 | * @info: Pointer to a watchdog_info structure. |
61 | * @ops: Pointer to the list of watchdog operations. | 64 | * @ops: Pointer to the list of watchdog operations. |
65 | * @gov: Pointer to watchdog pretimeout governor. | ||
62 | * @bootstatus: Status of the watchdog device at boot. | 66 | * @bootstatus: Status of the watchdog device at boot. |
63 | * @timeout: The watchdog devices timeout value (in seconds). | 67 | * @timeout: The watchdog devices timeout value (in seconds). |
68 | * @pretimeout: The watchdog devices pre_timeout value. | ||
64 | * @min_timeout:The watchdog devices minimum timeout value (in seconds). | 69 | * @min_timeout:The watchdog devices minimum timeout value (in seconds). |
65 | * @max_timeout:The watchdog devices maximum timeout value (in seconds) | 70 | * @max_timeout:The watchdog devices maximum timeout value (in seconds) |
66 | * as configurable from user space. Only relevant if | 71 | * as configurable from user space. Only relevant if |
@@ -94,8 +99,10 @@ struct watchdog_device { | |||
94 | const struct attribute_group **groups; | 99 | const struct attribute_group **groups; |
95 | const struct watchdog_info *info; | 100 | const struct watchdog_info *info; |
96 | const struct watchdog_ops *ops; | 101 | const struct watchdog_ops *ops; |
102 | const struct watchdog_governor *gov; | ||
97 | unsigned int bootstatus; | 103 | unsigned int bootstatus; |
98 | unsigned int timeout; | 104 | unsigned int timeout; |
105 | unsigned int pretimeout; | ||
99 | unsigned int min_timeout; | 106 | unsigned int min_timeout; |
100 | unsigned int max_timeout; | 107 | unsigned int max_timeout; |
101 | unsigned int min_hw_heartbeat_ms; | 108 | unsigned int min_hw_heartbeat_ms; |
@@ -163,6 +170,13 @@ static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigne | |||
163 | t > wdd->max_timeout); | 170 | t > wdd->max_timeout); |
164 | } | 171 | } |
165 | 172 | ||
173 | /* Use the following function to check if a pretimeout value is invalid */ | ||
174 | static inline bool watchdog_pretimeout_invalid(struct watchdog_device *wdd, | ||
175 | unsigned int t) | ||
176 | { | ||
177 | return t && wdd->timeout && t >= wdd->timeout; | ||
178 | } | ||
179 | |||
166 | /* Use the following functions to manipulate watchdog driver specific data */ | 180 | /* Use the following functions to manipulate watchdog driver specific data */ |
167 | static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) | 181 | static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) |
168 | { | 182 | { |
@@ -174,6 +188,16 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd) | |||
174 | return wdd->driver_data; | 188 | return wdd->driver_data; |
175 | } | 189 | } |
176 | 190 | ||
191 | /* Use the following functions to report watchdog pretimeout event */ | ||
192 | #if IS_ENABLED(CONFIG_WATCHDOG_PRETIMEOUT_GOV) | ||
193 | void watchdog_notify_pretimeout(struct watchdog_device *wdd); | ||
194 | #else | ||
195 | static inline void watchdog_notify_pretimeout(struct watchdog_device *wdd) | ||
196 | { | ||
197 | pr_alert("watchdog%d: pretimeout event\n", wdd->id); | ||
198 | } | ||
199 | #endif | ||
200 | |||
177 | /* drivers/watchdog/watchdog_core.c */ | 201 | /* drivers/watchdog/watchdog_core.c */ |
178 | void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority); | 202 | void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority); |
179 | extern int watchdog_init_timeout(struct watchdog_device *wdd, | 203 | extern int watchdog_init_timeout(struct watchdog_device *wdd, |