Skip to content

Commit a14d257

Browse files
authored
Merge pull request torvalds#222 from analogdevicesinc/fix-dwc3-4.14
Fix dwc3 crashes
2 parents 2350b4a + cd06a68 commit a14d257

File tree

7 files changed

+81
-106
lines changed

7 files changed

+81
-106
lines changed

drivers/usb/dwc3/core.h

+6
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ struct dwc3_event_buffer {
532532
* @pending_list: list of pending requests for this endpoint
533533
* @started_list: list of started requests on this endpoint
534534
* @wait_end_transfer: wait_queue_head_t for waiting on End Transfer complete
535+
* @aborted_trbs: Pointer to the first aborted TRB. These will be cleared at the
536+
* End of Transfer complete.
537+
* @num_aborted_trbs: Number of aborted TRBs.
535538
* @lock: spinlock for endpoint request queue traversal
536539
* @regs: pointer to first endpoint register
537540
* @trb_pool: array of transaction buffers
@@ -558,6 +561,9 @@ struct dwc3_ep {
558561

559562
wait_queue_head_t wait_end_transfer;
560563

564+
struct dwc3_trb *aborted_trbs;
565+
unsigned int num_aborted_trbs;
566+
561567
spinlock_t lock;
562568
void __iomem *regs;
563569

drivers/usb/dwc3/ep0.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
246246
struct dwc3_request *req;
247247

248248
req = next_request(&dep->pending_list);
249-
dwc3_gadget_giveback(dep, req, -ECONNRESET);
249+
dwc3_gadget_giveback(dep, req, -ECONNRESET, true);
250250
}
251251

252252
dwc->ep0state = EP0_SETUP_PHASE;
@@ -906,7 +906,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
906906
if (status == DWC3_TRBSTS_SETUP_PENDING) {
907907
dwc->setup_packet_pending = true;
908908
if (r)
909-
dwc3_gadget_giveback(ep0, r, -ECONNRESET);
909+
dwc3_gadget_giveback(ep0, r, -ECONNRESET, true);
910910

911911
return;
912912
}
@@ -932,7 +932,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
932932
if ((epnum & 1) && ur->actual < ur->length)
933933
dwc3_ep0_stall_and_restart(dwc);
934934
else
935-
dwc3_gadget_giveback(ep0, r, 0);
935+
dwc3_gadget_giveback(ep0, r, 0, true);
936936
}
937937

938938
static void dwc3_ep0_complete_status(struct dwc3 *dwc,
@@ -951,7 +951,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
951951
if (!list_empty(&dep->pending_list)) {
952952
r = next_request(&dep->pending_list);
953953

954-
dwc3_gadget_giveback(dep, r, 0);
954+
dwc3_gadget_giveback(dep, r, 0, true);
955955
}
956956

957957
if (dwc->test_mode) {

drivers/usb/dwc3/gadget.c

+60-91
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,12 @@ static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
185185
* layers that it has completed.
186186
*/
187187
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
188-
int status)
188+
int status, bool giveback)
189189
{
190190
struct dwc3 *dwc = dep->dwc;
191191

192192
req->started = false;
193-
list_del(&req->list);
193+
list_del_init(&req->list);
194194
req->remaining = 0;
195195

196196
if (req->request.status == -EINPROGRESS)
@@ -204,9 +204,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
204204

205205
trace_dwc3_gadget_giveback(req);
206206

207-
spin_unlock(&dwc->lock);
208-
usb_gadget_giveback_request(&dep->endpoint, &req->request);
209-
spin_lock(&dwc->lock);
207+
if (giveback) {
208+
spin_unlock(&dwc->lock);
209+
usb_gadget_giveback_request(&dep->endpoint, &req->request);
210+
spin_lock(&dwc->lock);
211+
}
210212

211213
if (dep->number > 1)
212214
pm_runtime_put(dwc->dev);
@@ -530,7 +532,7 @@ static void stream_timeout_function(unsigned long arg)
530532

531533
spin_lock_irqsave(&dwc->lock, flags);
532534
dwc3_stop_active_transfer(dwc, dep->number, true);
533-
__dwc3_gadget_kick_transfer(dep, 0);
535+
__dwc3_gadget_kick_transfer(dep, 0, true);
534536
spin_unlock_irqrestore(&dwc->lock, flags);
535537
}
536538

@@ -732,13 +734,13 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
732734
while (!list_empty(&dep->started_list)) {
733735
req = next_request(&dep->started_list);
734736

735-
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
737+
dwc3_gadget_giveback(dep, req, -ESHUTDOWN, true);
736738
}
737739

738740
while (!list_empty(&dep->pending_list)) {
739741
req = next_request(&dep->pending_list);
740742

741-
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
743+
dwc3_gadget_giveback(dep, req, -ESHUTDOWN, true);
742744
}
743745
}
744746

@@ -872,6 +874,7 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
872874

873875
req->epnum = dep->number;
874876
req->dep = dep;
877+
INIT_LIST_HEAD(&req->list);
875878

876879
dep->allocated_requests++;
877880

@@ -1246,7 +1249,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
12461249
}
12471250
}
12481251

1249-
int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
1252+
int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, bool giveback)
12501253
{
12511254
struct dwc3_gadget_ep_cmd_params params;
12521255
struct dwc3_request *req;
@@ -1289,14 +1292,15 @@ int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
12891292
if (req->trb)
12901293
memset(req->trb, 0, sizeof(struct dwc3_trb));
12911294
dep->queued_requests--;
1292-
dwc3_gadget_giveback(dep, req, ret);
1295+
dwc3_gadget_giveback(dep, req, ret, giveback);
12931296
return ret;
12941297
}
12951298

12961299
dep->flags |= DWC3_EP_BUSY;
12971300

12981301
if (starting) {
1299-
if (dep->stream_capable) {
1302+
/* FIXME: Enable this again once it works properly */
1303+
if (dep->stream_capable && 0) {
13001304
dep->stream_timeout_timer.expires = jiffies +
13011305
msecs_to_jiffies(STREAM_TIMEOUT);
13021306
add_timer(&dep->stream_timeout_timer);
@@ -1334,7 +1338,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
13341338
*/
13351339
uf = cur_uf + max_t(u32, 4, dep->interval);
13361340

1337-
__dwc3_gadget_kick_transfer(dep, uf);
1341+
__dwc3_gadget_kick_transfer(dep, uf, true);
13381342
}
13391343

13401344
static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
@@ -1410,7 +1414,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
14101414
!(dep->flags & DWC3_EP_MISSED_ISOC)) {
14111415
WARN_ON_ONCE(!dep->resource_index);
14121416
ret = __dwc3_gadget_kick_transfer(dep,
1413-
dep->resource_index);
1417+
dep->resource_index, false);
14141418
}
14151419

14161420
goto out;
@@ -1419,7 +1423,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
14191423
if (!dwc3_calc_trbs_left(dep))
14201424
return 0;
14211425

1422-
ret = __dwc3_gadget_kick_transfer(dep, 0);
1426+
ret = __dwc3_gadget_kick_transfer(dep, 0, false);
14231427
out:
14241428
if (ret == -EBUSY)
14251429
ret = 0;
@@ -1461,93 +1465,45 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
14611465

14621466
spin_lock_irqsave(&dwc->lock, flags);
14631467

1468+
/* Not queued, nothing to do */
1469+
if (list_empty(&req->list))
1470+
goto out0;
1471+
14641472
list_for_each_entry(r, &dep->pending_list, list) {
1473+
if (r == req)
1474+
goto out1;
1475+
}
1476+
1477+
list_for_each_entry(r, &dep->started_list, list) {
14651478
if (r == req)
14661479
break;
14671480
}
14681481

14691482
if (r != req) {
1470-
list_for_each_entry(r, &dep->started_list, list) {
1471-
if (r == req)
1472-
break;
1473-
}
1474-
if (r == req) {
1475-
/* wait until it is processed */
1476-
dwc3_stop_active_transfer(dwc, dep->number, true);
1477-
1478-
/*
1479-
* If request was already started, this means we had to
1480-
* stop the transfer. With that we also need to ignore
1481-
* all TRBs used by the request, however TRBs can only
1482-
* be modified after completion of END_TRANSFER
1483-
* command. So what we do here is that we wait for
1484-
* END_TRANSFER completion and only after that, we jump
1485-
* over TRBs by clearing HWO and incrementing dequeue
1486-
* pointer.
1487-
*
1488-
* Note that we have 2 possible types of transfers here:
1489-
*
1490-
* i) Linear buffer request
1491-
* ii) SG-list based request
1492-
*
1493-
* SG-list based requests will have r->num_pending_sgs
1494-
* set to a valid number (> 0). Linear requests,
1495-
* normally use a single TRB.
1496-
*
1497-
* For each of these two cases, if r->unaligned flag is
1498-
* set, one extra TRB has been used to align transfer
1499-
* size to wMaxPacketSize.
1500-
*
1501-
* All of these cases need to be taken into
1502-
* consideration so we don't mess up our TRB ring
1503-
* pointers.
1504-
*/
1505-
wait_event_lock_irq(dep->wait_end_transfer,
1506-
!(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
1507-
dwc->lock);
1508-
1509-
if (!r->trb)
1510-
goto out1;
1511-
1512-
if (r->num_pending_sgs) {
1513-
struct dwc3_trb *trb;
1514-
int i = 0;
1515-
1516-
for (i = 0; i < r->num_pending_sgs; i++) {
1517-
trb = r->trb + i;
1518-
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
1519-
dwc3_ep_inc_deq(dep);
1520-
}
1521-
1522-
if (r->unaligned || r->zero) {
1523-
trb = r->trb + r->num_pending_sgs + 1;
1524-
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
1525-
dwc3_ep_inc_deq(dep);
1526-
}
1527-
} else {
1528-
struct dwc3_trb *trb = r->trb;
1529-
1530-
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
1531-
dwc3_ep_inc_deq(dep);
1532-
1533-
if (r->unaligned || r->zero) {
1534-
trb = r->trb + 1;
1535-
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
1536-
dwc3_ep_inc_deq(dep);
1537-
}
1538-
}
1539-
goto out1;
1540-
}
15411483
dev_err(dwc->dev, "request %pK was not queued to %s\n",
15421484
request, ep->name);
15431485
ret = -EINVAL;
15441486
goto out0;
15451487
}
15461488

1489+
if (dep->stream_capable)
1490+
del_timer(&dep->stream_timeout_timer);
1491+
1492+
dep->aborted_trbs = r->trb;
1493+
if (r->num_pending_sgs)
1494+
dep->num_aborted_trbs = r->num_pending_sgs;
1495+
else
1496+
dep->num_aborted_trbs = 1;
1497+
1498+
if (r->unaligned || r->zero)
1499+
dep->num_aborted_trbs += 1;
1500+
1501+
dwc3_stop_active_transfer(dwc, dep->number, true);
1502+
15471503
out1:
15481504
/* giveback the request */
15491505
dep->queued_requests--;
1550-
dwc3_gadget_giveback(dep, req, -ECONNRESET);
1506+
dwc3_gadget_giveback(dep, req, -ECONNRESET, true);
15511507

15521508
out0:
15531509
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -2456,10 +2412,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
24562412
* to kick transfer again if (req->num_pending_sgs > 0)
24572413
*/
24582414
if (req->num_pending_sgs)
2459-
return __dwc3_gadget_kick_transfer(dep, 0);
2415+
return __dwc3_gadget_kick_transfer(dep, 0, true);
24602416
}
24612417

2462-
dwc3_gadget_giveback(dep, req, status);
2418+
dwc3_gadget_giveback(dep, req, status, true);
24632419

24642420
if (ret) {
24652421
if ((event->status & DEPEVT_STATUS_IOC) &&
@@ -2560,7 +2516,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
25602516
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
25612517
int ret;
25622518

2563-
ret = __dwc3_gadget_kick_transfer(dep, 0);
2519+
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
25642520
if (!ret || ret == -EBUSY)
25652521
return;
25662522
}
@@ -2609,7 +2565,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
26092565
} else {
26102566
int ret;
26112567

2612-
ret = __dwc3_gadget_kick_transfer(dep, 0);
2568+
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
26132569
if (!ret || ret == -EBUSY)
26142570
return;
26152571
}
@@ -2638,6 +2594,19 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
26382594
cmd = DEPEVT_PARAMETER_CMD(event->parameters);
26392595

26402596
if (cmd == DWC3_DEPCMD_ENDTRANSFER) {
2597+
if (dep->aborted_trbs) {
2598+
struct dwc3_trb *trb = dep->aborted_trbs;
2599+
int i = 0;
2600+
2601+
for (i = 0; i < dep->num_aborted_trbs; i++) {
2602+
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
2603+
dwc3_ep_inc_deq(dep);
2604+
trb++;
2605+
}
2606+
2607+
dep->aborted_trbs = NULL;
2608+
dep->num_aborted_trbs = 0;
2609+
}
26412610
dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
26422611
wake_up(&dep->wait_end_transfer);
26432612
}
@@ -2736,7 +2705,7 @@ void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
27362705
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
27372706
memset(&params, 0, sizeof(params));
27382707
ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
2739-
WARN_ON_ONCE(ret);
2708+
WARN_ON_ONCE(ret && ret != -ETIMEDOUT);
27402709
dep->flags &= ~DWC3_EP_BUSY;
27412710

27422711
/*

drivers/usb/dwc3/gadget.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
9696
}
9797

9898
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
99-
int status);
99+
int status, bool giveback);
100100

101101
void dwc3_ep0_interrupt(struct dwc3 *dwc,
102102
const struct dwc3_event_depevt *event);
@@ -110,7 +110,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
110110
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
111111
int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, bool modify, bool restore);
112112
int __dwc3_gadget_ep_disable(struct dwc3_ep *dep);
113-
int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param);
113+
int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, bool giveback);
114114
void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
115115
int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend);
116116
dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, struct dwc3_trb *trb);

drivers/usb/dwc3/gadget_hibernation.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ static int restore_eps(struct dwc3 *dwc)
217217
dep->resource_index =
218218
dwc3_gadget_ep_get_transfer_index(dep);
219219
} else {
220-
ret = __dwc3_gadget_kick_transfer(dep, 0);
220+
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
221221
if (ret) {
222222
dev_err(dwc->dev,
223223
"%s: restart transfer failed\n",

0 commit comments

Comments
 (0)