To aid code readability, we're gonna split __dwc3_gadget_kick_transfer() into its constituent parts: scatter gather and linear buffers. That way, it's easier to follow the code and focus debug effort when one or the other fails. Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx> --- drivers/usb/dwc3/gadget.c | 122 ++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 57 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index eca131f0be59..adf743bca36f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -881,6 +881,65 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) return dep->trb_dequeue - dep->trb_enqueue; } +static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, + struct dwc3_request *req, unsigned int trbs_left) +{ + struct usb_request *request = &req->request; + struct scatterlist *sg = request->sg; + struct scatterlist *s; + unsigned int last = false; + unsigned int length; + dma_addr_t dma; + int i; + + for_each_sg(sg, s, request->num_mapped_sgs, i) { + unsigned chain = true; + + length = sg_dma_len(s); + dma = sg_dma_address(s); + + if (sg_is_last(s)) { + if (list_is_last(&req->list, &dep->pending_list)) + last = true; + + chain = false; + } + + if (!trbs_left) + last = true; + + if (last) + chain = false; + + dwc3_prepare_one_trb(dep, req, dma, length, + last, chain, i); + + if (last) + break; + } +} + +static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, + struct dwc3_request *req, unsigned int trbs_left) +{ + unsigned int last = false; + unsigned int length; + dma_addr_t dma; + + dma = req->request.dma; + length = req->request.length; + + if (!trbs_left) + last = true; + + /* Is this the last request? */ + if (list_is_last(&req->list, &dep->pending_list)) + last = true; + + dwc3_prepare_one_trb(dep, req, dma, length, + last, false, 0); +} + /* * dwc3_prepare_trbs - setup TRBs from requests * @dep: endpoint for which requests are being prepared @@ -893,70 +952,19 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) { struct dwc3_request *req, *n; u32 trbs_left; - unsigned int last_one = 0; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); trbs_left = dwc3_calc_trbs_left(dep); list_for_each_entry_safe(req, n, &dep->pending_list, list) { - unsigned length; - dma_addr_t dma; - last_one = false; - - if (req->request.num_mapped_sgs > 0) { - struct usb_request *request = &req->request; - struct scatterlist *sg = request->sg; - struct scatterlist *s; - int i; - - for_each_sg(sg, s, request->num_mapped_sgs, i) { - unsigned chain = true; - - length = sg_dma_len(s); - dma = sg_dma_address(s); - - if (sg_is_last(s)) { - if (list_is_last(&req->list, &dep->pending_list)) - last_one = true; - - chain = false; - } - - trbs_left--; - if (!trbs_left) - last_one = true; - - if (last_one) - chain = false; - - dwc3_prepare_one_trb(dep, req, dma, length, - last_one, chain, i); - - if (last_one) - break; - } - - if (last_one) - break; - } else { - dma = req->request.dma; - length = req->request.length; - trbs_left--; - - if (!trbs_left) - last_one = true; - - /* Is this the last request? */ - if (list_is_last(&req->list, &dep->pending_list)) - last_one = true; - - dwc3_prepare_one_trb(dep, req, dma, length, - last_one, false, 0); + if (req->request.num_mapped_sgs > 0) + dwc3_prepare_one_trb_sg(dep, req, trbs_left--); + else + dwc3_prepare_one_trb_linear(dep, req, trbs_left--); - if (last_one) - break; - } + if (!trbs_left) + return; } } -- 2.8.2 --------------------------------------------------------------------- Intel Finland Oy Registered Address: PL 281, 00181 Helsinki Business Identity Code: 0357606 - 4 Domiciled in Helsinki This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies. -- 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