diff options
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/at91_udc.c | 14 | ||||
-rw-r--r-- | drivers/usb/gadget/atmel_usba_udc.c | 16 | ||||
-rw-r--r-- | drivers/usb/gadget/atmel_usba_udc.h | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/f_fs.c | 612 | ||||
-rw-r--r-- | drivers/usb/gadget/gr_udc.c | 10 | ||||
-rw-r--r-- | drivers/usb/gadget/printer.c | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/s3c-hsotg.c | 143 | ||||
-rw-r--r-- | drivers/usb/gadget/s3c-hsudc.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/u_ether.c | 101 | ||||
-rw-r--r-- | drivers/usb/gadget/u_fs.h | 30 |
11 files changed, 684 insertions, 254 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 42f017afd366..3557c7e5040d 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -301,7 +301,6 @@ config USB_PXA27X gadget drivers to also be dynamically linked. config USB_S3C_HSOTG - depends on ARM tristate "Designware/S3C HS/OtG USB Device controller" help The Designware USB2.0 high-speed gadget controller diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index cea8c20a1425..f605ad8c1902 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1758,15 +1758,15 @@ static int at91udc_probe(struct platform_device *pdev) /* newer chips have more FIFO memory than rm9200 */ if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) { - usb_ep_set_maxpacket_limit(&udc->ep[0].ep, 64); - usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64); - usb_ep_set_maxpacket_limit(&udc->ep[4].ep, 512); - usb_ep_set_maxpacket_limit(&udc->ep[5].ep, 512); + udc->ep[0].maxpacket = 64; + udc->ep[3].maxpacket = 64; + udc->ep[4].maxpacket = 512; + udc->ep[5].maxpacket = 512; } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) { - usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64); + udc->ep[3].maxpacket = 64; } else if (cpu_is_at91sam9263()) { - usb_ep_set_maxpacket_limit(&udc->ep[0].ep, 64); - usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64); + udc->ep[0].maxpacket = 64; + udc->ep[3].maxpacket = 64; } udc->udp_baseaddr = ioremap(res->start, resource_size(res)); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 52771d4c44bc..9f65324f9ae0 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1661,7 +1661,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) if (dma_status) { int i; - for (i = 1; i < USBA_NR_ENDPOINTS; i++) + for (i = 1; i < USBA_NR_DMAS; i++) if (dma_status & (1 << i)) usba_dma_irq(udc, &udc->usba_ep[i]); } @@ -1670,7 +1670,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) if (ep_status) { int i; - for (i = 0; i < USBA_NR_ENDPOINTS; i++) + for (i = 0; i < udc->num_ep; i++) if (ep_status & (1 << i)) { if (ep_is_control(&udc->usba_ep[i])) usba_control_irq(udc, &udc->usba_ep[i]); @@ -1827,12 +1827,12 @@ static int atmel_usba_stop(struct usb_gadget *gadget, toggle_bias(0); usba_writel(udc, CTRL, USBA_DISABLE_MASK); - udc->driver = NULL; - clk_disable_unprepare(udc->hclk); clk_disable_unprepare(udc->pclk); - DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); + DBG(DBG_GADGET, "unregistered driver `%s'\n", udc->driver->driver.name); + + udc->driver = NULL; return 0; } @@ -1914,6 +1914,12 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, i++; } + if (i == 0) { + dev_err(&pdev->dev, "of_probe: no endpoint specified\n"); + ret = -EINVAL; + goto err; + } + return eps; err: return ERR_PTR(ret); diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index 2922db50befe..a70706e8cb02 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -210,7 +210,7 @@ #define USBA_FIFO_BASE(x) ((x) << 16) /* Synth parameters */ -#define USBA_NR_ENDPOINTS 7 +#define USBA_NR_DMAS 7 #define EP0_FIFO_SIZE 64 #define EP0_EPT_SIZE USBA_EPT_SIZE_64 diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 2b4334394076..10c086afa2f4 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -28,6 +28,10 @@ #include <linux/usb/composite.h> #include <linux/usb/functionfs.h> +#include <linux/aio.h> +#include <linux/mmu_context.h> +#include <linux/poll.h> + #include "u_fs.h" #include "configfs.h" @@ -99,6 +103,14 @@ static struct ffs_function *ffs_func_from_usb(struct usb_function *f) } +static inline enum ffs_setup_state +ffs_setup_state_clear_cancelled(struct ffs_data *ffs) +{ + return (enum ffs_setup_state) + cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP); +} + + static void ffs_func_eps_disable(struct ffs_function *func); static int __must_check ffs_func_eps_enable(struct ffs_function *func); @@ -122,8 +134,8 @@ struct ffs_ep { struct usb_ep *ep; /* P: ffs->eps_lock */ struct usb_request *req; /* P: epfile->mutex */ - /* [0]: full speed, [1]: high speed */ - struct usb_endpoint_descriptor *descs[2]; + /* [0]: full speed, [1]: high speed, [2]: super speed */ + struct usb_endpoint_descriptor *descs[3]; u8 num; @@ -148,6 +160,25 @@ struct ffs_epfile { unsigned char _pad; }; +/* ffs_io_data structure ***************************************************/ + +struct ffs_io_data { + bool aio; + bool read; + + struct kiocb *kiocb; + const struct iovec *iovec; + unsigned long nr_segs; + char __user *buf; + size_t len; + + struct mm_struct *mm; + struct work_struct work; + + struct usb_ep *ep; + struct usb_request *req; +}; + static int __must_check ffs_epfiles_create(struct ffs_data *ffs); static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count); @@ -161,8 +192,10 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data, DEFINE_MUTEX(ffs_lock); EXPORT_SYMBOL(ffs_lock); -static struct ffs_dev *ffs_find_dev(const char *name); +static struct ffs_dev *_ffs_find_dev(const char *name); +static struct ffs_dev *_ffs_alloc_dev(void); static int _ffs_name_dev(struct ffs_dev *dev, const char *name); +static void _ffs_free_dev(struct ffs_dev *dev); static void *ffs_acquire_dev(const char *dev_name); static void ffs_release_dev(struct ffs_data *ffs_data); static int ffs_ready(struct ffs_data *ffs); @@ -218,7 +251,7 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) } ffs->setup_state = FFS_NO_SETUP; - return ffs->ep0req_status; + return req->status ? req->status : req->actual; } static int __ffs_ep0_stall(struct ffs_data *ffs) @@ -244,7 +277,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ENTER(); /* Fast check if setup was canceled */ - if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) + if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; /* Acquire mutex */ @@ -310,8 +343,8 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, * rather then _irqsave */ spin_lock_irq(&ffs->ev.waitq.lock); - switch (FFS_SETUP_STATE(ffs)) { - case FFS_SETUP_CANCELED: + switch (ffs_setup_state_clear_cancelled(ffs)) { + case FFS_SETUP_CANCELLED: ret = -EIDRM; goto done_spin; @@ -346,7 +379,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, /* * We are guaranteed to be still in FFS_ACTIVE state * but the state of setup could have changed from - * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need + * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need * to check for that. If that happened we copied data * from user space in vain but it's unlikely. * @@ -355,7 +388,8 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, * transition can be performed and it's protected by * mutex. */ - if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { + if (ffs_setup_state_clear_cancelled(ffs) == + FFS_SETUP_CANCELLED) { ret = -EIDRM; done_spin: spin_unlock_irq(&ffs->ev.waitq.lock); @@ -421,7 +455,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, ENTER(); /* Fast check if setup was canceled */ - if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) + if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; /* Acquire mutex */ @@ -441,8 +475,8 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, */ spin_lock_irq(&ffs->ev.waitq.lock); - switch (FFS_SETUP_STATE(ffs)) { - case FFS_SETUP_CANCELED: + switch (ffs_setup_state_clear_cancelled(ffs)) { + case FFS_SETUP_CANCELLED: ret = -EIDRM; break; @@ -489,7 +523,8 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, spin_lock_irq(&ffs->ev.waitq.lock); /* See ffs_ep0_write() */ - if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { + if (ffs_setup_state_clear_cancelled(ffs) == + FFS_SETUP_CANCELLED) { ret = -EIDRM; break; } @@ -558,6 +593,45 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) return ret; } +static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait) +{ + struct ffs_data *ffs = file->private_data; + unsigned int mask = POLLWRNORM; + int ret; + + poll_wait(file, &ffs->ev.waitq, wait); + + ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); + if (unlikely(ret < 0)) + return mask; + + switch (ffs->state) { + case FFS_READ_DESCRIPTORS: + case FFS_READ_STRINGS: + mask |= POLLOUT; + break; + + case FFS_ACTIVE: + switch (ffs->setup_state) { + case FFS_NO_SETUP: + if (ffs->ev.count) + mask |= POLLIN; + break; + + case FFS_SETUP_PENDING: + case FFS_SETUP_CANCELLED: + mask |= (POLLIN | POLLOUT); + break; + } + case FFS_CLOSING: + break; + } + + mutex_unlock(&ffs->mutex); + + return mask; +} + static const struct file_operations ffs_ep0_operations = { .llseek = no_llseek, @@ -566,6 +640,7 @@ static const struct file_operations ffs_ep0_operations = { .read = ffs_ep0_read, .release = ffs_ep0_release, .unlocked_ioctl = ffs_ep0_ioctl, + .poll = ffs_ep0_poll, }; @@ -581,8 +656,52 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) } } -static ssize_t ffs_epfile_io(struct file *file, - char __user *buf, size_t len, int read) +static void ffs_user_copy_worker(struct work_struct *work) +{ + struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, + work); + int ret = io_data->req->status ? io_data->req->status : + io_data->req->actual; + + if (io_data->read && ret > 0) { + int i; + size_t pos = 0; + use_mm(io_data->mm); + for (i = 0; i < io_data->nr_segs; i++) { + if (unlikely(copy_to_user(io_data->iovec[i].iov_base, + &io_data->buf[pos], + io_data->iovec[i].iov_len))) { + ret = -EFAULT; + break; + } + pos += io_data->iovec[i].iov_len; + } + unuse_mm(io_data->mm); + } + + aio_complete(io_data->kiocb, ret, ret); + + usb_ep_free_request(io_data->ep, io_data->req); + + io_data->kiocb->private = NULL; + if (io_data->read) + kfree(io_data->iovec); + kfree(io_data->buf); + kfree(io_data); +} + +static void ffs_epfile_async_io_complete(struct usb_ep *_ep, + struct usb_request *req) +{ + struct ffs_io_data *io_data = req->context; + + ENTER(); + + INIT_WORK(&io_data->work, ffs_user_copy_worker); + schedule_work(&io_data->work); +} + +static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) { struct ffs_epfile *epfile = file->private_data; struct ffs_ep *ep; @@ -612,7 +731,7 @@ static ssize_t ffs_epfile_io(struct file *file, } /* Do we halt? */ - halt = !read == !epfile->in; + halt = (!io_data->read == !epfile->in); if (halt && epfile->isoc) { ret = -EINVAL; goto error; @@ -630,15 +749,32 @@ static ssize_t ffs_epfile_io(struct file *file, * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint. */ - data_len = read ? usb_ep_align_maybe(gadget, ep->ep, len) : len; + data_len = io_data->read ? + usb_ep_align_maybe(gadget, ep->ep, io_data->len) : + io_data->len; data = kmalloc(data_len, GFP_KERNEL); if (unlikely(!data)) return -ENOMEM; - - if (!read && unlikely(copy_from_user(data, buf, len))) { - ret = -EFAULT; - goto error; + if (io_data->aio && !io_data->read) { + int i; + size_t pos = 0; + for (i = 0; i < io_data->nr_segs; i++) { + if (unlikely(copy_from_user(&data[pos], + io_data->iovec[i].iov_base, + io_data->iovec[i].iov_len))) { + ret = -EFAULT; + goto error; + } + pos += io_data->iovec[i].iov_len; + } + } else { + if (!io_data->read && + unlikely(__copy_from_user(data, io_data->buf, + io_data->len))) { + ret = -EFAULT; + goto error; + } } } @@ -661,40 +797,74 @@ static ssize_t ffs_epfile_io(struct file *file, ret = -EBADMSG; } else { /* Fire the request */ - DECLARE_COMPLETION_ONSTACK(done); + struct usb_request *req; - struct usb_request *req = ep->req; - req->context = &done; - req->complete = ffs_epfile_io_complete; - req->buf = data; - req->length = data_len; + if (io_data->aio) { + req = usb_ep_alloc_request(ep->ep, GFP_KERNEL); + if (unlikely(!req)) + goto error; - ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); + req->buf = data; + req->length = io_data->len; - spin_unlock_irq(&epfile->ffs->eps_lock); + io_data->buf = data; + io_data->ep = ep->ep; + io_data->req = req; - if (unlikely(ret < 0)) { - /* nop */ - } else if (unlikely(wait_for_completion_interruptible(&done))) { - ret = -EINTR; - usb_ep_dequeue(ep->ep, req); + req->context = io_data; + req->complete = ffs_epfile_async_io_complete; + + ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); + if (unlikely(ret)) { + usb_ep_free_request(ep->ep, req); + goto error; + } + ret = -EIOCBQUEUED; + + spin_unlock_irq(&epfile->ffs->eps_lock); } else { - /* - * XXX We may end up silently droping data here. - * Since data_len (i.e. req->length) may be bigger - * than len (after being rounded up to maxpacketsize), - * we may end up with more data then user space has - * space for. - */ - ret = ep->status; - if (read && ret > 0 && - unlikely(copy_to_user(buf, data, - min_t(size_t, ret, len)))) - ret = -EFAULT; + DECLARE_COMPLETION_ONSTACK(done); + + req = ep->req; + req->buf = data; + req->length = io_data->len; + + req->context = &done; + req->complete = ffs_epfile_io_complete; + + ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); + + spin_unlock_irq(&epfile->ffs->eps_lock); + + if (unlikely(ret < 0)) { + /* nop */ + } else if (unlikely( + wait_for_completion_interruptible(&done))) { + ret = -EINTR; + usb_ep_dequeue(ep->ep, req); + } else { + /* + * XXX We may end up silently droping data + * here. Since data_len (i.e. req->length) may + * be bigger than len (after being rounded up + * to maxpacketsize), we may end up with more + * data then user space has space for. + */ + ret = ep->status; + if (io_data->read && ret > 0) { + ret = min_t(size_t, ret, io_data->len); + + if (unlikely(copy_to_user(io_data->buf, + data, ret))) + ret = -EFAULT; + } + } + kfree(data); } } mutex_unlock(&epfile->mutex); + return ret; error: kfree(data); return ret; @@ -704,17 +874,31 @@ static ssize_t ffs_epfile_write(struct file *file, const char __user *buf, size_t len, loff_t *ptr) { + struct ffs_io_data io_data; + ENTER(); - return ffs_epfile_io(file, (char __user *)buf, len, 0); + io_data.aio = false; + io_data.read = false; + io_data.buf = (char * __user)buf; + io_data.len = len; + + return ffs_epfile_io(file, &io_data); } static ssize_t ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) { + struct ffs_io_data io_data; + ENTER(); - return ffs_epfile_io(file, buf, len, 1); + io_data.aio = false; + io_data.read = true; + io_data.buf = buf; + io_data.len = len; + + return ffs_epfile_io(file, &io_data); } static int @@ -733,6 +917,89 @@ ffs_epfile_open(struct inode *inode, struct file *file) return 0; } +static int ffs_aio_cancel(struct kiocb *kiocb) +{ + struct ffs_io_data *io_data = kiocb->private; + struct ffs_epfile *epfile = kiocb->ki_filp->private_data; + int value; + + ENTER(); + + spin_lock_irq(&epfile->ffs->eps_lock); + + if (likely(io_data && io_data->ep && io_data->req)) + value = usb_ep_dequeue(io_data->ep, io_data->req); + else + value = -EINVAL; + + spin_unlock_irq(&epfile->ffs->eps_lock); + + return value; +} + +static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, + const struct iovec *iovec, + unsigned long nr_segs, loff_t loff) +{ + struct ffs_io_data *io_data; + + ENTER(); + + io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); + if (unlikely(!io_data)) + return -ENOMEM; + + io_data->aio = true; + io_data->read = false; + io_data->kiocb = kiocb; + io_data->iovec = iovec; + io_data->nr_segs = nr_segs; + io_data->len = kiocb->ki_nbytes; + io_data->mm = current->mm; + + kiocb->private = io_data; + + kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); + + return ffs_epfile_io(kiocb->ki_filp, io_data); +} + +static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, + const struct iovec *iovec, + unsigned long nr_segs, loff_t loff) +{ + struct ffs_io_data *io_data; + struct iovec *iovec_copy; + + ENTER(); + + iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL); + if (unlikely(!iovec_copy)) + return -ENOMEM; + + memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs); + + io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); + if (unlikely(!io_data)) { + kfree(iovec_copy); + return -ENOMEM; + } + + io_data->aio = true; + io_data->read = true; + io_data->kiocb = kiocb; + io_data->iovec = iovec_copy; + io_data->nr_segs = nr_segs; + io_data->len = kiocb->ki_nbytes; + io_data->mm = current->mm; + + kiocb->private = io_data; + + kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); + + return ffs_epfile_io(kiocb->ki_filp, io_data); +} + static int ffs_epfile_release(struct inode *inode, struct file *file) { @@ -789,6 +1056,8 @@ static const struct file_operations ffs_epfile_operations = { .open = ffs_epfile_open, .write = ffs_epfile_write, .read = ffs_epfile_read, + .aio_write = ffs_epfile_aio_write, + .aio_read = ffs_epfile_aio_read, .release = ffs_epfile_release, .unlocked_ioctl = ffs_epfile_ioctl, }; @@ -1172,7 +1441,7 @@ static void ffs_data_clear(struct ffs_data *ffs) if (ffs->epfiles) ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); - kfree(ffs->raw_descs); + kfree(ffs->raw_descs_data); kfree(ffs->raw_strings); kfree(ffs->stringtabs); } @@ -1184,14 +1453,15 @@ static void ffs_data_reset(struct ffs_data *ffs) ffs_data_clear(ffs); ffs->epfiles = NULL; + ffs->raw_descs_data = NULL; ffs->raw_descs = NULL; ffs->raw_strings = NULL; ffs->stringtabs = NULL; ffs->raw_descs_length = 0; - ffs->raw_fs_descs_length = 0; ffs->fs_descs_count = 0; ffs->hs_descs_count = 0; + ffs->ss_descs_count = 0; ffs->strings_count = 0; ffs->interfaces_count = 0; @@ -1334,7 +1604,24 @@ static int ffs_func_eps_enable(struct ffs_function *func) spin_lock_irqsave(&func->ffs->eps_lock, flags); do { struct usb_endpoint_descriptor *ds; - ds = ep->descs[ep->descs[1] ? 1 : 0]; + int desc_idx; + + if (ffs->gadget->speed == USB_SPEED_SUPER) + desc_idx = 2; + else if (ffs->gadget->speed == USB_SPEED_HIGH) + desc_idx = 1; + else + desc_idx = 0; + + /* fall-back to lower speed if desc missing for current speed */ + do { + ds = ep->descs[desc_idx]; + } while (!ds && --desc_idx >= 0); + + if (!ds) { + ret = -EINVAL; + break; + } ep->ep->driver_data = ep; ep->ep->desc = ds; @@ -1469,6 +1756,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len, } break; + case USB_DT_SS_ENDPOINT_COMP: + pr_vdebug("EP SS companion descriptor\n"); + if (length != sizeof(struct usb_ss_ep_comp_descriptor)) + goto inv_length; + break; + case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_INTERFACE_POWER: case USB_DT_DEBUG: @@ -1579,60 +1872,76 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, static int __ffs_data_got_descs(struct ffs_data *ffs, char *const _data, size_t len) { - unsigned fs_count, hs_count; - int fs_len, ret = -EINVAL; - char *data = _data; + char *data = _data, *raw_descs; + unsigned counts[3], flags; + int ret = -EINVAL, i; ENTER(); - if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC || - get_unaligned_le32(data + 4) != len)) + if (get_unaligned_le32(data + 4) != len) goto error; - fs_count = get_unaligned_le32(data + 8); - hs_count = get_unaligned_le32(data + 12); - - if (!fs_count && !hs_count) - goto einval; - data += 16; - len -= 16; - - if (likely(fs_count)) { - fs_len = ffs_do_descs(fs_count, data, len, - __ffs_data_do_entity, ffs); - if (unlikely(fs_len < 0)) { - ret = fs_len; + switch (get_unaligned_le32(data)) { + case FUNCTIONFS_DESCRIPTORS_MAGIC: + flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC; + data += 8; + len -= 8; + break; + case FUNCTIONFS_DESCRIPTORS_MAGIC_V2: + flags = get_unaligned_le32(data + 8); + if (flags & ~(FUNCTIONFS_HAS_FS_DESC | + FUNCTIONFS_HAS_HS_DESC | + FUNCTIONFS_HAS_SS_DESC)) { + ret = -ENOSYS; goto error; } + data += 12; + len -= 12; + break; + default: + goto error; + } - data += fs_len; - len -= fs_len; - } else { - fs_len = 0; + /* Read fs_count, hs_count and ss_count (if present) */ + for (i = 0; i < 3; ++i) { + if (!(flags & (1 << i))) { + counts[i] = 0; + } else if (len < 4) { + goto error; + } else { + counts[i] = get_unaligned_le32(data); + data += 4; + len -= 4; + } } - if (likely(hs_count)) { - ret = ffs_do_descs(hs_count, data, len, + /* Read descriptors */ + raw_descs = data; + for (i = 0; i < 3; ++i) { + if (!counts[i]) + continue; + ret = ffs_do_descs(counts[i], data, len, __ffs_data_do_entity, ffs); - if (unlikely(ret < 0)) + if (ret < 0) goto error; - } else { - ret = 0; + data += ret; + len -= ret; } - if (unlikely(len != ret)) - goto einval; + if (raw_descs == data || len) { + ret = -EINVAL; + goto error; + } - ffs->raw_fs_descs_length = fs_len; - ffs->raw_descs_length = fs_len + ret; - ffs->raw_descs = _data; - ffs->fs_descs_count = fs_count; - ffs->hs_descs_count = hs_count; + ffs->raw_descs_data = _data; + ffs->raw_descs = raw_descs; + ffs->raw_descs_length = data - raw_descs; + ffs->fs_descs_count = counts[0]; + ffs->hs_descs_count = counts[1]; + ffs->ss_descs_count = counts[2]; return 0; -einval: - ret = -EINVAL; error: kfree(_data); return ret; @@ -1789,7 +2098,7 @@ static void __ffs_event_add(struct ffs_data *ffs, * the source does nothing. */ if (ffs->setup_state == FFS_SETUP_PENDING) - ffs->setup_state = FFS_SETUP_CANCELED; + ffs->setup_state = FFS_SETUP_CANCELLED; switch (type) { case FUNCTIONFS_RESUME: @@ -1850,21 +2159,28 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, struct usb_endpoint_descriptor *ds = (void *)desc; struct ffs_function *func = priv; struct ffs_ep *ffs_ep; - - /* - * If hs_descriptors is not NULL then we are reading hs - * descriptors now - */ - const int isHS = func->function.hs_descriptors != NULL; - unsigned idx; + unsigned ep_desc_id, idx; + static const char *speed_names[] = { "full", "high", "super" }; if (type != FFS_DESCRIPTOR) return 0; - if (isHS) + /* + * If ss_descriptors is not NULL, we are reading super speed + * descriptors; if hs_descriptors is not NULL, we are reading high + * speed descriptors; otherwise, we are reading full speed + * descriptors. + */ + if (func->function.ss_descriptors) { + ep_desc_id = 2; + func->function.ss_descriptors[(long)valuep] = desc; + } else if (func->function.hs_descriptors) { + ep_desc_id = 1; func->function.hs_descriptors[(long)valuep] = desc; - else + } else { + ep_desc_id = 0; func->function.fs_descriptors[(long)valuep] = desc; + } if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) return 0; @@ -1872,13 +2188,13 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1; ffs_ep = func->eps + idx; - if (unlikely(ffs_ep->descs[isHS])) { - pr_vdebug("two %sspeed descriptors for EP %d\n", - isHS ? "high" : "full", + if (unlikely(ffs_ep->descs[ep_desc_id])) { + pr_err("two %sspeed descriptors for EP %d\n", + speed_names[ep_desc_id], ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); return -EINVAL; } - ffs_ep->descs[isHS] = ds; + ffs_ep->descs[ep_desc_id] = ds; ffs_dump_mem(": Original ep desc", ds, ds->bLength); if (ffs_ep->ep) { @@ -2022,8 +2338,10 @@ static int _ffs_func_bind(struct usb_configuration *c, const int full = !!func->ffs->fs_descs_count; const int high = gadget_is_dualspeed(func->gadget) && func->ffs->hs_descs_count; + const int super = gadget_is_superspeed(func->gadget) && + func->ffs->ss_descs_count; - int ret; + int fs_len, hs_len, ret; /* Make it a single chunk, less management later on */ vla_group(d); @@ -2032,15 +2350,16 @@ static int _ffs_func_bind(struct usb_configuration *c, full ? ffs->fs_descs_count + 1 : 0); vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs, high ? ffs->hs_descs_count + 1 : 0); + vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, + super ? ffs->ss_descs_count + 1 : 0); vla_item_with_sz(d, short, inums, ffs->interfaces_count); - vla_item_with_sz(d, char, raw_descs, - high ? ffs->raw_descs_length : ffs->raw_fs_descs_length); + vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); char *vlabuf; ENTER(); - /* Only high speed but not supported by gadget? */ - if (unlikely(!(full | high))) + /* Has descriptors only for speeds gadget does not support */ + if (unlikely(!(full | high | super))) return -ENOTSUPP; /* Allocate a single chunk, less management later on */ @@ -2050,8 +2369,10 @@ static int _ffs_func_bind(struct usb_configuration *c, /* Zero */ memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz); - memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16, - d_raw_descs__sz); + /* Copy descriptors */ + memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs, + ffs->raw_descs_length); + memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); for (ret = ffs->eps_count; ret; --ret) { struct ffs_ep *ptr; @@ -2073,22 +2394,38 @@ static int _ffs_func_bind(struct usb_configuration *c, */ if (likely(full)) { func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs); - ret = ffs_do_descs(ffs->fs_descs_count, - vla_ptr(vlabuf, d, raw_descs), - d_raw_descs__sz, - __ffs_func_bind_do_descs, func); - if (unlikely(ret < 0)) + fs_len = ffs_do_descs(ffs->fs_descs_count, + vla_ptr(vlabuf, d, raw_descs), + d_raw_descs__sz, + __ffs_func_bind_do_descs, func); + if (unlikely(fs_len < 0)) { + ret = fs_len; goto error; + } } else { - ret = 0; + fs_len = 0; } if (likely(high)) { func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs); - ret = ffs_do_descs(ffs->hs_descs_count, - vla_ptr(vlabuf, d, raw_descs) + ret, - d_raw_descs__sz - ret, - __ffs_func_bind_do_descs, func); + hs_len = ffs_do_descs(ffs->hs_descs_count, + vla_ptr(vlabuf, d, raw_descs) + fs_len, + d_raw_descs__sz - fs_len, + __ffs_func_bind_do_descs, func); + if (unlikely(hs_len < 0)) { + ret = hs_len; + goto error; + } + } else { + hs_len = 0; + } + + if (likely(super)) { + func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs); + ret = ffs_do_descs(ffs->ss_descs_count, + vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len, + d_raw_descs__sz - fs_len - hs_len, + __ffs_func_bind_do_descs, func); if (unlikely(ret < 0)) goto error; } @@ -2099,7 +2436,8 @@ static int _ffs_func_bind(struct usb_configuration *c, * now. */ ret = ffs_do_descs(ffs->fs_descs_count + - (high ? ffs->hs_descs_count : 0), + (high ? ffs->hs_descs_count : 0) + + (super ? ffs->ss_descs_count : 0), vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz, __ffs_func_bind_do_nums, func); if (unlikely(ret < 0)) @@ -2258,7 +2596,7 @@ static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf) static LIST_HEAD(ffs_devices); -static struct ffs_dev *_ffs_find_dev(const char *name) +static struct ffs_dev *_ffs_do_find_dev(const char *name) { struct ffs_dev *dev; @@ -2275,7 +2613,7 @@ static struct ffs_dev *_ffs_find_dev(const char *name) /* * ffs_lock must be taken by the caller of this function */ -static struct ffs_dev *ffs_get_single_dev(void) +static struct ffs_dev *_ffs_get_single_dev(void) { struct ffs_dev *dev; @@ -2291,15 +2629,15 @@ static struct ffs_dev *ffs_get_single_dev(void) /* * ffs_lock must be taken by the caller of this function */ -static struct ffs_dev *ffs_find_dev(const char *name) +static struct ffs_dev *_ffs_find_dev(const char *name) { struct ffs_dev *dev; - dev = ffs_get_single_dev(); + dev = _ffs_get_single_dev(); if (dev) return dev; - return _ffs_find_dev(name); + return _ffs_do_find_dev(name); } /* Configfs support *********************************************************/ @@ -2335,7 +2673,7 @@ static void ffs_free_inst(struct usb_function_instance *f) opts = to_f_fs_opts(f); ffs_dev_lock(); - ffs_free_dev(opts->dev); + _ffs_free_dev(opts->dev); ffs_dev_unlock(); kfree(opts); } @@ -2390,7 +2728,7 @@ static struct usb_function_instance *ffs_alloc_inst(void) opts->func_inst.set_inst_name = ffs_set_inst_name; opts->func_inst.free_func_inst = ffs_free_inst; ffs_dev_lock(); - dev = ffs_alloc_dev(); + dev = _ffs_alloc_dev(); ffs_dev_unlock(); if (IS_ERR(dev)) { kfree(opts); @@ -2446,6 +2784,7 @@ static void ffs_func_unbind(struct usb_configuration *c, */ func->function.fs_descriptors = NULL; func->function.hs_descriptors = NULL; + func->function.ss_descriptors = NULL; func->interfaces_nums = NULL; ffs_event_add(ffs, FUNCTIONFS_UNBIND); @@ -2478,12 +2817,12 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi) /* * ffs_lock must be taken by the caller of this function */ -struct ffs_dev *ffs_alloc_dev(void) +static struct ffs_dev *_ffs_alloc_dev(void) { struct ffs_dev *dev; int ret; - if (ffs_get_single_dev()) + if (_ffs_get_single_dev()) return ERR_PTR(-EBUSY); dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -2511,10 +2850,10 @@ static int _ffs_name_dev(struct ffs_dev *dev, const char *name) { struct ffs_dev *existing; - existing = _ffs_find_dev(name); + existing = _ffs_do_find_dev(name); if (existing) return -EBUSY; - + dev->name = name; return 0; @@ -2555,7 +2894,7 @@ EXPORT_SYMBOL(ffs_single_dev); /* * ffs_lock must be taken by the caller of this function */ -void ffs_free_dev(struct ffs_dev *dev) +static void _ffs_free_dev(struct ffs_dev *dev) { list_del(&dev->entry); if (dev->name_allocated) @@ -2572,7 +2911,7 @@ static void *ffs_acquire_dev(const char *dev_name) ENTER(); ffs_dev_lock(); - ffs_dev = ffs_find_dev(dev_name); + ffs_dev = _ffs_find_dev(dev_name); if (!ffs_dev) ffs_dev = ERR_PTR(-ENODEV); else if (ffs_dev->mounted) @@ -2595,11 +2934,12 @@ static void ffs_release_dev(struct ffs_data *ffs_data) ffs_dev_lock(); ffs_dev = ffs_data->private_data; - if (ffs_dev) + if (ffs_dev) { ffs_dev->mounted = false; - - if (ffs_dev->ffs_release_dev_callback) - ffs_dev->ffs_release_dev_callback(ffs_dev); + + if (ffs_dev->ffs_release_dev_callback) + ffs_dev->ffs_release_dev_callback(ffs_dev); + } ffs_dev_unlock(); } diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c index 914cbd84ee40..f984ee75324d 100644 --- a/drivers/usb/gadget/gr_udc.c +++ b/drivers/usb/gadget/gr_udc.c @@ -225,14 +225,8 @@ static void gr_dfs_create(struct gr_udc *dev) const char *name = "gr_udc_state"; dev->dfs_root = debugfs_create_dir(dev_name(dev->dev), NULL); - if (IS_ERR(dev->dfs_root)) { - dev_err(dev->dev, "Failed to create debugfs directory\n"); - return; - } - dev->dfs_state = debugfs_create_file(name, 0444, dev->dfs_root, - dev, &gr_dfs_fops); - if (IS_ERR(dev->dfs_state)) - dev_err(dev->dev, "Failed to create debugfs file %s\n", name); + dev->dfs_state = debugfs_create_file(name, 0444, dev->dfs_root, dev, + &gr_dfs_fops); } static void gr_dfs_delete(struct gr_udc *dev) diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 69b76efd11e9..6474081dcbaf 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -427,12 +427,17 @@ setup_rx_reqs(struct printer_dev *dev) req->length = USB_BUFSIZE; req->complete = rx_complete; + /* here, we unlock, and only unlock, to avoid deadlock. */ + spin_unlock(&dev->lock); error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC); + spin_lock(&dev->lock); if (error) { DBG(dev, "rx submit --> %d\n", error); list_add(&req->list, &dev->rx_reqs); break; - } else { + } + /* if the req is empty, then add it into dev->rx_reqs_active. */ + else if (list_empty(&req->list)) { list_add(&req->list, &dev->rx_reqs_active); } } @@ -1133,6 +1138,7 @@ static int __init printer_bind_config(struct usb_configuration *c) NULL, "g_printer"); if (IS_ERR(dev->pdev)) { ERROR(dev, "Failed to create device: g_printer\n"); + status = PTR_ERR(dev->pdev); goto fail; } diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 1172eaeddd85..2a9cb674926a 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -617,7 +617,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, to_write = DIV_ROUND_UP(to_write, 4); data = hs_req->req.buf + buf_pos; - writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); + iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); return (to_write >= can_write) ? -ENOSPC : 0; } @@ -720,8 +720,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, ureq->length, ureq->actual); if (0) dev_dbg(hsotg->dev, - "REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n", - ureq->buf, length, ureq->dma, + "REQ buf %p len %d dma 0x%pad noi=%d zp=%d snok=%d\n", + ureq->buf, length, &ureq->dma, ureq->no_interrupt, ureq->zero, ureq->short_not_ok); maxreq = get_ep_limit(hs_ep); @@ -789,8 +789,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); writel(ureq->dma, hsotg->regs + dma_reg); - dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n", - __func__, ureq->dma, dma_reg); + dev_dbg(hsotg->dev, "%s: 0x%pad => 0x%08x\n", + __func__, &ureq->dma, dma_reg); } ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ @@ -1186,6 +1186,41 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg); /** + * s3c_hsotg_stall_ep0 - stall ep0 + * @hsotg: The device state + * + * Set stall for ep0 as response for setup request. + */ +static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) { + struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; + u32 reg; + u32 ctrl; + + dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); + reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; + + /* + * DxEPCTL_Stall will be cleared by EP once it has + * taken effect, so no need to clear later. + */ + + ctrl = readl(hsotg->regs + reg); + ctrl |= DxEPCTL_Stall; + ctrl |= DxEPCTL_CNAK; + writel(ctrl, hsotg->regs + reg); + + dev_dbg(hsotg->dev, + "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", + ctrl, reg, readl(hsotg->regs + reg)); + + /* + * complete won't be called, so we enqueue + * setup request here + */ + s3c_hsotg_enqueue_setup(hsotg); +} + +/** * s3c_hsotg_process_control - process a control request * @hsotg: The device state * @ctrl: The control request received @@ -1262,38 +1297,8 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, * so respond with a STALL for the status stage to indicate failure. */ - if (ret < 0) { - u32 reg; - u32 ctrl; - - dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); - reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; - - /* - * DxEPCTL_Stall will be cleared by EP once it has - * taken effect, so no need to clear later. - */ - - ctrl = readl(hsotg->regs + reg); - ctrl |= DxEPCTL_Stall; - ctrl |= DxEPCTL_CNAK; - writel(ctrl, hsotg->regs + reg); - - dev_dbg(hsotg->dev, - "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", - ctrl, reg, readl(hsotg->regs + reg)); - - /* - * don't believe we need to anything more to get the EP - * to reply with a STALL packet - */ - - /* - * complete won't be called, so we enqueue - * setup request here - */ - s3c_hsotg_enqueue_setup(hsotg); - } + if (ret < 0) + s3c_hsotg_stall_ep0(hsotg); } /** @@ -1488,7 +1493,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) * note, we might over-write the buffer end by 3 bytes depending on * alignment of the data. */ - readsl(fifo, hs_req->req.buf + read_ptr, to_read); + ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read); } /** @@ -2832,6 +2837,15 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); + if (index == 0) { + if (value) + s3c_hsotg_stall_ep0(hs); + else + dev_warn(hs->dev, + "%s: can't clear halt on ep0\n", __func__); + return 0; + } + /* write both IN and OUT control registers */ epreg = DIEPCTL(index); @@ -3760,10 +3774,55 @@ static int s3c_hsotg_remove(struct platform_device *pdev) return 0; } -#if 1 -#define s3c_hsotg_suspend NULL -#define s3c_hsotg_resume NULL -#endif +static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); + unsigned long flags; + int ret = 0; + + if (hsotg->driver) + dev_info(hsotg->dev, "suspending usb gadget %s\n", + hsotg->driver->driver.name); + + spin_lock_irqsave(&hsotg->lock, flags); + s3c_hsotg_disconnect(hsotg); + s3c_hsotg_phy_disable(hsotg); + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + spin_unlock_irqrestore(&hsotg->lock, flags); + + if (hsotg->driver) { + int ep; + for (ep = 0; ep < hsotg->num_of_eps; ep++) + s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); + + ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + } + + return ret; +} + +static int s3c_hsotg_resume(struct platform_device *pdev) +{ + struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); + unsigned long flags; + int ret = 0; + + if (hsotg->driver) { + dev_info(hsotg->dev, "resuming usb gadget %s\n", + hsotg->driver->driver.name); + ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + } + + spin_lock_irqsave(&hsotg->lock, flags); + hsotg->last_rst = jiffies; + s3c_hsotg_phy_enable(hsotg); + s3c_hsotg_core_init(hsotg); + spin_unlock_irqrestore(&hsotg->lock, flags); + + return ret; +} #ifdef CONFIG_OF static const struct of_device_id s3c_hsotg_of_ids[] = { diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index ea4bbfe72ec0..10c6a128250c 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1344,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev) return 0; err_add_udc: -err_add_device: clk_disable(hsudc->uclk); err_res: if (!IS_ERR_OR_NULL(hsudc->transceiver)) diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index b7d4f82872b7..50d09c289137 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -48,6 +48,8 @@ #define UETH__VERSION "29-May-2008" +#define GETHER_NAPI_WEIGHT 32 + struct eth_dev { /* lock is held while accessing port_usb */ @@ -72,6 +74,7 @@ struct eth_dev { struct sk_buff_head *list); struct work_struct work; + struct napi_struct rx_napi; unsigned long todo; #define WORK_RX_MEMORY 0 @@ -253,18 +256,16 @@ enomem: DBG(dev, "rx submit --> %d\n", retval); if (skb) dev_kfree_skb_any(skb); - spin_lock_irqsave(&dev->req_lock, flags); - list_add(&req->list, &dev->rx_reqs); - spin_unlock_irqrestore(&dev->req_lock, flags); } return retval; } static void rx_complete(struct usb_ep *ep, struct usb_request *req) { - struct sk_buff *skb = req->context, *skb2; + struct sk_buff *skb = req->context; struct eth_dev *dev = ep->driver_data; int status = req->status; + bool rx_queue = 0; switch (status) { @@ -288,30 +289,8 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) } else { skb_queue_tail(&dev->rx_frames, skb); } - skb = NULL; - - skb2 = skb_dequeue(&dev->rx_frames); - while (skb2) { - if (status < 0 - || ETH_HLEN > skb2->len - || skb2->len > VLAN_ETH_FRAME_LEN) { - dev->net->stats.rx_errors++; - dev->net->stats.rx_length_errors++; - DBG(dev, "rx length %d\n", skb2->len); - dev_kfree_skb_any(skb2); - goto next_frame; - } - skb2->protocol = eth_type_trans(skb2, dev->net); - dev->net->stats.rx_packets++; - dev->net->stats.rx_bytes += skb2->len; - - /* no buffer copies needed, unless hardware can't - * use skb buffers. - */ - status = netif_rx(skb2); -next_frame: - skb2 = skb_dequeue(&dev->rx_frames); - } + if (!status) + rx_queue = 1; break; /* software-driven interface shutdown */ @@ -334,22 +313,20 @@ quiesce: /* FALLTHROUGH */ default: + rx_queue = 1; + dev_kfree_skb_any(skb); dev->net->stats.rx_errors++; DBG(dev, "rx status %d\n", status); break; } - if (skb) - dev_kfree_skb_any(skb); - if (!netif_running(dev->net)) { clean: spin_lock(&dev->req_lock); list_add(&req->list, &dev->rx_reqs); spin_unlock(&dev->req_lock); - req = NULL; - } - if (req) - rx_submit(dev, req, GFP_ATOMIC); + + if (rx_queue && likely(napi_schedule_prep(&dev->rx_napi))) + __napi_schedule(&dev->rx_napi); } static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) @@ -414,16 +391,24 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) { struct usb_request *req; unsigned long flags; + int rx_counts = 0; /* fill unused rxq slots with some skb */ spin_lock_irqsave(&dev->req_lock, flags); while (!list_empty(&dev->rx_reqs)) { + + if (++rx_counts > qlen(dev->gadget, dev->qmult)) + break; + req = container_of(dev->rx_reqs.next, struct usb_request, list); list_del_init(&req->list); spin_unlock_irqrestore(&dev->req_lock, flags); if (rx_submit(dev, req, gfp_flags) < 0) { + spin_lock_irqsave(&dev->req_lock, flags); + list_add(&req->list, &dev->rx_reqs); + spin_unlock_irqrestore(&dev->req_lock, flags); defer_kevent(dev, WORK_RX_MEMORY); return; } @@ -433,6 +418,41 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) spin_unlock_irqrestore(&dev->req_lock, flags); } +static int gether_poll(struct napi_struct *napi, int budget) +{ + struct eth_dev *dev = container_of(napi, struct eth_dev, rx_napi); + struct sk_buff *skb; + unsigned int work_done = 0; + int status = 0; + + while ((skb = skb_dequeue(&dev->rx_frames))) { + if (status < 0 + || ETH_HLEN > skb->len + || skb->len > VLAN_ETH_FRAME_LEN) { + dev->net->stats.rx_errors++; + dev->net->stats.rx_length_errors++; + DBG(dev, "rx length %d\n", skb->len); + dev_kfree_skb_any(skb); + continue; + } + skb->protocol = eth_type_trans(skb, dev->net); + dev->net->stats.rx_packets++; + dev->net->stats.rx_bytes += skb->len; + + status = netif_rx_ni(skb); + } + + if (netif_running(dev->net)) { + rx_fill(dev, GFP_KERNEL); + work_done++; + } + + if (work_done < budget) + napi_complete(&dev->rx_napi); + + return work_done; +} + static void eth_work(struct work_struct *work) { struct eth_dev *dev = container_of(work, struct eth_dev, work); @@ -625,6 +645,7 @@ static void eth_start(struct eth_dev *dev, gfp_t gfp_flags) /* and open the tx floodgates */ atomic_set(&dev->tx_qlen, 0); netif_wake_queue(dev->net); + napi_enable(&dev->rx_napi); } static int eth_open(struct net_device *net) @@ -651,6 +672,7 @@ static int eth_stop(struct net_device *net) unsigned long flags; VDBG(dev, "%s\n", __func__); + napi_disable(&dev->rx_napi); netif_stop_queue(net); DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", @@ -768,6 +790,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, return ERR_PTR(-ENOMEM); dev = netdev_priv(net); + netif_napi_add(net, &dev->rx_napi, gether_poll, GETHER_NAPI_WEIGHT); spin_lock_init(&dev->lock); spin_lock_init(&dev->req_lock); INIT_WORK(&dev->work, eth_work); @@ -830,6 +853,7 @@ struct net_device *gether_setup_name_default(const char *netname) return ERR_PTR(-ENOMEM); dev = netdev_priv(net); + netif_napi_add(net, &dev->rx_napi, gether_poll, GETHER_NAPI_WEIGHT); spin_lock_init(&dev->lock); spin_lock_init(&dev->req_lock); INIT_WORK(&dev->work, eth_work); @@ -1113,6 +1137,7 @@ void gether_disconnect(struct gether *link) { struct eth_dev *dev = link->ioport; struct usb_request *req; + struct sk_buff *skb; WARN_ON(!dev); if (!dev) @@ -1139,6 +1164,12 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->req_lock); } spin_unlock(&dev->req_lock); + + spin_lock(&dev->rx_frames.lock); + while ((skb = __skb_dequeue(&dev->rx_frames))) + dev_kfree_skb_any(skb); + spin_unlock(&dev->rx_frames.lock); + link->in_ep->driver_data = NULL; link->in_ep->desc = NULL; diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h index bc2d3718219b..bf0ba375d459 100644 --- a/drivers/usb/gadget/u_fs.h +++ b/drivers/usb/gadget/u_fs.h @@ -65,10 +65,8 @@ static inline void ffs_dev_unlock(void) mutex_unlock(&ffs_lock); } -struct ffs_dev *ffs_alloc_dev(void); int ffs_name_dev(struct ffs_dev *dev, const char *name); int ffs_single_dev(struct ffs_dev *dev); -void ffs_free_dev(struct ffs_dev *dev); struct ffs_epfile; struct ffs_function; @@ -125,7 +123,7 @@ enum ffs_setup_state { * setup. If this state is set read/write on ep0 return * -EIDRM. This state is only set when adding event. */ - FFS_SETUP_CANCELED + FFS_SETUP_CANCELLED }; struct ffs_data { @@ -156,7 +154,6 @@ struct ffs_data { */ struct usb_request *ep0req; /* P: mutex */ struct completion ep0req_completion; /* P: mutex */ - int ep0req_status; /* P: mutex */ /* reference counter */ atomic_t ref; @@ -168,19 +165,18 @@ struct ffs_data { /* * Possible transitions: - * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock + * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock * happens only in ep0 read which is P: mutex - * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock + * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock * happens only in ep0 i/o which is P: mutex - * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELED -- P: ev.waitq.lock - * + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg + * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELLED -- P: ev.waitq.lock + * + FFS_SETUP_CANCELLED -> FFS_NO_SETUP -- cmpxchg + * + * This field should never be accessed directly and instead + * ffs_setup_state_clear_cancelled function should be used. */ enum ffs_setup_state setup_state; -#define FFS_SETUP_STATE(ffs) \ - ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \ - FFS_SETUP_CANCELED, FFS_NO_SETUP)) - /* Events & such. */ struct { u8 types[4]; @@ -210,16 +206,16 @@ struct ffs_data { /* filled by __ffs_data_got_descs() */ /* - * Real descriptors are 16 bytes after raw_descs (so you need - * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the - * first full speed descriptor). raw_descs_length and - * raw_fs_descs_length do not have those 16 bytes added. + * raw_descs is what you kfree, real_descs points inside of raw_descs, + * where full speed, high speed and super speed descriptors start. + * real_descs_length is the length of all those descriptors. */ + const void *raw_descs_data; const void *raw_descs; unsigned raw_descs_length; - unsigned raw_fs_descs_length; unsigned fs_descs_count; unsigned hs_descs_count; + unsigned ss_descs_count; unsigned short strings_count; unsigned short interfaces_count; |