diff options
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 22 | 
1 files changed, 14 insertions, 8 deletions
| diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 311597bba80e..d0b6806275e0 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -366,7 +366,9 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,  /* Must be called with xhci->lock held, releases and aquires lock back */  static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)  { -	u32 temp_32; +	struct xhci_segment *new_seg	= xhci->cmd_ring->deq_seg; +	union xhci_trb *new_deq		= xhci->cmd_ring->dequeue; +	u64 crcr;  	int ret;  	xhci_dbg(xhci, "Abort command ring\n"); @@ -375,13 +377,18 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags)  	/*  	 * The control bits like command stop, abort are located in lower -	 * dword of the command ring control register. Limit the write -	 * to the lower dword to avoid corrupting the command ring pointer -	 * in case if the command ring is stopped by the time upper dword -	 * is written. +	 * dword of the command ring control register. +	 * Some controllers require all 64 bits to be written to abort the ring. +	 * Make sure the upper dword is valid, pointing to the next command, +	 * avoiding corrupting the command ring pointer in case the command ring +	 * is stopped by the time the upper dword is written.  	 */ -	temp_32 = readl(&xhci->op_regs->cmd_ring); -	writel(temp_32 | CMD_RING_ABORT, &xhci->op_regs->cmd_ring); +	next_trb(xhci, NULL, &new_seg, &new_deq); +	if (trb_is_link(new_deq)) +		next_trb(xhci, NULL, &new_seg, &new_deq); + +	crcr = xhci_trb_virt_to_dma(new_seg, new_deq); +	xhci_write_64(xhci, crcr | CMD_RING_ABORT, &xhci->op_regs->cmd_ring);  	/* Section 4.6.1.2 of xHCI 1.0 spec says software should also time the  	 * completion of the Command Abort operation. If CRR is not negated in 5 @@ -1518,7 +1525,6 @@ static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)  	if (xhci->quirks & XHCI_EP_LIMIT_QUIRK)  		/* Delete default control endpoint resources */  		xhci_free_device_endpoint_resources(xhci, virt_dev, true); -	xhci_free_virt_device(xhci, slot_id);  }  static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id, |