forked from Minki/linux
usb: dwc2: host: fix logical omissions in dwc2_process_non_isoc_desc
Fixes memory manipulation issues and makes Host DDMA bulk transfers work. dwc2_process_non_isoc_desc() must return non zero value ONLY when failure happens in one of the queued descriptors. After receiving non zero value the caller must stop processing of remaining QTDs and their descriptors from chain. Commit26a19ea699
("usb: dwc2: host: fix use of qtd after free in desc dma mode") breaks non_isoc transaction completion logic in Host DDMA mode. There were bugs before that, but after this patch dwc2_process_non_isoc_desc() returns fail status even if descriptor was processed normally. This causes break from loop which is processing remaining descriptors assigned to QTD, which is not correct for QTDs containing more than one descriptor. Current dwc2 driver gathers queued BULK URBs until receiving URB without URB_NO_INTERRUPT flag. Once getting it, SW creates descriptor chain, stores it in qh structure and passes start address to HW. Multiple URB data is contained in that chain. Hence on getting error on descriptor after its processing by HW, SW should go out of both loops(qh->qtd, qtd->descs) and report the failure. Fixes:26a19ea699
("usb: dwc2: host: fix use of qtd after free in desc dma mode") Cc: Gregory Herrero <gregory.herrero@intel.com> Signed-off-by: Vardan Mikayelyan <mvardan@synopsys.com> Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
This commit is contained in:
parent
c450960187
commit
3142a16b98
@ -1174,14 +1174,11 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
|
||||
failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc,
|
||||
halt_status, n_bytes,
|
||||
xfer_done);
|
||||
if (*xfer_done && urb->status != -EINPROGRESS)
|
||||
failed = 1;
|
||||
|
||||
if (failed) {
|
||||
if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
|
||||
dwc2_host_complete(hsotg, qtd, urb->status);
|
||||
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
|
||||
dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
|
||||
failed, *xfer_done, urb->status);
|
||||
dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x\n",
|
||||
failed, *xfer_done);
|
||||
return failed;
|
||||
}
|
||||
|
||||
@ -1236,21 +1233,23 @@ static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
|
||||
|
||||
list_for_each_safe(qtd_item, qtd_tmp, &qh->qtd_list) {
|
||||
int i;
|
||||
int qtd_desc_count;
|
||||
|
||||
qtd = list_entry(qtd_item, struct dwc2_qtd, qtd_list_entry);
|
||||
xfer_done = 0;
|
||||
qtd_desc_count = qtd->n_desc;
|
||||
|
||||
for (i = 0; i < qtd->n_desc; i++) {
|
||||
for (i = 0; i < qtd_desc_count; i++) {
|
||||
if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd,
|
||||
desc_num, halt_status,
|
||||
&xfer_done)) {
|
||||
qtd = NULL;
|
||||
break;
|
||||
}
|
||||
&xfer_done))
|
||||
goto stop_scan;
|
||||
|
||||
desc_num++;
|
||||
}
|
||||
}
|
||||
|
||||
stop_scan:
|
||||
if (qh->ep_type != USB_ENDPOINT_XFER_CONTROL) {
|
||||
/*
|
||||
* Resetting the data toggle for bulk and interrupt endpoints
|
||||
|
Loading…
Reference in New Issue
Block a user