diff options
Diffstat (limited to 'drivers/usb/host/xhci.c')
| -rw-r--r-- | drivers/usb/host/xhci.c | 28 | 
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1c4432d8fc1..3a0f695138f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1085,8 +1085,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  		if (urb->dev->speed == USB_SPEED_FULL) {  			ret = xhci_check_maxpacket(xhci, slot_id,  					ep_index, urb); -			if (ret < 0) +			if (ret < 0) { +				xhci_urb_free_priv(xhci, urb_priv); +				urb->hcpriv = NULL;  				return ret; +			}  		}  		/* We have a spinlock and interrupts disabled, so we must pass @@ -1097,6 +1100,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  			goto dying;  		ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,  				slot_id, ep_index); +		if (ret) +			goto free_priv;  		spin_unlock_irqrestore(&xhci->lock, flags);  	} else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {  		spin_lock_irqsave(&xhci->lock, flags); @@ -1117,6 +1122,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  			ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,  					slot_id, ep_index);  		} +		if (ret) +			goto free_priv;  		spin_unlock_irqrestore(&xhci->lock, flags);  	} else if (usb_endpoint_xfer_int(&urb->ep->desc)) {  		spin_lock_irqsave(&xhci->lock, flags); @@ -1124,6 +1131,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  			goto dying;  		ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,  				slot_id, ep_index); +		if (ret) +			goto free_priv;  		spin_unlock_irqrestore(&xhci->lock, flags);  	} else {  		spin_lock_irqsave(&xhci->lock, flags); @@ -1131,18 +1140,22 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  			goto dying;  		ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb,  				slot_id, ep_index); +		if (ret) +			goto free_priv;  		spin_unlock_irqrestore(&xhci->lock, flags);  	}  exit:  	return ret;  dying: -	xhci_urb_free_priv(xhci, urb_priv); -	urb->hcpriv = NULL;  	xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for "  			"non-responsive xHCI host.\n",  			urb->ep->desc.bEndpointAddress, urb); +	ret = -ESHUTDOWN; +free_priv: +	xhci_urb_free_priv(xhci, urb_priv); +	urb->hcpriv = NULL;  	spin_unlock_irqrestore(&xhci->lock, flags); -	return -ESHUTDOWN; +	return ret;  }  /* Get the right ring for the given URB. @@ -1239,6 +1252,13 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {  		xhci_dbg(xhci, "HW died, freeing TD.\n");  		urb_priv = urb->hcpriv; +		for (i = urb_priv->td_cnt; i < urb_priv->length; i++) { +			td = urb_priv->td[i]; +			if (!list_empty(&td->td_list)) +				list_del_init(&td->td_list); +			if (!list_empty(&td->cancelled_td_list)) +				list_del_init(&td->cancelled_td_list); +		}  		usb_hcd_unlink_urb_from_ep(hcd, urb);  		spin_unlock_irqrestore(&xhci->lock, flags);  |