From a1587d97ce3e53816c88b513a2038f6c5e5babd7 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:15 -0700 Subject: USB: xhci: Deal with stalled endpoints. 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 Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/usb/host/xhci.h') diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8936eeb5588..cde648a524f 100644 --- 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, struct urb *urb, gfp_t mem_flags); 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 *xhci, gfp_t mem_flags, struct urb *urb, 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, -- cgit v1.2.3-70-g09d2 From 8e595a5d30a5ee4bb745d4da6439d73ed7d91054 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:31 -0700 Subject: USB: xhci: Represent 64-bit addresses with one u64. 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 Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbg.c | 67 +++++++++++++++++--------------------------- 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, 137 insertions(+), 148 deletions(-) (limited to 'drivers/usb/host/xhci.h') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 56032f2d84e..6d62e4abe3c 100644 --- 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 *xhci, struct xhci_intr_reg *ir_set, int { 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, struct xhci_intr_reg *ir_set, int 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_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[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_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 *xhci, union xhci_trb *trb) 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 *xhci, union xhci_trb *trb) (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 *xhci, union xhci_trb *trb) 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 *xhci, struct xhci_segment *seg) 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, struct xhci_erst *erst) 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, struct xhci_erst *erst) 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, struct xhci_device_control *ctx, dma_ad &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); diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index ff99365cae4..e15773598e4 100644 --- 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 *xhci) 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 arg) { 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 arg) 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 arg) 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_virt_device *virt_dev) 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 *hcd, struct usb_device *udev) 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 *hcd, struct usb_device *udev) 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); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index c8a72de1c50..ec825f16dce 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -88,7 +88,7 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, 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_hcd *xhci, int slot_id) 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_hcd *xhci, int slot_id, * 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(struct xhci_hcd *xhci, struct usb_device *ud 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 *xhci, 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 *xhci, 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 *xhci) /* 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 *xhci) 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 *xhci) 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, gfp_t flags) 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, gfp_t flags) 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, gfp_t flags) (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, gfp_t flags) /* 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, gfp_t flags) /* 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); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d672ba14ff8..588686fca47 100644 --- 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 *xhci, struct xhci_ring *ring, 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_hcd *xhci) 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(struct xhci_hcd *xhci, 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(struct xhci_hcd *xhci, * 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 xhci_hcd *xhci, 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_hcd *xhci, 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_hcd *xhci, 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_hcd *xhci, gfp_t mem_flags, 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 *xhci, gfp_t mem_flags, 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_hcd *xhci, u32 trb_type, u32 slot_id) 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 xhci_hcd *xhci, dma_addr_t in_ctx_ptr, 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_hcd *xhci, int slot_id, 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/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index cde648a524f..60770c89132 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -25,6 +25,7 @@ #include #include +#include #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 xhci_hcd *xhci, 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); -- cgit v1.2.3-70-g09d2 From 66e49d8774fa03539713e8f91169c37c05df1e94 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:03:46 -0700 Subject: USB: xhci: Make debugging more verbose. Add more debugging to the irq handler, slot context initialization, ring operations, URB cancellation, and MMIO writes. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- 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(-) (limited to 'drivers/usb/host/xhci.h') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 2e8e5bf6b6c..764995fd59e 100644 --- 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, struct urb *urb, int status) 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 *hcd, struct usb_device *udev) 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 *hcd, struct usb_device *udev) 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; } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index fe9541a89a3..1fc0decfa0a 100644 --- 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 *xhci, 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 *xhci, struct xhci_ring *ring, bool consumer 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 *xhci, struct xhci_ring *ring, bool consumer { 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 *xhci, struct xhci_ring *ring, bool consumer 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_hcd *xhci) * 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_hcd *xhci, 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_hcd *xhci, /* 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_hcd *xhci, 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_hcd *xhci, 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 *xhci) 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) 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/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 60770c89132..074728e1022 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1065,10 +1065,9 @@ static inline unsigned int xhci_readl(const struct xhci_hcd *xhci, 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 xhci_hcd *xhci, 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); } -- cgit v1.2.3-70-g09d2 From 254c80a3a0eb811489f7410c3291f01a60e8e42f Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 27 Jul 2009 12:05:03 -0700 Subject: USB: xhci: Scratchpad buffer allocation 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 Acked-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 102 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 11 +++++ 2 files changed, 113 insertions(+) (limited to 'drivers/usb/host/xhci.h') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 41aca003ee8..71121d99235 100644 --- 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 *xhci, */ } +/* 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 *xhci) 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, gfp_t flags) 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/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 074728e1022..5a09b9a26e0 100644 --- 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; -- cgit v1.2.3-70-g09d2 From 28c2d2efb48dec2f0b050affae6d5787d6449e47 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:05:08 -0700 Subject: USB: xhci: Always align output device contexts to 64 bytes. 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 Signed-off-by: Greg Kroah-Hartman --- 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(-) (limited to 'drivers/usb/host/xhci.h') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 6d62e4abe3c..d77f8de1125 100644 --- 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 *xhci) 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); } diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 008326d5bc5..921dd173d79 100644 --- 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 *hcd, struct usb_device *udev) } 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 *hcd, struct usb_device *udev) 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 *hcd, struct usb_device *udev) /* 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. */ diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 71121d99235..8d6bdf2f801 100644 --- 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_hcd *xhci, int slot_id, 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_hcd *xhci, int slot_id, 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/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 5a09b9a26e0..d4d3c7777fb 100644 --- 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, 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); /* xHCI memory managment */ void xhci_mem_cleanup(struct xhci_hcd *xhci); -- cgit v1.2.3-70-g09d2 From d115b04818e57bdbc7ccde4d0660b15e33013dc8 Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 27 Jul 2009 12:05:15 -0700 Subject: USB: xhci: Support for 64-byte contexts 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 Acked-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- 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(-) (limited to 'drivers/usb/host/xhci.h') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index d77f8de1125..705e3432415 100644 --- 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 *xhci) 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); } diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 921dd173d79..057a07e876b 100644 --- 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 *hcd, struct usb_device *udev, 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 *hcd, struct usb_device *udev, } 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 *hcd, struct usb_device *udev, 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 *hcd, struct usb_device *udev, } 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 *hcd, struct usb_device *udev, 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 *hcd, struct usb_device *udev, * 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 *hcd, struct usb_device *udev, 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_virt_device *virt_dev) * 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 *hcd, struct usb_device *udev) 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 *hcd, struct usb_device *udev) 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 *hcd, struct usb_device *udev) } 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 *hcd, struct usb_device *udev) 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 *hcd, struct usb_device *udev) 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 *hcd, struct usb_device *udev) 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 *hcd, struct usb_device *udev) 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 *hcd, struct usb_device *udev) (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); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8d6bdf2f801..e6b9a1c6002 100644 --- 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_hcd *xhci, int slot_id) 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_hcd *xhci, int slot_id) 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_hcd *xhci, int slot_id, 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_hcd *xhci, int slot_id, 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(struct xhci_hcd *xhci, struct usb_device *ud 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(struct xhci_hcd *xhci, struct usb_device *ud 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(struct xhci_hcd *xhci, struct usb_device *ud 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(struct xhci_hcd *xhci, struct usb_device *ud */ 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 *xhci, 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 *xhci, 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, gfp_t flags) */ 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; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 0903e98989e..ea31753c313 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -362,6 +362,7 @@ static void find_new_dequeue_state(struct xhci_hcd *xhci, 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(struct xhci_hcd *xhci, 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(struct xhci_hcd *xhci, 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(struct xhci_hcd *xhci, 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(struct xhci_hcd *xhci, */ } 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_hcd *xhci, 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_hcd *xhci, 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_hcd *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/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index d4d3c7777fb..9c108c63270 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -446,6 +446,27 @@ struct xhci_doorbell_array { #define EPI_TO_DB(p) (((p) + 1) & 0xff) +/** + * 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 @@ -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 *xhci, struct xhci_ring *ring); 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, u16 typeReq, u16 wValue, u16 wIndex, 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 */ -- cgit v1.2.3-70-g09d2 From c92bcfa7b4038d8ffe1f02e21269f18eb0b64144 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 27 Jul 2009 12:05:21 -0700 Subject: USB: xhci: Stall handling bug fixes. 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 Signed-off-by: Greg Kroah-Hartman --- 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(-) (limited to 'drivers/usb/host/xhci.h') diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 057a07e876b..816c39caca1 100644 --- 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 *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 *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); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index ea31753c313..aa88a067148 100644 --- 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(struct xhci_hcd *xhci, 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_hcd *xhci, int slot_id, 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(struct xhci_hcd *xhci, 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(struct xhci_hcd *xhci, * 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(struct xhci_hcd *xhci, /* 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_hcd *xhci, 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_hcd *xhci, 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_hcd *xhci, 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_hcd *xhci, 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, struct xhci_ring *ep_ring, */ 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_hcd *xhci, int slot_id, 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/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 9c108c63270..d31d32206ba 100644 --- 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 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); +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, -- cgit v1.2.3-70-g09d2