Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  *  intel TCO vendor specific watchdog driver support
0004  *
0005  *  (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
0006  *
0007  *  Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
0008  *  provide warranty for any of this software. This material is
0009  *  provided "AS-IS" and at no charge.
0010  */
0011 
0012 /*
0013  *  Includes, defines, variables, module parameters, ...
0014  */
0015 
0016 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0017 
0018 /* Module and version information */
0019 #define DRV_NAME    "iTCO_vendor_support"
0020 #define DRV_VERSION "1.04"
0021 
0022 /* Includes */
0023 #include <linux/module.h>       /* For module specific items */
0024 #include <linux/moduleparam.h>      /* For new moduleparam's */
0025 #include <linux/types.h>        /* For standard types (like size_t) */
0026 #include <linux/errno.h>        /* For the -ENODEV/... values */
0027 #include <linux/kernel.h>       /* For printk/panic/... */
0028 #include <linux/init.h>         /* For __init/__exit/... */
0029 #include <linux/ioport.h>       /* For io-port access */
0030 #include <linux/io.h>           /* For inb/outb/... */
0031 
0032 #include "iTCO_vendor.h"
0033 
0034 /* List of vendor support modes */
0035 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
0036 #define SUPERMICRO_OLD_BOARD    1
0037 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems - no longer supported */
0038 #define SUPERMICRO_NEW_BOARD    2
0039 /* Broken BIOS */
0040 #define BROKEN_BIOS     911
0041 
0042 int iTCO_vendorsupport;
0043 EXPORT_SYMBOL(iTCO_vendorsupport);
0044 
0045 module_param_named(vendorsupport, iTCO_vendorsupport, int, 0);
0046 MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
0047             "0 (none), 1=SuperMicro Pent3, 911=Broken SMI BIOS");
0048 
0049 /*
0050  *  Vendor Specific Support
0051  */
0052 
0053 /*
0054  *  Vendor Support: 1
0055  *  Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE
0056  *  iTCO chipset: ICH2
0057  *
0058  *  Code contributed by: R. Seretny <lkpatches@paypc.com>
0059  *  Documentation obtained by R. Seretny from SuperMicro Technical Support
0060  *
0061  *  To enable Watchdog function:
0062  *      BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes
0063  *      This setting enables SMI to clear the watchdog expired flag.
0064  *      If BIOS or CPU fail which may cause SMI hang, then system will
0065  *      reboot. When application starts to use watchdog function,
0066  *      application has to take over the control from SMI.
0067  *
0068  *      For P3TSSE, J36 jumper needs to be removed to enable the Watchdog
0069  *      function.
0070  *
0071  *      Note: The system will reboot when Expire Flag is set TWICE.
0072  *      So, if the watchdog timer is 20 seconds, then the maximum hang
0073  *      time is about 40 seconds, and the minimum hang time is about
0074  *      20.6 seconds.
0075  */
0076 
0077 static void supermicro_old_pre_start(struct resource *smires)
0078 {
0079     unsigned long val32;
0080 
0081     /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
0082     val32 = inl(smires->start);
0083     val32 &= 0xffffdfff;    /* Turn off SMI clearing watchdog */
0084     outl(val32, smires->start); /* Needed to activate watchdog */
0085 }
0086 
0087 static void supermicro_old_pre_stop(struct resource *smires)
0088 {
0089     unsigned long val32;
0090 
0091     /* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
0092     val32 = inl(smires->start);
0093     val32 |= 0x00002000;    /* Turn on SMI clearing watchdog */
0094     outl(val32, smires->start); /* Needed to deactivate watchdog */
0095 }
0096 
0097 /*
0098  *  Vendor Support: 911
0099  *  Board: Some Intel ICHx based motherboards
0100  *  iTCO chipset: ICH7+
0101  *
0102  *  Some Intel motherboards have a broken BIOS implementation: i.e.
0103  *  the SMI handler clear's the TIMEOUT bit in the TC01_STS register
0104  *  and does not reload the time. Thus the TCO watchdog does not reboot
0105  *  the system.
0106  *
0107  *  These are the conclusions of Andriy Gapon <avg@icyb.net.ua> after
0108  *  debugging: the SMI handler is quite simple - it tests value in
0109  *  TCO1_CNT against 0x800, i.e. checks TCO_TMR_HLT. If the bit is set
0110  *  the handler goes into an infinite loop, apparently to allow the
0111  *  second timeout and reboot. Otherwise it simply clears TIMEOUT bit
0112  *  in TCO1_STS and that's it.
0113  *  So the logic seems to be reversed, because it is hard to see how
0114  *  TIMEOUT can get set to 1 and SMI generated when TCO_TMR_HLT is set
0115  *  (other than a transitional effect).
0116  *
0117  *  The only fix found to get the motherboard(s) to reboot is to put
0118  *  the glb_smi_en bit to 0. This is a dirty hack that bypasses the
0119  *  broken code by disabling Global SMI.
0120  *
0121  *  WARNING: globally disabling SMI could possibly lead to dramatic
0122  *  problems, especially on laptops! I.e. various ACPI things where
0123  *  SMI is used for communication between OS and firmware.
0124  *
0125  *  Don't use this fix if you don't need to!!!
0126  */
0127 
0128 static void broken_bios_start(struct resource *smires)
0129 {
0130     unsigned long val32;
0131 
0132     val32 = inl(smires->start);
0133     /* Bit 13: TCO_EN     -> 0 = Disables TCO logic generating an SMI#
0134        Bit  0: GBL_SMI_EN -> 0 = No SMI# will be generated by ICH. */
0135     val32 &= 0xffffdffe;
0136     outl(val32, smires->start);
0137 }
0138 
0139 static void broken_bios_stop(struct resource *smires)
0140 {
0141     unsigned long val32;
0142 
0143     val32 = inl(smires->start);
0144     /* Bit 13: TCO_EN     -> 1 = Enables TCO logic generating an SMI#
0145        Bit  0: GBL_SMI_EN -> 1 = Turn global SMI on again. */
0146     val32 |= 0x00002001;
0147     outl(val32, smires->start);
0148 }
0149 
0150 /*
0151  *  Generic Support Functions
0152  */
0153 
0154 void iTCO_vendor_pre_start(struct resource *smires,
0155                unsigned int heartbeat)
0156 {
0157     switch (iTCO_vendorsupport) {
0158     case SUPERMICRO_OLD_BOARD:
0159         supermicro_old_pre_start(smires);
0160         break;
0161     case BROKEN_BIOS:
0162         broken_bios_start(smires);
0163         break;
0164     }
0165 }
0166 EXPORT_SYMBOL(iTCO_vendor_pre_start);
0167 
0168 void iTCO_vendor_pre_stop(struct resource *smires)
0169 {
0170     switch (iTCO_vendorsupport) {
0171     case SUPERMICRO_OLD_BOARD:
0172         supermicro_old_pre_stop(smires);
0173         break;
0174     case BROKEN_BIOS:
0175         broken_bios_stop(smires);
0176         break;
0177     }
0178 }
0179 EXPORT_SYMBOL(iTCO_vendor_pre_stop);
0180 
0181 int iTCO_vendor_check_noreboot_on(void)
0182 {
0183     switch (iTCO_vendorsupport) {
0184     case SUPERMICRO_OLD_BOARD:
0185         return 0;
0186     default:
0187         return 1;
0188     }
0189 }
0190 EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
0191 
0192 static int __init iTCO_vendor_init_module(void)
0193 {
0194     if (iTCO_vendorsupport == SUPERMICRO_NEW_BOARD) {
0195         pr_warn("Option vendorsupport=%d is no longer supported, "
0196             "please use the w83627hf_wdt driver instead\n",
0197             SUPERMICRO_NEW_BOARD);
0198         return -EINVAL;
0199     }
0200     pr_info("vendor-support=%d\n", iTCO_vendorsupport);
0201     return 0;
0202 }
0203 
0204 static void __exit iTCO_vendor_exit_module(void)
0205 {
0206     pr_info("Module Unloaded\n");
0207 }
0208 
0209 module_init(iTCO_vendor_init_module);
0210 module_exit(iTCO_vendor_exit_module);
0211 
0212 MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, "
0213         "R. Seretny <lkpatches@paypc.com>");
0214 MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
0215 MODULE_VERSION(DRV_VERSION);
0216 MODULE_LICENSE("GPL");