root/drivers/watchdog/hpwdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hpwdt_hw_is_running
  2. hpwdt_start
  3. hpwdt_stop
  4. hpwdt_stop_core
  5. hpwdt_ping_ticks
  6. hpwdt_ping
  7. hpwdt_gettimeleft
  8. hpwdt_settimeout
  9. hpwdt_set_pretimeout
  10. hpwdt_my_nmi
  11. hpwdt_pretimeout
  12. hpwdt_init_nmi_decoding
  13. hpwdt_exit_nmi_decoding
  14. hpwdt_init_one
  15. hpwdt_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *      HPE WatchDog Driver
   4  *      based on
   5  *
   6  *      SoftDog 0.05:   A Software Watchdog Device
   7  *
   8  *      (c) Copyright 2018 Hewlett Packard Enterprise Development LP
   9  *      Thomas Mingarelli <thomas.mingarelli@hpe.com>
  10  */
  11 
  12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13 
  14 #include <linux/device.h>
  15 #include <linux/io.h>
  16 #include <linux/kernel.h>
  17 #include <linux/module.h>
  18 #include <linux/moduleparam.h>
  19 #include <linux/pci.h>
  20 #include <linux/pci_ids.h>
  21 #include <linux/types.h>
  22 #include <linux/watchdog.h>
  23 #include <asm/nmi.h>
  24 
  25 #define HPWDT_VERSION                   "2.0.3"
  26 #define SECS_TO_TICKS(secs)             ((secs) * 1000 / 128)
  27 #define TICKS_TO_SECS(ticks)            ((ticks) * 128 / 1000)
  28 #define HPWDT_MAX_TICKS                 65535
  29 #define HPWDT_MAX_TIMER                 TICKS_TO_SECS(HPWDT_MAX_TICKS)
  30 #define DEFAULT_MARGIN                  30
  31 #define PRETIMEOUT_SEC                  9
  32 
  33 static bool ilo5;
  34 static unsigned int soft_margin = DEFAULT_MARGIN;       /* in seconds */
  35 static bool nowayout = WATCHDOG_NOWAYOUT;
  36 static bool pretimeout = IS_ENABLED(CONFIG_HPWDT_NMI_DECODING);
  37 static int kdumptimeout = -1;
  38 
  39 static void __iomem *pci_mem_addr;              /* the PCI-memory address */
  40 static unsigned long __iomem *hpwdt_nmistat;
  41 static unsigned long __iomem *hpwdt_timer_reg;
  42 static unsigned long __iomem *hpwdt_timer_con;
  43 
  44 static const struct pci_device_id hpwdt_devices[] = {
  45         { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) },   /* iLO2 */
  46         { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) },       /* iLO3 */
  47         {0},                    /* terminate list */
  48 };
  49 MODULE_DEVICE_TABLE(pci, hpwdt_devices);
  50 
  51 static const struct pci_device_id hpwdt_blacklist[] = {
  52         { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP, 0x1979) }, /* auxilary iLO */
  53         { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP_3PAR, 0x0289) },  /* CL */
  54         {0},                    /* terminate list */
  55 };
  56 
  57 static struct watchdog_device hpwdt_dev;
  58 /*
  59  *      Watchdog operations
  60  */
  61 static int hpwdt_hw_is_running(void)
  62 {
  63         return ioread8(hpwdt_timer_con) & 0x01;
  64 }
  65 
  66 static int hpwdt_start(struct watchdog_device *wdd)
  67 {
  68         int control = 0x81 | (pretimeout ? 0x4 : 0);
  69         int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
  70 
  71         dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%08x:0x%02x\n", wdd->timeout, reload, control);
  72         iowrite16(reload, hpwdt_timer_reg);
  73         iowrite8(control, hpwdt_timer_con);
  74 
  75         return 0;
  76 }
  77 
  78 static void hpwdt_stop(void)
  79 {
  80         unsigned long data;
  81 
  82         pr_debug("stop  watchdog\n");
  83 
  84         data = ioread8(hpwdt_timer_con);
  85         data &= 0xFE;
  86         iowrite8(data, hpwdt_timer_con);
  87 }
  88 
  89 static int hpwdt_stop_core(struct watchdog_device *wdd)
  90 {
  91         hpwdt_stop();
  92 
  93         return 0;
  94 }
  95 
  96 static void hpwdt_ping_ticks(int val)
  97 {
  98         val = min(val, HPWDT_MAX_TICKS);
  99         iowrite16(val, hpwdt_timer_reg);
 100 }
 101 
 102 static int hpwdt_ping(struct watchdog_device *wdd)
 103 {
 104         int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
 105 
 106         dev_dbg(wdd->parent, "ping  watchdog 0x%08x:0x%08x\n", wdd->timeout, reload);
 107         hpwdt_ping_ticks(reload);
 108 
 109         return 0;
 110 }
 111 
 112 static unsigned int hpwdt_gettimeleft(struct watchdog_device *wdd)
 113 {
 114         return TICKS_TO_SECS(ioread16(hpwdt_timer_reg));
 115 }
 116 
 117 static int hpwdt_settimeout(struct watchdog_device *wdd, unsigned int val)
 118 {
 119         dev_dbg(wdd->parent, "set_timeout = %d\n", val);
 120 
 121         wdd->timeout = val;
 122         if (val <= wdd->pretimeout) {
 123                 dev_dbg(wdd->parent, "pretimeout < timeout. Setting to zero\n");
 124                 wdd->pretimeout = 0;
 125                 pretimeout = 0;
 126                 if (watchdog_active(wdd))
 127                         hpwdt_start(wdd);
 128         }
 129         hpwdt_ping(wdd);
 130 
 131         return 0;
 132 }
 133 
 134 #ifdef CONFIG_HPWDT_NMI_DECODING
 135 static int hpwdt_set_pretimeout(struct watchdog_device *wdd, unsigned int req)
 136 {
 137         unsigned int val = 0;
 138 
 139         dev_dbg(wdd->parent, "set_pretimeout = %d\n", req);
 140         if (req) {
 141                 val = PRETIMEOUT_SEC;
 142                 if (val >= wdd->timeout)
 143                         return -EINVAL;
 144         }
 145 
 146         if (val != req)
 147                 dev_dbg(wdd->parent, "Rounding pretimeout to: %d\n", val);
 148 
 149         wdd->pretimeout = val;
 150         pretimeout = !!val;
 151 
 152         if (watchdog_active(wdd))
 153                 hpwdt_start(wdd);
 154 
 155         return 0;
 156 }
 157 
 158 static int hpwdt_my_nmi(void)
 159 {
 160         return ioread8(hpwdt_nmistat) & 0x6;
 161 }
 162 
 163 /*
 164  *      NMI Handler
 165  */
 166 static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
 167 {
 168         unsigned int mynmi = hpwdt_my_nmi();
 169         static char panic_msg[] =
 170                 "00: An NMI occurred. Depending on your system the reason "
 171                 "for the NMI is logged in any one of the following resources:\n"
 172                 "1. Integrated Management Log (IML)\n"
 173                 "2. OA Syslog\n"
 174                 "3. OA Forward Progress Log\n"
 175                 "4. iLO Event Log";
 176 
 177         if (ilo5 && ulReason == NMI_UNKNOWN && !mynmi)
 178                 return NMI_DONE;
 179 
 180         if (ilo5 && !pretimeout && !mynmi)
 181                 return NMI_DONE;
 182 
 183         if (kdumptimeout < 0)
 184                 hpwdt_stop();
 185         else if (kdumptimeout == 0)
 186                 ;
 187         else {
 188                 unsigned int val = max((unsigned int)kdumptimeout, hpwdt_dev.timeout);
 189                 hpwdt_ping_ticks(SECS_TO_TICKS(val));
 190         }
 191 
 192         hex_byte_pack(panic_msg, mynmi);
 193         nmi_panic(regs, panic_msg);
 194 
 195         return NMI_HANDLED;
 196 }
 197 #endif /* CONFIG_HPWDT_NMI_DECODING */
 198 
 199 
 200 static const struct watchdog_info ident = {
 201         .options = WDIOF_PRETIMEOUT    |
 202                    WDIOF_SETTIMEOUT    |
 203                    WDIOF_KEEPALIVEPING |
 204                    WDIOF_MAGICCLOSE,
 205         .identity = "HPE iLO2+ HW Watchdog Timer",
 206 };
 207 
 208 /*
 209  *      Kernel interfaces
 210  */
 211 
 212 static const struct watchdog_ops hpwdt_ops = {
 213         .owner          = THIS_MODULE,
 214         .start          = hpwdt_start,
 215         .stop           = hpwdt_stop_core,
 216         .ping           = hpwdt_ping,
 217         .set_timeout    = hpwdt_settimeout,
 218         .get_timeleft   = hpwdt_gettimeleft,
 219 #ifdef CONFIG_HPWDT_NMI_DECODING
 220         .set_pretimeout = hpwdt_set_pretimeout,
 221 #endif
 222 };
 223 
 224 static struct watchdog_device hpwdt_dev = {
 225         .info           = &ident,
 226         .ops            = &hpwdt_ops,
 227         .min_timeout    = 1,
 228         .timeout        = DEFAULT_MARGIN,
 229         .pretimeout     = PRETIMEOUT_SEC,
 230         .max_hw_heartbeat_ms    = HPWDT_MAX_TIMER * 1000,
 231 };
 232 
 233 
 234 /*
 235  *      Init & Exit
 236  */
 237 
 238 static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
 239 {
 240 #ifdef CONFIG_HPWDT_NMI_DECODING
 241         int retval;
 242         /*
 243          * Only one function can register for NMI_UNKNOWN
 244          */
 245         retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, 0, "hpwdt");
 246         if (retval)
 247                 goto error;
 248         retval = register_nmi_handler(NMI_SERR, hpwdt_pretimeout, 0, "hpwdt");
 249         if (retval)
 250                 goto error1;
 251         retval = register_nmi_handler(NMI_IO_CHECK, hpwdt_pretimeout, 0, "hpwdt");
 252         if (retval)
 253                 goto error2;
 254 
 255         dev_info(&dev->dev,
 256                 "HPE Watchdog Timer Driver: NMI decoding initialized\n");
 257 
 258         return 0;
 259 
 260 error2:
 261         unregister_nmi_handler(NMI_SERR, "hpwdt");
 262 error1:
 263         unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
 264 error:
 265         dev_warn(&dev->dev,
 266                 "Unable to register a die notifier (err=%d).\n",
 267                 retval);
 268         return retval;
 269 #endif  /* CONFIG_HPWDT_NMI_DECODING */
 270         return 0;
 271 }
 272 
 273 static void hpwdt_exit_nmi_decoding(void)
 274 {
 275 #ifdef CONFIG_HPWDT_NMI_DECODING
 276         unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
 277         unregister_nmi_handler(NMI_SERR, "hpwdt");
 278         unregister_nmi_handler(NMI_IO_CHECK, "hpwdt");
 279 #endif
 280 }
 281 
 282 static int hpwdt_init_one(struct pci_dev *dev,
 283                                         const struct pci_device_id *ent)
 284 {
 285         int retval;
 286 
 287         /*
 288          * First let's find out if we are on an iLO2+ server. We will
 289          * not run on a legacy ASM box.
 290          * So we only support the G5 ProLiant servers and higher.
 291          */
 292         if (dev->subsystem_vendor != PCI_VENDOR_ID_HP &&
 293             dev->subsystem_vendor != PCI_VENDOR_ID_HP_3PAR) {
 294                 dev_warn(&dev->dev,
 295                         "This server does not have an iLO2+ ASIC.\n");
 296                 return -ENODEV;
 297         }
 298 
 299         if (pci_match_id(hpwdt_blacklist, dev)) {
 300                 dev_dbg(&dev->dev, "Not supported on this device\n");
 301                 return -ENODEV;
 302         }
 303 
 304         if (pci_enable_device(dev)) {
 305                 dev_warn(&dev->dev,
 306                         "Not possible to enable PCI Device: 0x%x:0x%x.\n",
 307                         ent->vendor, ent->device);
 308                 return -ENODEV;
 309         }
 310 
 311         pci_mem_addr = pci_iomap(dev, 1, 0x80);
 312         if (!pci_mem_addr) {
 313                 dev_warn(&dev->dev,
 314                         "Unable to detect the iLO2+ server memory.\n");
 315                 retval = -ENOMEM;
 316                 goto error_pci_iomap;
 317         }
 318         hpwdt_nmistat   = pci_mem_addr + 0x6e;
 319         hpwdt_timer_reg = pci_mem_addr + 0x70;
 320         hpwdt_timer_con = pci_mem_addr + 0x72;
 321 
 322         /* Have the core update running timer until user space is ready */
 323         if (hpwdt_hw_is_running()) {
 324                 dev_info(&dev->dev, "timer is running\n");
 325                 set_bit(WDOG_HW_RUNNING, &hpwdt_dev.status);
 326         }
 327 
 328         /* Initialize NMI Decoding functionality */
 329         retval = hpwdt_init_nmi_decoding(dev);
 330         if (retval != 0)
 331                 goto error_init_nmi_decoding;
 332 
 333         watchdog_stop_on_unregister(&hpwdt_dev);
 334         watchdog_set_nowayout(&hpwdt_dev, nowayout);
 335         watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
 336 
 337         if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
 338                 dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
 339                 pretimeout = 0;
 340         }
 341         hpwdt_dev.pretimeout = pretimeout ? PRETIMEOUT_SEC : 0;
 342         kdumptimeout = min(kdumptimeout, HPWDT_MAX_TIMER);
 343 
 344         hpwdt_dev.parent = &dev->dev;
 345         retval = watchdog_register_device(&hpwdt_dev);
 346         if (retval < 0)
 347                 goto error_wd_register;
 348 
 349         dev_info(&dev->dev, "HPE Watchdog Timer Driver: Version: %s\n",
 350                                 HPWDT_VERSION);
 351         dev_info(&dev->dev, "timeout: %d seconds (nowayout=%d)\n",
 352                                 hpwdt_dev.timeout, nowayout);
 353         dev_info(&dev->dev, "pretimeout: %s.\n",
 354                                 pretimeout ? "on" : "off");
 355         dev_info(&dev->dev, "kdumptimeout: %d.\n", kdumptimeout);
 356 
 357         if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
 358                 ilo5 = true;
 359 
 360         return 0;
 361 
 362 error_wd_register:
 363         hpwdt_exit_nmi_decoding();
 364 error_init_nmi_decoding:
 365         pci_iounmap(dev, pci_mem_addr);
 366 error_pci_iomap:
 367         pci_disable_device(dev);
 368         return retval;
 369 }
 370 
 371 static void hpwdt_exit(struct pci_dev *dev)
 372 {
 373         watchdog_unregister_device(&hpwdt_dev);
 374         hpwdt_exit_nmi_decoding();
 375         pci_iounmap(dev, pci_mem_addr);
 376         pci_disable_device(dev);
 377 }
 378 
 379 static struct pci_driver hpwdt_driver = {
 380         .name = "hpwdt",
 381         .id_table = hpwdt_devices,
 382         .probe = hpwdt_init_one,
 383         .remove = hpwdt_exit,
 384 };
 385 
 386 MODULE_AUTHOR("Tom Mingarelli");
 387 MODULE_DESCRIPTION("hpe watchdog driver");
 388 MODULE_LICENSE("GPL");
 389 MODULE_VERSION(HPWDT_VERSION);
 390 
 391 module_param(soft_margin, int, 0);
 392 MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
 393 
 394 module_param_named(timeout, soft_margin, int, 0);
 395 MODULE_PARM_DESC(timeout, "Alias of soft_margin");
 396 
 397 module_param(nowayout, bool, 0);
 398 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 399                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 400 
 401 module_param(kdumptimeout, int, 0444);
 402 MODULE_PARM_DESC(kdumptimeout, "Timeout applied for crash kernel transition in seconds");
 403 
 404 #ifdef CONFIG_HPWDT_NMI_DECODING
 405 module_param(pretimeout, bool, 0);
 406 MODULE_PARM_DESC(pretimeout, "Watchdog pretimeout enabled");
 407 #endif
 408 
 409 module_pci_driver(hpwdt_driver);

/* [<][>][^][v][top][bottom][index][help] */