From 9c1b70361e0b38e4acb8e62b54da66538cb77ff2 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 26 Mar 2014 18:46:38 +0200 Subject: usb: gadget: zero: Fix SuperSpeed enumeration for alternate setting 1 It was impossible to enumerate on a SuperSpeed (XHCI) host with alternate setting = 1 due to the wrongly set 'bMaxBurst' field in the SuperSpeed Endpoint Companion descriptor. Testcase: modprobe -r usbtest; modprobe usbtest alt=1 modprobe g_zero plug device to SuperSpeed port on the host. Without this patch the host always complains like so "usb 12-2: Not enough bandwidth for new device state. usb 12-2: Not enough bandwidth for altsetting 1" Bug was introduced by commit cf9a08ae in v3.9 Fixes: cf9a08ae5aec (usb: gadget: convert source sink and loopback to new function interface) Cc: 3.9+ # 3.9+ Reviewed-by: Felipe Balbi Acked-by: Sebastian Andrzej Siewior Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/zero.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 9f170c53e3d9..134f354ede62 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -300,7 +300,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev) ss_opts->isoc_interval = gzero_options.isoc_interval; ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket; ss_opts->isoc_mult = gzero_options.isoc_mult; - ss_opts->isoc_maxburst = gzero_options.isoc_maxpacket; + ss_opts->isoc_maxburst = gzero_options.isoc_maxburst; ss_opts->bulk_buflen = gzero_options.bulk_buflen; func_ss = usb_get_function(func_inst_ss); -- cgit v1.2.3 From 5cdf7d5be8443ba0e14a5cfe551c59f931983647 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 27 Mar 2014 08:09:21 +0100 Subject: usb: gadget: gadgetfs: Initialize CHIP to NULL before UDC probe Otherwise the value from the last probe would be retained that possibly is freed since (the UDC is removed) and therefore no longer relevant. Reproducible with the dummy UDC: modprobe dummy_hcd mount -t gadgetfs gadgetfs /dev/gadget umount /dev/gadget rmmod dummy_hcd mount -t gadgetfs gadgetfs /dev/gadget BUG: unable to handle kernel paging request at ffffffffa066fd9d Call Trace: [] ? d_alloc_name+0x22/0x50 [] ? selinux_d_instantiate+0x1c/0x20 [] gadgetfs_create_file+0x27/0xa0 [gadgetfs] [] ? setup_req.isra.4+0x80/0x80 [gadgetfs] [] gadgetfs_fill_super+0x13c/0x180 [gadgetfs] [] mount_single+0x92/0xc0 [] gadgetfs_mount+0x18/0x20 [gadgetfs] [] mount_fs+0x39/0x1b0 [] ? __alloc_percpu+0x10/0x20 [] vfs_kern_mount+0x63/0xf0 [] do_mount+0x23e/0xac0 [] ? strndup_user+0x4b/0xf0 [] SyS_mount+0x83/0xc0 [] system_call_fastpath+0x16/0x1b Signed-off-by: Lubomir Rintel Signed-off-by: Felipe Balbi --- drivers/usb/gadget/inode.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index b5be6f0308c2..a925d0cbcd41 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -2043,6 +2043,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) return -ESRCH; /* fake probe to determine $CHIP */ + CHIP = NULL; usb_gadget_probe_driver(&probe_driver); if (!CHIP) return -ENODEV; -- cgit v1.2.3 From fc696881c6ec991f39a2f93d41f9ae841c6ace38 Mon Sep 17 00:00:00 2001 From: Suresh Gupta Date: Wed, 2 Apr 2014 22:26:46 +0530 Subject: usb : gadget : fsl: fix the fault issue on rmmod completion in udc_controller->done should be assign with proper value before complete called. The complete called in fsl_udc_release which intern called from usb_del_gadget_udc, so moving assignment before calling usb_del_gadget_udc Signed-off-by: Suresh Gupta Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fsl_udc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 15960af0f67e..dcd0b07ae3a0 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2532,8 +2532,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) if (!udc_controller) return -ENODEV; - usb_del_gadget_udc(&udc_controller->gadget); udc_controller->done = &done; + usb_del_gadget_udc(&udc_controller->gadget); fsl_udc_clk_release(); -- cgit v1.2.3 From ae8dd0cc4146740e24ffb2092530c47e838001c5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 4 Apr 2014 22:27:59 -0300 Subject: usb: gadget: rndis: Include "u_rndis.h" Include "u_rndis.h" in order to fix the following sparse warning: drivers/usb/gadget/rndis.c:1144:5: warning: symbol 'rndis_init' was not declared. Should it be static? drivers/usb/gadget/rndis.c:1177:6: warning: symbol 'rndis_exit' was not declared. Should it be static? Signed-off-by: Fabio Estevam Signed-off-by: Felipe Balbi --- drivers/usb/gadget/rndis.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index d822d822efb3..7ed452d90f4d 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -35,6 +35,7 @@ #include #include +#include "u_rndis.h" #undef VERBOSE_DEBUG -- cgit v1.2.3 From 97839ca4b06ab27790700ad7da6be9a75fc0cc1d Mon Sep 17 00:00:00 2001 From: Chao Bi Date: Mon, 14 Apr 2014 11:19:53 +0800 Subject: usb: gadget: ffs: race between ffs_epfile_io() and ffs_func_eps_disable() ffs_epfile_io() is called from userspace, while ffs_func_eps_disable() might be called from USB disconnect interrupt, the two functions would run in parallel but they are not well protected, that epfile->ep would be removed by ffs_func_eps_disable() during ffs_epfile_io() is referring this pointer, then it leads to kernel PANIC. The scenario is as below: Thread 1 Thread 2 | | SyS_read dwc3_gadget_disconnect_interrupt | | ffs_epfile_read reset_config | | ffs_epfile_io ffs_func_eps_disable | | ----- usb_ep_disable(): epfile->ep->ep->desc = NULL | | usb_ep_align_maybe(): ----- it refers ep->desc->wMaxPacketSize ----- Signed-off-by: Chao Bi Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_fs.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 2e164dca08e8..1e12b3ee56fd 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -745,6 +745,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) */ struct usb_gadget *gadget = epfile->ffs->gadget; + spin_lock_irq(&epfile->ffs->eps_lock); + /* In the meantime, endpoint got disabled or changed. */ + if (epfile->ep != ep) { + spin_unlock_irq(&epfile->ffs->eps_lock); + return -ESHUTDOWN; + } /* * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint. @@ -752,6 +758,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) data_len = io_data->read ? usb_ep_align_maybe(gadget, ep->ep, io_data->len) : io_data->len; + spin_unlock_irq(&epfile->ffs->eps_lock); data = kmalloc(data_len, GFP_KERNEL); if (unlikely(!data)) -- cgit v1.2.3 From 252455c40316009cc791f00338ee2e367d2d2739 Mon Sep 17 00:00:00 2001 From: Suresh Gupta Date: Fri, 21 Mar 2014 16:38:12 +0530 Subject: usb: gadget: fsl driver pullup fix This fix the fsl usb gadget driver in a way that the usb device will be only "pulled up" on requests only when vbus is powered Signed-off-by: Suresh Gupta Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fsl_udc_core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index dcd0b07ae3a0..a2f26cdb56fe 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1219,6 +1219,10 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on) struct fsl_udc *udc; udc = container_of(gadget, struct fsl_udc, gadget); + + if (!udc->vbus_active) + return -EOPNOTSUPP; + udc->softconnect = (is_on != 0); if (can_pullup(udc)) fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP), -- cgit v1.2.3 From 9189a330936fe053d48e14c10a8d90aaef4408c9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 21 Apr 2014 10:15:12 -0500 Subject: Revert "usb: gadget: u_ether: move hardware transmit to RX NAPI" This reverts commit 716fb91dfe1777bd6d5e598f3d3572214b3ed296. That commit caused a regression which would end up in a kernel BUG() as below: [ 101.554300] g_ether gadget: full-speed config #1: CDC Subset/SAFE [ 101.585186] ------------[ cut here ]------------ [ 101.600587] kernel BUG at include/linux/netdevice.h:495! [ 101.615850] Internal error: Oops - BUG: 0 [#1] PREEMPT ARM [ 101.645539] Modules linked in: [ 101.660483] CPU: 0 PID: 0 Comm: swapper Not tainted 3.15.0-rc1+ #104 [ 101.690175] task: c05dc5c8 ti: c05d2000 task.ti: c05d2000 [ 101.705579] PC is at eth_start+0x64/0x8c [ 101.720981] LR is at __netif_schedule+0x7c/0x90 [ 101.736455] pc : [] lr : [] psr: 60000093 [ 101.736455] sp : c05d3d18 ip : c05d3cf8 fp : c05d3d2c [ 101.782340] r10: 00000000 r9 : c196c1f0 r8 : c196c1a0 [ 101.797823] r7 : 00000000 r6 : 00000002 r5 : c1976400 r4 : c1976400 [ 101.828058] r3 : 00000000 r2 : c05d3ce8 r1 : 00000001 r0 : 00000002 [ 101.858722] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Reported-by: Robert Jarzmik Signed-of-by: Felipe Balbi --- drivers/usb/gadget/u_ether.c | 101 +++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 66 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 50d09c289137..b7d4f82872b7 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -48,8 +48,6 @@ #define UETH__VERSION "29-May-2008" -#define GETHER_NAPI_WEIGHT 32 - struct eth_dev { /* lock is held while accessing port_usb */ @@ -74,7 +72,6 @@ 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 @@ -256,16 +253,18 @@ 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; + struct sk_buff *skb = req->context, *skb2; struct eth_dev *dev = ep->driver_data; int status = req->status; - bool rx_queue = 0; switch (status) { @@ -289,8 +288,30 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) } else { skb_queue_tail(&dev->rx_frames, skb); } - if (!status) - rx_queue = 1; + 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); + } break; /* software-driven interface shutdown */ @@ -313,20 +334,22 @@ 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); - - if (rx_queue && likely(napi_schedule_prep(&dev->rx_napi))) - __napi_schedule(&dev->rx_napi); + req = NULL; + } + if (req) + rx_submit(dev, req, GFP_ATOMIC); } static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) @@ -391,24 +414,16 @@ 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; } @@ -418,41 +433,6 @@ 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); @@ -645,7 +625,6 @@ 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) @@ -672,7 +651,6 @@ 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", @@ -790,7 +768,6 @@ 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); @@ -853,7 +830,6 @@ 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); @@ -1137,7 +1113,6 @@ 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) @@ -1164,12 +1139,6 @@ 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; -- cgit v1.2.3 From 2656c9e28125e96bee212f146cc3f2419fd3ffef Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Tue, 15 Apr 2014 16:09:33 +0800 Subject: usb: gadget: f_rndis: reduce NETTX irq caused by free skb header This patch reduce unecessary NETTX softirq call caused by free skb header. You will see this softirq comes twice while there is only one TX packet to be transmitted. So using dev_kfree_skb() instead of dev_kfree_skb_any() to avoid this problem. Cc: David S. Miller Cc: Stephen Hemminger Cc: Greg Kroah-Hartman Signed-off-by: Macpaul Lin Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_rndis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index c11761ce5113..9a4f49dc6ac4 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -377,7 +377,7 @@ static struct sk_buff *rndis_add_header(struct gether *port, if (skb2) rndis_add_hdr(skb2); - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); return skb2; } -- cgit v1.2.3