Commit a1dc6308 authored by Amitay Isaacs's avatar Amitay Isaacs Committed by Joel Stanley

fsi: sbefifo: Implement FSI_SBEFIFO_READ_TIMEOUT_SECONDS ioctl

FSI_SBEFIFO_READ_TIMEOUT_SECONDS ioctl sets the read timeout (in
seconds) for the response received by sbefifo device from sbe.  The
timeout affects only the read operation on current sbefifo device fd.

Certain SBE operations can take long time to complete and the default
timeout of 10 seconds might not be sufficient to start receiving
response from SBE.  In such cases, allow the timeout to be set to the
maximum of 120 seconds.

The kernel does not contain the definition of the various SBE
operations, so we must expose an interface to userspace to set the
timeout for the given operation.
Signed-off-by: default avatarAmitay Isaacs <amitay@ozlabs.org>
Signed-off-by: default avatarJoel Stanley <joel@jms.id.au>
Reviewed-by: default avatarEddie James <eajames@linux.ibm.com>
Link: https://lore.kernel.org/r/20220121053816.82253-3-joel@jms.id.auSigned-off-by: default avatarJoel Stanley <joel@jms.id.au>
parent b8d536d2
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <uapi/linux/fsi.h>
/* /*
* The SBEFIFO is a pipe-like FSI device for communicating with * The SBEFIFO is a pipe-like FSI device for communicating with
* the self boot engine on POWER processors. * the self boot engine on POWER processors.
...@@ -134,6 +136,7 @@ struct sbefifo_user { ...@@ -134,6 +136,7 @@ struct sbefifo_user {
void *cmd_page; void *cmd_page;
void *pending_cmd; void *pending_cmd;
size_t pending_len; size_t pending_len;
u32 read_timeout_ms;
}; };
static DEFINE_MUTEX(sbefifo_ffdc_mutex); static DEFINE_MUTEX(sbefifo_ffdc_mutex);
...@@ -796,6 +799,7 @@ static int sbefifo_user_open(struct inode *inode, struct file *file) ...@@ -796,6 +799,7 @@ static int sbefifo_user_open(struct inode *inode, struct file *file)
return -ENOMEM; return -ENOMEM;
} }
mutex_init(&user->file_lock); mutex_init(&user->file_lock);
user->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP;
return 0; return 0;
} }
...@@ -838,7 +842,9 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf, ...@@ -838,7 +842,9 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf,
rc = mutex_lock_interruptible(&sbefifo->lock); rc = mutex_lock_interruptible(&sbefifo->lock);
if (rc) if (rc)
goto bail; goto bail;
sbefifo->timeout_start_rsp_ms = user->read_timeout_ms;
rc = __sbefifo_submit(sbefifo, user->pending_cmd, cmd_len, &resp_iter); rc = __sbefifo_submit(sbefifo, user->pending_cmd, cmd_len, &resp_iter);
sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP;
mutex_unlock(&sbefifo->lock); mutex_unlock(&sbefifo->lock);
if (rc < 0) if (rc < 0)
goto bail; goto bail;
...@@ -928,12 +934,55 @@ static int sbefifo_user_release(struct inode *inode, struct file *file) ...@@ -928,12 +934,55 @@ static int sbefifo_user_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int sbefifo_read_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->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP;
dev_dbg(dev, "Timeout reset to %d\n", user->read_timeout_ms);
return 0;
}
if (timeout < 10 || timeout > 120)
return -EINVAL;
user->read_timeout_ms = timeout * 1000; /* user timeout is in sec */
dev_dbg(dev, "Timeout set to %d\n", user->read_timeout_ms);
return 0;
}
static long sbefifo_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct sbefifo_user *user = file->private_data;
int rc = -ENOTTY;
if (!user)
return -EINVAL;
mutex_lock(&user->file_lock);
switch (cmd) {
case FSI_SBEFIFO_READ_TIMEOUT_SECONDS:
rc = sbefifo_read_timeout(user, (void __user *)arg);
break;
}
mutex_unlock(&user->file_lock);
return rc;
}
static const struct file_operations sbefifo_fops = { static const struct file_operations sbefifo_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = sbefifo_user_open, .open = sbefifo_user_open,
.read = sbefifo_user_read, .read = sbefifo_user_read,
.write = sbefifo_user_write, .write = sbefifo_user_write,
.release = sbefifo_user_release, .release = sbefifo_user_release,
.unlocked_ioctl = sbefifo_user_ioctl,
}; };
static void sbefifo_free(struct device *dev) static void sbefifo_free(struct device *dev)
......
...@@ -55,4 +55,18 @@ struct scom_access { ...@@ -55,4 +55,18 @@ struct scom_access {
#define FSI_SCOM_WRITE _IOWR('s', 0x02, struct scom_access) #define FSI_SCOM_WRITE _IOWR('s', 0x02, struct scom_access)
#define FSI_SCOM_RESET _IOW('s', 0x03, __u32) #define FSI_SCOM_RESET _IOW('s', 0x03, __u32)
/*
* /dev/sbefifo* ioctl interface
*/
/**
* FSI_SBEFIFO_READ_TIMEOUT sets the read timeout for response from SBE.
*
* The read timeout is specified in seconds. The minimum value of read
* timeout is 10 seconds (default) and the maximum value of read timeout is
* 120 seconds. A read timeout of 0 will reset the value to the default of
* (10 seconds).
*/
#define FSI_SBEFIFO_READ_TIMEOUT_SECONDS _IOW('s', 0x00, __u32)
#endif /* _UAPI_LINUX_FSI_H */ #endif /* _UAPI_LINUX_FSI_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment