aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/xhci.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci.h')
-rw-r--r--drivers/usb/host/xhci.h793
1 files changed, 647 insertions, 146 deletions
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 2d7b6374b58d..e3e935291ed6 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -425,6 +425,7 @@ struct xhci_op_regs {
#define PORT_L1DS_MASK (0xff << 8)
#define PORT_L1DS(p) (((p) & 0xff) << 8)
#define PORT_HLE (1 << 16)
+#define PORT_TEST_MODE_SHIFT 28
/* USB3 Protocol PORTLI Port Link Information */
#define PORT_RX_LANES(p) (((p) >> 16) & 0xf)
@@ -617,6 +618,7 @@ struct xhci_slot_ctx {
#define ROUTE_STRING_MASK (0xfffff)
/* Device speed - values defined by PORTSC Device Speed field - 20:23 */
#define DEV_SPEED (0xf << 20)
+#define GET_DEV_SPEED(n) (((n) & DEV_SPEED) >> 20)
/* bit 24 reserved */
/* Is this LS/FS device connected through a HS hub? - bit 25 */
#define DEV_MTT (0x1 << 25)
@@ -637,6 +639,7 @@ struct xhci_slot_ctx {
#define DEVINFO_TO_ROOT_HUB_PORT(p) (((p) >> 16) & 0xff)
/* Maximum number of ports under a hub device */
#define XHCI_MAX_PORTS(p) (((p) & 0xff) << 24)
+#define DEVINFO_TO_MAX_PORTS(p) (((p) & (0xff << 24)) >> 24)
/* tt_info bitmasks */
/*
@@ -651,6 +654,7 @@ struct xhci_slot_ctx {
*/
#define TT_PORT (0xff << 8)
#define TT_THINK_TIME(p) (((p) & 0x3) << 16)
+#define GET_TT_THINK_TIME(p) (((p) & (0x3 << 16)) >> 16)
/* dev_state bitmasks */
/* USB device address - assigned by the HC */
@@ -912,7 +916,7 @@ struct xhci_virt_ep {
unsigned int ep_state;
#define SET_DEQ_PENDING (1 << 0)
#define EP_HALTED (1 << 1) /* For stall handling */
-#define EP_HALT_PENDING (1 << 2) /* For URB cancellation */
+#define EP_STOP_CMD_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)
@@ -920,11 +924,8 @@ struct xhci_virt_ep {
#define EP_GETTING_NO_STREAMS (1 << 5)
/* ---- Related to URB cancellation ---- */
struct list_head cancelled_td_list;
- 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;
struct xhci_hcd *xhci;
/* Dequeue pointer and dequeue segment for a submitted Set TR Dequeue
* command. We'll need to update the ring's dequeue segment and dequeue
@@ -990,10 +991,6 @@ struct xhci_virt_device {
struct xhci_container_ctx *out_ctx;
/* Used for addressing devices and configuration changes */
struct xhci_container_ctx *in_ctx;
- /* Rings saved to ensure old alt settings can be re-instated */
- struct xhci_ring **ring_cache;
- int num_rings_cached;
-#define XHCI_MAX_RINGS_CACHED 31
struct xhci_virt_ep eps[31];
u8 fake_port;
u8 real_port;
@@ -1061,76 +1058,122 @@ struct xhci_transfer_event {
/* Completion Code - only applicable for some types of TRBs */
#define COMP_CODE_MASK (0xff << 24)
#define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24)
-#define COMP_SUCCESS 1
-/* Data Buffer Error */
-#define COMP_DB_ERR 2
-/* Babble Detected Error */
-#define COMP_BABBLE 3
-/* USB Transaction Error */
-#define COMP_TX_ERR 4
-/* TRB Error - some TRB field is invalid */
-#define COMP_TRB_ERR 5
-/* Stall Error - USB device is stalled */
-#define COMP_STALL 6
-/* Resource Error - HC doesn't have memory for that device configuration */
-#define COMP_ENOMEM 7
-/* Bandwidth Error - not enough room in schedule for this dev config */
-#define COMP_BW_ERR 8
-/* No Slots Available Error - HC ran out of device slots */
-#define COMP_ENOSLOTS 9
-/* Invalid Stream Type Error */
-#define COMP_STREAM_ERR 10
-/* Slot Not Enabled Error - doorbell rung for disabled device slot */
-#define COMP_EBADSLT 11
-/* Endpoint Not Enabled Error */
-#define COMP_EBADEP 12
-/* Short Packet */
-#define COMP_SHORT_TX 13
-/* Ring Underrun - doorbell rung for an empty isoc OUT ep ring */
-#define COMP_UNDERRUN 14
-/* Ring Overrun - isoc IN ep ring is empty when ep is scheduled to RX */
-#define COMP_OVERRUN 15
-/* Virtual Function Event Ring Full Error */
-#define COMP_VF_FULL 16
-/* Parameter Error - Context parameter is invalid */
-#define COMP_EINVAL 17
-/* Bandwidth Overrun Error - isoc ep exceeded its allocated bandwidth */
-#define COMP_BW_OVER 18
-/* Context State Error - illegal context state transition requested */
-#define COMP_CTX_STATE 19
-/* No Ping Response Error - HC didn't get PING_RESPONSE in time to TX */
-#define COMP_PING_ERR 20
-/* Event Ring is full */
-#define COMP_ER_FULL 21
-/* Incompatible Device Error */
-#define COMP_DEV_ERR 22
-/* Missed Service Error - HC couldn't service an isoc ep within interval */
-#define COMP_MISSED_INT 23
-/* Successfully stopped command ring */
-#define COMP_CMD_STOP 24
-/* Successfully aborted current command and stopped command ring */
-#define COMP_CMD_ABORT 25
-/* Stopped - transfer was terminated by a stop endpoint command */
-#define COMP_STOP 26
-/* Same as COMP_EP_STOPPED, but the transferred length in the event is invalid */
-#define COMP_STOP_INVAL 27
-/* Same as COMP_EP_STOPPED, but a short packet detected */
-#define COMP_STOP_SHORT 28
-/* Max Exit Latency Too Large Error */
-#define COMP_MEL_ERR 29
-/* TRB type 30 reserved */
-/* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */
-#define COMP_BUFF_OVER 31
-/* Event Lost Error - xHC has an "internal event overrun condition" */
-#define COMP_ISSUES 32
-/* Undefined Error - reported when other error codes don't apply */
-#define COMP_UNKNOWN 33
-/* Invalid Stream ID Error */
-#define COMP_STRID_ERR 34
-/* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */
-#define COMP_2ND_BW_ERR 35
-/* Split Transaction Error */
-#define COMP_SPLIT_ERR 36
+#define COMP_INVALID 0
+#define COMP_SUCCESS 1
+#define COMP_DATA_BUFFER_ERROR 2
+#define COMP_BABBLE_DETECTED_ERROR 3
+#define COMP_USB_TRANSACTION_ERROR 4
+#define COMP_TRB_ERROR 5
+#define COMP_STALL_ERROR 6
+#define COMP_RESOURCE_ERROR 7
+#define COMP_BANDWIDTH_ERROR 8
+#define COMP_NO_SLOTS_AVAILABLE_ERROR 9
+#define COMP_INVALID_STREAM_TYPE_ERROR 10
+#define COMP_SLOT_NOT_ENABLED_ERROR 11
+#define COMP_ENDPOINT_NOT_ENABLED_ERROR 12
+#define COMP_SHORT_PACKET 13
+#define COMP_RING_UNDERRUN 14
+#define COMP_RING_OVERRUN 15
+#define COMP_VF_EVENT_RING_FULL_ERROR 16
+#define COMP_PARAMETER_ERROR 17
+#define COMP_BANDWIDTH_OVERRUN_ERROR 18
+#define COMP_CONTEXT_STATE_ERROR 19
+#define COMP_NO_PING_RESPONSE_ERROR 20
+#define COMP_EVENT_RING_FULL_ERROR 21
+#define COMP_INCOMPATIBLE_DEVICE_ERROR 22
+#define COMP_MISSED_SERVICE_ERROR 23
+#define COMP_COMMAND_RING_STOPPED 24
+#define COMP_COMMAND_ABORTED 25
+#define COMP_STOPPED 26
+#define COMP_STOPPED_LENGTH_INVALID 27
+#define COMP_STOPPED_SHORT_PACKET 28
+#define COMP_MAX_EXIT_LATENCY_TOO_LARGE_ERROR 29
+#define COMP_ISOCH_BUFFER_OVERRUN 31
+#define COMP_EVENT_LOST_ERROR 32
+#define COMP_UNDEFINED_ERROR 33
+#define COMP_INVALID_STREAM_ID_ERROR 34
+#define COMP_SECONDARY_BANDWIDTH_ERROR 35
+#define COMP_SPLIT_TRANSACTION_ERROR 36
+
+static inline const char *xhci_trb_comp_code_string(u8 status)
+{
+ switch (status) {
+ case COMP_INVALID:
+ return "Invalid";
+ case COMP_SUCCESS:
+ return "Success";
+ case COMP_DATA_BUFFER_ERROR:
+ return "Data Buffer Error";
+ case COMP_BABBLE_DETECTED_ERROR:
+ return "Babble Detected";
+ case COMP_USB_TRANSACTION_ERROR:
+ return "USB Transaction Error";
+ case COMP_TRB_ERROR:
+ return "TRB Error";
+ case COMP_STALL_ERROR:
+ return "Stall Error";
+ case COMP_RESOURCE_ERROR:
+ return "Resource Error";
+ case COMP_BANDWIDTH_ERROR:
+ return "Bandwidth Error";
+ case COMP_NO_SLOTS_AVAILABLE_ERROR:
+ return "No Slots Available Error";
+ case COMP_INVALID_STREAM_TYPE_ERROR:
+ return "Invalid Stream Type Error";
+ case COMP_SLOT_NOT_ENABLED_ERROR:
+ return "Slot Not Enabled Error";
+ case COMP_ENDPOINT_NOT_ENABLED_ERROR:
+ return "Endpoint Not Enabled Error";
+ case COMP_SHORT_PACKET:
+ return "Short Packet";
+ case COMP_RING_UNDERRUN:
+ return "Ring Underrun";
+ case COMP_RING_OVERRUN:
+ return "Ring Overrun";
+ case COMP_VF_EVENT_RING_FULL_ERROR:
+ return "VF Event Ring Full Error";
+ case COMP_PARAMETER_ERROR:
+ return "Parameter Error";
+ case COMP_BANDWIDTH_OVERRUN_ERROR:
+ return "Bandwidth Overrun Error";
+ case COMP_CONTEXT_STATE_ERROR:
+ return "Context State Error";
+ case COMP_NO_PING_RESPONSE_ERROR:
+ return "No Ping Response Error";
+ case COMP_EVENT_RING_FULL_ERROR:
+ return "Event Ring Full Error";
+ case COMP_INCOMPATIBLE_DEVICE_ERROR:
+ return "Incompatible Device Error";
+ case COMP_MISSED_SERVICE_ERROR:
+ return "Missed Service Error";
+ case COMP_COMMAND_RING_STOPPED:
+ return "Command Ring Stopped";
+ case COMP_COMMAND_ABORTED:
+ return "Command Aborted";
+ case COMP_STOPPED:
+ return "Stopped";
+ case COMP_STOPPED_LENGTH_INVALID:
+ return "Stopped - Length Invalid";
+ case COMP_STOPPED_SHORT_PACKET:
+ return "Stopped - Short Packet";
+ case COMP_MAX_EXIT_LATENCY_TOO_LARGE_ERROR:
+ return "Max Exit Latency Too Large Error";
+ case COMP_ISOCH_BUFFER_OVERRUN:
+ return "Isoch Buffer Overrun";
+ case COMP_EVENT_LOST_ERROR:
+ return "Event Lost Error";
+ case COMP_UNDEFINED_ERROR:
+ return "Undefined Error";
+ case COMP_INVALID_STREAM_ID_ERROR:
+ return "Invalid Stream ID Error";
+ case COMP_SECONDARY_BANDWIDTH_ERROR:
+ return "Secondary Bandwidth Error";
+ case COMP_SPLIT_TRANSACTION_ERROR:
+ return "Split Transaction Error";
+ default:
+ return "Unknown!!";
+ }
+}
struct xhci_link_trb {
/* 64-bit segment pointer*/
@@ -1154,6 +1197,32 @@ struct xhci_event_cmd {
/* Address device - disable SetAddress */
#define TRB_BSR (1<<9)
+
+/* Configure Endpoint - Deconfigure */
+#define TRB_DC (1<<9)
+
+/* Stop Ring - Transfer State Preserve */
+#define TRB_TSP (1<<9)
+
+enum xhci_ep_reset_type {
+ EP_HARD_RESET,
+ EP_SOFT_RESET,
+};
+
+/* Force Event */
+#define TRB_TO_VF_INTR_TARGET(p) (((p) & (0x3ff << 22)) >> 22)
+#define TRB_TO_VF_ID(p) (((p) & (0xff << 16)) >> 16)
+
+/* Set Latency Tolerance Value */
+#define TRB_TO_BELT(p) (((p) & (0xfff << 16)) >> 16)
+
+/* Get Port Bandwidth */
+#define TRB_TO_DEV_SPEED(p) (((p) & (0xf << 16)) >> 16)
+
+/* Force Header */
+#define TRB_TO_PACKET_TYPE(p) ((p) & 0x1f)
+#define TRB_TO_ROOTHUB_PORT(p) (((p) & (0xff << 24)) >> 24)
+
enum xhci_setup_dev {
SETUP_CONTEXT_ONLY,
SETUP_CONTEXT_ADDRESS,
@@ -1177,16 +1246,21 @@ enum xhci_setup_dev {
#define STREAM_ID_FOR_TRB(p) ((((p)) & 0xffff) << 16)
#define SCT_FOR_TRB(p) (((p) << 1) & 0x7)
+/* Link TRB specific fields */
+#define TRB_TC (1<<1)
/* Port Status Change Event TRB fields */
/* Port ID - bits 31:24 */
#define GET_PORT_ID(p) (((p) & (0xff << 24)) >> 24)
+#define EVENT_DATA (1 << 2)
+
/* Normal TRB fields */
/* transfer_len bitmasks - bits 0:16 */
#define TRB_LEN(p) ((p) & 0x1ffff)
/* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */
#define TRB_TD_SIZE(p) (min((p), (u32)31) << 17)
+#define GET_TD_SIZE(p) (((p) & 0x3e0000) >> 17)
/* xhci 1.1 uses the TD_SIZE field for TBC if Extended TBC is enabled (ETE) */
#define TRB_TD_SIZE_TBC(p) (min((p), (u32)31) << 17)
/* Interrupter Target - which MSI-X vector to target the completion event at */
@@ -1314,6 +1388,80 @@ union xhci_trb {
/* Get NEC firmware revision. */
#define TRB_NEC_GET_FW 49
+static inline const char *xhci_trb_type_string(u8 type)
+{
+ switch (type) {
+ case TRB_NORMAL:
+ return "Normal";
+ case TRB_SETUP:
+ return "Setup Stage";
+ case TRB_DATA:
+ return "Data Stage";
+ case TRB_STATUS:
+ return "Status Stage";
+ case TRB_ISOC:
+ return "Isoch";
+ case TRB_LINK:
+ return "Link";
+ case TRB_EVENT_DATA:
+ return "Event Data";
+ case TRB_TR_NOOP:
+ return "No-Op";
+ case TRB_ENABLE_SLOT:
+ return "Enable Slot Command";
+ case TRB_DISABLE_SLOT:
+ return "Disable Slot Command";
+ case TRB_ADDR_DEV:
+ return "Address Device Command";
+ case TRB_CONFIG_EP:
+ return "Configure Endpoint Command";
+ case TRB_EVAL_CONTEXT:
+ return "Evaluate Context Command";
+ case TRB_RESET_EP:
+ return "Reset Endpoint Command";
+ case TRB_STOP_RING:
+ return "Stop Ring Command";
+ case TRB_SET_DEQ:
+ return "Set TR Dequeue Pointer Command";
+ case TRB_RESET_DEV:
+ return "Reset Device Command";
+ case TRB_FORCE_EVENT:
+ return "Force Event Command";
+ case TRB_NEG_BANDWIDTH:
+ return "Negotiate Bandwidth Command";
+ case TRB_SET_LT:
+ return "Set Latency Tolerance Value Command";
+ case TRB_GET_BW:
+ return "Get Port Bandwidth Command";
+ case TRB_FORCE_HEADER:
+ return "Force Header Command";
+ case TRB_CMD_NOOP:
+ return "No-Op Command";
+ case TRB_TRANSFER:
+ return "Transfer Event";
+ case TRB_COMPLETION:
+ return "Command Completion Event";
+ case TRB_PORT_STATUS:
+ return "Port Status Change Event";
+ case TRB_BANDWIDTH_EVENT:
+ return "Bandwidth Request Event";
+ case TRB_DOORBELL:
+ return "Doorbell Event";
+ case TRB_HC_EVENT:
+ return "Host Controller Event";
+ case TRB_DEV_NOTE:
+ return "Device Notification Event";
+ case TRB_MFINDEX_WRAP:
+ return "MFINDEX Wrap Event";
+ case TRB_NEC_CMD_COMP:
+ return "NEC Command Completion Event";
+ case TRB_NEC_GET_FW:
+ return "NET Get Firmware Revision Command";
+ default:
+ return "UNKNOWN";
+ }
+}
+
#define TRB_TYPE_LINK(x) (((x) & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
/* Above, but for __le32 types -- can avoid work by swapping constants: */
#define TRB_TYPE_LINK_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \
@@ -1378,6 +1526,7 @@ struct xhci_dequeue_state {
struct xhci_segment *new_deq_seg;
union xhci_trb *new_deq_ptr;
int new_cycle_state;
+ unsigned int stream_id;
};
enum xhci_ring_type {
@@ -1390,15 +1539,35 @@ enum xhci_ring_type {
TYPE_EVENT,
};
+static inline const char *xhci_ring_type_string(enum xhci_ring_type type)
+{
+ switch (type) {
+ case TYPE_CTRL:
+ return "CTRL";
+ case TYPE_ISOC:
+ return "ISOC";
+ case TYPE_BULK:
+ return "BULK";
+ case TYPE_INTR:
+ return "INTR";
+ case TYPE_STREAM:
+ return "STREAM";
+ case TYPE_COMMAND:
+ return "CMD";
+ case TYPE_EVENT:
+ return "EVENT";
+ }
+
+ return "UNKNOWN";
+}
+
struct xhci_ring {
struct xhci_segment *first_seg;
struct xhci_segment *last_seg;
union xhci_trb *enqueue;
struct xhci_segment *enq_seg;
- unsigned int enq_updates;
union xhci_trb *dequeue;
struct xhci_segment *deq_seg;
- unsigned int deq_updates;
struct list_head td_list;
/*
* Write the cycle state into the TRB cycle field to give ownership of
@@ -1437,13 +1606,12 @@ struct xhci_scratchpad {
u64 *sp_array;
dma_addr_t sp_dma;
void **sp_buffers;
- dma_addr_t *sp_dma_buffers;
};
struct urb_priv {
- int length;
- int td_cnt;
- struct xhci_td *td[0];
+ int num_tds;
+ int num_tds_done;
+ struct xhci_td td[0];
};
/*
@@ -1549,14 +1717,12 @@ struct xhci_hcd {
u8 max_ports;
u8 isoc_threshold;
int event_ring_max;
- int addr_64;
/* 4KB min, 128MB max */
int page_size;
/* Valid values are 12 to 20, inclusive */
int page_shift;
/* msi-x vectors */
int msix_count;
- struct msix_entry *msix_entries;
/* optional clock */
struct clk *clk;
/* data structures */
@@ -1650,6 +1816,12 @@ struct xhci_hcd {
#define XHCI_SSIC_PORT_UNUSED (1 << 22)
#define XHCI_NO_64BIT_SUPPORT (1 << 23)
#define XHCI_MISSING_CAS (1 << 24)
+/* For controller with a broken Port Disable implementation */
+#define XHCI_BROKEN_PORT_PED (1 << 25)
+#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
+#define XHCI_U2_DISABLE_WAKE (1 << 27)
+#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
+
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1674,6 +1846,7 @@ struct xhci_hcd {
/* Compliance Mode Recovery Data */
struct timer_list comp_mode_recovery_timer;
u32 port_status_u0;
+ u16 test_mode;
/* Compliance Mode Timer Triggered every 2 seconds */
#define COMP_MODE_RCVRY_MSECS 2000
@@ -1749,19 +1922,10 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num);
void xhci_print_registers(struct xhci_hcd *xhci);
void xhci_dbg_regs(struct xhci_hcd *xhci);
void xhci_print_run_regs(struct xhci_hcd *xhci);
-void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb);
-void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb);
-void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg);
-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_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);
void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
const char *fmt, ...);
@@ -1775,16 +1939,8 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
struct usb_device *udev);
unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
unsigned int xhci_get_endpoint_address(unsigned int ep_index);
-unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
-unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index);
unsigned int xhci_last_valid_endpoint(u32 added_ctxs);
void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep);
-void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
- struct xhci_bw_info *ep_bw,
- struct xhci_interval_bw_table *bw_table,
- struct usb_device *udev,
- struct xhci_virt_ep *virt_ep,
- struct xhci_tt_bw_info *tt_info);
void xhci_update_tt_active_eps(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
int old_active_eps);
@@ -1806,7 +1962,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_trbs, gfp_t flags);
-void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
+void xhci_free_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,
@@ -1841,53 +1997,25 @@ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
void xhci_quiesce(struct xhci_hcd *xhci);
int xhci_halt(struct xhci_hcd *xhci);
+int xhci_start(struct xhci_hcd *xhci);
int xhci_reset(struct xhci_hcd *xhci);
-int xhci_init(struct usb_hcd *hcd);
int xhci_run(struct usb_hcd *hcd);
-void xhci_stop(struct usb_hcd *hcd);
-void xhci_shutdown(struct usb_hcd *hcd);
int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
void xhci_init_driver(struct hc_driver *drv,
const struct xhci_driver_overrides *over);
+int xhci_disable_slot(struct xhci_hcd *xhci,
+ struct xhci_command *command, u32 slot_id);
-#ifdef CONFIG_PM
int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
-#else
-#define xhci_suspend NULL
-#define xhci_resume NULL
-#endif
-int xhci_get_frame(struct usb_hcd *hcd);
irqreturn_t xhci_irq(struct usb_hcd *hcd);
irqreturn_t xhci_msi_irq(int irq, void *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_tt_info(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
-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_enable_device(struct usb_hcd *hcd, struct usb_device *udev);
-int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev);
-int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
- struct usb_device *udev, int enable);
-int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
- struct usb_tt *tt, gfp_t mem_flags);
-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_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev);
-int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
-void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
/* xHCI ring, segment, TRB, and TD functions */
dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
@@ -1918,7 +2046,8 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci,
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd,
dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed);
int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd,
- int slot_id, unsigned int ep_index);
+ int slot_id, unsigned int ep_index,
+ enum xhci_ep_reset_type reset_type);
int xhci_queue_reset_device(struct xhci_hcd *xhci, struct xhci_command *cmd,
u32 slot_id);
void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
@@ -1927,13 +2056,9 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
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,
- unsigned int ep_index, struct xhci_td *td);
-void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
- unsigned int slot_id, unsigned int ep_index,
struct xhci_dequeue_state *deq_state);
+void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index,
+ unsigned int stream_id, struct xhci_td *td);
void xhci_stop_endpoint_command_watchdog(unsigned long arg);
void xhci_handle_command_timeout(struct work_struct *work);
@@ -1944,16 +2069,13 @@ void xhci_cleanup_command_queue(struct xhci_hcd *xhci);
/* xHCI roothub code */
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 link_state);
-int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
- struct usb_device *udev, enum usb3_link_state state);
-int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
- struct usb_device *udev, enum usb3_link_state state);
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 port_bit);
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);
int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
+void xhci_hc_died(struct xhci_hcd *xhci);
#ifdef CONFIG_PM
int xhci_bus_suspend(struct usb_hcd *hcd);
@@ -1984,4 +2106,383 @@ static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
urb->stream_id);
}
+static inline char *xhci_slot_state_string(u32 state)
+{
+ switch (state) {
+ case SLOT_STATE_ENABLED:
+ return "enabled/disabled";
+ case SLOT_STATE_DEFAULT:
+ return "default";
+ case SLOT_STATE_ADDRESSED:
+ return "addressed";
+ case SLOT_STATE_CONFIGURED:
+ return "configured";
+ default:
+ return "reserved";
+ }
+}
+
+static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2,
+ u32 field3)
+{
+ static char str[256];
+ int type = TRB_FIELD_TO_TYPE(field3);
+
+ switch (type) {
+ case TRB_LINK:
+ sprintf(str,
+ "LINK %08x%08x intr %d type '%s' flags %c:%c:%c:%c",
+ field1, field0, GET_INTR_TARGET(field2),
+ xhci_trb_type_string(type),
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CHAIN ? 'C' : 'c',
+ field3 & TRB_TC ? 'T' : 't',
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_TRANSFER:
+ case TRB_COMPLETION:
+ case TRB_PORT_STATUS:
+ case TRB_BANDWIDTH_EVENT:
+ case TRB_DOORBELL:
+ case TRB_HC_EVENT:
+ case TRB_DEV_NOTE:
+ case TRB_MFINDEX_WRAP:
+ sprintf(str,
+ "TRB %08x%08x status '%s' len %d slot %d ep %d type '%s' flags %c:%c",
+ field1, field0,
+ xhci_trb_comp_code_string(GET_COMP_CODE(field2)),
+ EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3),
+ /* Macro decrements 1, maybe it shouldn't?!? */
+ TRB_TO_EP_INDEX(field3) + 1,
+ xhci_trb_type_string(type),
+ field3 & EVENT_DATA ? 'E' : 'e',
+ field3 & TRB_CYCLE ? 'C' : 'c');
+
+ break;
+ case TRB_SETUP:
+ sprintf(str, "bRequestType %02x bRequest %02x wValue %02x%02x wIndex %02x%02x wLength %d length %d TD size %d intr %d type '%s' flags %c:%c:%c",
+ field0 & 0xff,
+ (field0 & 0xff00) >> 8,
+ (field0 & 0xff000000) >> 24,
+ (field0 & 0xff0000) >> 16,
+ (field1 & 0xff00) >> 8,
+ field1 & 0xff,
+ (field1 & 0xff000000) >> 16 |
+ (field1 & 0xff0000) >> 16,
+ TRB_LEN(field2), GET_TD_SIZE(field2),
+ GET_INTR_TARGET(field2),
+ xhci_trb_type_string(type),
+ field3 & TRB_IDT ? 'I' : 'i',
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_DATA:
+ sprintf(str, "Buffer %08x%08x length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c:%c:%c:%c",
+ field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2),
+ GET_INTR_TARGET(field2),
+ xhci_trb_type_string(type),
+ field3 & TRB_IDT ? 'I' : 'i',
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CHAIN ? 'C' : 'c',
+ field3 & TRB_NO_SNOOP ? 'S' : 's',
+ field3 & TRB_ISP ? 'I' : 'i',
+ field3 & TRB_ENT ? 'E' : 'e',
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_STATUS:
+ sprintf(str, "Buffer %08x%08x length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c",
+ field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2),
+ GET_INTR_TARGET(field2),
+ xhci_trb_type_string(type),
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CHAIN ? 'C' : 'c',
+ field3 & TRB_ENT ? 'E' : 'e',
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_NORMAL:
+ case TRB_ISOC:
+ case TRB_EVENT_DATA:
+ case TRB_TR_NOOP:
+ sprintf(str,
+ "Buffer %08x%08x length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c:%c:%c:%c:%c",
+ field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2),
+ GET_INTR_TARGET(field2),
+ xhci_trb_type_string(type),
+ field3 & TRB_BEI ? 'B' : 'b',
+ field3 & TRB_IDT ? 'I' : 'i',
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CHAIN ? 'C' : 'c',
+ field3 & TRB_NO_SNOOP ? 'S' : 's',
+ field3 & TRB_ISP ? 'I' : 'i',
+ field3 & TRB_ENT ? 'E' : 'e',
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+
+ case TRB_CMD_NOOP:
+ case TRB_ENABLE_SLOT:
+ sprintf(str,
+ "%s: flags %c",
+ xhci_trb_type_string(type),
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_DISABLE_SLOT:
+ case TRB_NEG_BANDWIDTH:
+ sprintf(str,
+ "%s: slot %d flags %c",
+ xhci_trb_type_string(type),
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_ADDR_DEV:
+ sprintf(str,
+ "%s: ctx %08x%08x slot %d flags %c:%c",
+ xhci_trb_type_string(type),
+ field1, field0,
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_BSR ? 'B' : 'b',
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_CONFIG_EP:
+ sprintf(str,
+ "%s: ctx %08x%08x slot %d flags %c:%c",
+ xhci_trb_type_string(type),
+ field1, field0,
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_DC ? 'D' : 'd',
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_EVAL_CONTEXT:
+ sprintf(str,
+ "%s: ctx %08x%08x slot %d flags %c",
+ xhci_trb_type_string(type),
+ field1, field0,
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_RESET_EP:
+ sprintf(str,
+ "%s: ctx %08x%08x slot %d ep %d flags %c",
+ xhci_trb_type_string(type),
+ field1, field0,
+ TRB_TO_SLOT_ID(field3),
+ /* Macro decrements 1, maybe it shouldn't?!? */
+ TRB_TO_EP_INDEX(field3) + 1,
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_STOP_RING:
+ sprintf(str,
+ "%s: slot %d sp %d ep %d flags %c",
+ xhci_trb_type_string(type),
+ TRB_TO_SLOT_ID(field3),
+ TRB_TO_SUSPEND_PORT(field3),
+ /* Macro decrements 1, maybe it shouldn't?!? */
+ TRB_TO_EP_INDEX(field3) + 1,
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_SET_DEQ:
+ sprintf(str,
+ "%s: deq %08x%08x stream %d slot %d ep %d flags %c",
+ xhci_trb_type_string(type),
+ field1, field0,
+ TRB_TO_STREAM_ID(field2),
+ TRB_TO_SLOT_ID(field3),
+ /* Macro decrements 1, maybe it shouldn't?!? */
+ TRB_TO_EP_INDEX(field3) + 1,
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_RESET_DEV:
+ sprintf(str,
+ "%s: slot %d flags %c",
+ xhci_trb_type_string(type),
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_FORCE_EVENT:
+ sprintf(str,
+ "%s: event %08x%08x vf intr %d vf id %d flags %c",
+ xhci_trb_type_string(type),
+ field1, field0,
+ TRB_TO_VF_INTR_TARGET(field2),
+ TRB_TO_VF_ID(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_SET_LT:
+ sprintf(str,
+ "%s: belt %d flags %c",
+ xhci_trb_type_string(type),
+ TRB_TO_BELT(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_GET_BW:
+ sprintf(str,
+ "%s: ctx %08x%08x slot %d speed %d flags %c",
+ xhci_trb_type_string(type),
+ field1, field0,
+ TRB_TO_SLOT_ID(field3),
+ TRB_TO_DEV_SPEED(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ case TRB_FORCE_HEADER:
+ sprintf(str,
+ "%s: info %08x%08x%08x pkt type %d roothub port %d flags %c",
+ xhci_trb_type_string(type),
+ field2, field1, field0 & 0xffffffe0,
+ TRB_TO_PACKET_TYPE(field0),
+ TRB_TO_ROOTHUB_PORT(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
+ break;
+ default:
+ sprintf(str,
+ "type '%s' -> raw %08x %08x %08x %08x",
+ xhci_trb_type_string(type),
+ field0, field1, field2, field3);
+ }
+
+ return str;
+}
+
+static inline const char *xhci_decode_slot_context(u32 info, u32 info2,
+ u32 tt_info, u32 state)
+{
+ static char str[1024];
+ u32 speed;
+ u32 hub;
+ u32 mtt;
+ int ret = 0;
+
+ speed = info & DEV_SPEED;
+ hub = info & DEV_HUB;
+ mtt = info & DEV_MTT;
+
+ ret = sprintf(str, "RS %05x %s%s%s Ctx Entries %d MEL %d us Port# %d/%d",
+ info & ROUTE_STRING_MASK,
+ ({ char *s;
+ switch (speed) {
+ case SLOT_SPEED_FS:
+ s = "full-speed";
+ break;
+ case SLOT_SPEED_LS:
+ s = "low-speed";
+ break;
+ case SLOT_SPEED_HS:
+ s = "high-speed";
+ break;
+ case SLOT_SPEED_SS:
+ s = "super-speed";
+ break;
+ case SLOT_SPEED_SSP:
+ s = "super-speed plus";
+ break;
+ default:
+ s = "UNKNOWN speed";
+ } s; }),
+ mtt ? " multi-TT" : "",
+ hub ? " Hub" : "",
+ (info & LAST_CTX_MASK) >> 27,
+ info2 & MAX_EXIT,
+ DEVINFO_TO_ROOT_HUB_PORT(info2),
+ DEVINFO_TO_MAX_PORTS(info2));
+
+ ret += sprintf(str + ret, " [TT Slot %d Port# %d TTT %d Intr %d] Addr %d State %s",
+ tt_info & TT_SLOT, (tt_info & TT_PORT) >> 8,
+ GET_TT_THINK_TIME(tt_info), GET_INTR_TARGET(tt_info),
+ state & DEV_ADDR_MASK,
+ xhci_slot_state_string(GET_SLOT_STATE(state)));
+
+ return str;
+}
+
+static inline const char *xhci_ep_state_string(u8 state)
+{
+ switch (state) {
+ case EP_STATE_DISABLED:
+ return "disabled";
+ case EP_STATE_RUNNING:
+ return "running";
+ case EP_STATE_HALTED:
+ return "halted";
+ case EP_STATE_STOPPED:
+ return "stopped";
+ case EP_STATE_ERROR:
+ return "error";
+ default:
+ return "INVALID";
+ }
+}
+
+static inline const char *xhci_ep_type_string(u8 type)
+{
+ switch (type) {
+ case ISOC_OUT_EP:
+ return "Isoc OUT";
+ case BULK_OUT_EP:
+ return "Bulk OUT";
+ case INT_OUT_EP:
+ return "Int OUT";
+ case CTRL_EP:
+ return "Ctrl";
+ case ISOC_IN_EP:
+ return "Isoc IN";
+ case BULK_IN_EP:
+ return "Bulk IN";
+ case INT_IN_EP:
+ return "Int IN";
+ default:
+ return "INVALID";
+ }
+}
+
+static inline const char *xhci_decode_ep_context(u32 info, u32 info2, u64 deq,
+ u32 tx_info)
+{
+ static char str[1024];
+ int ret;
+
+ u32 esit;
+ u16 maxp;
+ u16 avg;
+
+ u8 max_pstr;
+ u8 ep_state;
+ u8 interval;
+ u8 ep_type;
+ u8 burst;
+ u8 cerr;
+ u8 mult;
+ u8 lsa;
+ u8 hid;
+
+ esit = EP_MAX_ESIT_PAYLOAD_HI(info) << 16 |
+ EP_MAX_ESIT_PAYLOAD_LO(tx_info);
+
+ ep_state = info & EP_STATE_MASK;
+ max_pstr = info & EP_MAXPSTREAMS_MASK;
+ interval = CTX_TO_EP_INTERVAL(info);
+ mult = CTX_TO_EP_MULT(info) + 1;
+ lsa = info & EP_HAS_LSA;
+
+ cerr = (info2 & (3 << 1)) >> 1;
+ ep_type = CTX_TO_EP_TYPE(info2);
+ hid = info2 & (1 << 7);
+ burst = CTX_TO_MAX_BURST(info2);
+ maxp = MAX_PACKET_DECODED(info2);
+
+ avg = EP_AVG_TRB_LENGTH(tx_info);
+
+ ret = sprintf(str, "State %s mult %d max P. Streams %d %s",
+ xhci_ep_state_string(ep_state), mult,
+ max_pstr, lsa ? "LSA " : "");
+
+ ret += sprintf(str + ret, "interval %d us max ESIT payload %d CErr %d ",
+ (1 << interval) * 125, esit, cerr);
+
+ ret += sprintf(str + ret, "Type %s %sburst %d maxp %d deq %016llx ",
+ xhci_ep_type_string(ep_type), hid ? "HID" : "",
+ burst, maxp, deq);
+
+ ret += sprintf(str + ret, "avg trb len %d", avg);
+
+ return str;
+}
+
#endif /* __LINUX_XHCI_HCD_H */