kempld_wdt.c 15 KB

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