1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2022 International Business Machines, Inc.
6 #include <linux/bitops.h>
7 #include <linux/kernel.h>
8 #include <linux/limits.h>
9 #include <linux/math.h>
10 #include <linux/mod_devicetable.h>
11 #include <linux/module.h>
12 #include <linux/moduleparam.h>
13 #include <linux/platform_device.h>
14 #include <linux/time64.h>
15 #include <linux/watchdog.h>
17 #define DRV_NAME "pseries-wdt"
24 * Bits 48-55: "operation"
26 #define PSERIES_WDTF_OP_START 0x100UL /* start timer */
27 #define PSERIES_WDTF_OP_STOP 0x200UL /* stop timer */
28 #define PSERIES_WDTF_OP_QUERY 0x300UL /* query timer capabilities */
31 * Bits 56-63: "timeoutAction" (for "Start Watchdog" only)
33 #define PSERIES_WDTF_ACTION_HARD_POWEROFF 0x1UL /* poweroff */
34 #define PSERIES_WDTF_ACTION_HARD_RESTART 0x2UL /* restart */
35 #define PSERIES_WDTF_ACTION_DUMP_RESTART 0x3UL /* dump + restart */
42 * H_SUCCESS The operation completed.
44 * H_BUSY The hypervisor is too busy; retry the operation.
46 * H_PARAMETER The given "flags" are somehow invalid. Either the
47 * "operation" or "timeoutAction" is invalid, or a
48 * reserved bit is set.
50 * H_P2 The given "watchdogNumber" is zero or exceeds the
51 * supported maximum value.
53 * H_P3 The given "timeoutInMs" is below the supported
56 * H_NOOP The given "watchdogNumber" is already stopped.
58 * H_HARDWARE The operation failed for ineffable reasons.
60 * H_FUNCTION The H_WATCHDOG hypercall is not supported by this
65 * - For the "Query Watchdog Capabilities" operation, a 64-bit
68 #define PSERIES_WDTQ_MIN_TIMEOUT(cap) (((cap) >> 48) & 0xffff)
69 #define PSERIES_WDTQ_MAX_NUMBER(cap) (((cap) >> 32) & 0xffff)
71 static const unsigned long pseries_wdt_action
[] = {
72 [0] = PSERIES_WDTF_ACTION_HARD_POWEROFF
,
73 [1] = PSERIES_WDTF_ACTION_HARD_RESTART
,
74 [2] = PSERIES_WDTF_ACTION_DUMP_RESTART
,
77 #define WATCHDOG_ACTION 1
78 static unsigned int action
= WATCHDOG_ACTION
;
79 module_param(action
, uint
, 0444);
80 MODULE_PARM_DESC(action
, "Action taken when watchdog expires (default="
81 __MODULE_STRING(WATCHDOG_ACTION
) ")");
83 static bool nowayout
= WATCHDOG_NOWAYOUT
;
84 module_param(nowayout
, bool, 0444);
85 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started (default="
86 __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
88 #define WATCHDOG_TIMEOUT 60
89 static unsigned int timeout
= WATCHDOG_TIMEOUT
;
90 module_param(timeout
, uint
, 0444);
91 MODULE_PARM_DESC(timeout
, "Initial watchdog timeout in seconds (default="
92 __MODULE_STRING(WATCHDOG_TIMEOUT
) ")");
95 struct watchdog_device wd
;
97 unsigned long num
; /* Watchdog numbers are 1-based */
100 static int pseries_wdt_start(struct watchdog_device
*wdd
)
102 struct pseries_wdt
*pw
= watchdog_get_drvdata(wdd
);
103 struct device
*dev
= wdd
->parent
;
104 unsigned long flags
, msecs
;
107 flags
= pw
->action
| PSERIES_WDTF_OP_START
;
108 msecs
= wdd
->timeout
* MSEC_PER_SEC
;
109 rc
= plpar_hcall_norets(H_WATCHDOG
, flags
, pw
->num
, msecs
);
110 if (rc
!= H_SUCCESS
) {
111 dev_crit(dev
, "H_WATCHDOG: %ld: failed to start timer %lu",
118 static int pseries_wdt_stop(struct watchdog_device
*wdd
)
120 struct pseries_wdt
*pw
= watchdog_get_drvdata(wdd
);
121 struct device
*dev
= wdd
->parent
;
124 rc
= plpar_hcall_norets(H_WATCHDOG
, PSERIES_WDTF_OP_STOP
, pw
->num
);
125 if (rc
!= H_SUCCESS
&& rc
!= H_NOOP
) {
126 dev_crit(dev
, "H_WATCHDOG: %ld: failed to stop timer %lu",
133 static struct watchdog_info pseries_wdt_info
= {
134 .identity
= DRV_NAME
,
135 .options
= WDIOF_KEEPALIVEPING
| WDIOF_MAGICCLOSE
| WDIOF_SETTIMEOUT
139 static const struct watchdog_ops pseries_wdt_ops
= {
140 .owner
= THIS_MODULE
,
141 .start
= pseries_wdt_start
,
142 .stop
= pseries_wdt_stop
,
145 static int pseries_wdt_probe(struct platform_device
*pdev
)
147 unsigned long ret
[PLPAR_HCALL_BUFSIZE
] = { 0 };
148 struct pseries_wdt
*pw
;
153 rc
= plpar_hcall(H_WATCHDOG
, ret
, PSERIES_WDTF_OP_QUERY
);
154 if (rc
== H_FUNCTION
)
160 pw
= devm_kzalloc(&pdev
->dev
, sizeof(*pw
), GFP_KERNEL
);
165 * Assume watchdogNumber 1 for now. If we ever support
166 * multiple timers we will need to devise a way to choose a
167 * distinct watchdogNumber for each platform device at device
171 if (PSERIES_WDTQ_MAX_NUMBER(cap
) < pw
->num
)
174 if (action
>= ARRAY_SIZE(pseries_wdt_action
))
176 pw
->action
= pseries_wdt_action
[action
];
178 pw
->wd
.parent
= &pdev
->dev
;
179 pw
->wd
.info
= &pseries_wdt_info
;
180 pw
->wd
.ops
= &pseries_wdt_ops
;
181 msecs
= PSERIES_WDTQ_MIN_TIMEOUT(cap
);
182 pw
->wd
.min_timeout
= DIV_ROUND_UP(msecs
, MSEC_PER_SEC
);
183 pw
->wd
.max_timeout
= UINT_MAX
/ 1000; /* from linux/watchdog.h */
184 pw
->wd
.timeout
= timeout
;
185 if (watchdog_init_timeout(&pw
->wd
, 0, NULL
))
187 watchdog_set_nowayout(&pw
->wd
, nowayout
);
188 watchdog_stop_on_reboot(&pw
->wd
);
189 watchdog_stop_on_unregister(&pw
->wd
);
190 watchdog_set_drvdata(&pw
->wd
, pw
);
192 err
= devm_watchdog_register_device(&pdev
->dev
, &pw
->wd
);
196 platform_set_drvdata(pdev
, &pw
->wd
);
201 static int pseries_wdt_suspend(struct platform_device
*pdev
, pm_message_t state
)
203 struct watchdog_device
*wd
= platform_get_drvdata(pdev
);
205 if (watchdog_active(wd
))
206 return pseries_wdt_stop(wd
);
210 static int pseries_wdt_resume(struct platform_device
*pdev
)
212 struct watchdog_device
*wd
= platform_get_drvdata(pdev
);
214 if (watchdog_active(wd
))
215 return pseries_wdt_start(wd
);
219 static const struct platform_device_id pseries_wdt_id
[] = {
220 { .name
= "pseries-wdt" },
223 MODULE_DEVICE_TABLE(platform
, pseries_wdt_id
);
225 static struct platform_driver pseries_wdt_driver
= {
229 .id_table
= pseries_wdt_id
,
230 .probe
= pseries_wdt_probe
,
231 .resume
= pseries_wdt_resume
,
232 .suspend
= pseries_wdt_suspend
,
234 module_platform_driver(pseries_wdt_driver
);
236 MODULE_AUTHOR("Alexey Kardashevskiy");
237 MODULE_AUTHOR("Scott Cheloha");
238 MODULE_DESCRIPTION("POWER Architecture Platform Watchdog Driver");
239 MODULE_LICENSE("GPL");