[PATCH 1/1] ipmi/watchdog: Add WDIOC_GETTIMELEFT ioctl

From: Ryan O'Leary
Date: Tue Mar 16 2021 - 20:11:58 EST


This is the same ioctl the rest of the watchdogs support. GETTIMELEFT
returns the number of seconds in the countdown -- useful for testing
whether the watchdog is functioning.

Signed-off-by: Ryan O'Leary <ryanoleary@xxxxxxxxxx>
---
drivers/char/ipmi/ipmi_watchdog.c | 75 +++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)

diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 32c334e34d55..f253c8667395 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -456,6 +456,71 @@ static int ipmi_set_timeout(int do_heartbeat)
return rv;
}

+static unsigned int __ipmi_get_timeout(struct ipmi_smi_msg *smi_msg,
+ struct ipmi_recv_msg *recv_msg,
+ int *countdown)
+{
+ struct kernel_ipmi_msg msg;
+ int rv = 0;
+ struct ipmi_system_interface_addr addr;
+
+
+ addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ addr.channel = IPMI_BMC_CHANNEL;
+ addr.lun = 0;
+
+ msg.netfn = 0x06;
+ msg.cmd = IPMI_WDOG_GET_TIMER;
+ msg.data = NULL;
+ msg.data_len = 0;
+ rv = ipmi_request_supply_msgs(watchdog_user,
+ (struct ipmi_addr *) &addr,
+ 0,
+ &msg,
+ NULL,
+ smi_msg,
+ recv_msg,
+ 1);
+ if (rv) {
+ pr_warn("get timeout error: %d\n", rv);
+ return rv;
+ }
+
+ wait_for_completion(&msg_wait);
+
+ if (recv_msg->msg.data_len < 9) {
+ pr_warn("get timeout response size: %d (expected 9)\n",
+ recv_msg->msg.data_len);
+ return -EIO;
+ }
+
+ if (recv_msg->msg.data[0] != 0) {
+ pr_warn("get timeout completion code error: %d\n",
+ recv_msg->msg.data[0]);
+ return -EIO;
+ }
+
+ *countdown = WDOG_GET_TIMEOUT(recv_msg->msg.data[7], recv_msg->msg.data[8]);
+
+ return rv;
+}
+
+static int _ipmi_get_timeout(int *countdown)
+{
+ int rv;
+
+ if (!watchdog_user)
+ return -ENODEV;
+
+ atomic_set(&msg_tofree, 2);
+
+ rv = __ipmi_get_timeout(&smi_msg,
+ &recv_msg,
+ countdown);
+
+ return rv;
+}
+
static atomic_t panic_done_count = ATOMIC_INIT(0);

static void panic_smi_free(struct ipmi_smi_msg *msg)
@@ -729,6 +794,16 @@ static int ipmi_ioctl(struct file *file,
return -EFAULT;
return 0;

+ case WDIOC_GETTIMELEFT:
+ val = 0;
+ i = _ipmi_get_timeout(&val);
+ if (i)
+ return i;
+ i = copy_to_user(argp, &val, sizeof(val));
+ if (i)
+ return -EFAULT;
+ return 0;
+
default:
return -ENOIOCTLCMD;
}
--
2.31.0.rc2.261.g7f71774620-goog