hc
2024-05-10 23fa18eaa71266feff7ba8d83022d9e1cc83c65a
kernel/drivers/watchdog/hpwdt.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * HPE WatchDog Driver
34 * based on
....@@ -6,11 +7,6 @@
67 *
78 * (c) Copyright 2018 Hewlett Packard Enterprise Development LP
89 * Thomas Mingarelli <thomas.mingarelli@hpe.com>
9
- *
10
- * This program is free software; you can redistribute it and/or
11
- * modify it under the terms of the GNU General Public License
12
- * version 2 as published by the Free Software Foundation
13
- *
1410 */
1511
1612 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
....@@ -26,10 +22,11 @@
2622 #include <linux/watchdog.h>
2723 #include <asm/nmi.h>
2824
29
-#define HPWDT_VERSION "2.0.0"
25
+#define HPWDT_VERSION "2.0.3"
3026 #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
3127 #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
32
-#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
28
+#define HPWDT_MAX_TICKS 65535
29
+#define HPWDT_MAX_TIMER TICKS_TO_SECS(HPWDT_MAX_TICKS)
3330 #define DEFAULT_MARGIN 30
3431 #define PRETIMEOUT_SEC 9
3532
....@@ -37,6 +34,7 @@
3734 static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */
3835 static bool nowayout = WATCHDOG_NOWAYOUT;
3936 static bool pretimeout = IS_ENABLED(CONFIG_HPWDT_NMI_DECODING);
37
+static int kdumptimeout = -1;
4038
4139 static void __iomem *pci_mem_addr; /* the PCI-memory address */
4240 static unsigned long __iomem *hpwdt_nmistat;
....@@ -50,16 +48,27 @@
5048 };
5149 MODULE_DEVICE_TABLE(pci, hpwdt_devices);
5250
51
+static const struct pci_device_id hpwdt_blacklist[] = {
52
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP, 0x1979) }, /* auxilary iLO */
53
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP_3PAR, 0x0289) }, /* CL */
54
+ {0}, /* terminate list */
55
+};
5356
57
+static struct watchdog_device hpwdt_dev;
5458 /*
5559 * Watchdog operations
5660 */
61
+static int hpwdt_hw_is_running(void)
62
+{
63
+ return ioread8(hpwdt_timer_con) & 0x01;
64
+}
65
+
5766 static int hpwdt_start(struct watchdog_device *wdd)
5867 {
5968 int control = 0x81 | (pretimeout ? 0x4 : 0);
60
- int reload = SECS_TO_TICKS(wdd->timeout);
69
+ int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
6170
62
- dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%02x\n", reload, control);
71
+ dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%08x:0x%02x\n", wdd->timeout, reload, control);
6372 iowrite16(reload, hpwdt_timer_reg);
6473 iowrite8(control, hpwdt_timer_con);
6574
....@@ -84,12 +93,18 @@
8493 return 0;
8594 }
8695
96
+static void hpwdt_ping_ticks(int val)
97
+{
98
+ val = min(val, HPWDT_MAX_TICKS);
99
+ iowrite16(val, hpwdt_timer_reg);
100
+}
101
+
87102 static int hpwdt_ping(struct watchdog_device *wdd)
88103 {
89
- int reload = SECS_TO_TICKS(wdd->timeout);
104
+ int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
90105
91
- dev_dbg(wdd->parent, "ping watchdog 0x%08x\n", reload);
92
- iowrite16(reload, hpwdt_timer_reg);
106
+ dev_dbg(wdd->parent, "ping watchdog 0x%08x:0x%08x\n", wdd->timeout, reload);
107
+ hpwdt_ping_ticks(reload);
93108
94109 return 0;
95110 }
....@@ -162,10 +177,17 @@
162177 if (ilo5 && ulReason == NMI_UNKNOWN && !mynmi)
163178 return NMI_DONE;
164179
165
- if (ilo5 && !pretimeout)
180
+ if (ilo5 && !pretimeout && !mynmi)
166181 return NMI_DONE;
167182
168
- hpwdt_stop();
183
+ if (kdumptimeout < 0)
184
+ hpwdt_stop();
185
+ else if (kdumptimeout == 0)
186
+ ;
187
+ else {
188
+ unsigned int val = max((unsigned int)kdumptimeout, hpwdt_dev.timeout);
189
+ hpwdt_ping_ticks(SECS_TO_TICKS(val));
190
+ }
169191
170192 hex_byte_pack(panic_msg, mynmi);
171193 nmi_panic(regs, panic_msg);
....@@ -203,11 +225,9 @@
203225 .info = &ident,
204226 .ops = &hpwdt_ops,
205227 .min_timeout = 1,
206
- .max_timeout = HPWDT_MAX_TIMER,
207228 .timeout = DEFAULT_MARGIN,
208
-#ifdef CONFIG_HPWDT_NMI_DECODING
209229 .pretimeout = PRETIMEOUT_SEC,
210
-#endif
230
+ .max_hw_heartbeat_ms = HPWDT_MAX_TIMER * 1000,
211231 };
212232
213233
....@@ -276,12 +296,10 @@
276296 return -ENODEV;
277297 }
278298
279
- /*
280
- * Ignore all auxilary iLO devices with the following PCI ID
281
- */
282
- if (dev->subsystem_vendor == PCI_VENDOR_ID_HP &&
283
- dev->subsystem_device == 0x1979)
299
+ if (pci_match_id(hpwdt_blacklist, dev)) {
300
+ dev_dbg(&dev->dev, "Not supported on this device\n");
284301 return -ENODEV;
302
+ }
285303
286304 if (pci_enable_device(dev)) {
287305 dev_warn(&dev->dev,
....@@ -301,28 +319,40 @@
301319 hpwdt_timer_reg = pci_mem_addr + 0x70;
302320 hpwdt_timer_con = pci_mem_addr + 0x72;
303321
304
- /* Make sure that timer is disabled until /dev/watchdog is opened */
305
- hpwdt_stop();
322
+ /* Have the core update running timer until user space is ready */
323
+ if (hpwdt_hw_is_running()) {
324
+ dev_info(&dev->dev, "timer is running\n");
325
+ set_bit(WDOG_HW_RUNNING, &hpwdt_dev.status);
326
+ }
306327
307328 /* Initialize NMI Decoding functionality */
308329 retval = hpwdt_init_nmi_decoding(dev);
309330 if (retval != 0)
310331 goto error_init_nmi_decoding;
311332
333
+ watchdog_stop_on_unregister(&hpwdt_dev);
312334 watchdog_set_nowayout(&hpwdt_dev, nowayout);
313
- if (watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL))
314
- dev_warn(&dev->dev, "Invalid soft_margin: %d.\n", soft_margin);
335
+ watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
336
+
337
+ if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
338
+ dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
339
+ pretimeout = 0;
340
+ }
341
+ hpwdt_dev.pretimeout = pretimeout ? PRETIMEOUT_SEC : 0;
342
+ kdumptimeout = min(kdumptimeout, HPWDT_MAX_TIMER);
315343
316344 hpwdt_dev.parent = &dev->dev;
317345 retval = watchdog_register_device(&hpwdt_dev);
318
- if (retval < 0) {
319
- dev_err(&dev->dev, "watchdog register failed: %d.\n", retval);
346
+ if (retval < 0)
320347 goto error_wd_register;
321
- }
322348
323
- dev_info(&dev->dev, "HPE Watchdog Timer Driver: %s"
324
- ", timer margin: %d seconds (nowayout=%d).\n",
325
- HPWDT_VERSION, hpwdt_dev.timeout, nowayout);
349
+ dev_info(&dev->dev, "HPE Watchdog Timer Driver: Version: %s\n",
350
+ HPWDT_VERSION);
351
+ dev_info(&dev->dev, "timeout: %d seconds (nowayout=%d)\n",
352
+ hpwdt_dev.timeout, nowayout);
353
+ dev_info(&dev->dev, "pretimeout: %s.\n",
354
+ pretimeout ? "on" : "off");
355
+ dev_info(&dev->dev, "kdumptimeout: %d.\n", kdumptimeout);
326356
327357 if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
328358 ilo5 = true;
....@@ -340,9 +370,6 @@
340370
341371 static void hpwdt_exit(struct pci_dev *dev)
342372 {
343
- if (!nowayout)
344
- hpwdt_stop();
345
-
346373 watchdog_unregister_device(&hpwdt_dev);
347374 hpwdt_exit_nmi_decoding();
348375 pci_iounmap(dev, pci_mem_addr);
....@@ -364,10 +391,16 @@
364391 module_param(soft_margin, int, 0);
365392 MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
366393
394
+module_param_named(timeout, soft_margin, int, 0);
395
+MODULE_PARM_DESC(timeout, "Alias of soft_margin");
396
+
367397 module_param(nowayout, bool, 0);
368398 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
369399 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
370400
401
+module_param(kdumptimeout, int, 0444);
402
+MODULE_PARM_DESC(kdumptimeout, "Timeout applied for crash kernel transition in seconds");
403
+
371404 #ifdef CONFIG_HPWDT_NMI_DECODING
372405 module_param(pretimeout, bool, 0);
373406 MODULE_PARM_DESC(pretimeout, "Watchdog pretimeout enabled");