Update transfer is issued for the TRBs where HWO switches from 0 to 1. Lets say we had issued START TRANSFER with 8 TRBs having HWO as 1. Now we need to update 9th TRB, Then we need to call UPDATE TRANSFER with parameter as 9th TRB. Current code was issuing UPDATE transfer with 2nd TRB, which was already cached correctly during START TRANSFER. Two simplify the flow two functions dwc3_prepare_trbs & __dwc3_gadget_kick_transfer have been merged. Signed-off-by: Pratyush Anand <pratyush.anand@xxxxxx> --- drivers/usb/dwc3/gadget.c | 156 +++++++++++++++++++++------------------------ 1 files changed, 72 insertions(+), 84 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 783bc87..65b757e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -842,24 +842,73 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl |= DWC3_TRB_CTRL_HWO; } -/* - * dwc3_prepare_trbs - setup TRBs from requests - * @dep: endpoint for which requests are being prepared - * @starting: true if the endpoint is idle and no requests are queued. - * - * The function goes through the requests list and sets up TRBs for the - * transfers. The function returns once there are no more TRBs available or - * it runs out of requests. - */ -static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) +static int __dwc3_start_update_transfer(struct dwc3_ep *dep, + struct dwc3_request *req, bool start_new, u16 cmd_param) +{ + struct dwc3 *dwc = dep->dwc; + struct dwc3_gadget_ep_cmd_params params; + int ret; + u32 cmd; + + memset(¶ms, 0, sizeof(params)); + params.param0 = upper_32_bits(req->trb_dma); + params.param1 = lower_32_bits(req->trb_dma); + + if (start_new) + cmd = DWC3_DEPCMD_STARTTRANSFER; + else + cmd = DWC3_DEPCMD_UPDATETRANSFER; + + cmd |= DWC3_DEPCMD_PARAM(cmd_param); + ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); + if (ret < 0) { + dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n"); + + /* + * FIXME we need to iterate over the list of requests + * here and stop, unmap, free and del each of the linked + * requests instead of what we do now. + */ + usb_gadget_unmap_request(&dwc->gadget, &req->request, + req->direction); + list_del(&req->list); + return ret; + } + + dep->flags |= DWC3_EP_BUSY; + + if (start_new) { + dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, + dep->number); + WARN_ON_ONCE(!dep->resource_index); + } + + return 0; +} + +static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, + int start_new) { struct dwc3_request *req, *n; u32 trbs_left; u32 max; unsigned int last_one = 0; + struct dwc3 *dwc = dep->dwc; + + if (start_new && (dep->flags & DWC3_EP_BUSY)) { + dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name); + return -EBUSY; + } BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); + if (list_empty(&dep->request_list)) { + dev_vdbg(dwc->dev, "ep %s run out for requests.\n", + dep->name); + dep->flags |= DWC3_EP_PENDING_REQUEST; + return 0; + } + /* the first request must not be queued */ trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK; @@ -876,8 +925,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) * full and don't do anything */ if (!trbs_left) { - if (!starting) - return; + if (!start_new) + return 0; trbs_left = DWC3_TRB_NUM; /* * In case we start from scratch, we queue the ISOC requests @@ -899,10 +948,6 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) } } - /* The last TRB is a link TRB, not used for xfer */ - if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) - return; - list_for_each_entry_safe(req, n, &dep->request_list, list) { unsigned length; dma_addr_t dma; @@ -935,6 +980,9 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) dwc3_prepare_one_trb(dep, req, dma, length, last_one, chain); + if (!start_new) + __dwc3_start_update_transfer(dep, req, + start_new, cmd_param); if (last_one) break; } @@ -953,81 +1001,21 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) dwc3_prepare_one_trb(dep, req, dma, length, last_one, false); + if (!start_new) + __dwc3_start_update_transfer(dep, req, + start_new, cmd_param); if (last_one) break; } + /* The last TRB is a link TRB, not used for xfer */ + if ((trbs_left <= 1) && + usb_endpoint_xfer_isoc(dep->endpoint.desc)) + break; } -} - -static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, - int start_new) -{ - struct dwc3_gadget_ep_cmd_params params; - struct dwc3_request *req; - struct dwc3 *dwc = dep->dwc; - int ret; - u32 cmd; - - if (start_new && (dep->flags & DWC3_EP_BUSY)) { - dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name); - return -EBUSY; - } - dep->flags &= ~DWC3_EP_PENDING_REQUEST; - /* - * If we are getting here after a short-out-packet we don't enqueue any - * new requests as we try to set the IOC bit only on the last request. - */ if (start_new) { - if (list_empty(&dep->req_queued)) - dwc3_prepare_trbs(dep, start_new); - - /* req points to the first request which will be sent */ req = next_request(&dep->req_queued); - } else { - dwc3_prepare_trbs(dep, start_new); - - /* - * req points to the first request where HWO changed from 0 to 1 - */ - req = next_request(&dep->req_queued); - } - if (!req) { - dep->flags |= DWC3_EP_PENDING_REQUEST; - return 0; - } - - memset(¶ms, 0, sizeof(params)); - params.param0 = upper_32_bits(req->trb_dma); - params.param1 = lower_32_bits(req->trb_dma); - - if (start_new) - cmd = DWC3_DEPCMD_STARTTRANSFER; - else - cmd = DWC3_DEPCMD_UPDATETRANSFER; - - cmd |= DWC3_DEPCMD_PARAM(cmd_param); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); - if (ret < 0) { - dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n"); - - /* - * FIXME we need to iterate over the list of requests - * here and stop, unmap, free and del each of the linked - * requests instead of what we do now. - */ - usb_gadget_unmap_request(&dwc->gadget, &req->request, - req->direction); - list_del(&req->list); - return ret; - } - - dep->flags |= DWC3_EP_BUSY; - - if (start_new) { - dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, - dep->number); - WARN_ON_ONCE(!dep->resource_index); + __dwc3_start_update_transfer(dep, req, start_new, cmd_param); } return 0; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html