root/drivers/watchdog/wdat_wdt.c

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

DEFINITIONS

This source file includes following definitions.
  1. wdat_wdt_read
  2. wdat_wdt_write
  3. wdat_wdt_run_action
  4. wdat_wdt_enable_reboot
  5. wdat_wdt_boot_status
  6. wdat_wdt_set_running
  7. wdat_wdt_start
  8. wdat_wdt_stop
  9. wdat_wdt_ping
  10. wdat_wdt_set_timeout
  11. wdat_wdt_get_timeleft
  12. wdat_wdt_probe
  13. wdat_wdt_suspend_noirq
  14. wdat_wdt_resume_noirq

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * ACPI Hardware Watchdog (WDAT) driver.
   4  *
   5  * Copyright (C) 2016, Intel Corporation
   6  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
   7  */
   8 
   9 #include <linux/acpi.h>
  10 #include <linux/ioport.h>
  11 #include <linux/module.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/pm.h>
  14 #include <linux/watchdog.h>
  15 
  16 #define MAX_WDAT_ACTIONS ACPI_WDAT_ACTION_RESERVED
  17 
  18 /**
  19  * struct wdat_instruction - Single ACPI WDAT instruction
  20  * @entry: Copy of the ACPI table instruction
  21  * @reg: Register the instruction is accessing
  22  * @node: Next instruction in action sequence
  23  */
  24 struct wdat_instruction {
  25         struct acpi_wdat_entry entry;
  26         void __iomem *reg;
  27         struct list_head node;
  28 };
  29 
  30 /**
  31  * struct wdat_wdt - ACPI WDAT watchdog device
  32  * @pdev: Parent platform device
  33  * @wdd: Watchdog core device
  34  * @period: How long is one watchdog period in ms
  35  * @stopped_in_sleep: Is this watchdog stopped by the firmware in S1-S5
  36  * @stopped: Was the watchdog stopped by the driver in suspend
  37  * @actions: An array of instruction lists indexed by an action number from
  38  *           the WDAT table. There can be %NULL entries for not implemented
  39  *           actions.
  40  */
  41 struct wdat_wdt {
  42         struct platform_device *pdev;
  43         struct watchdog_device wdd;
  44         unsigned int period;
  45         bool stopped_in_sleep;
  46         bool stopped;
  47         struct list_head *instructions[MAX_WDAT_ACTIONS];
  48 };
  49 
  50 #define to_wdat_wdt(wdd) container_of(wdd, struct wdat_wdt, wdd)
  51 
  52 static bool nowayout = WATCHDOG_NOWAYOUT;
  53 module_param(nowayout, bool, 0);
  54 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
  55                  __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  56 
  57 #define WDAT_DEFAULT_TIMEOUT    30
  58 
  59 static int timeout = WDAT_DEFAULT_TIMEOUT;
  60 module_param(timeout, int, 0);
  61 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
  62                  __MODULE_STRING(WDAT_DEFAULT_TIMEOUT) ")");
  63 
  64 static int wdat_wdt_read(struct wdat_wdt *wdat,
  65          const struct wdat_instruction *instr, u32 *value)
  66 {
  67         const struct acpi_generic_address *gas = &instr->entry.register_region;
  68 
  69         switch (gas->access_width) {
  70         case 1:
  71                 *value = ioread8(instr->reg);
  72                 break;
  73         case 2:
  74                 *value = ioread16(instr->reg);
  75                 break;
  76         case 3:
  77                 *value = ioread32(instr->reg);
  78                 break;
  79         default:
  80                 return -EINVAL;
  81         }
  82 
  83         dev_dbg(&wdat->pdev->dev, "Read %#x from 0x%08llx\n", *value,
  84                 gas->address);
  85 
  86         return 0;
  87 }
  88 
  89 static int wdat_wdt_write(struct wdat_wdt *wdat,
  90         const struct wdat_instruction *instr, u32 value)
  91 {
  92         const struct acpi_generic_address *gas = &instr->entry.register_region;
  93 
  94         switch (gas->access_width) {
  95         case 1:
  96                 iowrite8((u8)value, instr->reg);
  97                 break;
  98         case 2:
  99                 iowrite16((u16)value, instr->reg);
 100                 break;
 101         case 3:
 102                 iowrite32(value, instr->reg);
 103                 break;
 104         default:
 105                 return -EINVAL;
 106         }
 107 
 108         dev_dbg(&wdat->pdev->dev, "Wrote %#x to 0x%08llx\n", value,
 109                 gas->address);
 110 
 111         return 0;
 112 }
 113 
 114 static int wdat_wdt_run_action(struct wdat_wdt *wdat, unsigned int action,
 115                                u32 param, u32 *retval)
 116 {
 117         struct wdat_instruction *instr;
 118 
 119         if (action >= ARRAY_SIZE(wdat->instructions))
 120                 return -EINVAL;
 121 
 122         if (!wdat->instructions[action])
 123                 return -EOPNOTSUPP;
 124 
 125         dev_dbg(&wdat->pdev->dev, "Running action %#x\n", action);
 126 
 127         /* Run each instruction sequentially */
 128         list_for_each_entry(instr, wdat->instructions[action], node) {
 129                 const struct acpi_wdat_entry *entry = &instr->entry;
 130                 const struct acpi_generic_address *gas;
 131                 u32 flags, value, mask, x, y;
 132                 bool preserve;
 133                 int ret;
 134 
 135                 gas = &entry->register_region;
 136 
 137                 preserve = entry->instruction & ACPI_WDAT_PRESERVE_REGISTER;
 138                 flags = entry->instruction & ~ACPI_WDAT_PRESERVE_REGISTER;
 139                 value = entry->value;
 140                 mask = entry->mask;
 141 
 142                 switch (flags) {
 143                 case ACPI_WDAT_READ_VALUE:
 144                         ret = wdat_wdt_read(wdat, instr, &x);
 145                         if (ret)
 146                                 return ret;
 147                         x >>= gas->bit_offset;
 148                         x &= mask;
 149                         if (retval)
 150                                 *retval = x == value;
 151                         break;
 152 
 153                 case ACPI_WDAT_READ_COUNTDOWN:
 154                         ret = wdat_wdt_read(wdat, instr, &x);
 155                         if (ret)
 156                                 return ret;
 157                         x >>= gas->bit_offset;
 158                         x &= mask;
 159                         if (retval)
 160                                 *retval = x;
 161                         break;
 162 
 163                 case ACPI_WDAT_WRITE_VALUE:
 164                         x = value & mask;
 165                         x <<= gas->bit_offset;
 166                         if (preserve) {
 167                                 ret = wdat_wdt_read(wdat, instr, &y);
 168                                 if (ret)
 169                                         return ret;
 170                                 y = y & ~(mask << gas->bit_offset);
 171                                 x |= y;
 172                         }
 173                         ret = wdat_wdt_write(wdat, instr, x);
 174                         if (ret)
 175                                 return ret;
 176                         break;
 177 
 178                 case ACPI_WDAT_WRITE_COUNTDOWN:
 179                         x = param;
 180                         x &= mask;
 181                         x <<= gas->bit_offset;
 182                         if (preserve) {
 183                                 ret = wdat_wdt_read(wdat, instr, &y);
 184                                 if (ret)
 185                                         return ret;
 186                                 y = y & ~(mask << gas->bit_offset);
 187                                 x |= y;
 188                         }
 189                         ret = wdat_wdt_write(wdat, instr, x);
 190                         if (ret)
 191                                 return ret;
 192                         break;
 193 
 194                 default:
 195                         dev_err(&wdat->pdev->dev, "Unknown instruction: %u\n",
 196                                 flags);
 197                         return -EINVAL;
 198                 }
 199         }
 200 
 201         return 0;
 202 }
 203 
 204 static int wdat_wdt_enable_reboot(struct wdat_wdt *wdat)
 205 {
 206         int ret;
 207 
 208         /*
 209          * WDAT specification says that the watchdog is required to reboot
 210          * the system when it fires. However, it also states that it is
 211          * recommeded to make it configurable through hardware register. We
 212          * enable reboot now if it is configrable, just in case.
 213          */
 214         ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_REBOOT, 0, NULL);
 215         if (ret && ret != -EOPNOTSUPP) {
 216                 dev_err(&wdat->pdev->dev,
 217                         "Failed to enable reboot when watchdog triggers\n");
 218                 return ret;
 219         }
 220 
 221         return 0;
 222 }
 223 
 224 static void wdat_wdt_boot_status(struct wdat_wdt *wdat)
 225 {
 226         u32 boot_status = 0;
 227         int ret;
 228 
 229         ret = wdat_wdt_run_action(wdat, ACPI_WDAT_GET_STATUS, 0, &boot_status);
 230         if (ret && ret != -EOPNOTSUPP) {
 231                 dev_err(&wdat->pdev->dev, "Failed to read boot status\n");
 232                 return;
 233         }
 234 
 235         if (boot_status)
 236                 wdat->wdd.bootstatus = WDIOF_CARDRESET;
 237 
 238         /* Clear the boot status in case BIOS did not do it */
 239         ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_STATUS, 0, NULL);
 240         if (ret && ret != -EOPNOTSUPP)
 241                 dev_err(&wdat->pdev->dev, "Failed to clear boot status\n");
 242 }
 243 
 244 static void wdat_wdt_set_running(struct wdat_wdt *wdat)
 245 {
 246         u32 running = 0;
 247         int ret;
 248 
 249         ret = wdat_wdt_run_action(wdat, ACPI_WDAT_GET_RUNNING_STATE, 0,
 250                                   &running);
 251         if (ret && ret != -EOPNOTSUPP)
 252                 dev_err(&wdat->pdev->dev, "Failed to read running state\n");
 253 
 254         if (running)
 255                 set_bit(WDOG_HW_RUNNING, &wdat->wdd.status);
 256 }
 257 
 258 static int wdat_wdt_start(struct watchdog_device *wdd)
 259 {
 260         return wdat_wdt_run_action(to_wdat_wdt(wdd),
 261                                    ACPI_WDAT_SET_RUNNING_STATE, 0, NULL);
 262 }
 263 
 264 static int wdat_wdt_stop(struct watchdog_device *wdd)
 265 {
 266         return wdat_wdt_run_action(to_wdat_wdt(wdd),
 267                                    ACPI_WDAT_SET_STOPPED_STATE, 0, NULL);
 268 }
 269 
 270 static int wdat_wdt_ping(struct watchdog_device *wdd)
 271 {
 272         return wdat_wdt_run_action(to_wdat_wdt(wdd), ACPI_WDAT_RESET, 0, NULL);
 273 }
 274 
 275 static int wdat_wdt_set_timeout(struct watchdog_device *wdd,
 276                                 unsigned int timeout)
 277 {
 278         struct wdat_wdt *wdat = to_wdat_wdt(wdd);
 279         unsigned int periods;
 280         int ret;
 281 
 282         periods = timeout * 1000 / wdat->period;
 283         ret = wdat_wdt_run_action(wdat, ACPI_WDAT_SET_COUNTDOWN, periods, NULL);
 284         if (!ret)
 285                 wdd->timeout = timeout;
 286         return ret;
 287 }
 288 
 289 static unsigned int wdat_wdt_get_timeleft(struct watchdog_device *wdd)
 290 {
 291         struct wdat_wdt *wdat = to_wdat_wdt(wdd);
 292         u32 periods = 0;
 293 
 294         wdat_wdt_run_action(wdat, ACPI_WDAT_GET_CURRENT_COUNTDOWN, 0, &periods);
 295         return periods * wdat->period / 1000;
 296 }
 297 
 298 static const struct watchdog_info wdat_wdt_info = {
 299         .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 300         .firmware_version = 0,
 301         .identity = "wdat_wdt",
 302 };
 303 
 304 static const struct watchdog_ops wdat_wdt_ops = {
 305         .owner = THIS_MODULE,
 306         .start = wdat_wdt_start,
 307         .stop = wdat_wdt_stop,
 308         .ping = wdat_wdt_ping,
 309         .set_timeout = wdat_wdt_set_timeout,
 310         .get_timeleft = wdat_wdt_get_timeleft,
 311 };
 312 
 313 static int wdat_wdt_probe(struct platform_device *pdev)
 314 {
 315         struct device *dev = &pdev->dev;
 316         const struct acpi_wdat_entry *entries;
 317         const struct acpi_table_wdat *tbl;
 318         struct wdat_wdt *wdat;
 319         struct resource *res;
 320         void __iomem **regs;
 321         acpi_status status;
 322         int i, ret;
 323 
 324         status = acpi_get_table(ACPI_SIG_WDAT, 0,
 325                                 (struct acpi_table_header **)&tbl);
 326         if (ACPI_FAILURE(status))
 327                 return -ENODEV;
 328 
 329         wdat = devm_kzalloc(dev, sizeof(*wdat), GFP_KERNEL);
 330         if (!wdat)
 331                 return -ENOMEM;
 332 
 333         regs = devm_kcalloc(dev, pdev->num_resources, sizeof(*regs),
 334                             GFP_KERNEL);
 335         if (!regs)
 336                 return -ENOMEM;
 337 
 338         /* WDAT specification wants to have >= 1ms period */
 339         if (tbl->timer_period < 1)
 340                 return -EINVAL;
 341         if (tbl->min_count > tbl->max_count)
 342                 return -EINVAL;
 343 
 344         wdat->period = tbl->timer_period;
 345         wdat->wdd.min_hw_heartbeat_ms = wdat->period * tbl->min_count;
 346         wdat->wdd.max_hw_heartbeat_ms = wdat->period * tbl->max_count;
 347         wdat->stopped_in_sleep = tbl->flags & ACPI_WDAT_STOPPED;
 348         wdat->wdd.info = &wdat_wdt_info;
 349         wdat->wdd.ops = &wdat_wdt_ops;
 350         wdat->pdev = pdev;
 351 
 352         /* Request and map all resources */
 353         for (i = 0; i < pdev->num_resources; i++) {
 354                 void __iomem *reg;
 355 
 356                 res = &pdev->resource[i];
 357                 if (resource_type(res) == IORESOURCE_MEM) {
 358                         reg = devm_ioremap_resource(dev, res);
 359                         if (IS_ERR(reg))
 360                                 return PTR_ERR(reg);
 361                 } else if (resource_type(res) == IORESOURCE_IO) {
 362                         reg = devm_ioport_map(dev, res->start, 1);
 363                         if (!reg)
 364                                 return -ENOMEM;
 365                 } else {
 366                         dev_err(dev, "Unsupported resource\n");
 367                         return -EINVAL;
 368                 }
 369 
 370                 regs[i] = reg;
 371         }
 372 
 373         entries = (struct acpi_wdat_entry *)(tbl + 1);
 374         for (i = 0; i < tbl->entries; i++) {
 375                 const struct acpi_generic_address *gas;
 376                 struct wdat_instruction *instr;
 377                 struct list_head *instructions;
 378                 unsigned int action;
 379                 struct resource r;
 380                 int j;
 381 
 382                 action = entries[i].action;
 383                 if (action >= MAX_WDAT_ACTIONS) {
 384                         dev_dbg(dev, "Skipping unknown action: %u\n", action);
 385                         continue;
 386                 }
 387 
 388                 instr = devm_kzalloc(dev, sizeof(*instr), GFP_KERNEL);
 389                 if (!instr)
 390                         return -ENOMEM;
 391 
 392                 INIT_LIST_HEAD(&instr->node);
 393                 instr->entry = entries[i];
 394 
 395                 gas = &entries[i].register_region;
 396 
 397                 memset(&r, 0, sizeof(r));
 398                 r.start = gas->address;
 399                 r.end = r.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1;
 400                 if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 401                         r.flags = IORESOURCE_MEM;
 402                 } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
 403                         r.flags = IORESOURCE_IO;
 404                 } else {
 405                         dev_dbg(dev, "Unsupported address space: %d\n",
 406                                 gas->space_id);
 407                         continue;
 408                 }
 409 
 410                 /* Find the matching resource */
 411                 for (j = 0; j < pdev->num_resources; j++) {
 412                         res = &pdev->resource[j];
 413                         if (resource_contains(res, &r)) {
 414                                 instr->reg = regs[j] + r.start - res->start;
 415                                 break;
 416                         }
 417                 }
 418 
 419                 if (!instr->reg) {
 420                         dev_err(dev, "I/O resource not found\n");
 421                         return -EINVAL;
 422                 }
 423 
 424                 instructions = wdat->instructions[action];
 425                 if (!instructions) {
 426                         instructions = devm_kzalloc(dev,
 427                                                     sizeof(*instructions),
 428                                                     GFP_KERNEL);
 429                         if (!instructions)
 430                                 return -ENOMEM;
 431 
 432                         INIT_LIST_HEAD(instructions);
 433                         wdat->instructions[action] = instructions;
 434                 }
 435 
 436                 list_add_tail(&instr->node, instructions);
 437         }
 438 
 439         wdat_wdt_boot_status(wdat);
 440         wdat_wdt_set_running(wdat);
 441 
 442         ret = wdat_wdt_enable_reboot(wdat);
 443         if (ret)
 444                 return ret;
 445 
 446         platform_set_drvdata(pdev, wdat);
 447 
 448         /*
 449          * Set initial timeout so that userspace has time to configure the
 450          * watchdog properly after it has opened the device. In some cases
 451          * the BIOS default is too short and causes immediate reboot.
 452          */
 453         if (timeout * 1000 < wdat->wdd.min_hw_heartbeat_ms ||
 454             timeout * 1000 > wdat->wdd.max_hw_heartbeat_ms) {
 455                 dev_warn(dev, "Invalid timeout %d given, using %d\n",
 456                          timeout, WDAT_DEFAULT_TIMEOUT);
 457                 timeout = WDAT_DEFAULT_TIMEOUT;
 458         }
 459 
 460         ret = wdat_wdt_set_timeout(&wdat->wdd, timeout);
 461         if (ret)
 462                 return ret;
 463 
 464         watchdog_set_nowayout(&wdat->wdd, nowayout);
 465         return devm_watchdog_register_device(dev, &wdat->wdd);
 466 }
 467 
 468 #ifdef CONFIG_PM_SLEEP
 469 static int wdat_wdt_suspend_noirq(struct device *dev)
 470 {
 471         struct wdat_wdt *wdat = dev_get_drvdata(dev);
 472         int ret;
 473 
 474         if (!watchdog_active(&wdat->wdd))
 475                 return 0;
 476 
 477         /*
 478          * We need to stop the watchdog if firmare is not doing it or if we
 479          * are going suspend to idle (where firmware is not involved). If
 480          * firmware is stopping the watchdog we kick it here one more time
 481          * to give it some time.
 482          */
 483         wdat->stopped = false;
 484         if (acpi_target_system_state() == ACPI_STATE_S0 ||
 485             !wdat->stopped_in_sleep) {
 486                 ret = wdat_wdt_stop(&wdat->wdd);
 487                 if (!ret)
 488                         wdat->stopped = true;
 489         } else {
 490                 ret = wdat_wdt_ping(&wdat->wdd);
 491         }
 492 
 493         return ret;
 494 }
 495 
 496 static int wdat_wdt_resume_noirq(struct device *dev)
 497 {
 498         struct wdat_wdt *wdat = dev_get_drvdata(dev);
 499         int ret;
 500 
 501         if (!watchdog_active(&wdat->wdd))
 502                 return 0;
 503 
 504         if (!wdat->stopped) {
 505                 /*
 506                  * Looks like the boot firmware reinitializes the watchdog
 507                  * before it hands off to the OS on resume from sleep so we
 508                  * stop and reprogram the watchdog here.
 509                  */
 510                 ret = wdat_wdt_stop(&wdat->wdd);
 511                 if (ret)
 512                         return ret;
 513 
 514                 ret = wdat_wdt_set_timeout(&wdat->wdd, wdat->wdd.timeout);
 515                 if (ret)
 516                         return ret;
 517 
 518                 ret = wdat_wdt_enable_reboot(wdat);
 519                 if (ret)
 520                         return ret;
 521 
 522                 ret = wdat_wdt_ping(&wdat->wdd);
 523                 if (ret)
 524                         return ret;
 525         }
 526 
 527         return wdat_wdt_start(&wdat->wdd);
 528 }
 529 #endif
 530 
 531 static const struct dev_pm_ops wdat_wdt_pm_ops = {
 532         SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(wdat_wdt_suspend_noirq,
 533                                       wdat_wdt_resume_noirq)
 534 };
 535 
 536 static struct platform_driver wdat_wdt_driver = {
 537         .probe = wdat_wdt_probe,
 538         .driver = {
 539                 .name = "wdat_wdt",
 540                 .pm = &wdat_wdt_pm_ops,
 541         },
 542 };
 543 
 544 module_platform_driver(wdat_wdt_driver);
 545 
 546 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
 547 MODULE_DESCRIPTION("ACPI Hardware Watchdog (WDAT) driver");
 548 MODULE_LICENSE("GPL v2");
 549 MODULE_ALIAS("platform:wdat_wdt");

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