aboutsummaryrefslogtreecommitdiffstats
path: root/usb.current/usb-xhci-set-ep0-dequeue-ptr-after-reset-of-configured-device.patch
diff options
Diffstat (limited to 'usb.current/usb-xhci-set-ep0-dequeue-ptr-after-reset-of-configured-device.patch')
-rw-r--r--usb.current/usb-xhci-set-ep0-dequeue-ptr-after-reset-of-configured-device.patch88
1 files changed, 88 insertions, 0 deletions
diff --git a/usb.current/usb-xhci-set-ep0-dequeue-ptr-after-reset-of-configured-device.patch b/usb.current/usb-xhci-set-ep0-dequeue-ptr-after-reset-of-configured-device.patch
new file mode 100644
index 00000000000000..90217537686f4c
--- /dev/null
+++ b/usb.current/usb-xhci-set-ep0-dequeue-ptr-after-reset-of-configured-device.patch
@@ -0,0 +1,88 @@
+From sarah.a.sharp@linux.intel.com Fri Jul 9 14:33:25 2010
+From: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Date: Fri, 9 Jul 2010 17:08:54 +0200
+Subject: USB: xhci: Set EP0 dequeue ptr after reset of configured device.
+To: Greg KH <gregkh@suse.de>
+Cc: linux-usb@vger.kernel.org, Fajun Chen <fajun.chen@seagate.com>, stable@vger.kernel.org
+Message-ID: <20100709150854.GA3804@xanatos>
+Content-Disposition: inline
+
+
+When a configured device is reset, the control endpoint's ring is reused.
+If control transfers to the device were issued before the device is reset,
+the dequeue pointer will be somewhere in the middle of the ring. If the
+device is then issued an address with the set address command, the xHCI
+driver must provide a valid input context for control endpoint zero.
+
+The original code would give the hardware the original input context,
+which had a dequeue pointer set to the top of the ring. This would cause
+the host to re-execute any control transfers until it reached the ring's
+enqueue pointer. When issuing a set address command for a device that has
+just been configured and then reset, use the control endpoint's enqueue
+pointer as the hardware's dequeue pointer.
+
+Assumption: All control transfers will be completed or cancelled before
+the set address command is issued to the device. If there are any
+outstanding control transfers, this code will not work.
+
+Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/xhci-mem.c | 21 +++++++++++++++++++++
+ drivers/usb/host/xhci.c | 2 ++
+ drivers/usb/host/xhci.h | 2 ++
+ 3 files changed, 25 insertions(+)
+
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -835,6 +835,27 @@ fail:
+ return 0;
+ }
+
++void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
++ struct usb_device *udev)
++{
++ struct xhci_virt_device *virt_dev;
++ struct xhci_ep_ctx *ep0_ctx;
++ struct xhci_ring *ep_ring;
++
++ virt_dev = xhci->devs[udev->slot_id];
++ ep0_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, 0);
++ ep_ring = virt_dev->eps[0].ring;
++ /*
++ * FIXME we don't keep track of the dequeue pointer very well after a
++ * Set TR dequeue pointer, so we're setting the dequeue pointer of the
++ * host to our enqueue pointer. This should only be called after a
++ * configured device has reset, so all control transfers should have
++ * been completed or cancelled before the reset.
++ */
++ ep0_ctx->deq = xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue);
++ ep0_ctx->deq |= ep_ring->cycle_state;
++}
++
+ /* Setup an xHCI virtual device for a Set Address command */
+ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev)
+ {
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -2134,6 +2134,8 @@ int xhci_address_device(struct usb_hcd *
+ /* If this is a Set Address to an unconfigured device, setup ep 0 */
+ if (!udev->config)
+ xhci_setup_addressable_virt_dev(xhci, udev);
++ else
++ xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev);
+ /* Otherwise, assume the core has the device configured how it wants */
+ xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
+ xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1292,6 +1292,8 @@ int xhci_mem_init(struct xhci_hcd *xhci,
+ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id);
+ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags);
+ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev);
++void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
++ struct usb_device *udev);
+ unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
+ unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
+ unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index);