0001
0002
0003
0004
0005
0006 #include <linux/bitops.h>
0007 #include <linux/kernel.h>
0008 #include <linux/limits.h>
0009 #include <linux/math.h>
0010 #include <linux/mod_devicetable.h>
0011 #include <linux/module.h>
0012 #include <linux/moduleparam.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/time64.h>
0015 #include <linux/watchdog.h>
0016
0017 #define DRV_NAME "pseries-wdt"
0018
0019
0020
0021
0022
0023
0024
0025
0026 #define PSERIES_WDTF_OP_START 0x100UL
0027 #define PSERIES_WDTF_OP_STOP 0x200UL
0028 #define PSERIES_WDTF_OP_QUERY 0x300UL
0029
0030
0031
0032
0033 #define PSERIES_WDTF_ACTION_HARD_POWEROFF 0x1UL
0034 #define PSERIES_WDTF_ACTION_HARD_RESTART 0x2UL
0035 #define PSERIES_WDTF_ACTION_DUMP_RESTART 0x3UL
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068 #define PSERIES_WDTQ_MIN_TIMEOUT(cap) (((cap) >> 48) & 0xffff)
0069 #define PSERIES_WDTQ_MAX_NUMBER(cap) (((cap) >> 32) & 0xffff)
0070
0071 static const unsigned long pseries_wdt_action[] = {
0072 [0] = PSERIES_WDTF_ACTION_HARD_POWEROFF,
0073 [1] = PSERIES_WDTF_ACTION_HARD_RESTART,
0074 [2] = PSERIES_WDTF_ACTION_DUMP_RESTART,
0075 };
0076
0077 #define WATCHDOG_ACTION 1
0078 static unsigned int action = WATCHDOG_ACTION;
0079 module_param(action, uint, 0444);
0080 MODULE_PARM_DESC(action, "Action taken when watchdog expires (default="
0081 __MODULE_STRING(WATCHDOG_ACTION) ")");
0082
0083 static bool nowayout = WATCHDOG_NOWAYOUT;
0084 module_param(nowayout, bool, 0444);
0085 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
0086 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0087
0088 #define WATCHDOG_TIMEOUT 60
0089 static unsigned int timeout = WATCHDOG_TIMEOUT;
0090 module_param(timeout, uint, 0444);
0091 MODULE_PARM_DESC(timeout, "Initial watchdog timeout in seconds (default="
0092 __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
0093
0094 struct pseries_wdt {
0095 struct watchdog_device wd;
0096 unsigned long action;
0097 unsigned long num;
0098 };
0099
0100 static int pseries_wdt_start(struct watchdog_device *wdd)
0101 {
0102 struct pseries_wdt *pw = watchdog_get_drvdata(wdd);
0103 struct device *dev = wdd->parent;
0104 unsigned long flags, msecs;
0105 long rc;
0106
0107 flags = pw->action | PSERIES_WDTF_OP_START;
0108 msecs = wdd->timeout * MSEC_PER_SEC;
0109 rc = plpar_hcall_norets(H_WATCHDOG, flags, pw->num, msecs);
0110 if (rc != H_SUCCESS) {
0111 dev_crit(dev, "H_WATCHDOG: %ld: failed to start timer %lu",
0112 rc, pw->num);
0113 return -EIO;
0114 }
0115 return 0;
0116 }
0117
0118 static int pseries_wdt_stop(struct watchdog_device *wdd)
0119 {
0120 struct pseries_wdt *pw = watchdog_get_drvdata(wdd);
0121 struct device *dev = wdd->parent;
0122 long rc;
0123
0124 rc = plpar_hcall_norets(H_WATCHDOG, PSERIES_WDTF_OP_STOP, pw->num);
0125 if (rc != H_SUCCESS && rc != H_NOOP) {
0126 dev_crit(dev, "H_WATCHDOG: %ld: failed to stop timer %lu",
0127 rc, pw->num);
0128 return -EIO;
0129 }
0130 return 0;
0131 }
0132
0133 static struct watchdog_info pseries_wdt_info = {
0134 .identity = DRV_NAME,
0135 .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT
0136 | WDIOF_PRETIMEOUT,
0137 };
0138
0139 static const struct watchdog_ops pseries_wdt_ops = {
0140 .owner = THIS_MODULE,
0141 .start = pseries_wdt_start,
0142 .stop = pseries_wdt_stop,
0143 };
0144
0145 static int pseries_wdt_probe(struct platform_device *pdev)
0146 {
0147 unsigned long ret[PLPAR_HCALL_BUFSIZE] = { 0 };
0148 struct pseries_wdt *pw;
0149 unsigned long cap;
0150 long msecs, rc;
0151 int err;
0152
0153 rc = plpar_hcall(H_WATCHDOG, ret, PSERIES_WDTF_OP_QUERY);
0154 if (rc == H_FUNCTION)
0155 return -ENODEV;
0156 if (rc != H_SUCCESS)
0157 return -EIO;
0158 cap = ret[0];
0159
0160 pw = devm_kzalloc(&pdev->dev, sizeof(*pw), GFP_KERNEL);
0161 if (!pw)
0162 return -ENOMEM;
0163
0164
0165
0166
0167
0168
0169
0170 pw->num = 1;
0171 if (PSERIES_WDTQ_MAX_NUMBER(cap) < pw->num)
0172 return -ENODEV;
0173
0174 if (action >= ARRAY_SIZE(pseries_wdt_action))
0175 return -EINVAL;
0176 pw->action = pseries_wdt_action[action];
0177
0178 pw->wd.parent = &pdev->dev;
0179 pw->wd.info = &pseries_wdt_info;
0180 pw->wd.ops = &pseries_wdt_ops;
0181 msecs = PSERIES_WDTQ_MIN_TIMEOUT(cap);
0182 pw->wd.min_timeout = DIV_ROUND_UP(msecs, MSEC_PER_SEC);
0183 pw->wd.max_timeout = UINT_MAX / 1000;
0184 pw->wd.timeout = timeout;
0185 if (watchdog_init_timeout(&pw->wd, 0, NULL))
0186 return -EINVAL;
0187 watchdog_set_nowayout(&pw->wd, nowayout);
0188 watchdog_stop_on_reboot(&pw->wd);
0189 watchdog_stop_on_unregister(&pw->wd);
0190 watchdog_set_drvdata(&pw->wd, pw);
0191
0192 err = devm_watchdog_register_device(&pdev->dev, &pw->wd);
0193 if (err)
0194 return err;
0195
0196 platform_set_drvdata(pdev, &pw->wd);
0197
0198 return 0;
0199 }
0200
0201 static int pseries_wdt_suspend(struct platform_device *pdev, pm_message_t state)
0202 {
0203 struct watchdog_device *wd = platform_get_drvdata(pdev);
0204
0205 if (watchdog_active(wd))
0206 return pseries_wdt_stop(wd);
0207 return 0;
0208 }
0209
0210 static int pseries_wdt_resume(struct platform_device *pdev)
0211 {
0212 struct watchdog_device *wd = platform_get_drvdata(pdev);
0213
0214 if (watchdog_active(wd))
0215 return pseries_wdt_start(wd);
0216 return 0;
0217 }
0218
0219 static const struct platform_device_id pseries_wdt_id[] = {
0220 { .name = "pseries-wdt" },
0221 {}
0222 };
0223 MODULE_DEVICE_TABLE(platform, pseries_wdt_id);
0224
0225 static struct platform_driver pseries_wdt_driver = {
0226 .driver = {
0227 .name = DRV_NAME,
0228 },
0229 .id_table = pseries_wdt_id,
0230 .probe = pseries_wdt_probe,
0231 .resume = pseries_wdt_resume,
0232 .suspend = pseries_wdt_suspend,
0233 };
0234 module_platform_driver(pseries_wdt_driver);
0235
0236 MODULE_AUTHOR("Alexey Kardashevskiy");
0237 MODULE_AUTHOR("Scott Cheloha");
0238 MODULE_DESCRIPTION("POWER Architecture Platform Watchdog Driver");
0239 MODULE_LICENSE("GPL");