]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.0.49/xhci-handle-command-after-aborting-the-command-ring.patch
Fixes for 4.19
[thirdparty/kernel/stable-queue.git] / releases / 3.0.49 / xhci-handle-command-after-aborting-the-command-ring.patch
1 From b63f4053cc8aa22a98e3f9a97845afe6c15d0a0d Mon Sep 17 00:00:00 2001
2 From: Elric Fu <elricfu1@gmail.com>
3 Date: Wed, 27 Jun 2012 16:55:43 +0800
4 Subject: xHCI: handle command after aborting the command ring
5
6 From: Elric Fu <elricfu1@gmail.com>
7
8 commit b63f4053cc8aa22a98e3f9a97845afe6c15d0a0d upstream.
9
10 According to xHCI spec section 4.6.1.1 and section 4.6.1.2,
11 after aborting a command on the command ring, xHC will
12 generate a command completion event with its completion
13 code set to Command Ring Stopped at least. If a command is
14 currently executing at the time of aborting a command, xHC
15 also generate a command completion event with its completion
16 code set to Command Abort. When the command ring is stopped,
17 software may remove, add, or rearrage Command Descriptors.
18
19 To cancel a command, software will initialize a command
20 descriptor for the cancel command, and add it into a
21 cancel_cmd_list of xhci. When the command ring is stopped,
22 software will find the command trbs described by command
23 descriptors in cancel_cmd_list and modify it to No Op
24 command. If software can't find the matched trbs, we can
25 think it had been finished.
26
27 This patch should be backported to kernels as old as 3.0, that contain
28 the commit 7ed603ecf8b68ab81f4c83097d3063d43ec73bb8 "xhci: Add an
29 assertion to check for virt_dev=0 bug." That commit papers over a NULL
30 pointer dereference, and this patch fixes the underlying issue that
31 caused the NULL pointer dereference.
32
33 Note from Sarah: The TRB_TYPE_LINK_LE32 macro is not in the 3.0 stable
34 kernel, so I added it to this patch.
35
36 Signed-off-by: Elric Fu <elricfu1@gmail.com>
37 Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
38 Tested-by: Miroslav Sabljic <miroslav.sabljic@avl.com>
39 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
40
41
42 ---
43 drivers/usb/host/xhci-ring.c | 171 +++++++++++++++++++++++++++++++++++++++++--
44 drivers/usb/host/xhci.h | 3
45 2 files changed, 168 insertions(+), 6 deletions(-)
46
47 --- a/drivers/usb/host/xhci-ring.c
48 +++ b/drivers/usb/host/xhci-ring.c
49 @@ -1157,6 +1157,20 @@ static void handle_reset_ep_completion(s
50 }
51 }
52
53 +/* Complete the command and detele it from the devcie's command queue.
54 + */
55 +static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
56 + struct xhci_command *command, u32 status)
57 +{
58 + command->status = status;
59 + list_del(&command->cmd_list);
60 + if (command->completion)
61 + complete(command->completion);
62 + else
63 + xhci_free_command(xhci, command);
64 +}
65 +
66 +
67 /* Check to see if a command in the device's command queue matches this one.
68 * Signal the completion or free the command, and return 1. Return 0 if the
69 * completed command isn't at the head of the command list.
70 @@ -1175,15 +1189,144 @@ static int handle_cmd_in_cmd_wait_list(s
71 if (xhci->cmd_ring->dequeue != command->command_trb)
72 return 0;
73
74 - command->status = GET_COMP_CODE(le32_to_cpu(event->status));
75 - list_del(&command->cmd_list);
76 - if (command->completion)
77 - complete(command->completion);
78 - else
79 - xhci_free_command(xhci, command);
80 + xhci_complete_cmd_in_cmd_wait_list(xhci, command,
81 + GET_COMP_CODE(le32_to_cpu(event->status)));
82 return 1;
83 }
84
85 +/*
86 + * Finding the command trb need to be cancelled and modifying it to
87 + * NO OP command. And if the command is in device's command wait
88 + * list, finishing and freeing it.
89 + *
90 + * If we can't find the command trb, we think it had already been
91 + * executed.
92 + */
93 +static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd)
94 +{
95 + struct xhci_segment *cur_seg;
96 + union xhci_trb *cmd_trb;
97 + u32 cycle_state;
98 +
99 + if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
100 + return;
101 +
102 + /* find the current segment of command ring */
103 + cur_seg = find_trb_seg(xhci->cmd_ring->first_seg,
104 + xhci->cmd_ring->dequeue, &cycle_state);
105 +
106 + /* find the command trb matched by cd from command ring */
107 + for (cmd_trb = xhci->cmd_ring->dequeue;
108 + cmd_trb != xhci->cmd_ring->enqueue;
109 + next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) {
110 + /* If the trb is link trb, continue */
111 + if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3]))
112 + continue;
113 +
114 + if (cur_cd->cmd_trb == cmd_trb) {
115 +
116 + /* If the command in device's command list, we should
117 + * finish it and free the command structure.
118 + */
119 + if (cur_cd->command)
120 + xhci_complete_cmd_in_cmd_wait_list(xhci,
121 + cur_cd->command, COMP_CMD_STOP);
122 +
123 + /* get cycle state from the origin command trb */
124 + cycle_state = le32_to_cpu(cmd_trb->generic.field[3])
125 + & TRB_CYCLE;
126 +
127 + /* modify the command trb to NO OP command */
128 + cmd_trb->generic.field[0] = 0;
129 + cmd_trb->generic.field[1] = 0;
130 + cmd_trb->generic.field[2] = 0;
131 + cmd_trb->generic.field[3] = cpu_to_le32(
132 + TRB_TYPE(TRB_CMD_NOOP) | cycle_state);
133 + break;
134 + }
135 + }
136 +}
137 +
138 +static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci)
139 +{
140 + struct xhci_cd *cur_cd, *next_cd;
141 +
142 + if (list_empty(&xhci->cancel_cmd_list))
143 + return;
144 +
145 + list_for_each_entry_safe(cur_cd, next_cd,
146 + &xhci->cancel_cmd_list, cancel_cmd_list) {
147 + xhci_cmd_to_noop(xhci, cur_cd);
148 + list_del(&cur_cd->cancel_cmd_list);
149 + kfree(cur_cd);
150 + }
151 +}
152 +
153 +/*
154 + * traversing the cancel_cmd_list. If the command descriptor according
155 + * to cmd_trb is found, the function free it and return 1, otherwise
156 + * return 0.
157 + */
158 +static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci,
159 + union xhci_trb *cmd_trb)
160 +{
161 + struct xhci_cd *cur_cd, *next_cd;
162 +
163 + if (list_empty(&xhci->cancel_cmd_list))
164 + return 0;
165 +
166 + list_for_each_entry_safe(cur_cd, next_cd,
167 + &xhci->cancel_cmd_list, cancel_cmd_list) {
168 + if (cur_cd->cmd_trb == cmd_trb) {
169 + if (cur_cd->command)
170 + xhci_complete_cmd_in_cmd_wait_list(xhci,
171 + cur_cd->command, COMP_CMD_STOP);
172 + list_del(&cur_cd->cancel_cmd_list);
173 + kfree(cur_cd);
174 + return 1;
175 + }
176 + }
177 +
178 + return 0;
179 +}
180 +
181 +/*
182 + * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the
183 + * trb pointed by the command ring dequeue pointer is the trb we want to
184 + * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will
185 + * traverse the cancel_cmd_list to trun the all of the commands according
186 + * to command descriptor to NO-OP trb.
187 + */
188 +static int handle_stopped_cmd_ring(struct xhci_hcd *xhci,
189 + int cmd_trb_comp_code)
190 +{
191 + int cur_trb_is_good = 0;
192 +
193 + /* Searching the cmd trb pointed by the command ring dequeue
194 + * pointer in command descriptor list. If it is found, free it.
195 + */
196 + cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci,
197 + xhci->cmd_ring->dequeue);
198 +
199 + if (cmd_trb_comp_code == COMP_CMD_ABORT)
200 + xhci->cmd_ring_state = CMD_RING_STATE_STOPPED;
201 + else if (cmd_trb_comp_code == COMP_CMD_STOP) {
202 + /* traversing the cancel_cmd_list and canceling
203 + * the command according to command descriptor
204 + */
205 + xhci_cancel_cmd_in_cd_list(xhci);
206 +
207 + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
208 + /*
209 + * ring command ring doorbell again to restart the
210 + * command ring
211 + */
212 + if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue)
213 + xhci_ring_cmd_db(xhci);
214 + }
215 + return cur_trb_is_good;
216 +}
217 +
218 static void handle_cmd_completion(struct xhci_hcd *xhci,
219 struct xhci_event_cmd *event)
220 {
221 @@ -1209,6 +1352,22 @@ static void handle_cmd_completion(struct
222 xhci->error_bitmask |= 1 << 5;
223 return;
224 }
225 +
226 + if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
227 + (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
228 + /* If the return value is 0, we think the trb pointed by
229 + * command ring dequeue pointer is a good trb. The good
230 + * trb means we don't want to cancel the trb, but it have
231 + * been stopped by host. So we should handle it normally.
232 + * Otherwise, driver should invoke inc_deq() and return.
233 + */
234 + if (handle_stopped_cmd_ring(xhci,
235 + GET_COMP_CODE(le32_to_cpu(event->status)))) {
236 + inc_deq(xhci, xhci->cmd_ring, false);
237 + return;
238 + }
239 + }
240 +
241 switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
242 & TRB_TYPE_BITMASK) {
243 case TRB_TYPE(TRB_ENABLE_SLOT):
244 --- a/drivers/usb/host/xhci.h
245 +++ b/drivers/usb/host/xhci.h
246 @@ -1070,6 +1070,9 @@ union xhci_trb {
247 #define TRB_MFINDEX_WRAP 39
248 /* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
249
250 +#define TRB_TYPE_LINK_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \
251 + cpu_to_le32(TRB_TYPE(TRB_LINK)))
252 +
253 /* Nec vendor-specific command completion event. */
254 #define TRB_NEC_CMD_COMP 48
255 /* Get NEC firmware revision. */