iTCO_vendor_support.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * intel TCO vendor specific watchdog driver support
  4. *
  5. * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
  6. *
  7. * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
  8. * provide warranty for any of this software. This material is
  9. * provided "AS-IS" and at no charge.
  10. */
  11. /*
  12. * Includes, defines, variables, module parameters, ...
  13. */
  14. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  15. /* Module and version information */
  16. #define DRV_NAME "iTCO_vendor_support"
  17. #define DRV_VERSION "1.04"
  18. /* Includes */
  19. #include <linux/module.h> /* For module specific items */
  20. #include <linux/moduleparam.h> /* For new moduleparam's */
  21. #include <linux/types.h> /* For standard types (like size_t) */
  22. #include <linux/errno.h> /* For the -ENODEV/... values */
  23. #include <linux/kernel.h> /* For printk/panic/... */
  24. #include <linux/init.h> /* For __init/__exit/... */
  25. #include <linux/ioport.h> /* For io-port access */
  26. #include <linux/io.h> /* For inb/outb/... */
  27. #include "iTCO_vendor.h"
  28. /* List of vendor support modes */
  29. /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
  30. #define SUPERMICRO_OLD_BOARD 1
  31. /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems - no longer supported */
  32. #define SUPERMICRO_NEW_BOARD 2
  33. /* Broken BIOS */
  34. #define BROKEN_BIOS 911
  35. int iTCO_vendorsupport;
  36. EXPORT_SYMBOL(iTCO_vendorsupport);
  37. module_param_named(vendorsupport, iTCO_vendorsupport, int, 0);
  38. MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
  39. "0 (none), 1=SuperMicro Pent3, 911=Broken SMI BIOS");
  40. /*
  41. * Vendor Specific Support
  42. */
  43. /*
  44. * Vendor Support: 1
  45. * Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE
  46. * iTCO chipset: ICH2
  47. *
  48. * Code contributed by: R. Seretny <lkpatches@paypc.com>
  49. * Documentation obtained by R. Seretny from SuperMicro Technical Support
  50. *
  51. * To enable Watchdog function:
  52. * BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes
  53. * This setting enables SMI to clear the watchdog expired flag.
  54. * If BIOS or CPU fail which may cause SMI hang, then system will
  55. * reboot. When application starts to use watchdog function,
  56. * application has to take over the control from SMI.
  57. *
  58. * For P3TSSE, J36 jumper needs to be removed to enable the Watchdog
  59. * function.
  60. *
  61. * Note: The system will reboot when Expire Flag is set TWICE.
  62. * So, if the watchdog timer is 20 seconds, then the maximum hang
  63. * time is about 40 seconds, and the minimum hang time is about
  64. * 20.6 seconds.
  65. */
  66. static void supermicro_old_pre_start(struct resource *smires)
  67. {
  68. unsigned long val32;
  69. /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
  70. val32 = inl(smires->start);
  71. val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
  72. outl(val32, smires->start); /* Needed to activate watchdog */
  73. }
  74. static void supermicro_old_pre_stop(struct resource *smires)
  75. {
  76. unsigned long val32;
  77. /* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
  78. val32 = inl(smires->start);
  79. val32 |= 0x00002000; /* Turn on SMI clearing watchdog */
  80. outl(val32, smires->start); /* Needed to deactivate watchdog */
  81. }
  82. /*
  83. * Vendor Support: 911
  84. * Board: Some Intel ICHx based motherboards
  85. * iTCO chipset: ICH7+
  86. *
  87. * Some Intel motherboards have a broken BIOS implementation: i.e.
  88. * the SMI handler clear's the TIMEOUT bit in the TC01_STS register
  89. * and does not reload the time. Thus the TCO watchdog does not reboot
  90. * the system.
  91. *
  92. * These are the conclusions of Andriy Gapon <avg@icyb.net.ua> after
  93. * debugging: the SMI handler is quite simple - it tests value in
  94. * TCO1_CNT against 0x800, i.e. checks TCO_TMR_HLT. If the bit is set
  95. * the handler goes into an infinite loop, apparently to allow the
  96. * second timeout and reboot. Otherwise it simply clears TIMEOUT bit
  97. * in TCO1_STS and that's it.
  98. * So the logic seems to be reversed, because it is hard to see how
  99. * TIMEOUT can get set to 1 and SMI generated when TCO_TMR_HLT is set
  100. * (other than a transitional effect).
  101. *
  102. * The only fix found to get the motherboard(s) to reboot is to put
  103. * the glb_smi_en bit to 0. This is a dirty hack that bypasses the
  104. * broken code by disabling Global SMI.
  105. *
  106. * WARNING: globally disabling SMI could possibly lead to dramatic
  107. * problems, especially on laptops! I.e. various ACPI things where
  108. * SMI is used for communication between OS and firmware.
  109. *
  110. * Don't use this fix if you don't need to!!!
  111. */
  112. static void broken_bios_start(struct resource *smires)
  113. {
  114. unsigned long val32;
  115. val32 = inl(smires->start);
  116. /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI#
  117. Bit 0: GBL_SMI_EN -> 0 = No SMI# will be generated by ICH. */
  118. val32 &= 0xffffdffe;
  119. outl(val32, smires->start);
  120. }
  121. static void broken_bios_stop(struct resource *smires)
  122. {
  123. unsigned long val32;
  124. val32 = inl(smires->start);
  125. /* Bit 13: TCO_EN -> 1 = Enables TCO logic generating an SMI#
  126. Bit 0: GBL_SMI_EN -> 1 = Turn global SMI on again. */
  127. val32 |= 0x00002001;
  128. outl(val32, smires->start);
  129. }
  130. /*
  131. * Generic Support Functions
  132. */
  133. void iTCO_vendor_pre_start(struct resource *smires,
  134. unsigned int heartbeat)
  135. {
  136. switch (iTCO_vendorsupport) {
  137. case SUPERMICRO_OLD_BOARD:
  138. supermicro_old_pre_start(smires);
  139. break;
  140. case BROKEN_BIOS:
  141. broken_bios_start(smires);
  142. break;
  143. }
  144. }
  145. EXPORT_SYMBOL(iTCO_vendor_pre_start);
  146. void iTCO_vendor_pre_stop(struct resource *smires)
  147. {
  148. switch (iTCO_vendorsupport) {
  149. case SUPERMICRO_OLD_BOARD:
  150. supermicro_old_pre_stop(smires);
  151. break;
  152. case BROKEN_BIOS:
  153. broken_bios_stop(smires);
  154. break;
  155. }
  156. }
  157. EXPORT_SYMBOL(iTCO_vendor_pre_stop);
  158. int iTCO_vendor_check_noreboot_on(void)
  159. {
  160. switch (iTCO_vendorsupport) {
  161. case SUPERMICRO_OLD_BOARD:
  162. return 0;
  163. default:
  164. return 1;
  165. }
  166. }
  167. EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
  168. static int __init iTCO_vendor_init_module(void)
  169. {
  170. if (iTCO_vendorsupport == SUPERMICRO_NEW_BOARD) {
  171. pr_warn("Option vendorsupport=%d is no longer supported, "
  172. "please use the w83627hf_wdt driver instead\n",
  173. SUPERMICRO_NEW_BOARD);
  174. return -EINVAL;
  175. }
  176. pr_info("vendor-support=%d\n", iTCO_vendorsupport);
  177. return 0;
  178. }
  179. static void __exit iTCO_vendor_exit_module(void)
  180. {
  181. pr_info("Module Unloaded\n");
  182. }
  183. module_init(iTCO_vendor_init_module);
  184. module_exit(iTCO_vendor_exit_module);
  185. MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, "
  186. "R. Seretny <lkpatches@paypc.com>");
  187. MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
  188. MODULE_VERSION(DRV_VERSION);
  189. MODULE_LICENSE("GPL");