Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  HPE WatchDog Driver
0004  *  based on
0005  *
0006  *  SoftDog 0.05:   A Software Watchdog Device
0007  *
0008  *  (c) Copyright 2018 Hewlett Packard Enterprise Development LP
0009  *  Thomas Mingarelli <thomas.mingarelli@hpe.com>
0010  */
0011 
0012 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0013 
0014 #include <linux/device.h>
0015 #include <linux/io.h>
0016 #include <linux/kernel.h>
0017 #include <linux/module.h>
0018 #include <linux/moduleparam.h>
0019 #include <linux/pci.h>
0020 #include <linux/pci_ids.h>
0021 #include <linux/types.h>
0022 #include <linux/watchdog.h>
0023 #include <asm/nmi.h>
0024 #include <linux/crash_dump.h>
0025 
0026 #define HPWDT_VERSION           "2.0.4"
0027 #define SECS_TO_TICKS(secs)     ((secs) * 1000 / 128)
0028 #define TICKS_TO_SECS(ticks)        ((ticks) * 128 / 1000)
0029 #define HPWDT_MAX_TICKS         65535
0030 #define HPWDT_MAX_TIMER         TICKS_TO_SECS(HPWDT_MAX_TICKS)
0031 #define DEFAULT_MARGIN          30
0032 #define PRETIMEOUT_SEC          9
0033 
0034 static bool ilo5;
0035 static unsigned int soft_margin = DEFAULT_MARGIN;   /* in seconds */
0036 static bool nowayout = WATCHDOG_NOWAYOUT;
0037 static bool pretimeout = IS_ENABLED(CONFIG_HPWDT_NMI_DECODING);
0038 static int kdumptimeout = -1;
0039 
0040 static void __iomem *pci_mem_addr;      /* the PCI-memory address */
0041 static unsigned long __iomem *hpwdt_nmistat;
0042 static unsigned long __iomem *hpwdt_timer_reg;
0043 static unsigned long __iomem *hpwdt_timer_con;
0044 
0045 static const struct pci_device_id hpwdt_devices[] = {
0046     { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) },   /* iLO2 */
0047     { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) },   /* iLO3 */
0048     { PCI_DEVICE(PCI_VENDOR_ID_HP_3PAR, 0x0389) },  /* PCtrl */
0049     {0},            /* terminate list */
0050 };
0051 MODULE_DEVICE_TABLE(pci, hpwdt_devices);
0052 
0053 static const struct pci_device_id hpwdt_blacklist[] = {
0054     { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP, 0x1979) }, /* auxilary iLO */
0055     { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP_3PAR, 0x0289) },  /* CL */
0056     {0},            /* terminate list */
0057 };
0058 
0059 static struct watchdog_device hpwdt_dev;
0060 /*
0061  *  Watchdog operations
0062  */
0063 static int hpwdt_hw_is_running(void)
0064 {
0065     return ioread8(hpwdt_timer_con) & 0x01;
0066 }
0067 
0068 static int hpwdt_start(struct watchdog_device *wdd)
0069 {
0070     int control = 0x81 | (pretimeout ? 0x4 : 0);
0071     int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
0072 
0073     dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%08x:0x%02x\n", wdd->timeout, reload, control);
0074     iowrite16(reload, hpwdt_timer_reg);
0075     iowrite8(control, hpwdt_timer_con);
0076 
0077     return 0;
0078 }
0079 
0080 static void hpwdt_stop(void)
0081 {
0082     unsigned long data;
0083 
0084     pr_debug("stop  watchdog\n");
0085 
0086     data = ioread8(hpwdt_timer_con);
0087     data &= 0xFE;
0088     iowrite8(data, hpwdt_timer_con);
0089 }
0090 
0091 static int hpwdt_stop_core(struct watchdog_device *wdd)
0092 {
0093     hpwdt_stop();
0094 
0095     return 0;
0096 }
0097 
0098 static void hpwdt_ping_ticks(int val)
0099 {
0100     val = min(val, HPWDT_MAX_TICKS);
0101     iowrite16(val, hpwdt_timer_reg);
0102 }
0103 
0104 static int hpwdt_ping(struct watchdog_device *wdd)
0105 {
0106     int reload = SECS_TO_TICKS(min(wdd->timeout, wdd->max_hw_heartbeat_ms/1000));
0107 
0108     dev_dbg(wdd->parent, "ping  watchdog 0x%08x:0x%08x\n", wdd->timeout, reload);
0109     hpwdt_ping_ticks(reload);
0110 
0111     return 0;
0112 }
0113 
0114 static unsigned int hpwdt_gettimeleft(struct watchdog_device *wdd)
0115 {
0116     return TICKS_TO_SECS(ioread16(hpwdt_timer_reg));
0117 }
0118 
0119 static int hpwdt_settimeout(struct watchdog_device *wdd, unsigned int val)
0120 {
0121     dev_dbg(wdd->parent, "set_timeout = %d\n", val);
0122 
0123     wdd->timeout = val;
0124     if (val <= wdd->pretimeout) {
0125         dev_dbg(wdd->parent, "pretimeout < timeout. Setting to zero\n");
0126         wdd->pretimeout = 0;
0127         pretimeout = false;
0128         if (watchdog_active(wdd))
0129             hpwdt_start(wdd);
0130     }
0131     hpwdt_ping(wdd);
0132 
0133     return 0;
0134 }
0135 
0136 #ifdef CONFIG_HPWDT_NMI_DECODING
0137 static int hpwdt_set_pretimeout(struct watchdog_device *wdd, unsigned int req)
0138 {
0139     unsigned int val = 0;
0140 
0141     dev_dbg(wdd->parent, "set_pretimeout = %d\n", req);
0142     if (req) {
0143         val = PRETIMEOUT_SEC;
0144         if (val >= wdd->timeout)
0145             return -EINVAL;
0146     }
0147 
0148     if (val != req)
0149         dev_dbg(wdd->parent, "Rounding pretimeout to: %d\n", val);
0150 
0151     wdd->pretimeout = val;
0152     pretimeout = !!val;
0153 
0154     if (watchdog_active(wdd))
0155         hpwdt_start(wdd);
0156 
0157     return 0;
0158 }
0159 
0160 static int hpwdt_my_nmi(void)
0161 {
0162     return ioread8(hpwdt_nmistat) & 0x6;
0163 }
0164 
0165 /*
0166  *  NMI Handler
0167  */
0168 static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
0169 {
0170     unsigned int mynmi = hpwdt_my_nmi();
0171     static char panic_msg[] =
0172         "00: An NMI occurred. Depending on your system the reason "
0173         "for the NMI is logged in any one of the following resources:\n"
0174         "1. Integrated Management Log (IML)\n"
0175         "2. OA Syslog\n"
0176         "3. OA Forward Progress Log\n"
0177         "4. iLO Event Log";
0178 
0179     if (ilo5 && ulReason == NMI_UNKNOWN && !mynmi)
0180         return NMI_DONE;
0181 
0182     if (ilo5 && !pretimeout && !mynmi)
0183         return NMI_DONE;
0184 
0185     if (kdumptimeout < 0)
0186         hpwdt_stop();
0187     else if (kdumptimeout == 0)
0188         ;
0189     else {
0190         unsigned int val = max((unsigned int)kdumptimeout, hpwdt_dev.timeout);
0191         hpwdt_ping_ticks(SECS_TO_TICKS(val));
0192     }
0193 
0194     hex_byte_pack(panic_msg, mynmi);
0195     nmi_panic(regs, panic_msg);
0196 
0197     return NMI_HANDLED;
0198 }
0199 #endif /* CONFIG_HPWDT_NMI_DECODING */
0200 
0201 
0202 static const struct watchdog_info ident = {
0203     .options = WDIOF_PRETIMEOUT    |
0204            WDIOF_SETTIMEOUT    |
0205            WDIOF_KEEPALIVEPING |
0206            WDIOF_MAGICCLOSE,
0207     .identity = "HPE iLO2+ HW Watchdog Timer",
0208 };
0209 
0210 /*
0211  *  Kernel interfaces
0212  */
0213 
0214 static const struct watchdog_ops hpwdt_ops = {
0215     .owner      = THIS_MODULE,
0216     .start      = hpwdt_start,
0217     .stop       = hpwdt_stop_core,
0218     .ping       = hpwdt_ping,
0219     .set_timeout    = hpwdt_settimeout,
0220     .get_timeleft   = hpwdt_gettimeleft,
0221 #ifdef CONFIG_HPWDT_NMI_DECODING
0222     .set_pretimeout = hpwdt_set_pretimeout,
0223 #endif
0224 };
0225 
0226 static struct watchdog_device hpwdt_dev = {
0227     .info       = &ident,
0228     .ops        = &hpwdt_ops,
0229     .min_timeout    = 1,
0230     .timeout    = DEFAULT_MARGIN,
0231     .pretimeout = PRETIMEOUT_SEC,
0232     .max_hw_heartbeat_ms    = HPWDT_MAX_TIMER * 1000,
0233 };
0234 
0235 
0236 /*
0237  *  Init & Exit
0238  */
0239 
0240 static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
0241 {
0242 #ifdef CONFIG_HPWDT_NMI_DECODING
0243     int retval;
0244     /*
0245      * Only one function can register for NMI_UNKNOWN
0246      */
0247     retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, 0, "hpwdt");
0248     if (retval)
0249         goto error;
0250     retval = register_nmi_handler(NMI_SERR, hpwdt_pretimeout, 0, "hpwdt");
0251     if (retval)
0252         goto error1;
0253     retval = register_nmi_handler(NMI_IO_CHECK, hpwdt_pretimeout, 0, "hpwdt");
0254     if (retval)
0255         goto error2;
0256 
0257     dev_info(&dev->dev,
0258         "HPE Watchdog Timer Driver: NMI decoding initialized\n");
0259 
0260     return 0;
0261 
0262 error2:
0263     unregister_nmi_handler(NMI_SERR, "hpwdt");
0264 error1:
0265     unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
0266 error:
0267     dev_warn(&dev->dev,
0268         "Unable to register a die notifier (err=%d).\n",
0269         retval);
0270     return retval;
0271 #endif  /* CONFIG_HPWDT_NMI_DECODING */
0272     return 0;
0273 }
0274 
0275 static void hpwdt_exit_nmi_decoding(void)
0276 {
0277 #ifdef CONFIG_HPWDT_NMI_DECODING
0278     unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
0279     unregister_nmi_handler(NMI_SERR, "hpwdt");
0280     unregister_nmi_handler(NMI_IO_CHECK, "hpwdt");
0281 #endif
0282 }
0283 
0284 static int hpwdt_init_one(struct pci_dev *dev,
0285                     const struct pci_device_id *ent)
0286 {
0287     int retval;
0288 
0289     /*
0290      * First let's find out if we are on an iLO2+ server. We will
0291      * not run on a legacy ASM box.
0292      * So we only support the G5 ProLiant servers and higher.
0293      */
0294     if (dev->subsystem_vendor != PCI_VENDOR_ID_HP &&
0295         dev->subsystem_vendor != PCI_VENDOR_ID_HP_3PAR) {
0296         dev_warn(&dev->dev,
0297             "This server does not have an iLO2+ ASIC.\n");
0298         return -ENODEV;
0299     }
0300 
0301     if (pci_match_id(hpwdt_blacklist, dev)) {
0302         dev_dbg(&dev->dev, "Not supported on this device\n");
0303         return -ENODEV;
0304     }
0305 
0306     if (pci_enable_device(dev)) {
0307         dev_warn(&dev->dev,
0308             "Not possible to enable PCI Device: 0x%x:0x%x.\n",
0309             ent->vendor, ent->device);
0310         return -ENODEV;
0311     }
0312 
0313     pci_mem_addr = pci_iomap(dev, 1, 0x80);
0314     if (!pci_mem_addr) {
0315         dev_warn(&dev->dev,
0316             "Unable to detect the iLO2+ server memory.\n");
0317         retval = -ENOMEM;
0318         goto error_pci_iomap;
0319     }
0320     hpwdt_nmistat   = pci_mem_addr + 0x6e;
0321     hpwdt_timer_reg = pci_mem_addr + 0x70;
0322     hpwdt_timer_con = pci_mem_addr + 0x72;
0323 
0324     /* Have the core update running timer until user space is ready */
0325     if (hpwdt_hw_is_running()) {
0326         dev_info(&dev->dev, "timer is running\n");
0327         set_bit(WDOG_HW_RUNNING, &hpwdt_dev.status);
0328     }
0329 
0330     /* Initialize NMI Decoding functionality */
0331     retval = hpwdt_init_nmi_decoding(dev);
0332     if (retval != 0)
0333         goto error_init_nmi_decoding;
0334 
0335     watchdog_stop_on_unregister(&hpwdt_dev);
0336     watchdog_set_nowayout(&hpwdt_dev, nowayout);
0337     watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
0338 
0339     if (is_kdump_kernel()) {
0340         pretimeout = false;
0341         kdumptimeout = 0;
0342     }
0343 
0344     if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
0345         dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
0346         pretimeout = false;
0347     }
0348     hpwdt_dev.pretimeout = pretimeout ? PRETIMEOUT_SEC : 0;
0349     kdumptimeout = min(kdumptimeout, HPWDT_MAX_TIMER);
0350 
0351     hpwdt_dev.parent = &dev->dev;
0352     retval = watchdog_register_device(&hpwdt_dev);
0353     if (retval < 0)
0354         goto error_wd_register;
0355 
0356     dev_info(&dev->dev, "HPE Watchdog Timer Driver: Version: %s\n",
0357                 HPWDT_VERSION);
0358     dev_info(&dev->dev, "timeout: %d seconds (nowayout=%d)\n",
0359                 hpwdt_dev.timeout, nowayout);
0360     dev_info(&dev->dev, "pretimeout: %s.\n",
0361                 pretimeout ? "on" : "off");
0362     dev_info(&dev->dev, "kdumptimeout: %d.\n", kdumptimeout);
0363 
0364     if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
0365         ilo5 = true;
0366 
0367     return 0;
0368 
0369 error_wd_register:
0370     hpwdt_exit_nmi_decoding();
0371 error_init_nmi_decoding:
0372     pci_iounmap(dev, pci_mem_addr);
0373 error_pci_iomap:
0374     pci_disable_device(dev);
0375     return retval;
0376 }
0377 
0378 static void hpwdt_exit(struct pci_dev *dev)
0379 {
0380     watchdog_unregister_device(&hpwdt_dev);
0381     hpwdt_exit_nmi_decoding();
0382     pci_iounmap(dev, pci_mem_addr);
0383     pci_disable_device(dev);
0384 }
0385 
0386 static struct pci_driver hpwdt_driver = {
0387     .name = "hpwdt",
0388     .id_table = hpwdt_devices,
0389     .probe = hpwdt_init_one,
0390     .remove = hpwdt_exit,
0391 };
0392 
0393 MODULE_AUTHOR("Tom Mingarelli");
0394 MODULE_DESCRIPTION("hpe watchdog driver");
0395 MODULE_LICENSE("GPL");
0396 MODULE_VERSION(HPWDT_VERSION);
0397 
0398 module_param(soft_margin, int, 0);
0399 MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
0400 
0401 module_param_named(timeout, soft_margin, int, 0);
0402 MODULE_PARM_DESC(timeout, "Alias of soft_margin");
0403 
0404 module_param(nowayout, bool, 0);
0405 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
0406         __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0407 
0408 module_param(kdumptimeout, int, 0444);
0409 MODULE_PARM_DESC(kdumptimeout, "Timeout applied for crash kernel transition in seconds");
0410 
0411 #ifdef CONFIG_HPWDT_NMI_DECODING
0412 module_param(pretimeout, bool, 0);
0413 MODULE_PARM_DESC(pretimeout, "Watchdog pretimeout enabled");
0414 #endif
0415 
0416 module_pci_driver(hpwdt_driver);