From b83cdc8f4d94a127e9319bef37f384b01ecca72e Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Thu, 5 May 2011 18:13:56 +0800 Subject: [PATCH 1/6] xHCI 1.0: Setup Stage TRB Transfer Type flag Setup Stage Transfer Type field is added to indicate the presence and the direction of the Data Stage TD, and determines the direction of the Status Stage TD so the wLength length field should be ignored by the xHC. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-ring.c | 11 +++++++++++ drivers/usb/host/xhci.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 396f8d2a2e8d..3e759af049b7 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3053,6 +3053,17 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field |= TRB_IDT | TRB_TYPE(TRB_SETUP); if (start_cycle == 0) field |= 0x1; + + /* xHCI 1.0 6.4.1.2.1: Transfer Type field */ + if (xhci->hci_version == 0x100) { + if (urb->transfer_buffer_length > 0) { + if (setup->bRequestType & USB_DIR_IN) + field |= TRB_TX_TYPE(TRB_DATA_IN); + else + field |= TRB_TX_TYPE(TRB_DATA_OUT); + } + } + queue_trb(xhci, ep_ring, false, true, setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16, le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index db661543a805..af8b66f2fd00 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -967,6 +967,9 @@ struct xhci_event_cmd { /* Control transfer TRB specific fields */ #define TRB_DIR_IN (1<<16) +#define TRB_TX_TYPE(p) ((p) << 16) +#define TRB_DATA_OUT 2 +#define TRB_DATA_IN 3 /* Isochronous TRB specific fields */ #define TRB_SIA (1<<31) From 51eb01a746089f2c3d9b87f870353772d2fb4c37 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Thu, 5 May 2011 18:13:58 +0800 Subject: [PATCH 2/6] xHCI 1.0: Control endpoint average TRB length field set xHCI 1.0 specification indicates that software should set Average TRB Length to '8' for control endpoints. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-mem.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index a4fc4d929385..543833b9dbad 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1246,8 +1246,15 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, * including link TRBs, No-op TRBs, and Event data TRBs. Since we don't * use Event Data TRBs, and we don't chain in a link TRB on short * transfers, we're basically dividing by 1. + * + * xHCI 1.0 specification indicates that the Average TRB Length should + * be set to 8 for control endpoints. */ - ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(max_esit_payload)); + if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version == 0x100) + ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8)); + else + ep_ctx->tx_info |= + cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(max_esit_payload)); /* FIXME Debug endpoint context */ return 0; From 7b1fc2ea8a5fbf9487d83865456cff77d0249ea9 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Thu, 5 May 2011 18:14:00 +0800 Subject: [PATCH 3/6] xHCI 1.0: Isoch endpoint CErr field set xHCI 1.0 specification specifies that CErr does not apply to Isoch endpoints and shall be set to '0' for Isoch endpoints. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 543833b9dbad..04145740686c 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1190,12 +1190,12 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, /* FIXME dig Mult and streams info out of ep companion desc */ /* Allow 3 retries for everything but isoc; - * error count = 0 means infinite retries. + * CErr shall be set to 0 for Isoch endpoints. */ if (!usb_endpoint_xfer_isoc(&ep->desc)) ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(3)); else - ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(1)); + ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(0)); ep_ctx->ep_info2 |= cpu_to_le32(xhci_get_endpoint_type(udev, ep)); From ad106f292369d753d5c75751cb9e760726e3cd00 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Thu, 5 May 2011 18:14:02 +0800 Subject: [PATCH 4/6] xHCI 1.0: Block Interrupts for Isoch transfer Currently an isoc URB is divided into multiple TDs, and every TD will trigger an interrupt when it's processed. However, software can schedule multiple TDs at a time, and it only needs an interrupt every URB. xHCI 1.0 introduces the Block Event Interrupt(BEI) flag which allows Normal and Isoch Transfer TRBs to place an Event TRB on an Event Ring but not assert an intrrupt to the host, and the interrupt rate is significantly reduced and the system performance is improved. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-ring.c | 5 +++++ drivers/usb/host/xhci.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3e759af049b7..c35058b94de6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3293,6 +3293,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } else { td->last_trb = ep_ring->enqueue; field |= TRB_IOC; + if (xhci->hci_version == 0x100) { + /* Set BEI bit except for the last td */ + if (i < num_tds - 1) + field |= TRB_BEI; + } more_trbs_coming = false; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index af8b66f2fd00..33a49d5d6c22 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -964,6 +964,8 @@ struct xhci_event_cmd { /* The buffer pointer contains immediate data */ #define TRB_IDT (1<<6) +/* Block Event Interrupt */ +#define TRB_BEI (1<<9) /* Control transfer TRB specific fields */ #define TRB_DIR_IN (1<<16) From 700b41736c07f357df0a1b8f342fd237f365b58d Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Thu, 5 May 2011 18:14:05 +0800 Subject: [PATCH 5/6] xHCI 1.0: TT_THINK_TIME set xHCI 1.0 spec says the TT Think Time field shall be set to zero if the device is not a High-speed hub. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6864759c8d1a..3abf33223b1c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2699,11 +2699,16 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, /* Set TT think time - convert from ns to FS bit times. * 0 = 8 FS bit times, 1 = 16 FS bit times, * 2 = 24 FS bit times, 3 = 32 FS bit times. + * + * xHCI 1.0: this field shall be 0 if the device is not a + * High-spped hub. */ think_time = tt->think_time; if (think_time != 0) think_time = (think_time / 666) - 1; - slot_ctx->tt_info |= cpu_to_le32(TT_THINK_TIME(think_time)); + if (xhci->hci_version < 0x100 || hdev->speed == USB_SPEED_HIGH) + slot_ctx->tt_info |= + cpu_to_le32(TT_THINK_TIME(think_time)); } else { xhci_dbg(xhci, "xHCI version %x doesn't need hub " "TT think time or number of ports\n", From 1bb73a88839d473f4f2c529ecf453029439aa837 Mon Sep 17 00:00:00 2001 From: Alex He Date: Thu, 5 May 2011 18:14:12 +0800 Subject: [PATCH 6/6] xHCI 1.0: Max Exit Latency Too Large Error This is a new TRB Completion Code of the xHCI spec 1.0. Asserted by the Evalute Context Command if the proposed Max Exit Latency would not allow the periodic endpoints of the Device Slot to be scheduled. Signed-off-by: Alex He Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci.c | 5 +++++ drivers/usb/host/xhci.h | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 3abf33223b1c..013e113b818a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1560,6 +1560,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1); ret = -EINVAL; break; + case COMP_MEL_ERR: + /* Max Exit Latency too large error */ + dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n"); + ret = -EINVAL; + break; case COMP_SUCCESS: dev_dbg(&udev->dev, "Successful evaluate context command\n"); ret = 0; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 33a49d5d6c22..e12db7cfb9bb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -881,7 +881,9 @@ struct xhci_transfer_event { #define COMP_STOP_INVAL 27 /* Control Abort Error - Debug Capability - control pipe aborted */ #define COMP_DBG_ABORT 28 -/* TRB type 29 and 30 reserved */ +/* 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" */