diff options
Diffstat (limited to 'drivers/usb')
34 files changed, 804 insertions, 335 deletions
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 3c1d67d324f..d8f741f9e56 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,7 +1,10 @@  config USB_DWC3  	tristate "DesignWare USB3 DRD Core Support" -	depends on (USB || USB_GADGET) +	depends on (USB && USB_GADGET)  	select USB_OTG_UTILS +	select USB_GADGET_DUALSPEED +	select USB_GADGET_SUPERSPEED +	select USB_XHCI_PLATFORM  	help  	  Say Y or M here if your system has a Dual Role SuperSpeed  	  USB controller based on the DesignWare USB3 IP Core. diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 593d1dbc465..900ae74357f 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -4,10 +4,8 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG  obj-$(CONFIG_USB_DWC3)			+= dwc3.o  dwc3-y					:= core.o - -ifneq ($(CONFIG_USB_GADGET_DWC3),) -	dwc3-y				+= gadget.o ep0.o -endif +dwc3-y					+= host.o +dwc3-y					+= gadget.o ep0.o  ifneq ($(CONFIG_DEBUG_FS),)  	dwc3-y				+= debugfs.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 717ebc9ff94..455bb1e748d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -59,6 +59,60 @@  #include "debug.h" +static char *maximum_speed = "super"; +module_param(maximum_speed, charp, 0); +MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); + +/* -------------------------------------------------------------------------- */ + +#define DWC3_DEVS_POSSIBLE	32 + +static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE); + +int dwc3_get_device_id(void) +{ +	int		id; + +again: +	id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE); +	if (id < DWC3_DEVS_POSSIBLE) { +		int old; + +		old = test_and_set_bit(id, dwc3_devs); +		if (old) +			goto again; +	} else { +		pr_err("dwc3: no space for new device\n"); +		id = -ENOMEM; +	} + +	return 0; +} +EXPORT_SYMBOL_GPL(dwc3_get_device_id); + +void dwc3_put_device_id(int id) +{ +	int			ret; + +	if (id < 0) +		return; + +	ret = test_bit(id, dwc3_devs); +	WARN(!ret, "dwc3: ID %d not in use\n", id); +	clear_bit(id, dwc3_devs); +} +EXPORT_SYMBOL_GPL(dwc3_put_device_id); + +void dwc3_set_mode(struct dwc3 *dwc, u32 mode) +{ +	u32 reg; + +	reg = dwc3_readl(dwc->regs, DWC3_GCTL); +	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); +	reg |= DWC3_GCTL_PRTCAPDIR(mode); +	dwc3_writel(dwc->regs, DWC3_GCTL, reg); +} +  /**   * dwc3_core_soft_reset - Issues core soft reset and PHY reset   * @dwc: pointer to our context structure @@ -150,7 +204,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)  	struct dwc3_event_buffer	*evt;  	int i; -	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) { +	for (i = 0; i < dwc->num_event_buffers; i++) {  		evt = dwc->ev_buffs[i];  		if (evt) {  			dwc3_free_one_event_buffer(dwc, evt); @@ -162,17 +216,25 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)  /**   * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length   * @dwc: Pointer to out controller context structure - * @num: number of event buffers to allocate   * @length: size of event buffer   *   * Returns 0 on success otherwise negative errno. In error the case, dwc   * may contain some buffers allocated but not all which were requested.   */ -static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num, -		unsigned length) +static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)  { +	int			num;  	int			i; +	num = DWC3_NUM_INT(dwc->hwparams.hwparams1); +	dwc->num_event_buffers = num; + +	dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL); +	if (!dwc->ev_buffs) { +		dev_err(dwc->dev, "can't allocate event buffers array\n"); +		return -ENOMEM; +	} +  	for (i = 0; i < num; i++) {  		struct dwc3_event_buffer	*evt; @@ -198,7 +260,7 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)  	struct dwc3_event_buffer	*evt;  	int				n; -	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) { +	for (n = 0; n < dwc->num_event_buffers; n++) {  		evt = dwc->ev_buffs[n];  		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",  				evt->buf, (unsigned long long) evt->dma, @@ -221,7 +283,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)  	struct dwc3_event_buffer	*evt;  	int				n; -	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) { +	for (n = 0; n < dwc->num_event_buffers; n++) {  		evt = dwc->ev_buffs[n];  		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);  		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); @@ -285,8 +347,32 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)  		cpu_relax();  	} while (true); -	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM, -			DWC3_EVENT_BUFFERS_SIZE); +	dwc3_cache_hwparams(dwc); + +	reg = dwc3_readl(dwc->regs, DWC3_GCTL); +	reg &= ~DWC3_GCTL_SCALEDOWN(3); +	reg &= ~DWC3_GCTL_DISSCRAMBLE; + +	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { +	case DWC3_GHWPARAMS1_EN_PWROPT_CLK: +		reg &= ~DWC3_GCTL_DSBLCLKGTNG; +		break; +	default: +		dev_dbg(dwc->dev, "No power optimization available\n"); +	} + +	/* +	 * WORKAROUND: DWC3 revisions <1.90a have a bug +	 * when The device fails to connect at SuperSpeed +	 * and falls back to high-speed mode which causes +	 * the device to enter in a Connect/Disconnect loop +	 */ +	if (dwc->revision < DWC3_REVISION_190A) +		reg |= DWC3_GCTL_U2RSTECN; + +	dwc3_writel(dwc->regs, DWC3_GCTL, reg); + +	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);  	if (ret) {  		dev_err(dwc->dev, "failed to allocate event buffers\n");  		ret = -ENOMEM; @@ -299,8 +385,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)  		goto err1;  	} -	dwc3_cache_hwparams(dwc); -  	return 0;  err1: @@ -320,15 +404,17 @@ static void dwc3_core_exit(struct dwc3 *dwc)  static int __devinit dwc3_probe(struct platform_device *pdev)  { -	const struct platform_device_id *id = platform_get_device_id(pdev);  	struct resource		*res;  	struct dwc3		*dwc; -	void __iomem		*regs; -	unsigned int		features = id->driver_data; +  	int			ret = -ENOMEM;  	int			irq; + +	void __iomem		*regs;  	void			*mem; +	u8			mode; +  	mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);  	if (!mem) {  		dev_err(&pdev->dev, "not enough memory\n"); @@ -343,6 +429,8 @@ static int __devinit dwc3_probe(struct platform_device *pdev)  		goto err1;  	} +	dwc->res = res; +  	res = request_mem_region(res->start, resource_size(res),  			dev_name(&pdev->dev));  	if (!res) { @@ -370,6 +458,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev)  	dwc->dev	= &pdev->dev;  	dwc->irq	= irq; +	if (!strncmp("super", maximum_speed, 5)) +		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; +	else if (!strncmp("high", maximum_speed, 4)) +		dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; +	else if (!strncmp("full", maximum_speed, 4)) +		dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; +	else if (!strncmp("low", maximum_speed, 3)) +		dwc->maximum_speed = DWC3_DCFG_LOWSPEED; +	else +		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; +  	pm_runtime_enable(&pdev->dev);  	pm_runtime_get_sync(&pdev->dev);  	pm_runtime_forbid(&pdev->dev); @@ -380,13 +479,44 @@ static int __devinit dwc3_probe(struct platform_device *pdev)  		goto err3;  	} -	if (features & DWC3_HAS_PERIPHERAL) { +	mode = DWC3_MODE(dwc->hwparams.hwparams0); + +	switch (mode) { +	case DWC3_MODE_DEVICE: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); +		ret = dwc3_gadget_init(dwc); +		if (ret) { +			dev_err(&pdev->dev, "failed to initialize gadget\n"); +			goto err4; +		} +		break; +	case DWC3_MODE_HOST: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); +		ret = dwc3_host_init(dwc); +		if (ret) { +			dev_err(&pdev->dev, "failed to initialize host\n"); +			goto err4; +		} +		break; +	case DWC3_MODE_DRD: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); +		ret = dwc3_host_init(dwc); +		if (ret) { +			dev_err(&pdev->dev, "failed to initialize host\n"); +			goto err4; +		} +  		ret = dwc3_gadget_init(dwc);  		if (ret) { -			dev_err(&pdev->dev, "failed to initialized gadget\n"); +			dev_err(&pdev->dev, "failed to initialize gadget\n");  			goto err4;  		} +		break; +	default: +		dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode); +		goto err4;  	} +	dwc->mode = mode;  	ret = dwc3_debugfs_init(dwc);  	if (ret) { @@ -399,8 +529,21 @@ static int __devinit dwc3_probe(struct platform_device *pdev)  	return 0;  err5: -	if (features & DWC3_HAS_PERIPHERAL) +	switch (mode) { +	case DWC3_MODE_DEVICE:  		dwc3_gadget_exit(dwc); +		break; +	case DWC3_MODE_HOST: +		dwc3_host_exit(dwc); +		break; +	case DWC3_MODE_DRD: +		dwc3_host_exit(dwc); +		dwc3_gadget_exit(dwc); +		break; +	default: +		/* do nothing */ +		break; +	}  err4:  	dwc3_core_exit(dwc); @@ -420,10 +563,8 @@ err0:  static int __devexit dwc3_remove(struct platform_device *pdev)  { -	const struct platform_device_id *id = platform_get_device_id(pdev);  	struct dwc3	*dwc = platform_get_drvdata(pdev);  	struct resource	*res; -	unsigned int	features = id->driver_data;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -432,8 +573,21 @@ static int __devexit dwc3_remove(struct platform_device *pdev)  	dwc3_debugfs_exit(dwc); -	if (features & DWC3_HAS_PERIPHERAL) +	switch (dwc->mode) { +	case DWC3_MODE_DEVICE:  		dwc3_gadget_exit(dwc); +		break; +	case DWC3_MODE_HOST: +		dwc3_host_exit(dwc); +		break; +	case DWC3_MODE_DRD: +		dwc3_host_exit(dwc); +		dwc3_gadget_exit(dwc); +		break; +	default: +		/* do nothing */ +		break; +	}  	dwc3_core_exit(dwc);  	release_mem_region(res->start, resource_size(res)); @@ -443,30 +597,15 @@ static int __devexit dwc3_remove(struct platform_device *pdev)  	return 0;  } -static const struct platform_device_id dwc3_id_table[] __devinitconst = { -	{ -		.name	= "dwc3-omap", -		.driver_data = (DWC3_HAS_PERIPHERAL -			| DWC3_HAS_XHCI -			| DWC3_HAS_OTG), -	}, -	{ -		.name	= "dwc3-pci", -		.driver_data = DWC3_HAS_PERIPHERAL, -	}, -	{  },	/* Terminating Entry */ -}; -MODULE_DEVICE_TABLE(platform, dwc3_id_table); -  static struct platform_driver dwc3_driver = {  	.probe		= dwc3_probe,  	.remove		= __devexit_p(dwc3_remove),  	.driver		= {  		.name	= "dwc3",  	}, -	.id_table	= dwc3_id_table,  }; +MODULE_ALIAS("platform:dwc3");  MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");  MODULE_LICENSE("Dual BSD/GPL");  MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 29a8e1679e1..9e57f8e9bf1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -41,6 +41,7 @@  #include <linux/device.h>  #include <linux/spinlock.h> +#include <linux/ioport.h>  #include <linux/list.h>  #include <linux/dma-mapping.h>  #include <linux/mm.h> @@ -52,7 +53,6 @@  /* Global constants */  #define DWC3_ENDPOINTS_NUM	32 -#define DWC3_EVENT_BUFFERS_NUM	2  #define DWC3_EVENT_BUFFERS_SIZE	PAGE_SIZE  #define DWC3_EVENT_TYPE_MASK	0xfe @@ -153,6 +153,7 @@  #define DWC3_GCTL_CLK_PIPEHALF	(2)  #define DWC3_GCTL_CLK_MASK	(3) +#define DWC3_GCTL_PRTCAP(n)	(((n) & (3 << 12)) >> 12)  #define DWC3_GCTL_PRTCAPDIR(n)	(n << 12)  #define DWC3_GCTL_PRTCAP_HOST	1  #define DWC3_GCTL_PRTCAP_DEVICE	2 @@ -347,6 +348,7 @@ struct dwc3_ep {  	u32			free_slot;  	u32			busy_slot;  	const struct usb_endpoint_descriptor *desc; +	const struct usb_ss_ep_comp_descriptor *comp_desc;  	struct dwc3		*dwc;  	unsigned		flags; @@ -536,6 +538,31 @@ struct dwc3_hwparams {  	u32	hwparams8;  }; +/* HWPARAMS0 */ +#define DWC3_MODE(n)		((n) & 0x7) + +#define DWC3_MODE_DEVICE	0 +#define DWC3_MODE_HOST		1 +#define DWC3_MODE_DRD		2 +#define DWC3_MODE_HUB		3 + +/* HWPARAMS1 */ +#define DWC3_NUM_INT(n)	(((n) & (0x3f << 15)) >> 15) + +struct dwc3_request { +	struct usb_request	request; +	struct list_head	list; +	struct dwc3_ep		*dep; + +	u8			epnum; +	struct dwc3_trb_hw	*trb; +	dma_addr_t		trb_dma; + +	unsigned		direction:1; +	unsigned		mapped:1; +	unsigned		queued:1; +}; +  /**   * struct dwc3 - representation of our controller   * @ctrl_req: usb control request which is used for ep0 @@ -549,19 +576,24 @@ struct dwc3_hwparams {   * @ep0_bounce_addr: dma address of ep0_bounce   * @lock: for synchronizing   * @dev: pointer to our struct device + * @xhci: pointer to our xHCI child   * @event_buffer_list: a list of event buffers   * @gadget: device side representation of the peripheral controller   * @gadget_driver: pointer to the gadget driver   * @regs: base address for our registers   * @regs_size: address space size   * @irq: IRQ number + * @num_event_buffers: calculated number of event buffers + * @u1u2: only used on revisions <1.83a for workaround + * @maximum_speed: maximum speed requested (mainly for testing purposes)   * @revision: revision register contents + * @mode: mode of operation   * @is_selfpowered: true when we are selfpowered   * @three_stage_setup: set if we perform a three phase setup - * @ep0_status_pending: ep0 status response without a req is pending   * @ep0_bounced: true when we used bounce buffer   * @ep0_expect_in: true when we expect a DATA IN transfer   * @start_config_issued: true when StartConfig command has been issued + * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround   * @ep0_next_event: hold the next expected event   * @ep0state: state of endpoint zero   * @link_state: link state @@ -579,12 +611,15 @@ struct dwc3 {  	dma_addr_t		ep0_trb_addr;  	dma_addr_t		setup_buf_addr;  	dma_addr_t		ep0_bounce_addr; -	struct usb_request	ep0_usb_req; +	struct dwc3_request	ep0_usb_req;  	/* device lock */  	spinlock_t		lock;  	struct device		*dev; -	struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM]; +	struct platform_device	*xhci; +	struct resource		*res; + +	struct dwc3_event_buffer **ev_buffs;  	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];  	struct usb_gadget	gadget; @@ -595,7 +630,11 @@ struct dwc3 {  	int			irq; +	u32			num_event_buffers; +	u32			u1u2; +	u32			maximum_speed;  	u32			revision; +	u32			mode;  #define DWC3_REVISION_173A	0x5533173a  #define DWC3_REVISION_175A	0x5533175a @@ -607,10 +646,11 @@ struct dwc3 {  	unsigned		is_selfpowered:1;  	unsigned		three_stage_setup:1; -	unsigned		ep0_status_pending:1;  	unsigned		ep0_bounced:1;  	unsigned		ep0_expect_in:1;  	unsigned		start_config_issued:1; +	unsigned		setup_packet_pending:1; +	unsigned		delayed_status:1;  	enum dwc3_ep0_next	ep0_next_event;  	enum dwc3_ep0_state	ep0state; @@ -765,4 +805,16 @@ union dwc3_event {  #define DWC3_HAS_XHCI			BIT(1)  #define DWC3_HAS_OTG			BIT(3) +/* prototypes */ +void dwc3_set_mode(struct dwc3 *dwc, u32 mode); + +int dwc3_host_init(struct dwc3 *dwc); +void dwc3_host_exit(struct dwc3 *dwc); + +int dwc3_gadget_init(struct dwc3 *dwc); +void dwc3_gadget_exit(struct dwc3 *dwc); + +extern int dwc3_get_device_id(void); +extern void dwc3_put_device_id(int id); +  #endif /* __DRIVERS_USB_DWC3_CORE_H */ diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index da1ad77d8d5..87d403df1f3 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -44,12 +44,12 @@  #include <linux/debugfs.h>  #include <linux/seq_file.h>  #include <linux/delay.h> - -#include <asm/uaccess.h> +#include <linux/uaccess.h>  #include "core.h"  #include "gadget.h"  #include "io.h" +#include "debug.h"  struct dwc3_register {  	const char	*name; @@ -405,6 +405,75 @@ static const struct file_operations dwc3_regdump_fops = {  	.release		= single_release,  }; +static int dwc3_mode_show(struct seq_file *s, void *unused) +{ +	struct dwc3		*dwc = s->private; +	unsigned long		flags; +	u32			reg; + +	spin_lock_irqsave(&dwc->lock, flags); +	reg = dwc3_readl(dwc->regs, DWC3_GCTL); +	spin_unlock_irqrestore(&dwc->lock, flags); + +	switch (DWC3_GCTL_PRTCAP(reg)) { +	case DWC3_GCTL_PRTCAP_HOST: +		seq_printf(s, "host\n"); +		break; +	case DWC3_GCTL_PRTCAP_DEVICE: +		seq_printf(s, "device\n"); +		break; +	case DWC3_GCTL_PRTCAP_OTG: +		seq_printf(s, "OTG\n"); +		break; +	default: +		seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg)); +	} + +	return 0; +} + +static int dwc3_mode_open(struct inode *inode, struct file *file) +{ +	return single_open(file, dwc3_mode_show, inode->i_private); +} + +static ssize_t dwc3_mode_write(struct file *file, +		const char __user *ubuf, size_t count, loff_t *ppos) +{ +	struct seq_file		*s = file->private_data; +	struct dwc3		*dwc = s->private; +	unsigned long		flags; +	u32			mode = 0; +	char			buf[32]; + +	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) +		return -EFAULT; + +	if (!strncmp(buf, "host", 4)) +		mode |= DWC3_GCTL_PRTCAP_HOST; + +	if (!strncmp(buf, "device", 6)) +		mode |= DWC3_GCTL_PRTCAP_DEVICE; + +	if (!strncmp(buf, "otg", 3)) +		mode |= DWC3_GCTL_PRTCAP_OTG; + +	if (mode) { +		spin_lock_irqsave(&dwc->lock, flags); +		dwc3_set_mode(dwc, mode); +		spin_unlock_irqrestore(&dwc->lock, flags); +	} +	return count; +} + +static const struct file_operations dwc3_mode_fops = { +	.open			= dwc3_mode_open, +	.write			= dwc3_mode_write, +	.read			= seq_read, +	.llseek			= seq_lseek, +	.release		= single_release, +}; +  int __devinit dwc3_debugfs_init(struct dwc3 *dwc)  {  	struct dentry		*root; @@ -412,7 +481,7 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)  	int			ret;  	root = debugfs_create_dir(dev_name(dwc->dev), NULL); -	if (IS_ERR(root)){ +	if (IS_ERR(root)) {  		ret = PTR_ERR(root);  		goto err0;  	} @@ -425,6 +494,14 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)  		ret = PTR_ERR(file);  		goto err1;  	} + +	file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, +			dwc, &dwc3_mode_fops); +	if (IS_ERR(file)) { +		ret = PTR_ERR(file); +		goto err1; +	} +  	return 0;  err1: diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 4e27d5bf40a..3274ac8f120 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -48,6 +48,7 @@  #include <linux/io.h>  #include <linux/module.h> +#include "core.h"  #include "io.h"  /* @@ -200,6 +201,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)  	struct dwc3_omap	*omap;  	struct resource		*res; +	int			devid;  	int			ret = -ENOMEM;  	int			irq; @@ -236,16 +238,20 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)  		goto err1;  	} -	dwc3 = platform_device_alloc("dwc3-omap", -1); +	devid = dwc3_get_device_id(); +	if (devid < 0) +		goto err2; + +	dwc3 = platform_device_alloc("dwc3", devid);  	if (!dwc3) {  		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); -		goto err2; +		goto err3;  	}  	context = kzalloc(resource_size(res), GFP_KERNEL);  	if (!context) {  		dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n"); -		goto err3; +		goto err4;  	}  	spin_lock_init(&omap->lock); @@ -299,7 +305,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)  	if (ret) {  		dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",  				omap->irq, ret); -		goto err4; +		goto err5;  	}  	/* enable all IRQs */ @@ -322,26 +328,29 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)  			pdev->num_resources);  	if (ret) {  		dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n"); -		goto err5; +		goto err6;  	}  	ret = platform_device_add(dwc3);  	if (ret) {  		dev_err(&pdev->dev, "failed to register dwc3 device\n"); -		goto err5; +		goto err6;  	}  	return 0; -err5: +err6:  	free_irq(omap->irq, omap); -err4: +err5:  	kfree(omap->context); -err3: +err4:  	platform_device_put(dwc3); +err3: +	dwc3_put_device_id(devid); +  err2:  	iounmap(base); @@ -358,6 +367,7 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev)  	platform_device_unregister(omap->dwc3); +	dwc3_put_device_id(omap->dwc3->id);  	free_irq(omap->irq, omap);  	iounmap(omap->base); @@ -386,6 +396,7 @@ static struct platform_driver dwc3_omap_driver = {  module_platform_driver(dwc3_omap_driver); +MODULE_ALIAS("platform:omap-dwc3");  MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");  MODULE_LICENSE("Dual BSD/GPL");  MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index f77c0004268..cd1429f168c 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -42,52 +42,17 @@  #include <linux/pci.h>  #include <linux/platform_device.h> +#include "core.h" +  /* FIXME define these in <linux/pci_ids.h> */  #define PCI_VENDOR_ID_SYNOPSYS		0x16c3  #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd -#define DWC3_PCI_DEVS_POSSIBLE	32 -  struct dwc3_pci {  	struct device		*dev;  	struct platform_device	*dwc3;  }; -static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE); - -static int dwc3_pci_get_device_id(struct dwc3_pci *glue) -{ -	int		id; - -again: -	id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE); -	if (id < DWC3_PCI_DEVS_POSSIBLE) { -		int old; - -		old = test_and_set_bit(id, dwc3_pci_devs); -		if (old) -			goto again; -	} else { -		dev_err(glue->dev, "no space for new device\n"); -		id = -ENOMEM; -	} - -	return 0; -} - -static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id) -{ -	int			ret; - -	if (id < 0) -		return; - -	ret = test_bit(id, dwc3_pci_devs); -	WARN(!ret, "Device: %s\nID %d not in use\n", -			dev_driver_string(glue->dev), id); -	clear_bit(id, dwc3_pci_devs); -} -  static int __devinit dwc3_pci_probe(struct pci_dev *pci,  		const struct pci_device_id *id)  { @@ -114,11 +79,11 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,  	pci_set_power_state(pci, PCI_D0);  	pci_set_master(pci); -	devid = dwc3_pci_get_device_id(glue); +	devid = dwc3_get_device_id();  	if (devid < 0)  		goto err2; -	dwc3 = platform_device_alloc("dwc3-pci", devid); +	dwc3 = platform_device_alloc("dwc3", devid);  	if (!dwc3) {  		dev_err(&pci->dev, "couldn't allocate dwc3 device\n");  		goto err3; @@ -163,7 +128,7 @@ err4:  	platform_device_put(dwc3);  err3: -	dwc3_pci_put_device_id(glue, devid); +	dwc3_put_device_id(devid);  err2:  	pci_disable_device(pci); @@ -179,7 +144,7 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)  {  	struct dwc3_pci	*glue = pci_get_drvdata(pci); -	dwc3_pci_put_device_id(glue, glue->dwc3->id); +	dwc3_put_device_id(glue->dwc3->id);  	platform_device_unregister(glue->dwc3);  	pci_set_drvdata(pci, NULL);  	pci_disable_device(pci); @@ -196,7 +161,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {  MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);  static struct pci_driver dwc3_pci_driver = { -	.name		= "pci-dwc3", +	.name		= "dwc3-pci",  	.id_table	= dwc3_pci_id_table,  	.probe		= dwc3_pci_probe,  	.remove		= __devexit_p(dwc3_pci_remove), diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 69a4e43ddf5..2f51de57593 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -48,13 +48,13 @@  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> +#include <linux/usb/composite.h>  #include "core.h"  #include "gadget.h"  #include "io.h" -static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, -		const struct dwc3_event_depevt *event); +static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);  static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)  { @@ -125,6 +125,8 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,  static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,  		struct dwc3_request *req)  { +	struct dwc3		*dwc = dep->dwc; +	u32			type;  	int			ret = 0;  	req->request.actual	= 0; @@ -143,9 +145,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,  	 * IRQ we were waiting for is long gone.  	 */  	if (dep->flags & DWC3_EP_PENDING_REQUEST) { -		struct dwc3	*dwc = dep->dwc;  		unsigned	direction; -		u32		type;  		direction = !!(dep->flags & DWC3_EP0_DIR_IN); @@ -165,6 +165,13 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,  				req->request.dma, req->request.length, type);  		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |  				DWC3_EP0_DIR_IN); +	} else if (dwc->delayed_status) { +		dwc->delayed_status = false; + +		if (dwc->ep0state == EP0_STATUS_PHASE) +			dwc3_ep0_do_control_status(dwc, 1); +		else +			dev_dbg(dwc->dev, "too early for delayed status\n");  	}  	return ret; @@ -190,9 +197,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,  	}  	/* we share one TRB for ep0/1 */ -	if (!list_empty(&dwc->eps[0]->request_list) || -			!list_empty(&dwc->eps[1]->request_list) || -			dwc->ep0_status_pending) { +	if (!list_empty(&dep->request_list)) {  		ret = -EBUSY;  		goto out;  	} @@ -214,8 +219,9 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)  	struct dwc3_ep		*dep = dwc->eps[0];  	/* stall is always issued on EP0 */ -	__dwc3_gadget_ep_set_halt(dwc->eps[0], 1); -	dwc->eps[0]->flags = DWC3_EP_ENABLED; +	__dwc3_gadget_ep_set_halt(dep, 1); +	dep->flags = DWC3_EP_ENABLED; +	dwc->delayed_status = false;  	if (!list_empty(&dep->request_list)) {  		struct dwc3_request	*req; @@ -254,17 +260,14 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)  	return NULL;  } -static void dwc3_ep0_send_status_response(struct dwc3 *dwc) +static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req)  { -	dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr, -			dwc->ep0_usb_req.length, -			DWC3_TRBCTL_CONTROL_DATA);  } -  /*   * ch 9.4.5   */ -static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) +static int dwc3_ep0_handle_status(struct dwc3 *dwc, +		struct usb_ctrlrequest *ctrl)  {  	struct dwc3_ep		*dep;  	u32			recip; @@ -291,7 +294,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl  	case USB_RECIP_ENDPOINT:  		dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);  		if (!dep) -		       return -EINVAL; +			return -EINVAL;  		if (dep->flags & DWC3_EP_STALL)  			usb_status = 1 << USB_ENDPOINT_HALT; @@ -302,10 +305,14 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl  	response_pkt = (__le16 *) dwc->setup_buf;  	*response_pkt = cpu_to_le16(usb_status); -	dwc->ep0_usb_req.length = sizeof(*response_pkt); -	dwc->ep0_status_pending = 1; -	return 0; +	dep = dwc->eps[0]; +	dwc->ep0_usb_req.dep = dep; +	dwc->ep0_usb_req.request.length = sizeof(*response_pkt); +	dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr; +	dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; + +	return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);  }  static int dwc3_ep0_handle_feature(struct dwc3 *dwc, @@ -396,8 +403,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,  	case USB_RECIP_ENDPOINT:  		switch (wValue) {  		case USB_ENDPOINT_HALT: - -			dep =  dwc3_wIndex_to_dep(dwc, ctrl->wIndex); +			dep =  dwc3_wIndex_to_dep(dwc, wIndex);  			if (!dep)  				return -EINVAL;  			ret = __dwc3_gadget_ep_set_halt(dep, set); @@ -422,8 +428,15 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)  	u32 reg;  	addr = le16_to_cpu(ctrl->wValue); -	if (addr > 127) +	if (addr > 127) { +		dev_dbg(dwc->dev, "invalid device address %d\n", addr);  		return -EINVAL; +	} + +	if (dwc->dev_state == DWC3_CONFIGURED_STATE) { +		dev_dbg(dwc->dev, "trying to set address when configured\n"); +		return -EINVAL; +	}  	reg = dwc3_readl(dwc->regs, DWC3_DCFG);  	reg &= ~(DWC3_DCFG_DEVADDR_MASK); @@ -473,8 +486,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)  		if (!cfg)  			dwc->dev_state = DWC3_ADDRESS_STATE;  		break; +	default: +		ret = -EINVAL;  	} -	return 0; +	return ret;  }  static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) @@ -537,6 +552,9 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,  	else  		ret = dwc3_ep0_delegate_req(dwc, ctrl); +	if (ret == USB_GADGET_DELAYED_STATUS) +		dwc->delayed_status = true; +  	if (ret >= 0)  		return; @@ -550,27 +568,21 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,  	struct dwc3_request	*r = NULL;  	struct usb_request	*ur;  	struct dwc3_trb		trb; -	struct dwc3_ep		*dep; +	struct dwc3_ep		*ep0;  	u32			transferred;  	u8			epnum;  	epnum = event->endpoint_number; -	dep = dwc->eps[epnum]; +	ep0 = dwc->eps[0];  	dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; -	if (!dwc->ep0_status_pending) { -		r = next_request(&dwc->eps[0]->request_list); -		ur = &r->request; -	} else { -		ur = &dwc->ep0_usb_req; -		dwc->ep0_status_pending = 0; -	} +	r = next_request(&ep0->request_list); +	ur = &r->request;  	dwc3_trb_to_nat(dwc->ep0_trb, &trb);  	if (dwc->ep0_bounced) { -		struct dwc3_ep	*ep0 = dwc->eps[0];  		transferred = min_t(u32, ur->length,  				ep0->endpoint.maxpacket - trb.length); @@ -591,7 +603,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,  		 * seems to be case when req.length > maxpacket. Could it be?  		 */  		if (r) -			dwc3_gadget_giveback(dep, r, 0); +			dwc3_gadget_giveback(ep0, r, 0);  	}  } @@ -619,6 +631,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,  	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];  	dep->flags &= ~DWC3_EP_BUSY; +	dwc->setup_packet_pending = false;  	switch (dwc->ep0state) {  	case EP0_SETUP_PHASE: @@ -643,7 +656,6 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,  static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,  		const struct dwc3_event_depevt *event)  { -	dwc->ep0state = EP0_SETUP_PHASE;  	dwc3_ep0_out_start(dwc);  } @@ -655,12 +667,6 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,  	int			ret;  	dep = dwc->eps[0]; -	dwc->ep0state = EP0_DATA_PHASE; - -	if (dwc->ep0_status_pending) { -		dwc3_ep0_send_status_response(dwc); -		return; -	}  	if (list_empty(&dep->request_list)) {  		dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); @@ -674,7 +680,6 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,  	req = next_request(&dep->request_list);  	req->direction = !!event->endpoint_number; -	dwc->ep0state = EP0_DATA_PHASE;  	if (req->request.length == 0) {  		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,  				dwc->ctrl_req_addr, 0, @@ -706,35 +711,79 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,  	WARN_ON(ret < 0);  } -static void dwc3_ep0_do_control_status(struct dwc3 *dwc, -		const struct dwc3_event_depevt *event) +static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)  { +	struct dwc3		*dwc = dep->dwc;  	u32			type; -	int			ret; - -	dwc->ep0state = EP0_STATUS_PHASE;  	type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3  		: DWC3_TRBCTL_CONTROL_STATUS2; -	ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, +	return dwc3_ep0_start_trans(dwc, dep->number,  			dwc->ctrl_req_addr, 0, type); +} -	WARN_ON(ret < 0); +static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum) +{ +	struct dwc3_ep		*dep = dwc->eps[epnum]; + +	WARN_ON(dwc3_ep0_start_control_status(dep));  }  static void dwc3_ep0_xfernotready(struct dwc3 *dwc,  		const struct dwc3_event_depevt *event)  { +	dwc->setup_packet_pending = true; + +	/* +	 * This part is very tricky: If we has just handled +	 * XferNotReady(Setup) and we're now expecting a +	 * XferComplete but, instead, we receive another +	 * XferNotReady(Setup), we should STALL and restart +	 * the state machine. +	 * +	 * In all other cases, we just continue waiting +	 * for the XferComplete event. +	 * +	 * We are a little bit unsafe here because we're +	 * not trying to ensure that last event was, indeed, +	 * XferNotReady(Setup). +	 * +	 * Still, we don't expect any condition where that +	 * should happen and, even if it does, it would be +	 * another error condition. +	 */ +	if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) { +		switch (event->status) { +		case DEPEVT_STATUS_CONTROL_SETUP: +			dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n"); +			dwc3_ep0_stall_and_restart(dwc); +			break; +		case DEPEVT_STATUS_CONTROL_DATA: +			/* FALLTHROUGH */ +		case DEPEVT_STATUS_CONTROL_STATUS: +			/* FALLTHROUGH */ +		default: +			dev_vdbg(dwc->dev, "waiting for XferComplete\n"); +		} + +		return; +	} +  	switch (event->status) {  	case DEPEVT_STATUS_CONTROL_SETUP:  		dev_vdbg(dwc->dev, "Control Setup\n"); + +		dwc->ep0state = EP0_SETUP_PHASE; +  		dwc3_ep0_do_control_setup(dwc, event);  		break;  	case DEPEVT_STATUS_CONTROL_DATA:  		dev_vdbg(dwc->dev, "Control Data\n"); +		dwc->ep0state = EP0_DATA_PHASE; +  		if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {  			dev_vdbg(dwc->dev, "Expected %d got %d\n",  					dwc->ep0_next_event, @@ -764,6 +813,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,  	case DEPEVT_STATUS_CONTROL_STATUS:  		dev_vdbg(dwc->dev, "Control Status\n"); +		dwc->ep0state = EP0_STATUS_PHASE; +  		if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {  			dev_vdbg(dwc->dev, "Expected %d got %d\n",  					dwc->ep0_next_event, @@ -772,12 +823,19 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,  			dwc3_ep0_stall_and_restart(dwc);  			return;  		} -		dwc3_ep0_do_control_status(dwc, event); + +		if (dwc->delayed_status) { +			WARN_ON_ONCE(event->endpoint_number != 1); +			dev_vdbg(dwc->dev, "Mass Storage delayed status\n"); +			return; +		} + +		dwc3_ep0_do_control_status(dwc, event->endpoint_number);  	}  }  void dwc3_ep0_interrupt(struct dwc3 *dwc, -		const const struct dwc3_event_depevt *event) +		const struct dwc3_event_depevt *event)  {  	u8			epnum = event->endpoint_number; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 25dbd8614e7..026c53cf164 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -251,7 +251,8 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)  }  static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, -		const struct usb_endpoint_descriptor *desc) +		const struct usb_endpoint_descriptor *desc, +		const struct usb_ss_ep_comp_descriptor *comp_desc)  {  	struct dwc3_gadget_ep_cmd_params params; @@ -264,7 +265,8 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,  	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN  		| DWC3_DEPCFG_XFER_NOT_READY_EN; -	if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) { +	if (comp_desc && USB_SS_MAX_STREAMS(comp_desc->bmAttributes) +			&& usb_endpoint_xfer_bulk(desc)) {  		params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE  			| DWC3_DEPCFG_STREAM_EVENT_EN;  		dep->stream_capable = true; @@ -317,7 +319,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)   * Caller should take care of locking   */  static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, -		const struct usb_endpoint_descriptor *desc) +		const struct usb_endpoint_descriptor *desc, +		const struct usb_ss_ep_comp_descriptor *comp_desc)  {  	struct dwc3		*dwc = dep->dwc;  	u32			reg; @@ -329,7 +332,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  			return ret;  	} -	ret = dwc3_gadget_set_ep_config(dwc, dep, desc); +	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);  	if (ret)  		return ret; @@ -343,6 +346,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  			return ret;  		dep->desc = desc; +		dep->comp_desc = comp_desc;  		dep->type = usb_endpoint_type(desc);  		dep->flags |= DWC3_EP_ENABLED; @@ -405,6 +409,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)  	dep->stream_capable = false;  	dep->desc = NULL; +	dep->comp_desc = NULL;  	dep->type = 0;  	dep->flags = 0; @@ -473,7 +478,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,  	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);  	spin_lock_irqsave(&dwc->lock, flags); -	ret = __dwc3_gadget_ep_enable(dep, desc); +	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc);  	spin_unlock_irqrestore(&dwc->lock, flags);  	return ret; @@ -745,8 +750,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,  	dep->flags |= DWC3_EP_BUSY;  	dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,  			dep->number); -	if (!dep->res_trans_idx) -		printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__); + +	WARN_ON_ONCE(!dep->res_trans_idx); +  	return 0;  } @@ -1155,35 +1161,9 @@ static int dwc3_gadget_start(struct usb_gadget *g,  	dwc->gadget_driver	= driver;  	dwc->gadget.dev.driver	= &driver->driver; -	reg = dwc3_readl(dwc->regs, DWC3_GCTL); - -	reg &= ~DWC3_GCTL_SCALEDOWN(3); -	reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG); -	reg &= ~DWC3_GCTL_DISSCRAMBLE; -	reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE); - -	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) { -	case DWC3_GHWPARAMS1_EN_PWROPT_CLK: -		reg &= ~DWC3_GCTL_DSBLCLKGTNG; -		break; -	default: -		dev_dbg(dwc->dev, "No power optimization available\n"); -	} - -	/* -	 * WORKAROUND: DWC3 revisions <1.90a have a bug -	 * when The device fails to connect at SuperSpeed -	 * and falls back to high-speed mode which causes -	 * the device to enter in a Connect/Disconnect loop -	 */ -	if (dwc->revision < DWC3_REVISION_190A) -		reg |= DWC3_GCTL_U2RSTECN; - -	dwc3_writel(dwc->regs, DWC3_GCTL, reg); -  	reg = dwc3_readl(dwc->regs, DWC3_DCFG);  	reg &= ~(DWC3_DCFG_SPEED_MASK); -	reg |= DWC3_DCFG_SUPERSPEED; +	reg |= dwc->maximum_speed;  	dwc3_writel(dwc->regs, DWC3_DCFG, reg);  	dwc->start_config_issued = false; @@ -1192,14 +1172,14 @@ static int dwc3_gadget_start(struct usb_gadget *g,  	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		goto err0;  	}  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		goto err1; @@ -1290,11 +1270,10 @@ static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)  					&dwc->gadget.ep_list);  			ret = dwc3_alloc_trb_pool(dep); -			if (ret) { -				dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name); +			if (ret)  				return ret; -			}  		} +  		INIT_LIST_HEAD(&dep->request_list);  		INIT_LIST_HEAD(&dep->req_queued);  	} @@ -1334,8 +1313,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,  	do {  		req = next_request(&dep->req_queued); -		if (!req) -			break; +		if (!req) { +			WARN_ON_ONCE(1); +			return 1; +		}  		dwc3_trb_to_nat(req->trb, &trb); @@ -1400,6 +1381,31 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,  		dep->flags &= ~DWC3_EP_BUSY;  		dep->res_trans_idx = 0;  	} + +	/* +	 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround. +	 * See dwc3_gadget_linksts_change_interrupt() for 1st half. +	 */ +	if (dwc->revision < DWC3_REVISION_183A) { +		u32		reg; +		int		i; + +		for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { +			struct dwc3_ep	*dep = dwc->eps[i]; + +			if (!(dep->flags & DWC3_EP_ENABLED)) +				continue; + +			if (!list_empty(&dep->req_queued)) +				return; +		} + +		reg = dwc3_readl(dwc->regs, DWC3_DCTL); +		reg |= dwc->u1u2; +		dwc3_writel(dwc->regs, DWC3_DCTL, reg); + +		dwc->u1u2 = 0; +	}  }  static void dwc3_gadget_start_isoc(struct dwc3 *dwc, @@ -1639,6 +1645,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)  	dwc->start_config_issued = false;  	dwc->gadget.speed = USB_SPEED_UNKNOWN; +	dwc->setup_packet_pending = false;  }  static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on) @@ -1675,6 +1682,37 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)  	dev_vdbg(dwc->dev, "%s\n", __func__); +	/* +	 * WORKAROUND: DWC3 revisions <1.88a have an issue which +	 * would cause a missing Disconnect Event if there's a +	 * pending Setup Packet in the FIFO. +	 * +	 * There's no suggested workaround on the official Bug +	 * report, which states that "unless the driver/application +	 * is doing any special handling of a disconnect event, +	 * there is no functional issue". +	 * +	 * Unfortunately, it turns out that we _do_ some special +	 * handling of a disconnect event, namely complete all +	 * pending transfers, notify gadget driver of the +	 * disconnection, and so on. +	 * +	 * Our suggested workaround is to follow the Disconnect +	 * Event steps here, instead, based on a setup_packet_pending +	 * flag. Such flag gets set whenever we have a XferNotReady +	 * event on EP0 and gets cleared on XferComplete for the +	 * same endpoint. +	 * +	 * Refers to: +	 * +	 * STAR#9000466709: RTL: Device : Disconnect event not +	 * generated if setup packet pending in FIFO +	 */ +	if (dwc->revision < DWC3_REVISION_188A) { +		if (dwc->setup_packet_pending) +			dwc3_gadget_disconnect_interrupt(dwc); +	} +  	/* Enable PHYs */  	dwc3_gadget_usb2_phy_power(dwc, true);  	dwc3_gadget_usb3_phy_power(dwc, true); @@ -1755,6 +1793,22 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)  	switch (speed) {  	case DWC3_DCFG_SUPERSPEED: +		/* +		 * WORKAROUND: DWC3 revisions <1.90a have an issue which +		 * would cause a missing USB3 Reset event. +		 * +		 * In such situations, we should force a USB3 Reset +		 * event by calling our dwc3_gadget_reset_interrupt() +		 * routine. +		 * +		 * Refers to: +		 * +		 * STAR#9000483510: RTL: SS : USB3 reset event may +		 * not be generated always when the link enters poll +		 */ +		if (dwc->revision < DWC3_REVISION_190A) +			dwc3_gadget_reset_interrupt(dwc); +  		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);  		dwc->gadget.ep0->maxpacket = 512;  		dwc->gadget.speed = USB_SPEED_SUPER; @@ -1781,14 +1835,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)  	dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		return;  	}  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		return; @@ -1818,8 +1872,55 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)  static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,  		unsigned int evtinfo)  { -	/*  The fith bit says SuperSpeed yes or no. */ -	dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK; +	enum dwc3_link_state	next = evtinfo & DWC3_LINK_STATE_MASK; + +	/* +	 * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending +	 * on the link partner, the USB session might do multiple entry/exit +	 * of low power states before a transfer takes place. +	 * +	 * Due to this problem, we might experience lower throughput. The +	 * suggested workaround is to disable DCTL[12:9] bits if we're +	 * transitioning from U1/U2 to U0 and enable those bits again +	 * after a transfer completes and there are no pending transfers +	 * on any of the enabled endpoints. +	 * +	 * This is the first half of that workaround. +	 * +	 * Refers to: +	 * +	 * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us +	 * core send LGO_Ux entering U0 +	 */ +	if (dwc->revision < DWC3_REVISION_183A) { +		if (next == DWC3_LINK_STATE_U0) { +			u32	u1u2; +			u32	reg; + +			switch (dwc->link_state) { +			case DWC3_LINK_STATE_U1: +			case DWC3_LINK_STATE_U2: +				reg = dwc3_readl(dwc->regs, DWC3_DCTL); +				u1u2 = reg & (DWC3_DCTL_INITU2ENA +						| DWC3_DCTL_ACCEPTU2ENA +						| DWC3_DCTL_INITU1ENA +						| DWC3_DCTL_ACCEPTU1ENA); + +				if (!dwc->u1u2) +					dwc->u1u2 = reg & u1u2; + +				reg &= ~u1u2; + +				dwc3_writel(dwc->regs, DWC3_DCTL, reg); +				break; +			default: +				/* do nothing */ +				break; +			} +		} +	} + +	dwc->link_state = next;  	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);  } @@ -1925,7 +2026,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)  	spin_lock(&dwc->lock); -	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) { +	for (i = 0; i < dwc->num_event_buffers; i++) {  		irqreturn_t status;  		status = dwc3_process_event_buf(dwc, i); @@ -2076,7 +2177,6 @@ err0:  void dwc3_gadget_exit(struct dwc3 *dwc)  {  	int			irq; -	int			i;  	usb_del_gadget_udc(&dwc->gadget);  	irq = platform_get_irq(to_platform_device(dwc->dev), 0); @@ -2084,9 +2184,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc)  	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);  	free_irq(irq, dwc); -	for (i = 0; i < ARRAY_SIZE(dwc->eps); i++) -		__dwc3_gadget_ep_disable(dwc->eps[i]); -  	dwc3_gadget_free_endpoints(dwc);  	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 71145a449d9..d97f467d41c 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -79,19 +79,6 @@ struct dwc3_gadget_ep_cmd_params {  /* -------------------------------------------------------------------------- */ -struct dwc3_request { -	struct usb_request	request; -	struct list_head	list; -	struct dwc3_ep		*dep; - -	u8			epnum; -	struct dwc3_trb_hw	*trb; -	dma_addr_t		trb_dma; - -	unsigned		direction:1; -	unsigned		mapped:1; -	unsigned		queued:1; -};  #define to_dwc3_request(r)	(container_of(r, struct dwc3_request, request))  static inline struct dwc3_request *next_request(struct list_head *list) @@ -110,23 +97,11 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)  	list_move_tail(&req->list, &dep->req_queued);  } -#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE) -int dwc3_gadget_init(struct dwc3 *dwc); -void dwc3_gadget_exit(struct dwc3 *dwc); -#else -static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; } -static inline void dwc3_gadget_exit(struct dwc3 *dwc) { } -static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, -		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) -{ -	return 0; -} -#endif -  void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,  		int status); -void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event); +void dwc3_ep0_interrupt(struct dwc3 *dwc, +		const struct dwc3_event_depevt *event);  void dwc3_ep0_out_start(struct dwc3 *dwc);  int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,  		gfp_t gfp_flags); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c new file mode 100644 index 00000000000..7cfe211b6c3 --- /dev/null +++ b/drivers/usb/dwc3/host.c @@ -0,0 +1,102 @@ +/** + * host.c - DesignWare USB3 DRD Controller Host Glue + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: Felipe Balbi <balbi@ti.com>, + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2, as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/platform_device.h> + +#include "core.h" + +static struct resource generic_resources[] = { +	{ +		.flags = IORESOURCE_IRQ, +	}, +	{ +		.flags = IORESOURCE_MEM, +	}, +}; + +int dwc3_host_init(struct dwc3 *dwc) +{ +	struct platform_device	*xhci; +	int			ret; + +	xhci = platform_device_alloc("xhci", -1); +	if (!xhci) { +		dev_err(dwc->dev, "couldn't allocate xHCI device\n"); +		ret = -ENOMEM; +		goto err0; +	} + +	dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask); + +	xhci->dev.parent	= dwc->dev; +	xhci->dev.dma_mask	= dwc->dev->dma_mask; +	xhci->dev.dma_parms	= dwc->dev->dma_parms; + +	dwc->xhci = xhci; + +	/* setup resources */ +	generic_resources[0].start = dwc->irq; + +	generic_resources[1].start = dwc->res->start; +	generic_resources[1].end = dwc->res->start + 0x7fff; + +	ret = platform_device_add_resources(xhci, generic_resources, +			ARRAY_SIZE(generic_resources)); +	if (ret) { +		dev_err(dwc->dev, "couldn't add resources to xHCI device\n"); +		goto err1; +	} + +	ret = platform_device_add(xhci); +	if (ret) { +		dev_err(dwc->dev, "failed to register xHCI device\n"); +		goto err1; +	} + +	return 0; + +err1: +	platform_device_put(xhci); + +err0: +	return ret; +} + +void dwc3_host_exit(struct dwc3 *dwc) +{ +	platform_device_unregister(dwc->xhci); +} diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index bc957db1ea4..071d561f3e6 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -39,7 +39,7 @@  #ifndef __DRIVERS_USB_DWC3_IO_H  #define __DRIVERS_USB_DWC3_IO_H -#include <asm/io.h> +#include <linux/io.h>  static inline u32 dwc3_readl(void __iomem *base, u32 offset)  { diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3162a7da872..71108c26c56 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -319,18 +319,6 @@ config USB_PXA_U2O  	  PXA9xx Processor series include a high speed USB2.0 device  	  controller, which support high speed and full speed USB peripheral. -config USB_GADGET_DWC3 -	tristate "DesignWare USB3.0 (DRD) Controller" -	depends on USB_DWC3 -	select USB_GADGET_DUALSPEED -	select USB_GADGET_SUPERSPEED -	help -	  DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller -	  which can be configured for peripheral-only, host-only, hub-only -	  and Dual-Role operation. This Controller was first integrated into -	  the OMAP5 series of processors. More information about the OMAP5 -	  version of this controller, refer to http://www.ti.com/omap5. -  #  # Controllers available in both integrated and discrete versions  # diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 4730016d7cd..45f422ac103 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1959,7 +1959,7 @@ static int amd5536_start(struct usb_gadget_driver *driver,  	u32 tmp;  	if (!driver || !bind || !driver->setup -			|| driver->speed != USB_SPEED_HIGH) +			|| driver->speed < USB_SPEED_HIGH)  		return -EINVAL;  	if (!dev)  		return -ENODEV; diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 91fdf790ed2..cf33a8d0fd5 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -131,8 +131,8 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  	}  	if (!gser->port.in->desc || !gser->port.out->desc) {  		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num); -		if (!config_ep_by_speed(cdev->gadget, f, gser->port.in) || -		    !config_ep_by_speed(cdev->gadget, f, gser->port.out)) { +		if (config_ep_by_speed(cdev->gadget, f, gser->port.in) || +		    config_ep_by_speed(cdev->gadget, f, gser->port.out)) {  			gser->port.in->desc = NULL;  			gser->port.out->desc = NULL;  			return -EINVAL; diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index 43a49ecc1f3..dcbc0a2e48d 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c @@ -16,6 +16,7 @@  #include <linux/err.h>  #include <linux/fsl_devices.h>  #include <linux/platform_device.h> +#include <linux/io.h>  #include <mach/hardware.h> @@ -88,7 +89,6 @@ eenahb:  void fsl_udc_clk_finalize(struct platform_device *pdev)  {  	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; -#if defined(CONFIG_SOC_IMX35)  	if (cpu_is_mx35()) {  		unsigned int v; @@ -101,7 +101,6 @@ void fsl_udc_clk_finalize(struct platform_device *pdev)  					USBPHYCTRL_OTGBASE_OFFSET));  		}  	} -#endif  	/* ULPI transceivers don't need usbpll */  	if (pdata->phy_mode == FSL_USB2_PHY_ULPI) { diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 811ea76ae76..f75c56a259a 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2336,8 +2336,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver,  	if (!udc_controller)  		return -ENODEV; -	if (!driver || (driver->speed != USB_SPEED_FULL -			&& driver->speed != USB_SPEED_HIGH) +	if (!driver || driver->speed < USB_SPEED_FULL  			|| !bind || !driver->disconnect || !driver->setup)  		return -EINVAL; diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index b3b3d83b7c3..dd28ef3def7 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -696,12 +696,31 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)  		kfree(req);  } -/*-------------------------------------------------------------------------*/ +/* Actually add a dTD chain to an empty dQH and let go */ +static void fsl_prime_ep(struct fsl_ep *ep, struct ep_td_struct *td) +{ +	struct ep_queue_head *qh = get_qh_by_ep(ep); + +	/* Write dQH next pointer and terminate bit to 0 */ +	qh->next_dtd_ptr = cpu_to_hc32(td->td_dma +			& EP_QUEUE_HEAD_NEXT_POINTER_MASK); + +	/* Clear active and halt bit */ +	qh->size_ioc_int_sts &= cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE +					| EP_QUEUE_HEAD_STATUS_HALT)); + +	/* Ensure that updates to the QH will occur before priming. */ +	wmb(); + +	/* Prime endpoint by writing correct bit to ENDPTPRIME */ +	fsl_writel(ep_is_in(ep) ? (1 << (ep_index(ep) + 16)) +			: (1 << (ep_index(ep))), &dr_regs->endpointprime); +} + +/* Add dTD chain to the dQH of an EP */  static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)  { -	int i = ep_index(ep) * 2 + ep_is_in(ep);  	u32 temp, bitmask, tmp_stat; -	struct ep_queue_head *dQH = &ep->udc->ep_qh[i];  	/* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr);  	VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */ @@ -719,7 +738,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)  			cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);  		/* Read prime bit, if 1 goto done */  		if (fsl_readl(&dr_regs->endpointprime) & bitmask) -			goto out; +			return;  		do {  			/* Set ATDTW bit in USBCMD */ @@ -736,28 +755,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)  		fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd);  		if (tmp_stat) -			goto out; +			return;  	} -	/* Write dQH next pointer and terminate bit to 0 */ -	temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; -	dQH->next_dtd_ptr = cpu_to_hc32(temp); - -	/* Clear active and halt bit */ -	temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE -			| EP_QUEUE_HEAD_STATUS_HALT)); -	dQH->size_ioc_int_sts &= temp; - -	/* Ensure that updates to the QH will occur before priming. */ -	wmb(); - -	/* Prime endpoint by writing 1 to ENDPTPRIME */ -	temp = ep_is_in(ep) -		? (1 << (ep_index(ep) + 16)) -		: (1 << (ep_index(ep))); -	fsl_writel(temp, &dr_regs->endpointprime); -out: -	return; +	fsl_prime_ep(ep, req->head);  }  /* Fill in the dTD structure @@ -877,7 +878,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)  		VDBG("%s, bad ep", __func__);  		return -EINVAL;  	} -	if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { +	if (usb_endpoint_xfer_isoc(ep->desc)) {  		if (req->req.length > ep->ep.maxpacket)  			return -EMSGSIZE;  	} @@ -973,25 +974,20 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)  		/* The request isn't the last request in this ep queue */  		if (req->queue.next != &ep->queue) { -			struct ep_queue_head *qh;  			struct fsl_req *next_req; -			qh = ep->qh;  			next_req = list_entry(req->queue.next, struct fsl_req,  					queue); -			/* Point the QH to the first TD of next request */ -			fsl_writel((u32) next_req->head, &qh->curr_dtd_ptr); +			/* prime with dTD of next request */ +			fsl_prime_ep(ep, next_req->head);  		} - -		/* The request hasn't been processed, patch up the TD chain */ +	/* The request hasn't been processed, patch up the TD chain */  	} else {  		struct fsl_req *prev_req;  		prev_req = list_entry(req->queue.prev, struct fsl_req, queue); -		fsl_writel(fsl_readl(&req->tail->next_td_ptr), -				&prev_req->tail->next_td_ptr); - +		prev_req->tail->next_td_ptr = req->tail->next_td_ptr;  	}  	done(ep, req, -ECONNRESET); @@ -1032,7 +1028,7 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value)  		goto out;  	} -	if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { +	if (usb_endpoint_xfer_isoc(ep->desc)) {  		status = -EOPNOTSUPP;  		goto out;  	} @@ -1068,7 +1064,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)  	struct fsl_udc *udc;  	int size = 0;  	u32 bitmask; -	struct ep_queue_head *d_qh; +	struct ep_queue_head *qh;  	ep = container_of(_ep, struct fsl_ep, ep);  	if (!_ep || (!ep->desc && ep_index(ep) != 0)) @@ -1079,13 +1075,13 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)  	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)  		return -ESHUTDOWN; -	d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)]; +	qh = get_qh_by_ep(ep);  	bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :  	    (1 << (ep_index(ep)));  	if (fsl_readl(&dr_regs->endptstatus) & bitmask) -		size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE) +		size = (qh->size_ioc_int_sts & DTD_PACKET_SIZE)  		    >> DTD_LENGTH_BIT_POS;  	pr_debug("%s %u\n", __func__, size); @@ -1938,8 +1934,7 @@ static int fsl_start(struct usb_gadget_driver *driver,  	if (!udc_controller)  		return -ENODEV; -	if (!driver || (driver->speed != USB_SPEED_FULL -				&& driver->speed != USB_SPEED_HIGH) +	if (!driver || driver->speed < USB_SPEED_FULL  			|| !bind || !driver->disconnect || !driver->setup)  		return -EINVAL; diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 1d51be83fda..f781f5dec41 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -569,6 +569,16 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)  					* 2 + ((windex & USB_DIR_IN) ? 1 : 0))  #define get_pipe_by_ep(EP)	(ep_index(EP) * 2 + ep_is_in(EP)) +static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep) +{ +	/* we only have one ep0 structure but two queue heads */ +	if (ep_index(ep) != 0) +		return ep->qh; +	else +		return &ep->udc->ep_qh[(ep->udc->ep0_dir == +				USB_DIR_IN) ? 1 : 0]; +} +  struct platform_device;  #ifdef CONFIG_ARCH_MXC  int fsl_udc_clk_init(struct platform_device *pdev); diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 91d0af2a24a..9aa1cbbee45 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1472,7 +1472,7 @@ static int m66592_start(struct usb_gadget_driver *driver,  	int retval;  	if (!driver -			|| driver->speed != USB_SPEED_HIGH +			|| driver->speed < USB_SPEED_HIGH  			|| !bind  			|| !driver->setup)  		return -EINVAL; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 7f1bc9a73cd..da2b9d0be3c 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1881,7 +1881,7 @@ static int net2280_start(struct usb_gadget *_gadget,  	 * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE)  	 * "must not be used in normal operation"  	 */ -	if (!driver || driver->speed != USB_SPEED_HIGH +	if (!driver || driver->speed < USB_SPEED_HIGH  			|| !driver->setup)  		return -EINVAL; diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 24f84b210ce..fc719a3f855 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1746,7 +1746,7 @@ static int r8a66597_start(struct usb_gadget *gadget,  	struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);  	if (!driver -			|| driver->speed != USB_SPEED_HIGH +			|| driver->speed < USB_SPEED_HIGH  			|| !driver->setup)  		return -EINVAL;  	if (!r8a66597) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 745a3081fb3..c59156c0061 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2586,10 +2586,8 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,  		return -EINVAL;  	} -	if (driver->speed != USB_SPEED_HIGH && -	    driver->speed != USB_SPEED_FULL) { +	if (driver->speed < USB_SPEED_FULL)  		dev_err(hsotg->dev, "%s: bad speed\n", __func__); -	}  	if (!bind || !driver->setup) {  		dev_err(hsotg->dev, "%s: missing entry points\n", __func__); diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index baf506a66de..787ac5baae9 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1142,8 +1142,7 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,  	int ret;  	if (!driver -		|| (driver->speed != USB_SPEED_FULL && -			driver->speed != USB_SPEED_HIGH) +		|| driver->speed < USB_SPEED_FULL  		|| !bind  		|| !driver->unbind || !driver->disconnect || !driver->setup)  		return -EINVAL; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 56a32033adb..a60679cbbf8 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1475,6 +1475,7 @@ iso_stream_schedule (  	 * jump until after the queue is primed.  	 */  	else { +		int done = 0;  		start = SCHEDULE_SLOP + (now & ~0x07);  		/* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */ @@ -1492,18 +1493,18 @@ iso_stream_schedule (  			if (stream->highspeed) {  				if (itd_slot_ok(ehci, mod, start,  						stream->usecs, period)) -					break; +					done = 1;  			} else {  				if ((start % 8) >= 6)  					continue;  				if (sitd_slot_ok(ehci, mod, stream,  						start, sched, period)) -					break; +					done = 1;  			} -		} while (start > next); +		} while (start > next && !done);  		/* no room in the schedule */ -		if (start == next) { +		if (!done) {  			ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n",  				urb, now, now + mod);  			status = -ENOSPC; diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index a91712c8bff..76083ae9213 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -124,7 +124,7 @@ void qset_clear(struct whc *whc, struct whc_qset *qset)  {  	qset->td_start = qset->td_end = qset->ntds = 0; -	qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); +	qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);  	qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;  	qset->qh.err_count = 0;  	qset->qh.scratch[0] = 0; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index aa94c019579..a1afb7c39f7 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -711,7 +711,10 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)  	ring = xhci->cmd_ring;  	seg = ring->deq_seg;  	do { -		memset(seg->trbs, 0, SEGMENT_SIZE); +		memset(seg->trbs, 0, +			sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); +		seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= +			cpu_to_le32(~TRB_CYCLE);  		seg = seg->next;  	} while (seg != ring->deq_seg); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 54958508679..227c1dfa6be 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2300,18 +2300,12 @@ static int musb_suspend(struct device *dev)  		 */  	} -	musb_save_context(musb); -  	spin_unlock_irqrestore(&musb->lock, flags);  	return 0;  }  static int musb_resume_noirq(struct device *dev)  { -	struct musb	*musb = dev_to_musb(dev); - -	musb_restore_context(musb); -  	/* for static cmos like DaVinci, register values were preserved  	 * unless for some reason the whole soc powered down or the USB  	 * module got reset through the PSC (vs just being disabled). diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index d51043acfe1..922148ff8d2 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1903,7 +1903,7 @@ static int musb_gadget_start(struct usb_gadget *g,  	unsigned long		flags;  	int			retval = -EINVAL; -	if (driver->speed != USB_SPEED_HIGH) +	if (driver->speed < USB_SPEED_HIGH)  		goto err0;  	pm_runtime_get_sync(musb->controller); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index d9717e0bc1f..7f4e8033857 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -751,53 +751,32 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,  		struct usb_gadget_driver *driver)  {  	struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); -	struct usbhs_priv *priv; -	struct device *dev; -	int ret; +	struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);  	if (!driver		||  	    !driver->setup	|| -	    driver->speed != USB_SPEED_HIGH) +	    driver->speed < USB_SPEED_FULL)  		return -EINVAL; -	dev  = usbhsg_gpriv_to_dev(gpriv); -	priv = usbhsg_gpriv_to_priv(gpriv); -  	/* first hook up the driver ... */  	gpriv->driver = driver;  	gpriv->gadget.dev.driver = &driver->driver; -	ret = device_add(&gpriv->gadget.dev); -	if (ret) { -		dev_err(dev, "device_add error %d\n", ret); -		goto add_fail; -	} -  	return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD); - -add_fail: -	gpriv->driver = NULL; -	gpriv->gadget.dev.driver = NULL; - -	return ret;  }  static int usbhsg_gadget_stop(struct usb_gadget *gadget,  		struct usb_gadget_driver *driver)  {  	struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); -	struct usbhs_priv *priv; -	struct device *dev; +	struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);  	if (!driver		||  	    !driver->unbind)  		return -EINVAL; -	dev  = usbhsg_gpriv_to_dev(gpriv); -	priv = usbhsg_gpriv_to_priv(gpriv); -  	usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD); -	device_del(&gpriv->gadget.dev); +	gpriv->gadget.dev.driver = NULL;  	gpriv->driver = NULL;  	return 0; @@ -827,6 +806,13 @@ static int usbhsg_start(struct usbhs_priv *priv)  static int usbhsg_stop(struct usbhs_priv *priv)  { +	struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + +	/* cable disconnect */ +	if (gpriv->driver && +	    gpriv->driver->disconnect) +		gpriv->driver->disconnect(&gpriv->gadget); +  	return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED);  } @@ -876,12 +862,14 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)  	/*  	 * init gadget  	 */ -	device_initialize(&gpriv->gadget.dev);  	dev_set_name(&gpriv->gadget.dev, "gadget");  	gpriv->gadget.dev.parent	= dev;  	gpriv->gadget.name		= "renesas_usbhs_udc";  	gpriv->gadget.ops		= &usbhsg_gadget_ops;  	gpriv->gadget.is_dualspeed	= 1; +	ret = device_register(&gpriv->gadget.dev); +	if (ret < 0) +		goto err_add_udc;  	INIT_LIST_HEAD(&gpriv->gadget.ep_list); @@ -912,12 +900,15 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)  	ret = usb_add_gadget_udc(dev, &gpriv->gadget);  	if (ret) -		goto err_add_udc; +		goto err_register;  	dev_info(dev, "gadget probed\n");  	return 0; + +err_register: +	device_unregister(&gpriv->gadget.dev);  err_add_udc:  	kfree(gpriv->uep); @@ -933,6 +924,8 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv)  	usb_del_gadget_udc(&gpriv->gadget); +	device_unregister(&gpriv->gadget.dev); +  	usbhsg_controller_unregister(gpriv);  	kfree(gpriv->uep); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 13e4ecc6e43..c290df97108 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -736,6 +736,7 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },  	{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),  		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },  	{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID), diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 571fa96b49c..055b64ef0bb 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -112,6 +112,7 @@  /* Propox devices */  #define FTDI_PROPOX_JTAGCABLEII_PID	0xD738 +#define FTDI_PROPOX_ISPCABLEIII_PID	0xD739  /* Lenz LI-USB Computer Interface. */  #define FTDI_LENZ_LIUSB_PID	0xD780 diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d865878c9f9..e3426602dc8 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -661,6 +661,9 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) },  	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) },  	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x08) },  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, @@ -747,6 +750,7 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ +	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */  	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */  	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) },  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 3041a974faf..24caba79d72 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1854,6 +1854,13 @@ UNUSUAL_DEV(  0x1370, 0x6828, 0x0110, 0x0110,  		USB_SC_DEVICE, USB_PR_DEVICE, NULL,  		US_FL_IGNORE_RESIDUE ), +/* Reported by Qinglin Ye <yestyle@gmail.com> */ +UNUSUAL_DEV(  0x13fe, 0x3600, 0x0100, 0x0100, +		"Kingston", +		"DT 101 G2", +		USB_SC_DEVICE, USB_PR_DEVICE, NULL, +		US_FL_BULK_IGNORE_TAG ), +  /* Reported by Francesco Foresti <frafore@tiscali.it> */  UNUSUAL_DEV(  0x14cd, 0x6600, 0x0201, 0x0201,  		"Super Top",  |