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.an...@st.com>
---
 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(&params, 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, &params);
+       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(&params, 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, &params);
-       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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to