]>
Commit | Line | Data |
---|---|---|
b2758999 GKH |
1 | From ec7e43e2d98173483866fe2e4e690143626b659c Mon Sep 17 00:00:00 2001 |
2 | From: Mathias Nyman <mathias.nyman@linux.intel.com> | |
3 | Date: Fri, 30 Aug 2013 18:25:49 +0300 | |
4 | Subject: xhci: Ensure a command structure points to the correct trb on the command ring | |
5 | ||
6 | From: Mathias Nyman <mathias.nyman@linux.intel.com> | |
7 | ||
8 | commit ec7e43e2d98173483866fe2e4e690143626b659c upstream. | |
9 | ||
10 | If a command on the command ring needs to be cancelled before it is handled | |
11 | it can be turned to a no-op operation when the ring is stopped. | |
12 | We want to store the command ring enqueue pointer in the command structure | |
13 | when the command in enqueued for the cancellation case. | |
14 | ||
15 | Some commands used to store the command ring dequeue pointers instead of enqueue | |
16 | (these often worked because enqueue happends to equal dequeue quite often) | |
17 | ||
18 | Other commands correctly used the enqueue pointer but did not check if it pointed | |
19 | to a valid trb or a link trb, this caused for example stop endpoint command to timeout in | |
20 | xhci_stop_device() in about 2% of suspend/resume cases. | |
21 | ||
22 | This should also solve some weird behavior happening in command cancellation cases. | |
23 | ||
24 | This patch is based on a patch submitted by Sarah Sharp to linux-usb, but | |
25 | then forgotten: | |
26 | http://marc.info/?l=linux-usb&m=136269803207465&w=2 | |
27 | ||
28 | This patch should be backported to kernels as old as 3.7, that contain | |
29 | the commit b92cc66c047ff7cf587b318fe377061a353c120f "xHCI: add aborting | |
30 | command ring function" | |
31 | ||
32 | Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> | |
33 | Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> | |
34 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
35 | ||
36 | --- | |
37 | drivers/usb/host/xhci-hub.c | 2 +- | |
38 | drivers/usb/host/xhci-ring.c | 10 ++++++++++ | |
39 | drivers/usb/host/xhci.c | 25 +++++-------------------- | |
40 | drivers/usb/host/xhci.h | 1 + | |
41 | 4 files changed, 17 insertions(+), 21 deletions(-) | |
42 | ||
43 | --- a/drivers/usb/host/xhci-hub.c | |
44 | +++ b/drivers/usb/host/xhci-hub.c | |
45 | @@ -287,7 +287,7 @@ static int xhci_stop_device(struct xhci_ | |
46 | if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) | |
47 | xhci_queue_stop_endpoint(xhci, slot_id, i, suspend); | |
48 | } | |
49 | - cmd->command_trb = xhci->cmd_ring->enqueue; | |
50 | + cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring); | |
51 | list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list); | |
52 | xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend); | |
53 | xhci_ring_cmd_db(xhci); | |
54 | --- a/drivers/usb/host/xhci-ring.c | |
55 | +++ b/drivers/usb/host/xhci-ring.c | |
56 | @@ -122,6 +122,16 @@ static int enqueue_is_link_trb(struct xh | |
57 | return TRB_TYPE_LINK_LE32(link->control); | |
58 | } | |
59 | ||
60 | +union xhci_trb *xhci_find_next_enqueue(struct xhci_ring *ring) | |
61 | +{ | |
62 | + /* Enqueue pointer can be left pointing to the link TRB, | |
63 | + * we must handle that | |
64 | + */ | |
65 | + if (TRB_TYPE_LINK_LE32(ring->enqueue->link.control)) | |
66 | + return ring->enq_seg->next->trbs; | |
67 | + return ring->enqueue; | |
68 | +} | |
69 | + | |
70 | /* Updates trb to point to the next TRB in the ring, and updates seg if the next | |
71 | * TRB is in a new segment. This does not skip over link TRBs, and it does not | |
72 | * effect the ring dequeue or enqueue pointers. | |
73 | --- a/drivers/usb/host/xhci.c | |
74 | +++ b/drivers/usb/host/xhci.c | |
75 | @@ -2582,15 +2582,7 @@ static int xhci_configure_endpoint(struc | |
76 | if (command) { | |
77 | cmd_completion = command->completion; | |
78 | cmd_status = &command->status; | |
79 | - command->command_trb = xhci->cmd_ring->enqueue; | |
80 | - | |
81 | - /* Enqueue pointer can be left pointing to the link TRB, | |
82 | - * we must handle that | |
83 | - */ | |
84 | - if (TRB_TYPE_LINK_LE32(command->command_trb->link.control)) | |
85 | - command->command_trb = | |
86 | - xhci->cmd_ring->enq_seg->next->trbs; | |
87 | - | |
88 | + command->command_trb = xhci_find_next_enqueue(xhci->cmd_ring); | |
89 | list_add_tail(&command->cmd_list, &virt_dev->cmd_list); | |
90 | } else { | |
91 | cmd_completion = &virt_dev->cmd_completion; | |
92 | @@ -2598,7 +2590,7 @@ static int xhci_configure_endpoint(struc | |
93 | } | |
94 | init_completion(cmd_completion); | |
95 | ||
96 | - cmd_trb = xhci->cmd_ring->dequeue; | |
97 | + cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); | |
98 | if (!ctx_change) | |
99 | ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, | |
100 | udev->slot_id, must_succeed); | |
101 | @@ -3383,14 +3375,7 @@ int xhci_discover_or_reset_device(struct | |
102 | ||
103 | /* Attempt to submit the Reset Device command to the command ring */ | |
104 | spin_lock_irqsave(&xhci->lock, flags); | |
105 | - reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; | |
106 | - | |
107 | - /* Enqueue pointer can be left pointing to the link TRB, | |
108 | - * we must handle that | |
109 | - */ | |
110 | - if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control)) | |
111 | - reset_device_cmd->command_trb = | |
112 | - xhci->cmd_ring->enq_seg->next->trbs; | |
113 | + reset_device_cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring); | |
114 | ||
115 | list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); | |
116 | ret = xhci_queue_reset_device(xhci, slot_id); | |
117 | @@ -3594,7 +3579,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, | |
118 | union xhci_trb *cmd_trb; | |
119 | ||
120 | spin_lock_irqsave(&xhci->lock, flags); | |
121 | - cmd_trb = xhci->cmd_ring->dequeue; | |
122 | + cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); | |
123 | ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0); | |
124 | if (ret) { | |
125 | spin_unlock_irqrestore(&xhci->lock, flags); | |
126 | @@ -3721,7 +3706,7 @@ int xhci_address_device(struct usb_hcd * | |
127 | xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); | |
128 | ||
129 | spin_lock_irqsave(&xhci->lock, flags); | |
130 | - cmd_trb = xhci->cmd_ring->dequeue; | |
131 | + cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); | |
132 | ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, | |
133 | udev->slot_id); | |
134 | if (ret) { | |
135 | --- a/drivers/usb/host/xhci.h | |
136 | +++ b/drivers/usb/host/xhci.h | |
137 | @@ -1811,6 +1811,7 @@ int xhci_cancel_cmd(struct xhci_hcd *xhc | |
138 | union xhci_trb *cmd_trb); | |
139 | void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, | |
140 | unsigned int ep_index, unsigned int stream_id); | |
141 | +union xhci_trb *xhci_find_next_enqueue(struct xhci_ring *ring); | |
142 | ||
143 | /* xHCI roothub code */ | |
144 | void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, |