/* Write */ static ssize_t intel_scu_write(struct file *file, char const *data, size_t len, loff_t *ppos) { pr_debug(PFX "watchdog %s\n", __func__); if (watchdog_device.shutdown_flag == true) /* do nothing if we are shutting down */ return len; if (watchdog_device.started) { /* Watchdog already started, keep it alive */ watchdog_keepalive(); wake_unlock(&watchdog_wake_lock); } else { /* Start watchdog with timer value set by init */ watchdog_config_and_start(timeout, pre_timeout); } return len; }
/* ioctl */ static long intel_scu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; u32 __user *p = argp; u32 val; int options; static const struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, /* @todo Get from SCU via ipc_get_scu_fw_version()? */ .firmware_version = 0, /* len < 32 */ .identity = "Intel_SCU IOH Watchdog" }; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_KEEPALIVE: pr_warn("%s: KeepAlive ioctl\n", __func__); if (!watchdog_device.started) return -EINVAL; watchdog_keepalive(); return 0; case WDIOC_SETPRETIMEOUT: pr_warn("%s: SetPreTimeout ioctl\n", __func__); if (watchdog_device.started) return -EBUSY; /* Timeout to warn */ if (get_user(val, p)) return -EFAULT; pre_timeout = val; return 0; case WDIOC_SETTIMEOUT: pr_warn("%s: SetTimeout ioctl\n", __func__); if (watchdog_device.started) return -EBUSY; if (get_user(val, p)) return -EFAULT; timeout = val; return 0; case WDIOC_GETTIMEOUT: return put_user(timeout, p); case WDIOC_SETOPTIONS: if (get_user(options, p)) return -EFAULT; if (options & WDIOS_DISABLECARD) { pr_warn("%s: Stopping the watchdog\n", __func__); watchdog_stop(); return 0; } if (options & WDIOS_ENABLECARD) { pr_warn("%s: Starting the watchdog\n", __func__); if (watchdog_device.started) return -EBUSY; if (check_timeouts(pre_timeout, timeout)) { pr_warn("%s: Invalid thresholds\n", __func__); return -EINVAL; } if (watchdog_config_and_start(timeout, pre_timeout)) return -EINVAL; return 0; } return 0; default: return -ENOTTY; } } static int watchdog_set_reset_type(int reset_type) { int ret; struct ipc_wd_on_timeout { u32 reset_type; } ipc_wd_on_timeout = { reset_type }; ret = rpmsg_send_command(watchdog_instance, IPC_WATCHDOG, SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT, (u8 *)&ipc_wd_on_timeout, NULL, sizeof(ipc_wd_on_timeout), 0); if (ret) { pr_crit("Error setting watchdog action: %d\n", ret); return -EIO; } watchdog_device.normal_wd_action = reset_type; return 0; }