From 1624ae1c19e227096ba85bfc389d9b99cb6f7dde Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 6 May 2010 13:40:08 -0700 Subject: USB: xhci: Fix issue with set interface after stall. When the USB core installs a new interface, it unconditionally clears the halts on all the endpoints on the new interface. Usually the xHCI host needs to know when an endpoint is reset, so it can change its internal endpoint state. In this case, it doesn't care, because the endpoints were never halted in the first place. To avoid issuing a redundant Reset Endpoint command, the xHCI driver looks at xhci_virt_ep->stopped_td to determine if the endpoint was actually halted. However, the functions that handle the stall never set that variable to NULL after it dealt with the stall. So if an endpoint stalled and a Reset Endpoint command completed, and then the class driver tried to install a new alternate setting, the xHCI driver would access the old xhci_virt_ep->stopped_td pointer. A similar problem occurs if the endpoint has been stopped to cancel a transfer. Signed-off-by: Sarah Sharp Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/host/xhci.c') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7e427727390..077dfcd57dc 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1438,6 +1438,8 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, kfree(virt_ep->stopped_td); xhci_ring_cmd_db(xhci); } + virt_ep->stopped_td = NULL; + virt_ep->stopped_trb = NULL; spin_unlock_irqrestore(&xhci->lock, flags); if (ret) -- cgit v1.2.3-70-g09d2 From 8df75f42f8e67e2851cdcf6da91640fb881defd1 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 2 Apr 2010 15:34:16 -0700 Subject: USB: xhci: Add memory allocation for USB3 bulk streams. Add support for allocating streams for USB 3.0 bulk endpoints. See Documentation/usb/bulk-streams.txt for more information about how and why you would use streams. When an endpoint has streams enabled, instead of having one ring where all transfers are enqueued to the hardware, it has several rings. The ring dequeue pointer in the endpoint context is changed to point to a "Stream Context Array". This is basically an array of pointers to transfer rings, one for each stream ID that the driver wants to use. The Stream Context Array size must be a power of two, and host controllers can place a limit on the size of the array (4 to 2^16 entries). These two facts make calculating the size of the Stream Context Array and the number of entries actually used by the driver a bit tricky. Besides the Stream Context Array and rings for all the stream IDs, we need one more data structure. The xHCI hardware will not tell us which stream ID a transfer event was for, but it will give us the slot ID, endpoint index, and physical address for the TRB that caused the event. For every endpoint on a device, add a radix tree to map physical TRB addresses to virtual segments within a stream ring. Keep track of whether an endpoint is transitioning to using streams, and don't enqueue any URBs while that's taking place. Refuse to transition an endpoint to streams if there are already URBs enqueued for that endpoint. We need to make sure that freeing streams does not fail, since a driver's disconnect() function may attempt to do this, and it cannot fail. Pre-allocate the command structure used to issue the Configure Endpoint command, and reserve space on the command ring for each stream endpoint. This may be a bit overkill, but it is permissible for the driver to allocate all streams in one call and free them in multiple calls. (It is not advised, however, since it is a waste of resources and time.) Even with the memory and ring room pre-allocated, freeing streams can still fail because the xHC rejects the configure endpoint command. It is valid (by the xHCI 0.96 spec) to return a "Bandwidth Error" or a "Resource Error" for a configure endpoint command. We should never see a Bandwidth Error, since bulk endpoints do not effect the reserved bandwidth. The host controller can still return a Resource Error, but it's improbable since the xHC would be going from a more resource-intensive configuration (streams) to a less resource-intensive configuration (no streams). If the xHC returns a Resource Error, the endpoint will be stuck with streams and will be unusable for drivers. It's an unavoidable consequence of broken host controller hardware. Includes bug fixes from the original patch, contributed by John Youn and Andy Green Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 379 +++++++++++++++++++++++++++++++++++++++- drivers/usb/host/xhci-ring.c | 9 +- drivers/usb/host/xhci.c | 399 ++++++++++++++++++++++++++++++++++++++++++- drivers/usb/host/xhci.h | 84 ++++++++- 4 files changed, 857 insertions(+), 14 deletions(-) (limited to 'drivers/usb/host/xhci.c') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d64f5724bfc..d299ffad806 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -304,6 +304,350 @@ struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, (ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params))); } + +/***************** Streams structures manipulation *************************/ + +void xhci_free_stream_ctx(struct xhci_hcd *xhci, + unsigned int num_stream_ctxs, + struct xhci_stream_ctx *stream_ctx, dma_addr_t dma) +{ + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) + pci_free_consistent(pdev, + sizeof(struct xhci_stream_ctx)*num_stream_ctxs, + stream_ctx, dma); + else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) + return dma_pool_free(xhci->small_streams_pool, + stream_ctx, dma); + else + return dma_pool_free(xhci->medium_streams_pool, + stream_ctx, dma); +} + +/* + * The stream context array for each endpoint with bulk streams enabled can + * vary in size, based on: + * - how many streams the endpoint supports, + * - the maximum primary stream array size the host controller supports, + * - and how many streams the device driver asks for. + * + * The stream context array must be a power of 2, and can be as small as + * 64 bytes or as large as 1MB. + */ +struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, + unsigned int num_stream_ctxs, dma_addr_t *dma, + gfp_t mem_flags) +{ + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) + return pci_alloc_consistent(pdev, + sizeof(struct xhci_stream_ctx)*num_stream_ctxs, + dma); + else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) + return dma_pool_alloc(xhci->small_streams_pool, + mem_flags, dma); + else + return dma_pool_alloc(xhci->medium_streams_pool, + mem_flags, dma); +} + +#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING +struct xhci_ring *dma_to_stream_ring( + struct xhci_stream_info *stream_info, + u64 address) +{ + return radix_tree_lookup(&stream_info->trb_address_map, + address >> SEGMENT_SHIFT); +} +#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */ + +#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING +static int xhci_test_radix_tree(struct xhci_hcd *xhci, + unsigned int num_streams, + struct xhci_stream_info *stream_info) +{ + u32 cur_stream; + struct xhci_ring *cur_ring; + u64 addr; + + for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { + struct xhci_ring *mapped_ring; + int trb_size = sizeof(union xhci_trb); + + cur_ring = stream_info->stream_rings[cur_stream]; + for (addr = cur_ring->first_seg->dma; + addr < cur_ring->first_seg->dma + SEGMENT_SIZE; + addr += trb_size) { + mapped_ring = dma_to_stream_ring(stream_info, addr); + if (cur_ring != mapped_ring) { + xhci_warn(xhci, "WARN: DMA address 0x%08llx " + "didn't map to stream ID %u; " + "mapped to ring %p\n", + (unsigned long long) addr, + cur_stream, + mapped_ring); + return -EINVAL; + } + } + /* One TRB after the end of the ring segment shouldn't return a + * pointer to the current ring (although it may be a part of a + * different ring). + */ + mapped_ring = dma_to_stream_ring(stream_info, addr); + if (mapped_ring != cur_ring) { + /* One TRB before should also fail */ + addr = cur_ring->first_seg->dma - trb_size; + mapped_ring = dma_to_stream_ring(stream_info, addr); + } + if (mapped_ring == cur_ring) { + xhci_warn(xhci, "WARN: Bad DMA address 0x%08llx " + "mapped to valid stream ID %u; " + "mapped ring = %p\n", + (unsigned long long) addr, + cur_stream, + mapped_ring); + return -EINVAL; + } + } + return 0; +} +#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */ + +/* + * Change an endpoint's internal structure so it supports stream IDs. The + * number of requested streams includes stream 0, which cannot be used by device + * drivers. + * + * The number of stream contexts in the stream context array may be bigger than + * the number of streams the driver wants to use. This is because the number of + * stream context array entries must be a power of two. + * + * We need a radix tree for mapping physical addresses of TRBs to which stream + * ID they belong to. We need to do this because the host controller won't tell + * us which stream ring the TRB came from. We could store the stream ID in an + * event data TRB, but that doesn't help us for the cancellation case, since the + * endpoint may stop before it reaches that event data TRB. + * + * The radix tree maps the upper portion of the TRB DMA address to a ring + * segment that has the same upper portion of DMA addresses. For example, say I + * have segments of size 1KB, that are always 64-byte aligned. A segment may + * start at 0x10c91000 and end at 0x10c913f0. If I use the upper 10 bits, the + * key to the stream ID is 0x43244. I can use the DMA address of the TRB to + * pass the radix tree a key to get the right stream ID: + * + * 0x10c90fff >> 10 = 0x43243 + * 0x10c912c0 >> 10 = 0x43244 + * 0x10c91400 >> 10 = 0x43245 + * + * Obviously, only those TRBs with DMA addresses that are within the segment + * will make the radix tree return the stream ID for that ring. + * + * Caveats for the radix tree: + * + * The radix tree uses an unsigned long as a key pair. On 32-bit systems, an + * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be + * 64-bits. Since we only request 32-bit DMA addresses, we can use that as the + * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit + * PCI DMA addresses on a 64-bit system). There might be a problem on 32-bit + * extended systems (where the DMA address can be bigger than 32-bits), + * if we allow the PCI dma mask to be bigger than 32-bits. So don't do that. + */ +struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, + unsigned int num_stream_ctxs, + unsigned int num_streams, gfp_t mem_flags) +{ + struct xhci_stream_info *stream_info; + u32 cur_stream; + struct xhci_ring *cur_ring; + unsigned long key; + u64 addr; + int ret; + + xhci_dbg(xhci, "Allocating %u streams and %u " + "stream context array entries.\n", + num_streams, num_stream_ctxs); + if (xhci->cmd_ring_reserved_trbs == MAX_RSVD_CMD_TRBS) { + xhci_dbg(xhci, "Command ring has no reserved TRBs available\n"); + return NULL; + } + xhci->cmd_ring_reserved_trbs++; + + stream_info = kzalloc(sizeof(struct xhci_stream_info), mem_flags); + if (!stream_info) + goto cleanup_trbs; + + stream_info->num_streams = num_streams; + stream_info->num_stream_ctxs = num_stream_ctxs; + + /* Initialize the array of virtual pointers to stream rings. */ + stream_info->stream_rings = kzalloc( + sizeof(struct xhci_ring *)*num_streams, + mem_flags); + if (!stream_info->stream_rings) + goto cleanup_info; + + /* Initialize the array of DMA addresses for stream rings for the HW. */ + stream_info->stream_ctx_array = xhci_alloc_stream_ctx(xhci, + num_stream_ctxs, &stream_info->ctx_array_dma, + mem_flags); + if (!stream_info->stream_ctx_array) + goto cleanup_ctx; + memset(stream_info->stream_ctx_array, 0, + sizeof(struct xhci_stream_ctx)*num_stream_ctxs); + + /* Allocate everything needed to free the stream rings later */ + stream_info->free_streams_command = + xhci_alloc_command(xhci, true, true, mem_flags); + if (!stream_info->free_streams_command) + goto cleanup_ctx; + + INIT_RADIX_TREE(&stream_info->trb_address_map, GFP_ATOMIC); + + /* Allocate rings for all the streams that the driver will use, + * and add their segment DMA addresses to the radix tree. + * Stream 0 is reserved. + */ + for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { + stream_info->stream_rings[cur_stream] = + xhci_ring_alloc(xhci, 1, true, mem_flags); + cur_ring = stream_info->stream_rings[cur_stream]; + if (!cur_ring) + goto cleanup_rings; + /* Set deq ptr, cycle bit, and stream context type */ + addr = cur_ring->first_seg->dma | + SCT_FOR_CTX(SCT_PRI_TR) | + cur_ring->cycle_state; + stream_info->stream_ctx_array[cur_stream].stream_ring = addr; + xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", + cur_stream, (unsigned long long) addr); + + key = (unsigned long) + (cur_ring->first_seg->dma >> SEGMENT_SHIFT); + ret = radix_tree_insert(&stream_info->trb_address_map, + key, cur_ring); + if (ret) { + xhci_ring_free(xhci, cur_ring); + stream_info->stream_rings[cur_stream] = NULL; + goto cleanup_rings; + } + } + /* Leave the other unused stream ring pointers in the stream context + * array initialized to zero. This will cause the xHC to give us an + * error if the device asks for a stream ID we don't have setup (if it + * was any other way, the host controller would assume the ring is + * "empty" and wait forever for data to be queued to that stream ID). + */ +#if XHCI_DEBUG + /* Do a little test on the radix tree to make sure it returns the + * correct values. + */ + if (xhci_test_radix_tree(xhci, num_streams, stream_info)) + goto cleanup_rings; +#endif + + return stream_info; + +cleanup_rings: + for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { + cur_ring = stream_info->stream_rings[cur_stream]; + if (cur_ring) { + addr = cur_ring->first_seg->dma; + radix_tree_delete(&stream_info->trb_address_map, + addr >> SEGMENT_SHIFT); + xhci_ring_free(xhci, cur_ring); + stream_info->stream_rings[cur_stream] = NULL; + } + } + xhci_free_command(xhci, stream_info->free_streams_command); +cleanup_ctx: + kfree(stream_info->stream_rings); +cleanup_info: + kfree(stream_info); +cleanup_trbs: + xhci->cmd_ring_reserved_trbs--; + return NULL; +} +/* + * Sets the MaxPStreams field and the Linear Stream Array field. + * Sets the dequeue pointer to the stream context array. + */ +void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci, + struct xhci_ep_ctx *ep_ctx, + struct xhci_stream_info *stream_info) +{ + u32 max_primary_streams; + /* MaxPStreams is the number of stream context array entries, not the + * number we're actually using. Must be in 2^(MaxPstreams + 1) format. + * fls(0) = 0, fls(0x1) = 1, fls(0x10) = 2, fls(0x100) = 3, etc. + */ + max_primary_streams = fls(stream_info->num_stream_ctxs) - 2; + xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n", + 1 << (max_primary_streams + 1)); + ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK; + ep_ctx->ep_info |= EP_MAXPSTREAMS(max_primary_streams); + ep_ctx->ep_info |= EP_HAS_LSA; + ep_ctx->deq = stream_info->ctx_array_dma; +} + +/* + * Sets the MaxPStreams field and the Linear Stream Array field to 0. + * Reinstalls the "normal" endpoint ring (at its previous dequeue mark, + * not at the beginning of the ring). + */ +void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci, + struct xhci_ep_ctx *ep_ctx, + struct xhci_virt_ep *ep) +{ + dma_addr_t addr; + ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK; + ep_ctx->ep_info &= ~EP_HAS_LSA; + addr = xhci_trb_virt_to_dma(ep->ring->deq_seg, ep->ring->dequeue); + ep_ctx->deq = addr | ep->ring->cycle_state; +} + +/* Frees all stream contexts associated with the endpoint, + * + * Caller should fix the endpoint context streams fields. + */ +void xhci_free_stream_info(struct xhci_hcd *xhci, + struct xhci_stream_info *stream_info) +{ + int cur_stream; + struct xhci_ring *cur_ring; + dma_addr_t addr; + + if (!stream_info) + return; + + for (cur_stream = 1; cur_stream < stream_info->num_streams; + cur_stream++) { + cur_ring = stream_info->stream_rings[cur_stream]; + if (cur_ring) { + addr = cur_ring->first_seg->dma; + radix_tree_delete(&stream_info->trb_address_map, + addr >> SEGMENT_SHIFT); + xhci_ring_free(xhci, cur_ring); + stream_info->stream_rings[cur_stream] = NULL; + } + } + xhci_free_command(xhci, stream_info->free_streams_command); + xhci->cmd_ring_reserved_trbs--; + if (stream_info->stream_ctx_array) + xhci_free_stream_ctx(xhci, + stream_info->num_stream_ctxs, + stream_info->stream_ctx_array, + stream_info->ctx_array_dma); + + if (stream_info) + kfree(stream_info->stream_rings); + kfree(stream_info); +} + + +/***************** Device context manipulation *************************/ + static void xhci_init_endpoint_timer(struct xhci_hcd *xhci, struct xhci_virt_ep *ep) { @@ -328,9 +672,13 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) if (!dev) return; - for (i = 0; i < 31; ++i) + for (i = 0; i < 31; ++i) { if (dev->eps[i].ring) xhci_ring_free(xhci, dev->eps[i].ring); + if (dev->eps[i].stream_info) + xhci_free_stream_info(xhci, + dev->eps[i].stream_info); + } if (dev->ring_cache) { for (i = 0; i < dev->num_rings_cached; i++) @@ -655,6 +1003,9 @@ static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci, return max_packet * (max_burst + 1); } +/* Set up an endpoint with one ring segment. Do not allocate stream rings. + * Drivers will have to call usb_alloc_streams() to do that. + */ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_device *udev, @@ -1003,6 +1354,16 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->device_pool = NULL; xhci_dbg(xhci, "Freed device context pool\n"); + if (xhci->small_streams_pool) + dma_pool_destroy(xhci->small_streams_pool); + xhci->small_streams_pool = NULL; + xhci_dbg(xhci, "Freed small stream array pool\n"); + + if (xhci->medium_streams_pool) + dma_pool_destroy(xhci->medium_streams_pool); + xhci->medium_streams_pool = NULL; + xhci_dbg(xhci, "Freed medium stream array pool\n"); + xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr); if (xhci->dcbaa) pci_free_consistent(pdev, sizeof(*xhci->dcbaa), @@ -1239,6 +1600,22 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) if (!xhci->segment_pool || !xhci->device_pool) goto fail; + /* Linear stream context arrays don't have any boundary restrictions, + * and only need to be 16-byte aligned. + */ + xhci->small_streams_pool = + dma_pool_create("xHCI 256 byte stream ctx arrays", + dev, SMALL_STREAM_ARRAY_SIZE, 16, 0); + xhci->medium_streams_pool = + dma_pool_create("xHCI 1KB stream ctx arrays", + dev, MEDIUM_STREAM_ARRAY_SIZE, 16, 0); + /* Any stream context array bigger than MEDIUM_STREAM_ARRAY_SIZE + * will be allocated with pci_alloc_consistent() + */ + + if (!xhci->small_streams_pool || !xhci->medium_streams_pool) + goto fail; + /* Set up the command ring to have one segments for now. */ xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags); if (!xhci->cmd_ring) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index c1359ed310b..a14f657e279 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -323,6 +323,10 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci, ep_state = ep->ep_state; /* Don't ring the doorbell for this endpoint if there are pending * cancellations because the we don't want to interrupt processing. + * We don't want to restart any stream rings if there's a set dequeue + * pointer command pending because the device can choose to start any + * stream once the endpoint is on the HW schedule. + * FIXME - check all the stream rings for pending cancellations. */ if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING) && !(ep_state & EP_HALTED)) { @@ -916,8 +920,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, * Configure endpoint commands can come from the USB core * configuration or alt setting changes, or because the HW * needed an extra configure endpoint command after a reset - * endpoint command. In the latter case, the xHCI driver is - * not waiting on the configure endpoint command. + * endpoint command or streams were being configured. + * If the command was for a halted endpoint, the xHCI driver + * is not waiting on the configure endpoint command. */ ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 077dfcd57dc..2e370fea959 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -726,8 +727,21 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) spin_lock_irqsave(&xhci->lock, flags); if (xhci->xhc_state & XHCI_STATE_DYING) goto dying; - ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, - slot_id, ep_index); + if (xhci->devs[slot_id]->eps[ep_index].ep_state & + EP_GETTING_STREAMS) { + xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep " + "is transitioning to using streams.\n"); + ret = -EINVAL; + } else if (xhci->devs[slot_id]->eps[ep_index].ep_state & + EP_GETTING_NO_STREAMS) { + xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep " + "is transitioning to " + "not having streams.\n"); + ret = -EINVAL; + } else { + ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, + slot_id, ep_index); + } spin_unlock_irqrestore(&xhci->lock, flags); } else if (usb_endpoint_xfer_int(&urb->ep->desc)) { spin_lock_irqsave(&xhci->lock, flags); @@ -1446,6 +1460,387 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, xhci_warn(xhci, "FIXME allocate a new ring segment\n"); } +static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, + struct usb_device *udev, struct usb_host_endpoint *ep, + unsigned int slot_id) +{ + int ret; + unsigned int ep_index; + unsigned int ep_state; + + if (!ep) + return -EINVAL; + ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, __func__); + if (ret <= 0) + return -EINVAL; + if (!ep->ss_ep_comp) { + xhci_warn(xhci, "WARN: No SuperSpeed Endpoint Companion" + " descriptor for ep 0x%x\n", + ep->desc.bEndpointAddress); + return -EINVAL; + } + if (ep->ss_ep_comp->desc.bmAttributes == 0) { + xhci_warn(xhci, "WARN: SuperSpeed Endpoint Companion" + " descriptor for ep 0x%x does not support streams\n", + ep->desc.bEndpointAddress); + return -EINVAL; + } + + ep_index = xhci_get_endpoint_index(&ep->desc); + ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; + if (ep_state & EP_HAS_STREAMS || + ep_state & EP_GETTING_STREAMS) { + xhci_warn(xhci, "WARN: SuperSpeed bulk endpoint 0x%x " + "already has streams set up.\n", + ep->desc.bEndpointAddress); + xhci_warn(xhci, "Send email to xHCI maintainer and ask for " + "dynamic stream context array reallocation.\n"); + return -EINVAL; + } + if (!list_empty(&xhci->devs[slot_id]->eps[ep_index].ring->td_list)) { + xhci_warn(xhci, "Cannot setup streams for SuperSpeed bulk " + "endpoint 0x%x; URBs are pending.\n", + ep->desc.bEndpointAddress); + return -EINVAL; + } + return 0; +} + +static void xhci_calculate_streams_entries(struct xhci_hcd *xhci, + unsigned int *num_streams, unsigned int *num_stream_ctxs) +{ + unsigned int max_streams; + + /* The stream context array size must be a power of two */ + *num_stream_ctxs = roundup_pow_of_two(*num_streams); + /* + * Find out how many primary stream array entries the host controller + * supports. Later we may use secondary stream arrays (similar to 2nd + * level page entries), but that's an optional feature for xHCI host + * controllers. xHCs must support at least 4 stream IDs. + */ + max_streams = HCC_MAX_PSA(xhci->hcc_params); + if (*num_stream_ctxs > max_streams) { + xhci_dbg(xhci, "xHCI HW only supports %u stream ctx entries.\n", + max_streams); + *num_stream_ctxs = max_streams; + *num_streams = max_streams; + } +} + +/* Returns an error code if one of the endpoint already has streams. + * This does not change any data structures, it only checks and gathers + * information. + */ +static int xhci_calculate_streams_and_bitmask(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps, + unsigned int *num_streams, u32 *changed_ep_bitmask) +{ + struct usb_host_ss_ep_comp *ss_ep_comp; + unsigned int max_streams; + unsigned int endpoint_flag; + int i; + int ret; + + for (i = 0; i < num_eps; i++) { + ret = xhci_check_streams_endpoint(xhci, udev, + eps[i], udev->slot_id); + if (ret < 0) + return ret; + + ss_ep_comp = eps[i]->ss_ep_comp; + max_streams = USB_SS_MAX_STREAMS(ss_ep_comp->desc.bmAttributes); + if (max_streams < (*num_streams - 1)) { + xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n", + eps[i]->desc.bEndpointAddress, + max_streams); + *num_streams = max_streams+1; + } + + endpoint_flag = xhci_get_endpoint_flag(&eps[i]->desc); + if (*changed_ep_bitmask & endpoint_flag) + return -EINVAL; + *changed_ep_bitmask |= endpoint_flag; + } + return 0; +} + +static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps) +{ + u32 changed_ep_bitmask = 0; + unsigned int slot_id; + unsigned int ep_index; + unsigned int ep_state; + int i; + + slot_id = udev->slot_id; + if (!xhci->devs[slot_id]) + return 0; + + for (i = 0; i < num_eps; i++) { + ep_index = xhci_get_endpoint_index(&eps[i]->desc); + ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; + /* Are streams already being freed for the endpoint? */ + if (ep_state & EP_GETTING_NO_STREAMS) { + xhci_warn(xhci, "WARN Can't disable streams for " + "endpoint 0x%x\n, " + "streams are being disabled already.", + eps[i]->desc.bEndpointAddress); + return 0; + } + /* Are there actually any streams to free? */ + if (!(ep_state & EP_HAS_STREAMS) && + !(ep_state & EP_GETTING_STREAMS)) { + xhci_warn(xhci, "WARN Can't disable streams for " + "endpoint 0x%x\n, " + "streams are already disabled!", + eps[i]->desc.bEndpointAddress); + xhci_warn(xhci, "WARN xhci_free_streams() called " + "with non-streams endpoint\n"); + return 0; + } + changed_ep_bitmask |= xhci_get_endpoint_flag(&eps[i]->desc); + } + return changed_ep_bitmask; +} + +/* + * The USB device drivers use this function (though the HCD interface in USB + * core) to prepare a set of bulk endpoints to use streams. Streams are used to + * coordinate mass storage command queueing across multiple endpoints (basically + * a stream ID == a task ID). + * + * Setting up streams involves allocating the same size stream context array + * for each endpoint and issuing a configure endpoint command for all endpoints. + * + * Don't allow the call to succeed if one endpoint only supports one stream + * (which means it doesn't support streams at all). + * + * Drivers may get less stream IDs than they asked for, if the host controller + * hardware or endpoints claim they can't support the number of requested + * stream IDs. + */ +int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps, + unsigned int num_streams, gfp_t mem_flags) +{ + int i, ret; + struct xhci_hcd *xhci; + struct xhci_virt_device *vdev; + struct xhci_command *config_cmd; + unsigned int ep_index; + unsigned int num_stream_ctxs; + unsigned long flags; + u32 changed_ep_bitmask = 0; + + if (!eps) + return -EINVAL; + + /* Add one to the number of streams requested to account for + * stream 0 that is reserved for xHCI usage. + */ + num_streams += 1; + xhci = hcd_to_xhci(hcd); + xhci_dbg(xhci, "Driver wants %u stream IDs (including stream 0).\n", + num_streams); + + config_cmd = xhci_alloc_command(xhci, true, true, mem_flags); + if (!config_cmd) { + xhci_dbg(xhci, "Could not allocate xHCI command structure.\n"); + return -ENOMEM; + } + + /* Check to make sure all endpoints are not already configured for + * streams. While we're at it, find the maximum number of streams that + * all the endpoints will support and check for duplicate endpoints. + */ + spin_lock_irqsave(&xhci->lock, flags); + ret = xhci_calculate_streams_and_bitmask(xhci, udev, eps, + num_eps, &num_streams, &changed_ep_bitmask); + if (ret < 0) { + xhci_free_command(xhci, config_cmd); + spin_unlock_irqrestore(&xhci->lock, flags); + return ret; + } + if (num_streams <= 1) { + xhci_warn(xhci, "WARN: endpoints can't handle " + "more than one stream.\n"); + xhci_free_command(xhci, config_cmd); + spin_unlock_irqrestore(&xhci->lock, flags); + return -EINVAL; + } + vdev = xhci->devs[udev->slot_id]; + /* Mark each endpoint as being in transistion, so + * xhci_urb_enqueue() will reject all URBs. + */ + for (i = 0; i < num_eps; i++) { + ep_index = xhci_get_endpoint_index(&eps[i]->desc); + vdev->eps[ep_index].ep_state |= EP_GETTING_STREAMS; + } + spin_unlock_irqrestore(&xhci->lock, flags); + + /* Setup internal data structures and allocate HW data structures for + * streams (but don't install the HW structures in the input context + * until we're sure all memory allocation succeeded). + */ + xhci_calculate_streams_entries(xhci, &num_streams, &num_stream_ctxs); + xhci_dbg(xhci, "Need %u stream ctx entries for %u stream IDs.\n", + num_stream_ctxs, num_streams); + + for (i = 0; i < num_eps; i++) { + ep_index = xhci_get_endpoint_index(&eps[i]->desc); + vdev->eps[ep_index].stream_info = xhci_alloc_stream_info(xhci, + num_stream_ctxs, + num_streams, mem_flags); + if (!vdev->eps[ep_index].stream_info) + goto cleanup; + /* Set maxPstreams in endpoint context and update deq ptr to + * point to stream context array. FIXME + */ + } + + /* Set up the input context for a configure endpoint command. */ + for (i = 0; i < num_eps; i++) { + struct xhci_ep_ctx *ep_ctx; + + ep_index = xhci_get_endpoint_index(&eps[i]->desc); + ep_ctx = xhci_get_ep_ctx(xhci, config_cmd->in_ctx, ep_index); + + xhci_endpoint_copy(xhci, config_cmd->in_ctx, + vdev->out_ctx, ep_index); + xhci_setup_streams_ep_input_ctx(xhci, ep_ctx, + vdev->eps[ep_index].stream_info); + } + /* Tell the HW to drop its old copy of the endpoint context info + * and add the updated copy from the input context. + */ + xhci_setup_input_ctx_for_config_ep(xhci, config_cmd->in_ctx, + vdev->out_ctx, changed_ep_bitmask, changed_ep_bitmask); + + /* Issue and wait for the configure endpoint command */ + ret = xhci_configure_endpoint(xhci, udev, config_cmd, + false, false); + + /* xHC rejected the configure endpoint command for some reason, so we + * leave the old ring intact and free our internal streams data + * structure. + */ + if (ret < 0) + goto cleanup; + + spin_lock_irqsave(&xhci->lock, flags); + for (i = 0; i < num_eps; i++) { + ep_index = xhci_get_endpoint_index(&eps[i]->desc); + vdev->eps[ep_index].ep_state &= ~EP_GETTING_STREAMS; + xhci_dbg(xhci, "Slot %u ep ctx %u now has streams.\n", + udev->slot_id, ep_index); + vdev->eps[ep_index].ep_state |= EP_HAS_STREAMS; + } + xhci_free_command(xhci, config_cmd); + spin_unlock_irqrestore(&xhci->lock, flags); + + /* Subtract 1 for stream 0, which drivers can't use */ + return num_streams - 1; + +cleanup: + /* If it didn't work, free the streams! */ + for (i = 0; i < num_eps; i++) { + ep_index = xhci_get_endpoint_index(&eps[i]->desc); + xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info); + /* FIXME Unset maxPstreams in endpoint context and + * update deq ptr to point to normal string ring. + */ + vdev->eps[ep_index].ep_state &= ~EP_GETTING_STREAMS; + vdev->eps[ep_index].ep_state &= ~EP_HAS_STREAMS; + xhci_endpoint_zero(xhci, vdev, eps[i]); + } + xhci_free_command(xhci, config_cmd); + return -ENOMEM; +} + +/* Transition the endpoint from using streams to being a "normal" endpoint + * without streams. + * + * Modify the endpoint context state, submit a configure endpoint command, + * and free all endpoint rings for streams if that completes successfully. + */ +int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps, + gfp_t mem_flags) +{ + int i, ret; + struct xhci_hcd *xhci; + struct xhci_virt_device *vdev; + struct xhci_command *command; + unsigned int ep_index; + unsigned long flags; + u32 changed_ep_bitmask; + + xhci = hcd_to_xhci(hcd); + vdev = xhci->devs[udev->slot_id]; + + /* Set up a configure endpoint command to remove the streams rings */ + spin_lock_irqsave(&xhci->lock, flags); + changed_ep_bitmask = xhci_calculate_no_streams_bitmask(xhci, + udev, eps, num_eps); + if (changed_ep_bitmask == 0) { + spin_unlock_irqrestore(&xhci->lock, flags); + return -EINVAL; + } + + /* Use the xhci_command structure from the first endpoint. We may have + * allocated too many, but the driver may call xhci_free_streams() for + * each endpoint it grouped into one call to xhci_alloc_streams(). + */ + ep_index = xhci_get_endpoint_index(&eps[0]->desc); + command = vdev->eps[ep_index].stream_info->free_streams_command; + for (i = 0; i < num_eps; i++) { + struct xhci_ep_ctx *ep_ctx; + + ep_index = xhci_get_endpoint_index(&eps[i]->desc); + ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, ep_index); + xhci->devs[udev->slot_id]->eps[ep_index].ep_state |= + EP_GETTING_NO_STREAMS; + + xhci_endpoint_copy(xhci, command->in_ctx, + vdev->out_ctx, ep_index); + xhci_setup_no_streams_ep_input_ctx(xhci, ep_ctx, + &vdev->eps[ep_index]); + } + xhci_setup_input_ctx_for_config_ep(xhci, command->in_ctx, + vdev->out_ctx, changed_ep_bitmask, changed_ep_bitmask); + spin_unlock_irqrestore(&xhci->lock, flags); + + /* Issue and wait for the configure endpoint command, + * which must succeed. + */ + ret = xhci_configure_endpoint(xhci, udev, command, + false, true); + + /* xHC rejected the configure endpoint command for some reason, so we + * leave the streams rings intact. + */ + if (ret < 0) + return ret; + + spin_lock_irqsave(&xhci->lock, flags); + for (i = 0; i < num_eps; i++) { + ep_index = xhci_get_endpoint_index(&eps[i]->desc); + xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info); + /* FIXME Unset maxPstreams in endpoint context and + * update deq ptr to point to normal string ring. + */ + vdev->eps[ep_index].ep_state &= ~EP_GETTING_NO_STREAMS; + vdev->eps[ep_index].ep_state &= ~EP_HAS_STREAMS; + } + spin_unlock_irqrestore(&xhci->lock, flags); + + return 0; +} + /* * This submits a Reset Device Command, which will set the device state to 0, * set the device address to 0, and disable all the endpoints except the default diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a7c4e112290..7a9447cb6ea 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -117,7 +117,7 @@ struct xhci_cap_regs { /* true: no secondary Stream ID Support */ #define HCC_NSS(p) ((p) & (1 << 7)) /* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */ -#define HCC_MAX_PSA (1 << ((((p) >> 12) & 0xf) + 1)) +#define HCC_MAX_PSA(p) (1 << ((((p) >> 12) & 0xf) + 1)) /* Extended Capabilities pointer from PCI base - section 5.3.6 */ #define HCC_EXT_CAPS(p) XHCI_HCC_EXT_CAPS(p) @@ -585,6 +585,10 @@ struct xhci_ep_ctx { /* Interval - period between requests to an endpoint - 125u increments. */ #define EP_INTERVAL(p) ((p & 0xff) << 16) #define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff)) +#define EP_MAXPSTREAMS_MASK (0x1f << 10) +#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK) +/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */ +#define EP_HAS_LSA (1 << 15) /* ep_info2 bitmasks */ /* @@ -648,8 +652,50 @@ struct xhci_command { /* add context bitmasks */ #define ADD_EP(x) (0x1 << x) +struct xhci_stream_ctx { + /* 64-bit stream ring address, cycle state, and stream type */ + u64 stream_ring; + /* offset 0x14 - 0x1f reserved for HC internal use */ + u32 reserved[2]; +}; + +/* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */ +#define SCT_FOR_CTX(p) (((p) << 1) & 0x7) +/* Secondary stream array type, dequeue pointer is to a transfer ring */ +#define SCT_SEC_TR 0 +/* Primary stream array type, dequeue pointer is to a transfer ring */ +#define SCT_PRI_TR 1 +/* Dequeue pointer is for a secondary stream array (SSA) with 8 entries */ +#define SCT_SSA_8 2 +#define SCT_SSA_16 3 +#define SCT_SSA_32 4 +#define SCT_SSA_64 5 +#define SCT_SSA_128 6 +#define SCT_SSA_256 7 + +/* Assume no secondary streams for now */ +struct xhci_stream_info { + struct xhci_ring **stream_rings; + /* Number of streams, including stream 0 (which drivers can't use) */ + unsigned int num_streams; + /* The stream context array may be bigger than + * the number of streams the driver asked for + */ + struct xhci_stream_ctx *stream_ctx_array; + unsigned int num_stream_ctxs; + dma_addr_t ctx_array_dma; + /* For mapping physical TRB addresses to segments in stream rings */ + struct radix_tree_root trb_address_map; + struct xhci_command *free_streams_command; +}; + +#define SMALL_STREAM_ARRAY_SIZE 256 +#define MEDIUM_STREAM_ARRAY_SIZE 1024 + struct xhci_virt_ep { struct xhci_ring *ring; + /* Related to endpoints that are configured to use stream IDs only */ + struct xhci_stream_info *stream_info; /* Temporary storage in case the configure endpoint command fails and we * have to restore the device state to the previous state */ @@ -658,6 +704,11 @@ struct xhci_virt_ep { #define SET_DEQ_PENDING (1 << 0) #define EP_HALTED (1 << 1) /* For stall handling */ #define EP_HALT_PENDING (1 << 2) /* For URB cancellation */ +/* Transitioning the endpoint to using streams, don't enqueue URBs */ +#define EP_GETTING_STREAMS (1 << 3) +#define EP_HAS_STREAMS (1 << 4) +/* Transitioning the endpoint to not using streams, don't enqueue URBs */ +#define EP_GETTING_NO_STREAMS (1 << 5) /* ---- Related to URB cancellation ---- */ struct list_head cancelled_td_list; /* The TRB that was last reported in a stopped endpoint ring */ @@ -710,14 +761,6 @@ struct xhci_device_context_array { */ -struct xhci_stream_ctx { - /* 64-bit stream ring address, cycle state, and stream type */ - u64 stream_ring; - /* offset 0x14 - 0x1f reserved for HC internal use */ - u32 reserved[2]; -}; - - struct xhci_transfer_event { /* 64-bit buffer address, or immediate data */ u64 buffer; @@ -952,6 +995,10 @@ union xhci_trb { /* Allow two commands + a link TRB, along with any reserved command TRBs */ #define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3) #define SEGMENT_SIZE (TRBS_PER_SEGMENT*16) +/* SEGMENT_SHIFT should be log2(SEGMENT_SIZE). + * Change this if you change TRBS_PER_SEGMENT! + */ +#define SEGMENT_SHIFT 10 /* TRB buffer pointers can't cross 64KB boundaries */ #define TRB_MAX_BUFF_SHIFT 16 #define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) @@ -1088,6 +1135,8 @@ struct xhci_hcd { /* DMA pools */ struct dma_pool *device_pool; struct dma_pool *segment_pool; + struct dma_pool *small_streams_pool; + struct dma_pool *medium_streams_pool; #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING /* Poll the rings - for debugging */ @@ -1242,6 +1291,17 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, unsigned int ep_index); +struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, + unsigned int num_stream_ctxs, + unsigned int num_streams, gfp_t flags); +void xhci_free_stream_info(struct xhci_hcd *xhci, + struct xhci_stream_info *stream_info); +void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci, + struct xhci_ep_ctx *ep_ctx, + struct xhci_stream_info *stream_info); +void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci, + struct xhci_ep_ctx *ep_ctx, + struct xhci_virt_ep *ep); struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, bool allocate_in_ctx, bool allocate_completion, gfp_t mem_flags); @@ -1266,6 +1326,12 @@ int xhci_get_frame(struct usb_hcd *hcd); irqreturn_t xhci_irq(struct usb_hcd *hcd); int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); +int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps, + unsigned int num_streams, gfp_t mem_flags); +int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint **eps, unsigned int num_eps, + gfp_t mem_flags); int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags); -- cgit v1.2.3-70-g09d2 From e9df17eb1408cfafa3d1844bfc7f22c7237b31b8 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 2 Apr 2010 15:34:43 -0700 Subject: USB: xhci: Correct assumptions about number of rings per endpoint. Much of the xHCI driver code assumes that endpoints only have one ring. Now an endpoint can have one ring per enabled stream ID, so correct that assumption. Use functions that translate the stream_id field in the URB or the DMA address of a TRB into the correct stream ring. Correct the polling loop to print out all enabled stream rings. Make the URB cancellation routine find the correct stream ring if the URB has stream_id set. Make sure the URB enqueueing routine does the same. Also correct the code that handles stalled/halted endpoints. Check that commands and registers that can take stream IDs handle them properly. That includes ringing an endpoint doorbell, resetting a stalled/halted endpoint, and setting a transfer ring dequeue pointer (since that command can set the dequeue pointer in a stream context or an endpoint context). Correct the transfer event handler to translate a TRB DMA address into the stream ring it was enqueued to. Make the code to allocate and prepare TD structures adds the TD to the right td_list for the stream ring. Make sure the code to give the first TRB in a TD to the hardware manipulates the correct stream ring. When an endpoint stalls, store the stream ID of the stream ring that stalled in the xhci_virt_ep structure. Use that instead of the stream ID in the URB, since an URB may be re-used after it is given back after a non-control endpoint stall. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbg.c | 24 ++++++ drivers/usb/host/xhci-mem.c | 74 ++++++++++++++++- drivers/usb/host/xhci-ring.c | 192 +++++++++++++++++++++++++++++++++---------- drivers/usb/host/xhci.c | 19 +++-- drivers/usb/host/xhci.h | 26 +++++- 5 files changed, 280 insertions(+), 55 deletions(-) (limited to 'drivers/usb/host/xhci.c') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 105fa8b025b..fcbf4abbf38 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -364,6 +364,30 @@ void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring) xhci_debug_segment(xhci, seg); } +void xhci_dbg_ep_rings(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, + struct xhci_virt_ep *ep) +{ + int i; + struct xhci_ring *ring; + + if (ep->ep_state & EP_HAS_STREAMS) { + for (i = 1; i < ep->stream_info->num_streams; i++) { + ring = ep->stream_info->stream_rings[i]; + xhci_dbg(xhci, "Dev %d endpoint %d stream ID %d:\n", + slot_id, ep_index, i); + xhci_debug_segment(xhci, ring->deq_seg); + } + } else { + ring = ep->ring; + if (!ring) + return; + xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", + slot_id, ep_index); + xhci_debug_segment(xhci, ring->deq_seg); + } +} + void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) { u32 addr = (u32) erst->erst_dma_addr; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d299ffad806..5711048708d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -353,8 +353,19 @@ struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, mem_flags, dma); } +struct xhci_ring *xhci_dma_to_transfer_ring( + struct xhci_virt_ep *ep, + u64 address) +{ + if (ep->ep_state & EP_HAS_STREAMS) + return radix_tree_lookup(&ep->stream_info->trb_address_map, + address >> SEGMENT_SHIFT); + return ep->ring; +} + +/* Only use this when you know stream_info is valid */ #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -struct xhci_ring *dma_to_stream_ring( +static struct xhci_ring *dma_to_stream_ring( struct xhci_stream_info *stream_info, u64 address) { @@ -363,6 +374,66 @@ struct xhci_ring *dma_to_stream_ring( } #endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */ +struct xhci_ring *xhci_stream_id_to_ring( + struct xhci_virt_device *dev, + unsigned int ep_index, + unsigned int stream_id) +{ + struct xhci_virt_ep *ep = &dev->eps[ep_index]; + + if (stream_id == 0) + return ep->ring; + if (!ep->stream_info) + return NULL; + + if (stream_id > ep->stream_info->num_streams) + return NULL; + return ep->stream_info->stream_rings[stream_id]; +} + +struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, + unsigned int stream_id) +{ + struct xhci_virt_ep *ep; + + ep = &xhci->devs[slot_id]->eps[ep_index]; + /* Common case: no streams */ + if (!(ep->ep_state & EP_HAS_STREAMS)) + return ep->ring; + + if (stream_id == 0) { + xhci_warn(xhci, + "WARN: Slot ID %u, ep index %u has streams, " + "but URB has no stream ID.\n", + slot_id, ep_index); + return NULL; + } + + if (stream_id < ep->stream_info->num_streams) + return ep->stream_info->stream_rings[stream_id]; + + xhci_warn(xhci, + "WARN: Slot ID %u, ep index %u has " + "stream IDs 1 to %u allocated, " + "but stream ID %u is requested.\n", + slot_id, ep_index, + ep->stream_info->num_streams - 1, + stream_id); + return NULL; +} + +/* Get the right ring for the given URB. + * If the endpoint supports streams, boundary check the URB's stream ID. + * If the endpoint doesn't support streams, return the singular endpoint ring. + */ +struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, + struct urb *urb) +{ + return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id, + xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id); +} + #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING static int xhci_test_radix_tree(struct xhci_hcd *xhci, unsigned int num_streams, @@ -515,6 +586,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, cur_ring = stream_info->stream_rings[cur_stream]; if (!cur_ring) goto cleanup_rings; + cur_ring->stream_id = cur_stream; /* Set deq ptr, cycle bit, and stream context type */ addr = cur_ring->first_seg->dma | SCT_FOR_CTX(SCT_PRI_TR) | diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a14f657e279..16ef5fd77ce 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -312,7 +312,8 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci) static void ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, - unsigned int ep_index) + unsigned int ep_index, + unsigned int stream_id) { struct xhci_virt_ep *ep; unsigned int ep_state; @@ -331,7 +332,8 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci, if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING) && !(ep_state & EP_HALTED)) { field = xhci_readl(xhci, db_addr) & DB_MASK; - xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr); + field |= EPI_TO_DB(ep_index) | STREAM_ID_TO_DB(stream_id); + xhci_writel(xhci, field, db_addr); /* Flush PCI posted writes - FIXME Matthew Wilcox says this * isn't time-critical and we shouldn't make the CPU wait for * the flush. @@ -340,6 +342,31 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci, } } +/* Ring the doorbell for any rings with pending URBs */ +static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci, + unsigned int slot_id, + unsigned int ep_index) +{ + unsigned int stream_id; + struct xhci_virt_ep *ep; + + ep = &xhci->devs[slot_id]->eps[ep_index]; + + /* A ring has pending URBs if its TD list is not empty */ + if (!(ep->ep_state & EP_HAS_STREAMS)) { + if (!(list_empty(&ep->ring->td_list))) + ring_ep_doorbell(xhci, slot_id, ep_index, 0); + return; + } + + for (stream_id = 1; stream_id < ep->stream_info->num_streams; + stream_id++) { + struct xhci_stream_info *stream_info = ep->stream_info; + if (!list_empty(&stream_info->stream_rings[stream_id]->td_list)) + ring_ep_doorbell(xhci, slot_id, ep_index, stream_id); + } +} + /* * Find the segment that trb is in. Start searching in start_seg. * If we must move past a segment that has a link TRB with a toggle cycle state @@ -382,14 +409,23 @@ static struct xhci_segment *find_trb_seg( */ 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) + unsigned int stream_id, 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->eps[ep_index].ring; + struct xhci_ring *ep_ring; struct xhci_generic_trb *trb; struct xhci_ep_ctx *ep_ctx; dma_addr_t addr; + ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id, + ep_index, stream_id); + if (!ep_ring) { + xhci_warn(xhci, "WARN can't find new dequeue state " + "for invalid stream ID %u.\n", + stream_id); + return; + } 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, @@ -469,11 +505,13 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, } static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, struct xhci_segment *deq_seg, + unsigned int ep_index, unsigned int stream_id, + struct xhci_segment *deq_seg, union xhci_trb *deq_ptr, u32 cycle_state); void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, + unsigned int stream_id, struct xhci_dequeue_state *deq_state) { struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; @@ -485,7 +523,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, 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, + queue_set_tr_deq(xhci, slot_id, ep_index, stream_id, deq_state->new_deq_seg, deq_state->new_deq_ptr, (u32) deq_state->new_cycle_state); @@ -553,11 +591,10 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); ep = &xhci->devs[slot_id]->eps[ep_index]; - ep_ring = ep->ring; if (list_empty(&ep->cancelled_td_list)) { xhci_stop_watchdog_timer_in_irq(xhci, ep); - ring_ep_doorbell(xhci, slot_id, ep_index); + ring_doorbell_for_active_rings(xhci, slot_id, ep_index); return; } @@ -571,15 +608,36 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n", cur_td->first_trb, (unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb)); + ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb); + if (!ep_ring) { + /* This shouldn't happen unless a driver is mucking + * with the stream ID after submission. This will + * leave the TD on the hardware ring, and the hardware + * will try to execute it, and may access a buffer + * that has already been freed. In the best case, the + * hardware will execute it, and the event handler will + * ignore the completion event for that TD, since it was + * removed from the td_list for that endpoint. In + * short, don't muck with the stream ID after + * submission. + */ + xhci_warn(xhci, "WARN Cancelled URB %p " + "has invalid stream ID %u.\n", + cur_td->urb, + cur_td->urb->stream_id); + goto remove_finished_td; + } /* * If we stopped on the TD we need to cancel, then we have to * move the xHC endpoint ring dequeue pointer past this TD. */ if (cur_td == ep->stopped_td) - xhci_find_new_dequeue_state(xhci, slot_id, ep_index, cur_td, - &deq_state); + xhci_find_new_dequeue_state(xhci, slot_id, ep_index, + cur_td->urb->stream_id, + cur_td, &deq_state); else td_to_noop(xhci, ep_ring, cur_td); +remove_finished_td: /* * The event handler won't see a completion for this TD anymore, * so remove it from the endpoint ring's TD list. Keep it in @@ -593,11 +651,13 @@ 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_queue_new_dequeue_state(xhci, - slot_id, ep_index, &deq_state); + slot_id, ep_index, + ep->stopped_td->urb->stream_id, + &deq_state); xhci_ring_cmd_db(xhci); } else { - /* Otherwise just ring the doorbell to restart the ring */ - ring_ep_doorbell(xhci, slot_id, ep_index); + /* Otherwise ring the doorbell(s) to restart queued transfers */ + ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } ep->stopped_td = NULL; ep->stopped_trb = NULL; @@ -757,6 +817,7 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, { unsigned int slot_id; unsigned int ep_index; + unsigned int stream_id; struct xhci_ring *ep_ring; struct xhci_virt_device *dev; struct xhci_ep_ctx *ep_ctx; @@ -764,8 +825,19 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); + stream_id = TRB_TO_STREAM_ID(trb->generic.field[2]); dev = xhci->devs[slot_id]; - ep_ring = dev->eps[ep_index].ring; + + ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id); + if (!ep_ring) { + xhci_warn(xhci, "WARN Set TR deq ptr command for " + "freed stream ID %u\n", + stream_id); + /* XXX: Harmless??? */ + dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING; + return; + } + ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); @@ -810,7 +882,8 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, } dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING; - ring_ep_doorbell(xhci, slot_id, ep_index); + /* Restart any rings with pending URBs */ + ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } static void handle_reset_ep_completion(struct xhci_hcd *xhci, @@ -819,11 +892,9 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci, { int slot_id; unsigned int ep_index; - struct xhci_ring *ep_ring; slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); - ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; /* This command will only fail if the endpoint wasn't halted, * but we don't care. */ @@ -841,9 +912,9 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci, false); xhci_ring_cmd_db(xhci); } else { - /* Clear our internal halted state and restart the ring */ + /* Clear our internal halted state and restart the ring(s) */ xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; - ring_ep_doorbell(xhci, slot_id, ep_index); + ring_doorbell_for_active_rings(xhci, slot_id, ep_index); } } @@ -929,8 +1000,10 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, /* Input ctx add_flags are the endpoint index plus one */ ep_index = xhci_last_valid_endpoint(ctrl_ctx->add_flags) - 1; /* A usb_set_interface() call directly after clearing a halted - * condition may race on this quirky hardware. - * Not worth worrying about, since this is prototype hardware. + * condition may race on this quirky hardware. Not worth + * worrying about, since this is prototype hardware. Not sure + * if this will work for streams, but streams support was + * untested on this prototype. */ if (xhci->quirks & XHCI_RESET_EP_QUIRK && ep_index != (unsigned int) -1 && @@ -943,10 +1016,10 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, xhci_dbg(xhci, "Completed config ep cmd - " "last ep index = %d, state = %d\n", ep_index, ep_state); - /* Clear our internal halted state and restart ring */ + /* Clear internal halted state and restart ring(s) */ xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; - ring_ep_doorbell(xhci, slot_id, ep_index); + ring_doorbell_for_active_rings(xhci, slot_id, ep_index); break; } bandwidth_change: @@ -1079,12 +1152,14 @@ struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, + unsigned int stream_id, struct xhci_td *td, union xhci_trb *event_trb) { struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; ep->ep_state |= EP_HALTED; ep->stopped_td = td; ep->stopped_trb = event_trb; + ep->stopped_stream = stream_id; xhci_queue_reset_ep(xhci, slot_id, ep_index); xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index); @@ -1169,10 +1244,11 @@ 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 = &xdev->eps[ep_index]; - ep_ring = ep->ring; + ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer); 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"); + xhci_err(xhci, "ERROR Transfer event for disabled endpoint " + "or incorrect stream ring\n"); return -ENODEV; } @@ -1303,7 +1379,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, td->urb->actual_length = 0; xhci_cleanup_halted_endpoint(xhci, - slot_id, ep_index, td, event_trb); + slot_id, ep_index, 0, td, event_trb); goto td_cleanup; } /* @@ -1452,6 +1528,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, */ ep->stopped_td = td; ep->stopped_trb = event_trb; + ep->stopped_stream = ep_ring->stream_id; } else if (xhci_requires_manual_halt_cleanup(xhci, ep_ctx, trb_comp_code)) { /* Other types of errors halt the endpoint, but the @@ -1460,7 +1537,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, * xHCI hardware manually. */ xhci_cleanup_halted_endpoint(xhci, - slot_id, ep_index, td, event_trb); + slot_id, ep_index, ep_ring->stream_id, td, event_trb); } else { /* Update ring dequeue pointer */ while (ep_ring->dequeue != td->last_trb) @@ -1656,14 +1733,24 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, static int prepare_transfer(struct xhci_hcd *xhci, struct xhci_virt_device *xdev, unsigned int ep_index, + unsigned int stream_id, unsigned int num_trbs, struct urb *urb, struct xhci_td **td, gfp_t mem_flags) { int ret; + struct xhci_ring *ep_ring; struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); - ret = prepare_ring(xhci, xdev->eps[ep_index].ring, + + ep_ring = xhci_stream_id_to_ring(xdev, ep_index, stream_id); + if (!ep_ring) { + xhci_dbg(xhci, "Can't prepare ring for bad stream ID %u\n", + stream_id); + return -EINVAL; + } + + ret = prepare_ring(xhci, ep_ring, ep_ctx->ep_info & EP_STATE_MASK, num_trbs, mem_flags); if (ret) @@ -1683,9 +1770,9 @@ static int prepare_transfer(struct xhci_hcd *xhci, (*td)->urb = urb; urb->hcpriv = (void *) (*td); /* Add this TD to the tail of the endpoint ring's TD list */ - list_add_tail(&(*td)->td_list, &xdev->eps[ep_index].ring->td_list); - (*td)->start_seg = xdev->eps[ep_index].ring->enq_seg; - (*td)->first_trb = xdev->eps[ep_index].ring->enqueue; + list_add_tail(&(*td)->td_list, &ep_ring->td_list); + (*td)->start_seg = ep_ring->enq_seg; + (*td)->first_trb = ep_ring->enqueue; return 0; } @@ -1751,7 +1838,7 @@ static void check_trb_math(struct urb *urb, int num_trbs, int running_total) } static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, int start_cycle, + unsigned int ep_index, unsigned int stream_id, int start_cycle, struct xhci_generic_trb *start_trb, struct xhci_td *td) { /* @@ -1760,7 +1847,7 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id, */ wmb(); start_trb->field[3] |= start_cycle; - ring_ep_doorbell(xhci, slot_id, ep_index); + ring_ep_doorbell(xhci, slot_id, ep_index, stream_id); } /* @@ -1834,12 +1921,16 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct xhci_generic_trb *start_trb; int start_cycle; - ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; + ep_ring = xhci_urb_to_transfer_ring(xhci, urb); + if (!ep_ring) + return -EINVAL; + num_trbs = count_sg_trbs_needed(xhci, urb); num_sgs = urb->num_sgs; trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], - ep_index, num_trbs, urb, &td, mem_flags); + ep_index, urb->stream_id, + num_trbs, urb, &td, mem_flags); if (trb_buff_len < 0) return trb_buff_len; /* @@ -1948,7 +2039,8 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } while (running_total < urb->transfer_buffer_length); check_trb_math(urb, num_trbs, running_total); - giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td); + giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, + start_cycle, start_trb, td); return 0; } @@ -1970,7 +2062,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (urb->num_sgs) return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index); - ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; + ep_ring = xhci_urb_to_transfer_ring(xhci, urb); + if (!ep_ring) + return -EINVAL; num_trbs = 0; /* How much data is (potentially) left before the 64KB boundary? */ @@ -1997,7 +2091,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, (unsigned long long)urb->transfer_dma, num_trbs); - ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, num_trbs, urb, &td, mem_flags); if (ret < 0) return ret; @@ -2067,7 +2162,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } while (running_total < urb->transfer_buffer_length); check_trb_math(urb, num_trbs, running_total); - giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td); + giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, + start_cycle, start_trb, td); return 0; } @@ -2084,7 +2180,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, u32 field, length_field; struct xhci_td *td; - ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; + ep_ring = xhci_urb_to_transfer_ring(xhci, urb); + if (!ep_ring) + return -EINVAL; /* * Need to copy setup packet into setup TRB, so we can't use the setup @@ -2105,8 +2203,9 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, */ if (urb->transfer_buffer_length > 0) num_trbs++; - ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, num_trbs, - urb, &td, mem_flags); + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + num_trbs, urb, &td, mem_flags); if (ret < 0) return ret; @@ -2161,7 +2260,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Event on completion */ field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state); - giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td); + giveback_first_trb(xhci, slot_id, ep_index, 0, + start_cycle, start_trb, td); return 0; } @@ -2273,12 +2373,14 @@ int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, * This should not be used for endpoints that have streams enabled. */ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, struct xhci_segment *deq_seg, + unsigned int ep_index, unsigned int stream_id, + struct xhci_segment *deq_seg, union xhci_trb *deq_ptr, u32 cycle_state) { dma_addr_t addr; u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); + u32 trb_stream_id = STREAM_ID_FOR_TRB(stream_id); u32 type = TRB_TYPE(TRB_SET_DEQ); addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr); @@ -2289,7 +2391,7 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, return 0; } return queue_command(xhci, lower_32_bits(addr) | cycle_state, - upper_32_bits(addr), 0, + upper_32_bits(addr), trb_stream_id, trb_slot_id | trb_ep_index | type, false); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 2e370fea959..3cac2ff8b50 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -353,11 +353,7 @@ void xhci_event_ring_work(unsigned long arg) if (!xhci->devs[i]) continue; for (j = 0; j < 31; ++j) { - struct xhci_ring *ring = xhci->devs[i]->eps[j].ring; - if (!ring) - continue; - xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", i, j); - xhci_debug_segment(xhci, ring->deq_seg); + xhci_dbg_ep_rings(xhci, i, j, &xhci->devs[i]->eps[j]); } } @@ -839,7 +835,12 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) xhci_debug_ring(xhci, xhci->event_ring); ep_index = xhci_get_endpoint_index(&urb->ep->desc); ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index]; - ep_ring = ep->ring; + ep_ring = xhci_urb_to_transfer_ring(xhci, urb); + if (!ep_ring) { + ret = -EINVAL; + goto done; + } + xhci_dbg(xhci, "Endpoint ring:\n"); xhci_debug_ring(xhci, ep_ring); td = (struct xhci_td *) urb->hcpriv; @@ -1383,7 +1384,7 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, * or it will attempt to resend it on the next doorbell ring. */ xhci_find_new_dequeue_state(xhci, udev->slot_id, - ep_index, ep->stopped_td, + ep_index, ep->stopped_stream, ep->stopped_td, &deq_state); /* HW with the reset endpoint quirk will use the saved dequeue state to @@ -1392,10 +1393,12 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) { xhci_dbg(xhci, "Queueing new dequeue state\n"); xhci_queue_new_dequeue_state(xhci, udev->slot_id, - ep_index, &deq_state); + ep_index, ep->stopped_stream, &deq_state); } else { /* Better hope no one uses the input context between now and the * reset endpoint completion! + * XXX: No idea how this hardware will react when stream rings + * are enabled. */ xhci_dbg(xhci, "Setting up input context for " "configure endpoint command\n"); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 7a9447cb6ea..dada2fb5926 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -444,6 +444,7 @@ struct xhci_doorbell_array { /* Endpoint Target - bits 0:7 */ #define EPI_TO_DB(p) (((p) + 1) & 0xff) +#define STREAM_ID_TO_DB(p) (((p) & 0xffff) << 16) /** @@ -714,6 +715,7 @@ struct xhci_virt_ep { /* The TRB that was last reported in a stopped endpoint ring */ union xhci_trb *stopped_trb; struct xhci_td *stopped_td; + unsigned int stopped_stream; /* Watchdog timer for stop endpoint command to cancel URBs */ struct timer_list stop_cmd_timer; int stop_cmds_pending; @@ -871,6 +873,10 @@ struct xhci_event_cmd { #define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1) #define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16) +/* Set TR Dequeue Pointer command TRB fields */ +#define TRB_TO_STREAM_ID(p) ((((p) & (0xffff << 16)) >> 16)) +#define STREAM_ID_FOR_TRB(p) ((((p)) & 0xffff) << 16) + /* Port Status Change Event TRB fields */ /* Port ID - bits 31:24 */ @@ -1040,6 +1046,7 @@ struct xhci_ring { * if we own the TRB (if we are the consumer). See section 4.9.1. */ u32 cycle_state; + unsigned int stream_id; }; struct xhci_erst_entry { @@ -1265,6 +1272,9 @@ void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep); char *xhci_get_slot_state(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); +void xhci_dbg_ep_rings(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, + struct xhci_virt_ep *ep); /* xHCI memory management */ void xhci_mem_cleanup(struct xhci_hcd *xhci); @@ -1302,6 +1312,18 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci, void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci, struct xhci_ep_ctx *ep_ctx, struct xhci_virt_ep *ep); +struct xhci_ring *xhci_dma_to_transfer_ring( + struct xhci_virt_ep *ep, + u64 address); +struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, + struct urb *urb); +struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, + unsigned int stream_id); +struct xhci_ring *xhci_stream_id_to_ring( + struct xhci_virt_device *dev, + unsigned int ep_index, + unsigned int stream_id); struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, bool allocate_in_ctx, bool allocate_completion, gfp_t mem_flags); @@ -1374,9 +1396,11 @@ int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id); 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); + unsigned int stream_id, struct xhci_td *cur_td, + struct xhci_dequeue_state *state); void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, + unsigned int stream_id, struct xhci_dequeue_state *deq_state); void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, struct usb_device *udev, unsigned int ep_index); -- cgit v1.2.3-70-g09d2 From 842f16905dfc6743c1dd80c3d29b49ba3ab7f7c8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 30 Apr 2010 12:44:46 -0400 Subject: USB: remove the usb_host_ss_ep_comp structure This patch (as1375) eliminates the usb_host_ss_ep_comp structure used for storing a dynamically-allocated copy of the SuperSpeed endpoint companion descriptor. The SuperSpeed descriptor is placed directly in the usb_host_endpoint structure, alongside the standard endpoint descriptor. Signed-off-by: Alan Stern Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 185 +++++++++++++------------------------------- drivers/usb/host/xhci-mem.c | 22 ++---- drivers/usb/host/xhci.c | 13 +--- include/linux/usb.h | 19 +---- 4 files changed, 68 insertions(+), 171 deletions(-) (limited to 'drivers/usb/host/xhci.c') diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index e4909c26bec..83126b03e7c 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -21,32 +21,6 @@ static inline const char *plural(int n) return (n == 1 ? "" : "s"); } -/* FIXME: this is a kludge */ -static int find_next_descriptor_more(unsigned char *buffer, int size, - int dt1, int dt2, int dt3, int *num_skipped) -{ - struct usb_descriptor_header *h; - int n = 0; - unsigned char *buffer0 = buffer; - - /* Find the next descriptor of type dt1 or dt2 or dt3 */ - while (size > 0) { - h = (struct usb_descriptor_header *) buffer; - if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 || - h->bDescriptorType == dt3) - break; - buffer += h->bLength; - size -= h->bLength; - ++n; - } - - /* Store the number of descriptors skipped and return the - * number of bytes skipped */ - if (num_skipped) - *num_skipped = n; - return buffer - buffer0; -} - static int find_next_descriptor(unsigned char *buffer, int size, int dt1, int dt2, int *num_skipped) { @@ -71,47 +45,41 @@ static int find_next_descriptor(unsigned char *buffer, int size, return buffer - buffer0; } -static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, +static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, int inum, int asnum, struct usb_host_endpoint *ep, - int num_ep, unsigned char *buffer, int size) + unsigned char *buffer, int size) { - unsigned char *buffer_start = buffer; - struct usb_ss_ep_comp_descriptor *desc; - int retval; - int num_skipped; + struct usb_ss_ep_comp_descriptor *desc; int max_tx; - int i; + /* The SuperSpeed endpoint companion descriptor is supposed to + * be the first thing immediately following the endpoint descriptor. + */ desc = (struct usb_ss_ep_comp_descriptor *) buffer; - if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) { + if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP || + size < USB_DT_SS_EP_COMP_SIZE) { dev_warn(ddev, "No SuperSpeed endpoint companion for config %d " " interface %d altsetting %d ep %d: " "using minimum values\n", cfgno, inum, asnum, ep->desc.bEndpointAddress); - /* - * The next descriptor is for an Endpoint or Interface, - * no extra descriptors to copy into the companion structure, - * and we didn't eat up any of the buffer. + + /* Fill in some default values. + * Leave bmAttributes as zero, which will mean no streams for + * bulk, and isoc won't support multiple bursts of packets. + * With bursts of only one packet, and a Mult of 1, the max + * amount of data moved per endpoint service interval is one + * packet. */ - return 0; + ep->ss_ep_comp.bLength = USB_DT_SS_EP_COMP_SIZE; + ep->ss_ep_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; + if (usb_endpoint_xfer_isoc(&ep->desc) || + usb_endpoint_xfer_int(&ep->desc)) + ep->ss_ep_comp.wBytesPerInterval = + ep->desc.wMaxPacketSize; + return; } - memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE); - desc = &ep->ss_ep_comp->desc; - buffer += desc->bLength; - size -= desc->bLength; - /* Eat up the other descriptors we don't care about */ - ep->ss_ep_comp->extra = buffer; - i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, - USB_DT_INTERFACE, &num_skipped); - ep->ss_ep_comp->extralen = i; - buffer += i; - size -= i; - retval = buffer - buffer_start; - if (num_skipped > 0) - dev_dbg(ddev, "skipped %d descriptor%s after %s\n", - num_skipped, plural(num_skipped), - "SuperSpeed endpoint companion"); + memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE); /* Check the various values */ if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) { @@ -119,47 +87,48 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, "config %d interface %d altsetting %d ep %d: " "setting to zero\n", desc->bMaxBurst, cfgno, inum, asnum, ep->desc.bEndpointAddress); - desc->bMaxBurst = 0; - } - if (desc->bMaxBurst > 15) { + ep->ss_ep_comp.bMaxBurst = 0; + } else if (desc->bMaxBurst > 15) { dev_warn(ddev, "Endpoint with bMaxBurst = %d in " "config %d interface %d altsetting %d ep %d: " "setting to 15\n", desc->bMaxBurst, cfgno, inum, asnum, ep->desc.bEndpointAddress); - desc->bMaxBurst = 15; + ep->ss_ep_comp.bMaxBurst = 15; } - if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc)) - && desc->bmAttributes != 0) { + + if ((usb_endpoint_xfer_control(&ep->desc) || + usb_endpoint_xfer_int(&ep->desc)) && + desc->bmAttributes != 0) { dev_warn(ddev, "%s endpoint with bmAttributes = %d in " "config %d interface %d altsetting %d ep %d: " "setting to zero\n", usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk", desc->bmAttributes, cfgno, inum, asnum, ep->desc.bEndpointAddress); - desc->bmAttributes = 0; - } - if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) { + ep->ss_ep_comp.bmAttributes = 0; + } else if (usb_endpoint_xfer_bulk(&ep->desc) && + desc->bmAttributes > 16) { dev_warn(ddev, "Bulk endpoint with more than 65536 streams in " "config %d interface %d altsetting %d ep %d: " "setting to max\n", cfgno, inum, asnum, ep->desc.bEndpointAddress); - desc->bmAttributes = 16; - } - if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) { + ep->ss_ep_comp.bmAttributes = 16; + } else if (usb_endpoint_xfer_isoc(&ep->desc) && + desc->bmAttributes > 2) { dev_warn(ddev, "Isoc endpoint has Mult of %d in " "config %d interface %d altsetting %d ep %d: " "setting to 3\n", desc->bmAttributes + 1, cfgno, inum, asnum, ep->desc.bEndpointAddress); - desc->bmAttributes = 2; + ep->ss_ep_comp.bmAttributes = 2; } - if (usb_endpoint_xfer_isoc(&ep->desc)) { + + if (usb_endpoint_xfer_isoc(&ep->desc)) max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) * (desc->bmAttributes + 1); - } else if (usb_endpoint_xfer_int(&ep->desc)) { + else if (usb_endpoint_xfer_int(&ep->desc)) max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1); - } else { - goto valid; - } + else + max_tx = 999999; if (desc->wBytesPerInterval > max_tx) { dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in " "config %d interface %d altsetting %d ep %d: " @@ -168,10 +137,8 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, desc->wBytesPerInterval, cfgno, inum, asnum, ep->desc.bEndpointAddress, max_tx); - desc->wBytesPerInterval = max_tx; + ep->ss_ep_comp.wBytesPerInterval = max_tx; } -valid: - return retval; } static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, @@ -293,61 +260,19 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, cfgno, inum, asnum, d->bEndpointAddress, maxp); } - /* Allocate room for and parse any SS endpoint companion descriptors */ - if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) { - endpoint->extra = buffer; - i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP, - USB_DT_ENDPOINT, USB_DT_INTERFACE, &n); - endpoint->extralen = i; - buffer += i; - size -= i; - - /* Allocate space for the SS endpoint companion descriptor */ - endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp), - GFP_KERNEL); - if (!endpoint->ss_ep_comp) - return -ENOMEM; - /* Fill in some default values (may be overwritten later) */ - endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE; - endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; - endpoint->ss_ep_comp->desc.bMaxBurst = 0; - /* - * Leave bmAttributes as zero, which will mean no streams for - * bulk, and isoc won't support multiple bursts of packets. - * With bursts of only one packet, and a Mult of 1, the max - * amount of data moved per endpoint service interval is one - * packet. - */ - if (usb_endpoint_xfer_isoc(&endpoint->desc) || - usb_endpoint_xfer_int(&endpoint->desc)) - endpoint->ss_ep_comp->desc.wBytesPerInterval = - endpoint->desc.wMaxPacketSize; - - if (size > 0) { - retval = usb_parse_ss_endpoint_companion(ddev, cfgno, - inum, asnum, endpoint, num_ep, buffer, - size); - if (retval >= 0) { - buffer += retval; - retval = buffer - buffer0; - } - } else { - dev_warn(ddev, "config %d interface %d altsetting %d " - "endpoint 0x%X has no " - "SuperSpeed companion descriptor\n", - cfgno, inum, asnum, d->bEndpointAddress); - retval = buffer - buffer0; - } - } else { - /* Skip over any Class Specific or Vendor Specific descriptors; - * find the next endpoint or interface descriptor */ - endpoint->extra = buffer; - i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, - USB_DT_INTERFACE, &n); - endpoint->extralen = i; - retval = buffer - buffer0 + i; - } + /* Parse a possible SuperSpeed endpoint companion descriptor */ + if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) + usb_parse_ss_endpoint_companion(ddev, cfgno, + inum, asnum, endpoint, buffer, size); + + /* Skip over any Class Specific or Vendor Specific descriptors; + * find the next endpoint or interface descriptor */ + endpoint->extra = buffer; + i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, + USB_DT_INTERFACE, &n); + endpoint->extralen = i; + retval = buffer - buffer0 + i; if (n > 0) dev_dbg(ddev, "skipped %d descriptor%s after %s\n", n, plural(n), "endpoint"); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 4df752cb0f7..fd9e03afd91 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1010,9 +1010,9 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev, static inline u32 xhci_get_endpoint_mult(struct usb_device *udev, struct usb_host_endpoint *ep) { - if (udev->speed != USB_SPEED_SUPER || !ep->ss_ep_comp) + if (udev->speed != USB_SPEED_SUPER) return 0; - return ep->ss_ep_comp->desc.bmAttributes; + return ep->ss_ep_comp.bmAttributes; } static inline u32 xhci_get_endpoint_type(struct usb_device *udev, @@ -1061,13 +1061,8 @@ static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci, usb_endpoint_xfer_bulk(&ep->desc)) return 0; - if (udev->speed == USB_SPEED_SUPER) { - if (ep->ss_ep_comp) - return ep->ss_ep_comp->desc.wBytesPerInterval; - xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n"); - /* Assume no bursts, no multiple opportunities to send. */ - return ep->desc.wMaxPacketSize; - } + if (udev->speed == USB_SPEED_SUPER) + return ep->ss_ep_comp.wBytesPerInterval; max_packet = ep->desc.wMaxPacketSize & 0x3ff; max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11; @@ -1131,12 +1126,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, max_packet = ep->desc.wMaxPacketSize; ep_ctx->ep_info2 |= MAX_PACKET(max_packet); /* dig out max burst from ep companion desc */ - if (!ep->ss_ep_comp) { - xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n"); - max_packet = 0; - } else { - max_packet = ep->ss_ep_comp->desc.bMaxBurst; - } + max_packet = ep->ss_ep_comp.bMaxBurst; + if (!max_packet) + xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n"); ep_ctx->ep_info2 |= MAX_BURST(max_packet); break; case USB_SPEED_HIGH: diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 3cac2ff8b50..59f38a5f2fe 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1476,13 +1476,7 @@ static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, __func__); if (ret <= 0) return -EINVAL; - if (!ep->ss_ep_comp) { - xhci_warn(xhci, "WARN: No SuperSpeed Endpoint Companion" - " descriptor for ep 0x%x\n", - ep->desc.bEndpointAddress); - return -EINVAL; - } - if (ep->ss_ep_comp->desc.bmAttributes == 0) { + if (ep->ss_ep_comp.bmAttributes == 0) { xhci_warn(xhci, "WARN: SuperSpeed Endpoint Companion" " descriptor for ep 0x%x does not support streams\n", ep->desc.bEndpointAddress); @@ -1540,7 +1534,6 @@ static int xhci_calculate_streams_and_bitmask(struct xhci_hcd *xhci, struct usb_host_endpoint **eps, unsigned int num_eps, unsigned int *num_streams, u32 *changed_ep_bitmask) { - struct usb_host_ss_ep_comp *ss_ep_comp; unsigned int max_streams; unsigned int endpoint_flag; int i; @@ -1552,8 +1545,8 @@ static int xhci_calculate_streams_and_bitmask(struct xhci_hcd *xhci, if (ret < 0) return ret; - ss_ep_comp = eps[i]->ss_ep_comp; - max_streams = USB_SS_MAX_STREAMS(ss_ep_comp->desc.bmAttributes); + max_streams = USB_SS_MAX_STREAMS( + eps[i]->ss_ep_comp.bmAttributes); if (max_streams < (*num_streams - 1)) { xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n", eps[i]->desc.bEndpointAddress, diff --git a/include/linux/usb.h b/include/linux/usb.h index 1ea25377ca0..a748815ee62 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -45,27 +45,14 @@ struct wusb_dev; struct ep_device; -/* For SS devices */ -/** - * struct usb_host_ss_ep_comp - Valid for SuperSpeed devices only - * @desc: endpoint companion descriptor, wMaxPacketSize in native byteorder - * @extra: descriptors following this endpoint companion descriptor - * @extralen: how many bytes of "extra" are valid - */ -struct usb_host_ss_ep_comp { - struct usb_ss_ep_comp_descriptor desc; - unsigned char *extra; /* Extra descriptors */ - int extralen; -}; - /** * struct usb_host_endpoint - host-side endpoint descriptor and queue * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder + * @ss_ep_comp: SuperSpeed companion descriptor for this endpoint * @urb_list: urbs queued to this endpoint; maintained by usbcore * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH) * with one or more transfer descriptors (TDs) per urb * @ep_dev: ep_device for sysfs info - * @ss_ep_comp: companion descriptor information for this endpoint * @extra: descriptors following this endpoint in the configuration * @extralen: how many bytes of "extra" are valid * @enabled: URBs may be submitted to this endpoint @@ -74,11 +61,11 @@ struct usb_host_ss_ep_comp { * descriptor within an active interface in a given USB configuration. */ struct usb_host_endpoint { - struct usb_endpoint_descriptor desc; + struct usb_endpoint_descriptor desc; + struct usb_ss_ep_comp_descriptor ss_ep_comp; struct list_head urb_list; void *hcpriv; struct ep_device *ep_dev; /* For sysfs info */ - struct usb_host_ss_ep_comp *ss_ep_comp; /* For SS devices */ unsigned char *extra; /* Extra descriptors */ int extralen; -- cgit v1.2.3-70-g09d2 From 8a007748fbadb8317d0af289f3bca5694354d63a Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 30 Apr 2010 15:37:56 -0700 Subject: USB: xhci: Avoid double free after streams are disabled. When a device is disconnected, xhci_free_virt_device() is called. Ramya found that if the device had streams enabled, and then the driver freed the streams with a call to usb_free_streams(), then about a minute after he had called this, his machine crashed with a Bad DMA error. It turns out that xhci_free_virt_device() would attempt to free the endpoint's stream_info data structure if it wasn't NULL, and the free streams function was not setting it to NULL after freeing it. Signed-off-by: Sarah Sharp Tested-by: Ramya Desai Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/host/xhci.c') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 59f38a5f2fe..a9b836d4b29 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1746,6 +1746,7 @@ cleanup: for (i = 0; i < num_eps; i++) { ep_index = xhci_get_endpoint_index(&eps[i]->desc); xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info); + vdev->eps[ep_index].stream_info = NULL; /* FIXME Unset maxPstreams in endpoint context and * update deq ptr to point to normal string ring. */ @@ -1826,6 +1827,7 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, for (i = 0; i < num_eps; i++) { ep_index = xhci_get_endpoint_index(&eps[i]->desc); xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info); + vdev->eps[ep_index].stream_info = NULL; /* FIXME Unset maxPstreams in endpoint context and * update deq ptr to point to normal string ring. */ -- cgit v1.2.3-70-g09d2 From 5e5cf6fc59db2322dfe3ac8e1002f066b06d868f Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 6 May 2010 13:40:18 -0700 Subject: USB: xhci: Set stream ID to 0 after cleaning up stalls. After using state stored in xhci_virt_ep to clean up a stalled endpoint, be sure to set the stalled stream ID back to 0. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 1 + drivers/usb/host/xhci.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/usb/host/xhci.c') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a67caef265b..15f02e88f32 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1166,6 +1166,7 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, ep->stopped_td = NULL; ep->stopped_trb = NULL; + ep->stopped_stream = 0; xhci_ring_cmd_db(xhci); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index a9b836d4b29..40e0a0c221b 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1457,6 +1457,7 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, } virt_ep->stopped_td = NULL; virt_ep->stopped_trb = NULL; + virt_ep->stopped_stream = 0; spin_unlock_irqrestore(&xhci->lock, flags); if (ret) -- cgit v1.2.3-70-g09d2