550 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ACPI Hardware Watchdog (WDAT) driver.4 *5 * Copyright (C) 2016, Intel Corporation6 * 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_RESERVED17 18/**19 * struct wdat_instruction - Single ACPI WDAT instruction20 * @entry: Copy of the ACPI table instruction21 * @reg: Register the instruction is accessing22 * @node: Next instruction in action sequence23 */24struct 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 device32 * @pdev: Parent platform device33 * @wdd: Watchdog core device34 * @period: How long is one watchdog period in ms35 * @stopped_in_sleep: Is this watchdog stopped by the firmware in S1-S536 * @stopped: Was the watchdog stopped by the driver in suspend37 * @instructions: An array of instruction lists indexed by an action number from38 * the WDAT table. There can be %NULL entries for not implemented39 * actions.40 */41struct 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 52static bool nowayout = WATCHDOG_NOWAYOUT;53module_param(nowayout, bool, 0);54MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="55 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");56 57#define WDAT_DEFAULT_TIMEOUT 3058 59static int timeout = WDAT_DEFAULT_TIMEOUT;60module_param(timeout, int, 0);61MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="62 __MODULE_STRING(WDAT_DEFAULT_TIMEOUT) ")");63 64static 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 89static 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 114static 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 204static 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 reboot210 * the system when it fires. However, it also states that it is211 * recommended to make it configurable through hardware register. We212 * enable reboot now if it is configurable, 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 224static 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 244static 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 258static 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 264static 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 270static int wdat_wdt_ping(struct watchdog_device *wdd)271{272 return wdat_wdt_run_action(to_wdat_wdt(wdd), ACPI_WDAT_RESET, wdd->timeout, NULL);273}274 275static 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 289static 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 298static 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 304static 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};311 312static int wdat_wdt_probe(struct platform_device *pdev)313{314 struct device *dev = &pdev->dev;315 const struct acpi_wdat_entry *entries;316 const struct acpi_table_wdat *tbl;317 struct wdat_wdt *wdat;318 struct resource *res;319 void __iomem **regs;320 acpi_status status;321 int i, ret;322 323 status = acpi_get_table(ACPI_SIG_WDAT, 0,324 (struct acpi_table_header **)&tbl);325 if (ACPI_FAILURE(status))326 return -ENODEV;327 328 wdat = devm_kzalloc(dev, sizeof(*wdat), GFP_KERNEL);329 if (!wdat)330 return -ENOMEM;331 332 regs = devm_kcalloc(dev, pdev->num_resources, sizeof(*regs),333 GFP_KERNEL);334 if (!regs)335 return -ENOMEM;336 337 /* WDAT specification wants to have >= 1ms period */338 if (tbl->timer_period < 1)339 return -EINVAL;340 if (tbl->min_count > tbl->max_count)341 return -EINVAL;342 343 wdat->period = tbl->timer_period;344 wdat->wdd.min_timeout = DIV_ROUND_UP(wdat->period * tbl->min_count, 1000);345 wdat->wdd.max_timeout = wdat->period * tbl->max_count / 1000;346 wdat->stopped_in_sleep = tbl->flags & ACPI_WDAT_STOPPED;347 wdat->wdd.info = &wdat_wdt_info;348 wdat->wdd.ops = &wdat_wdt_ops;349 wdat->pdev = pdev;350 351 /* Request and map all resources */352 for (i = 0; i < pdev->num_resources; i++) {353 void __iomem *reg;354 355 res = &pdev->resource[i];356 if (resource_type(res) == IORESOURCE_MEM) {357 reg = devm_ioremap_resource(dev, res);358 if (IS_ERR(reg))359 return PTR_ERR(reg);360 } else if (resource_type(res) == IORESOURCE_IO) {361 reg = devm_ioport_map(dev, res->start, 1);362 if (!reg)363 return -ENOMEM;364 } else {365 dev_err(dev, "Unsupported resource\n");366 return -EINVAL;367 }368 369 regs[i] = reg;370 }371 372 entries = (struct acpi_wdat_entry *)(tbl + 1);373 for (i = 0; i < tbl->entries; i++) {374 const struct acpi_generic_address *gas;375 struct wdat_instruction *instr;376 struct list_head *instructions;377 unsigned int action;378 struct resource r;379 int j;380 381 action = entries[i].action;382 if (action >= MAX_WDAT_ACTIONS) {383 dev_dbg(dev, "Skipping unknown action: %u\n", action);384 continue;385 }386 387 instr = devm_kzalloc(dev, sizeof(*instr), GFP_KERNEL);388 if (!instr)389 return -ENOMEM;390 391 INIT_LIST_HEAD(&instr->node);392 instr->entry = entries[i];393 394 gas = &entries[i].register_region;395 396 memset(&r, 0, sizeof(r));397 r.start = gas->address;398 r.end = r.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1;399 if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {400 r.flags = IORESOURCE_MEM;401 } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {402 r.flags = IORESOURCE_IO;403 } else {404 dev_dbg(dev, "Unsupported address space: %d\n",405 gas->space_id);406 continue;407 }408 409 /* Find the matching resource */410 for (j = 0; j < pdev->num_resources; j++) {411 res = &pdev->resource[j];412 if (resource_contains(res, &r)) {413 instr->reg = regs[j] + r.start - res->start;414 break;415 }416 }417 418 if (!instr->reg) {419 dev_err(dev, "I/O resource not found\n");420 return -EINVAL;421 }422 423 instructions = wdat->instructions[action];424 if (!instructions) {425 instructions = devm_kzalloc(dev,426 sizeof(*instructions),427 GFP_KERNEL);428 if (!instructions)429 return -ENOMEM;430 431 INIT_LIST_HEAD(instructions);432 wdat->instructions[action] = instructions;433 }434 435 list_add_tail(&instr->node, instructions);436 }437 438 if (wdat->instructions[ACPI_WDAT_GET_CURRENT_COUNTDOWN])439 wdat_wdt_ops.get_timeleft = wdat_wdt_get_timeleft;440 441 wdat_wdt_boot_status(wdat);442 wdat_wdt_set_running(wdat);443 444 ret = wdat_wdt_enable_reboot(wdat);445 if (ret)446 return ret;447 448 platform_set_drvdata(pdev, wdat);449 450 /*451 * Set initial timeout so that userspace has time to configure the452 * watchdog properly after it has opened the device. In some cases453 * the BIOS default is too short and causes immediate reboot.454 */455 if (watchdog_timeout_invalid(&wdat->wdd, timeout)) {456 dev_warn(dev, "Invalid timeout %d given, using %d\n",457 timeout, WDAT_DEFAULT_TIMEOUT);458 timeout = WDAT_DEFAULT_TIMEOUT;459 }460 461 ret = wdat_wdt_set_timeout(&wdat->wdd, timeout);462 if (ret)463 return ret;464 465 watchdog_set_nowayout(&wdat->wdd, nowayout);466 watchdog_stop_on_reboot(&wdat->wdd);467 watchdog_stop_on_unregister(&wdat->wdd);468 return devm_watchdog_register_device(dev, &wdat->wdd);469}470 471static int wdat_wdt_suspend_noirq(struct device *dev)472{473 struct wdat_wdt *wdat = dev_get_drvdata(dev);474 int ret;475 476 if (!watchdog_active(&wdat->wdd))477 return 0;478 479 /*480 * We need to stop the watchdog if firmware is not doing it or if we481 * are going suspend to idle (where firmware is not involved). If482 * firmware is stopping the watchdog we kick it here one more time483 * to give it some time.484 */485 wdat->stopped = false;486 if (acpi_target_system_state() == ACPI_STATE_S0 ||487 !wdat->stopped_in_sleep) {488 ret = wdat_wdt_stop(&wdat->wdd);489 if (!ret)490 wdat->stopped = true;491 } else {492 ret = wdat_wdt_ping(&wdat->wdd);493 }494 495 return ret;496}497 498static int wdat_wdt_resume_noirq(struct device *dev)499{500 struct wdat_wdt *wdat = dev_get_drvdata(dev);501 int ret;502 503 if (!watchdog_active(&wdat->wdd))504 return 0;505 506 if (!wdat->stopped) {507 /*508 * Looks like the boot firmware reinitializes the watchdog509 * before it hands off to the OS on resume from sleep so we510 * stop and reprogram the watchdog here.511 */512 ret = wdat_wdt_stop(&wdat->wdd);513 if (ret)514 return ret;515 516 ret = wdat_wdt_set_timeout(&wdat->wdd, wdat->wdd.timeout);517 if (ret)518 return ret;519 520 ret = wdat_wdt_enable_reboot(wdat);521 if (ret)522 return ret;523 524 ret = wdat_wdt_ping(&wdat->wdd);525 if (ret)526 return ret;527 }528 529 return wdat_wdt_start(&wdat->wdd);530}531 532static const struct dev_pm_ops wdat_wdt_pm_ops = {533 NOIRQ_SYSTEM_SLEEP_PM_OPS(wdat_wdt_suspend_noirq, wdat_wdt_resume_noirq)534};535 536static struct platform_driver wdat_wdt_driver = {537 .probe = wdat_wdt_probe,538 .driver = {539 .name = "wdat_wdt",540 .pm = pm_sleep_ptr(&wdat_wdt_pm_ops),541 },542};543 544module_platform_driver(wdat_wdt_driver);545 546MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");547MODULE_DESCRIPTION("ACPI Hardware Watchdog (WDAT) driver");548MODULE_LICENSE("GPL v2");549MODULE_ALIAS("platform:wdat_wdt");550