diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2009-04-29 19:02:31 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-15 21:44:49 -0700 |
commit | ae636747146ea97efa18e04576acd3416e2514f5 (patch) | |
tree | 22e392df7126974c0ac4dc2fe516dc9e16a49873 /drivers/usb/host/xhci.h | |
parent | 8a96c052283e68fe91a6c657c175b39bfed80bed (diff) |
USB: xhci: URB cancellation support.
Add URB cancellation support to the xHCI host controller driver. This
currently supports cancellation for endpoints that do not have streams
enabled.
An URB is represented by a number of Transaction Request Buffers (TRBs),
that are chained together to make one (or more) Transaction Descriptors
(TDs) on an endpoint ring. The ring is comprised of contiguous segments,
linked together with Link TRBs (which may or may not be chained into a TD).
To cancel an URB, we must stop the endpoint ring, make the hardware skip
over the TDs in the URB (either by turning them into No-op TDs, or by
moving the hardware's ring dequeue pointer past the last TRB in the last
TD), and then restart the ring.
There are times when we must drop the xHCI lock during this process, like
when we need to complete cancelled URBs. We must ensure that additional
URBs can be marked as cancelled, and that new URBs can be enqueued (since
the URB completion handlers can do either). The new endpoint ring
variables cancels_pending and state (which can only be modified while
holding the xHCI lock) ensure that future cancellation and enqueueing do
not interrupt any pending cancellation code.
To facilitate cancellation, we must keep track of the starting ring
segment, first TRB, and last TRB for each URB. We also need to keep track
of the list of TDs that have been marked as cancelled, separate from the
list of TDs that are queued for this endpoint. The new variables and
cancellation list are stored in the xhci_td structure.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci.h')
-rw-r--r-- | drivers/usb/host/xhci.h | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 06e07616631..7b7103405c6 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -514,6 +514,7 @@ struct xhci_slot_ctx { /* bits 8:26 reserved */ /* Slot state */ #define SLOT_STATE (0x1f << 27) +#define GET_SLOT_STATE(p) (((p) & (0x1f << 27)) >> 27) /** @@ -765,6 +766,11 @@ struct xhci_event_cmd { #define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24) #define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24) +/* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */ +#define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1) +#define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16) + + /* Port Status Change Event TRB fields */ /* Port ID - bits 31:24 */ #define GET_PORT_ID(p) (((p) & (0xff << 24)) >> 24) @@ -893,12 +899,6 @@ union xhci_trb { #define TRB_MAX_BUFF_SHIFT 16 #define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) -struct xhci_td { - struct list_head td_list; - struct urb *urb; - union xhci_trb *last_trb; -}; - struct xhci_segment { union xhci_trb *trbs; /* private to HCD */ @@ -906,6 +906,15 @@ struct xhci_segment { dma_addr_t dma; } __attribute__ ((packed)); +struct xhci_td { + struct list_head td_list; + struct list_head cancelled_td_list; + struct urb *urb; + struct xhci_segment *start_seg; + union xhci_trb *first_trb; + union xhci_trb *last_trb; +}; + struct xhci_ring { struct xhci_segment *first_seg; union xhci_trb *enqueue; @@ -915,6 +924,14 @@ struct xhci_ring { struct xhci_segment *deq_seg; unsigned int deq_updates; struct list_head td_list; + /* ---- Related to URB cancellation ---- */ + struct list_head cancelled_td_list; + unsigned int cancels_pending; + unsigned int state; +#define SET_DEQ_PENDING (1 << 0) + /* The TRB that was last reported in a stopped endpoint ring */ + union xhci_trb *stopped_trb; + struct xhci_td *stopped_td; /* * Write the cycle state into the TRB cycle field to give ownership of * the TRB to the host controller (if we are the producer), or to check @@ -1119,6 +1136,8 @@ void handle_event(struct xhci_hcd *xhci); void set_hc_event_deq(struct xhci_hcd *xhci); int queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); int queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id); +int queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, + unsigned int ep_index); int queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index); int queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index); int queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id); |