fsi: sbefifo: Bump max command length
Otherwise cronus putmem fails istep and BML fails to upload skiboot To do that, we still use our one-page command buffer for small commands for speed, and for anything bigger, with a limit of 1MB plus a page, we vmalloc a temporary buffer. The limit was chosen because Cronus will break up any data transfer into 1M chunks (the extra page is for the command header). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>hifive-unleashed-5.1
parent
aa1221b258
commit
15e2a7218c
|
@ -30,6 +30,7 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/uio.h>
|
#include <linux/uio.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The SBEFIFO is a pipe-like FSI device for communicating with
|
* The SBEFIFO is a pipe-like FSI device for communicating with
|
||||||
|
@ -110,7 +111,7 @@ enum sbe_state
|
||||||
#define SBEFIFO_TIMEOUT_IN_RSP 1000
|
#define SBEFIFO_TIMEOUT_IN_RSP 1000
|
||||||
|
|
||||||
/* Other constants */
|
/* Other constants */
|
||||||
#define SBEFIFO_MAX_CMD_LEN PAGE_SIZE
|
#define SBEFIFO_MAX_USER_CMD_LEN (0x100000 + PAGE_SIZE)
|
||||||
#define SBEFIFO_RESET_MAGIC 0x52534554 /* "RSET" */
|
#define SBEFIFO_RESET_MAGIC 0x52534554 /* "RSET" */
|
||||||
|
|
||||||
struct sbefifo {
|
struct sbefifo {
|
||||||
|
@ -128,6 +129,7 @@ struct sbefifo {
|
||||||
struct sbefifo_user {
|
struct sbefifo_user {
|
||||||
struct sbefifo *sbefifo;
|
struct sbefifo *sbefifo;
|
||||||
struct mutex file_lock;
|
struct mutex file_lock;
|
||||||
|
void *cmd_page;
|
||||||
void *pending_cmd;
|
void *pending_cmd;
|
||||||
size_t pending_len;
|
size_t pending_len;
|
||||||
};
|
};
|
||||||
|
@ -726,7 +728,7 @@ int sbefifo_submit(struct device *dev, const __be32 *command, size_t cmd_len,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (WARN_ON_ONCE(sbefifo->magic != SBEFIFO_MAGIC))
|
if (WARN_ON_ONCE(sbefifo->magic != SBEFIFO_MAGIC))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (!resp_len || !command || !response || cmd_len > SBEFIFO_MAX_CMD_LEN)
|
if (!resp_len || !command || !response)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Prepare iov iterator */
|
/* Prepare iov iterator */
|
||||||
|
@ -751,6 +753,15 @@ EXPORT_SYMBOL_GPL(sbefifo_submit);
|
||||||
/*
|
/*
|
||||||
* Char device interface
|
* Char device interface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static void sbefifo_release_command(struct sbefifo_user *user)
|
||||||
|
{
|
||||||
|
if (is_vmalloc_addr(user->pending_cmd))
|
||||||
|
vfree(user->pending_cmd);
|
||||||
|
user->pending_cmd = NULL;
|
||||||
|
user->pending_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int sbefifo_user_open(struct inode *inode, struct file *file)
|
static int sbefifo_user_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct sbefifo *sbefifo = container_of(inode->i_cdev, struct sbefifo, cdev);
|
struct sbefifo *sbefifo = container_of(inode->i_cdev, struct sbefifo, cdev);
|
||||||
|
@ -762,8 +773,8 @@ static int sbefifo_user_open(struct inode *inode, struct file *file)
|
||||||
|
|
||||||
file->private_data = user;
|
file->private_data = user;
|
||||||
user->sbefifo = sbefifo;
|
user->sbefifo = sbefifo;
|
||||||
user->pending_cmd = (void *)__get_free_page(GFP_KERNEL);
|
user->cmd_page = (void *)__get_free_page(GFP_KERNEL);
|
||||||
if (!user->pending_cmd) {
|
if (!user->cmd_page) {
|
||||||
kfree(user);
|
kfree(user);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -816,7 +827,7 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf,
|
||||||
/* Extract the response length */
|
/* Extract the response length */
|
||||||
rc = len - iov_iter_count(&resp_iter);
|
rc = len - iov_iter_count(&resp_iter);
|
||||||
bail:
|
bail:
|
||||||
user->pending_len = 0;
|
sbefifo_release_command(user);
|
||||||
mutex_unlock(&user->file_lock);
|
mutex_unlock(&user->file_lock);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -831,13 +842,23 @@ static ssize_t sbefifo_user_write(struct file *file, const char __user *buf,
|
||||||
if (!user)
|
if (!user)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
sbefifo = user->sbefifo;
|
sbefifo = user->sbefifo;
|
||||||
if (len > SBEFIFO_MAX_CMD_LEN)
|
if (len > SBEFIFO_MAX_USER_CMD_LEN)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (len & 3)
|
if (len & 3)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&user->file_lock);
|
mutex_lock(&user->file_lock);
|
||||||
|
|
||||||
|
/* Can we use the pre-allocate buffer ? If not, allocate */
|
||||||
|
if (len <= PAGE_SIZE)
|
||||||
|
user->pending_cmd = user->cmd_page;
|
||||||
|
else
|
||||||
|
user->pending_cmd = vmalloc(len);
|
||||||
|
if (!user->pending_cmd) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
/* Copy the command into the staging buffer */
|
/* Copy the command into the staging buffer */
|
||||||
if (copy_from_user(user->pending_cmd, buf, len)) {
|
if (copy_from_user(user->pending_cmd, buf, len)) {
|
||||||
rc = -EFAULT;
|
rc = -EFAULT;
|
||||||
|
@ -863,6 +884,9 @@ static ssize_t sbefifo_user_write(struct file *file, const char __user *buf,
|
||||||
/* Update the staging buffer size */
|
/* Update the staging buffer size */
|
||||||
user->pending_len = len;
|
user->pending_len = len;
|
||||||
bail:
|
bail:
|
||||||
|
if (!user->pending_len)
|
||||||
|
sbefifo_release_command(user);
|
||||||
|
|
||||||
mutex_unlock(&user->file_lock);
|
mutex_unlock(&user->file_lock);
|
||||||
|
|
||||||
/* And that's it, we'll issue the command on a read */
|
/* And that's it, we'll issue the command on a read */
|
||||||
|
@ -876,7 +900,8 @@ static int sbefifo_user_release(struct inode *inode, struct file *file)
|
||||||
if (!user)
|
if (!user)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
free_page((unsigned long)user->pending_cmd);
|
sbefifo_release_command(user);
|
||||||
|
free_page((unsigned long)user->cmd_page);
|
||||||
kfree(user);
|
kfree(user);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue