hpwdt.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * HPE WatchDog Driver
  4. * based on
  5. *
  6. * SoftDog 0.05: A Software Watchdog Device
  7. *
  8. * (c) Copyright 2018 Hewlett Packard Enterprise Development LP
  9. * Thomas Mingarelli <[email protected]>
  10. */
  11. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12. #include <linux/device.h>
  13. #include <linux/io.h>
  14. #include <linux/kernel.h>
  15. #include <linux/module.h>
  16. #include <linux/moduleparam.h>
  17. #include <linux/pci.h>
  18. #include <linux/pci_ids.h>
  19. #include <linux/types.h>
  20. #include <linux/watchdog.h>
  21. #ifdef CONFIG_HPWDT_NMI_DECODING
  22. #include <asm/nmi.h>
  23. #endif
  24. #include <linux/crash_dump.h>
  25. #define HPWDT_VERSION "2.0.4"
  26. #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
  27. #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
  28. #define HPWDT_MAX_TICKS 65535
  29. #define HPWDT_MAX_TIMER TICKS_TO_SECS(HPWDT_MAX_TICKS)
  30. #define DEFAULT_MARGIN 30
  31. #define PRETIMEOUT_SEC 9
  32. static bool ilo5;
  33. static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */
  34. static bool nowayout = WATCHDOG_NOWAYOUT;
  35. static bool pretimeout = IS_ENABLED(CONFIG_HPWDT_NMI_DECODING);
  36. static int kdumptimeout = -1;
  37. static void __iomem *pci_mem_addr; /* the PCI-memory address */
  38. static unsigned long __iomem *hpwdt_nmistat;
  39. static unsigned long __iomem *hpwdt_timer_reg;
  40. static unsigned long __iomem *hpwdt_timer_con;
  41. static const struct pci_device_id hpwdt_devices[] = {
  42. { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */
  43. { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */
  44. { PCI_DEVICE(PCI_VENDOR_ID_HP_3PAR, 0x0389) }, /* PCtrl */
  45. {0}, /* terminate list */
  46. };
  47. MODULE_DEVICE_TABLE(pci, hpwdt_devices);
  48. static const struct pci_device_id hpwdt_blacklist[] = {
  49. { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP, 0x1979) }, /* auxilary iLO */
  50. { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP_3PAR, 0x0289) }, /* CL */
  51. {0}, /* terminate list */
  52. };
  53. static struct watchdog_device hpwdt_dev;
  54. /*
  55. * Watchdog operations
  56. */
  57. static int hpwdt_hw_is_running(void)
  58. {
  59. return ioread8(hpwdt_timer_con) & 0x01;
  60. }
  61. static int hpwdt_start(struct watchdog_device *wdd)
  62. {
  63. int control = 0x81 | (pretimeout ? 0x4 : 0);
  64. int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
  65. dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%08x:0x%02x\n", wdd->timeout, reload, control);
  66. iowrite16(reload, hpwdt_timer_reg);
  67. iowrite8(control, hpwdt_timer_con);
  68. return 0;
  69. }
  70. static void hpwdt_stop(void)
  71. {
  72. unsigned long data;
  73. pr_debug("stop watchdog\n");
  74. data = ioread8(hpwdt_timer_con);
  75. data &= 0xFE;
  76. iowrite8(data, hpwdt_timer_con);
  77. }
  78. static int hpwdt_stop_core(struct watchdog_device *wdd)
  79. {
  80. hpwdt_stop();
  81. return 0;
  82. }
  83. static void hpwdt_ping_ticks(int val)
  84. {
  85. val = min(val, HPWDT_MAX_TICKS);
  86. iowrite16(val, hpwdt_timer_reg);
  87. }
  88. static int hpwdt_ping(struct watchdog_device *wdd)
  89. {
  90. int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
  91. dev_dbg(wdd->parent, "ping watchdog 0x%08x:0x%08x\n", wdd->timeout, reload);
  92. hpwdt_ping_ticks(reload);
  93. return 0;
  94. }
  95. static unsigned int hpwdt_gettimeleft(struct watchdog_device *wdd)
  96. {
  97. return TICKS_TO_SECS(ioread16(hpwdt_timer_reg));
  98. }
  99. static int hpwdt_settimeout(struct watchdog_device *wdd, unsigned int val)
  100. {
  101. dev_dbg(wdd->parent, "set_timeout = %d\n", val);
  102. wdd->timeout = val;
  103. if (val <= wdd->pretimeout) {
  104. dev_dbg(wdd->parent, "pretimeout < timeout. Setting to zero\n");
  105. wdd->pretimeout = 0;
  106. pretimeout = false;
  107. if (watchdog_active(wdd))
  108. hpwdt_start(wdd);
  109. }
  110. hpwdt_ping(wdd);
  111. return 0;
  112. }
  113. #ifdef CONFIG_HPWDT_NMI_DECODING
  114. static int hpwdt_set_pretimeout(struct watchdog_device *wdd, unsigned int req)
  115. {
  116. unsigned int val = 0;
  117. dev_dbg(wdd->parent, "set_pretimeout = %d\n", req);
  118. if (req) {
  119. val = PRETIMEOUT_SEC;
  120. if (val >= wdd->timeout)
  121. return -EINVAL;
  122. }
  123. if (val != req)
  124. dev_dbg(wdd->parent, "Rounding pretimeout to: %d\n", val);
  125. wdd->pretimeout = val;
  126. pretimeout = !!val;
  127. if (watchdog_active(wdd))
  128. hpwdt_start(wdd);
  129. return 0;
  130. }
  131. static int hpwdt_my_nmi(void)
  132. {
  133. return ioread8(hpwdt_nmistat) & 0x6;
  134. }
  135. /*
  136. * NMI Handler
  137. */
  138. static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
  139. {
  140. unsigned int mynmi = hpwdt_my_nmi();
  141. static char panic_msg[] =
  142. "00: An NMI occurred. Depending on your system the reason "
  143. "for the NMI is logged in any one of the following resources:\n"
  144. "1. Integrated Management Log (IML)\n"
  145. "2. OA Syslog\n"
  146. "3. OA Forward Progress Log\n"
  147. "4. iLO Event Log";
  148. if (ilo5 && ulReason == NMI_UNKNOWN && !mynmi)
  149. return NMI_DONE;
  150. if (ilo5 && !pretimeout && !mynmi)
  151. return NMI_DONE;
  152. if (kdumptimeout < 0)
  153. hpwdt_stop();
  154. else if (kdumptimeout == 0)
  155. ;
  156. else {
  157. unsigned int val = max((unsigned int)kdumptimeout, hpwdt_dev.timeout);
  158. hpwdt_ping_ticks(SECS_TO_TICKS(val));
  159. }
  160. hex_byte_pack(panic_msg, mynmi);
  161. nmi_panic(regs, panic_msg);
  162. return NMI_HANDLED;
  163. }
  164. #endif /* CONFIG_HPWDT_NMI_DECODING */
  165. static const struct watchdog_info ident = {
  166. .options = WDIOF_PRETIMEOUT |
  167. WDIOF_SETTIMEOUT |
  168. WDIOF_KEEPALIVEPING |
  169. WDIOF_MAGICCLOSE,
  170. .identity = "HPE iLO2+ HW Watchdog Timer",
  171. };
  172. /*
  173. * Kernel interfaces
  174. */
  175. static const struct watchdog_ops hpwdt_ops = {
  176. .owner = THIS_MODULE,
  177. .start = hpwdt_start,
  178. .stop = hpwdt_stop_core,
  179. .ping = hpwdt_ping,
  180. .set_timeout = hpwdt_settimeout,
  181. .get_timeleft = hpwdt_gettimeleft,
  182. #ifdef CONFIG_HPWDT_NMI_DECODING
  183. .set_pretimeout = hpwdt_set_pretimeout,
  184. #endif
  185. };
  186. static struct watchdog_device hpwdt_dev = {
  187. .info = &ident,
  188. .ops = &hpwdt_ops,
  189. .min_timeout = 1,
  190. .timeout = DEFAULT_MARGIN,
  191. .pretimeout = PRETIMEOUT_SEC,
  192. .max_hw_heartbeat_ms = HPWDT_MAX_TIMER * 1000,
  193. };
  194. /*
  195. * Init & Exit
  196. */
  197. static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
  198. {
  199. #ifdef CONFIG_HPWDT_NMI_DECODING
  200. int retval;
  201. /*
  202. * Only one function can register for NMI_UNKNOWN
  203. */
  204. retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, 0, "hpwdt");
  205. if (retval)
  206. goto error;
  207. retval = register_nmi_handler(NMI_SERR, hpwdt_pretimeout, 0, "hpwdt");
  208. if (retval)
  209. goto error1;
  210. retval = register_nmi_handler(NMI_IO_CHECK, hpwdt_pretimeout, 0, "hpwdt");
  211. if (retval)
  212. goto error2;
  213. dev_info(&dev->dev,
  214. "HPE Watchdog Timer Driver: NMI decoding initialized\n");
  215. return 0;
  216. error2:
  217. unregister_nmi_handler(NMI_SERR, "hpwdt");
  218. error1:
  219. unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
  220. error:
  221. dev_warn(&dev->dev,
  222. "Unable to register a die notifier (err=%d).\n",
  223. retval);
  224. return retval;
  225. #endif /* CONFIG_HPWDT_NMI_DECODING */
  226. return 0;
  227. }
  228. static void hpwdt_exit_nmi_decoding(void)
  229. {
  230. #ifdef CONFIG_HPWDT_NMI_DECODING
  231. unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
  232. unregister_nmi_handler(NMI_SERR, "hpwdt");
  233. unregister_nmi_handler(NMI_IO_CHECK, "hpwdt");
  234. #endif
  235. }
  236. static int hpwdt_init_one(struct pci_dev *dev,
  237. const struct pci_device_id *ent)
  238. {
  239. int retval;
  240. /*
  241. * First let's find out if we are on an iLO2+ server. We will
  242. * not run on a legacy ASM box.
  243. * So we only support the G5 ProLiant servers and higher.
  244. */
  245. if (dev->subsystem_vendor != PCI_VENDOR_ID_HP &&
  246. dev->subsystem_vendor != PCI_VENDOR_ID_HP_3PAR) {
  247. dev_warn(&dev->dev,
  248. "This server does not have an iLO2+ ASIC.\n");
  249. return -ENODEV;
  250. }
  251. if (pci_match_id(hpwdt_blacklist, dev)) {
  252. dev_dbg(&dev->dev, "Not supported on this device\n");
  253. return -ENODEV;
  254. }
  255. if (pci_enable_device(dev)) {
  256. dev_warn(&dev->dev,
  257. "Not possible to enable PCI Device: 0x%x:0x%x.\n",
  258. ent->vendor, ent->device);
  259. return -ENODEV;
  260. }
  261. pci_mem_addr = pci_iomap(dev, 1, 0x80);
  262. if (!pci_mem_addr) {
  263. dev_warn(&dev->dev,
  264. "Unable to detect the iLO2+ server memory.\n");
  265. retval = -ENOMEM;
  266. goto error_pci_iomap;
  267. }
  268. hpwdt_nmistat = pci_mem_addr + 0x6e;
  269. hpwdt_timer_reg = pci_mem_addr + 0x70;
  270. hpwdt_timer_con = pci_mem_addr + 0x72;
  271. /* Have the core update running timer until user space is ready */
  272. if (hpwdt_hw_is_running()) {
  273. dev_info(&dev->dev, "timer is running\n");
  274. set_bit(WDOG_HW_RUNNING, &hpwdt_dev.status);
  275. }
  276. /* Initialize NMI Decoding functionality */
  277. retval = hpwdt_init_nmi_decoding(dev);
  278. if (retval != 0)
  279. goto error_init_nmi_decoding;
  280. watchdog_stop_on_unregister(&hpwdt_dev);
  281. watchdog_set_nowayout(&hpwdt_dev, nowayout);
  282. watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
  283. if (is_kdump_kernel()) {
  284. pretimeout = false;
  285. kdumptimeout = 0;
  286. }
  287. if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
  288. dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
  289. pretimeout = false;
  290. }
  291. hpwdt_dev.pretimeout = pretimeout ? PRETIMEOUT_SEC : 0;
  292. kdumptimeout = min(kdumptimeout, HPWDT_MAX_TIMER);
  293. hpwdt_dev.parent = &dev->dev;
  294. retval = watchdog_register_device(&hpwdt_dev);
  295. if (retval < 0)
  296. goto error_wd_register;
  297. dev_info(&dev->dev, "HPE Watchdog Timer Driver: Version: %s\n",
  298. HPWDT_VERSION);
  299. dev_info(&dev->dev, "timeout: %d seconds (nowayout=%d)\n",
  300. hpwdt_dev.timeout, nowayout);
  301. dev_info(&dev->dev, "pretimeout: %s.\n",
  302. pretimeout ? "on" : "off");
  303. dev_info(&dev->dev, "kdumptimeout: %d.\n", kdumptimeout);
  304. if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
  305. ilo5 = true;
  306. return 0;
  307. error_wd_register:
  308. hpwdt_exit_nmi_decoding();
  309. error_init_nmi_decoding:
  310. pci_iounmap(dev, pci_mem_addr);
  311. error_pci_iomap:
  312. pci_disable_device(dev);
  313. return retval;
  314. }
  315. static void hpwdt_exit(struct pci_dev *dev)
  316. {
  317. watchdog_unregister_device(&hpwdt_dev);
  318. hpwdt_exit_nmi_decoding();
  319. pci_iounmap(dev, pci_mem_addr);
  320. pci_disable_device(dev);
  321. }
  322. static struct pci_driver hpwdt_driver = {
  323. .name = "hpwdt",
  324. .id_table = hpwdt_devices,
  325. .probe = hpwdt_init_one,
  326. .remove = hpwdt_exit,
  327. };
  328. MODULE_AUTHOR("Tom Mingarelli");
  329. MODULE_DESCRIPTION("hpe watchdog driver");
  330. MODULE_LICENSE("GPL");
  331. MODULE_VERSION(HPWDT_VERSION);
  332. module_param(soft_margin, int, 0);
  333. MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
  334. module_param_named(timeout, soft_margin, int, 0);
  335. MODULE_PARM_DESC(timeout, "Alias of soft_margin");
  336. module_param(nowayout, bool, 0);
  337. MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
  338. __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  339. module_param(kdumptimeout, int, 0444);
  340. MODULE_PARM_DESC(kdumptimeout, "Timeout applied for crash kernel transition in seconds");
  341. #ifdef CONFIG_HPWDT_NMI_DECODING
  342. module_param(pretimeout, bool, 0);
  343. MODULE_PARM_DESC(pretimeout, "Watchdog pretimeout enabled");
  344. #endif
  345. module_pci_driver(hpwdt_driver);