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