fsi: sbefifo: Add configurable in-command timeout
Commit Message
A new use case for the SBEFIFO requires a long in-command timeout
as the SBE processes each part of the command before clearing the
upstream FIFO for the next part of the command. Add ioctl support
to configure this timeout in a similar way to the existing read
timeout.
Signed-off-by: Eddie James <eajames@linux.ibm.com>
---
drivers/fsi/fsi-sbefifo.c | 33 ++++++++++++++++++++++++++++++++-
include/uapi/linux/fsi.h | 10 ++++++++++
2 files changed, 42 insertions(+), 1 deletion(-)
Comments
On Fri, 17 Mar 2023 at 13:46, Eddie James <eajames@linux.ibm.com> wrote:
>
> A new use case for the SBEFIFO requires a long in-command timeout
> as the SBE processes each part of the command before clearing the
> upstream FIFO for the next part of the command. Add ioctl support
> to configure this timeout in a similar way to the existing read
> timeout.
>
> Signed-off-by: Eddie James <eajames@linux.ibm.com>
I've got one minor suggestion below that I'll make when applying.
Reviewed-by: Joel Stanley <joel@jms.id.au>
> ---
> drivers/fsi/fsi-sbefifo.c | 33 ++++++++++++++++++++++++++++++++-
> include/uapi/linux/fsi.h | 10 ++++++++++
> 2 files changed, 42 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
> index 9912b7a6a4b9..223486b3cfcb 100644
> --- a/drivers/fsi/fsi-sbefifo.c
> +++ b/drivers/fsi/fsi-sbefifo.c
> @@ -127,6 +127,7 @@ struct sbefifo {
> bool dead;
> bool async_ffdc;
> bool timed_out;
> + u32 timeout_in_cmd_ms;
> u32 timeout_start_rsp_ms;
> };
>
> @@ -136,6 +137,7 @@ struct sbefifo_user {
> void *cmd_page;
> void *pending_cmd;
> size_t pending_len;
> + u32 cmd_timeout_ms;
> u32 read_timeout_ms;
> };
>
> @@ -508,7 +510,7 @@ static int sbefifo_send_command(struct sbefifo *sbefifo,
> rc = sbefifo_wait(sbefifo, true, &status, timeout);
> if (rc < 0)
> return rc;
> - timeout = msecs_to_jiffies(SBEFIFO_TIMEOUT_IN_CMD);
> + timeout = msecs_to_jiffies(sbefifo->timeout_in_cmd_ms);
>
> vacant = sbefifo_vacant(status);
> len = chunk = min(vacant, remaining);
> @@ -802,6 +804,7 @@ static int sbefifo_user_open(struct inode *inode, struct file *file)
> return -ENOMEM;
> }
> mutex_init(&user->file_lock);
> + user->cmd_timeout_ms = SBEFIFO_TIMEOUT_IN_CMD;
> user->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP;
>
> return 0;
> @@ -845,9 +848,11 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf,
> rc = mutex_lock_interruptible(&sbefifo->lock);
> if (rc)
> goto bail;
> + sbefifo->timeout_in_cmd_ms = user->cmd_timeout_ms;
> sbefifo->timeout_start_rsp_ms = user->read_timeout_ms;
> rc = __sbefifo_submit(sbefifo, user->pending_cmd, cmd_len, &resp_iter);
> sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP;
> + sbefifo->timeout_in_cmd_ms = SBEFIFO_TIMEOUT_IN_CMD;
> mutex_unlock(&sbefifo->lock);
> if (rc < 0)
> goto bail;
> @@ -937,6 +942,28 @@ static int sbefifo_user_release(struct inode *inode, struct file *file)
> return 0;
> }
>
> +static int sbefifo_cmd_timeout(struct sbefifo_user *user, void __user *argp)
> +{
> + struct device *dev = &user->sbefifo->dev;
> + u32 timeout;
> +
> + if (get_user(timeout, (__u32 __user *)argp))
> + return -EFAULT;
> +
> + if (timeout == 0) {
> + user->cmd_timeout_ms = SBEFIFO_TIMEOUT_IN_CMD;
> + dev_dbg(dev, "Command timeout reset to %u\n", user->cmd_timeout_ms);
%u ms ? Or divide it by 1000 to print it in seconds?
> + return 0;
> + }
> +
> + if (timeout > 120)
> + return -EINVAL;
> +
> + user->cmd_timeout_ms = timeout * 1000; /* user timeout is in sec */
> + dev_dbg(dev, "Command timeout set to %u\n", user->cmd_timeout_ms);
Same here.
> + return 0;
> +}
> +
> static int sbefifo_read_timeout(struct sbefifo_user *user, void __user *argp)
> {
> struct device *dev = &user->sbefifo->dev;
> @@ -971,6 +998,9 @@ static long sbefifo_user_ioctl(struct file *file, unsigned int cmd, unsigned lon
>
> mutex_lock(&user->file_lock);
> switch (cmd) {
> + case FSI_SBEFIFO_CMD_TIMEOUT_SECONDS:
> + rc = sbefifo_cmd_timeout(user, (void __user *)arg);
> + break;
> case FSI_SBEFIFO_READ_TIMEOUT_SECONDS:
> rc = sbefifo_read_timeout(user, (void __user *)arg);
> break;
> @@ -1025,6 +1055,7 @@ static int sbefifo_probe(struct device *dev)
> sbefifo->fsi_dev = fsi_dev;
> dev_set_drvdata(dev, sbefifo);
> mutex_init(&sbefifo->lock);
> + sbefifo->timeout_in_cmd_ms = SBEFIFO_TIMEOUT_IN_CMD;
> sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP;
>
> /*
> diff --git a/include/uapi/linux/fsi.h b/include/uapi/linux/fsi.h
> index b2f1977378c7..a2e730fc6309 100644
> --- a/include/uapi/linux/fsi.h
> +++ b/include/uapi/linux/fsi.h
> @@ -59,6 +59,16 @@ struct scom_access {
> * /dev/sbefifo* ioctl interface
> */
>
> +/**
> + * FSI_SBEFIFO_CMD_TIMEOUT sets the timeout for writing data to the SBEFIFO.
> + *
> + * The command timeout is specified in seconds. The minimum value of command
> + * timeout is 1 seconds (default) and the maximum value of command timeout is
> + * 120 seconds. A command timeout of 0 will reset the value to the default of
> + * 1 seconds.
> + */
> +#define FSI_SBEFIFO_CMD_TIMEOUT_SECONDS _IOW('s', 0x01, __u32)
> +
> /**
> * FSI_SBEFIFO_READ_TIMEOUT sets the read timeout for response from SBE.
> *
> --
> 2.31.1
>
@@ -127,6 +127,7 @@ struct sbefifo {
bool dead;
bool async_ffdc;
bool timed_out;
+ u32 timeout_in_cmd_ms;
u32 timeout_start_rsp_ms;
};
@@ -136,6 +137,7 @@ struct sbefifo_user {
void *cmd_page;
void *pending_cmd;
size_t pending_len;
+ u32 cmd_timeout_ms;
u32 read_timeout_ms;
};
@@ -508,7 +510,7 @@ static int sbefifo_send_command(struct sbefifo *sbefifo,
rc = sbefifo_wait(sbefifo, true, &status, timeout);
if (rc < 0)
return rc;
- timeout = msecs_to_jiffies(SBEFIFO_TIMEOUT_IN_CMD);
+ timeout = msecs_to_jiffies(sbefifo->timeout_in_cmd_ms);
vacant = sbefifo_vacant(status);
len = chunk = min(vacant, remaining);
@@ -802,6 +804,7 @@ static int sbefifo_user_open(struct inode *inode, struct file *file)
return -ENOMEM;
}
mutex_init(&user->file_lock);
+ user->cmd_timeout_ms = SBEFIFO_TIMEOUT_IN_CMD;
user->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP;
return 0;
@@ -845,9 +848,11 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf,
rc = mutex_lock_interruptible(&sbefifo->lock);
if (rc)
goto bail;
+ sbefifo->timeout_in_cmd_ms = user->cmd_timeout_ms;
sbefifo->timeout_start_rsp_ms = user->read_timeout_ms;
rc = __sbefifo_submit(sbefifo, user->pending_cmd, cmd_len, &resp_iter);
sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP;
+ sbefifo->timeout_in_cmd_ms = SBEFIFO_TIMEOUT_IN_CMD;
mutex_unlock(&sbefifo->lock);
if (rc < 0)
goto bail;
@@ -937,6 +942,28 @@ static int sbefifo_user_release(struct inode *inode, struct file *file)
return 0;
}
+static int sbefifo_cmd_timeout(struct sbefifo_user *user, void __user *argp)
+{
+ struct device *dev = &user->sbefifo->dev;
+ u32 timeout;
+
+ if (get_user(timeout, (__u32 __user *)argp))
+ return -EFAULT;
+
+ if (timeout == 0) {
+ user->cmd_timeout_ms = SBEFIFO_TIMEOUT_IN_CMD;
+ dev_dbg(dev, "Command timeout reset to %u\n", user->cmd_timeout_ms);
+ return 0;
+ }
+
+ if (timeout > 120)
+ return -EINVAL;
+
+ user->cmd_timeout_ms = timeout * 1000; /* user timeout is in sec */
+ dev_dbg(dev, "Command timeout set to %u\n", user->cmd_timeout_ms);
+ return 0;
+}
+
static int sbefifo_read_timeout(struct sbefifo_user *user, void __user *argp)
{
struct device *dev = &user->sbefifo->dev;
@@ -971,6 +998,9 @@ static long sbefifo_user_ioctl(struct file *file, unsigned int cmd, unsigned lon
mutex_lock(&user->file_lock);
switch (cmd) {
+ case FSI_SBEFIFO_CMD_TIMEOUT_SECONDS:
+ rc = sbefifo_cmd_timeout(user, (void __user *)arg);
+ break;
case FSI_SBEFIFO_READ_TIMEOUT_SECONDS:
rc = sbefifo_read_timeout(user, (void __user *)arg);
break;
@@ -1025,6 +1055,7 @@ static int sbefifo_probe(struct device *dev)
sbefifo->fsi_dev = fsi_dev;
dev_set_drvdata(dev, sbefifo);
mutex_init(&sbefifo->lock);
+ sbefifo->timeout_in_cmd_ms = SBEFIFO_TIMEOUT_IN_CMD;
sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP;
/*
@@ -59,6 +59,16 @@ struct scom_access {
* /dev/sbefifo* ioctl interface
*/
+/**
+ * FSI_SBEFIFO_CMD_TIMEOUT sets the timeout for writing data to the SBEFIFO.
+ *
+ * The command timeout is specified in seconds. The minimum value of command
+ * timeout is 1 seconds (default) and the maximum value of command timeout is
+ * 120 seconds. A command timeout of 0 will reset the value to the default of
+ * 1 seconds.
+ */
+#define FSI_SBEFIFO_CMD_TIMEOUT_SECONDS _IOW('s', 0x01, __u32)
+
/**
* FSI_SBEFIFO_READ_TIMEOUT sets the read timeout for response from SBE.
*