diff options
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 69 | 
1 files changed, 48 insertions, 21 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 86ab9fd9fe9..81cda09b47e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -71,7 +71,6 @@  static const char	hcd_name [] = "ehci_hcd"; -#undef VERBOSE_DEBUG  #undef EHCI_URB_TRACE  /* magic numbers that can affect system performance */ @@ -110,6 +109,9 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");  #include "ehci.h"  #include "pci-quirks.h" +static void compute_tt_budget(u8 budget_table[EHCI_BANDWIDTH_SIZE], +		struct ehci_tt *tt); +  /*   * The MosChip MCS9990 controller updates its microframe counter   * a little before the frame counter, and occasionally we will read @@ -484,6 +486,7 @@ static int ehci_init(struct usb_hcd *hcd)  	INIT_LIST_HEAD(&ehci->intr_qh_list);  	INIT_LIST_HEAD(&ehci->cached_itd_list);  	INIT_LIST_HEAD(&ehci->cached_sitd_list); +	INIT_LIST_HEAD(&ehci->tt_list);  	if (HCC_PGM_FRAMELISTLEN(hcc_params)) {  		/* periodic schedule size can be smaller than default */ @@ -682,8 +685,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);  	u32			status, masked_status, pcd_status = 0, cmd;  	int			bh; +	unsigned long		flags; -	spin_lock (&ehci->lock); +	/* +	 * For threadirqs option we use spin_lock_irqsave() variant to prevent +	 * deadlock with ehci hrtimer callback, because hrtimer callbacks run +	 * in interrupt context even when threadirqs is specified. We can go +	 * back to spin_lock() variant when hrtimer callbacks become threaded. +	 */ +	spin_lock_irqsave(&ehci->lock, flags);  	status = ehci_readl(ehci, &ehci->regs->status); @@ -701,7 +711,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  	/* Shared IRQ? */  	if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) { -		spin_unlock(&ehci->lock); +		spin_unlock_irqrestore(&ehci->lock, flags);  		return IRQ_NONE;  	} @@ -710,13 +720,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  	cmd = ehci_readl(ehci, &ehci->regs->command);  	bh = 0; -#ifdef	VERBOSE_DEBUG -	/* unrequested/ignored: Frame List Rollover */ -	dbg_status (ehci, "irq", status); -#endif - -	/* INT, ERR, and IAA interrupt rates can be throttled */ -  	/* normal [4.15.1.2] or error [4.15.1.1] completion */  	if (likely ((status & (STS_INT|STS_ERR)) != 0)) {  		if (likely ((status & STS_ERR) == 0)) @@ -819,7 +822,7 @@ dead:  	if (bh)  		ehci_work (ehci); -	spin_unlock (&ehci->lock); +	spin_unlock_irqrestore(&ehci->lock, flags);  	if (pcd_status)  		usb_hcd_poll_rh_status(hcd);  	return IRQ_HANDLED; @@ -956,6 +959,7 @@ rescan:  			goto idle_timeout;  		/* BUG_ON(!list_empty(&stream->free_list)); */ +		reserve_release_iso_bandwidth(ehci, stream, -1);  		kfree(stream);  		goto done;  	} @@ -982,6 +986,8 @@ idle_timeout:  		if (qh->clearing_tt)  			goto idle_timeout;  		if (list_empty (&qh->qtd_list)) { +			if (qh->ps.bw_uperiod) +				reserve_release_intr_bandwidth(ehci, qh, -1);  			qh_destroy(ehci, qh);  			break;  		} @@ -1022,7 +1028,6 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)  	 * the toggle bit in the QH.  	 */  	if (qh) { -		usb_settoggle(qh->dev, epnum, is_out, 0);  		if (!list_empty(&qh->qtd_list)) {  			WARN_ONCE(1, "clear_halt for a busy endpoint\n");  		} else { @@ -1030,6 +1035,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)  			 * while the QH is active.  Unlink it now;  			 * re-linking will call qh_refresh().  			 */ +			usb_settoggle(qh->ps.udev, epnum, is_out, 0);  			qh->exception = 1;  			if (eptype == USB_ENDPOINT_XFER_BULK)  				start_unlink_async(ehci, qh); @@ -1048,6 +1054,19 @@ static int ehci_get_frame (struct usb_hcd *hcd)  /*-------------------------------------------------------------------------*/ +/* Device addition and removal */ + +static void ehci_remove_device(struct usb_hcd *hcd, struct usb_device *udev) +{ +	struct ehci_hcd		*ehci = hcd_to_ehci(hcd); + +	spin_lock_irq(&ehci->lock); +	drop_tt(udev); +	spin_unlock_irq(&ehci->lock); +} + +/*-------------------------------------------------------------------------*/ +  #ifdef	CONFIG_PM  /* suspend/resume, section 4.3 */ @@ -1075,6 +1094,14 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)  	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);  	spin_unlock_irq(&ehci->lock); +	synchronize_irq(hcd->irq); + +	/* Check for race with a wakeup request */ +	if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { +		ehci_resume(hcd, false); +		return -EBUSY; +	} +  	return 0;  }  EXPORT_SYMBOL_GPL(ehci_suspend); @@ -1158,7 +1185,7 @@ static const struct hc_driver ehci_hc_driver = {  	 * generic hardware linkage  	 */  	.irq =			ehci_irq, -	.flags =		HCD_MEMORY | HCD_USB2, +	.flags =		HCD_MEMORY | HCD_USB2 | HCD_BH,  	/*  	 * basic lifecycle operations @@ -1191,6 +1218,11 @@ static const struct hc_driver ehci_hc_driver = {  	.bus_resume =		ehci_bus_resume,  	.relinquish_port =	ehci_relinquish_port,  	.port_handed_over =	ehci_port_handed_over, + +	/* +	 * device support +	 */ +	.free_dev =		ehci_remove_device,  };  void ehci_init_driver(struct hc_driver *drv, @@ -1238,11 +1270,6 @@ MODULE_LICENSE ("GPL");  #define XILINX_OF_PLATFORM_DRIVER	ehci_hcd_xilinx_of_driver  #endif -#ifdef CONFIG_USB_W90X900_EHCI -#include "ehci-w90x900.c" -#define	PLATFORM_DRIVER		ehci_hcd_w90x900_driver -#endif -  #ifdef CONFIG_USB_OCTEON_EHCI  #include "ehci-octeon.c"  #define PLATFORM_DRIVER		ehci_octeon_driver @@ -1292,7 +1319,7 @@ static int __init ehci_hcd_init(void)  		 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),  		 sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  	ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);  	if (!ehci_debug_root) {  		retval = -ENOENT; @@ -1341,7 +1368,7 @@ clean2:  	platform_driver_unregister(&PLATFORM_DRIVER);  clean0:  #endif -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  	debugfs_remove(ehci_debug_root);  	ehci_debug_root = NULL;  err_debug: @@ -1365,7 +1392,7 @@ static void __exit ehci_hcd_cleanup(void)  #ifdef PS3_SYSTEM_BUS_DRIVER  	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);  #endif -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  	debugfs_remove(ehci_debug_root);  #endif  	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);  | 
