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