1 /* 2 * Kontron PLD watchdog driver 3 * 4 * Copyright (c) 2010-2013 Kontron Europe GmbH 5 * Author: Michael Brunner <michael.brunner@kontron.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License 2 as published 9 * by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * Note: From the PLD watchdog point of view timeout and pretimeout are 17 * defined differently than in the kernel. 18 * First the pretimeout stage runs out before the timeout stage gets 19 * active. 20 * 21 * Kernel/API: P-----| pretimeout 22 * |-----------------------T timeout 23 * Watchdog: |-----------------P pretimeout_stage 24 * |-----T timeout_stage 25 */ 26 27 #include <linux/module.h> 28 #include <linux/moduleparam.h> 29 #include <linux/uaccess.h> 30 #include <linux/watchdog.h> 31 #include <linux/platform_device.h> 32 #include <linux/mfd/kempld.h> 33 34 #define KEMPLD_WDT_STAGE_TIMEOUT(x) (0x1b + (x) * 4) 35 #define KEMPLD_WDT_STAGE_CFG(x) (0x18 + (x)) 36 #define STAGE_CFG_GET_PRESCALER(x) (((x) & 0x30) >> 4) 37 #define STAGE_CFG_SET_PRESCALER(x) (((x) & 0x3) << 4) 38 #define STAGE_CFG_PRESCALER_MASK 0x30 39 #define STAGE_CFG_ACTION_MASK 0x7 40 #define STAGE_CFG_ASSERT (1 << 3) 41 42 #define KEMPLD_WDT_MAX_STAGES 2 43 #define KEMPLD_WDT_KICK 0x16 44 #define KEMPLD_WDT_CFG 0x17 45 #define KEMPLD_WDT_CFG_ENABLE 0x10 46 #define KEMPLD_WDT_CFG_ENABLE_LOCK 0x8 47 #define KEMPLD_WDT_CFG_GLOBAL_LOCK 0x80 48 49 enum { 50 ACTION_NONE = 0, 51 ACTION_RESET, 52 ACTION_NMI, 53 ACTION_SMI, 54 ACTION_SCI, 55 ACTION_DELAY, 56 }; 57 58 enum { 59 STAGE_TIMEOUT = 0, 60 STAGE_PRETIMEOUT, 61 }; 62 63 enum { 64 PRESCALER_21 = 0, 65 PRESCALER_17, 66 PRESCALER_12, 67 }; 68 69 static const u32 kempld_prescaler[] = { 70 [PRESCALER_21] = (1 << 21) - 1, 71 [PRESCALER_17] = (1 << 17) - 1, 72 [PRESCALER_12] = (1 << 12) - 1, 73 0, 74 }; 75 76 struct kempld_wdt_stage { 77 unsigned int id; 78 u32 mask; 79 }; 80 81 struct kempld_wdt_data { 82 struct kempld_device_data *pld; 83 struct watchdog_device wdd; 84 unsigned int pretimeout; 85 struct kempld_wdt_stage stage[KEMPLD_WDT_MAX_STAGES]; 86 #ifdef CONFIG_PM 87 u8 pm_status_store; 88 #endif 89 }; 90 91 #define DEFAULT_TIMEOUT 30 /* seconds */ 92 #define DEFAULT_PRETIMEOUT 0 93 94 static unsigned int timeout = DEFAULT_TIMEOUT; 95 module_param(timeout, uint, 0); 96 MODULE_PARM_DESC(timeout, 97 "Watchdog timeout in seconds. (>=0, default=" 98 __MODULE_STRING(DEFAULT_TIMEOUT) ")"); 99 100 static unsigned int pretimeout = DEFAULT_PRETIMEOUT; 101 module_param(pretimeout, uint, 0); 102 MODULE_PARM_DESC(pretimeout, 103 "Watchdog pretimeout in seconds. (>=0, default=" 104 __MODULE_STRING(DEFAULT_PRETIMEOUT) ")"); 105 106 static bool nowayout = WATCHDOG_NOWAYOUT; 107 module_param(nowayout, bool, 0); 108 MODULE_PARM_DESC(nowayout, 109 "Watchdog cannot be stopped once started (default=" 110 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 111 112 static int kempld_wdt_set_stage_action(struct kempld_wdt_data *wdt_data, 113 struct kempld_wdt_stage *stage, 114 u8 action) 115 { 116 struct kempld_device_data *pld = wdt_data->pld; 117 u8 stage_cfg; 118 119 if (!stage || !stage->mask) 120 return -EINVAL; 121 122 kempld_get_mutex(pld); 123 stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id)); 124 stage_cfg &= ~STAGE_CFG_ACTION_MASK; 125 stage_cfg |= (action & STAGE_CFG_ACTION_MASK); 126 127 if (action == ACTION_RESET) 128 stage_cfg |= STAGE_CFG_ASSERT; 129 else 130 stage_cfg &= ~STAGE_CFG_ASSERT; 131 132 kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg); 133 kempld_release_mutex(pld); 134 135 return 0; 136 } 137 138 static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data, 139 struct kempld_wdt_stage *stage, 140 unsigned int timeout) 141 { 142 struct kempld_device_data *pld = wdt_data->pld; 143 u32 prescaler; 144 u64 stage_timeout64; 145 u32 stage_timeout; 146 u32 remainder; 147 u8 stage_cfg; 148 149 #if GCC_VERSION < 40400 150 /* work around a bug compiling do_div() */ 151 prescaler = READ_ONCE(kempld_prescaler[PRESCALER_21]); 152 #else 153 prescaler = kempld_prescaler[PRESCALER_21]; 154 #endif 155 156 if (!stage) 157 return -EINVAL; 158 159 stage_timeout64 = (u64)timeout * pld->pld_clock; 160 remainder = do_div(stage_timeout64, prescaler); 161 if (remainder) 162 stage_timeout64++; 163 164 if (stage_timeout64 > stage->mask) 165 return -EINVAL; 166 167 stage_timeout = stage_timeout64 & stage->mask; 168 169 kempld_get_mutex(pld); 170 stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id)); 171 stage_cfg &= ~STAGE_CFG_PRESCALER_MASK; 172 stage_cfg |= STAGE_CFG_SET_PRESCALER(PRESCALER_21); 173 kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg); 174 kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id), 175 stage_timeout); 176 kempld_release_mutex(pld); 177 178 return 0; 179 } 180 181 /* 182 * kempld_get_mutex must be called prior to calling this function. 183 */ 184 static unsigned int kempld_wdt_get_timeout(struct kempld_wdt_data *wdt_data, 185 struct kempld_wdt_stage *stage) 186 { 187 struct kempld_device_data *pld = wdt_data->pld; 188 unsigned int timeout; 189 u64 stage_timeout; 190 u32 prescaler; 191 u32 remainder; 192 u8 stage_cfg; 193 194 if (!stage->mask) 195 return 0; 196 197 stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id)); 198 stage_timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id)); 199 prescaler = kempld_prescaler[STAGE_CFG_GET_PRESCALER(stage_cfg)]; 200 201 stage_timeout = (stage_timeout & stage->mask) * prescaler; 202 remainder = do_div(stage_timeout, pld->pld_clock); 203 if (remainder) 204 stage_timeout++; 205 206 timeout = stage_timeout; 207 WARN_ON_ONCE(timeout != stage_timeout); 208 209 return timeout; 210 } 211 212 static int kempld_wdt_set_timeout(struct watchdog_device *wdd, 213 unsigned int timeout) 214 { 215 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd); 216 struct kempld_wdt_stage *pretimeout_stage; 217 struct kempld_wdt_stage *timeout_stage; 218 int ret; 219 220 timeout_stage = &wdt_data->stage[STAGE_TIMEOUT]; 221 pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT]; 222 223 if (pretimeout_stage->mask && wdt_data->pretimeout > 0) 224 timeout = wdt_data->pretimeout; 225 226 ret = kempld_wdt_set_stage_action(wdt_data, timeout_stage, 227 ACTION_RESET); 228 if (ret) 229 return ret; 230 ret = kempld_wdt_set_stage_timeout(wdt_data, timeout_stage, 231 timeout); 232 if (ret) 233 return ret; 234 235 wdd->timeout = timeout; 236 return 0; 237 } 238 239 static int kempld_wdt_set_pretimeout(struct watchdog_device *wdd, 240 unsigned int pretimeout) 241 { 242 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd); 243 struct kempld_wdt_stage *pretimeout_stage; 244 u8 action = ACTION_NONE; 245 int ret; 246 247 pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT]; 248 249 if (!pretimeout_stage->mask) 250 return -ENXIO; 251 252 if (pretimeout > wdd->timeout) 253 return -EINVAL; 254 255 if (pretimeout > 0) 256 action = ACTION_NMI; 257 258 ret = kempld_wdt_set_stage_action(wdt_data, pretimeout_stage, 259 action); 260 if (ret) 261 return ret; 262 ret = kempld_wdt_set_stage_timeout(wdt_data, pretimeout_stage, 263 wdd->timeout - pretimeout); 264 if (ret) 265 return ret; 266 267 wdt_data->pretimeout = pretimeout; 268 return 0; 269 } 270 271 static void kempld_wdt_update_timeouts(struct kempld_wdt_data *wdt_data) 272 { 273 struct kempld_device_data *pld = wdt_data->pld; 274 struct kempld_wdt_stage *pretimeout_stage; 275 struct kempld_wdt_stage *timeout_stage; 276 unsigned int pretimeout, timeout; 277 278 pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT]; 279 timeout_stage = &wdt_data->stage[STAGE_TIMEOUT]; 280 281 kempld_get_mutex(pld); 282 pretimeout = kempld_wdt_get_timeout(wdt_data, pretimeout_stage); 283 timeout = kempld_wdt_get_timeout(wdt_data, timeout_stage); 284 kempld_release_mutex(pld); 285 286 if (pretimeout) 287 wdt_data->pretimeout = timeout; 288 else 289 wdt_data->pretimeout = 0; 290 291 wdt_data->wdd.timeout = pretimeout + timeout; 292 } 293 294 static int kempld_wdt_start(struct watchdog_device *wdd) 295 { 296 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd); 297 struct kempld_device_data *pld = wdt_data->pld; 298 u8 status; 299 int ret; 300 301 ret = kempld_wdt_set_timeout(wdd, wdd->timeout); 302 if (ret) 303 return ret; 304 305 kempld_get_mutex(pld); 306 status = kempld_read8(pld, KEMPLD_WDT_CFG); 307 status |= KEMPLD_WDT_CFG_ENABLE; 308 kempld_write8(pld, KEMPLD_WDT_CFG, status); 309 status = kempld_read8(pld, KEMPLD_WDT_CFG); 310 kempld_release_mutex(pld); 311 312 /* Check if the watchdog was enabled */ 313 if (!(status & KEMPLD_WDT_CFG_ENABLE)) 314 return -EACCES; 315 316 return 0; 317 } 318 319 static int kempld_wdt_stop(struct watchdog_device *wdd) 320 { 321 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd); 322 struct kempld_device_data *pld = wdt_data->pld; 323 u8 status; 324 325 kempld_get_mutex(pld); 326 status = kempld_read8(pld, KEMPLD_WDT_CFG); 327 status &= ~KEMPLD_WDT_CFG_ENABLE; 328 kempld_write8(pld, KEMPLD_WDT_CFG, status); 329 status = kempld_read8(pld, KEMPLD_WDT_CFG); 330 kempld_release_mutex(pld); 331 332 /* Check if the watchdog was disabled */ 333 if (status & KEMPLD_WDT_CFG_ENABLE) 334 return -EACCES; 335 336 return 0; 337 } 338 339 static int kempld_wdt_keepalive(struct watchdog_device *wdd) 340 { 341 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd); 342 struct kempld_device_data *pld = wdt_data->pld; 343 344 kempld_get_mutex(pld); 345 kempld_write8(pld, KEMPLD_WDT_KICK, 'K'); 346 kempld_release_mutex(pld); 347 348 return 0; 349 } 350 351 static long kempld_wdt_ioctl(struct watchdog_device *wdd, unsigned int cmd, 352 unsigned long arg) 353 { 354 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd); 355 void __user *argp = (void __user *)arg; 356 int ret = -ENOIOCTLCMD; 357 int __user *p = argp; 358 int new_value; 359 360 switch (cmd) { 361 case WDIOC_SETPRETIMEOUT: 362 if (get_user(new_value, p)) 363 return -EFAULT; 364 ret = kempld_wdt_set_pretimeout(wdd, new_value); 365 if (ret) 366 return ret; 367 ret = kempld_wdt_keepalive(wdd); 368 break; 369 case WDIOC_GETPRETIMEOUT: 370 ret = put_user(wdt_data->pretimeout, (int __user *)arg); 371 break; 372 } 373 374 return ret; 375 } 376 377 static int kempld_wdt_probe_stages(struct watchdog_device *wdd) 378 { 379 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd); 380 struct kempld_device_data *pld = wdt_data->pld; 381 struct kempld_wdt_stage *pretimeout_stage; 382 struct kempld_wdt_stage *timeout_stage; 383 u8 index, data, data_orig; 384 u32 mask; 385 int i, j; 386 387 pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT]; 388 timeout_stage = &wdt_data->stage[STAGE_TIMEOUT]; 389 390 pretimeout_stage->mask = 0; 391 timeout_stage->mask = 0; 392 393 for (i = 0; i < 3; i++) { 394 index = KEMPLD_WDT_STAGE_TIMEOUT(i); 395 mask = 0; 396 397 kempld_get_mutex(pld); 398 /* Probe each byte individually. */ 399 for (j = 0; j < 4; j++) { 400 data_orig = kempld_read8(pld, index + j); 401 kempld_write8(pld, index + j, 0x00); 402 data = kempld_read8(pld, index + j); 403 /* A failed write means this byte is reserved */ 404 if (data != 0x00) 405 break; 406 kempld_write8(pld, index + j, data_orig); 407 mask |= 0xff << (j * 8); 408 } 409 kempld_release_mutex(pld); 410 411 /* Assign available stages to timeout and pretimeout */ 412 if (!timeout_stage->mask) { 413 timeout_stage->mask = mask; 414 timeout_stage->id = i; 415 } else { 416 if (pld->feature_mask & KEMPLD_FEATURE_BIT_NMI) { 417 pretimeout_stage->mask = timeout_stage->mask; 418 timeout_stage->mask = mask; 419 pretimeout_stage->id = timeout_stage->id; 420 timeout_stage->id = i; 421 } 422 break; 423 } 424 } 425 426 if (!timeout_stage->mask) 427 return -ENODEV; 428 429 return 0; 430 } 431 432 static const struct watchdog_info kempld_wdt_info = { 433 .identity = "KEMPLD Watchdog", 434 .options = WDIOF_SETTIMEOUT | 435 WDIOF_KEEPALIVEPING | 436 WDIOF_MAGICCLOSE | 437 WDIOF_PRETIMEOUT 438 }; 439 440 static const struct watchdog_ops kempld_wdt_ops = { 441 .owner = THIS_MODULE, 442 .start = kempld_wdt_start, 443 .stop = kempld_wdt_stop, 444 .ping = kempld_wdt_keepalive, 445 .set_timeout = kempld_wdt_set_timeout, 446 .ioctl = kempld_wdt_ioctl, 447 }; 448 449 static int kempld_wdt_probe(struct platform_device *pdev) 450 { 451 struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent); 452 struct kempld_wdt_data *wdt_data; 453 struct device *dev = &pdev->dev; 454 struct watchdog_device *wdd; 455 u8 status; 456 int ret = 0; 457 458 wdt_data = devm_kzalloc(dev, sizeof(*wdt_data), GFP_KERNEL); 459 if (!wdt_data) 460 return -ENOMEM; 461 462 wdt_data->pld = pld; 463 wdd = &wdt_data->wdd; 464 wdd->parent = dev; 465 466 kempld_get_mutex(pld); 467 status = kempld_read8(pld, KEMPLD_WDT_CFG); 468 kempld_release_mutex(pld); 469 470 /* Enable nowayout if watchdog is already locked */ 471 if (status & (KEMPLD_WDT_CFG_ENABLE_LOCK | 472 KEMPLD_WDT_CFG_GLOBAL_LOCK)) { 473 if (!nowayout) 474 dev_warn(dev, 475 "Forcing nowayout - watchdog lock enabled!\n"); 476 nowayout = true; 477 } 478 479 wdd->info = &kempld_wdt_info; 480 wdd->ops = &kempld_wdt_ops; 481 482 watchdog_set_drvdata(wdd, wdt_data); 483 watchdog_set_nowayout(wdd, nowayout); 484 485 ret = kempld_wdt_probe_stages(wdd); 486 if (ret) 487 return ret; 488 489 kempld_wdt_set_timeout(wdd, timeout); 490 kempld_wdt_set_pretimeout(wdd, pretimeout); 491 492 /* Check if watchdog is already enabled */ 493 if (status & KEMPLD_WDT_CFG_ENABLE) { 494 /* Get current watchdog settings */ 495 kempld_wdt_update_timeouts(wdt_data); 496 dev_info(dev, "Watchdog was already enabled\n"); 497 } 498 499 platform_set_drvdata(pdev, wdt_data); 500 ret = watchdog_register_device(wdd); 501 if (ret) 502 return ret; 503 504 dev_info(dev, "Watchdog registered with %ds timeout\n", wdd->timeout); 505 506 return 0; 507 } 508 509 static void kempld_wdt_shutdown(struct platform_device *pdev) 510 { 511 struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev); 512 513 kempld_wdt_stop(&wdt_data->wdd); 514 } 515 516 static int kempld_wdt_remove(struct platform_device *pdev) 517 { 518 struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev); 519 struct watchdog_device *wdd = &wdt_data->wdd; 520 int ret = 0; 521 522 if (!nowayout) 523 ret = kempld_wdt_stop(wdd); 524 watchdog_unregister_device(wdd); 525 526 return ret; 527 } 528 529 #ifdef CONFIG_PM 530 /* Disable watchdog if it is active during suspend */ 531 static int kempld_wdt_suspend(struct platform_device *pdev, 532 pm_message_t message) 533 { 534 struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev); 535 struct kempld_device_data *pld = wdt_data->pld; 536 struct watchdog_device *wdd = &wdt_data->wdd; 537 538 kempld_get_mutex(pld); 539 wdt_data->pm_status_store = kempld_read8(pld, KEMPLD_WDT_CFG); 540 kempld_release_mutex(pld); 541 542 kempld_wdt_update_timeouts(wdt_data); 543 544 if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE) 545 return kempld_wdt_stop(wdd); 546 547 return 0; 548 } 549 550 /* Enable watchdog and configure it if necessary */ 551 static int kempld_wdt_resume(struct platform_device *pdev) 552 { 553 struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev); 554 struct watchdog_device *wdd = &wdt_data->wdd; 555 556 /* 557 * If watchdog was stopped before suspend be sure it gets disabled 558 * again, for the case BIOS has enabled it during resume 559 */ 560 if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE) 561 return kempld_wdt_start(wdd); 562 else 563 return kempld_wdt_stop(wdd); 564 } 565 #else 566 #define kempld_wdt_suspend NULL 567 #define kempld_wdt_resume NULL 568 #endif 569 570 static struct platform_driver kempld_wdt_driver = { 571 .driver = { 572 .name = "kempld-wdt", 573 }, 574 .probe = kempld_wdt_probe, 575 .remove = kempld_wdt_remove, 576 .shutdown = kempld_wdt_shutdown, 577 .suspend = kempld_wdt_suspend, 578 .resume = kempld_wdt_resume, 579 }; 580 581 module_platform_driver(kempld_wdt_driver); 582 583 MODULE_DESCRIPTION("KEM PLD Watchdog Driver"); 584 MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>"); 585 MODULE_LICENSE("GPL"); 586