linux/drivers/watchdog/iTCO_wdt.c
<<
>>
Prefs
   1/*
   2 *      intel TCO Watchdog Driver
   3 *
   4 *      (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 *
  11 *      Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
  12 *      provide warranty for any of this software. This material is
  13 *      provided "AS-IS" and at no charge.
  14 *
  15 *      The TCO watchdog is implemented in the following I/O controller hubs:
  16 *      (See the intel documentation on http://developer.intel.com.)
  17 *      document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO)
  18 *      document number 290687-002, 298242-027: 82801BA (ICH2)
  19 *      document number 290733-003, 290739-013: 82801CA (ICH3-S)
  20 *      document number 290716-001, 290718-007: 82801CAM (ICH3-M)
  21 *      document number 290744-001, 290745-025: 82801DB (ICH4)
  22 *      document number 252337-001, 252663-008: 82801DBM (ICH4-M)
  23 *      document number 273599-001, 273645-002: 82801E (C-ICH)
  24 *      document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R)
  25 *      document number 300641-004, 300884-013: 6300ESB
  26 *      document number 301473-002, 301474-026: 82801F (ICH6)
  27 *      document number 313082-001, 313075-006: 631xESB, 632xESB
  28 *      document number 307013-003, 307014-024: 82801G (ICH7)
  29 *      document number 313056-003, 313057-017: 82801H (ICH8)
  30 *      document number 316972-004, 316973-012: 82801I (ICH9)
  31 *      document number 319973-002, 319974-002: 82801J (ICH10)
  32 *      document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
  33 *      document number 320066-003, 320257-008: EP80597 (IICH)
  34 *      document number TBD                   : Cougar Point (CPT)
  35 *      document number TBD                   : Patsburg (PBG)
  36 */
  37
  38/*
  39 *      Includes, defines, variables, module parameters, ...
  40 */
  41
  42/* Module and version information */
  43#define DRV_NAME        "iTCO_wdt"
  44#define DRV_VERSION     "1.06"
  45#define PFX             DRV_NAME ": "
  46
  47/* Includes */
  48#include <linux/module.h>               /* For module specific items */
  49#include <linux/moduleparam.h>          /* For new moduleparam's */
  50#include <linux/types.h>                /* For standard types (like size_t) */
  51#include <linux/errno.h>                /* For the -ENODEV/... values */
  52#include <linux/kernel.h>               /* For printk/panic/... */
  53#include <linux/miscdevice.h>           /* For MODULE_ALIAS_MISCDEV
  54                                                        (WATCHDOG_MINOR) */
  55#include <linux/watchdog.h>             /* For the watchdog specific items */
  56#include <linux/init.h>                 /* For __init/__exit/... */
  57#include <linux/fs.h>                   /* For file operations */
  58#include <linux/platform_device.h>      /* For platform_driver framework */
  59#include <linux/pci.h>                  /* For pci functions */
  60#include <linux/ioport.h>               /* For io-port access */
  61#include <linux/spinlock.h>             /* For spin_lock/spin_unlock/... */
  62#include <linux/uaccess.h>              /* For copy_to_user/put_user/... */
  63#include <linux/io.h>                   /* For inb/outb/... */
  64
  65#include "iTCO_vendor.h"
  66
  67/* TCO related info */
  68enum iTCO_chipsets {
  69        TCO_ICH = 0,    /* ICH */
  70        TCO_ICH0,       /* ICH0 */
  71        TCO_ICH2,       /* ICH2 */
  72        TCO_ICH2M,      /* ICH2-M */
  73        TCO_ICH3,       /* ICH3-S */
  74        TCO_ICH3M,      /* ICH3-M */
  75        TCO_ICH4,       /* ICH4 */
  76        TCO_ICH4M,      /* ICH4-M */
  77        TCO_CICH,       /* C-ICH */
  78        TCO_ICH5,       /* ICH5 & ICH5R */
  79        TCO_6300ESB,    /* 6300ESB */
  80        TCO_ICH6,       /* ICH6 & ICH6R */
  81        TCO_ICH6M,      /* ICH6-M */
  82        TCO_ICH6W,      /* ICH6W & ICH6RW */
  83        TCO_631XESB,    /* 631xESB/632xESB */
  84        TCO_ICH7,       /* ICH7 & ICH7R */
  85        TCO_ICH7DH,     /* ICH7DH */
  86        TCO_ICH7M,      /* ICH7-M & ICH7-U */
  87        TCO_ICH7MDH,    /* ICH7-M DH */
  88        TCO_ICH8,       /* ICH8 & ICH8R */
  89        TCO_ICH8DH,     /* ICH8DH */
  90        TCO_ICH8DO,     /* ICH8DO */
  91        TCO_ICH8M,      /* ICH8M */
  92        TCO_ICH8ME,     /* ICH8M-E */
  93        TCO_ICH9,       /* ICH9 */
  94        TCO_ICH9R,      /* ICH9R */
  95        TCO_ICH9DH,     /* ICH9DH */
  96        TCO_ICH9DO,     /* ICH9DO */
  97        TCO_ICH9M,      /* ICH9M */
  98        TCO_ICH9ME,     /* ICH9M-E */
  99        TCO_ICH10,      /* ICH10 */
 100        TCO_ICH10R,     /* ICH10R */
 101        TCO_ICH10D,     /* ICH10D */
 102        TCO_ICH10DO,    /* ICH10DO */
 103        TCO_PCH,        /* PCH Desktop Full Featured */
 104        TCO_PCHM,       /* PCH Mobile Full Featured */
 105        TCO_P55,        /* P55 */
 106        TCO_PM55,       /* PM55 */
 107        TCO_H55,        /* H55 */
 108        TCO_QM57,       /* QM57 */
 109        TCO_H57,        /* H57 */
 110        TCO_HM55,       /* HM55 */
 111        TCO_Q57,        /* Q57 */
 112        TCO_HM57,       /* HM57 */
 113        TCO_PCHMSFF,    /* PCH Mobile SFF Full Featured */
 114        TCO_QS57,       /* QS57 */
 115        TCO_3400,       /* 3400 */
 116        TCO_3420,       /* 3420 */
 117        TCO_3450,       /* 3450 */
 118        TCO_EP80579,    /* EP80579 */
 119        TCO_CPT1,       /* Cougar Point */
 120        TCO_CPT2,       /* Cougar Point Desktop */
 121        TCO_CPT3,       /* Cougar Point Mobile */
 122        TCO_CPT4,       /* Cougar Point */
 123        TCO_CPT5,       /* Cougar Point */
 124        TCO_CPT6,       /* Cougar Point */
 125        TCO_CPT7,       /* Cougar Point */
 126        TCO_CPT8,       /* Cougar Point */
 127        TCO_CPT9,       /* Cougar Point */
 128        TCO_CPT10,      /* Cougar Point */
 129        TCO_CPT11,      /* Cougar Point */
 130        TCO_CPT12,      /* Cougar Point */
 131        TCO_CPT13,      /* Cougar Point */
 132        TCO_CPT14,      /* Cougar Point */
 133        TCO_CPT15,      /* Cougar Point */
 134        TCO_CPT16,      /* Cougar Point */
 135        TCO_CPT17,      /* Cougar Point */
 136        TCO_CPT18,      /* Cougar Point */
 137        TCO_CPT19,      /* Cougar Point */
 138        TCO_CPT20,      /* Cougar Point */
 139        TCO_CPT21,      /* Cougar Point */
 140        TCO_CPT22,      /* Cougar Point */
 141        TCO_CPT23,      /* Cougar Point */
 142        TCO_CPT24,      /* Cougar Point */
 143        TCO_CPT25,      /* Cougar Point */
 144        TCO_CPT26,      /* Cougar Point */
 145        TCO_CPT27,      /* Cougar Point */
 146        TCO_CPT28,      /* Cougar Point */
 147        TCO_CPT29,      /* Cougar Point */
 148        TCO_CPT30,      /* Cougar Point */
 149        TCO_CPT31,      /* Cougar Point */
 150        TCO_PBG1,       /* Patsburg */
 151        TCO_PBG2,       /* Patsburg */
 152};
 153
 154static struct {
 155        char *name;
 156        unsigned int iTCO_version;
 157} iTCO_chipset_info[] __devinitdata = {
 158        {"ICH", 1},
 159        {"ICH0", 1},
 160        {"ICH2", 1},
 161        {"ICH2-M", 1},
 162        {"ICH3-S", 1},
 163        {"ICH3-M", 1},
 164        {"ICH4", 1},
 165        {"ICH4-M", 1},
 166        {"C-ICH", 1},
 167        {"ICH5 or ICH5R", 1},
 168        {"6300ESB", 1},
 169        {"ICH6 or ICH6R", 2},
 170        {"ICH6-M", 2},
 171        {"ICH6W or ICH6RW", 2},
 172        {"631xESB/632xESB", 2},
 173        {"ICH7 or ICH7R", 2},
 174        {"ICH7DH", 2},
 175        {"ICH7-M or ICH7-U", 2},
 176        {"ICH7-M DH", 2},
 177        {"ICH8 or ICH8R", 2},
 178        {"ICH8DH", 2},
 179        {"ICH8DO", 2},
 180        {"ICH8M", 2},
 181        {"ICH8M-E", 2},
 182        {"ICH9", 2},
 183        {"ICH9R", 2},
 184        {"ICH9DH", 2},
 185        {"ICH9DO", 2},
 186        {"ICH9M", 2},
 187        {"ICH9M-E", 2},
 188        {"ICH10", 2},
 189        {"ICH10R", 2},
 190        {"ICH10D", 2},
 191        {"ICH10DO", 2},
 192        {"PCH Desktop Full Featured", 2},
 193        {"PCH Mobile Full Featured", 2},
 194        {"P55", 2},
 195        {"PM55", 2},
 196        {"H55", 2},
 197        {"QM57", 2},
 198        {"H57", 2},
 199        {"HM55", 2},
 200        {"Q57", 2},
 201        {"HM57", 2},
 202        {"PCH Mobile SFF Full Featured", 2},
 203        {"QS57", 2},
 204        {"3400", 2},
 205        {"3420", 2},
 206        {"3450", 2},
 207        {"EP80579", 2},
 208        {"Cougar Point", 2},
 209        {"Cougar Point", 2},
 210        {"Cougar Point", 2},
 211        {"Cougar Point", 2},
 212        {"Cougar Point", 2},
 213        {"Cougar Point", 2},
 214        {"Cougar Point", 2},
 215        {"Cougar Point", 2},
 216        {"Cougar Point", 2},
 217        {"Cougar Point", 2},
 218        {"Cougar Point", 2},
 219        {"Cougar Point", 2},
 220        {"Cougar Point", 2},
 221        {"Cougar Point", 2},
 222        {"Cougar Point", 2},
 223        {"Cougar Point", 2},
 224        {"Cougar Point", 2},
 225        {"Cougar Point", 2},
 226        {"Cougar Point", 2},
 227        {"Cougar Point", 2},
 228        {"Cougar Point", 2},
 229        {"Cougar Point", 2},
 230        {"Cougar Point", 2},
 231        {"Cougar Point", 2},
 232        {"Cougar Point", 2},
 233        {"Cougar Point", 2},
 234        {"Cougar Point", 2},
 235        {"Cougar Point", 2},
 236        {"Cougar Point", 2},
 237        {"Cougar Point", 2},
 238        {"Cougar Point", 2},
 239        {"Patsburg", 2},
 240        {"Patsburg", 2},
 241        {NULL, 0}
 242};
 243
 244#define ITCO_PCI_DEVICE(dev, data)      \
 245        .vendor = PCI_VENDOR_ID_INTEL,  \
 246        .device = dev,                  \
 247        .subvendor = PCI_ANY_ID,        \
 248        .subdevice = PCI_ANY_ID,        \
 249        .class = 0,                     \
 250        .class_mask = 0,                \
 251        .driver_data = data
 252
 253/*
 254 * This data only exists for exporting the supported PCI ids
 255 * via MODULE_DEVICE_TABLE.  We do not actually register a
 256 * pci_driver, because the I/O Controller Hub has also other
 257 * functions that probably will be registered by other drivers.
 258 */
 259static struct pci_device_id iTCO_wdt_pci_tbl[] = {
 260        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0,        TCO_ICH)},
 261        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0,        TCO_ICH0)},
 262        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0,        TCO_ICH2)},
 263        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10,       TCO_ICH2M)},
 264        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0,        TCO_ICH3)},
 265        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12,       TCO_ICH3M)},
 266        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0,        TCO_ICH4)},
 267        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12,       TCO_ICH4M)},
 268        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0,         TCO_CICH)},
 269        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0,        TCO_ICH5)},
 270        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1,            TCO_6300ESB)},
 271        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0,           TCO_ICH6)},
 272        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1,           TCO_ICH6M)},
 273        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2,           TCO_ICH6W)},
 274        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0,           TCO_631XESB)},
 275        { ITCO_PCI_DEVICE(0x2671,                               TCO_631XESB)},
 276        { ITCO_PCI_DEVICE(0x2672,                               TCO_631XESB)},
 277        { ITCO_PCI_DEVICE(0x2673,                               TCO_631XESB)},
 278        { ITCO_PCI_DEVICE(0x2674,                               TCO_631XESB)},
 279        { ITCO_PCI_DEVICE(0x2675,                               TCO_631XESB)},
 280        { ITCO_PCI_DEVICE(0x2676,                               TCO_631XESB)},
 281        { ITCO_PCI_DEVICE(0x2677,                               TCO_631XESB)},
 282        { ITCO_PCI_DEVICE(0x2678,                               TCO_631XESB)},
 283        { ITCO_PCI_DEVICE(0x2679,                               TCO_631XESB)},
 284        { ITCO_PCI_DEVICE(0x267a,                               TCO_631XESB)},
 285        { ITCO_PCI_DEVICE(0x267b,                               TCO_631XESB)},
 286        { ITCO_PCI_DEVICE(0x267c,                               TCO_631XESB)},
 287        { ITCO_PCI_DEVICE(0x267d,                               TCO_631XESB)},
 288        { ITCO_PCI_DEVICE(0x267e,                               TCO_631XESB)},
 289        { ITCO_PCI_DEVICE(0x267f,                               TCO_631XESB)},
 290        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0,           TCO_ICH7)},
 291        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30,          TCO_ICH7DH)},
 292        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1,           TCO_ICH7M)},
 293        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31,          TCO_ICH7MDH)},
 294        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0,           TCO_ICH8)},
 295        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2,           TCO_ICH8DH)},
 296        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3,           TCO_ICH8DO)},
 297        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4,           TCO_ICH8M)},
 298        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1,           TCO_ICH8ME)},
 299        { ITCO_PCI_DEVICE(0x2918,                               TCO_ICH9)},
 300        { ITCO_PCI_DEVICE(0x2916,                               TCO_ICH9R)},
 301        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2,           TCO_ICH9DH)},
 302        { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4,           TCO_ICH9DO)},
 303        { ITCO_PCI_DEVICE(0x2919,                               TCO_ICH9M)},
 304        { ITCO_PCI_DEVICE(0x2917,                               TCO_ICH9ME)},
 305        { ITCO_PCI_DEVICE(0x3a18,                               TCO_ICH10)},
 306        { ITCO_PCI_DEVICE(0x3a16,                               TCO_ICH10R)},
 307        { ITCO_PCI_DEVICE(0x3a1a,                               TCO_ICH10D)},
 308        { ITCO_PCI_DEVICE(0x3a14,                               TCO_ICH10DO)},
 309        { ITCO_PCI_DEVICE(0x3b00,                               TCO_PCH)},
 310        { ITCO_PCI_DEVICE(0x3b01,                               TCO_PCHM)},
 311        { ITCO_PCI_DEVICE(0x3b02,                               TCO_P55)},
 312        { ITCO_PCI_DEVICE(0x3b03,                               TCO_PM55)},
 313        { ITCO_PCI_DEVICE(0x3b06,                               TCO_H55)},
 314        { ITCO_PCI_DEVICE(0x3b07,                               TCO_QM57)},
 315        { ITCO_PCI_DEVICE(0x3b08,                               TCO_H57)},
 316        { ITCO_PCI_DEVICE(0x3b09,                               TCO_HM55)},
 317        { ITCO_PCI_DEVICE(0x3b0a,                               TCO_Q57)},
 318        { ITCO_PCI_DEVICE(0x3b0b,                               TCO_HM57)},
 319        { ITCO_PCI_DEVICE(0x3b0d,                               TCO_PCHMSFF)},
 320        { ITCO_PCI_DEVICE(0x3b0f,                               TCO_QS57)},
 321        { ITCO_PCI_DEVICE(0x3b12,                               TCO_3400)},
 322        { ITCO_PCI_DEVICE(0x3b14,                               TCO_3420)},
 323        { ITCO_PCI_DEVICE(0x3b16,                               TCO_3450)},
 324        { ITCO_PCI_DEVICE(0x5031,                               TCO_EP80579)},
 325        { ITCO_PCI_DEVICE(0x1c41,                               TCO_CPT1)},
 326        { ITCO_PCI_DEVICE(0x1c42,                               TCO_CPT2)},
 327        { ITCO_PCI_DEVICE(0x1c43,                               TCO_CPT3)},
 328        { ITCO_PCI_DEVICE(0x1c44,                               TCO_CPT4)},
 329        { ITCO_PCI_DEVICE(0x1c45,                               TCO_CPT5)},
 330        { ITCO_PCI_DEVICE(0x1c46,                               TCO_CPT6)},
 331        { ITCO_PCI_DEVICE(0x1c47,                               TCO_CPT7)},
 332        { ITCO_PCI_DEVICE(0x1c48,                               TCO_CPT8)},
 333        { ITCO_PCI_DEVICE(0x1c49,                               TCO_CPT9)},
 334        { ITCO_PCI_DEVICE(0x1c4a,                               TCO_CPT10)},
 335        { ITCO_PCI_DEVICE(0x1c4b,                               TCO_CPT11)},
 336        { ITCO_PCI_DEVICE(0x1c4c,                               TCO_CPT12)},
 337        { ITCO_PCI_DEVICE(0x1c4d,                               TCO_CPT13)},
 338        { ITCO_PCI_DEVICE(0x1c4e,                               TCO_CPT14)},
 339        { ITCO_PCI_DEVICE(0x1c4f,                               TCO_CPT15)},
 340        { ITCO_PCI_DEVICE(0x1c50,                               TCO_CPT16)},
 341        { ITCO_PCI_DEVICE(0x1c51,                               TCO_CPT17)},
 342        { ITCO_PCI_DEVICE(0x1c52,                               TCO_CPT18)},
 343        { ITCO_PCI_DEVICE(0x1c53,                               TCO_CPT19)},
 344        { ITCO_PCI_DEVICE(0x1c54,                               TCO_CPT20)},
 345        { ITCO_PCI_DEVICE(0x1c55,                               TCO_CPT21)},
 346        { ITCO_PCI_DEVICE(0x1c56,                               TCO_CPT22)},
 347        { ITCO_PCI_DEVICE(0x1c57,                               TCO_CPT23)},
 348        { ITCO_PCI_DEVICE(0x1c58,                               TCO_CPT24)},
 349        { ITCO_PCI_DEVICE(0x1c59,                               TCO_CPT25)},
 350        { ITCO_PCI_DEVICE(0x1c5a,                               TCO_CPT26)},
 351        { ITCO_PCI_DEVICE(0x1c5b,                               TCO_CPT27)},
 352        { ITCO_PCI_DEVICE(0x1c5c,                               TCO_CPT28)},
 353        { ITCO_PCI_DEVICE(0x1c5d,                               TCO_CPT29)},
 354        { ITCO_PCI_DEVICE(0x1c5e,                               TCO_CPT30)},
 355        { ITCO_PCI_DEVICE(0x1c5f,                               TCO_CPT31)},
 356        { ITCO_PCI_DEVICE(0x1d40,                               TCO_PBG1)},
 357        { ITCO_PCI_DEVICE(0x1d41,                               TCO_PBG2)},
 358        { 0, },                 /* End of list */
 359};
 360MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
 361
 362/* Address definitions for the TCO */
 363/* TCO base address */
 364#define TCOBASE         (iTCO_wdt_private.ACPIBASE + 0x60)
 365/* SMI Control and Enable Register */
 366#define SMI_EN          (iTCO_wdt_private.ACPIBASE + 0x30)
 367
 368#define TCO_RLD         (TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */
 369#define TCOv1_TMR       (TCOBASE + 0x01) /* TCOv1 Timer Initial Value   */
 370#define TCO_DAT_IN      (TCOBASE + 0x02) /* TCO Data In Register        */
 371#define TCO_DAT_OUT     (TCOBASE + 0x03) /* TCO Data Out Register       */
 372#define TCO1_STS        (TCOBASE + 0x04) /* TCO1 Status Register        */
 373#define TCO2_STS        (TCOBASE + 0x06) /* TCO2 Status Register        */
 374#define TCO1_CNT        (TCOBASE + 0x08) /* TCO1 Control Register       */
 375#define TCO2_CNT        (TCOBASE + 0x0a) /* TCO2 Control Register       */
 376#define TCOv2_TMR       (TCOBASE + 0x12) /* TCOv2 Timer Initial Value   */
 377
 378/* internal variables */
 379static unsigned long is_active;
 380static char expect_release;
 381static struct {         /* this is private data for the iTCO_wdt device */
 382        /* TCO version/generation */
 383        unsigned int iTCO_version;
 384        /* The device's ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
 385        unsigned long ACPIBASE;
 386        /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/
 387        unsigned long __iomem *gcs;
 388        /* the lock for io operations */
 389        spinlock_t io_lock;
 390        /* the PCI-device */
 391        struct pci_dev *pdev;
 392} iTCO_wdt_private;
 393
 394/* the watchdog platform device */
 395static struct platform_device *iTCO_wdt_platform_device;
 396
 397/* module parameters */
 398#define WATCHDOG_HEARTBEAT 30   /* 30 sec default heartbeat */
 399static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
 400module_param(heartbeat, int, 0);
 401MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
 402        "5..76 (TCO v1) or 3..614 (TCO v2), default="
 403                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 404
 405static int nowayout = WATCHDOG_NOWAYOUT;
 406module_param(nowayout, int, 0);
 407MODULE_PARM_DESC(nowayout,
 408        "Watchdog cannot be stopped once started (default="
 409                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 410
 411/*
 412 * Some TCO specific functions
 413 */
 414
 415static inline unsigned int seconds_to_ticks(int seconds)
 416{
 417        /* the internal timer is stored as ticks which decrement
 418         * every 0.6 seconds */
 419        return (seconds * 10) / 6;
 420}
 421
 422static void iTCO_wdt_set_NO_REBOOT_bit(void)
 423{
 424        u32 val32;
 425
 426        /* Set the NO_REBOOT bit: this disables reboots */
 427        if (iTCO_wdt_private.iTCO_version == 2) {
 428                val32 = readl(iTCO_wdt_private.gcs);
 429                val32 |= 0x00000020;
 430                writel(val32, iTCO_wdt_private.gcs);
 431        } else if (iTCO_wdt_private.iTCO_version == 1) {
 432                pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
 433                val32 |= 0x00000002;
 434                pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
 435        }
 436}
 437
 438static int iTCO_wdt_unset_NO_REBOOT_bit(void)
 439{
 440        int ret = 0;
 441        u32 val32;
 442
 443        /* Unset the NO_REBOOT bit: this enables reboots */
 444        if (iTCO_wdt_private.iTCO_version == 2) {
 445                val32 = readl(iTCO_wdt_private.gcs);
 446                val32 &= 0xffffffdf;
 447                writel(val32, iTCO_wdt_private.gcs);
 448
 449                val32 = readl(iTCO_wdt_private.gcs);
 450                if (val32 & 0x00000020)
 451                        ret = -EIO;
 452        } else if (iTCO_wdt_private.iTCO_version == 1) {
 453                pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
 454                val32 &= 0xfffffffd;
 455                pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
 456
 457                pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
 458                if (val32 & 0x00000002)
 459                        ret = -EIO;
 460        }
 461
 462        return ret; /* returns: 0 = OK, -EIO = Error */
 463}
 464
 465static int iTCO_wdt_start(void)
 466{
 467        unsigned int val;
 468
 469        spin_lock(&iTCO_wdt_private.io_lock);
 470
 471        iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
 472
 473        /* disable chipset's NO_REBOOT bit */
 474        if (iTCO_wdt_unset_NO_REBOOT_bit()) {
 475                spin_unlock(&iTCO_wdt_private.io_lock);
 476                printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
 477                                        "reboot disabled by hardware/BIOS\n");
 478                return -EIO;
 479        }
 480
 481        /* Force the timer to its reload value by writing to the TCO_RLD
 482           register */
 483        if (iTCO_wdt_private.iTCO_version == 2)
 484                outw(0x01, TCO_RLD);
 485        else if (iTCO_wdt_private.iTCO_version == 1)
 486                outb(0x01, TCO_RLD);
 487
 488        /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
 489        val = inw(TCO1_CNT);
 490        val &= 0xf7ff;
 491        outw(val, TCO1_CNT);
 492        val = inw(TCO1_CNT);
 493        spin_unlock(&iTCO_wdt_private.io_lock);
 494
 495        if (val & 0x0800)
 496                return -1;
 497        return 0;
 498}
 499
 500static int iTCO_wdt_stop(void)
 501{
 502        unsigned int val;
 503
 504        spin_lock(&iTCO_wdt_private.io_lock);
 505
 506        iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
 507
 508        /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
 509        val = inw(TCO1_CNT);
 510        val |= 0x0800;
 511        outw(val, TCO1_CNT);
 512        val = inw(TCO1_CNT);
 513
 514        /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
 515        iTCO_wdt_set_NO_REBOOT_bit();
 516
 517        spin_unlock(&iTCO_wdt_private.io_lock);
 518
 519        if ((val & 0x0800) == 0)
 520                return -1;
 521        return 0;
 522}
 523
 524static int iTCO_wdt_keepalive(void)
 525{
 526        spin_lock(&iTCO_wdt_private.io_lock);
 527
 528        iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
 529
 530        /* Reload the timer by writing to the TCO Timer Counter register */
 531        if (iTCO_wdt_private.iTCO_version == 2)
 532                outw(0x01, TCO_RLD);
 533        else if (iTCO_wdt_private.iTCO_version == 1) {
 534                /* Reset the timeout status bit so that the timer
 535                 * needs to count down twice again before rebooting */
 536                outw(0x0008, TCO1_STS); /* write 1 to clear bit */
 537
 538                outb(0x01, TCO_RLD);
 539        }
 540
 541        spin_unlock(&iTCO_wdt_private.io_lock);
 542        return 0;
 543}
 544
 545static int iTCO_wdt_set_heartbeat(int t)
 546{
 547        unsigned int val16;
 548        unsigned char val8;
 549        unsigned int tmrval;
 550
 551        tmrval = seconds_to_ticks(t);
 552
 553        /* For TCO v1 the timer counts down twice before rebooting */
 554        if (iTCO_wdt_private.iTCO_version == 1)
 555                tmrval /= 2;
 556
 557        /* from the specs: */
 558        /* "Values of 0h-3h are ignored and should not be attempted" */
 559        if (tmrval < 0x04)
 560                return -EINVAL;
 561        if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
 562            ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
 563                return -EINVAL;
 564
 565        iTCO_vendor_pre_set_heartbeat(tmrval);
 566
 567        /* Write new heartbeat to watchdog */
 568        if (iTCO_wdt_private.iTCO_version == 2) {
 569                spin_lock(&iTCO_wdt_private.io_lock);
 570                val16 = inw(TCOv2_TMR);
 571                val16 &= 0xfc00;
 572                val16 |= tmrval;
 573                outw(val16, TCOv2_TMR);
 574                val16 = inw(TCOv2_TMR);
 575                spin_unlock(&iTCO_wdt_private.io_lock);
 576
 577                if ((val16 & 0x3ff) != tmrval)
 578                        return -EINVAL;
 579        } else if (iTCO_wdt_private.iTCO_version == 1) {
 580                spin_lock(&iTCO_wdt_private.io_lock);
 581                val8 = inb(TCOv1_TMR);
 582                val8 &= 0xc0;
 583                val8 |= (tmrval & 0xff);
 584                outb(val8, TCOv1_TMR);
 585                val8 = inb(TCOv1_TMR);
 586                spin_unlock(&iTCO_wdt_private.io_lock);
 587
 588                if ((val8 & 0x3f) != tmrval)
 589                        return -EINVAL;
 590        }
 591
 592        heartbeat = t;
 593        return 0;
 594}
 595
 596static int iTCO_wdt_get_timeleft(int *time_left)
 597{
 598        unsigned int val16;
 599        unsigned char val8;
 600
 601        /* read the TCO Timer */
 602        if (iTCO_wdt_private.iTCO_version == 2) {
 603                spin_lock(&iTCO_wdt_private.io_lock);
 604                val16 = inw(TCO_RLD);
 605                val16 &= 0x3ff;
 606                spin_unlock(&iTCO_wdt_private.io_lock);
 607
 608                *time_left = (val16 * 6) / 10;
 609        } else if (iTCO_wdt_private.iTCO_version == 1) {
 610                spin_lock(&iTCO_wdt_private.io_lock);
 611                val8 = inb(TCO_RLD);
 612                val8 &= 0x3f;
 613                if (!(inw(TCO1_STS) & 0x0008))
 614                        val8 += (inb(TCOv1_TMR) & 0x3f);
 615                spin_unlock(&iTCO_wdt_private.io_lock);
 616
 617                *time_left = (val8 * 6) / 10;
 618        } else
 619                return -EINVAL;
 620        return 0;
 621}
 622
 623/*
 624 *      /dev/watchdog handling
 625 */
 626
 627static int iTCO_wdt_open(struct inode *inode, struct file *file)
 628{
 629        /* /dev/watchdog can only be opened once */
 630        if (test_and_set_bit(0, &is_active))
 631                return -EBUSY;
 632
 633        /*
 634         *      Reload and activate timer
 635         */
 636        iTCO_wdt_start();
 637        return nonseekable_open(inode, file);
 638}
 639
 640static int iTCO_wdt_release(struct inode *inode, struct file *file)
 641{
 642        /*
 643         *      Shut off the timer.
 644         */
 645        if (expect_release == 42) {
 646                iTCO_wdt_stop();
 647        } else {
 648                printk(KERN_CRIT PFX
 649                        "Unexpected close, not stopping watchdog!\n");
 650                iTCO_wdt_keepalive();
 651        }
 652        clear_bit(0, &is_active);
 653        expect_release = 0;
 654        return 0;
 655}
 656
 657static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
 658                              size_t len, loff_t *ppos)
 659{
 660        /* See if we got the magic character 'V' and reload the timer */
 661        if (len) {
 662                if (!nowayout) {
 663                        size_t i;
 664
 665                        /* note: just in case someone wrote the magic
 666                           character five months ago... */
 667                        expect_release = 0;
 668
 669                        /* scan to see whether or not we got the
 670                           magic character */
 671                        for (i = 0; i != len; i++) {
 672                                char c;
 673                                if (get_user(c, data + i))
 674                                        return -EFAULT;
 675                                if (c == 'V')
 676                                        expect_release = 42;
 677                        }
 678                }
 679
 680                /* someone wrote to us, we should reload the timer */
 681                iTCO_wdt_keepalive();
 682        }
 683        return len;
 684}
 685
 686static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
 687                                                        unsigned long arg)
 688{
 689        int new_options, retval = -EINVAL;
 690        int new_heartbeat;
 691        void __user *argp = (void __user *)arg;
 692        int __user *p = argp;
 693        static const struct watchdog_info ident = {
 694                .options =              WDIOF_SETTIMEOUT |
 695                                        WDIOF_KEEPALIVEPING |
 696                                        WDIOF_MAGICCLOSE,
 697                .firmware_version =     0,
 698                .identity =             DRV_NAME,
 699        };
 700
 701        switch (cmd) {
 702        case WDIOC_GETSUPPORT:
 703                return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
 704        case WDIOC_GETSTATUS:
 705        case WDIOC_GETBOOTSTATUS:
 706                return put_user(0, p);
 707
 708        case WDIOC_SETOPTIONS:
 709        {
 710                if (get_user(new_options, p))
 711                        return -EFAULT;
 712
 713                if (new_options & WDIOS_DISABLECARD) {
 714                        iTCO_wdt_stop();
 715                        retval = 0;
 716                }
 717                if (new_options & WDIOS_ENABLECARD) {
 718                        iTCO_wdt_keepalive();
 719                        iTCO_wdt_start();
 720                        retval = 0;
 721                }
 722                return retval;
 723        }
 724        case WDIOC_KEEPALIVE:
 725                iTCO_wdt_keepalive();
 726                return 0;
 727
 728        case WDIOC_SETTIMEOUT:
 729        {
 730                if (get_user(new_heartbeat, p))
 731                        return -EFAULT;
 732                if (iTCO_wdt_set_heartbeat(new_heartbeat))
 733                        return -EINVAL;
 734                iTCO_wdt_keepalive();
 735                /* Fall */
 736        }
 737        case WDIOC_GETTIMEOUT:
 738                return put_user(heartbeat, p);
 739        case WDIOC_GETTIMELEFT:
 740        {
 741                int time_left;
 742                if (iTCO_wdt_get_timeleft(&time_left))
 743                        return -EINVAL;
 744                return put_user(time_left, p);
 745        }
 746        default:
 747                return -ENOTTY;
 748        }
 749}
 750
 751/*
 752 *      Kernel Interfaces
 753 */
 754
 755static const struct file_operations iTCO_wdt_fops = {
 756        .owner =                THIS_MODULE,
 757        .llseek =               no_llseek,
 758        .write =                iTCO_wdt_write,
 759        .unlocked_ioctl =       iTCO_wdt_ioctl,
 760        .open =                 iTCO_wdt_open,
 761        .release =              iTCO_wdt_release,
 762};
 763
 764static struct miscdevice iTCO_wdt_miscdev = {
 765        .minor =        WATCHDOG_MINOR,
 766        .name =         "watchdog",
 767        .fops =         &iTCO_wdt_fops,
 768};
 769
 770/*
 771 *      Init & exit routines
 772 */
 773
 774static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
 775                const struct pci_device_id *ent, struct platform_device *dev)
 776{
 777        int ret;
 778        u32 base_address;
 779        unsigned long RCBA;
 780        unsigned long val32;
 781
 782        /*
 783         *      Find the ACPI/PM base I/O address which is the base
 784         *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
 785         *      ACPIBASE is bits [15:7] from 0x40-0x43
 786         */
 787        pci_read_config_dword(pdev, 0x40, &base_address);
 788        base_address &= 0x0000ff80;
 789        if (base_address == 0x00000000) {
 790                /* Something's wrong here, ACPIBASE has to be set */
 791                printk(KERN_ERR PFX "failed to get TCOBASE address, "
 792                                        "device disabled by hardware/BIOS\n");
 793                return -ENODEV;
 794        }
 795        iTCO_wdt_private.iTCO_version =
 796                        iTCO_chipset_info[ent->driver_data].iTCO_version;
 797        iTCO_wdt_private.ACPIBASE = base_address;
 798        iTCO_wdt_private.pdev = pdev;
 799
 800        /* Get the Memory-Mapped GCS register, we need it for the
 801           NO_REBOOT flag (TCO v2). To get access to it you have to
 802           read RCBA from PCI Config space 0xf0 and use it as base.
 803           GCS = RCBA + ICH6_GCS(0x3410). */
 804        if (iTCO_wdt_private.iTCO_version == 2) {
 805                pci_read_config_dword(pdev, 0xf0, &base_address);
 806                if ((base_address & 1) == 0) {
 807                        printk(KERN_ERR PFX "RCBA is disabled by hardware"
 808                                                "/BIOS, device disabled\n");
 809                        ret = -ENODEV;
 810                        goto out;
 811                }
 812                RCBA = base_address & 0xffffc000;
 813                iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4);
 814        }
 815
 816        /* Check chipset's NO_REBOOT bit */
 817        if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
 818                printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, "
 819                                        "device disabled by hardware/BIOS\n");
 820                ret = -ENODEV;  /* Cannot reset NO_REBOOT bit */
 821                goto out_unmap;
 822        }
 823
 824        /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
 825        iTCO_wdt_set_NO_REBOOT_bit();
 826
 827        /* The TCO logic uses the TCO_EN bit in the SMI_EN register */
 828        if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
 829                printk(KERN_ERR PFX
 830                        "I/O address 0x%04lx already in use, "
 831                                                "device disabled\n", SMI_EN);
 832                ret = -EIO;
 833                goto out_unmap;
 834        }
 835        /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
 836        val32 = inl(SMI_EN);
 837        val32 &= 0xffffdfff;    /* Turn off SMI clearing watchdog */
 838        outl(val32, SMI_EN);
 839
 840        /* The TCO I/O registers reside in a 32-byte range pointed to
 841           by the TCOBASE value */
 842        if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
 843                printk(KERN_ERR PFX "I/O address 0x%04lx already in use "
 844                                                "device disabled\n", TCOBASE);
 845                ret = -EIO;
 846                goto unreg_smi_en;
 847        }
 848
 849        printk(KERN_INFO PFX
 850                "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
 851                        iTCO_chipset_info[ent->driver_data].name,
 852                        iTCO_chipset_info[ent->driver_data].iTCO_version,
 853                        TCOBASE);
 854
 855        /* Clear out the (probably old) status */
 856        outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
 857        outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
 858        outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */
 859
 860        /* Make sure the watchdog is not running */
 861        iTCO_wdt_stop();
 862
 863        /* Check that the heartbeat value is within it's range;
 864           if not reset to the default */
 865        if (iTCO_wdt_set_heartbeat(heartbeat)) {
 866                iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
 867                printk(KERN_INFO PFX
 868                        "timeout value out of range, using %d\n", heartbeat);
 869        }
 870
 871        ret = misc_register(&iTCO_wdt_miscdev);
 872        if (ret != 0) {
 873                printk(KERN_ERR PFX
 874                        "cannot register miscdev on minor=%d (err=%d)\n",
 875                                                        WATCHDOG_MINOR, ret);
 876                goto unreg_region;
 877        }
 878
 879        printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
 880                                                        heartbeat, nowayout);
 881
 882        return 0;
 883
 884unreg_region:
 885        release_region(TCOBASE, 0x20);
 886unreg_smi_en:
 887        release_region(SMI_EN, 4);
 888out_unmap:
 889        if (iTCO_wdt_private.iTCO_version == 2)
 890                iounmap(iTCO_wdt_private.gcs);
 891out:
 892        iTCO_wdt_private.ACPIBASE = 0;
 893        return ret;
 894}
 895
 896static void __devexit iTCO_wdt_cleanup(void)
 897{
 898        /* Stop the timer before we leave */
 899        if (!nowayout)
 900                iTCO_wdt_stop();
 901
 902        /* Deregister */
 903        misc_deregister(&iTCO_wdt_miscdev);
 904        release_region(TCOBASE, 0x20);
 905        release_region(SMI_EN, 4);
 906        if (iTCO_wdt_private.iTCO_version == 2)
 907                iounmap(iTCO_wdt_private.gcs);
 908        pci_dev_put(iTCO_wdt_private.pdev);
 909        iTCO_wdt_private.ACPIBASE = 0;
 910}
 911
 912static int __devinit iTCO_wdt_probe(struct platform_device *dev)
 913{
 914        int ret = -ENODEV;
 915        int found = 0;
 916        struct pci_dev *pdev = NULL;
 917        const struct pci_device_id *ent;
 918
 919        spin_lock_init(&iTCO_wdt_private.io_lock);
 920
 921        for_each_pci_dev(pdev) {
 922                ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
 923                if (ent) {
 924                        found++;
 925                        ret = iTCO_wdt_init(pdev, ent, dev);
 926                        if (!ret)
 927                                break;
 928                }
 929        }
 930
 931        if (!found)
 932                printk(KERN_INFO PFX "No device detected.\n");
 933
 934        return ret;
 935}
 936
 937static int __devexit iTCO_wdt_remove(struct platform_device *dev)
 938{
 939        if (iTCO_wdt_private.ACPIBASE)
 940                iTCO_wdt_cleanup();
 941
 942        return 0;
 943}
 944
 945static void iTCO_wdt_shutdown(struct platform_device *dev)
 946{
 947        iTCO_wdt_stop();
 948}
 949
 950#define iTCO_wdt_suspend NULL
 951#define iTCO_wdt_resume  NULL
 952
 953static struct platform_driver iTCO_wdt_driver = {
 954        .probe          = iTCO_wdt_probe,
 955        .remove         = __devexit_p(iTCO_wdt_remove),
 956        .shutdown       = iTCO_wdt_shutdown,
 957        .suspend        = iTCO_wdt_suspend,
 958        .resume         = iTCO_wdt_resume,
 959        .driver         = {
 960                .owner  = THIS_MODULE,
 961                .name   = DRV_NAME,
 962        },
 963};
 964
 965static int __init iTCO_wdt_init_module(void)
 966{
 967        int err;
 968
 969        printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
 970                DRV_VERSION);
 971
 972        err = platform_driver_register(&iTCO_wdt_driver);
 973        if (err)
 974                return err;
 975
 976        iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME,
 977                                                                -1, NULL, 0);
 978        if (IS_ERR(iTCO_wdt_platform_device)) {
 979                err = PTR_ERR(iTCO_wdt_platform_device);
 980                goto unreg_platform_driver;
 981        }
 982
 983        return 0;
 984
 985unreg_platform_driver:
 986        platform_driver_unregister(&iTCO_wdt_driver);
 987        return err;
 988}
 989
 990static void __exit iTCO_wdt_cleanup_module(void)
 991{
 992        platform_device_unregister(iTCO_wdt_platform_device);
 993        platform_driver_unregister(&iTCO_wdt_driver);
 994        printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
 995}
 996
 997module_init(iTCO_wdt_init_module);
 998module_exit(iTCO_wdt_cleanup_module);
 999
1000MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
1001MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
1002MODULE_VERSION(DRV_VERSION);
1003MODULE_LICENSE("GPL");
1004MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
1005