aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Zhang <zhangjerry@google.com>2016-11-11 12:19:58 -0800
committerMister Oyster <oysterized@gmail.com>2017-09-14 17:11:21 +0200
commit5fe0d89935609c6f30e450941949d22a9407868d (patch)
tree1e0e2d24a2954bec9a22a3d65b63c31bdf4e283e
parent17882e4f29339cc4e67bb13ec425ffff1a9d7354 (diff)
usb: gadget: f_fs: Add ioctl for allocating endpoint buffers.
This creates an ioctl named FUNCTIONFS_ENDPOINT_ALLOC which will preallocate buffers for a given size. Any reads/writes on that endpoint below that size will use those buffers instead of allocating their own. If the endpoint is not active, the buffer will not be allocated until it becomes active. Change-Id: I4da517620ed913161ea9e21a31f6b92c9a012b44 Signed-off-by: Jerry Zhang <zhangjerry@google.com>
-rw-r--r--drivers/usb/gadget/f_fs.c47
-rw-r--r--include/uapi/linux/usb/functionfs.h5
2 files changed, 46 insertions, 6 deletions
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index dce917ed3..ef910d05e 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -332,6 +332,9 @@ struct ffs_epfile {
unsigned char isoc; /* P: ffs->eps_lock */
unsigned char _pad;
+
+ unsigned long buf_len;
+ char *buffer;
};
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
@@ -767,7 +770,7 @@ static ssize_t ffs_epfile_io(struct file *file,
char *data = NULL;
ssize_t ret;
int halt;
- int buffer_len = 0;
+ size_t buffer_len = 0;
pr_debug("%s: len %lld, read %d\n", __func__, (u64)len, read);
@@ -830,9 +833,13 @@ first_try:
/* Allocate & copy */
if (!halt && !data) {
#if defined(CONFIG_64BIT) && defined(CONFIG_MTK_LM_MODE)
- data = kzalloc(buffer_len, GFP_KERNEL | GFP_DMA);
+ data = buffer_len > epfile->buf_len ?
+ kzalloc(buffer_len, GFP_KERNEL| GFP_DMA) :
+ epfile->buffer;
#else
- data = kzalloc(buffer_len, GFP_KERNEL);
+ data = buffer_len > epfile->buf_len ?
+ kzalloc(buffer_len, GFP_KERNEL) :
+ epfile->buffer;
#endif
if (unlikely(!data))
return -ENOMEM;
@@ -922,7 +929,8 @@ first_try:
mutex_unlock(&epfile->mutex);
error:
- kfree(data);
+ if (buffer_len > epfile->buf_len)
+ kfree(data);
return ret;
}
@@ -985,7 +993,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
return -ENODEV;
spin_lock_irq(&epfile->ffs->eps_lock);
- if (likely(epfile->ep)) {
+ if (epfile->ep) {
switch (code) {
case FUNCTIONFS_FIFO_STATUS:
ret = usb_ep_fifo_status(epfile->ep->ep);
@@ -1023,11 +1031,28 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
ret = -EFAULT;
return ret;
}
+ case FUNCTIONFS_ENDPOINT_ALLOC:
+ kfree(epfile->buffer);
+ epfile->buffer = NULL;
+ epfile->buf_len = value;
+ if (epfile->buf_len) {
+ epfile->buffer = kzalloc(epfile->buf_len,
+ GFP_KERNEL);
+ if (!epfile->buffer)
+ ret = -ENOMEM;
+ }
+ break;
default:
ret = -ENOTTY;
}
} else {
- ret = -ENODEV;
+ switch (code) {
+ case FUNCTIONFS_ENDPOINT_ALLOC:
+ epfile->buf_len = value;
+ break;
+ default:
+ ret = -ENODEV;
+ }
}
spin_unlock_irq(&epfile->ffs->eps_lock);
@@ -1635,6 +1660,8 @@ static void ffs_func_eps_disable(struct ffs_function *func)
do {
atomic_set(&epfile->error, 1);
epfile->ep = NULL;
+ kfree(epfile->buffer);
+ epfile->buffer = NULL;
/* pending requests get nuked */
if (likely(ep->ep)) {
@@ -1677,6 +1704,14 @@ static int ffs_func_eps_enable(struct ffs_function *func)
ep->ep->driver_data = ep;
ep->ep->desc = ds;
+ if (epfile->buf_len) {
+ epfile->buffer = kzalloc(epfile->buf_len,
+ GFP_KERNEL);
+ if (!epfile->buffer) {
+ ret = -ENOMEM;
+ break;
+ }
+ }
ret = usb_ep_enable(ep->ep);
if (likely(!ret)) {
epfile->ep = ep;
diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h
index 8a17a23d0..94aba0243 100644
--- a/include/uapi/linux/usb/functionfs.h
+++ b/include/uapi/linux/usb/functionfs.h
@@ -175,6 +175,11 @@ struct usb_functionfs_event {
#define FUNCTIONFS_ENDPOINT_DESC _IOR('g', 130, \
struct usb_endpoint_descriptor)
+/*
+ * Sets a buffer length for which all r/w operations under that size use a
+ * preallocated buffer. Behavior of larger operations does not change.
+ */
+#define FUNCTIONFS_ENDPOINT_ALLOC _IOR('g', 131, __u32)
#endif /* _UAPI__LINUX_FUNCTIONFS_H__ */