^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * intel TCO Watchdog Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (c) Copyright 2006-2011 Wim Van Sebroeck <wim@iguana.be>.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * provide warranty for any of this software. This material is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * provided "AS-IS" and at no charge.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * The TCO watchdog is implemented in the following I/O controller hubs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * (See the intel documentation on http://developer.intel.com.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * document number 290687-002, 298242-027: 82801BA (ICH2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * document number 290733-003, 290739-013: 82801CA (ICH3-S)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * document number 290716-001, 290718-007: 82801CAM (ICH3-M)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * document number 290744-001, 290745-025: 82801DB (ICH4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * document number 252337-001, 252663-008: 82801DBM (ICH4-M)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * document number 273599-001, 273645-002: 82801E (C-ICH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * document number 300641-004, 300884-013: 6300ESB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * document number 301473-002, 301474-026: 82801F (ICH6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * document number 313082-001, 313075-006: 631xESB, 632xESB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * document number 307013-003, 307014-024: 82801G (ICH7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * document number 322896-001, 322897-001: NM10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * document number 313056-003, 313057-017: 82801H (ICH8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * document number 316972-004, 316973-012: 82801I (ICH9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * document number 319973-002, 319974-002: 82801J (ICH10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * document number 320066-003, 320257-008: EP80597 (IICH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * document number 324645-001, 324646-001: Cougar Point (CPT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * document number TBD : Patsburg (PBG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * document number TBD : DH89xxCC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * document number TBD : Panther Point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * document number TBD : Lynx Point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * document number TBD : Lynx Point-LP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * Includes, defines, variables, module parameters, ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Module and version information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define DRV_NAME "iTCO_wdt"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define DRV_VERSION "1.11"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* Includes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #include <linux/acpi.h> /* For ACPI support */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #include <linux/bits.h> /* For BIT() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #include <linux/module.h> /* For module specific items */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #include <linux/moduleparam.h> /* For new moduleparam's */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #include <linux/types.h> /* For standard types (like size_t) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #include <linux/errno.h> /* For the -ENODEV/... values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #include <linux/kernel.h> /* For printk/panic/... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #include <linux/watchdog.h> /* For the watchdog specific items */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #include <linux/init.h> /* For __init/__exit/... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #include <linux/fs.h> /* For file operations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #include <linux/platform_device.h> /* For platform_driver framework */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #include <linux/pci.h> /* For pci functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #include <linux/ioport.h> /* For io-port access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #include <linux/uaccess.h> /* For copy_to_user/put_user/... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #include <linux/io.h> /* For inb/outb/... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #include <linux/platform_data/itco_wdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #include <linux/mfd/intel_pmc_bxt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #include "iTCO_vendor.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Address definitions for the TCO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* TCO base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define TCOBASE(p) ((p)->tco_res->start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* SMI Control and Enable Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define SMI_EN(p) ((p)->smi_res->start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define TCO_RLD(p) (TCOBASE(p) + 0x00) /* TCO Timer Reload/Curr. Value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define TCOv1_TMR(p) (TCOBASE(p) + 0x01) /* TCOv1 Timer Initial Value*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define TCO_DAT_IN(p) (TCOBASE(p) + 0x02) /* TCO Data In Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define TCO_DAT_OUT(p) (TCOBASE(p) + 0x03) /* TCO Data Out Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define TCO1_STS(p) (TCOBASE(p) + 0x04) /* TCO1 Status Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define TCO2_STS(p) (TCOBASE(p) + 0x06) /* TCO2 Status Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define TCO1_CNT(p) (TCOBASE(p) + 0x08) /* TCO1 Control Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define TCO2_CNT(p) (TCOBASE(p) + 0x0a) /* TCO2 Control Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define TCOv2_TMR(p) (TCOBASE(p) + 0x12) /* TCOv2 Timer Initial Value*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* internal variables */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct iTCO_wdt_private {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct watchdog_device wddev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /* TCO version/generation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned int iTCO_version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct resource *tco_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct resource *smi_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * or memory-mapped PMC register bit 4 (TCO version 3).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct resource *gcs_pmc_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) unsigned long __iomem *gcs_pmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* the lock for io operations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) spinlock_t io_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* the PCI-device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct pci_dev *pci_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* whether or not the watchdog has been suspended */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) bool suspended;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* no reboot API private data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) void *no_reboot_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /* no reboot update function pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) int (*update_no_reboot_bit)(void *p, bool set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* module parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #define WATCHDOG_TIMEOUT 30 /* 30 sec default heartbeat */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static int heartbeat = WATCHDOG_TIMEOUT; /* in seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) module_param(heartbeat, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) "5..76 (TCO v1) or 3..614 (TCO v2), default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static bool nowayout = WATCHDOG_NOWAYOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) module_param(nowayout, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) MODULE_PARM_DESC(nowayout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) "Watchdog cannot be stopped once started (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static int turn_SMI_watchdog_clear_off = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) module_param(turn_SMI_watchdog_clear_off, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) MODULE_PARM_DESC(turn_SMI_watchdog_clear_off,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) "Turn off SMI clearing watchdog (depends on TCO-version)(default=1)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * Some TCO specific functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * The iTCO v1 and v2's internal timer is stored as ticks which decrement
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * every 0.6 seconds. v3's internal timer is stored as seconds (some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * datasheets incorrectly state 0.6 seconds).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static inline unsigned int seconds_to_ticks(struct iTCO_wdt_private *p,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int secs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return p->iTCO_version == 3 ? secs : (secs * 10) / 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static inline unsigned int ticks_to_seconds(struct iTCO_wdt_private *p,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) int ticks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return p->iTCO_version == 3 ? ticks : (ticks * 6) / 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static inline u32 no_reboot_bit(struct iTCO_wdt_private *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) u32 enable_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) switch (p->iTCO_version) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) enable_bit = 0x00000010;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) enable_bit = 0x00000020;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) enable_bit = 0x00000002;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return enable_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static int update_no_reboot_bit_def(void *priv, bool set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static int update_no_reboot_bit_pci(void *priv, bool set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct iTCO_wdt_private *p = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) u32 val32 = 0, newval32 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) pci_read_config_dword(p->pci_dev, 0xd4, &val32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) val32 |= no_reboot_bit(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) val32 &= ~no_reboot_bit(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) pci_write_config_dword(p->pci_dev, 0xd4, val32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) pci_read_config_dword(p->pci_dev, 0xd4, &newval32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /* make sure the update is successful */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (val32 != newval32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static int update_no_reboot_bit_mem(void *priv, bool set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct iTCO_wdt_private *p = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) u32 val32 = 0, newval32 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) val32 = readl(p->gcs_pmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) val32 |= no_reboot_bit(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) val32 &= ~no_reboot_bit(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) writel(val32, p->gcs_pmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) newval32 = readl(p->gcs_pmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* make sure the update is successful */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (val32 != newval32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static int update_no_reboot_bit_cnt(void *priv, bool set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) struct iTCO_wdt_private *p = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) u16 val, newval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) val = inw(TCO1_CNT(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) val |= BIT(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) val &= ~BIT(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) outw(val, TCO1_CNT(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) newval = inw(TCO1_CNT(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) /* make sure the update is successful */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return val != newval ? -EIO : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static int update_no_reboot_bit_pmc(void *priv, bool set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) struct intel_pmc_dev *pmc = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) u32 bits = PMC_CFG_NO_REBOOT_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) u32 value = set ? bits : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return intel_pmc_gcr_update(pmc, PMC_GCR_PMC_CFG_REG, bits, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) static void iTCO_wdt_no_reboot_bit_setup(struct iTCO_wdt_private *p,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct itco_wdt_platform_data *pdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (pdata->no_reboot_use_pmc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) struct intel_pmc_dev *pmc = dev_get_drvdata(pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) p->update_no_reboot_bit = update_no_reboot_bit_pmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) p->no_reboot_priv = pmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (p->iTCO_version >= 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) p->update_no_reboot_bit = update_no_reboot_bit_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) else if (p->iTCO_version >= 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) p->update_no_reboot_bit = update_no_reboot_bit_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) else if (p->iTCO_version == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) p->update_no_reboot_bit = update_no_reboot_bit_pci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) p->update_no_reboot_bit = update_no_reboot_bit_def;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) p->no_reboot_priv = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int iTCO_wdt_start(struct watchdog_device *wd_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) spin_lock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) iTCO_vendor_pre_start(p->smi_res, wd_dev->timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /* disable chipset's NO_REBOOT bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (p->update_no_reboot_bit(p->no_reboot_priv, false)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) spin_unlock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) /* Force the timer to its reload value by writing to the TCO_RLD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (p->iTCO_version >= 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) outw(0x01, TCO_RLD(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) else if (p->iTCO_version == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) outb(0x01, TCO_RLD(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) val = inw(TCO1_CNT(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) val &= 0xf7ff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) outw(val, TCO1_CNT(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) val = inw(TCO1_CNT(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) spin_unlock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (val & 0x0800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static int iTCO_wdt_stop(struct watchdog_device *wd_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) spin_lock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) iTCO_vendor_pre_stop(p->smi_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) val = inw(TCO1_CNT(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) val |= 0x0800;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) outw(val, TCO1_CNT(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) val = inw(TCO1_CNT(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) p->update_no_reboot_bit(p->no_reboot_priv, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) spin_unlock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if ((val & 0x0800) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) spin_lock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) /* Reload the timer by writing to the TCO Timer Counter register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (p->iTCO_version >= 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) outw(0x01, TCO_RLD(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) } else if (p->iTCO_version == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) /* Reset the timeout status bit so that the timer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * needs to count down twice again before rebooting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) outw(0x0008, TCO1_STS(p)); /* write 1 to clear bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) outb(0x01, TCO_RLD(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) spin_unlock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) unsigned int val16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) unsigned char val8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) unsigned int tmrval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) tmrval = seconds_to_ticks(p, t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) /* For TCO v1 the timer counts down twice before rebooting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (p->iTCO_version == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) tmrval /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /* from the specs: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) /* "Values of 0h-3h are ignored and should not be attempted" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (tmrval < 0x04)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if ((p->iTCO_version >= 2 && tmrval > 0x3ff) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) (p->iTCO_version == 1 && tmrval > 0x03f))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) /* Write new heartbeat to watchdog */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (p->iTCO_version >= 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) spin_lock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) val16 = inw(TCOv2_TMR(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) val16 &= 0xfc00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) val16 |= tmrval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) outw(val16, TCOv2_TMR(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) val16 = inw(TCOv2_TMR(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) spin_unlock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if ((val16 & 0x3ff) != tmrval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) } else if (p->iTCO_version == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) spin_lock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) val8 = inb(TCOv1_TMR(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) val8 &= 0xc0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) val8 |= (tmrval & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) outb(val8, TCOv1_TMR(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) val8 = inb(TCOv1_TMR(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) spin_unlock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) if ((val8 & 0x3f) != tmrval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) wd_dev->timeout = t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) unsigned int val16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) unsigned char val8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) unsigned int time_left = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) /* read the TCO Timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (p->iTCO_version >= 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) spin_lock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) val16 = inw(TCO_RLD(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) val16 &= 0x3ff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) spin_unlock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) time_left = ticks_to_seconds(p, val16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) } else if (p->iTCO_version == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) spin_lock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) val8 = inb(TCO_RLD(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) val8 &= 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (!(inw(TCO1_STS(p)) & 0x0008))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) val8 += (inb(TCOv1_TMR(p)) & 0x3f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) spin_unlock(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) time_left = ticks_to_seconds(p, val8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return time_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) * Kernel Interfaces
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static const struct watchdog_info ident = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) .options = WDIOF_SETTIMEOUT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) WDIOF_KEEPALIVEPING |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) WDIOF_MAGICCLOSE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) .firmware_version = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) .identity = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static const struct watchdog_ops iTCO_wdt_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) .start = iTCO_wdt_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) .stop = iTCO_wdt_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) .ping = iTCO_wdt_ping,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) .set_timeout = iTCO_wdt_set_timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) .get_timeleft = iTCO_wdt_get_timeleft,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * Init & exit routines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static int iTCO_wdt_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) struct itco_wdt_platform_data *pdata = dev_get_platdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) struct iTCO_wdt_private *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) unsigned long val32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (!pdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (!p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) spin_lock_init(&p->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) p->tco_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_TCO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (!p->tco_res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) p->iTCO_version = pdata->version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) p->pci_dev = to_pci_dev(dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) p->smi_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_SMI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (p->smi_res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) /* The TCO logic uses the TCO_EN bit in the SMI_EN register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if (!devm_request_region(dev, p->smi_res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) resource_size(p->smi_res),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) pdev->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) pr_err("I/O address 0x%04llx already in use, device disabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) (u64)SMI_EN(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) } else if (iTCO_vendorsupport ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) turn_SMI_watchdog_clear_off >= p->iTCO_version) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) pr_err("SMI I/O resource is missing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) iTCO_wdt_no_reboot_bit_setup(p, pdev, pdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * Get the Memory-Mapped GCS or PMC register, we need it for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) * NO_REBOOT flag (TCO v2 and v3).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) if (p->iTCO_version >= 2 && p->iTCO_version < 6 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) !pdata->no_reboot_use_pmc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) p->gcs_pmc_res = platform_get_resource(pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) IORESOURCE_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) ICH_RES_MEM_GCS_PMC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) p->gcs_pmc = devm_ioremap_resource(dev, p->gcs_pmc_res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) if (IS_ERR(p->gcs_pmc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) return PTR_ERR(p->gcs_pmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /* Check chipset's NO_REBOOT bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (p->update_no_reboot_bit(p->no_reboot_priv, false) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) iTCO_vendor_check_noreboot_on()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return -ENODEV; /* Cannot reset NO_REBOOT bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) p->update_no_reboot_bit(p->no_reboot_priv, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) if (turn_SMI_watchdog_clear_off >= p->iTCO_version) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) * Bit 13: TCO_EN -> 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) * Disables TCO logic generating an SMI#
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) val32 = inl(SMI_EN(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) outl(val32, SMI_EN(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (!devm_request_region(dev, p->tco_res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) resource_size(p->tco_res),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) pdev->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) pr_err("I/O address 0x%04llx already in use, device disabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) (u64)TCOBASE(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) pdata->name, pdata->version, (u64)TCOBASE(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) /* Clear out the (probably old) status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) switch (p->iTCO_version) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) outl(0x20008, TCO1_STS(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) outw(0x0004, TCO2_STS(p)); /* Clear BOOT_STS bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) p->wddev.info = &ident,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) p->wddev.ops = &iTCO_wdt_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) p->wddev.bootstatus = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) p->wddev.timeout = WATCHDOG_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) watchdog_set_nowayout(&p->wddev, nowayout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) p->wddev.parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) watchdog_set_drvdata(&p->wddev, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) platform_set_drvdata(pdev, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) /* Make sure the watchdog is not running */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) iTCO_wdt_stop(&p->wddev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) /* Check that the heartbeat value is within it's range;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if not reset to the default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (iTCO_wdt_set_timeout(&p->wddev, heartbeat)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) iTCO_wdt_set_timeout(&p->wddev, WATCHDOG_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) pr_info("timeout value out of range, using %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) WATCHDOG_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) watchdog_stop_on_reboot(&p->wddev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) watchdog_stop_on_unregister(&p->wddev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) ret = devm_watchdog_register_device(dev, &p->wddev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (ret != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) pr_err("cannot register watchdog device (err=%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) heartbeat, nowayout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) * the watchdog cannot be pinged while in that state. In ACPI sleep states the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) * watchdog is stopped by the platform firmware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) #ifdef CONFIG_ACPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) static inline bool need_suspend(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) return acpi_target_system_state() == ACPI_STATE_S0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) static inline bool need_suspend(void) { return true; }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) static int iTCO_wdt_suspend_noirq(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) struct iTCO_wdt_private *p = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) p->suspended = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) if (watchdog_active(&p->wddev) && need_suspend()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) ret = iTCO_wdt_stop(&p->wddev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) p->suspended = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) static int iTCO_wdt_resume_noirq(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) struct iTCO_wdt_private *p = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (p->suspended)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) iTCO_wdt_start(&p->wddev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) static const struct dev_pm_ops iTCO_wdt_pm = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) .suspend_noirq = iTCO_wdt_suspend_noirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) .resume_noirq = iTCO_wdt_resume_noirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) #define ITCO_WDT_PM_OPS (&iTCO_wdt_pm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) #define ITCO_WDT_PM_OPS NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) #endif /* CONFIG_PM_SLEEP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) static struct platform_driver iTCO_wdt_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) .probe = iTCO_wdt_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) .pm = ITCO_WDT_PM_OPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) static int __init iTCO_wdt_init_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return platform_driver_register(&iTCO_wdt_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) static void __exit iTCO_wdt_cleanup_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) platform_driver_unregister(&iTCO_wdt_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) pr_info("Watchdog Module Unloaded\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) module_init(iTCO_wdt_init_module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) module_exit(iTCO_wdt_cleanup_module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) MODULE_VERSION(DRV_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) MODULE_ALIAS("platform:" DRV_NAME);