diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-27 12:38:48 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-27 12:38:48 -0700 |
| commit | 5ecb6c37c2cb884b005c862309fe3cf70755b536 (patch) | |
| tree | ac71489a2fd01d98c52bfd01f9d2f858b40f91f0 /usb.current | |
| parent | 65cf46e6d75002ca50a34ef2fefc772a23f5aa97 (diff) | |
| download | patches-5ecb6c37c2cb884b005c862309fe3cf70755b536.tar.gz | |
xhci patches
Diffstat (limited to 'usb.current')
17 files changed, 3545 insertions, 0 deletions
diff --git a/usb.current/usb-fix-parsing-of-superspeed-endpoint-companion-descriptor.patch b/usb.current/usb-fix-parsing-of-superspeed-endpoint-companion-descriptor.patch new file mode 100644 index 00000000000000..278cecff3d474d --- /dev/null +++ b/usb.current/usb-fix-parsing-of-superspeed-endpoint-companion-descriptor.patch @@ -0,0 +1,108 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:29:49 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:04:52 -0700 +Subject: USB: Fix parsing of SuperSpeed Endpoint Companion descriptor. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190452.GA7915@gamba.jf.intel.com> +Content-Disposition: inline + + +usb_parse_ss_endpoint_companion() was supposed to allocate a structure to +hold the SuperSpeed Endpoint Companion descriptor, and either copy the +values the device returned, or fill in default values if the device +descriptor did not include the companion descriptor. + +However, the previous code would miss the last endpoint in a configuration +with no descriptors after it. Make usb_parse_endpoint() allocate the SS +endpoint companion descriptor and fill it with default values, even if +we've run out of buffer space in this configuration descriptor. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/config.c | 48 +++++++++++++++++++++++++--------------------- + 1 file changed, 27 insertions(+), 21 deletions(-) + +--- a/drivers/usb/core/config.c ++++ b/drivers/usb/core/config.c +@@ -80,38 +80,18 @@ static int usb_parse_ss_endpoint_compani + int max_tx; + int i; + +- /* Allocate space for the SS endpoint companion descriptor */ +- ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp), +- GFP_KERNEL); +- if (!ep->ss_ep_comp) +- return -ENOMEM; + desc = (struct usb_ss_ep_comp_descriptor *) buffer; + if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) { + dev_warn(ddev, "No SuperSpeed endpoint companion for config %d " + " interface %d altsetting %d ep %d: " + "using minimum values\n", + cfgno, inum, asnum, ep->desc.bEndpointAddress); +- ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE; +- ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; +- ep->ss_ep_comp->desc.bMaxBurst = 0; +- /* +- * Leave bmAttributes as zero, which will mean no streams for +- * bulk, and isoc won't support multiple bursts of packets. +- * With bursts of only one packet, and a Mult of 1, the max +- * amount of data moved per endpoint service interval is one +- * packet. +- */ +- if (usb_endpoint_xfer_isoc(&ep->desc) || +- usb_endpoint_xfer_int(&ep->desc)) +- ep->ss_ep_comp->desc.wBytesPerInterval = +- ep->desc.wMaxPacketSize; + /* + * The next descriptor is for an Endpoint or Interface, + * no extra descriptors to copy into the companion structure, + * and we didn't eat up any of the buffer. + */ +- retval = 0; +- goto valid; ++ return 0; + } + memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE); + desc = &ep->ss_ep_comp->desc; +@@ -320,6 +300,28 @@ static int usb_parse_endpoint(struct dev + buffer += i; + size -= i; + ++ /* Allocate space for the SS endpoint companion descriptor */ ++ endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp), ++ GFP_KERNEL); ++ if (!endpoint->ss_ep_comp) ++ return -ENOMEM; ++ ++ /* Fill in some default values (may be overwritten later) */ ++ endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE; ++ endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; ++ endpoint->ss_ep_comp->desc.bMaxBurst = 0; ++ /* ++ * Leave bmAttributes as zero, which will mean no streams for ++ * bulk, and isoc won't support multiple bursts of packets. ++ * With bursts of only one packet, and a Mult of 1, the max ++ * amount of data moved per endpoint service interval is one ++ * packet. ++ */ ++ if (usb_endpoint_xfer_isoc(&endpoint->desc) || ++ usb_endpoint_xfer_int(&endpoint->desc)) ++ endpoint->ss_ep_comp->desc.wBytesPerInterval = ++ endpoint->desc.wMaxPacketSize; ++ + if (size > 0) { + retval = usb_parse_ss_endpoint_companion(ddev, cfgno, + inum, asnum, endpoint, num_ep, buffer, +@@ -329,6 +331,10 @@ static int usb_parse_endpoint(struct dev + retval = buffer - buffer0; + } + } else { ++ dev_warn(ddev, "config %d interface %d altsetting %d " ++ "endpoint 0x%X has no " ++ "SuperSpeed companion descriptor\n", ++ cfgno, inum, asnum, d->bEndpointAddress); + retval = buffer - buffer0; + } + } else { diff --git a/usb.current/usb-xhci-always-align-output-device-contexts-to-64-bytes.patch b/usb.current/usb-xhci-always-align-output-device-contexts-to-64-bytes.patch new file mode 100644 index 00000000000000..4a97a1e30f16b5 --- /dev/null +++ b/usb.current/usb-xhci-always-align-output-device-contexts-to-64-bytes.patch @@ -0,0 +1,287 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:31:34 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:05:08 -0700 +Subject: USB: xhci: Always align output device contexts to 64 bytes. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190508.GA7988@gamba.jf.intel.com> +Content-Disposition: inline + + +Make sure the xHCI output device context is 64-byte aligned. Previous +code was using the same structure for both the output device context and +the input control context. Since the structure had 32 bytes of flags +before the device context, the output device context wouldn't be 64-byte +aligned. Define a new structure to use for the output device context and +clean up the debugging for these two structures. + +The copy of the device context in the input control context does *not* +need to be 64-byte aligned. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-dbg.c | 101 +++++++++++++++++++++++++++----------------- + drivers/usb/host/xhci-hcd.c | 7 --- + drivers/usb/host/xhci-mem.c | 15 +++--- + drivers/usb/host/xhci.h | 19 +++++++- + 4 files changed, 89 insertions(+), 53 deletions(-) + +--- a/drivers/usb/host/xhci-dbg.c ++++ b/drivers/usb/host/xhci-dbg.c +@@ -393,78 +393,103 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd * + upper_32_bits(val)); + } + +-void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) ++dma_addr_t xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_slot_ctx *slot, dma_addr_t dma) + { +- int i, j; +- int last_ep_ctx = 31; + /* Fields are 32 bits wide, DMA addresses are in bytes */ + int field_size = 32 / 8; +- +- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", +- &ctx->drop_flags, (unsigned long long)dma, +- ctx->drop_flags); +- dma += field_size; +- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", +- &ctx->add_flags, (unsigned long long)dma, +- ctx->add_flags); +- dma += field_size; +- for (i = 0; i < 6; ++i) { +- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", +- &ctx->rsvd[i], (unsigned long long)dma, +- ctx->rsvd[i], i); +- dma += field_size; +- } ++ int i; + + xhci_dbg(xhci, "Slot Context:\n"); + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", +- &ctx->slot.dev_info, +- (unsigned long long)dma, ctx->slot.dev_info); ++ &slot->dev_info, ++ (unsigned long long)dma, slot->dev_info); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", +- &ctx->slot.dev_info2, +- (unsigned long long)dma, ctx->slot.dev_info2); ++ &slot->dev_info2, ++ (unsigned long long)dma, slot->dev_info2); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", +- &ctx->slot.tt_info, +- (unsigned long long)dma, ctx->slot.tt_info); ++ &slot->tt_info, ++ (unsigned long long)dma, slot->tt_info); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", +- &ctx->slot.dev_state, +- (unsigned long long)dma, ctx->slot.dev_state); ++ &slot->dev_state, ++ (unsigned long long)dma, slot->dev_state); + dma += field_size; + for (i = 0; i < 4; ++i) { + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", +- &ctx->slot.reserved[i], (unsigned long long)dma, +- ctx->slot.reserved[i], i); ++ &slot->reserved[i], (unsigned long long)dma, ++ slot->reserved[i], i); + dma += field_size; + } + ++ return dma; ++} ++ ++dma_addr_t xhci_dbg_ep_ctx(struct xhci_hcd *xhci, struct xhci_ep_ctx *ep, dma_addr_t dma, unsigned int last_ep) ++{ ++ int i, j; ++ int last_ep_ctx = 31; ++ /* Fields are 32 bits wide, DMA addresses are in bytes */ ++ int field_size = 32 / 8; ++ + if (last_ep < 31) + last_ep_ctx = last_ep + 1; + for (i = 0; i < last_ep_ctx; ++i) { + xhci_dbg(xhci, "Endpoint %02d Context:\n", i); + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", +- &ctx->ep[i].ep_info, +- (unsigned long long)dma, ctx->ep[i].ep_info); ++ &ep[i].ep_info, ++ (unsigned long long)dma, ep[i].ep_info); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", +- &ctx->ep[i].ep_info2, +- (unsigned long long)dma, ctx->ep[i].ep_info2); ++ &ep[i].ep_info2, ++ (unsigned long long)dma, ep[i].ep_info2); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", +- &ctx->ep[i].deq, +- (unsigned long long)dma, ctx->ep[i].deq); ++ &ep[i].deq, ++ (unsigned long long)dma, ep[i].deq); + dma += 2*field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", +- &ctx->ep[i].tx_info, +- (unsigned long long)dma, ctx->ep[i].tx_info); ++ &ep[i].tx_info, ++ (unsigned long long)dma, ep[i].tx_info); + dma += field_size; + for (j = 0; j < 3; ++j) { + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", +- &ctx->ep[i].reserved[j], ++ &ep[i].reserved[j], + (unsigned long long)dma, +- ctx->ep[i].reserved[j], j); ++ ep[i].reserved[j], j); + dma += field_size; + } + } ++ return dma; ++} ++ ++void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) ++{ ++ int i; ++ /* Fields are 32 bits wide, DMA addresses are in bytes */ ++ int field_size = 32 / 8; ++ ++ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", ++ &ctx->drop_flags, (unsigned long long)dma, ++ ctx->drop_flags); ++ dma += field_size; ++ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", ++ &ctx->add_flags, (unsigned long long)dma, ++ ctx->add_flags); ++ dma += field_size; ++ for (i = 0; i < 6; ++i) { ++ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", ++ &ctx->rsvd[i], (unsigned long long)dma, ++ ctx->rsvd[i], i); ++ dma += field_size; ++ } ++ dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma); ++ dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep); ++} ++ ++void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep) ++{ ++ dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma); ++ dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep); + } +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -584,15 +584,29 @@ struct xhci_ep_ctx { + + /** + * struct xhci_device_control +- * Input/Output context; see section 6.2.5. ++ * Input context; see section 6.2.5. + * + * @drop_context: set the bit of the endpoint context you want to disable + * @add_context: set the bit of the endpoint context you want to enable + */ + struct xhci_device_control { ++ /* Input control context */ + u32 drop_flags; + u32 add_flags; + u32 rsvd[6]; ++ /* Copy of device context */ ++ struct xhci_slot_ctx slot; ++ struct xhci_ep_ctx ep[31]; ++}; ++ ++/** ++ * struct xhci_device_ctx ++ * Device context; see section 6.2.1. ++ * ++ * @slot: slot context for the device. ++ * @ep: array of endpoint contexts for the device. ++ */ ++struct xhci_device_ctx { + struct xhci_slot_ctx slot; + struct xhci_ep_ctx ep[31]; + }; +@@ -612,7 +626,7 @@ struct xhci_virt_device { + * track of input and output contexts separately because + * these commands might fail and we don't trust the hardware. + */ +- struct xhci_device_control *out_ctx; ++ struct xhci_device_ctx *out_ctx; + dma_addr_t out_ctx_dma; + /* Used for addressing devices and configuration changes */ + struct xhci_device_control *in_ctx; +@@ -1126,6 +1140,7 @@ void xhci_dbg_erst(struct xhci_hcd *xhci + void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); + void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); + void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep); ++void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep); + + /* xHCI memory managment */ + void xhci_mem_cleanup(struct xhci_hcd *xhci); +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -1013,7 +1013,7 @@ int xhci_check_bandwidth(struct usb_hcd + } + + xhci_dbg(xhci, "Output context after successful config ep cmd:\n"); +- xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, ++ xhci_dbg_device_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, + LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); + + xhci_zero_in_ctx(virt_dev); +@@ -1265,7 +1265,7 @@ int xhci_address_device(struct usb_hcd * + xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2); + xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); +- xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); ++ xhci_dbg_device_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); + /* + * USB core uses address 1 for the roothubs, so we add one to the + * address given back to us by the HC. +@@ -1274,9 +1274,6 @@ int xhci_address_device(struct usb_hcd * + /* Zero the input context control for later use */ + virt_dev->in_ctx->add_flags = 0; + virt_dev->in_ctx->drop_flags = 0; +- /* Mirror flags in the output context for future ep enable/disable */ +- virt_dev->out_ctx->add_flags = SLOT_FLAG | EP0_FLAG; +- virt_dev->out_ctx->drop_flags = 0; + + xhci_dbg(xhci, "Device address = %d\n", udev->devnum); + /* XXX Meh, not sure if anyone else but choose_address uses this. */ +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -235,7 +235,10 @@ int xhci_alloc_virt_device(struct xhci_h + return 0; + dev = xhci->devs[slot_id]; + +- /* Allocate the (output) device context that will be used in the HC */ ++ /* Allocate the (output) device context that will be used in the HC. ++ * The structure is 32 bytes smaller than the input context, but that's ++ * fine. ++ */ + dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); + if (!dev->out_ctx) + goto fail; +@@ -260,16 +263,12 @@ int xhci_alloc_virt_device(struct xhci_h + + init_completion(&dev->cmd_completion); + +- /* +- * Point to output device context in dcbaa; skip the output control +- * context, which is eight 32 bit fields (or 32 bytes long) +- */ +- xhci->dcbaa->dev_context_ptrs[slot_id] = +- (u32) dev->out_ctx_dma + (32); ++ /* Point to output device context in dcbaa. */ ++ xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx_dma; + xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", + slot_id, + &xhci->dcbaa->dev_context_ptrs[slot_id], +- (unsigned long long)dev->out_ctx_dma); ++ (unsigned long long) xhci->dcbaa->dev_context_ptrs[slot_id]); + + return 1; + fail: diff --git a/usb.current/usb-xhci-check-if-the-host-controller-died-in-irq-handler.patch b/usb.current/usb-xhci-check-if-the-host-controller-died-in-irq-handler.patch new file mode 100644 index 00000000000000..88c6ebff5335e1 --- /dev/null +++ b/usb.current/usb-xhci-check-if-the-host-controller-died-in-irq-handler.patch @@ -0,0 +1,36 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:28:48 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:04:01 -0700 +Subject: USB: xhci: Check if the host controller died in IRQ handler. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190401.GA7765@gamba.jf.intel.com> +Content-Disposition: inline + + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-hcd.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -277,6 +277,9 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd + /* Check if the xHC generated the interrupt, or the irq is shared */ + temp = xhci_readl(xhci, &xhci->op_regs->status); + temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending); ++ if (temp == 0xffffffff && temp2 == 0xffffffff) ++ goto hw_died; ++ + if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) { + spin_unlock(&xhci->lock); + return IRQ_NONE; +@@ -294,6 +297,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd + if (temp & STS_FATAL) { + xhci_warn(xhci, "WARNING: Host System Error\n"); + xhci_halt(xhci); ++hw_died: + xhci_to_hcd(xhci)->state = HC_STATE_HALT; + spin_unlock(&xhci->lock); + return -ESHUTDOWN; diff --git a/usb.current/usb-xhci-correct-event-handler-busy-flag-usage.patch b/usb.current/usb-xhci-correct-event-handler-busy-flag-usage.patch new file mode 100644 index 00000000000000..6079ae01d04116 --- /dev/null +++ b/usb.current/usb-xhci-correct-event-handler-busy-flag-usage.patch @@ -0,0 +1,55 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:28:05 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:03:40 -0700 +Subject: USB: xhci: Correct Event Handler Busy flag usage. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190340.GA7653@gamba.jf.intel.com> +Content-Disposition: inline + + +The Event Handler Busy bit in the event ring dequeue pointer is write 1 to +clear. Fix the interrupt service routine to clear that bit after the +event handler has run. + +xhci_set_hc_event_deq() is designed to update the event ring dequeue pointer +without changing any of the four reserved bits in the lower nibble. The event +handler busy (EHB) bit is write one to clear, so the new value must always +contain a zero in that bit in order to preserve the EHB value. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/host/xhci-hcd.c | 4 ++-- + drivers/usb/host/xhci-ring.c | 6 +++++- + 2 files changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -249,9 +249,9 @@ static void xhci_work(struct xhci_hcd *x + /* FIXME this should be a delayed service routine that clears the EHB */ + xhci_handle_event(xhci); + +- /* Clear the event handler busy flag; the event ring should be empty. */ ++ /* Clear the event handler busy flag (RW1C); the event ring should be empty. */ + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); +- xhci_write_64(xhci, temp_64 & ~ERST_EHB, &xhci->ir_set->erst_dequeue); ++ xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue); + /* Flush posted writes -- FIXME is this necessary? */ + xhci_readl(xhci, &xhci->ir_set->irq_pending); + } +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -248,8 +248,12 @@ void xhci_set_hc_event_deq(struct xhci_h + /* Update HC event ring dequeue pointer */ + temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + temp &= ERST_PTR_MASK; ++ /* Don't clear the EHB bit (which is RW1C) because ++ * there might be more events to service. ++ */ ++ temp &= ~ERST_EHB; + if (!in_interrupt()) +- xhci_dbg(xhci, "// Write event ring dequeue pointer\n"); ++ xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n"); + xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, + &xhci->ir_set->erst_dequeue); + } diff --git a/usb.current/usb-xhci-deal-with-stalled-endpoints.patch b/usb.current/usb-xhci-deal-with-stalled-endpoints.patch new file mode 100644 index 00000000000000..cc737a0a560f0e --- /dev/null +++ b/usb.current/usb-xhci-deal-with-stalled-endpoints.patch @@ -0,0 +1,219 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:23:41 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:03:15 -0700 +Subject: USB: xhci: Deal with stalled endpoints. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190315.GA7497@gamba.jf.intel.com> + + +When an endpoint on a device under an xHCI host controller stalls, the +host controller driver must let the hardware know that the USB core has +successfully cleared the halt condition. The HCD submits a Reset Endpoint +Command, which will clear the toggle bit for USB 2.0 devices, and set the +sequence number to zero for USB 3.0 devices. + +The xHCI urb_enqueue will accept new URBs while the endpoint is halted, +and will queue them to the hardware rings. However, the endpoint doorbell +will not be rung until the Reset Endpoint Command completes. + +Don't queue a reset endpoint command for root hubs. khubd clears halt +conditions on the roothub during the initialization process, but the roothub +isn't a real device, so the xHCI host controller doesn't need to know about the +cleared halt. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-hcd.c | 44 ++++++++++++++++++++++++++++++++++++++++++- + drivers/usb/host/xhci-pci.c | 1 + drivers/usb/host/xhci-ring.c | 36 ++++++++++++++++++++++++++++++++++- + drivers/usb/host/xhci.h | 8 +++++-- + 4 files changed, 85 insertions(+), 4 deletions(-) + +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -848,8 +848,8 @@ union xhci_trb { + #define TRB_CONFIG_EP 12 + /* Evaluate Context Command */ + #define TRB_EVAL_CONTEXT 13 +-/* Reset Transfer Ring Command */ +-#define TRB_RESET_RING 14 ++/* Reset Endpoint Command */ ++#define TRB_RESET_EP 14 + /* Stop Transfer Ring Command */ + #define TRB_STOP_RING 15 + /* Set Transfer Ring Dequeue Pointer Command */ +@@ -929,6 +929,7 @@ struct xhci_ring { + unsigned int cancels_pending; + unsigned int state; + #define SET_DEQ_PENDING (1 << 0) ++#define EP_HALTED (1 << 1) + /* The TRB that was last reported in a stopped endpoint ring */ + union xhci_trb *stopped_trb; + struct xhci_td *stopped_td; +@@ -1128,6 +1129,7 @@ int xhci_urb_enqueue(struct usb_hcd *hcd + int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); + int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); + int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); ++void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep); + int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); + void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); + +@@ -1148,6 +1150,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd * + int slot_id, unsigned int ep_index); + int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, + u32 slot_id); ++int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, ++ unsigned int ep_index); + + /* xHCI roothub code */ + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -787,8 +787,11 @@ int xhci_add_endpoint(struct usb_hcd *hc + int ret = 0; + + ret = xhci_check_args(hcd, udev, ep, 1, __func__); +- if (ret <= 0) ++ if (ret <= 0) { ++ /* So we won't queue a reset ep command for a root hub */ ++ ep->hcpriv = NULL; + return ret; ++ } + xhci = hcd_to_xhci(hcd); + + added_ctxs = xhci_get_endpoint_flag(&ep->desc); +@@ -851,6 +854,9 @@ int xhci_add_endpoint(struct usb_hcd *hc + } + new_slot_info = in_ctx->slot.dev_info; + ++ /* Store the usb_device pointer for later use */ ++ ep->hcpriv = udev; ++ + xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", + (unsigned int) ep->desc.bEndpointAddress, + udev->slot_id, +@@ -1026,6 +1032,42 @@ void xhci_reset_bandwidth(struct usb_hcd + xhci_zero_in_ctx(virt_dev); + } + ++/* Deal with stalled endpoints. The core should have sent the control message ++ * to clear the halt condition. However, we need to make the xHCI hardware ++ * reset its sequence number, since a device will expect a sequence number of ++ * zero after the halt condition is cleared. ++ * Context: in_interrupt ++ */ ++void xhci_endpoint_reset(struct usb_hcd *hcd, ++ struct usb_host_endpoint *ep) ++{ ++ struct xhci_hcd *xhci; ++ struct usb_device *udev; ++ unsigned int ep_index; ++ unsigned long flags; ++ int ret; ++ ++ xhci = hcd_to_xhci(hcd); ++ udev = (struct usb_device *) ep->hcpriv; ++ /* Called with a root hub endpoint (or an endpoint that wasn't added ++ * with xhci_add_endpoint() ++ */ ++ if (!ep->hcpriv) ++ return; ++ ep_index = xhci_get_endpoint_index(&ep->desc); ++ ++ xhci_dbg(xhci, "Queueing reset endpoint command\n"); ++ spin_lock_irqsave(&xhci->lock, flags); ++ ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index); ++ if (!ret) { ++ xhci_ring_cmd_db(xhci); ++ } ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ ++ if (ret) ++ xhci_warn(xhci, "FIXME allocate a new ring segment\n"); ++} ++ + /* + * At this point, the struct usb_device is about to go away, the device has + * disconnected, and all traffic has been stopped and the endpoints have been +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -117,6 +117,7 @@ static const struct hc_driver xhci_pci_h + .free_dev = xhci_free_dev, + .add_endpoint = xhci_add_endpoint, + .drop_endpoint = xhci_drop_endpoint, ++ .endpoint_reset = xhci_endpoint_reset, + .check_bandwidth = xhci_check_bandwidth, + .reset_bandwidth = xhci_reset_bandwidth, + .address_device = xhci_address_device, +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -279,7 +279,8 @@ static void ring_ep_doorbell(struct xhci + /* Don't ring the doorbell for this endpoint if there are pending + * cancellations because the we don't want to interrupt processing. + */ +- if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING)) { ++ if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING) ++ && !(ep_ring->state & EP_HALTED)) { + field = xhci_readl(xhci, db_addr) & DB_MASK; + xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr); + /* Flush PCI posted writes - FIXME Matthew Wilcox says this +@@ -603,6 +604,25 @@ static void handle_set_deq_completion(st + ring_ep_doorbell(xhci, slot_id, ep_index); + } + ++static void handle_reset_ep_completion(struct xhci_hcd *xhci, ++ struct xhci_event_cmd *event, ++ union xhci_trb *trb) ++{ ++ int slot_id; ++ unsigned int ep_index; ++ ++ slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); ++ ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); ++ /* This command will only fail if the endpoint wasn't halted, ++ * but we don't care. ++ */ ++ xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n", ++ (unsigned int) GET_COMP_CODE(event->status)); ++ ++ /* Clear our internal halted state and restart the ring */ ++ xhci->devs[slot_id]->ep_rings[ep_index]->state &= ~EP_HALTED; ++ ring_ep_doorbell(xhci, slot_id, ep_index); ++} + + static void handle_cmd_completion(struct xhci_hcd *xhci, + struct xhci_event_cmd *event) +@@ -653,6 +673,9 @@ static void handle_cmd_completion(struct + case TRB_TYPE(TRB_CMD_NOOP): + ++xhci->noops_handled; + break; ++ case TRB_TYPE(TRB_RESET_EP): ++ handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue); ++ break; + default: + /* Skip over unknown commands on the event ring */ + xhci->error_bitmask |= 1 << 6; +@@ -823,6 +846,7 @@ static int handle_tx_event(struct xhci_h + break; + case COMP_STALL: + xhci_warn(xhci, "WARN: Stalled endpoint\n"); ++ ep_ring->state |= EP_HALTED; + status = -EPIPE; + break; + case COMP_TRB_ERR: +@@ -1656,3 +1680,13 @@ static int queue_set_tr_deq(struct xhci_ + return queue_command(xhci, (u32) addr | cycle_state, 0, 0, + trb_slot_id | trb_ep_index | type); + } ++ ++int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, ++ unsigned int ep_index) ++{ ++ u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); ++ u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); ++ u32 type = TRB_TYPE(TRB_RESET_EP); ++ ++ return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type); ++} diff --git a/usb.current/usb-xhci-don-t-oops-if-the-host-doesn-t-halt.patch b/usb.current/usb-xhci-don-t-oops-if-the-host-doesn-t-halt.patch new file mode 100644 index 00000000000000..4464332d0ee9c2 --- /dev/null +++ b/usb.current/usb-xhci-don-t-oops-if-the-host-doesn-t-halt.patch @@ -0,0 +1,30 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:28:35 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:03:50 -0700 +Subject: USB: xhci: Don't oops if the host doesn't halt. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190350.GA7729@gamba.jf.intel.com> +Content-Disposition: inline + + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-hcd.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -103,7 +103,10 @@ int xhci_reset(struct xhci_hcd *xhci) + u32 state; + + state = xhci_readl(xhci, &xhci->op_regs->status); +- BUG_ON((state & STS_HALT) == 0); ++ if ((state & STS_HALT) == 0) { ++ xhci_warn(xhci, "Host controller not halted, aborting reset.\n"); ++ return 0; ++ } + + xhci_dbg(xhci, "// Reset the HC\n"); + command = xhci_readl(xhci, &xhci->op_regs->command); diff --git a/usb.current/usb-xhci-fail-gracefully-if-there-s-no-ss-ep-companion-descriptor.patch b/usb.current/usb-xhci-fail-gracefully-if-there-s-no-ss-ep-companion-descriptor.patch new file mode 100644 index 00000000000000..c6cffaeb9b46fe --- /dev/null +++ b/usb.current/usb-xhci-fail-gracefully-if-there-s-no-ss-ep-companion-descriptor.patch @@ -0,0 +1,36 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:29:33 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:04:38 -0700 +Subject: USB: xhci: Fail gracefully if there's no SS ep companion descriptor. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190438.GA7879@gamba.jf.intel.com> +Content-Disposition: inline + + +This is a work around for a bug in the SuperSpeed Endpoint Companion Descriptor +parsing code. It fails in some corner cases, which means ep->ss_ep_comp may be +NULL. + +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 | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -496,7 +496,12 @@ int xhci_endpoint_init(struct xhci_hcd * + max_packet = ep->desc.wMaxPacketSize; + ep_ctx->ep_info2 |= MAX_PACKET(max_packet); + /* dig out max burst from ep companion desc */ +- max_packet = ep->ss_ep_comp->desc.bMaxBurst; ++ if (!ep->ss_ep_comp) { ++ xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n"); ++ max_packet = 0; ++ } else { ++ max_packet = ep->ss_ep_comp->desc.bMaxBurst; ++ } + ep_ctx->ep_info2 |= MAX_BURST(max_packet); + break; + case USB_SPEED_HIGH: diff --git a/usb.current/usb-xhci-handle-babble-errors-on-transfers.patch b/usb.current/usb-xhci-handle-babble-errors-on-transfers.patch new file mode 100644 index 00000000000000..84abb604c3f519 --- /dev/null +++ b/usb.current/usb-xhci-handle-babble-errors-on-transfers.patch @@ -0,0 +1,31 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:29:18 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:04:32 -0700 +Subject: USB: xhci: Handle babble errors on transfers. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190432.GA7838@gamba.jf.intel.com> +Content-Disposition: inline + + +Pass back a babble error when this error code is seen in the transfer event TRB. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-ring.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -876,6 +876,10 @@ static int handle_tx_event(struct xhci_h + xhci_warn(xhci, "WARN: transfer error on endpoint\n"); + status = -EPROTO; + break; ++ case COMP_BABBLE: ++ xhci_warn(xhci, "WARN: babble error on endpoint\n"); ++ status = -EOVERFLOW; ++ break; + case COMP_DB_ERR: + xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n"); + status = -ENOSR; diff --git a/usb.current/usb-xhci-handle-short-control-packets-correctly.patch b/usb.current/usb-xhci-handle-short-control-packets-correctly.patch new file mode 100644 index 00000000000000..bae4254b985ad0 --- /dev/null +++ b/usb.current/usb-xhci-handle-short-control-packets-correctly.patch @@ -0,0 +1,56 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:27:20 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:03:36 -0700 +Subject: USB: xhci: Handle short control packets correctly. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190336.GA7615@gamba.jf.intel.com> +Content-Disposition: inline + + +When there is a short packet on a control transfer, the xHCI host controller +hardware will generate two events. The first event will be for the data stage +TD with a completion code for a short packet. The second event will be for the +status stage with a successful completion code. Before this patch, the xHCI +driver would giveback the short control URB when it received the event for the +data stage TD. Then it would become confused when it saw a status stage event +for the endpoint for an URB it had already finished processing. + +Change the xHCI host controller driver to wait for the status stage event when +it receives a short transfer completion code for a data stage TD. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-ring.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -892,15 +892,23 @@ static int handle_tx_event(struct xhci_h + if (event_trb != ep_ring->dequeue) { + /* The event was for the status stage */ + if (event_trb == td->last_trb) { +- td->urb->actual_length = +- td->urb->transfer_buffer_length; ++ /* Did we already see a short data stage? */ ++ if (td->urb->actual_length != 0) ++ status = -EREMOTEIO; ++ else ++ td->urb->actual_length = ++ td->urb->transfer_buffer_length; + } else { + /* Maybe the event was for the data stage? */ +- if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) ++ if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) { + /* We didn't stop on a link TRB in the middle */ + td->urb->actual_length = + td->urb->transfer_buffer_length - + TRB_LEN(event->transfer_len); ++ xhci_dbg(xhci, "Waiting for status stage event\n"); ++ urb = NULL; ++ goto cleanup; ++ } + } + } + } else { diff --git a/usb.current/usb-xhci-make-debugging-more-verbose.patch b/usb.current/usb-xhci-make-debugging-more-verbose.patch new file mode 100644 index 00000000000000..1aa6c98a669921 --- /dev/null +++ b/usb.current/usb-xhci-make-debugging-more-verbose.patch @@ -0,0 +1,291 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:28:17 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:03:46 -0700 +Subject: USB: xhci: Make debugging more verbose. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190346.GA7692@gamba.jf.intel.com> +Content-Disposition: inline + + +Add more debugging to the irq handler, slot context initialization, ring +operations, URB cancellation, and MMIO writes. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-hcd.c | 47 ++++++++++++++++++++++++++++++------------- + drivers/usb/host/xhci-ring.c | 35 ++++++++++++++++++++++++++++++-- + drivers/usb/host/xhci.h | 14 +++++------- + 3 files changed, 72 insertions(+), 24 deletions(-) + +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1065,10 +1065,9 @@ static inline unsigned int xhci_readl(co + static inline void xhci_writel(struct xhci_hcd *xhci, + const unsigned int val, __u32 __iomem *regs) + { +- if (!in_interrupt()) +- xhci_dbg(xhci, +- "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n", +- regs, val); ++ xhci_dbg(xhci, ++ "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n", ++ regs, val); + writel(val, regs); + } + +@@ -1096,10 +1095,9 @@ static inline void xhci_write_64(struct + u32 val_lo = lower_32_bits(val); + u32 val_hi = upper_32_bits(val); + +- if (!in_interrupt()) +- xhci_dbg(xhci, +- "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n", +- regs, (long unsigned int) val); ++ xhci_dbg(xhci, ++ "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n", ++ regs, (long unsigned int) val); + writel(val_lo, ptr); + writel(val_hi, ptr + 1); + } +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -267,8 +267,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd + { + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + u32 temp, temp2; ++ union xhci_trb *trb; + + spin_lock(&xhci->lock); ++ trb = xhci->event_ring->dequeue; + /* Check if the xHC generated the interrupt, or the irq is shared */ + temp = xhci_readl(xhci, &xhci->op_regs->status); + temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending); +@@ -276,6 +278,15 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd + spin_unlock(&xhci->lock); + return IRQ_NONE; + } ++ xhci_dbg(xhci, "op reg status = %08x\n", temp); ++ xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2); ++ xhci_dbg(xhci, "Event ring dequeue ptr:\n"); ++ xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n", ++ (unsigned long long)xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb), ++ lower_32_bits(trb->link.segment_ptr), ++ upper_32_bits(trb->link.segment_ptr), ++ (unsigned int) trb->link.intr_target, ++ (unsigned int) trb->link.control); + + if (temp & STS_FATAL) { + xhci_warn(xhci, "WARNING: Host System Error\n"); +@@ -385,6 +396,20 @@ int xhci_run(struct usb_hcd *hcd) + add_timer(&xhci->event_ring_timer); + #endif + ++ xhci_dbg(xhci, "Command ring memory map follows:\n"); ++ xhci_debug_ring(xhci, xhci->cmd_ring); ++ xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); ++ xhci_dbg_cmd_ptrs(xhci); ++ ++ xhci_dbg(xhci, "ERST memory map follows:\n"); ++ xhci_dbg_erst(xhci, &xhci->erst); ++ xhci_dbg(xhci, "Event ring:\n"); ++ xhci_debug_ring(xhci, xhci->event_ring); ++ xhci_dbg_ring_ptrs(xhci, xhci->event_ring); ++ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); ++ temp_64 &= ~ERST_PTR_MASK; ++ xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); ++ + xhci_dbg(xhci, "// Set the interrupt modulation register\n"); + temp = xhci_readl(xhci, &xhci->ir_set->irq_control); + temp &= ~ER_IRQ_INTERVAL_MASK; +@@ -409,20 +434,6 @@ int xhci_run(struct usb_hcd *hcd) + if (NUM_TEST_NOOPS > 0) + doorbell = xhci_setup_one_noop(xhci); + +- xhci_dbg(xhci, "Command ring memory map follows:\n"); +- xhci_debug_ring(xhci, xhci->cmd_ring); +- xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); +- xhci_dbg_cmd_ptrs(xhci); +- +- xhci_dbg(xhci, "ERST memory map follows:\n"); +- xhci_dbg_erst(xhci, &xhci->erst); +- xhci_dbg(xhci, "Event ring:\n"); +- xhci_debug_ring(xhci, xhci->event_ring); +- xhci_dbg_ring_ptrs(xhci, xhci->event_ring); +- temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); +- temp_64 &= ~ERST_PTR_MASK; +- xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); +- + temp = xhci_readl(xhci, &xhci->op_regs->command); + temp |= (CMD_RUN); + xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", +@@ -665,8 +676,12 @@ int xhci_urb_dequeue(struct usb_hcd *hcd + goto done; + + xhci_dbg(xhci, "Cancel URB %p\n", urb); ++ xhci_dbg(xhci, "Event ring:\n"); ++ xhci_debug_ring(xhci, xhci->event_ring); + ep_index = xhci_get_endpoint_index(&urb->ep->desc); + ep_ring = xhci->devs[urb->dev->slot_id]->ep_rings[ep_index]; ++ xhci_dbg(xhci, "Endpoint ring:\n"); ++ xhci_debug_ring(xhci, ep_ring); + td = (struct xhci_td *) urb->hcpriv; + + ep_ring->cancels_pending++; +@@ -1178,6 +1193,8 @@ int xhci_address_device(struct usb_hcd * + if (!udev->config) + xhci_setup_addressable_virt_dev(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, virt_dev->in_ctx_dma, 2); + + spin_lock_irqsave(&xhci->lock, flags); + ret = xhci_queue_address_device(xhci, virt_dev->in_ctx_dma, +@@ -1221,6 +1238,8 @@ int xhci_address_device(struct usb_hcd * + default: + xhci_err(xhci, "ERROR: unexpected command completion " + "code 0x%x.\n", virt_dev->cmd_status); ++ xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); ++ xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); + ret = -EINVAL; + break; + } +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -135,6 +135,7 @@ static void next_trb(struct xhci_hcd *xh + static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer) + { + union xhci_trb *next = ++(ring->dequeue); ++ unsigned long long addr; + + ring->deq_updates++; + /* Update the dequeue pointer further if that was a link TRB or we're at +@@ -152,6 +153,13 @@ static void inc_deq(struct xhci_hcd *xhc + ring->dequeue = ring->deq_seg->trbs; + next = ring->dequeue; + } ++ addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue); ++ if (ring == xhci->event_ring) ++ xhci_dbg(xhci, "Event ring deq = 0x%llx (DMA)\n", addr); ++ else if (ring == xhci->cmd_ring) ++ xhci_dbg(xhci, "Command ring deq = 0x%llx (DMA)\n", addr); ++ else ++ xhci_dbg(xhci, "Ring deq = 0x%llx (DMA)\n", addr); + } + + /* +@@ -171,6 +179,7 @@ static void inc_enq(struct xhci_hcd *xhc + { + u32 chain; + union xhci_trb *next; ++ unsigned long long addr; + + chain = ring->enqueue->generic.field[3] & TRB_CHAIN; + next = ++(ring->enqueue); +@@ -204,6 +213,13 @@ static void inc_enq(struct xhci_hcd *xhc + ring->enqueue = ring->enq_seg->trbs; + next = ring->enqueue; + } ++ addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue); ++ if (ring == xhci->event_ring) ++ xhci_dbg(xhci, "Event ring enq = 0x%llx (DMA)\n", addr); ++ else if (ring == xhci->cmd_ring) ++ xhci_dbg(xhci, "Command ring enq = 0x%llx (DMA)\n", addr); ++ else ++ xhci_dbg(xhci, "Ring enq = 0x%llx (DMA)\n", addr); + } + + /* +@@ -252,8 +268,7 @@ void xhci_set_hc_event_deq(struct xhci_h + * there might be more events to service. + */ + temp &= ~ERST_EHB; +- if (!in_interrupt()) +- xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n"); ++ xhci_dbg(xhci, "// Write event ring dequeue pointer, preserving EHB bit\n"); + xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, + &xhci->ir_set->erst_dequeue); + } +@@ -781,6 +796,7 @@ static int handle_tx_event(struct xhci_h + struct urb *urb = 0; + int status = -EINPROGRESS; + ++ xhci_dbg(xhci, "In %s\n", __func__); + xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)]; + if (!xdev) { + xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n"); +@@ -789,6 +805,7 @@ static int handle_tx_event(struct xhci_h + + /* Endpoint ID is 1 based, our index is zero based */ + ep_index = TRB_TO_EP_ID(event->flags) - 1; ++ xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index); + ep_ring = xdev->ep_rings[ep_index]; + if (!ep_ring || (xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) { + xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n"); +@@ -797,6 +814,7 @@ static int handle_tx_event(struct xhci_h + + event_dma = event->buffer; + /* This TRB should be in the TD at the head of this ring's TD list */ ++ xhci_dbg(xhci, "%s - checking for list empty\n", __func__); + if (list_empty(&ep_ring->td_list)) { + xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", + TRB_TO_SLOT_ID(event->flags), ep_index); +@@ -806,11 +824,14 @@ static int handle_tx_event(struct xhci_h + urb = NULL; + goto cleanup; + } ++ xhci_dbg(xhci, "%s - getting list entry\n", __func__); + td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); + + /* Is this a TRB in the currently executing TD? */ ++ xhci_dbg(xhci, "%s - looking for TD\n", __func__); + event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, + td->last_trb, event_dma); ++ xhci_dbg(xhci, "%s - found event_seg = %p\n", __func__, event_seg); + if (!event_seg) { + /* HC is busted, give up! */ + xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not part of current TD\n"); +@@ -1027,6 +1048,8 @@ cleanup: + /* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */ + if (urb) { + usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb); ++ xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n", ++ urb, td->urb->actual_length, status); + spin_unlock(&xhci->lock); + usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status); + spin_lock(&xhci->lock); +@@ -1044,6 +1067,7 @@ void xhci_handle_event(struct xhci_hcd * + int update_ptrs = 1; + int ret; + ++ xhci_dbg(xhci, "In %s\n", __func__); + if (!xhci->event_ring || !xhci->event_ring->dequeue) { + xhci->error_bitmask |= 1 << 1; + return; +@@ -1056,18 +1080,25 @@ void xhci_handle_event(struct xhci_hcd * + xhci->error_bitmask |= 1 << 2; + return; + } ++ xhci_dbg(xhci, "%s - OS owns TRB\n", __func__); + + /* FIXME: Handle more event types. */ + switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) { + case TRB_TYPE(TRB_COMPLETION): ++ xhci_dbg(xhci, "%s - calling handle_cmd_completion\n", __func__); + handle_cmd_completion(xhci, &event->event_cmd); ++ xhci_dbg(xhci, "%s - returned from handle_cmd_completion\n", __func__); + break; + case TRB_TYPE(TRB_PORT_STATUS): ++ xhci_dbg(xhci, "%s - calling handle_port_status\n", __func__); + handle_port_status(xhci, event); ++ xhci_dbg(xhci, "%s - returned from handle_port_status\n", __func__); + update_ptrs = 0; + break; + case TRB_TYPE(TRB_TRANSFER): ++ xhci_dbg(xhci, "%s - calling handle_tx_event\n", __func__); + ret = handle_tx_event(xhci, &event->trans_event); ++ xhci_dbg(xhci, "%s - returned from handle_tx_event\n", __func__); + if (ret < 0) + xhci->error_bitmask |= 1 << 9; + else diff --git a/usb.current/usb-xhci-represent-64-bit-addresses-with-one-u64.patch b/usb.current/usb-xhci-represent-64-bit-addresses-with-one-u64.patch new file mode 100644 index 00000000000000..d64bf41fcecbd4 --- /dev/null +++ b/usb.current/usb-xhci-represent-64-bit-addresses-with-one-u64.patch @@ -0,0 +1,744 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:24:11 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:03:31 -0700 +Subject: USB: xhci: Represent 64-bit addresses with one u64. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190331.GA7575@gamba.jf.intel.com> +Content-Disposition: inline + + +There are several xHCI data structures that use two 32-bit fields to +represent a 64-bit address. Since some architectures don't support 64-bit +PCI writes, the fields need to be written in two 32-bit writes. The xHCI +specification says that if a platform is incapable of generating 64-bit +writes, software must write the low 32-bits first, then the high 32-bits. +Hardware that supports 64-bit addressing will wait for the high 32-bit +write before reading the revised value, and hardware that only supports +32-bit writes will ignore the high 32-bit write. + +Previous xHCI code represented 64-bit addresses with two u32 values. This +lead to buggy code that would write the 32-bits in the wrong order, or +forget to write the upper 32-bits. Change the two u32s to one u64 and +create a function call to write all 64-bit addresses in the proper order. +This new function could be modified in the future if all platforms support +64-bit writes. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/host/xhci-dbg.c | 69 ++++++++++++++++--------------------------- + drivers/usb/host/xhci-hcd.c | 43 +++++++++++--------------- + drivers/usb/host/xhci-mem.c | 61 ++++++++++++++------------------------ + drivers/usb/host/xhci-ring.c | 49 ++++++++++++++---------------- + drivers/usb/host/xhci.h | 65 ++++++++++++++++++++++++++++------------ + 5 files changed, 138 insertions(+), 149 deletions(-) + +--- a/drivers/usb/host/xhci-dbg.c ++++ b/drivers/usb/host/xhci-dbg.c +@@ -173,6 +173,7 @@ void xhci_print_ir_set(struct xhci_hcd * + { + void *addr; + u32 temp; ++ u64 temp_64; + + addr = &ir_set->irq_pending; + temp = xhci_readl(xhci, addr); +@@ -200,25 +201,15 @@ void xhci_print_ir_set(struct xhci_hcd * + xhci_dbg(xhci, " WARN: %p: ir_set.rsvd = 0x%x\n", + addr, (unsigned int)temp); + +- addr = &ir_set->erst_base[0]; +- temp = xhci_readl(xhci, addr); +- xhci_dbg(xhci, " %p: ir_set.erst_base[0] = 0x%x\n", +- addr, (unsigned int) temp); +- +- addr = &ir_set->erst_base[1]; +- temp = xhci_readl(xhci, addr); +- xhci_dbg(xhci, " %p: ir_set.erst_base[1] = 0x%x\n", +- addr, (unsigned int) temp); +- +- addr = &ir_set->erst_dequeue[0]; +- temp = xhci_readl(xhci, addr); +- xhci_dbg(xhci, " %p: ir_set.erst_dequeue[0] = 0x%x\n", +- addr, (unsigned int) temp); +- +- addr = &ir_set->erst_dequeue[1]; +- temp = xhci_readl(xhci, addr); +- xhci_dbg(xhci, " %p: ir_set.erst_dequeue[1] = 0x%x\n", +- addr, (unsigned int) temp); ++ addr = &ir_set->erst_base; ++ temp_64 = xhci_read_64(xhci, addr); ++ xhci_dbg(xhci, " %p: ir_set.erst_base = @%08llx\n", ++ addr, temp_64); ++ ++ addr = &ir_set->erst_dequeue; ++ temp_64 = xhci_read_64(xhci, addr); ++ xhci_dbg(xhci, " %p: ir_set.erst_dequeue = @%08llx\n", ++ addr, temp_64); + } + + void xhci_print_run_regs(struct xhci_hcd *xhci) +@@ -268,8 +259,7 @@ void xhci_debug_trb(struct xhci_hcd *xhc + xhci_dbg(xhci, "Link TRB:\n"); + xhci_print_trb_offsets(xhci, trb); + +- address = trb->link.segment_ptr[0] + +- (((u64) trb->link.segment_ptr[1]) << 32); ++ address = trb->link.segment_ptr; + xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address); + + xhci_dbg(xhci, "Interrupter target = 0x%x\n", +@@ -282,8 +272,7 @@ void xhci_debug_trb(struct xhci_hcd *xhc + (unsigned int) (trb->link.control & TRB_NO_SNOOP)); + break; + case TRB_TYPE(TRB_TRANSFER): +- address = trb->trans_event.buffer[0] + +- (((u64) trb->trans_event.buffer[1]) << 32); ++ address = trb->trans_event.buffer; + /* + * FIXME: look at flags to figure out if it's an address or if + * the data is directly in the buffer field. +@@ -291,8 +280,7 @@ void xhci_debug_trb(struct xhci_hcd *xhc + xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address); + break; + case TRB_TYPE(TRB_COMPLETION): +- address = trb->event_cmd.cmd_trb[0] + +- (((u64) trb->event_cmd.cmd_trb[1]) << 32); ++ address = trb->event_cmd.cmd_trb; + xhci_dbg(xhci, "Command TRB pointer = %llu\n", address); + xhci_dbg(xhci, "Completion status = %u\n", + (unsigned int) GET_COMP_CODE(trb->event_cmd.status)); +@@ -328,8 +316,8 @@ void xhci_debug_segment(struct xhci_hcd + for (i = 0; i < TRBS_PER_SEGMENT; ++i) { + trb = &seg->trbs[i]; + xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr, +- (unsigned int) trb->link.segment_ptr[0], +- (unsigned int) trb->link.segment_ptr[1], ++ lower_32_bits(trb->link.segment_ptr), ++ upper_32_bits(trb->link.segment_ptr), + (unsigned int) trb->link.intr_target, + (unsigned int) trb->link.control); + addr += sizeof(*trb); +@@ -386,8 +374,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci + entry = &erst->entries[i]; + xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", + (unsigned int) addr, +- (unsigned int) entry->seg_addr[0], +- (unsigned int) entry->seg_addr[1], ++ lower_32_bits(entry->seg_addr), ++ upper_32_bits(entry->seg_addr), + (unsigned int) entry->seg_size, + (unsigned int) entry->rsvd); + addr += sizeof(*entry); +@@ -396,12 +384,13 @@ void xhci_dbg_erst(struct xhci_hcd *xhci + + void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) + { +- u32 val; ++ u64 val; + +- val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]); +- xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val); +- val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]); +- xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val); ++ val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); ++ xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n", ++ lower_32_bits(val)); ++ xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n", ++ upper_32_bits(val)); + } + + void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) +@@ -462,14 +451,10 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, + &ctx->ep[i].ep_info2, + (unsigned long long)dma, ctx->ep[i].ep_info2); + dma += field_size; +- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[0]\n", +- &ctx->ep[i].deq[0], +- (unsigned long long)dma, ctx->ep[i].deq[0]); +- dma += field_size; +- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[1]\n", +- &ctx->ep[i].deq[1], +- (unsigned long long)dma, ctx->ep[i].deq[1]); +- dma += field_size; ++ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", ++ &ctx->ep[i].deq, ++ (unsigned long long)dma, ctx->ep[i].deq); ++ dma += 2*field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", + &ctx->ep[i].tx_info, + (unsigned long long)dma, ctx->ep[i].tx_info); +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -25,6 +25,7 @@ + + #include <linux/usb.h> + #include <linux/timer.h> ++#include <linux/kernel.h> + + #include "../core/hcd.h" + /* Code sharing between pci-quirks and xhci hcd */ +@@ -42,14 +43,6 @@ + * xHCI register interface. + * This corresponds to the eXtensible Host Controller Interface (xHCI) + * Revision 0.95 specification +- * +- * Registers should always be accessed with double word or quad word accesses. +- * +- * Some xHCI implementations may support 64-bit address pointers. Registers +- * with 64-bit address pointers should be written to with dword accesses by +- * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. +- * xHCI implementations that do not support 64-bit address pointers will ignore +- * the high dword, and write order is irrelevant. + */ + + /** +@@ -166,10 +159,10 @@ struct xhci_op_regs { + u32 reserved1; + u32 reserved2; + u32 dev_notification; +- u32 cmd_ring[2]; ++ u64 cmd_ring; + /* rsvd: offset 0x20-2F */ + u32 reserved3[4]; +- u32 dcbaa_ptr[2]; ++ u64 dcbaa_ptr; + u32 config_reg; + /* rsvd: offset 0x3C-3FF */ + u32 reserved4[241]; +@@ -254,7 +247,7 @@ struct xhci_op_regs { + #define CMD_RING_RUNNING (1 << 3) + /* bits 4:5 reserved and should be preserved */ + /* Command Ring pointer - bit mask for the lower 32 bits. */ +-#define CMD_RING_ADDR_MASK (0xffffffc0) ++#define CMD_RING_RSVD_BITS (0x3f) + + /* CONFIG - Configure Register - config_reg bitmasks */ + /* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */ +@@ -382,8 +375,8 @@ struct xhci_intr_reg { + u32 irq_control; + u32 erst_size; + u32 rsvd; +- u32 erst_base[2]; +- u32 erst_dequeue[2]; ++ u64 erst_base; ++ u64 erst_dequeue; + }; + + /* irq_pending bitmasks */ +@@ -538,7 +531,7 @@ struct xhci_slot_ctx { + struct xhci_ep_ctx { + u32 ep_info; + u32 ep_info2; +- u32 deq[2]; ++ u64 deq; + u32 tx_info; + /* offset 0x14 - 0x1f reserved for HC internal use */ + u32 reserved[3]; +@@ -641,7 +634,7 @@ struct xhci_virt_device { + */ + struct xhci_device_context_array { + /* 64-bit device addresses; we only write 32-bit addresses */ +- u32 dev_context_ptrs[2*MAX_HC_SLOTS]; ++ u64 dev_context_ptrs[MAX_HC_SLOTS]; + /* private xHCD pointers */ + dma_addr_t dma; + }; +@@ -654,7 +647,7 @@ struct xhci_device_context_array { + + struct xhci_stream_ctx { + /* 64-bit stream ring address, cycle state, and stream type */ +- u32 stream_ring[2]; ++ u64 stream_ring; + /* offset 0x14 - 0x1f reserved for HC internal use */ + u32 reserved[2]; + }; +@@ -662,7 +655,7 @@ struct xhci_stream_ctx { + + struct xhci_transfer_event { + /* 64-bit buffer address, or immediate data */ +- u32 buffer[2]; ++ u64 buffer; + u32 transfer_len; + /* This field is interpreted differently based on the type of TRB */ + u32 flags; +@@ -744,7 +737,7 @@ struct xhci_transfer_event { + + struct xhci_link_trb { + /* 64-bit segment pointer*/ +- u32 segment_ptr[2]; ++ u64 segment_ptr; + u32 intr_target; + u32 control; + }; +@@ -755,7 +748,7 @@ struct xhci_link_trb { + /* Command completion event TRB */ + struct xhci_event_cmd { + /* Pointer to command TRB, or the value passed by the event data trb */ +- u32 cmd_trb[2]; ++ u64 cmd_trb; + u32 status; + u32 flags; + }; +@@ -943,7 +936,7 @@ struct xhci_ring { + + struct xhci_erst_entry { + /* 64-bit event ring segment address */ +- u32 seg_addr[2]; ++ u64 seg_addr; + u32 seg_size; + /* Set to zero */ + u32 rsvd; +@@ -1079,6 +1072,38 @@ static inline void xhci_writel(struct xh + writel(val, regs); + } + ++/* ++ * Registers should always be accessed with double word or quad word accesses. ++ * ++ * Some xHCI implementations may support 64-bit address pointers. Registers ++ * with 64-bit address pointers should be written to with dword accesses by ++ * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. ++ * xHCI implementations that do not support 64-bit address pointers will ignore ++ * the high dword, and write order is irrelevant. ++ */ ++static inline u64 xhci_read_64(const struct xhci_hcd *xhci, ++ __u64 __iomem *regs) ++{ ++ __u32 __iomem *ptr = (__u32 __iomem *) regs; ++ u64 val_lo = readl(ptr); ++ u64 val_hi = readl(ptr + 1); ++ return val_lo + (val_hi << 32); ++} ++static inline void xhci_write_64(struct xhci_hcd *xhci, ++ const u64 val, __u64 __iomem *regs) ++{ ++ __u32 __iomem *ptr = (__u32 __iomem *) regs; ++ u32 val_lo = lower_32_bits(val); ++ u32 val_hi = upper_32_bits(val); ++ ++ if (!in_interrupt()) ++ xhci_dbg(xhci, ++ "`MEM_WRITE_DWORD(3'b000, 64'h%p, 64'h%0lx, 4'hf);\n", ++ regs, (long unsigned int) val); ++ writel(val_lo, ptr); ++ writel(val_hi, ptr + 1); ++} ++ + /* xHCI debugging */ + void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num); + void xhci_print_registers(struct xhci_hcd *xhci); +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -226,6 +226,7 @@ int xhci_init(struct usb_hcd *hcd) + static void xhci_work(struct xhci_hcd *xhci) + { + u32 temp; ++ u64 temp_64; + + /* + * Clear the op reg interrupt status first, +@@ -249,8 +250,8 @@ static void xhci_work(struct xhci_hcd *x + xhci_handle_event(xhci); + + /* Clear the event handler busy flag; the event ring should be empty. */ +- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); +- xhci_writel(xhci, temp & ~ERST_EHB, &xhci->ir_set->erst_dequeue[0]); ++ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); ++ xhci_write_64(xhci, temp_64 & ~ERST_EHB, &xhci->ir_set->erst_dequeue); + /* Flush posted writes -- FIXME is this necessary? */ + xhci_readl(xhci, &xhci->ir_set->irq_pending); + } +@@ -295,6 +296,7 @@ void xhci_event_ring_work(unsigned long + { + unsigned long flags; + int temp; ++ u64 temp_64; + struct xhci_hcd *xhci = (struct xhci_hcd *) arg; + int i, j; + +@@ -311,9 +313,9 @@ void xhci_event_ring_work(unsigned long + xhci_dbg(xhci, "Event ring:\n"); + xhci_debug_segment(xhci, xhci->event_ring->deq_seg); + xhci_dbg_ring_ptrs(xhci, xhci->event_ring); +- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); +- temp &= ERST_PTR_MASK; +- xhci_dbg(xhci, "ERST deq = 0x%x\n", temp); ++ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); ++ temp_64 &= ~ERST_PTR_MASK; ++ xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); + xhci_dbg(xhci, "Command ring:\n"); + xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg); + xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); +@@ -356,6 +358,7 @@ void xhci_event_ring_work(unsigned long + int xhci_run(struct usb_hcd *hcd) + { + u32 temp; ++ u64 temp_64; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + void (*doorbell)(struct xhci_hcd *) = NULL; + +@@ -416,11 +419,9 @@ int xhci_run(struct usb_hcd *hcd) + xhci_dbg(xhci, "Event ring:\n"); + xhci_debug_ring(xhci, xhci->event_ring); + xhci_dbg_ring_ptrs(xhci, xhci->event_ring); +- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); +- temp &= ERST_PTR_MASK; +- xhci_dbg(xhci, "ERST deq = 0x%x\n", temp); +- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[1]); +- xhci_dbg(xhci, "ERST deq upper = 0x%x\n", temp); ++ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); ++ temp_64 &= ~ERST_PTR_MASK; ++ xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); + + temp = xhci_readl(xhci, &xhci->op_regs->command); + temp |= (CMD_RUN); +@@ -888,8 +889,7 @@ static void xhci_zero_in_ctx(struct xhci + ep_ctx = &virt_dev->in_ctx->ep[i]; + ep_ctx->ep_info = 0; + ep_ctx->ep_info2 = 0; +- ep_ctx->deq[0] = 0; +- ep_ctx->deq[1] = 0; ++ ep_ctx->deq = 0; + ep_ctx->tx_info = 0; + } + } +@@ -1165,7 +1165,7 @@ int xhci_address_device(struct usb_hcd * + struct xhci_virt_device *virt_dev; + int ret = 0; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- u32 temp; ++ u64 temp_64; + + if (!udev->slot_id) { + xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id); +@@ -1227,18 +1227,13 @@ int xhci_address_device(struct usb_hcd * + if (ret) { + return ret; + } +- temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[0]); +- xhci_dbg(xhci, "Op regs DCBAA ptr[0] = %#08x\n", temp); +- temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[1]); +- xhci_dbg(xhci, "Op regs DCBAA ptr[1] = %#08x\n", temp); +- xhci_dbg(xhci, "Slot ID %d dcbaa entry[0] @%p = %#08x\n", +- udev->slot_id, +- &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id], +- xhci->dcbaa->dev_context_ptrs[2*udev->slot_id]); +- xhci_dbg(xhci, "Slot ID %d dcbaa entry[1] @%p = %#08x\n", ++ temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); ++ xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64); ++ xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n", + udev->slot_id, +- &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1], +- xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1]); ++ &xhci->dcbaa->dev_context_ptrs[udev->slot_id], ++ (unsigned long long) ++ xhci->dcbaa->dev_context_ptrs[udev->slot_id]); + xhci_dbg(xhci, "Output Context DMA address = %#08llx\n", + (unsigned long long)virt_dev->out_ctx_dma); + xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -88,7 +88,7 @@ static void xhci_link_segments(struct xh + return; + prev->next = next; + if (link_trbs) { +- prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr[0] = next->dma; ++ prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = next->dma; + + /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ + val = prev->trbs[TRBS_PER_SEGMENT-1].link.control; +@@ -200,8 +200,7 @@ void xhci_free_virt_device(struct xhci_h + return; + + dev = xhci->devs[slot_id]; +- xhci->dcbaa->dev_context_ptrs[2*slot_id] = 0; +- xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0; ++ xhci->dcbaa->dev_context_ptrs[slot_id] = 0; + if (!dev) + return; + +@@ -265,13 +264,12 @@ int xhci_alloc_virt_device(struct xhci_h + * Point to output device context in dcbaa; skip the output control + * context, which is eight 32 bit fields (or 32 bytes long) + */ +- xhci->dcbaa->dev_context_ptrs[2*slot_id] = ++ xhci->dcbaa->dev_context_ptrs[slot_id] = + (u32) dev->out_ctx_dma + (32); + xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", + slot_id, +- &xhci->dcbaa->dev_context_ptrs[2*slot_id], ++ &xhci->dcbaa->dev_context_ptrs[slot_id], + (unsigned long long)dev->out_ctx_dma); +- xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0; + + return 1; + fail: +@@ -360,10 +358,9 @@ int xhci_setup_addressable_virt_dev(stru + ep0_ctx->ep_info2 |= MAX_BURST(0); + ep0_ctx->ep_info2 |= ERROR_COUNT(3); + +- ep0_ctx->deq[0] = ++ ep0_ctx->deq = + dev->ep_rings[0]->first_seg->dma; +- ep0_ctx->deq[0] |= dev->ep_rings[0]->cycle_state; +- ep0_ctx->deq[1] = 0; ++ ep0_ctx->deq |= dev->ep_rings[0]->cycle_state; + + /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ + +@@ -477,8 +474,7 @@ int xhci_endpoint_init(struct xhci_hcd * + if (!virt_dev->new_ep_rings[ep_index]) + return -ENOMEM; + ep_ring = virt_dev->new_ep_rings[ep_index]; +- ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state; +- ep_ctx->deq[1] = 0; ++ ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state; + + ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep); + +@@ -535,8 +531,7 @@ void xhci_endpoint_zero(struct xhci_hcd + + ep_ctx->ep_info = 0; + ep_ctx->ep_info2 = 0; +- ep_ctx->deq[0] = 0; +- ep_ctx->deq[1] = 0; ++ ep_ctx->deq = 0; + ep_ctx->tx_info = 0; + /* Don't free the endpoint ring until the set interface or configuration + * request succeeds. +@@ -551,10 +546,8 @@ void xhci_mem_cleanup(struct xhci_hcd *x + + /* Free the Event Ring Segment Table and the actual Event Ring */ + xhci_writel(xhci, 0, &xhci->ir_set->erst_size); +- xhci_writel(xhci, 0, &xhci->ir_set->erst_base[0]); +- xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]); +- xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[0]); +- xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]); ++ xhci_write_64(xhci, 0, &xhci->ir_set->erst_base); ++ xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue); + size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); + if (xhci->erst.entries) + pci_free_consistent(pdev, size, +@@ -566,8 +559,7 @@ void xhci_mem_cleanup(struct xhci_hcd *x + xhci->event_ring = NULL; + xhci_dbg(xhci, "Freed event ring\n"); + +- xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[0]); +- xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[1]); ++ xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring); + if (xhci->cmd_ring) + xhci_ring_free(xhci, xhci->cmd_ring); + xhci->cmd_ring = NULL; +@@ -586,8 +578,7 @@ void xhci_mem_cleanup(struct xhci_hcd *x + xhci->device_pool = NULL; + xhci_dbg(xhci, "Freed device context pool\n"); + +- xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[0]); +- xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[1]); ++ xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr); + if (xhci->dcbaa) + pci_free_consistent(pdev, sizeof(*xhci->dcbaa), + xhci->dcbaa, xhci->dcbaa->dma); +@@ -602,6 +593,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, + dma_addr_t dma; + struct device *dev = xhci_to_hcd(xhci)->self.controller; + unsigned int val, val2; ++ u64 val_64; + struct xhci_segment *seg; + u32 page_size; + int i; +@@ -647,8 +639,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, + xhci->dcbaa->dma = dma; + xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n", + (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); +- xhci_writel(xhci, dma, &xhci->op_regs->dcbaa_ptr[0]); +- xhci_writel(xhci, (u32) 0, &xhci->op_regs->dcbaa_ptr[1]); ++ xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); + + /* + * Initialize the ring segment pool. The ring must be a contiguous +@@ -675,14 +666,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, + (unsigned long long)xhci->cmd_ring->first_seg->dma); + + /* Set the address in the Command Ring Control register */ +- val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]); +- val = (val & ~CMD_RING_ADDR_MASK) | +- (xhci->cmd_ring->first_seg->dma & CMD_RING_ADDR_MASK) | ++ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); ++ val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | ++ (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) | + xhci->cmd_ring->cycle_state; +- xhci_dbg(xhci, "// Setting command ring address low bits to 0x%x\n", val); +- xhci_writel(xhci, val, &xhci->op_regs->cmd_ring[0]); +- xhci_dbg(xhci, "// Setting command ring address high bits to 0x0\n"); +- xhci_writel(xhci, (u32) 0, &xhci->op_regs->cmd_ring[1]); ++ xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val); ++ xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); + xhci_dbg_cmd_ptrs(xhci); + + val = xhci_readl(xhci, &xhci->cap_regs->db_off); +@@ -722,8 +711,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, + /* set ring base address and size for each segment table entry */ + for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) { + struct xhci_erst_entry *entry = &xhci->erst.entries[val]; +- entry->seg_addr[0] = seg->dma; +- entry->seg_addr[1] = 0; ++ entry->seg_addr = seg->dma; + entry->seg_size = TRBS_PER_SEGMENT; + entry->rsvd = 0; + seg = seg->next; +@@ -741,11 +729,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, + /* set the segment table base address */ + xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n", + (unsigned long long)xhci->erst.erst_dma_addr); +- val = xhci_readl(xhci, &xhci->ir_set->erst_base[0]); +- val &= ERST_PTR_MASK; +- val |= (xhci->erst.erst_dma_addr & ~ERST_PTR_MASK); +- xhci_writel(xhci, val, &xhci->ir_set->erst_base[0]); +- xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]); ++ val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base); ++ val_64 &= ERST_PTR_MASK; ++ val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK); ++ xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base); + + /* Set the event ring dequeue address */ + xhci_set_hc_event_deq(xhci); +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -237,7 +237,7 @@ static int room_on_ring(struct xhci_hcd + + void xhci_set_hc_event_deq(struct xhci_hcd *xhci) + { +- u32 temp; ++ u64 temp; + dma_addr_t deq; + + deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, +@@ -246,13 +246,12 @@ void xhci_set_hc_event_deq(struct xhci_h + xhci_warn(xhci, "WARN something wrong with SW event ring " + "dequeue ptr.\n"); + /* Update HC event ring dequeue pointer */ +- temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]); ++ temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + temp &= ERST_PTR_MASK; + if (!in_interrupt()) + xhci_dbg(xhci, "// Write event ring dequeue pointer\n"); +- xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]); +- xhci_writel(xhci, (deq & ~ERST_PTR_MASK) | temp, +- &xhci->ir_set->erst_dequeue[0]); ++ xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, ++ &xhci->ir_set->erst_dequeue); + } + + /* Ring the host controller doorbell after placing a command on the ring */ +@@ -352,7 +351,7 @@ static void find_new_dequeue_state(struc + if (!state->new_deq_seg) + BUG(); + /* Dig out the cycle state saved by the xHC during the stop ep cmd */ +- state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq[0]; ++ state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq; + + state->new_deq_ptr = cur_td->last_trb; + state->new_deq_seg = find_trb_seg(state->new_deq_seg, +@@ -594,10 +593,8 @@ static void handle_set_deq_completion(st + * cancelling URBs, which might not be an error... + */ + } else { +- xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq[0] = 0x%x, " +- "deq[1] = 0x%x.\n", +- dev->out_ctx->ep[ep_index].deq[0], +- dev->out_ctx->ep[ep_index].deq[1]); ++ xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n", ++ dev->out_ctx->ep[ep_index].deq); + } + + ep_ring->state &= ~SET_DEQ_PENDING; +@@ -631,7 +628,7 @@ static void handle_cmd_completion(struct + u64 cmd_dma; + dma_addr_t cmd_dequeue_dma; + +- cmd_dma = (((u64) event->cmd_trb[1]) << 32) + event->cmd_trb[0]; ++ cmd_dma = event->cmd_trb; + cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, + xhci->cmd_ring->dequeue); + /* Is the command ring deq ptr out of sync with the deq seg ptr? */ +@@ -794,10 +791,7 @@ static int handle_tx_event(struct xhci_h + return -ENODEV; + } + +- event_dma = event->buffer[0]; +- if (event->buffer[1] != 0) +- xhci_warn(xhci, "WARN ignoring upper 32-bits of 64-bit TRB dma address\n"); +- ++ event_dma = event->buffer; + /* This TRB should be in the TD at the head of this ring's TD list */ + if (list_empty(&ep_ring->td_list)) { + xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", +@@ -821,10 +815,10 @@ static int handle_tx_event(struct xhci_h + event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / sizeof(*event_trb)]; + xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", + (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10); +- xhci_dbg(xhci, "Offset 0x00 (buffer[0]) = 0x%x\n", +- (unsigned int) event->buffer[0]); +- xhci_dbg(xhci, "Offset 0x04 (buffer[0]) = 0x%x\n", +- (unsigned int) event->buffer[1]); ++ xhci_dbg(xhci, "Offset 0x00 (buffer lo) = 0x%x\n", ++ lower_32_bits(event->buffer)); ++ xhci_dbg(xhci, "Offset 0x04 (buffer hi) = 0x%x\n", ++ upper_32_bits(event->buffer)); + xhci_dbg(xhci, "Offset 0x08 (transfer length) = 0x%x\n", + (unsigned int) event->transfer_len); + xhci_dbg(xhci, "Offset 0x0C (flags) = 0x%x\n", +@@ -1343,8 +1337,8 @@ static int queue_bulk_sg_tx(struct xhci_ + TD_REMAINDER(urb->transfer_buffer_length - running_total) | + TRB_INTR_TARGET(0); + queue_trb(xhci, ep_ring, false, +- (u32) addr, +- (u32) ((u64) addr >> 32), ++ lower_32_bits(addr), ++ upper_32_bits(addr), + length_field, + /* We always want to know if the TRB was short, + * or we won't get an event when it completes. +@@ -1475,8 +1469,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd * + TD_REMAINDER(urb->transfer_buffer_length - running_total) | + TRB_INTR_TARGET(0); + queue_trb(xhci, ep_ring, false, +- (u32) addr, +- (u32) ((u64) addr >> 32), ++ lower_32_bits(addr), ++ upper_32_bits(addr), + length_field, + /* We always want to know if the TRB was short, + * or we won't get an event when it completes. +@@ -1637,7 +1631,8 @@ int xhci_queue_slot_control(struct xhci_ + int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, + u32 slot_id) + { +- return queue_command(xhci, in_ctx_ptr, 0, 0, ++ return queue_command(xhci, lower_32_bits(in_ctx_ptr), ++ upper_32_bits(in_ctx_ptr), 0, + TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id)); + } + +@@ -1645,7 +1640,8 @@ int xhci_queue_address_device(struct xhc + int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, + u32 slot_id) + { +- return queue_command(xhci, in_ctx_ptr, 0, 0, ++ return queue_command(xhci, lower_32_bits(in_ctx_ptr), ++ upper_32_bits(in_ctx_ptr), 0, + TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id)); + } + +@@ -1677,7 +1673,8 @@ static int queue_set_tr_deq(struct xhci_ + xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); + xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n", + deq_seg, deq_ptr); +- return queue_command(xhci, (u32) addr | cycle_state, 0, 0, ++ return queue_command(xhci, lower_32_bits(addr) | cycle_state, ++ upper_32_bits(addr), 0, + trb_slot_id | trb_ep_index | type); + } + diff --git a/usb.current/usb-xhci-scratchpad-buffer-allocation.patch b/usb.current/usb-xhci-scratchpad-buffer-allocation.patch new file mode 100644 index 00000000000000..3b13823ff71af3 --- /dev/null +++ b/usb.current/usb-xhci-scratchpad-buffer-allocation.patch @@ -0,0 +1,185 @@ +From johnyoun@synopsys.com Mon Jul 27 12:30:05 2009 +From: John Youn <johnyoun@synopsys.com> +Date: Mon, 27 Jul 2009 12:05:03 -0700 +Subject: USB: xhci: Scratchpad buffer allocation +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com>, John Youn <johnyoun@synopsys.com> +Message-ID: <20090727190503.GA7953@gamba.jf.intel.com> + + +From: John Youn <johnyoun@synopsys.com> + +Allocates and initializes the scratchpad buffer array (XHCI 4.20). This is an +array of 64-bit DMA addresses to scratch pages that the controller may use +during operation. The number of pages is specified in the "Max Scratchpad +Buffers" field of HCSPARAMS2. The DMA address of this array is written into +slot 0 of the DCBAA. + +Signed-off-by: John Youn <johnyoun@synopsys.com> +Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-mem.c | 102 ++++++++++++++++++++++++++++++++++++++++++++ + drivers/usb/host/xhci.h | 11 ++++ + 2 files changed, 113 insertions(+) + +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -89,6 +89,7 @@ struct xhci_cap_regs { + #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) + /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ + /* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ ++#define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f) + + /* HCSPARAMS3 - hcs_params3 - bitmasks */ + /* bits 0:7, Max U1 to U0 latency for the roothub ports */ +@@ -951,6 +952,13 @@ struct xhci_erst { + unsigned int erst_size; + }; + ++struct xhci_scratchpad { ++ u64 *sp_array; ++ dma_addr_t sp_dma; ++ void **sp_buffers; ++ dma_addr_t *sp_dma_buffers; ++}; ++ + /* + * Each segment table entry is 4*32bits long. 1K seems like an ok size: + * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, +@@ -1005,6 +1013,9 @@ struct xhci_hcd { + struct xhci_ring *cmd_ring; + struct xhci_ring *event_ring; + struct xhci_erst erst; ++ /* Scratchpad */ ++ struct xhci_scratchpad *scratchpad; ++ + /* slot enabling and address device helpers */ + struct completion addr_dev; + int slot_id; +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -545,6 +545,103 @@ void xhci_endpoint_zero(struct xhci_hcd + */ + } + ++/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */ ++static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) ++{ ++ int i; ++ struct device *dev = xhci_to_hcd(xhci)->self.controller; ++ int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); ++ ++ xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp); ++ ++ if (!num_sp) ++ return 0; ++ ++ xhci->scratchpad = kzalloc(sizeof(*xhci->scratchpad), flags); ++ if (!xhci->scratchpad) ++ goto fail_sp; ++ ++ xhci->scratchpad->sp_array = ++ pci_alloc_consistent(to_pci_dev(dev), ++ num_sp * sizeof(u64), ++ &xhci->scratchpad->sp_dma); ++ if (!xhci->scratchpad->sp_array) ++ goto fail_sp2; ++ ++ xhci->scratchpad->sp_buffers = kzalloc(sizeof(void *) * num_sp, flags); ++ if (!xhci->scratchpad->sp_buffers) ++ goto fail_sp3; ++ ++ xhci->scratchpad->sp_dma_buffers = ++ kzalloc(sizeof(dma_addr_t) * num_sp, flags); ++ ++ if (!xhci->scratchpad->sp_dma_buffers) ++ goto fail_sp4; ++ ++ xhci->dcbaa->dev_context_ptrs[0] = xhci->scratchpad->sp_dma; ++ for (i = 0; i < num_sp; i++) { ++ dma_addr_t dma; ++ void *buf = pci_alloc_consistent(to_pci_dev(dev), ++ xhci->page_size, &dma); ++ if (!buf) ++ goto fail_sp5; ++ ++ xhci->scratchpad->sp_array[i] = dma; ++ xhci->scratchpad->sp_buffers[i] = buf; ++ xhci->scratchpad->sp_dma_buffers[i] = dma; ++ } ++ ++ return 0; ++ ++ fail_sp5: ++ for (i = i - 1; i >= 0; i--) { ++ pci_free_consistent(to_pci_dev(dev), xhci->page_size, ++ xhci->scratchpad->sp_buffers[i], ++ xhci->scratchpad->sp_dma_buffers[i]); ++ } ++ kfree(xhci->scratchpad->sp_dma_buffers); ++ ++ fail_sp4: ++ kfree(xhci->scratchpad->sp_buffers); ++ ++ fail_sp3: ++ pci_free_consistent(to_pci_dev(dev), num_sp * sizeof(u64), ++ xhci->scratchpad->sp_array, ++ xhci->scratchpad->sp_dma); ++ ++ fail_sp2: ++ kfree(xhci->scratchpad); ++ xhci->scratchpad = NULL; ++ ++ fail_sp: ++ return -ENOMEM; ++} ++ ++static void scratchpad_free(struct xhci_hcd *xhci) ++{ ++ int num_sp; ++ int i; ++ struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); ++ ++ if (!xhci->scratchpad) ++ return; ++ ++ num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); ++ ++ for (i = 0; i < num_sp; i++) { ++ pci_free_consistent(pdev, xhci->page_size, ++ xhci->scratchpad->sp_buffers[i], ++ xhci->scratchpad->sp_dma_buffers[i]); ++ } ++ kfree(xhci->scratchpad->sp_dma_buffers); ++ kfree(xhci->scratchpad->sp_buffers); ++ pci_free_consistent(pdev, num_sp * sizeof(u64), ++ xhci->scratchpad->sp_array, ++ xhci->scratchpad->sp_dma); ++ kfree(xhci->scratchpad); ++ xhci->scratchpad = NULL; ++} ++ + void xhci_mem_cleanup(struct xhci_hcd *xhci) + { + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); +@@ -593,6 +690,7 @@ void xhci_mem_cleanup(struct xhci_hcd *x + + xhci->page_size = 0; + xhci->page_shift = 0; ++ scratchpad_free(xhci); + } + + int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) +@@ -755,7 +853,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, + for (i = 0; i < MAX_HC_SLOTS; ++i) + xhci->devs[i] = 0; + ++ if (scratchpad_alloc(xhci, flags)) ++ goto fail; ++ + return 0; ++ + fail: + xhci_warn(xhci, "Couldn't initialize memory\n"); + xhci_mem_cleanup(xhci); diff --git a/usb.current/usb-xhci-set-td-size-in-transfer-trb.patch b/usb.current/usb-xhci-set-td-size-in-transfer-trb.patch new file mode 100644 index 00000000000000..25f509e28ce03e --- /dev/null +++ b/usb.current/usb-xhci-set-td-size-in-transfer-trb.patch @@ -0,0 +1,97 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:23:20 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:03:07 -0700 +Subject: USB: xhci: Set TD size in transfer TRB. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190307.GA7455@gamba.jf.intel.com> + + +The 0.95 xHCI specification requires software to set the "TD size" field +in each transaction request block (TRB). This field gives the host +controller an indication of how much data is remaining in the TD +(including the buffer in the current TRB). Set this field in bulk TRBs +and data stage TRBs for control transfers. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-ring.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1285,6 +1285,7 @@ static int queue_bulk_sg_tx(struct xhci_ + /* Queue the first TRB, even if it's zero-length */ + do { + u32 field = 0; ++ u32 length_field = 0; + + /* Don't change the cycle bit of the first TRB until later */ + if (first_trb) +@@ -1314,10 +1315,13 @@ static int queue_bulk_sg_tx(struct xhci_ + (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), + (unsigned int) addr + trb_buff_len); + } ++ length_field = TRB_LEN(trb_buff_len) | ++ TD_REMAINDER(urb->transfer_buffer_length - running_total) | ++ TRB_INTR_TARGET(0); + queue_trb(xhci, ep_ring, false, + (u32) addr, + (u32) ((u64) addr >> 32), +- TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0), ++ length_field, + /* We always want to know if the TRB was short, + * or we won't get an event when it completes. + * (Unless we use event data TRBs, which are a +@@ -1365,7 +1369,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd * + struct xhci_generic_trb *start_trb; + bool first_trb; + int start_cycle; +- u32 field; ++ u32 field, length_field; + + int running_total, trb_buff_len, ret; + u64 addr; +@@ -1443,10 +1447,13 @@ int xhci_queue_bulk_tx(struct xhci_hcd * + td->last_trb = ep_ring->enqueue; + field |= TRB_IOC; + } ++ length_field = TRB_LEN(trb_buff_len) | ++ TD_REMAINDER(urb->transfer_buffer_length - running_total) | ++ TRB_INTR_TARGET(0); + queue_trb(xhci, ep_ring, false, + (u32) addr, + (u32) ((u64) addr >> 32), +- TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0), ++ length_field, + /* We always want to know if the TRB was short, + * or we won't get an event when it completes. + * (Unless we use event data TRBs, which are a +@@ -1478,7 +1485,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * + struct usb_ctrlrequest *setup; + struct xhci_generic_trb *start_trb; + int start_cycle; +- u32 field; ++ u32 field, length_field; + struct xhci_td *td; + + ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; +@@ -1528,13 +1535,16 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * + + /* If there's data, queue data TRBs */ + field = 0; ++ length_field = TRB_LEN(urb->transfer_buffer_length) | ++ TD_REMAINDER(urb->transfer_buffer_length) | ++ TRB_INTR_TARGET(0); + if (urb->transfer_buffer_length > 0) { + if (setup->bRequestType & USB_DIR_IN) + field |= TRB_DIR_IN; + queue_trb(xhci, ep_ring, false, + lower_32_bits(urb->transfer_dma), + upper_32_bits(urb->transfer_dma), +- TRB_LEN(urb->transfer_buffer_length) | TRB_INTR_TARGET(0), ++ length_field, + /* Event on short tx */ + field | TRB_ISP | TRB_TYPE(TRB_DATA) | ep_ring->cycle_state); + } diff --git a/usb.current/usb-xhci-setup-hw-retries-correctly.patch b/usb.current/usb-xhci-setup-hw-retries-correctly.patch new file mode 100644 index 00000000000000..fd3331c7bb09fe --- /dev/null +++ b/usb.current/usb-xhci-setup-hw-retries-correctly.patch @@ -0,0 +1,43 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:29:05 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:04:27 -0700 +Subject: USB: xhci: Setup HW retries correctly. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190427.GA7800@gamba.jf.intel.com> +Content-Disposition: inline + + +The xHCI host controller can be programmed to retry a transfer a certain number +of times per endpoint before it passes back an error condition to the host +controller driver. The xHC will return an error code when the error count +transitions from 1 to 0. Programming an error count of 3 means the xHC tries +the transfer 3 times, programming it with a 1 means it tries to transfer once, +and programming it with 0 means the HW tries the transfer infinitely. + +We want isochronous transfers to only be tried once, so set the error count to +one. + +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 | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -480,11 +480,13 @@ int xhci_endpoint_init(struct xhci_hcd * + + /* FIXME dig Mult and streams info out of ep companion desc */ + +- /* Allow 3 retries for everything but isoc */ ++ /* Allow 3 retries for everything but isoc; ++ * error count = 0 means infinite retries. ++ */ + if (!usb_endpoint_xfer_isoc(&ep->desc)) + ep_ctx->ep_info2 = ERROR_COUNT(3); + else +- ep_ctx->ep_info2 = ERROR_COUNT(0); ++ ep_ctx->ep_info2 = ERROR_COUNT(1); + + ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep); + diff --git a/usb.current/usb-xhci-stall-handling-bug-fixes.patch b/usb.current/usb-xhci-stall-handling-bug-fixes.patch new file mode 100644 index 00000000000000..b854e1524e5484 --- /dev/null +++ b/usb.current/usb-xhci-stall-handling-bug-fixes.patch @@ -0,0 +1,362 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:32:25 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:05:21 -0700 +Subject: USB: xhci: Stall handling bug fixes. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190521.GA8067@gamba.jf.intel.com> + + +Correct the xHCI code to handle stalls on USB endpoints. We need to move +the endpoint ring's dequeue pointer past the stalled transfer, or the HW +will try to restart the transfer the next time the doorbell is rung. + +Don't attempt to clear a halt on an endpoint if we haven't seen a stalled +transfer for it. The USB core will attempt to clear a halt on all +endpoints when it selects a new configuration. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-hcd.c | 24 +++++++ + drivers/usb/host/xhci-ring.c | 133 +++++++++++++++++++++++++++---------------- + drivers/usb/host/xhci.h | 12 +++ + 3 files changed, 120 insertions(+), 49 deletions(-) + +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -952,6 +952,12 @@ struct xhci_ring { + u32 cycle_state; + }; + ++struct xhci_dequeue_state { ++ struct xhci_segment *new_deq_seg; ++ union xhci_trb *new_deq_ptr; ++ int new_cycle_state; ++}; ++ + struct xhci_erst_entry { + /* 64-bit event ring segment address */ + u64 seg_addr; +@@ -1203,6 +1209,12 @@ int xhci_queue_configure_endpoint(struct + u32 slot_id); + int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, + unsigned int ep_index); ++void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, ++ unsigned int slot_id, unsigned int ep_index, ++ struct xhci_td *cur_td, struct xhci_dequeue_state *state); ++void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, ++ struct xhci_ring *ep_ring, unsigned int slot_id, ++ unsigned int ep_index, struct xhci_dequeue_state *deq_state); + + /* xHCI roothub code */ + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -1089,6 +1089,8 @@ void xhci_endpoint_reset(struct usb_hcd + unsigned int ep_index; + unsigned long flags; + int ret; ++ struct xhci_dequeue_state deq_state; ++ struct xhci_ring *ep_ring; + + xhci = hcd_to_xhci(hcd); + udev = (struct usb_device *) ep->hcpriv; +@@ -1098,11 +1100,33 @@ void xhci_endpoint_reset(struct usb_hcd + if (!ep->hcpriv) + return; + ep_index = xhci_get_endpoint_index(&ep->desc); ++ ep_ring = xhci->devs[udev->slot_id]->ep_rings[ep_index]; ++ if (!ep_ring->stopped_td) { ++ xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n", ++ ep->desc.bEndpointAddress); ++ return; ++ } + + xhci_dbg(xhci, "Queueing reset endpoint command\n"); + spin_lock_irqsave(&xhci->lock, flags); + ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index); ++ /* ++ * Can't change the ring dequeue pointer until it's transitioned to the ++ * stopped state, which is only upon a successful reset endpoint ++ * command. Better hope that last command worked! ++ */ + if (!ret) { ++ xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n"); ++ /* We need to move the HW's dequeue pointer past this TD, ++ * or it will attempt to resend it on the next doorbell ring. ++ */ ++ xhci_find_new_dequeue_state(xhci, udev->slot_id, ++ ep_index, ep_ring->stopped_td, &deq_state); ++ xhci_dbg(xhci, "Queueing new dequeue state\n"); ++ xhci_queue_new_dequeue_state(xhci, ep_ring, ++ udev->slot_id, ++ ep_index, &deq_state); ++ kfree(ep_ring->stopped_td); + xhci_ring_cmd_db(xhci); + } + spin_unlock_irqrestore(&xhci->lock, flags); +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -335,12 +335,6 @@ static struct xhci_segment *find_trb_seg + return cur_seg; + } + +-struct dequeue_state { +- struct xhci_segment *new_deq_seg; +- union xhci_trb *new_deq_ptr; +- int new_cycle_state; +-}; +- + /* + * Move the xHC's endpoint ring dequeue pointer past cur_td. + * Record the new state of the xHC's endpoint ring dequeue segment, +@@ -355,26 +349,30 @@ struct dequeue_state { + * - Finally we move the dequeue state one TRB further, toggling the cycle bit + * if we've moved it past a link TRB with the toggle cycle bit set. + */ +-static void find_new_dequeue_state(struct xhci_hcd *xhci, ++void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, +- struct xhci_td *cur_td, struct dequeue_state *state) ++ struct xhci_td *cur_td, struct xhci_dequeue_state *state) + { + struct xhci_virt_device *dev = xhci->devs[slot_id]; + struct xhci_ring *ep_ring = dev->ep_rings[ep_index]; + struct xhci_generic_trb *trb; + struct xhci_ep_ctx *ep_ctx; ++ dma_addr_t addr; + + state->new_cycle_state = 0; ++ xhci_dbg(xhci, "Finding segment containing stopped TRB.\n"); + state->new_deq_seg = find_trb_seg(cur_td->start_seg, + ep_ring->stopped_trb, + &state->new_cycle_state); + if (!state->new_deq_seg) + BUG(); + /* Dig out the cycle state saved by the xHC during the stop ep cmd */ ++ xhci_dbg(xhci, "Finding endpoint context\n"); + ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); + state->new_cycle_state = 0x1 & ep_ctx->deq; + + state->new_deq_ptr = cur_td->last_trb; ++ xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n"); + state->new_deq_seg = find_trb_seg(state->new_deq_seg, + state->new_deq_ptr, + &state->new_cycle_state); +@@ -388,6 +386,12 @@ static void find_new_dequeue_state(struc + next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr); + + /* Don't update the ring cycle state for the producer (us). */ ++ xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n", ++ state->new_deq_seg); ++ addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr); ++ xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n", ++ (unsigned long long) addr); ++ xhci_dbg(xhci, "Setting dequeue pointer in internal ring state.\n"); + ep_ring->dequeue = state->new_deq_ptr; + ep_ring->deq_seg = state->new_deq_seg; + } +@@ -437,6 +441,30 @@ static int queue_set_tr_deq(struct xhci_ + unsigned int ep_index, struct xhci_segment *deq_seg, + union xhci_trb *deq_ptr, u32 cycle_state); + ++void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, ++ struct xhci_ring *ep_ring, unsigned int slot_id, ++ unsigned int ep_index, struct xhci_dequeue_state *deq_state) ++{ ++ xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " ++ "new deq ptr = %p (0x%llx dma), new cycle = %u\n", ++ deq_state->new_deq_seg, ++ (unsigned long long)deq_state->new_deq_seg->dma, ++ deq_state->new_deq_ptr, ++ (unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr), ++ deq_state->new_cycle_state); ++ queue_set_tr_deq(xhci, slot_id, ep_index, ++ deq_state->new_deq_seg, ++ deq_state->new_deq_ptr, ++ (u32) deq_state->new_cycle_state); ++ /* Stop the TD queueing code from ringing the doorbell until ++ * this command completes. The HC won't set the dequeue pointer ++ * if the ring is running, and ringing the doorbell starts the ++ * ring running. ++ */ ++ ep_ring->state |= SET_DEQ_PENDING; ++ xhci_ring_cmd_db(xhci); ++} ++ + /* + * When we get a command completion for a Stop Endpoint Command, we need to + * unlink any cancelled TDs from the ring. There are two ways to do that: +@@ -457,7 +485,7 @@ static void handle_stopped_endpoint(stru + struct xhci_td *cur_td = 0; + struct xhci_td *last_unlinked_td; + +- struct dequeue_state deq_state; ++ struct xhci_dequeue_state deq_state; + #ifdef CONFIG_USB_HCD_STAT + ktime_t stop_time = ktime_get(); + #endif +@@ -485,7 +513,7 @@ static void handle_stopped_endpoint(stru + * move the xHC endpoint ring dequeue pointer past this TD. + */ + if (cur_td == ep_ring->stopped_td) +- find_new_dequeue_state(xhci, slot_id, ep_index, cur_td, ++ xhci_find_new_dequeue_state(xhci, slot_id, ep_index, cur_td, + &deq_state); + else + td_to_noop(xhci, ep_ring, cur_td); +@@ -501,24 +529,8 @@ static void handle_stopped_endpoint(stru + + /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ + if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { +- xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " +- "new deq ptr = %p (0x%llx dma), new cycle = %u\n", +- deq_state.new_deq_seg, +- (unsigned long long)deq_state.new_deq_seg->dma, +- deq_state.new_deq_ptr, +- (unsigned long long)xhci_trb_virt_to_dma(deq_state.new_deq_seg, deq_state.new_deq_ptr), +- deq_state.new_cycle_state); +- queue_set_tr_deq(xhci, slot_id, ep_index, +- deq_state.new_deq_seg, +- deq_state.new_deq_ptr, +- (u32) deq_state.new_cycle_state); +- /* Stop the TD queueing code from ringing the doorbell until +- * this command completes. The HC won't set the dequeue pointer +- * if the ring is running, and ringing the doorbell starts the +- * ring running. +- */ +- ep_ring->state |= SET_DEQ_PENDING; +- xhci_ring_cmd_db(xhci); ++ xhci_queue_new_dequeue_state(xhci, ep_ring, ++ slot_id, ep_index, &deq_state); + } else { + /* Otherwise just ring the doorbell to restart the ring */ + ring_ep_doorbell(xhci, slot_id, ep_index); +@@ -929,12 +941,15 @@ static int handle_tx_event(struct xhci_h + if (event_trb != ep_ring->dequeue) { + /* The event was for the status stage */ + if (event_trb == td->last_trb) { +- /* Did we already see a short data stage? */ +- if (td->urb->actual_length != 0) +- status = -EREMOTEIO; +- else ++ if (td->urb->actual_length != 0) { ++ /* Don't overwrite a previously set error code */ ++ if (status == -EINPROGRESS || status == 0) ++ /* Did we already see a short data stage? */ ++ status = -EREMOTEIO; ++ } else { + td->urb->actual_length = + td->urb->transfer_buffer_length; ++ } + } else { + /* Maybe the event was for the data stage? */ + if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) { +@@ -992,16 +1007,20 @@ static int handle_tx_event(struct xhci_h + TRB_LEN(event->transfer_len)); + td->urb->actual_length = 0; + } +- if (td->urb->transfer_flags & URB_SHORT_NOT_OK) +- status = -EREMOTEIO; +- else +- status = 0; ++ /* Don't overwrite a previously set error code */ ++ if (status == -EINPROGRESS) { ++ if (td->urb->transfer_flags & URB_SHORT_NOT_OK) ++ status = -EREMOTEIO; ++ else ++ status = 0; ++ } + } else { + td->urb->actual_length = td->urb->transfer_buffer_length; + /* Ignore a short packet completion if the + * untransferred length was zero. + */ +- status = 0; ++ if (status == -EREMOTEIO) ++ status = 0; + } + } else { + /* Slow path - walk the list, starting from the dequeue +@@ -1028,19 +1047,30 @@ static int handle_tx_event(struct xhci_h + TRB_LEN(event->transfer_len); + } + } +- /* The Endpoint Stop Command completion will take care of +- * any stopped TDs. A stopped TD may be restarted, so don't update the +- * ring dequeue pointer or take this TD off any lists yet. +- */ + if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL || + GET_COMP_CODE(event->transfer_len) == COMP_STOP) { ++ /* The Endpoint Stop Command completion will take care of any ++ * stopped TDs. A stopped TD may be restarted, so don't update ++ * the ring dequeue pointer or take this TD off any lists yet. ++ */ + ep_ring->stopped_td = td; + ep_ring->stopped_trb = event_trb; + } else { +- /* Update ring dequeue pointer */ +- while (ep_ring->dequeue != td->last_trb) ++ if (GET_COMP_CODE(event->transfer_len) == COMP_STALL) { ++ /* The transfer is completed from the driver's ++ * perspective, but we need to issue a set dequeue ++ * command for this stalled endpoint to move the dequeue ++ * pointer past the TD. We can't do that here because ++ * the halt condition must be cleared first. ++ */ ++ ep_ring->stopped_td = td; ++ ep_ring->stopped_trb = event_trb; ++ } else { ++ /* Update ring dequeue pointer */ ++ while (ep_ring->dequeue != td->last_trb) ++ inc_deq(xhci, ep_ring, false); + inc_deq(xhci, ep_ring, false); +- inc_deq(xhci, ep_ring, false); ++ } + + /* Clean up the endpoint's TD list */ + urb = td->urb; +@@ -1050,7 +1080,10 @@ static int handle_tx_event(struct xhci_h + list_del(&td->cancelled_td_list); + ep_ring->cancels_pending--; + } +- kfree(td); ++ /* Leave the TD around for the reset endpoint function to use */ ++ if (GET_COMP_CODE(event->transfer_len) != COMP_STALL) { ++ kfree(td); ++ } + urb->hcpriv = NULL; + } + cleanup: +@@ -1166,13 +1199,13 @@ static int prepare_ring(struct xhci_hcd + */ + xhci_warn(xhci, "WARN urb submitted to disabled ep\n"); + return -ENOENT; +- case EP_STATE_HALTED: + case EP_STATE_ERROR: +- xhci_warn(xhci, "WARN waiting for halt or error on ep " +- "to be cleared\n"); ++ xhci_warn(xhci, "WARN waiting for error on ep to be cleared\n"); + /* FIXME event handling code for error needs to clear it */ + /* XXX not sure if this should be -ENOENT or not */ + return -EINVAL; ++ case EP_STATE_HALTED: ++ xhci_dbg(xhci, "WARN halted endpoint, queueing URB anyway.\n"); + case EP_STATE_STOPPED: + case EP_STATE_RUNNING: + break; +@@ -1724,10 +1757,12 @@ static int queue_set_tr_deq(struct xhci_ + u32 type = TRB_TYPE(TRB_SET_DEQ); + + addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr); +- if (addr == 0) ++ if (addr == 0) { + xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); + xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n", + deq_seg, deq_ptr); ++ return 0; ++ } + return queue_command(xhci, lower_32_bits(addr) | cycle_state, + upper_32_bits(addr), 0, + trb_slot_id | trb_ep_index | type); diff --git a/usb.current/usb-xhci-support-for-64-byte-contexts.patch b/usb.current/usb-xhci-support-for-64-byte-contexts.patch new file mode 100644 index 00000000000000..82fcd510775790 --- /dev/null +++ b/usb.current/usb-xhci-support-for-64-byte-contexts.patch @@ -0,0 +1,925 @@ +From johnyoun@synopsys.com Mon Jul 27 12:32:02 2009 +From: John Youn <johnyoun@synopsys.com> +Date: Mon, 27 Jul 2009 12:05:15 -0700 +Subject: USB: xhci: Support for 64-byte contexts +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com>, John Youn <johnyoun@synopsys.com> +Message-ID: <20090727190515.GA8030@gamba.jf.intel.com> +Content-Disposition: inline + + +From: John Youn <johnyoun@synopsys.com> + +Adds support for controllers that use 64-byte contexts. The following context +data structures are affected by this: Device, Input, Input Control, Endpoint, +and Slot. To accommodate the use of either 32 or 64-byte contexts, a Device or +Input context can only be accessed through functions which look-up and return +pointers to their contained contexts. + +Signed-off-by: John Youn <johnyoun@synopsys.com> +Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-dbg.c | 125 +++++++++++++++++++++++++++---------------- + drivers/usb/host/xhci-hcd.c | 121 ++++++++++++++++++++++++----------------- + drivers/usb/host/xhci-mem.c | 121 +++++++++++++++++++++++++++++------------ + drivers/usb/host/xhci-ring.c | 22 +++++-- + drivers/usb/host/xhci.h | 61 +++++++++++--------- + 5 files changed, 287 insertions(+), 163 deletions(-) + +--- a/drivers/usb/host/xhci-dbg.c ++++ b/drivers/usb/host/xhci-dbg.c +@@ -393,103 +393,138 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd * + upper_32_bits(val)); + } + +-dma_addr_t xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_slot_ctx *slot, dma_addr_t dma) ++/* Print the last 32 bytes for 64-byte contexts */ ++static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma) ++{ ++ int i; ++ for (i = 0; i < 4; ++i) { ++ xhci_dbg(xhci, "@%p (virt) @%08llx " ++ "(dma) %#08llx - rsvd64[%d]\n", ++ &ctx[4 + i], (unsigned long long)dma, ++ ctx[4 + i], i); ++ dma += 8; ++ } ++} ++ ++void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx) + { + /* Fields are 32 bits wide, DMA addresses are in bytes */ + int field_size = 32 / 8; + int i; + ++ struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx); ++ dma_addr_t dma = ctx->dma + ((unsigned long)slot_ctx - (unsigned long)ctx); ++ int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); ++ + xhci_dbg(xhci, "Slot Context:\n"); + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", +- &slot->dev_info, +- (unsigned long long)dma, slot->dev_info); ++ &slot_ctx->dev_info, ++ (unsigned long long)dma, slot_ctx->dev_info); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", +- &slot->dev_info2, +- (unsigned long long)dma, slot->dev_info2); ++ &slot_ctx->dev_info2, ++ (unsigned long long)dma, slot_ctx->dev_info2); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", +- &slot->tt_info, +- (unsigned long long)dma, slot->tt_info); ++ &slot_ctx->tt_info, ++ (unsigned long long)dma, slot_ctx->tt_info); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", +- &slot->dev_state, +- (unsigned long long)dma, slot->dev_state); ++ &slot_ctx->dev_state, ++ (unsigned long long)dma, slot_ctx->dev_state); + dma += field_size; + for (i = 0; i < 4; ++i) { + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", +- &slot->reserved[i], (unsigned long long)dma, +- slot->reserved[i], i); ++ &slot_ctx->reserved[i], (unsigned long long)dma, ++ slot_ctx->reserved[i], i); + dma += field_size; + } + +- return dma; ++ if (csz) ++ dbg_rsvd64(xhci, (u64 *)slot_ctx, dma); + } + +-dma_addr_t xhci_dbg_ep_ctx(struct xhci_hcd *xhci, struct xhci_ep_ctx *ep, dma_addr_t dma, unsigned int last_ep) ++void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, ++ struct xhci_container_ctx *ctx, ++ unsigned int last_ep) + { + int i, j; + int last_ep_ctx = 31; + /* Fields are 32 bits wide, DMA addresses are in bytes */ + int field_size = 32 / 8; ++ int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); + + if (last_ep < 31) + last_ep_ctx = last_ep + 1; + for (i = 0; i < last_ep_ctx; ++i) { ++ struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i); ++ dma_addr_t dma = ctx->dma + ++ ((unsigned long)ep_ctx - (unsigned long)ctx); ++ + xhci_dbg(xhci, "Endpoint %02d Context:\n", i); + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", +- &ep[i].ep_info, +- (unsigned long long)dma, ep[i].ep_info); ++ &ep_ctx->ep_info, ++ (unsigned long long)dma, ep_ctx->ep_info); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", +- &ep[i].ep_info2, +- (unsigned long long)dma, ep[i].ep_info2); ++ &ep_ctx->ep_info2, ++ (unsigned long long)dma, ep_ctx->ep_info2); + dma += field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", +- &ep[i].deq, +- (unsigned long long)dma, ep[i].deq); ++ &ep_ctx->deq, ++ (unsigned long long)dma, ep_ctx->deq); + dma += 2*field_size; + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", +- &ep[i].tx_info, +- (unsigned long long)dma, ep[i].tx_info); ++ &ep_ctx->tx_info, ++ (unsigned long long)dma, ep_ctx->tx_info); + dma += field_size; + for (j = 0; j < 3; ++j) { + xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", +- &ep[i].reserved[j], ++ &ep_ctx->reserved[j], + (unsigned long long)dma, +- ep[i].reserved[j], j); ++ ep_ctx->reserved[j], j); + dma += field_size; + } ++ ++ if (csz) ++ dbg_rsvd64(xhci, (u64 *)ep_ctx, dma); + } +- return dma; + } + +-void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep) ++void xhci_dbg_ctx(struct xhci_hcd *xhci, ++ struct xhci_container_ctx *ctx, ++ unsigned int last_ep) + { + int i; + /* Fields are 32 bits wide, DMA addresses are in bytes */ + int field_size = 32 / 8; +- +- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", +- &ctx->drop_flags, (unsigned long long)dma, +- ctx->drop_flags); +- dma += field_size; +- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", +- &ctx->add_flags, (unsigned long long)dma, +- ctx->add_flags); +- dma += field_size; +- for (i = 0; i < 6; ++i) { +- xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", +- &ctx->rsvd[i], (unsigned long long)dma, +- ctx->rsvd[i], i); ++ struct xhci_slot_ctx *slot_ctx; ++ dma_addr_t dma = ctx->dma; ++ int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); ++ ++ if (ctx->type == XHCI_CTX_TYPE_INPUT) { ++ struct xhci_input_control_ctx *ctrl_ctx = ++ xhci_get_input_control_ctx(xhci, ctx); ++ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", ++ &ctrl_ctx->drop_flags, (unsigned long long)dma, ++ ctrl_ctx->drop_flags); + dma += field_size; ++ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", ++ &ctrl_ctx->add_flags, (unsigned long long)dma, ++ ctrl_ctx->add_flags); ++ dma += field_size; ++ for (i = 0; i < 6; ++i) { ++ xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd2[%d]\n", ++ &ctrl_ctx->rsvd2[i], (unsigned long long)dma, ++ ctrl_ctx->rsvd2[i], i); ++ dma += field_size; ++ } ++ ++ if (csz) ++ dbg_rsvd64(xhci, (u64 *)ctrl_ctx, dma); + } +- dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma); +- dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep); +-} + +-void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep) +-{ +- dma = xhci_dbg_slot_ctx(xhci, &ctx->slot, dma); +- dma = xhci_dbg_ep_ctx(xhci, ctx->ep, dma, last_ep); ++ slot_ctx = xhci_get_slot_ctx(xhci, ctx); ++ xhci_dbg_slot_ctx(xhci, ctx); ++ xhci_dbg_ep_ctx(xhci, ctx, last_ep); + } +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -447,6 +447,27 @@ struct xhci_doorbell_array { + + + /** ++ * struct xhci_container_ctx ++ * @type: Type of context. Used to calculated offsets to contained contexts. ++ * @size: Size of the context data ++ * @bytes: The raw context data given to HW ++ * @dma: dma address of the bytes ++ * ++ * Represents either a Device or Input context. Holds a pointer to the raw ++ * memory used for the context (bytes) and dma address of it (dma). ++ */ ++struct xhci_container_ctx { ++ unsigned type; ++#define XHCI_CTX_TYPE_DEVICE 0x1 ++#define XHCI_CTX_TYPE_INPUT 0x2 ++ ++ int size; ++ ++ u8 *bytes; ++ dma_addr_t dma; ++}; ++ ++/** + * struct xhci_slot_ctx + * @dev_info: Route string, device speed, hub info, and last valid endpoint + * @dev_info2: Max exit latency for device number, root hub port number +@@ -583,32 +604,16 @@ struct xhci_ep_ctx { + + + /** +- * struct xhci_device_control +- * Input context; see section 6.2.5. ++ * struct xhci_input_control_context ++ * Input control context; see section 6.2.5. + * + * @drop_context: set the bit of the endpoint context you want to disable + * @add_context: set the bit of the endpoint context you want to enable + */ +-struct xhci_device_control { +- /* Input control context */ ++struct xhci_input_control_ctx { + u32 drop_flags; + u32 add_flags; +- u32 rsvd[6]; +- /* Copy of device context */ +- struct xhci_slot_ctx slot; +- struct xhci_ep_ctx ep[31]; +-}; +- +-/** +- * struct xhci_device_ctx +- * Device context; see section 6.2.1. +- * +- * @slot: slot context for the device. +- * @ep: array of endpoint contexts for the device. +- */ +-struct xhci_device_ctx { +- struct xhci_slot_ctx slot; +- struct xhci_ep_ctx ep[31]; ++ u32 rsvd2[6]; + }; + + /* drop context bitmasks */ +@@ -616,7 +621,6 @@ struct xhci_device_ctx { + /* add context bitmasks */ + #define ADD_EP(x) (0x1 << x) + +- + struct xhci_virt_device { + /* + * Commands to the hardware are passed an "input context" that +@@ -626,11 +630,10 @@ struct xhci_virt_device { + * track of input and output contexts separately because + * these commands might fail and we don't trust the hardware. + */ +- struct xhci_device_ctx *out_ctx; +- dma_addr_t out_ctx_dma; ++ struct xhci_container_ctx *out_ctx; + /* Used for addressing devices and configuration changes */ +- struct xhci_device_control *in_ctx; +- dma_addr_t in_ctx_dma; ++ struct xhci_container_ctx *in_ctx; ++ + /* FIXME when stream support is added */ + struct xhci_ring *ep_rings[31]; + /* Temporary storage in case the configure endpoint command fails and we +@@ -1139,8 +1142,7 @@ void xhci_debug_ring(struct xhci_hcd *xh + void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); + void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); + void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); +-void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep); +-void xhci_dbg_device_ctx(struct xhci_hcd *xhci, struct xhci_device_ctx *ctx, dma_addr_t dma, unsigned int last_ep); ++void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep); + + /* xHCI memory managment */ + void xhci_mem_cleanup(struct xhci_hcd *xhci); +@@ -1207,4 +1209,9 @@ int xhci_hub_control(struct usb_hcd *hcd + char *buf, u16 wLength); + int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); + ++/* xHCI contexts */ ++struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); ++struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); ++struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); ++ + #endif /* __LINUX_XHCI_HCD_H */ +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -722,7 +722,9 @@ int xhci_drop_endpoint(struct usb_hcd *h + struct usb_host_endpoint *ep) + { + struct xhci_hcd *xhci; +- struct xhci_device_control *in_ctx; ++ struct xhci_container_ctx *in_ctx, *out_ctx; ++ struct xhci_input_control_ctx *ctrl_ctx; ++ struct xhci_slot_ctx *slot_ctx; + unsigned int last_ctx; + unsigned int ep_index; + struct xhci_ep_ctx *ep_ctx; +@@ -750,31 +752,34 @@ int xhci_drop_endpoint(struct usb_hcd *h + } + + in_ctx = xhci->devs[udev->slot_id]->in_ctx; ++ out_ctx = xhci->devs[udev->slot_id]->out_ctx; ++ ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); + ep_index = xhci_get_endpoint_index(&ep->desc); +- ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index]; ++ ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); + /* If the HC already knows the endpoint is disabled, + * or the HCD has noted it is disabled, ignore this request + */ + if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED || +- in_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) { ++ ctrl_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) { + xhci_warn(xhci, "xHCI %s called with disabled ep %p\n", + __func__, ep); + return 0; + } + +- in_ctx->drop_flags |= drop_flag; +- new_drop_flags = in_ctx->drop_flags; ++ ctrl_ctx->drop_flags |= drop_flag; ++ new_drop_flags = ctrl_ctx->drop_flags; + +- in_ctx->add_flags = ~drop_flag; +- new_add_flags = in_ctx->add_flags; ++ ctrl_ctx->add_flags = ~drop_flag; ++ new_add_flags = ctrl_ctx->add_flags; + +- last_ctx = xhci_last_valid_endpoint(in_ctx->add_flags); ++ last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags); ++ slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); + /* Update the last valid endpoint context, if we deleted the last one */ +- if ((in_ctx->slot.dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) { +- in_ctx->slot.dev_info &= ~LAST_CTX_MASK; +- in_ctx->slot.dev_info |= LAST_CTX(last_ctx); ++ if ((slot_ctx->dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) { ++ slot_ctx->dev_info &= ~LAST_CTX_MASK; ++ slot_ctx->dev_info |= LAST_CTX(last_ctx); + } +- new_slot_info = in_ctx->slot.dev_info; ++ new_slot_info = slot_ctx->dev_info; + + xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep); + +@@ -804,9 +809,11 @@ int xhci_add_endpoint(struct usb_hcd *hc + struct usb_host_endpoint *ep) + { + struct xhci_hcd *xhci; +- struct xhci_device_control *in_ctx; ++ struct xhci_container_ctx *in_ctx, *out_ctx; + unsigned int ep_index; + struct xhci_ep_ctx *ep_ctx; ++ struct xhci_slot_ctx *slot_ctx; ++ struct xhci_input_control_ctx *ctrl_ctx; + u32 added_ctxs; + unsigned int last_ctx; + u32 new_add_flags, new_drop_flags, new_slot_info; +@@ -839,12 +846,14 @@ int xhci_add_endpoint(struct usb_hcd *hc + } + + in_ctx = xhci->devs[udev->slot_id]->in_ctx; ++ out_ctx = xhci->devs[udev->slot_id]->out_ctx; ++ ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); + ep_index = xhci_get_endpoint_index(&ep->desc); +- ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index]; ++ ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); + /* If the HCD has already noted the endpoint is enabled, + * ignore this request. + */ +- if (in_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) { ++ if (ctrl_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) { + xhci_warn(xhci, "xHCI %s called with enabled ep %p\n", + __func__, ep); + return 0; +@@ -862,8 +871,8 @@ int xhci_add_endpoint(struct usb_hcd *hc + return -ENOMEM; + } + +- in_ctx->add_flags |= added_ctxs; +- new_add_flags = in_ctx->add_flags; ++ ctrl_ctx->add_flags |= added_ctxs; ++ new_add_flags = ctrl_ctx->add_flags; + + /* If xhci_endpoint_disable() was called for this endpoint, but the + * xHC hasn't been notified yet through the check_bandwidth() call, +@@ -871,14 +880,15 @@ int xhci_add_endpoint(struct usb_hcd *hc + * descriptors. We must drop and re-add this endpoint, so we leave the + * drop flags alone. + */ +- new_drop_flags = in_ctx->drop_flags; ++ new_drop_flags = ctrl_ctx->drop_flags; + ++ slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); + /* Update the last valid endpoint context, if we just added one past */ +- if ((in_ctx->slot.dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) { +- in_ctx->slot.dev_info &= ~LAST_CTX_MASK; +- in_ctx->slot.dev_info |= LAST_CTX(last_ctx); ++ if ((slot_ctx->dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) { ++ slot_ctx->dev_info &= ~LAST_CTX_MASK; ++ slot_ctx->dev_info |= LAST_CTX(last_ctx); + } +- new_slot_info = in_ctx->slot.dev_info; ++ new_slot_info = slot_ctx->dev_info; + + /* Store the usb_device pointer for later use */ + ep->hcpriv = udev; +@@ -892,9 +902,11 @@ int xhci_add_endpoint(struct usb_hcd *hc + return 0; + } + +-static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev) ++static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev) + { ++ struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_ep_ctx *ep_ctx; ++ struct xhci_slot_ctx *slot_ctx; + int i; + + /* When a device's add flag and drop flag are zero, any subsequent +@@ -902,13 +914,15 @@ static void xhci_zero_in_ctx(struct xhci + * untouched. Make sure we don't leave any old state in the input + * endpoint contexts. + */ +- virt_dev->in_ctx->drop_flags = 0; +- virt_dev->in_ctx->add_flags = 0; +- virt_dev->in_ctx->slot.dev_info &= ~LAST_CTX_MASK; ++ ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ++ ctrl_ctx->drop_flags = 0; ++ ctrl_ctx->add_flags = 0; ++ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); ++ slot_ctx->dev_info &= ~LAST_CTX_MASK; + /* Endpoint 0 is always valid */ +- virt_dev->in_ctx->slot.dev_info |= LAST_CTX(1); ++ slot_ctx->dev_info |= LAST_CTX(1); + for (i = 1; i < 31; ++i) { +- ep_ctx = &virt_dev->in_ctx->ep[i]; ++ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i); + ep_ctx->ep_info = 0; + ep_ctx->ep_info2 = 0; + ep_ctx->deq = 0; +@@ -934,6 +948,8 @@ int xhci_check_bandwidth(struct usb_hcd + unsigned long flags; + struct xhci_hcd *xhci; + struct xhci_virt_device *virt_dev; ++ struct xhci_input_control_ctx *ctrl_ctx; ++ struct xhci_slot_ctx *slot_ctx; + + ret = xhci_check_args(hcd, udev, NULL, 0, __func__); + if (ret <= 0) +@@ -949,16 +965,18 @@ int xhci_check_bandwidth(struct usb_hcd + virt_dev = xhci->devs[udev->slot_id]; + + /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */ +- virt_dev->in_ctx->add_flags |= SLOT_FLAG; +- virt_dev->in_ctx->add_flags &= ~EP0_FLAG; +- virt_dev->in_ctx->drop_flags &= ~SLOT_FLAG; +- virt_dev->in_ctx->drop_flags &= ~EP0_FLAG; ++ ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ++ ctrl_ctx->add_flags |= SLOT_FLAG; ++ ctrl_ctx->add_flags &= ~EP0_FLAG; ++ ctrl_ctx->drop_flags &= ~SLOT_FLAG; ++ ctrl_ctx->drop_flags &= ~EP0_FLAG; + xhci_dbg(xhci, "New Input Control Context:\n"); +- xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, +- LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); ++ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); ++ xhci_dbg_ctx(xhci, virt_dev->in_ctx, ++ LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); + + spin_lock_irqsave(&xhci->lock, flags); +- ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx_dma, ++ ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma, + udev->slot_id); + if (ret < 0) { + spin_unlock_irqrestore(&xhci->lock, flags); +@@ -1013,10 +1031,10 @@ int xhci_check_bandwidth(struct usb_hcd + } + + xhci_dbg(xhci, "Output context after successful config ep cmd:\n"); +- xhci_dbg_device_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, +- LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info)); ++ xhci_dbg_ctx(xhci, virt_dev->out_ctx, ++ LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); + +- xhci_zero_in_ctx(virt_dev); ++ xhci_zero_in_ctx(xhci, virt_dev); + /* Free any old rings */ + for (i = 1; i < 31; ++i) { + if (virt_dev->new_ep_rings[i]) { +@@ -1054,7 +1072,7 @@ void xhci_reset_bandwidth(struct usb_hcd + virt_dev->new_ep_rings[i] = NULL; + } + } +- xhci_zero_in_ctx(virt_dev); ++ xhci_zero_in_ctx(xhci, virt_dev); + } + + /* Deal with stalled endpoints. The core should have sent the control message +@@ -1187,6 +1205,8 @@ int xhci_address_device(struct usb_hcd * + struct xhci_virt_device *virt_dev; + int ret = 0; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); ++ struct xhci_slot_ctx *slot_ctx; ++ struct xhci_input_control_ctx *ctrl_ctx; + u64 temp_64; + + if (!udev->slot_id) { +@@ -1201,11 +1221,11 @@ int xhci_address_device(struct usb_hcd * + xhci_setup_addressable_virt_dev(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, virt_dev->in_ctx_dma, 2); ++ xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); + + spin_lock_irqsave(&xhci->lock, flags); +- ret = xhci_queue_address_device(xhci, virt_dev->in_ctx_dma, +- udev->slot_id); ++ ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, ++ udev->slot_id); + if (ret) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); +@@ -1246,7 +1266,7 @@ int xhci_address_device(struct usb_hcd * + xhci_err(xhci, "ERROR: unexpected command completion " + "code 0x%x.\n", virt_dev->cmd_status); + xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); +- xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); ++ xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); + ret = -EINVAL; + break; + } +@@ -1261,19 +1281,21 @@ int xhci_address_device(struct usb_hcd * + (unsigned long long) + xhci->dcbaa->dev_context_ptrs[udev->slot_id]); + xhci_dbg(xhci, "Output Context DMA address = %#08llx\n", +- (unsigned long long)virt_dev->out_ctx_dma); ++ (unsigned long long)virt_dev->out_ctx->dma); + xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); +- xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2); ++ xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); + xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); +- xhci_dbg_device_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2); ++ xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); + /* + * USB core uses address 1 for the roothubs, so we add one to the + * address given back to us by the HC. + */ +- udev->devnum = (virt_dev->out_ctx->slot.dev_state & DEV_ADDR_MASK) + 1; ++ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); ++ udev->devnum = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1; + /* Zero the input context control for later use */ +- virt_dev->in_ctx->add_flags = 0; +- virt_dev->in_ctx->drop_flags = 0; ++ ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ++ ctrl_ctx->add_flags = 0; ++ ctrl_ctx->drop_flags = 0; + + xhci_dbg(xhci, "Device address = %d\n", udev->devnum); + /* XXX Meh, not sure if anyone else but choose_address uses this. */ +@@ -1315,7 +1337,6 @@ static int __init xhci_hcd_init(void) + /* xhci_device_control has eight fields, and also + * embeds one xhci_slot_ctx and 31 xhci_ep_ctx + */ +- BUILD_BUG_ON(sizeof(struct xhci_device_control) != (8+8+8*31)*32/8); + BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8); + BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8); + BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8); +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -189,6 +189,63 @@ fail: + return 0; + } + ++#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32) ++ ++struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, ++ int type, gfp_t flags) ++{ ++ struct xhci_container_ctx *ctx = kzalloc(sizeof(*ctx), flags); ++ if (!ctx) ++ return NULL; ++ ++ BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT)); ++ ctx->type = type; ++ ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024; ++ if (type == XHCI_CTX_TYPE_INPUT) ++ ctx->size += CTX_SIZE(xhci->hcc_params); ++ ++ ctx->bytes = dma_pool_alloc(xhci->device_pool, flags, &ctx->dma); ++ memset(ctx->bytes, 0, ctx->size); ++ return ctx; ++} ++ ++void xhci_free_container_ctx(struct xhci_hcd *xhci, ++ struct xhci_container_ctx *ctx) ++{ ++ dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma); ++ kfree(ctx); ++} ++ ++struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, ++ struct xhci_container_ctx *ctx) ++{ ++ BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT); ++ return (struct xhci_input_control_ctx *)ctx->bytes; ++} ++ ++struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, ++ struct xhci_container_ctx *ctx) ++{ ++ if (ctx->type == XHCI_CTX_TYPE_DEVICE) ++ return (struct xhci_slot_ctx *)ctx->bytes; ++ ++ return (struct xhci_slot_ctx *) ++ (ctx->bytes + CTX_SIZE(xhci->hcc_params)); ++} ++ ++struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, ++ struct xhci_container_ctx *ctx, ++ unsigned int ep_index) ++{ ++ /* increment ep index by offset of start of ep ctx array */ ++ ep_index++; ++ if (ctx->type == XHCI_CTX_TYPE_INPUT) ++ ep_index++; ++ ++ return (struct xhci_ep_ctx *) ++ (ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params))); ++} ++ + /* All the xhci_tds in the ring's TD list should be freed at this point */ + void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) + { +@@ -209,11 +266,10 @@ void xhci_free_virt_device(struct xhci_h + xhci_ring_free(xhci, dev->ep_rings[i]); + + if (dev->in_ctx) +- dma_pool_free(xhci->device_pool, +- dev->in_ctx, dev->in_ctx_dma); ++ xhci_free_container_ctx(xhci, dev->in_ctx); + if (dev->out_ctx) +- dma_pool_free(xhci->device_pool, +- dev->out_ctx, dev->out_ctx_dma); ++ xhci_free_container_ctx(xhci, dev->out_ctx); ++ + kfree(xhci->devs[slot_id]); + xhci->devs[slot_id] = 0; + } +@@ -221,7 +277,6 @@ void xhci_free_virt_device(struct xhci_h + int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, + struct usb_device *udev, gfp_t flags) + { +- dma_addr_t dma; + struct xhci_virt_device *dev; + + /* Slot ID 0 is reserved */ +@@ -235,26 +290,21 @@ int xhci_alloc_virt_device(struct xhci_h + return 0; + dev = xhci->devs[slot_id]; + +- /* Allocate the (output) device context that will be used in the HC. +- * The structure is 32 bytes smaller than the input context, but that's +- * fine. +- */ +- dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); ++ /* Allocate the (output) device context that will be used in the HC. */ ++ dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags); + if (!dev->out_ctx) + goto fail; +- dev->out_ctx_dma = dma; ++ + xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, +- (unsigned long long)dma); +- memset(dev->out_ctx, 0, sizeof(*dev->out_ctx)); ++ (unsigned long long)dev->out_ctx->dma); + + /* Allocate the (input) device context for address device command */ +- dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma); ++ dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags); + if (!dev->in_ctx) + goto fail; +- dev->in_ctx_dma = dma; ++ + xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, +- (unsigned long long)dma); +- memset(dev->in_ctx, 0, sizeof(*dev->in_ctx)); ++ (unsigned long long)dev->in_ctx->dma); + + /* Allocate endpoint 0 ring */ + dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags); +@@ -264,7 +314,7 @@ int xhci_alloc_virt_device(struct xhci_h + init_completion(&dev->cmd_completion); + + /* Point to output device context in dcbaa. */ +- xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx_dma; ++ xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma; + xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", + slot_id, + &xhci->dcbaa->dev_context_ptrs[slot_id], +@@ -282,6 +332,8 @@ int xhci_setup_addressable_virt_dev(stru + struct xhci_virt_device *dev; + struct xhci_ep_ctx *ep0_ctx; + struct usb_device *top_dev; ++ struct xhci_slot_ctx *slot_ctx; ++ struct xhci_input_control_ctx *ctrl_ctx; + + dev = xhci->devs[udev->slot_id]; + /* Slot ID 0 is reserved */ +@@ -290,27 +342,29 @@ int xhci_setup_addressable_virt_dev(stru + udev->slot_id); + return -EINVAL; + } +- ep0_ctx = &dev->in_ctx->ep[0]; ++ ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0); ++ ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx); ++ slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx); + + /* 2) New slot context and endpoint 0 context are valid*/ +- dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG; ++ ctrl_ctx->add_flags = SLOT_FLAG | EP0_FLAG; + + /* 3) Only the control endpoint is valid - one endpoint context */ +- dev->in_ctx->slot.dev_info |= LAST_CTX(1); ++ slot_ctx->dev_info |= LAST_CTX(1); + + switch (udev->speed) { + case USB_SPEED_SUPER: +- dev->in_ctx->slot.dev_info |= (u32) udev->route; +- dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS; ++ slot_ctx->dev_info |= (u32) udev->route; ++ slot_ctx->dev_info |= (u32) SLOT_SPEED_SS; + break; + case USB_SPEED_HIGH: +- dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS; ++ slot_ctx->dev_info |= (u32) SLOT_SPEED_HS; + break; + case USB_SPEED_FULL: +- dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS; ++ slot_ctx->dev_info |= (u32) SLOT_SPEED_FS; + break; + case USB_SPEED_LOW: +- dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS; ++ slot_ctx->dev_info |= (u32) SLOT_SPEED_LS; + break; + case USB_SPEED_VARIABLE: + xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); +@@ -324,7 +378,7 @@ int xhci_setup_addressable_virt_dev(stru + for (top_dev = udev; top_dev->parent && top_dev->parent->parent; + top_dev = top_dev->parent) + /* Found device below root hub */; +- dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum); ++ slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum); + xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum); + + /* Is this a LS/FS device under a HS hub? */ +@@ -334,8 +388,8 @@ int xhci_setup_addressable_virt_dev(stru + */ + if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) && + udev->tt) { +- dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id; +- dev->in_ctx->slot.tt_info |= udev->ttport << 8; ++ slot_ctx->tt_info = udev->tt->hub->slot_id; ++ slot_ctx->tt_info |= udev->ttport << 8; + } + xhci_dbg(xhci, "udev->tt = %p\n", udev->tt); + xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport); +@@ -466,7 +520,7 @@ int xhci_endpoint_init(struct xhci_hcd * + unsigned int max_burst; + + ep_index = xhci_get_endpoint_index(&ep->desc); +- ep_ctx = &virt_dev->in_ctx->ep[ep_index]; ++ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); + + /* Set up the endpoint ring */ + virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags); +@@ -533,7 +587,7 @@ void xhci_endpoint_zero(struct xhci_hcd + struct xhci_ep_ctx *ep_ctx; + + ep_index = xhci_get_endpoint_index(&ep->desc); +- ep_ctx = &virt_dev->in_ctx->ep[ep_index]; ++ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); + + ep_ctx->ep_info = 0; + ep_ctx->ep_info2 = 0; +@@ -753,11 +807,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, + */ + xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, + SEGMENT_SIZE, 64, xhci->page_size); ++ + /* See Table 46 and Note on Figure 55 */ +- /* FIXME support 64-byte contexts */ + xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, +- sizeof(struct xhci_device_control), +- 64, xhci->page_size); ++ 2112, 64, xhci->page_size); + if (!xhci->segment_pool || !xhci->device_pool) + goto fail; + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -362,6 +362,7 @@ static void find_new_dequeue_state(struc + struct xhci_virt_device *dev = xhci->devs[slot_id]; + struct xhci_ring *ep_ring = dev->ep_rings[ep_index]; + struct xhci_generic_trb *trb; ++ struct xhci_ep_ctx *ep_ctx; + + state->new_cycle_state = 0; + state->new_deq_seg = find_trb_seg(cur_td->start_seg, +@@ -370,7 +371,8 @@ static void find_new_dequeue_state(struc + if (!state->new_deq_seg) + BUG(); + /* Dig out the cycle state saved by the xHC during the stop ep cmd */ +- state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq; ++ ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); ++ state->new_cycle_state = 0x1 & ep_ctx->deq; + + state->new_deq_ptr = cur_td->last_trb; + state->new_deq_seg = find_trb_seg(state->new_deq_seg, +@@ -570,11 +572,15 @@ static void handle_set_deq_completion(st + unsigned int ep_index; + struct xhci_ring *ep_ring; + struct xhci_virt_device *dev; ++ struct xhci_ep_ctx *ep_ctx; ++ struct xhci_slot_ctx *slot_ctx; + + slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); + ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); + dev = xhci->devs[slot_id]; + ep_ring = dev->ep_rings[ep_index]; ++ ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); ++ slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); + + if (GET_COMP_CODE(event->status) != COMP_SUCCESS) { + unsigned int ep_state; +@@ -588,9 +594,9 @@ static void handle_set_deq_completion(st + case COMP_CTX_STATE: + xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due " + "to incorrect slot or ep state.\n"); +- ep_state = dev->out_ctx->ep[ep_index].ep_info; ++ ep_state = ep_ctx->ep_info; + ep_state &= EP_STATE_MASK; +- slot_state = dev->out_ctx->slot.dev_state; ++ slot_state = slot_ctx->dev_state; + slot_state = GET_SLOT_STATE(slot_state); + xhci_dbg(xhci, "Slot state = %u, EP state = %u\n", + slot_state, ep_state); +@@ -613,7 +619,7 @@ static void handle_set_deq_completion(st + */ + } else { + xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n", +- dev->out_ctx->ep[ep_index].deq); ++ ep_ctx->deq); + } + + ep_ring->state &= ~SET_DEQ_PENDING; +@@ -795,6 +801,7 @@ static int handle_tx_event(struct xhci_h + union xhci_trb *event_trb; + struct urb *urb = 0; + int status = -EINPROGRESS; ++ struct xhci_ep_ctx *ep_ctx; + + xhci_dbg(xhci, "In %s\n", __func__); + xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)]; +@@ -807,7 +814,8 @@ static int handle_tx_event(struct xhci_h + ep_index = TRB_TO_EP_ID(event->flags) - 1; + xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index); + ep_ring = xdev->ep_rings[ep_index]; +- if (!ep_ring || (xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) { ++ ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); ++ if (!ep_ring || (ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) { + xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n"); + return -ENODEV; + } +@@ -1193,9 +1201,9 @@ static int prepare_transfer(struct xhci_ + gfp_t mem_flags) + { + int ret; +- ++ struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); + ret = prepare_ring(xhci, xdev->ep_rings[ep_index], +- xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK, ++ ep_ctx->ep_info & EP_STATE_MASK, + num_trbs, mem_flags); + if (ret) + return ret; diff --git a/usb.current/usb-xhci-use-gfp_atomic-while-holding-spinlocks.patch b/usb.current/usb-xhci-use-gfp_atomic-while-holding-spinlocks.patch new file mode 100644 index 00000000000000..66db17780f1932 --- /dev/null +++ b/usb.current/usb-xhci-use-gfp_atomic-while-holding-spinlocks.patch @@ -0,0 +1,40 @@ +From sarah.a.sharp@linux.intel.com Mon Jul 27 12:23:57 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Mon, 27 Jul 2009 12:03:23 -0700 +Subject: USB: xhci: Use GFP_ATOMIC while holding spinlocks. +Cc: linux-usb@vger.kernel.org, Greg KH <greg@kroah.com> +Message-ID: <20090727190323.GA7537@gamba.jf.intel.com> +Content-Disposition: inline + + +The xHCI functions to queue an URB onto the hardware rings must be called +with the xhci spinlock held. Those functions will allocate memory, and +take a gfp_t memory flags argument. We must pass them the GFP_ATOMIC +flag, since we don't want the memory allocation to attempt to sleep while +waiting for more memory to become available. + +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/xhci-hcd.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/xhci-hcd.c ++++ b/drivers/usb/host/xhci-hcd.c +@@ -601,10 +601,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd + goto exit; + } + if (usb_endpoint_xfer_control(&urb->ep->desc)) +- ret = xhci_queue_ctrl_tx(xhci, mem_flags, urb, ++ /* We have a spinlock and interrupts disabled, so we must pass ++ * atomic context to this function, which may allocate memory. ++ */ ++ ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb, + slot_id, ep_index); + else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) +- ret = xhci_queue_bulk_tx(xhci, mem_flags, urb, ++ ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, + slot_id, ep_index); + else + ret = -EINVAL; |
