| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * intel TCO vendor specific watchdog driver support |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License |
|---|
| 8 | | - * as published by the Free Software Foundation; either version |
|---|
| 9 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 10 | 6 | * |
|---|
| 11 | 7 | * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor |
|---|
| 12 | 8 | * provide warranty for any of this software. This material is |
|---|
| .. | .. |
|---|
| 38 | 34 | /* List of vendor support modes */ |
|---|
| 39 | 35 | /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */ |
|---|
| 40 | 36 | #define SUPERMICRO_OLD_BOARD 1 |
|---|
| 41 | | -/* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */ |
|---|
| 37 | +/* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems - no longer supported */ |
|---|
| 42 | 38 | #define SUPERMICRO_NEW_BOARD 2 |
|---|
| 43 | 39 | /* Broken BIOS */ |
|---|
| 44 | 40 | #define BROKEN_BIOS 911 |
|---|
| 45 | 41 | |
|---|
| 46 | | -static int vendorsupport; |
|---|
| 47 | | -module_param(vendorsupport, int, 0); |
|---|
| 42 | +int iTCO_vendorsupport; |
|---|
| 43 | +EXPORT_SYMBOL(iTCO_vendorsupport); |
|---|
| 44 | + |
|---|
| 45 | +module_param_named(vendorsupport, iTCO_vendorsupport, int, 0); |
|---|
| 48 | 46 | MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=" |
|---|
| 49 | | - "0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+, " |
|---|
| 50 | | - "911=Broken SMI BIOS"); |
|---|
| 47 | + "0 (none), 1=SuperMicro Pent3, 911=Broken SMI BIOS"); |
|---|
| 51 | 48 | |
|---|
| 52 | 49 | /* |
|---|
| 53 | 50 | * Vendor Specific Support |
|---|
| .. | .. |
|---|
| 95 | 92 | val32 = inl(smires->start); |
|---|
| 96 | 93 | val32 |= 0x00002000; /* Turn on SMI clearing watchdog */ |
|---|
| 97 | 94 | outl(val32, smires->start); /* Needed to deactivate watchdog */ |
|---|
| 98 | | -} |
|---|
| 99 | | - |
|---|
| 100 | | -/* |
|---|
| 101 | | - * Vendor Support: 2 |
|---|
| 102 | | - * Board: Super Micro Computer Inc. P4SBx, P4DPx |
|---|
| 103 | | - * iTCO chipset: ICH4 |
|---|
| 104 | | - * |
|---|
| 105 | | - * Code contributed by: R. Seretny <lkpatches@paypc.com> |
|---|
| 106 | | - * Documentation obtained by R. Seretny from SuperMicro Technical Support |
|---|
| 107 | | - * |
|---|
| 108 | | - * To enable Watchdog function: |
|---|
| 109 | | - * 1. BIOS |
|---|
| 110 | | - * For P4SBx: |
|---|
| 111 | | - * BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature |
|---|
| 112 | | - * For P4DPx: |
|---|
| 113 | | - * BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog |
|---|
| 114 | | - * This setting enables or disables Watchdog function. When enabled, the |
|---|
| 115 | | - * default watchdog timer is set to be 5 minutes (about 4m35s). It is |
|---|
| 116 | | - * enough to load and run the OS. The application (service or driver) has |
|---|
| 117 | | - * to take over the control once OS is running up and before watchdog |
|---|
| 118 | | - * expires. |
|---|
| 119 | | - * |
|---|
| 120 | | - * 2. JUMPER |
|---|
| 121 | | - * For P4SBx: JP39 |
|---|
| 122 | | - * For P4DPx: JP37 |
|---|
| 123 | | - * This jumper is used for safety. Closed is enabled. This jumper |
|---|
| 124 | | - * prevents user enables watchdog in BIOS by accident. |
|---|
| 125 | | - * |
|---|
| 126 | | - * To enable Watch Dog function, both BIOS and JUMPER must be enabled. |
|---|
| 127 | | - * |
|---|
| 128 | | - * The documentation lists motherboards P4SBx and P4DPx series as of |
|---|
| 129 | | - * 20-March-2002. However, this code works flawlessly with much newer |
|---|
| 130 | | - * motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82). |
|---|
| 131 | | - * |
|---|
| 132 | | - * The original iTCO driver as written does not actually reset the |
|---|
| 133 | | - * watchdog timer on these machines, as a result they reboot after five |
|---|
| 134 | | - * minutes. |
|---|
| 135 | | - * |
|---|
| 136 | | - * NOTE: You may leave the Watchdog function disabled in the SuperMicro |
|---|
| 137 | | - * BIOS to avoid a "boot-race"... This driver will enable watchdog |
|---|
| 138 | | - * functionality even if it's disabled in the BIOS once the /dev/watchdog |
|---|
| 139 | | - * file is opened. |
|---|
| 140 | | - */ |
|---|
| 141 | | - |
|---|
| 142 | | -/* I/O Port's */ |
|---|
| 143 | | -#define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */ |
|---|
| 144 | | -#define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */ |
|---|
| 145 | | - |
|---|
| 146 | | -/* Control Register's */ |
|---|
| 147 | | -#define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */ |
|---|
| 148 | | -#define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */ |
|---|
| 149 | | - |
|---|
| 150 | | -#define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */ |
|---|
| 151 | | - |
|---|
| 152 | | -#define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */ |
|---|
| 153 | | - |
|---|
| 154 | | -#define SM_ENDWATCH 0xAA /* Watchdog lock control page */ |
|---|
| 155 | | - |
|---|
| 156 | | -#define SM_COUNTMODE 0xf5 /* Watchdog count mode select */ |
|---|
| 157 | | - /* (Bit 3: 0 = seconds, 1 = minutes */ |
|---|
| 158 | | - |
|---|
| 159 | | -#define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */ |
|---|
| 160 | | - |
|---|
| 161 | | -#define SM_RESETCONTROL 0xf7 /* Watchdog reset control */ |
|---|
| 162 | | - /* Bit 6: timer is reset by kbd interrupt */ |
|---|
| 163 | | - /* Bit 7: timer is reset by mouse interrupt */ |
|---|
| 164 | | - |
|---|
| 165 | | -static void supermicro_new_unlock_watchdog(void) |
|---|
| 166 | | -{ |
|---|
| 167 | | - /* Write 0x87 to port 0x2e twice */ |
|---|
| 168 | | - outb(SM_WATCHPAGE, SM_REGINDEX); |
|---|
| 169 | | - outb(SM_WATCHPAGE, SM_REGINDEX); |
|---|
| 170 | | - /* Switch to watchdog control page */ |
|---|
| 171 | | - outb(SM_CTLPAGESW, SM_REGINDEX); |
|---|
| 172 | | - outb(SM_CTLPAGE, SM_DATAIO); |
|---|
| 173 | | -} |
|---|
| 174 | | - |
|---|
| 175 | | -static void supermicro_new_lock_watchdog(void) |
|---|
| 176 | | -{ |
|---|
| 177 | | - outb(SM_ENDWATCH, SM_REGINDEX); |
|---|
| 178 | | -} |
|---|
| 179 | | - |
|---|
| 180 | | -static void supermicro_new_pre_start(unsigned int heartbeat) |
|---|
| 181 | | -{ |
|---|
| 182 | | - unsigned int val; |
|---|
| 183 | | - |
|---|
| 184 | | - supermicro_new_unlock_watchdog(); |
|---|
| 185 | | - |
|---|
| 186 | | - /* Watchdog timer setting needs to be in seconds*/ |
|---|
| 187 | | - outb(SM_COUNTMODE, SM_REGINDEX); |
|---|
| 188 | | - val = inb(SM_DATAIO); |
|---|
| 189 | | - val &= 0xF7; |
|---|
| 190 | | - outb(val, SM_DATAIO); |
|---|
| 191 | | - |
|---|
| 192 | | - /* Write heartbeat interval to WDOG */ |
|---|
| 193 | | - outb(SM_WATCHTIMER, SM_REGINDEX); |
|---|
| 194 | | - outb((heartbeat & 255), SM_DATAIO); |
|---|
| 195 | | - |
|---|
| 196 | | - /* Make sure keyboard/mouse interrupts don't interfere */ |
|---|
| 197 | | - outb(SM_RESETCONTROL, SM_REGINDEX); |
|---|
| 198 | | - val = inb(SM_DATAIO); |
|---|
| 199 | | - val &= 0x3f; |
|---|
| 200 | | - outb(val, SM_DATAIO); |
|---|
| 201 | | - |
|---|
| 202 | | - /* enable watchdog by setting bit 0 of Watchdog Enable to 1 */ |
|---|
| 203 | | - outb(SM_WATCHENABLE, SM_REGINDEX); |
|---|
| 204 | | - val = inb(SM_DATAIO); |
|---|
| 205 | | - val |= 0x01; |
|---|
| 206 | | - outb(val, SM_DATAIO); |
|---|
| 207 | | - |
|---|
| 208 | | - supermicro_new_lock_watchdog(); |
|---|
| 209 | | -} |
|---|
| 210 | | - |
|---|
| 211 | | -static void supermicro_new_pre_stop(void) |
|---|
| 212 | | -{ |
|---|
| 213 | | - unsigned int val; |
|---|
| 214 | | - |
|---|
| 215 | | - supermicro_new_unlock_watchdog(); |
|---|
| 216 | | - |
|---|
| 217 | | - /* disable watchdog by setting bit 0 of Watchdog Enable to 0 */ |
|---|
| 218 | | - outb(SM_WATCHENABLE, SM_REGINDEX); |
|---|
| 219 | | - val = inb(SM_DATAIO); |
|---|
| 220 | | - val &= 0xFE; |
|---|
| 221 | | - outb(val, SM_DATAIO); |
|---|
| 222 | | - |
|---|
| 223 | | - supermicro_new_lock_watchdog(); |
|---|
| 224 | | -} |
|---|
| 225 | | - |
|---|
| 226 | | -static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat) |
|---|
| 227 | | -{ |
|---|
| 228 | | - supermicro_new_unlock_watchdog(); |
|---|
| 229 | | - |
|---|
| 230 | | - /* reset watchdog timeout to heartveat value */ |
|---|
| 231 | | - outb(SM_WATCHTIMER, SM_REGINDEX); |
|---|
| 232 | | - outb((heartbeat & 255), SM_DATAIO); |
|---|
| 233 | | - |
|---|
| 234 | | - supermicro_new_lock_watchdog(); |
|---|
| 235 | 95 | } |
|---|
| 236 | 96 | |
|---|
| 237 | 97 | /* |
|---|
| .. | .. |
|---|
| 294 | 154 | void iTCO_vendor_pre_start(struct resource *smires, |
|---|
| 295 | 155 | unsigned int heartbeat) |
|---|
| 296 | 156 | { |
|---|
| 297 | | - switch (vendorsupport) { |
|---|
| 157 | + switch (iTCO_vendorsupport) { |
|---|
| 298 | 158 | case SUPERMICRO_OLD_BOARD: |
|---|
| 299 | 159 | supermicro_old_pre_start(smires); |
|---|
| 300 | | - break; |
|---|
| 301 | | - case SUPERMICRO_NEW_BOARD: |
|---|
| 302 | | - supermicro_new_pre_start(heartbeat); |
|---|
| 303 | 160 | break; |
|---|
| 304 | 161 | case BROKEN_BIOS: |
|---|
| 305 | 162 | broken_bios_start(smires); |
|---|
| .. | .. |
|---|
| 310 | 167 | |
|---|
| 311 | 168 | void iTCO_vendor_pre_stop(struct resource *smires) |
|---|
| 312 | 169 | { |
|---|
| 313 | | - switch (vendorsupport) { |
|---|
| 170 | + switch (iTCO_vendorsupport) { |
|---|
| 314 | 171 | case SUPERMICRO_OLD_BOARD: |
|---|
| 315 | 172 | supermicro_old_pre_stop(smires); |
|---|
| 316 | | - break; |
|---|
| 317 | | - case SUPERMICRO_NEW_BOARD: |
|---|
| 318 | | - supermicro_new_pre_stop(); |
|---|
| 319 | 173 | break; |
|---|
| 320 | 174 | case BROKEN_BIOS: |
|---|
| 321 | 175 | broken_bios_stop(smires); |
|---|
| .. | .. |
|---|
| 324 | 178 | } |
|---|
| 325 | 179 | EXPORT_SYMBOL(iTCO_vendor_pre_stop); |
|---|
| 326 | 180 | |
|---|
| 327 | | -void iTCO_vendor_pre_keepalive(struct resource *smires, unsigned int heartbeat) |
|---|
| 328 | | -{ |
|---|
| 329 | | - if (vendorsupport == SUPERMICRO_NEW_BOARD) |
|---|
| 330 | | - supermicro_new_pre_set_heartbeat(heartbeat); |
|---|
| 331 | | -} |
|---|
| 332 | | -EXPORT_SYMBOL(iTCO_vendor_pre_keepalive); |
|---|
| 333 | | - |
|---|
| 334 | | -void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat) |
|---|
| 335 | | -{ |
|---|
| 336 | | - if (vendorsupport == SUPERMICRO_NEW_BOARD) |
|---|
| 337 | | - supermicro_new_pre_set_heartbeat(heartbeat); |
|---|
| 338 | | -} |
|---|
| 339 | | -EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat); |
|---|
| 340 | | - |
|---|
| 341 | 181 | int iTCO_vendor_check_noreboot_on(void) |
|---|
| 342 | 182 | { |
|---|
| 343 | | - switch (vendorsupport) { |
|---|
| 183 | + switch (iTCO_vendorsupport) { |
|---|
| 344 | 184 | case SUPERMICRO_OLD_BOARD: |
|---|
| 345 | 185 | return 0; |
|---|
| 346 | 186 | default: |
|---|
| .. | .. |
|---|
| 351 | 191 | |
|---|
| 352 | 192 | static int __init iTCO_vendor_init_module(void) |
|---|
| 353 | 193 | { |
|---|
| 354 | | - pr_info("vendor-support=%d\n", vendorsupport); |
|---|
| 194 | + if (iTCO_vendorsupport == SUPERMICRO_NEW_BOARD) { |
|---|
| 195 | + pr_warn("Option vendorsupport=%d is no longer supported, " |
|---|
| 196 | + "please use the w83627hf_wdt driver instead\n", |
|---|
| 197 | + SUPERMICRO_NEW_BOARD); |
|---|
| 198 | + return -EINVAL; |
|---|
| 199 | + } |
|---|
| 200 | + pr_info("vendor-support=%d\n", iTCO_vendorsupport); |
|---|
| 355 | 201 | return 0; |
|---|
| 356 | 202 | } |
|---|
| 357 | 203 | |
|---|
| .. | .. |
|---|
| 368 | 214 | MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support"); |
|---|
| 369 | 215 | MODULE_VERSION(DRV_VERSION); |
|---|
| 370 | 216 | MODULE_LICENSE("GPL"); |
|---|
| 371 | | - |
|---|