diff options
Diffstat (limited to 'drivers/usb/host')
32 files changed, 186 insertions, 44 deletions
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 4e0c67f1f51..b6315aa47f7 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -12,7 +12,7 @@ fhci-objs := fhci-hcd.o fhci-hub.o fhci-q.o fhci-mem.o \  ifeq ($(CONFIG_FHCI_DEBUG),y)  fhci-objs += fhci-dbg.o  endif -xhci-objs := xhci-hcd.o xhci-mem.o xhci-pci.o xhci-ring.o xhci-hub.o xhci-dbg.o +xhci-hcd-objs := xhci.o xhci-mem.o xhci-pci.o xhci-ring.o xhci-hub.o xhci-dbg.o  obj-$(CONFIG_USB_WHCI_HCD)	+= whci/ @@ -25,7 +25,7 @@ obj-$(CONFIG_USB_ISP1362_HCD)	+= isp1362-hcd.o  obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o  obj-$(CONFIG_USB_UHCI_HCD)	+= uhci-hcd.o  obj-$(CONFIG_USB_FHCI_HCD)	+= fhci.o -obj-$(CONFIG_USB_XHCI_HCD)	+= xhci.o +obj-$(CONFIG_USB_XHCI_HCD)	+= xhci-hcd.o  obj-$(CONFIG_USB_SL811_HCD)	+= sl811-hcd.o  obj-$(CONFIG_USB_SL811_CS)	+= sl811_cs.o  obj-$(CONFIG_USB_U132_HCD)	+= u132-hcd.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index d8d6d3461d3..13ead00aecd 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -23,7 +23,6 @@  #include <linux/delay.h>  #include <linux/ioport.h>  #include <linux/sched.h> -#include <linux/slab.h>  #include <linux/vmalloc.h>  #include <linux/errno.h>  #include <linux/init.h> @@ -35,6 +34,7 @@  #include <linux/moduleparam.h>  #include <linux/dma-mapping.h>  #include <linux/debugfs.h> +#include <linux/slab.h>  #include "../core/hcd.h" @@ -543,6 +543,7 @@ static int ehci_init(struct usb_hcd *hcd)  	 */  	ehci->periodic_size = DEFAULT_I_TDPS;  	INIT_LIST_HEAD(&ehci->cached_itd_list); +	INIT_LIST_HEAD(&ehci->cached_sitd_list);  	if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)  		return retval; @@ -995,7 +996,7 @@ rescan:  	/* endpoints can be iso streams.  for now, we don't  	 * accelerate iso completions ... so spin a while.  	 */ -	if (qh->hw->hw_info1 == 0) { +	if (qh->hw == NULL) {  		ehci_vdbg (ehci, "iso delay\n");  		goto idle_timeout;  	} diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 19372673bf0..c7178bcde67 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -801,7 +801,7 @@ static int ehci_hub_control (  			 * this bit; seems too long to spin routinely...  			 */  			retval = handshake(ehci, status_reg, -					PORT_RESET, 0, 750); +					PORT_RESET, 0, 1000);  			if (retval != 0) {  				ehci_err (ehci, "port %d reset error %d\n",  					wIndex + 1, retval); diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index aeda96e0af6..1f3f01eacaf 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -136,7 +136,7 @@ static inline void qh_put (struct ehci_qh *qh)  static void ehci_mem_cleanup (struct ehci_hcd *ehci)  { -	free_cached_itd_list(ehci); +	free_cached_lists(ehci);  	if (ehci->async)  		qh_put (ehci->async);  	ehci->async = NULL; diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index 23cd917088b..ead59f42e69 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -21,6 +21,7 @@  #include <linux/clk.h>  #include <linux/delay.h>  #include <linux/usb/otg.h> +#include <linux/slab.h>  #include <mach/mxc_ehci.h> diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index f0282d6bb7a..40a85833503 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -37,6 +37,7 @@  #include <linux/clk.h>  #include <linux/gpio.h>  #include <linux/regulator/consumer.h> +#include <linux/slab.h>  #include <plat/usb.h>  /* @@ -628,11 +629,13 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  		}  		snprintf(supply, sizeof(supply), "hsusb%d", i);  		omap->regulator[i] = regulator_get(omap->dev, supply); -		if (IS_ERR(omap->regulator[i])) +		if (IS_ERR(omap->regulator[i])) { +			omap->regulator[i] = NULL;  			dev_dbg(&pdev->dev,  			"failed to get ehci port%d regulator\n", i); -		else +		} else {  			regulator_enable(omap->regulator[i]); +		}  	}  	ret = omap_start_ehc(omap, hcd); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 39340ae00ac..805ec633a65 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -510,7 +510,7 @@ static int disable_periodic (struct ehci_hcd *ehci)  	ehci_writel(ehci, cmd, &ehci->regs->command);  	/* posted write ... */ -	free_cached_itd_list(ehci); +	free_cached_lists(ehci);  	ehci->next_uframe = -1;  	return 0; @@ -1123,8 +1123,8 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)  					urb->interval);  		} -	/* if dev->ep [epnum] is a QH, info1.maxpacket is nonzero */ -	} else if (unlikely (stream->hw_info1 != 0)) { +	/* if dev->ep [epnum] is a QH, hw is set */ +	} else if (unlikely (stream->hw != NULL)) {  		ehci_dbg (ehci, "dev %s ep%d%s, not iso??\n",  			urb->dev->devpath, epnum,  			usb_pipein(urb->pipe) ? "in" : "out"); @@ -1565,13 +1565,27 @@ itd_patch(  static inline void  itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)  { -	/* always prepend ITD/SITD ... only QH tree is order-sensitive */ -	itd->itd_next = ehci->pshadow [frame]; -	itd->hw_next = ehci->periodic [frame]; -	ehci->pshadow [frame].itd = itd; +	union ehci_shadow	*prev = &ehci->pshadow[frame]; +	__hc32			*hw_p = &ehci->periodic[frame]; +	union ehci_shadow	here = *prev; +	__hc32			type = 0; + +	/* skip any iso nodes which might belong to previous microframes */ +	while (here.ptr) { +		type = Q_NEXT_TYPE(ehci, *hw_p); +		if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) +			break; +		prev = periodic_next_shadow(ehci, prev, type); +		hw_p = shadow_next_periodic(ehci, &here, type); +		here = *prev; +	} + +	itd->itd_next = here; +	itd->hw_next = *hw_p; +	prev->itd = itd;  	itd->frame = frame;  	wmb (); -	ehci->periodic[frame] = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); +	*hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);  }  /* fit urb's itds into the selected schedule slot; activate as needed */ @@ -2125,13 +2139,27 @@ sitd_complete (  			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");  	}  	iso_stream_put (ehci, stream); -	/* OK to recycle this SITD now that its completion callback ran. */ +  done:  	sitd->urb = NULL; -	sitd->stream = NULL; -	list_move(&sitd->sitd_list, &stream->free_list); -	iso_stream_put(ehci, stream); - +	if (ehci->clock_frame != sitd->frame) { +		/* OK to recycle this SITD now. */ +		sitd->stream = NULL; +		list_move(&sitd->sitd_list, &stream->free_list); +		iso_stream_put(ehci, stream); +	} else { +		/* HW might remember this SITD, so we can't recycle it yet. +		 * Move it to a safe place until a new frame starts. +		 */ +		list_move(&sitd->sitd_list, &ehci->cached_sitd_list); +		if (stream->refcount == 2) { +			/* If iso_stream_put() were called here, stream +			 * would be freed.  Instead, just prevent reuse. +			 */ +			stream->ep->hcpriv = NULL; +			stream->ep = NULL; +		} +	}  	return retval;  } @@ -2197,9 +2225,10 @@ done:  /*-------------------------------------------------------------------------*/ -static void free_cached_itd_list(struct ehci_hcd *ehci) +static void free_cached_lists(struct ehci_hcd *ehci)  {  	struct ehci_itd *itd, *n; +	struct ehci_sitd *sitd, *sn;  	list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {  		struct ehci_iso_stream	*stream = itd->stream; @@ -2207,6 +2236,13 @@ static void free_cached_itd_list(struct ehci_hcd *ehci)  		list_move(&itd->itd_list, &stream->free_list);  		iso_stream_put(ehci, stream);  	} + +	list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) { +		struct ehci_iso_stream	*stream = sitd->stream; +		sitd->stream = NULL; +		list_move(&sitd->sitd_list, &stream->free_list); +		iso_stream_put(ehci, stream); +	}  }  /*-------------------------------------------------------------------------*/ @@ -2233,7 +2269,7 @@ scan_periodic (struct ehci_hcd *ehci)  		clock_frame = -1;  	}  	if (ehci->clock_frame != clock_frame) { -		free_cached_itd_list(ehci); +		free_cached_lists(ehci);  		ehci->clock_frame = clock_frame;  	}  	clock %= mod; @@ -2400,7 +2436,7 @@ restart:  			clock = now;  			clock_frame = clock >> 3;  			if (ehci->clock_frame != clock_frame) { -				free_cached_itd_list(ehci); +				free_cached_lists(ehci);  				ehci->clock_frame = clock_frame;  			}  		} else { diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 2d85e21ff28..556c0b48f3a 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -87,8 +87,9 @@ struct ehci_hcd {			/* one per controller */  	int			next_uframe;	/* scan periodic, start here */  	unsigned		periodic_sched;	/* periodic activity count */ -	/* list of itds completed while clock_frame was still active */ +	/* list of itds & sitds completed while clock_frame was still active */  	struct list_head	cached_itd_list; +	struct list_head	cached_sitd_list;  	unsigned		clock_frame;  	/* per root hub port */ @@ -195,7 +196,7 @@ timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)  	clear_bit (action, &ehci->actions);  } -static void free_cached_itd_list(struct ehci_hcd *ehci); +static void free_cached_lists(struct ehci_hcd *ehci);  /*-------------------------------------------------------------------------*/ @@ -394,9 +395,8 @@ struct ehci_iso_sched {   * acts like a qh would, if EHCI had them for ISO.   */  struct ehci_iso_stream { -	/* first two fields match QH, but info1 == 0 */ -	__hc32			hw_next; -	__hc32			hw_info1; +	/* first field matches ehci_hq, but is NULL */ +	struct ehci_qh_hw	*hw;  	u32			refcount;  	u8			bEndpointAddress; diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 5dcfb3de994..15379c63614 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -27,6 +27,7 @@  #include <linux/usb.h>  #include <linux/of_platform.h>  #include <linux/of_gpio.h> +#include <linux/slab.h>  #include <asm/qe.h>  #include <asm/fsl_gtm.h>  #include "../core/hcd.h" diff --git a/drivers/usb/host/fhci-mem.c b/drivers/usb/host/fhci-mem.c index 2c0736c9971..5591bfb499d 100644 --- a/drivers/usb/host/fhci-mem.c +++ b/drivers/usb/host/fhci-mem.c @@ -18,6 +18,7 @@  #include <linux/kernel.h>  #include <linux/types.h>  #include <linux/delay.h> +#include <linux/slab.h>  #include <linux/list.h>  #include <linux/usb.h>  #include "../core/hcd.h" diff --git a/drivers/usb/host/fhci-q.c b/drivers/usb/host/fhci-q.c index b0a1446ba29..f73c92359be 100644 --- a/drivers/usb/host/fhci-q.c +++ b/drivers/usb/host/fhci-q.c @@ -19,6 +19,7 @@  #include <linux/types.h>  #include <linux/spinlock.h>  #include <linux/errno.h> +#include <linux/slab.h>  #include <linux/list.h>  #include <linux/usb.h>  #include "../core/hcd.h" diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c index e1232890c78..57013479d7f 100644 --- a/drivers/usb/host/fhci-tds.c +++ b/drivers/usb/host/fhci-tds.c @@ -18,6 +18,7 @@  #include <linux/kernel.h>  #include <linux/types.h>  #include <linux/errno.h> +#include <linux/slab.h>  #include <linux/list.h>  #include <linux/io.h>  #include <linux/usb.h> diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 88b03214622..35742f8c7cd 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -55,6 +55,7 @@   */  #include <linux/kernel.h>  #include <linux/init.h> +#include <linux/slab.h>  #include <linux/module.h>  #include <linux/workqueue.h>  #include <linux/wait.h> diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index 213e270e1c2..8a12f297645 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -54,6 +54,7 @@  #include <linux/kernel.h>  #include <linux/list.h>  #include <linux/platform_device.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include "../core/hcd.h" diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index a2b305477af..92de71dc772 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -62,6 +62,7 @@  #include <linux/errno.h>  #include <linux/init.h>  #include <linux/list.h> +#include <linux/slab.h>  #include <linux/usb.h>  #include <linux/usb/isp116x.h>  #include <linux/platform_device.h> diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 68b83ab7071..944291e10f9 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -331,6 +331,8 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)  	 */  	if (at91_suspend_entering_slow_clock()) {  		ohci_usb_reset (ohci); +		/* flush the writes */ +		(void) ohci_readl (ohci, &ohci->regs->control);  		at91_stop_clock();  	} diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 4aa08d36d07..d22fb4d577b 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -23,7 +23,7 @@  #error "This file is DA8xx bus glue.  Define CONFIG_ARCH_DAVINCI_DA8XX."  #endif -#define CFGCHIP2	DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG) +#define CFGCHIP2	DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)  static struct clk *usb11_clk;  static struct clk *usb20_clk; diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 32bbce9718f..65cac8cc892 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -697,7 +697,7 @@ static int ohci_hub_control (  	u16		wLength  ) {  	struct ohci_hcd	*ohci = hcd_to_ohci (hcd); -	int		ports = hcd_to_bus (hcd)->root_hub->maxchild; +	int		ports = ohci->num_ports;  	u32		temp;  	int		retval = 0; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 35288bcae0d..83094d067e0 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -8,6 +8,7 @@   */  #include <linux/irq.h> +#include <linux/slab.h>  static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)  { diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 50f57f46883..e62b30b3e42 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -660,13 +660,13 @@ static struct ehci_qh *oxu_qh_alloc(struct oxu_hcd *oxu)  		if (qh->dummy == NULL) {  			oxu_dbg(oxu, "no dummy td\n");  			oxu->qh_used[i] = 0; - -			return NULL; +			qh = NULL; +			goto unlock;  		}  		oxu->qh_used[i] = 1;  	} - +unlock:  	spin_unlock(&oxu->mem_lock);  	return qh; diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index bee558aed42..d478ffad59b 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -37,6 +37,7 @@  #include <linux/io.h>  #include <linux/mm.h>  #include <linux/irq.h> +#include <linux/slab.h>  #include <asm/cacheflush.h>  #include "../core/hcd.h" @@ -418,7 +419,7 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb)  /* this function must be called with interrupt disabled */  static void free_usb_address(struct r8a66597 *r8a66597, -			     struct r8a66597_device *dev) +			     struct r8a66597_device *dev, int reset)  {  	int port; @@ -430,7 +431,13 @@ static void free_usb_address(struct r8a66597 *r8a66597,  	dev->state = USB_STATE_DEFAULT;  	r8a66597->address_map &= ~(1 << dev->address);  	dev->address = 0; -	dev_set_drvdata(&dev->udev->dev, NULL); +	/* +	 * Only when resetting USB, it is necessary to erase drvdata. When +	 * a usb device with usb hub is disconnect, "dev->udev" is already +	 * freed on usb_desconnect(). So we cannot access the data. +	 */ +	if (reset) +		dev_set_drvdata(&dev->udev->dev, NULL);  	list_del(&dev->device_list);  	kfree(dev); @@ -1069,7 +1076,7 @@ static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port)  	struct r8a66597_device *dev = r8a66597->root_hub[port].dev;  	disable_r8a66597_pipe_all(r8a66597, dev); -	free_usb_address(r8a66597, dev); +	free_usb_address(r8a66597, dev, 0);  	start_root_hub_sampling(r8a66597, port, 0);  } @@ -2085,7 +2092,7 @@ static void update_usb_address_map(struct r8a66597 *r8a66597,  				spin_lock_irqsave(&r8a66597->lock, flags);  				dev = get_r8a66597_device(r8a66597, addr);  				disable_r8a66597_pipe_all(r8a66597, dev); -				free_usb_address(r8a66597, dev); +				free_usb_address(r8a66597, dev, 0);  				put_child_connect_map(r8a66597, addr);  				spin_unlock_irqrestore(&r8a66597->lock, flags);  			} @@ -2228,7 +2235,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			rh->port |= (1 << USB_PORT_FEAT_RESET);  			disable_r8a66597_pipe_all(r8a66597, dev); -			free_usb_address(r8a66597, dev); +			free_usb_address(r8a66597, dev, 1);  			r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT,  				      get_dvstctr_reg(port)); diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index e11cc3aa4b8..3b867a8af7b 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -720,10 +720,10 @@ retry:  		/* port status seems weird until after reset, so  		 * force the reset and make khubd clean up later.  		 */ -		if (sl811->stat_insrmv & 1) -			sl811->port1 |= 1 << USB_PORT_FEAT_CONNECTION; -		else +		if (irqstat & SL11H_INTMASK_RD)  			sl811->port1 &= ~(1 << USB_PORT_FEAT_CONNECTION); +		else +			sl811->port1 |= 1 << USB_PORT_FEAT_CONNECTION;  		sl811->port1 |= 1 << USB_PORT_FEAT_C_CONNECTION; diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index e52b954dda4..98cf0b26b96 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -9,6 +9,7 @@   * (C) Copyright 1999-2001 Johannes Erdfelt   */ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/debugfs.h>  #include <linux/smp_lock.h> diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index 562eba10881..77324930603 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -16,6 +16,7 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */  #include <linux/kernel.h> +#include <linux/gfp.h>  #include <linux/dma-mapping.h>  #include <linux/uwb/umc.h>  #include <linux/usb.h> diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c index 8c1c610c951..c5305b599ca 100644 --- a/drivers/usb/host/whci/debug.c +++ b/drivers/usb/host/whci/debug.c @@ -15,6 +15,7 @@   * You should have received a copy of the GNU General Public License   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/debugfs.h>  #include <linux/seq_file.h> diff --git a/drivers/usb/host/whci/init.c b/drivers/usb/host/whci/init.c index 34a783cb013..f7582e8e216 100644 --- a/drivers/usb/host/whci/init.c +++ b/drivers/usb/host/whci/init.c @@ -16,6 +16,7 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */  #include <linux/kernel.h> +#include <linux/gfp.h>  #include <linux/dma-mapping.h>  #include <linux/uwb/umc.h> diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c index 0db3fb2dc03..33c5580b4d2 100644 --- a/drivers/usb/host/whci/pzl.c +++ b/drivers/usb/host/whci/pzl.c @@ -16,6 +16,7 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */  #include <linux/kernel.h> +#include <linux/gfp.h>  #include <linux/dma-mapping.h>  #include <linux/uwb/umc.h>  #include <linux/usb.h> diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index 7d4204db0f6..141d049beb3 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -17,6 +17,7 @@   */  #include <linux/kernel.h>  #include <linux/dma-mapping.h> +#include <linux/slab.h>  #include <linux/uwb/umc.h>  #include <linux/usb.h> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 49f7d72f8b1..d64f5724bfc 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -22,6 +22,7 @@  #include <linux/usb.h>  #include <linux/pci.h> +#include <linux/slab.h>  #include <linux/dmapool.h>  #include "xhci.h" @@ -566,8 +567,13 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,  			if (interval < 3)  				interval = 3;  			if ((1 << interval) != 8*ep->desc.bInterval) -				dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n", -						ep->desc.bEndpointAddress, 1 << interval); +				dev_warn(&udev->dev, +						"ep %#x - rounding interval" +						" to %d microframes, " +						"ep desc says %d microframes\n", +						ep->desc.bEndpointAddress, +						1 << interval, +						8*ep->desc.bInterval);  		}  		break;  	default: @@ -576,6 +582,19 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,  	return EP_INTERVAL(interval);  } +/* The "Mult" field in the endpoint context is only set for SuperSpeed devices. + * High speed endpoint descriptors can define "the number of additional + * transaction opportunities per microframe", but that goes in the Max Burst + * endpoint context field. + */ +static inline u32 xhci_get_endpoint_mult(struct usb_device *udev, +		struct usb_host_endpoint *ep) +{ +	if (udev->speed != USB_SPEED_SUPER || !ep->ss_ep_comp) +		return 0; +	return ep->ss_ep_comp->desc.bmAttributes; +} +  static inline u32 xhci_get_endpoint_type(struct usb_device *udev,  		struct usb_host_endpoint *ep)  { @@ -606,6 +625,36 @@ static inline u32 xhci_get_endpoint_type(struct usb_device *udev,  	return type;  } +/* Return the maximum endpoint service interval time (ESIT) payload. + * Basically, this is the maxpacket size, multiplied by the burst size + * and mult size. + */ +static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci, +		struct usb_device *udev, +		struct usb_host_endpoint *ep) +{ +	int max_burst; +	int max_packet; + +	/* Only applies for interrupt or isochronous endpoints */ +	if (usb_endpoint_xfer_control(&ep->desc) || +			usb_endpoint_xfer_bulk(&ep->desc)) +		return 0; + +	if (udev->speed == USB_SPEED_SUPER) { +		if (ep->ss_ep_comp) +			return ep->ss_ep_comp->desc.wBytesPerInterval; +		xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n"); +		/* Assume no bursts, no multiple opportunities to send. */ +		return ep->desc.wMaxPacketSize; +	} + +	max_packet = ep->desc.wMaxPacketSize & 0x3ff; +	max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11; +	/* A 0 in max burst means 1 transfer per ESIT */ +	return max_packet * (max_burst + 1); +} +  int xhci_endpoint_init(struct xhci_hcd *xhci,  		struct xhci_virt_device *virt_dev,  		struct usb_device *udev, @@ -617,6 +666,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,  	struct xhci_ring *ep_ring;  	unsigned int max_packet;  	unsigned int max_burst; +	u32 max_esit_payload;  	ep_index = xhci_get_endpoint_index(&ep->desc);  	ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); @@ -638,6 +688,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,  	ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state;  	ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep); +	ep_ctx->ep_info |= EP_MULT(xhci_get_endpoint_mult(udev, ep));  	/* FIXME dig Mult and streams info out of ep companion desc */ @@ -683,6 +734,26 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,  	default:  		BUG();  	} +	max_esit_payload = xhci_get_max_esit_payload(xhci, udev, ep); +	ep_ctx->tx_info = MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload); + +	/* +	 * XXX no idea how to calculate the average TRB buffer length for bulk +	 * endpoints, as the driver gives us no clue how big each scatter gather +	 * list entry (or buffer) is going to be. +	 * +	 * For isochronous and interrupt endpoints, we set it to the max +	 * available, until we have new API in the USB core to allow drivers to +	 * declare how much bandwidth they actually need. +	 * +	 * Normally, it would be calculated by taking the total of the buffer +	 * lengths in the TD and then dividing by the number of TRBs in a TD, +	 * including link TRBs, No-op TRBs, and Event data TRBs.  Since we don't +	 * use Event Data TRBs, and we don't chain in a link TRB on short +	 * transfers, we're basically dividing by 1. +	 */ +	ep_ctx->tx_info |= AVG_TRB_LENGTH_FOR_EP(max_esit_payload); +  	/* FIXME Debug endpoint context */  	return 0;  } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 6ba841bca4a..85d7e8f2085 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -65,6 +65,7 @@   */  #include <linux/scatterlist.h> +#include <linux/slab.h>  #include "xhci.h"  /* diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci.c index 4cb69e0af83..7e427727390 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci.c @@ -23,6 +23,7 @@  #include <linux/irq.h>  #include <linux/module.h>  #include <linux/moduleparam.h> +#include <linux/slab.h>  #include "xhci.h" @@ -1173,6 +1174,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,  		cmd_completion = &virt_dev->cmd_completion;  		cmd_status = &virt_dev->cmd_status;  	} +	init_completion(cmd_completion);  	if (!ctx_change)  		ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index e5eb09b2f38..ea389e9a493 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -609,6 +609,10 @@ struct xhci_ep_ctx {  #define MAX_PACKET_MASK		(0xffff << 16)  #define MAX_PACKET_DECODED(p)	(((p) >> 16) & 0xffff) +/* tx_info bitmasks */ +#define AVG_TRB_LENGTH_FOR_EP(p)	((p) & 0xffff) +#define MAX_ESIT_PAYLOAD_FOR_EP(p)	(((p) & 0xffff) << 16) +  /**   * struct xhci_input_control_context  |