kempld_wdt.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Kontron PLD watchdog driver
  4. *
  5. * Copyright (c) 2010-2013 Kontron Europe GmbH
  6. * Author: Michael Brunner <michael.brunner@kontron.com>
  7. *
  8. * Note: From the PLD watchdog point of view timeout and pretimeout are
  9. * defined differently than in the kernel.
  10. * First the pretimeout stage runs out before the timeout stage gets
  11. * active.
  12. *
  13. * Kernel/API: P-----| pretimeout
  14. * |-----------------------T timeout
  15. * Watchdog: |-----------------P pretimeout_stage
  16. * |-----T timeout_stage
  17. */
  18. #include <linux/module.h>
  19. #include <linux/moduleparam.h>
  20. #include <linux/uaccess.h>
  21. #include <linux/watchdog.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/mfd/kempld.h>
  24. #define KEMPLD_WDT_STAGE_TIMEOUT(x) (0x1b + (x) * 4)
  25. #define KEMPLD_WDT_STAGE_CFG(x) (0x18 + (x))
  26. #define STAGE_CFG_GET_PRESCALER(x) (((x) & 0x30) >> 4)
  27. #define STAGE_CFG_SET_PRESCALER(x) (((x) & 0x3) << 4)
  28. #define STAGE_CFG_PRESCALER_MASK 0x30
  29. #define STAGE_CFG_ACTION_MASK 0x7
  30. #define STAGE_CFG_ASSERT (1 << 3)
  31. #define KEMPLD_WDT_MAX_STAGES 2
  32. #define KEMPLD_WDT_KICK 0x16
  33. #define KEMPLD_WDT_CFG 0x17
  34. #define KEMPLD_WDT_CFG_ENABLE 0x10
  35. #define KEMPLD_WDT_CFG_ENABLE_LOCK 0x8
  36. #define KEMPLD_WDT_CFG_GLOBAL_LOCK 0x80
  37. enum {
  38. ACTION_NONE = 0,
  39. ACTION_RESET,
  40. ACTION_NMI,
  41. ACTION_SMI,
  42. ACTION_SCI,
  43. ACTION_DELAY,
  44. };
  45. enum {
  46. STAGE_TIMEOUT = 0,
  47. STAGE_PRETIMEOUT,
  48. };
  49. enum {
  50. PRESCALER_21 = 0,
  51. PRESCALER_17,
  52. PRESCALER_12,
  53. };
  54. static const u32 kempld_prescaler[] = {
  55. [PRESCALER_21] = (1 << 21) - 1,
  56. [PRESCALER_17] = (1 << 17) - 1,
  57. [PRESCALER_12] = (1 << 12) - 1,
  58. 0,
  59. };
  60. struct kempld_wdt_stage {
  61. unsigned int id;
  62. u32 mask;
  63. };
  64. struct kempld_wdt_data {
  65. struct kempld_device_data *pld;
  66. struct watchdog_device wdd;
  67. unsigned int pretimeout;
  68. struct kempld_wdt_stage stage[KEMPLD_WDT_MAX_STAGES];
  69. u8 pm_status_store;
  70. };
  71. #define DEFAULT_TIMEOUT 30 /* seconds */
  72. #define DEFAULT_PRETIMEOUT 0
  73. static unsigned int timeout = DEFAULT_TIMEOUT;
  74. module_param(timeout, uint, 0);
  75. MODULE_PARM_DESC(timeout,
  76. "Watchdog timeout in seconds. (>=0, default="
  77. __MODULE_STRING(DEFAULT_TIMEOUT) ")");
  78. static unsigned int pretimeout = DEFAULT_PRETIMEOUT;
  79. module_param(pretimeout, uint, 0);
  80. MODULE_PARM_DESC(pretimeout,
  81. "Watchdog pretimeout in seconds. (>=0, default="
  82. __MODULE_STRING(DEFAULT_PRETIMEOUT) ")");
  83. static bool nowayout = WATCHDOG_NOWAYOUT;
  84. module_param(nowayout, bool, 0);
  85. MODULE_PARM_DESC(nowayout,
  86. "Watchdog cannot be stopped once started (default="
  87. __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  88. static int kempld_wdt_set_stage_action(struct kempld_wdt_data *wdt_data,
  89. struct kempld_wdt_stage *stage,
  90. u8 action)
  91. {
  92. struct kempld_device_data *pld = wdt_data->pld;
  93. u8 stage_cfg;
  94. if (!stage || !stage->mask)
  95. return -EINVAL;
  96. kempld_get_mutex(pld);
  97. stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
  98. stage_cfg &= ~STAGE_CFG_ACTION_MASK;
  99. stage_cfg |= (action & STAGE_CFG_ACTION_MASK);
  100. if (action == ACTION_RESET)
  101. stage_cfg |= STAGE_CFG_ASSERT;
  102. else
  103. stage_cfg &= ~STAGE_CFG_ASSERT;
  104. kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
  105. kempld_release_mutex(pld);
  106. return 0;
  107. }
  108. static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data,
  109. struct kempld_wdt_stage *stage,
  110. unsigned int timeout)
  111. {
  112. struct kempld_device_data *pld = wdt_data->pld;
  113. u32 prescaler;
  114. u64 stage_timeout64;
  115. u32 stage_timeout;
  116. u32 remainder;
  117. u8 stage_cfg;
  118. prescaler = kempld_prescaler[PRESCALER_21];
  119. if (!stage)
  120. return -EINVAL;
  121. stage_timeout64 = (u64)timeout * pld->pld_clock;
  122. remainder = do_div(stage_timeout64, prescaler);
  123. if (remainder)
  124. stage_timeout64++;
  125. if (stage_timeout64 > stage->mask)
  126. return -EINVAL;
  127. stage_timeout = stage_timeout64 & stage->mask;
  128. kempld_get_mutex(pld);
  129. stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
  130. stage_cfg &= ~STAGE_CFG_PRESCALER_MASK;
  131. stage_cfg |= STAGE_CFG_SET_PRESCALER(PRESCALER_21);
  132. kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
  133. kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id),
  134. stage_timeout);
  135. kempld_release_mutex(pld);
  136. return 0;
  137. }
  138. /*
  139. * kempld_get_mutex must be called prior to calling this function.
  140. */
  141. static unsigned int kempld_wdt_get_timeout(struct kempld_wdt_data *wdt_data,
  142. struct kempld_wdt_stage *stage)
  143. {
  144. struct kempld_device_data *pld = wdt_data->pld;
  145. unsigned int timeout;
  146. u64 stage_timeout;
  147. u32 prescaler;
  148. u32 remainder;
  149. u8 stage_cfg;
  150. if (!stage->mask)
  151. return 0;
  152. stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
  153. stage_timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id));
  154. prescaler = kempld_prescaler[STAGE_CFG_GET_PRESCALER(stage_cfg)];
  155. stage_timeout = (stage_timeout & stage->mask) * prescaler;
  156. remainder = do_div(stage_timeout, pld->pld_clock);
  157. if (remainder)
  158. stage_timeout++;
  159. timeout = stage_timeout;
  160. WARN_ON_ONCE(timeout != stage_timeout);
  161. return timeout;
  162. }
  163. static int kempld_wdt_set_timeout(struct watchdog_device *wdd,
  164. unsigned int timeout)
  165. {
  166. struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
  167. struct kempld_wdt_stage *pretimeout_stage;
  168. struct kempld_wdt_stage *timeout_stage;
  169. int ret;
  170. timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
  171. pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
  172. if (pretimeout_stage->mask && wdt_data->pretimeout > 0)
  173. timeout = wdt_data->pretimeout;
  174. ret = kempld_wdt_set_stage_action(wdt_data, timeout_stage,
  175. ACTION_RESET);
  176. if (ret)
  177. return ret;
  178. ret = kempld_wdt_set_stage_timeout(wdt_data, timeout_stage,
  179. timeout);
  180. if (ret)
  181. return ret;
  182. wdd->timeout = timeout;
  183. return 0;
  184. }
  185. static int kempld_wdt_set_pretimeout(struct watchdog_device *wdd,
  186. unsigned int pretimeout)
  187. {
  188. struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
  189. struct kempld_wdt_stage *pretimeout_stage;
  190. u8 action = ACTION_NONE;
  191. int ret;
  192. pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
  193. if (!pretimeout_stage->mask)
  194. return -ENXIO;
  195. if (pretimeout > wdd->timeout)
  196. return -EINVAL;
  197. if (pretimeout > 0)
  198. action = ACTION_NMI;
  199. ret = kempld_wdt_set_stage_action(wdt_data, pretimeout_stage,
  200. action);
  201. if (ret)
  202. return ret;
  203. ret = kempld_wdt_set_stage_timeout(wdt_data, pretimeout_stage,
  204. wdd->timeout - pretimeout);
  205. if (ret)
  206. return ret;
  207. wdt_data->pretimeout = pretimeout;
  208. return 0;
  209. }
  210. static void kempld_wdt_update_timeouts(struct kempld_wdt_data *wdt_data)
  211. {
  212. struct kempld_device_data *pld = wdt_data->pld;
  213. struct kempld_wdt_stage *pretimeout_stage;
  214. struct kempld_wdt_stage *timeout_stage;
  215. unsigned int pretimeout, timeout;
  216. pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
  217. timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
  218. kempld_get_mutex(pld);
  219. pretimeout = kempld_wdt_get_timeout(wdt_data, pretimeout_stage);
  220. timeout = kempld_wdt_get_timeout(wdt_data, timeout_stage);
  221. kempld_release_mutex(pld);
  222. if (pretimeout)
  223. wdt_data->pretimeout = timeout;
  224. else
  225. wdt_data->pretimeout = 0;
  226. wdt_data->wdd.timeout = pretimeout + timeout;
  227. }
  228. static int kempld_wdt_start(struct watchdog_device *wdd)
  229. {
  230. struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
  231. struct kempld_device_data *pld = wdt_data->pld;
  232. u8 status;
  233. int ret;
  234. ret = kempld_wdt_set_timeout(wdd, wdd->timeout);
  235. if (ret)
  236. return ret;
  237. kempld_get_mutex(pld);
  238. status = kempld_read8(pld, KEMPLD_WDT_CFG);
  239. status |= KEMPLD_WDT_CFG_ENABLE;
  240. kempld_write8(pld, KEMPLD_WDT_CFG, status);
  241. status = kempld_read8(pld, KEMPLD_WDT_CFG);
  242. kempld_release_mutex(pld);
  243. /* Check if the watchdog was enabled */
  244. if (!(status & KEMPLD_WDT_CFG_ENABLE))
  245. return -EACCES;
  246. return 0;
  247. }
  248. static int kempld_wdt_stop(struct watchdog_device *wdd)
  249. {
  250. struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
  251. struct kempld_device_data *pld = wdt_data->pld;
  252. u8 status;
  253. kempld_get_mutex(pld);
  254. status = kempld_read8(pld, KEMPLD_WDT_CFG);
  255. status &= ~KEMPLD_WDT_CFG_ENABLE;
  256. kempld_write8(pld, KEMPLD_WDT_CFG, status);
  257. status = kempld_read8(pld, KEMPLD_WDT_CFG);
  258. kempld_release_mutex(pld);
  259. /* Check if the watchdog was disabled */
  260. if (status & KEMPLD_WDT_CFG_ENABLE)
  261. return -EACCES;
  262. return 0;
  263. }
  264. static int kempld_wdt_keepalive(struct watchdog_device *wdd)
  265. {
  266. struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
  267. struct kempld_device_data *pld = wdt_data->pld;
  268. kempld_get_mutex(pld);
  269. kempld_write8(pld, KEMPLD_WDT_KICK, 'K');
  270. kempld_release_mutex(pld);
  271. return 0;
  272. }
  273. static long kempld_wdt_ioctl(struct watchdog_device *wdd, unsigned int cmd,
  274. unsigned long arg)
  275. {
  276. struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
  277. void __user *argp = (void __user *)arg;
  278. int ret = -ENOIOCTLCMD;
  279. int __user *p = argp;
  280. int new_value;
  281. switch (cmd) {
  282. case WDIOC_SETPRETIMEOUT:
  283. if (get_user(new_value, p))
  284. return -EFAULT;
  285. ret = kempld_wdt_set_pretimeout(wdd, new_value);
  286. if (ret)
  287. return ret;
  288. ret = kempld_wdt_keepalive(wdd);
  289. break;
  290. case WDIOC_GETPRETIMEOUT:
  291. ret = put_user(wdt_data->pretimeout, (int __user *)arg);
  292. break;
  293. }
  294. return ret;
  295. }
  296. static int kempld_wdt_probe_stages(struct watchdog_device *wdd)
  297. {
  298. struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
  299. struct kempld_device_data *pld = wdt_data->pld;
  300. struct kempld_wdt_stage *pretimeout_stage;
  301. struct kempld_wdt_stage *timeout_stage;
  302. u8 index, data, data_orig;
  303. u32 mask;
  304. int i, j;
  305. pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
  306. timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
  307. pretimeout_stage->mask = 0;
  308. timeout_stage->mask = 0;
  309. for (i = 0; i < 3; i++) {
  310. index = KEMPLD_WDT_STAGE_TIMEOUT(i);
  311. mask = 0;
  312. kempld_get_mutex(pld);
  313. /* Probe each byte individually. */
  314. for (j = 0; j < 4; j++) {
  315. data_orig = kempld_read8(pld, index + j);
  316. kempld_write8(pld, index + j, 0x00);
  317. data = kempld_read8(pld, index + j);
  318. /* A failed write means this byte is reserved */
  319. if (data != 0x00)
  320. break;
  321. kempld_write8(pld, index + j, data_orig);
  322. mask |= 0xff << (j * 8);
  323. }
  324. kempld_release_mutex(pld);
  325. /* Assign available stages to timeout and pretimeout */
  326. if (!timeout_stage->mask) {
  327. timeout_stage->mask = mask;
  328. timeout_stage->id = i;
  329. } else {
  330. if (pld->feature_mask & KEMPLD_FEATURE_BIT_NMI) {
  331. pretimeout_stage->mask = timeout_stage->mask;
  332. timeout_stage->mask = mask;
  333. pretimeout_stage->id = timeout_stage->id;
  334. timeout_stage->id = i;
  335. }
  336. break;
  337. }
  338. }
  339. if (!timeout_stage->mask)
  340. return -ENODEV;
  341. return 0;
  342. }
  343. static const struct watchdog_info kempld_wdt_info = {
  344. .identity = "KEMPLD Watchdog",
  345. .options = WDIOF_SETTIMEOUT |
  346. WDIOF_KEEPALIVEPING |
  347. WDIOF_MAGICCLOSE |
  348. WDIOF_PRETIMEOUT
  349. };
  350. static const struct watchdog_ops kempld_wdt_ops = {
  351. .owner = THIS_MODULE,
  352. .start = kempld_wdt_start,
  353. .stop = kempld_wdt_stop,
  354. .ping = kempld_wdt_keepalive,
  355. .set_timeout = kempld_wdt_set_timeout,
  356. .ioctl = kempld_wdt_ioctl,
  357. };
  358. static int kempld_wdt_probe(struct platform_device *pdev)
  359. {
  360. struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
  361. struct kempld_wdt_data *wdt_data;
  362. struct device *dev = &pdev->dev;
  363. struct watchdog_device *wdd;
  364. u8 status;
  365. int ret = 0;
  366. wdt_data = devm_kzalloc(dev, sizeof(*wdt_data), GFP_KERNEL);
  367. if (!wdt_data)
  368. return -ENOMEM;
  369. wdt_data->pld = pld;
  370. wdd = &wdt_data->wdd;
  371. wdd->parent = dev;
  372. kempld_get_mutex(pld);
  373. status = kempld_read8(pld, KEMPLD_WDT_CFG);
  374. kempld_release_mutex(pld);
  375. /* Enable nowayout if watchdog is already locked */
  376. if (status & (KEMPLD_WDT_CFG_ENABLE_LOCK |
  377. KEMPLD_WDT_CFG_GLOBAL_LOCK)) {
  378. if (!nowayout)
  379. dev_warn(dev,
  380. "Forcing nowayout - watchdog lock enabled!\n");
  381. nowayout = true;
  382. }
  383. wdd->info = &kempld_wdt_info;
  384. wdd->ops = &kempld_wdt_ops;
  385. watchdog_set_drvdata(wdd, wdt_data);
  386. watchdog_set_nowayout(wdd, nowayout);
  387. ret = kempld_wdt_probe_stages(wdd);
  388. if (ret)
  389. return ret;
  390. kempld_wdt_set_timeout(wdd, timeout);
  391. kempld_wdt_set_pretimeout(wdd, pretimeout);
  392. /* Check if watchdog is already enabled */
  393. if (status & KEMPLD_WDT_CFG_ENABLE) {
  394. /* Get current watchdog settings */
  395. kempld_wdt_update_timeouts(wdt_data);
  396. dev_info(dev, "Watchdog was already enabled\n");
  397. }
  398. platform_set_drvdata(pdev, wdt_data);
  399. watchdog_stop_on_reboot(wdd);
  400. watchdog_stop_on_unregister(wdd);
  401. ret = devm_watchdog_register_device(dev, wdd);
  402. if (ret)
  403. return ret;
  404. dev_info(dev, "Watchdog registered with %ds timeout\n", wdd->timeout);
  405. return 0;
  406. }
  407. /* Disable watchdog if it is active during suspend */
  408. static int kempld_wdt_suspend(struct platform_device *pdev,
  409. pm_message_t message)
  410. {
  411. struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
  412. struct kempld_device_data *pld = wdt_data->pld;
  413. struct watchdog_device *wdd = &wdt_data->wdd;
  414. kempld_get_mutex(pld);
  415. wdt_data->pm_status_store = kempld_read8(pld, KEMPLD_WDT_CFG);
  416. kempld_release_mutex(pld);
  417. kempld_wdt_update_timeouts(wdt_data);
  418. if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
  419. return kempld_wdt_stop(wdd);
  420. return 0;
  421. }
  422. /* Enable watchdog and configure it if necessary */
  423. static int kempld_wdt_resume(struct platform_device *pdev)
  424. {
  425. struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
  426. struct watchdog_device *wdd = &wdt_data->wdd;
  427. /*
  428. * If watchdog was stopped before suspend be sure it gets disabled
  429. * again, for the case BIOS has enabled it during resume
  430. */
  431. if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
  432. return kempld_wdt_start(wdd);
  433. else
  434. return kempld_wdt_stop(wdd);
  435. }
  436. static struct platform_driver kempld_wdt_driver = {
  437. .driver = {
  438. .name = "kempld-wdt",
  439. },
  440. .probe = kempld_wdt_probe,
  441. .suspend = pm_ptr(kempld_wdt_suspend),
  442. .resume = pm_ptr(kempld_wdt_resume),
  443. };
  444. module_platform_driver(kempld_wdt_driver);
  445. MODULE_DESCRIPTION("KEM PLD Watchdog Driver");
  446. MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
  447. MODULE_LICENSE("GPL");