diff options
| author | Hans de Goede <hdegoede@redhat.com> | 2013-10-03 18:29:49 -0400 |
|---|---|---|
| committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2014-03-04 18:38:02 -0500 |
| commit | 9aad95e292f58d00aa0f2e30c7f7dafd7fc7491c (patch) | |
| tree | b0dda7e01959c435e0e4f08bb812e4f69bde3657 /drivers | |
| parent | 95241dbdf8281ece1355b8673b882d6a182f3c7d (diff) | |
xhci: For streams the dequeue ptr must be read from the stream ctx
This fixes TR dequeue validation failing on Intel XHCI controllers with the
following warning:
Mismatch between completed Set TR Deq Ptr command & xHCI internal state.
Interestingly enough reading the deq ptr from the ep ctx after a
TR Deq Ptr command does work on a Nec XHCI controller, it seems the Nec
writes the ptr to both the ep and stream contexts when streams are used.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 22 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 1 |
2 files changed, 16 insertions, 7 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f17e5c8c1cb3..b3d27e6467ea 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
| @@ -1081,12 +1081,14 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, | |||
| 1081 | unsigned int stream_id; | 1081 | unsigned int stream_id; |
| 1082 | struct xhci_ring *ep_ring; | 1082 | struct xhci_ring *ep_ring; |
| 1083 | struct xhci_virt_device *dev; | 1083 | struct xhci_virt_device *dev; |
| 1084 | struct xhci_virt_ep *ep; | ||
| 1084 | struct xhci_ep_ctx *ep_ctx; | 1085 | struct xhci_ep_ctx *ep_ctx; |
| 1085 | struct xhci_slot_ctx *slot_ctx; | 1086 | struct xhci_slot_ctx *slot_ctx; |
| 1086 | 1087 | ||
| 1087 | ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); | 1088 | ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); |
| 1088 | stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2])); | 1089 | stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2])); |
| 1089 | dev = xhci->devs[slot_id]; | 1090 | dev = xhci->devs[slot_id]; |
| 1091 | ep = &dev->eps[ep_index]; | ||
| 1090 | 1092 | ||
| 1091 | ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id); | 1093 | ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id); |
| 1092 | if (!ep_ring) { | 1094 | if (!ep_ring) { |
| @@ -1134,12 +1136,19 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, | |||
| 1134 | * cancelling URBs, which might not be an error... | 1136 | * cancelling URBs, which might not be an error... |
| 1135 | */ | 1137 | */ |
| 1136 | } else { | 1138 | } else { |
| 1139 | u64 deq; | ||
| 1140 | /* 4.6.10 deq ptr is written to the stream ctx for streams */ | ||
| 1141 | if (ep->ep_state & EP_HAS_STREAMS) { | ||
| 1142 | struct xhci_stream_ctx *ctx = | ||
| 1143 | &ep->stream_info->stream_ctx_array[stream_id]; | ||
| 1144 | deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK; | ||
| 1145 | } else { | ||
| 1146 | deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; | ||
| 1147 | } | ||
| 1137 | xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, | 1148 | xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, |
| 1138 | "Successful Set TR Deq Ptr cmd, deq = @%08llx", | 1149 | "Successful Set TR Deq Ptr cmd, deq = @%08llx", deq); |
| 1139 | le64_to_cpu(ep_ctx->deq)); | 1150 | if (xhci_trb_virt_to_dma(ep->queued_deq_seg, |
| 1140 | if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg, | 1151 | ep->queued_deq_ptr) == deq) { |
| 1141 | dev->eps[ep_index].queued_deq_ptr) == | ||
| 1142 | (le64_to_cpu(ep_ctx->deq) & ~(EP_CTX_CYCLE_MASK))) { | ||
| 1143 | /* Update the ring's dequeue segment and dequeue pointer | 1152 | /* Update the ring's dequeue segment and dequeue pointer |
| 1144 | * to reflect the new position. | 1153 | * to reflect the new position. |
| 1145 | */ | 1154 | */ |
| @@ -1148,8 +1157,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, | |||
| 1148 | } else { | 1157 | } else { |
| 1149 | xhci_warn(xhci, "Mismatch between completed Set TR Deq Ptr command & xHCI internal state.\n"); | 1158 | xhci_warn(xhci, "Mismatch between completed Set TR Deq Ptr command & xHCI internal state.\n"); |
| 1150 | xhci_warn(xhci, "ep deq seg = %p, deq ptr = %p\n", | 1159 | xhci_warn(xhci, "ep deq seg = %p, deq ptr = %p\n", |
| 1151 | dev->eps[ep_index].queued_deq_seg, | 1160 | ep->queued_deq_seg, ep->queued_deq_ptr); |
| 1152 | dev->eps[ep_index].queued_deq_ptr); | ||
| 1153 | } | 1161 | } |
| 1154 | } | 1162 | } |
| 1155 | 1163 | ||
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2c77bf7ab9e5..d280e9213d08 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
| @@ -703,6 +703,7 @@ struct xhci_ep_ctx { | |||
| 703 | 703 | ||
| 704 | /* deq bitmasks */ | 704 | /* deq bitmasks */ |
| 705 | #define EP_CTX_CYCLE_MASK (1 << 0) | 705 | #define EP_CTX_CYCLE_MASK (1 << 0) |
| 706 | #define SCTX_DEQ_MASK (~0xfL) | ||
| 706 | 707 | ||
| 707 | 708 | ||
| 708 | /** | 709 | /** |
