usb: dwc3: gadget: Revise preparation for extra TRBs
Subsystems (3)
Thinh Nguyen
maintainercover usb: dwc3: gadget: Revise preparation for extra TRBs
This series resolves various issues with ZLP handling and refactor handling of TRBs. This series has too many changes comparing to the "[PATCH v3 0/4] usb:
dwc3: gadget: Fix TRB preparation" series so I created different series instead.
Thinh Nguyen (10):
usb: dwc3: gadget: Check MPS of the request length
usb: dwc3: gadget: Reclaim extra TRBs after request completion
usb: dwc3: gadget: Refactor preparing extra TRB
usb: dwc3: gadget: Improve TRB ZLP setup
usb: dwc3: ep0: Fix ZLP for OUT ep0 requests
usb: dwc3: gadget: Return the number of prepared TRBs
usb: dwc3: gadget: Check for number of TRBs prepared
usb: dwc3: gadget: Set IOC if not enough for extra TRBs
usb: dwc3: gadget: Refactor preparing last TRBs
usb: dwc3: gadget: Rename misleading function names
drivers/usb/dwc3/ep0.c | 11 +- drivers/usb/dwc3/gadget.c | 262 +++++++++++++++++--------------------- 2 files changed, 124 insertions(+), 149 deletions(-)
base-commit: 2f45af92722ee6e78f12037af1870117bcae00d1
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 1/10 usb: dwc3: gadget: Check MPS of the request length
When preparing for SG, not all the entries are prepared at once. When resume, don't use the remaining request length to calculate for MPS alignment. Use the entire request->length to do that.
--- drivers/usb/dwc3/gadget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/dwc3/gadget.c +2 -2
@@ -1098,6 +1098,8 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,struct scatterlist *s;int i;unsigned int length = req->request.length; +unsigned int maxp =usb_endpoint_maxp (dep->endpoint.desc); +unsigned int rem = length % maxp;unsigned int remaining = req->request.num_mapped_sgs - req->num_queued_sgs;
@@ -1109,8 +1111,6 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, length -=sg_dma_len (s);for_each_sg (sg, s, remaining, i) { -unsigned int maxp =usb_endpoint_maxp (dep->endpoint.desc); -unsigned int rem = length % maxp;unsigned int trb_length;unsigned int chain = true;
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 2/10 usb: dwc3: gadget: Reclaim extra TRBs after request completion
In reply to Thinh NguyenAn SG request may be partially completed (due to no available TRBs). Don't reclaim extra TRBs and clear the needs_extra_trb flag until the request is fully completed. Otherwise, the driver will reclaim the wrong TRB.
--- drivers/usb/dwc3/gadget.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/usb/dwc3/gadget.c +5 -5
@@ -2738,6 +2738,11 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, ret =dwc3_gadget_ep_reclaim_trb_linear (dep, req, event, status); + req->request.actual = req->request.length - req->remaining; + +if (!dwc3_gadget_ep_request_completed (req)) + goto out; +if (req->needs_extra_trb) {unsigned int maxp =usb_endpoint_maxp (dep->endpoint.desc);
@@ -2753,11 +2758,6 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, req->needs_extra_trb = false; } - req->request.actual = req->request.length - req->remaining; - -if (!dwc3_gadget_ep_request_completed (req)) - goto out; -dwc3_gadget_giveback (dep, req, status); out:
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 3/10 usb: dwc3: gadget: Refactor preparing extra TRB
In reply to Thinh NguyenWhen the driver prepares the extra TRB, it uses bounce buffer. If we just add a new parameter to dwc3_prepare_one_trb() to indicate this, then we can refactor and simplify the driver quite a bit. dwc3_prepare_one_trb() also checks if a request had been moved to the started list. This is a prerequisite to subsequence patches improving the handling of extra TRBs.
--- drivers/usb/dwc3/gadget.c | 93 +++++++++++---------------------------- 1 file changed, 25 insertions(+), 68 deletions(-)
drivers/usb/dwc3/gadget.c +25 -68
@@ -1060,10 +1060,11 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,* @trb_length: buffer size of the TRB * @chain: should this TRB be chained to the next? * @node: only for isochronous endpoints. First TRB needs different type. +* @use_bounce_buffer: set to use bounce buffer */ static void dwc3_prepare_one_trb (struct dwc3_ep *dep,struct dwc3_request *req,unsigned int trb_length, -unsigned int chain,unsigned int node) +unsigned int chain,unsigned int node,bool use_bounce_buffer) {struct dwc3_trb *trb;dma_addr_t dma;
@@ -1072,7 +1073,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,unsigned int no_interrupt = req->request.no_interrupt;unsigned int is_last = req->request.is_last; -if (req->request.num_sgs >0 ) +if (use_bounce_buffer) + dma = dep->dwc->bounce_addr; +else if (req->request.num_sgs >0 ) dma =sg_dma_address (req->start_sg);else dma = req->request.dma;
@@ -1129,56 +1132,35 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, chain = false;if (rem &&usb_endpoint_dir_out (dep->endpoint.desc) && !chain) { -struct dwc3 *dwc = dep->dwc; -struct dwc3_trb *trb; - req->needs_extra_trb = true;/* prepare normal TRB */ -dwc3_prepare_one_trb (dep, req, trb_length, true, i); +dwc3_prepare_one_trb (dep, req, trb_length, + true, i, false);/* Now prepare one extra TRB to align transfer size */ - trb = &dep->trb_pool[dep->trb_enqueue]; - req->num_trbs++; -__dwc3_prepare_one_trb (dep, trb, dwc->bounce_addr, - maxp - rem, false,1 , - req->request.stream_id, - req->request.short_not_ok, - req->request.no_interrupt, - req->request.is_last); +dwc3_prepare_one_trb (dep, req, maxp - rem, + false,1 , true); }else if (req->request.zero && req->request.length && !usb_endpoint_xfer_isoc (dep->endpoint.desc) && !rem && !chain) { -struct dwc3 *dwc = dep->dwc; -struct dwc3_trb *trb; - req->needs_extra_trb = true;/* Prepare normal TRB */ -dwc3_prepare_one_trb (dep, req, trb_length, true, i); +dwc3_prepare_one_trb (dep, req, trb_length, + true, i, false);/* Prepare one extra TRB to handle ZLP */ - trb = &dep->trb_pool[dep->trb_enqueue]; - req->num_trbs++; -__dwc3_prepare_one_trb (dep, trb, dwc->bounce_addr,0 , - !req->direction,1 , - req->request.stream_id, - req->request.short_not_ok, - req->request.no_interrupt, - req->request.is_last); +dwc3_prepare_one_trb (dep, req,0 , + !req->direction,1 , true);/* Prepare one more TRB to handle MPS alignment */ -if (!req->direction) { - trb = &dep->trb_pool[dep->trb_enqueue]; - req->num_trbs++; -__dwc3_prepare_one_trb (dep, trb, dwc->bounce_addr, maxp, - false,1 , req->request.stream_id, - req->request.short_not_ok, - req->request.no_interrupt, - req->request.is_last); - } +if (!req->direction) +dwc3_prepare_one_trb (dep, req, maxp, + false,1 , true); }else { -dwc3_prepare_one_trb (dep, req, trb_length, chain, i); +dwc3_prepare_one_trb (dep, req, trb_length, + chain, i, false); }/*
@@ -1216,54 +1198,29 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,unsigned int rem = length % maxp;if ((!length || rem) &&usb_endpoint_dir_out (dep->endpoint.desc)) { -struct dwc3 *dwc = dep->dwc; -struct dwc3_trb *trb; - req->needs_extra_trb = true;/* prepare normal TRB */ -dwc3_prepare_one_trb (dep, req, length, true,0 ); +dwc3_prepare_one_trb (dep, req, length, true,0 , false);/* Now prepare one extra TRB to align transfer size */ - trb = &dep->trb_pool[dep->trb_enqueue]; - req->num_trbs++; -__dwc3_prepare_one_trb (dep, trb, dwc->bounce_addr, maxp - rem, - false,1 , req->request.stream_id, - req->request.short_not_ok, - req->request.no_interrupt, - req->request.is_last); +dwc3_prepare_one_trb (dep, req, maxp - rem, false,1 , true); }else if (req->request.zero && req->request.length && !usb_endpoint_xfer_isoc (dep->endpoint.desc) && (IS_ALIGNED (req->request.length, maxp))) { -struct dwc3 *dwc = dep->dwc; -struct dwc3_trb *trb; - req->needs_extra_trb = true;/* prepare normal TRB */ -dwc3_prepare_one_trb (dep, req, length, true,0 ); +dwc3_prepare_one_trb (dep, req, length, true,0 , false);/* Prepare one extra TRB to handle ZLP */ - trb = &dep->trb_pool[dep->trb_enqueue]; - req->num_trbs++; -__dwc3_prepare_one_trb (dep, trb, dwc->bounce_addr,0 , - !req->direction,1 , req->request.stream_id, - req->request.short_not_ok, - req->request.no_interrupt, - req->request.is_last); +dwc3_prepare_one_trb (dep, req,0 , !req->direction,1 , true);/* Prepare one more TRB to handle MPS alignment for OUT */ -if (!req->direction) { - trb = &dep->trb_pool[dep->trb_enqueue]; - req->num_trbs++; -__dwc3_prepare_one_trb (dep, trb, dwc->bounce_addr, maxp, - false,1 , req->request.stream_id, - req->request.short_not_ok, - req->request.no_interrupt, - req->request.is_last); - } +if (!req->direction) +dwc3_prepare_one_trb (dep, req, maxp, false,1 , true); }else { -dwc3_prepare_one_trb (dep, req, length, false,0 ); +dwc3_prepare_one_trb (dep, req, length, false,0 , false); } }
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 4/10 usb: dwc3: gadget: Improve TRB ZLP setup
In reply to Thinh NguyenFor OUT requests that requires extra TRBs for ZLP. We don't need to prepare the 0-length TRB and simply prepare the MPS size TRB. This reduces 1 TRB needed to prepare for ZLP.
--- drivers/usb/dwc3/gadget.c | 50 ++++++++++++++------------------------- 1 file changed, 18 insertions(+), 32 deletions(-)
drivers/usb/dwc3/gadget.c +18 -32
@@ -1132,11 +1132,12 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, chain = false;if (rem &&usb_endpoint_dir_out (dep->endpoint.desc) && !chain) { - req->needs_extra_trb = true; -/* prepare normal TRB */ -dwc3_prepare_one_trb (dep, req, trb_length, +if (req->request.length) { + req->needs_extra_trb = true; +dwc3_prepare_one_trb (dep, req, trb_length, true, i, false); + }/* Now prepare one extra TRB to align transfer size */ dwc3_prepare_one_trb(dep, req, maxp - rem,
@@ -1151,13 +1152,9 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, true, i, false);/* Prepare one extra TRB to handle ZLP */ -dwc3_prepare_one_trb (dep, req,0 , - !req->direction,1 , true); - -/* Prepare one more TRB to handle MPS alignment */ -if (!req->direction) -dwc3_prepare_one_trb (dep, req, maxp, - false,1 , true); +dwc3_prepare_one_trb (dep, req, + req->direction ?0 : maxp, + false,1 , true); }else {dwc3_prepare_one_trb (dep, req, trb_length, chain, i, false);
@@ -1198,10 +1195,11 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,unsigned int rem = length % maxp;if ((!length || rem) &&usb_endpoint_dir_out (dep->endpoint.desc)) { - req->needs_extra_trb = true; -/* prepare normal TRB */ -dwc3_prepare_one_trb (dep, req, length, true,0 , false); +if (req->request.length) { + req->needs_extra_trb = true; +dwc3_prepare_one_trb (dep, req, length, true,0 , false); + }/* Now prepare one extra TRB to align transfer size */ dwc3_prepare_one_trb (dep, req, maxp - rem, false,1 , true);
@@ -1214,11 +1212,8 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,dwc3_prepare_one_trb (dep, req, length, true,0 , false);/* Prepare one extra TRB to handle ZLP */ -dwc3_prepare_one_trb (dep, req,0 , !req->direction,1 , true); - -/* Prepare one more TRB to handle MPS alignment for OUT */ -if (!req->direction) -dwc3_prepare_one_trb (dep, req, maxp, false,1 , true); +dwc3_prepare_one_trb (dep, req, req->direction ?0 : maxp, + false,1 , true); }else {dwc3_prepare_one_trb (dep, req, length, false,0 , false); }
@@ -2615,12 +2610,12 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, }/* -* If we're dealing with unaligned size OUT transfer, we will be left -* with one TRB pending in the ring. We need to manually clear HWO bit -* from that TRB. +* We use bounce buffer for requests that needs extra TRB or OUT ZLP. If +* this TRB points to the bounce buffer address, it's a MPS alignment +* TRB. Don't add it to req->remaining calculation. */ - -if (req->needs_extra_trb && !(trb->ctrl &DWC3_TRB_CTRL_CHN )) { +if (trb->bpl ==lower_32_bits (dep->dwc->bounce_addr) && + trb->bph ==upper_32_bits (dep->dwc->bounce_addr)) { trb->ctrl &= ~DWC3_TRB_CTRL_HWO ;return 1 ; }
@@ -2701,17 +2696,8 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, goto out;if (req->needs_extra_trb) { -unsigned int maxp =usb_endpoint_maxp (dep->endpoint.desc); - ret =dwc3_gadget_ep_reclaim_trb_linear (dep, req, event, status); - -/* Reclaim MPS padding TRB for ZLP */ -if (!req->direction && req->request.zero && req->request.length && - !usb_endpoint_xfer_isoc (dep->endpoint.desc) && - (IS_ALIGNED (req->request.length, maxp))) - ret =dwc3_gadget_ep_reclaim_trb_linear (dep, req, event, status); - req->needs_extra_trb = false; }
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 5/10 usb: dwc3: ep0: Fix ZLP for OUT ep0 requests
In reply to Thinh NguyenThe current ZLP handling for ep0 requests is only for control IN requests. For OUT direction, DWC3 needs to check and setup for MPS alignment.
Usually, control OUT requests can indicate its transfer size via the wLength field of the control message. So usb_request->zero is usually not needed for OUT direction. To handle ZLP OUT for control endpoint, make sure the TRB is MPS size.
--- drivers/usb/dwc3/ep0.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/usb/dwc3/ep0.c +9 -2
@@ -947,12 +947,16 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,static void __dwc3_ep0_do_control_data (struct dwc3 *dwc,struct dwc3_ep *dep,struct dwc3_request *req) { +unsigned int trb_length =0 ;int ret; req->direction = !!dep->number;if (req->request.length ==0 ) { -dwc3_ep0_prepare_one_trb (dep, dwc->ep0_trb_addr,0 , +if (!req->direction) + trb_length = dep->endpoint.maxpacket; + +dwc3_ep0_prepare_one_trb (dep, dwc->bounce_addr, trb_length,DWC3_TRBCTL_CONTROL_DATA , false); ret =dwc3_ep0_start_trans (dep); } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
@@ -999,9 +1003,12 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, req->trb = &dwc->ep0_trb[dep->trb_enqueue -1 ]; +if (!req->direction) + trb_length = dep->endpoint.maxpacket; +/* Now prepare one extra TRB to align transfer size */ dwc3_ep0_prepare_one_trb (dep, dwc->bounce_addr, -0 ,DWC3_TRBCTL_CONTROL_DATA , + trb_length,DWC3_TRBCTL_CONTROL_DATA , false); ret =dwc3_ep0_start_trans (dep); }else {
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 6/10 usb: dwc3: gadget: Return the number of prepared TRBs
In reply to Thinh NguyenIn preparation for fixing the check for number of remaining TRBs, revise dwc3_prepare_one_trb_linear() and dwc3_prepare_one_trb_sg() to return the number of prepared TRBs.
--- drivers/usb/dwc3/gadget.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-)
drivers/usb/dwc3/gadget.c +33 -2
@@ -1094,7 +1094,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, stream_id, short_not_ok, no_interrupt, is_last); } -static void dwc3_prepare_one_trb_sg (struct dwc3_ep *dep, +static int dwc3_prepare_one_trb_sg (struct dwc3_ep *dep,struct dwc3_request *req) {struct scatterlist *sg = req->start_sg;
@@ -1105,6 +1105,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,unsigned int rem = length % maxp;unsigned int remaining = req->request.num_mapped_sgs - req->num_queued_sgs; +unsigned int num_trbs = req->num_trbs;/* * If we resume preparing the request, then get the remaining length of
@@ -1131,9 +1132,15 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,if ((i == remaining -1 ) || !length) chain = false; +if (!dwc3_calc_trbs_left (dep)) +break ; +if (rem &&usb_endpoint_dir_out (dep->endpoint.desc) && !chain) {/* prepare normal TRB */ if (req->request.length) { +if (dwc3_calc_trbs_left (dep) <2 ) + goto out; + req->needs_extra_trb = true;dwc3_prepare_one_trb (dep, req, trb_length, true, i, false);
@@ -1145,6 +1152,10 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, }else if (req->request.zero && req->request.length && !usb_endpoint_xfer_isoc (dep->endpoint.desc) && !rem && !chain) { + +if (dwc3_calc_trbs_left (dep) <2 ) + goto out; + req->needs_extra_trb = true;/* Prepare normal TRB */
@@ -1185,18 +1196,28 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,if (!dwc3_calc_trbs_left (dep))break ; } + +out: +return req->num_trbs - num_trbs; } -static void dwc3_prepare_one_trb_linear (struct dwc3_ep *dep, +static int dwc3_prepare_one_trb_linear (struct dwc3_ep *dep,struct dwc3_request *req) {unsigned int length = req->request.length;unsigned int maxp =usb_endpoint_maxp (dep->endpoint.desc);unsigned int rem = length % maxp; +unsigned int num_trbs = req->num_trbs; + +if (!dwc3_calc_trbs_left (dep)) + goto out;if ((!length || rem) &&usb_endpoint_dir_out (dep->endpoint.desc)) {/* prepare normal TRB */ if (req->request.length) { +if (dwc3_calc_trbs_left (dep) <2 ) + goto out; + req->needs_extra_trb = true;dwc3_prepare_one_trb (dep, req, length, true,0 , false); }
@@ -1206,6 +1227,10 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, }else if (req->request.zero && req->request.length && !usb_endpoint_xfer_isoc (dep->endpoint.desc) && (IS_ALIGNED (req->request.length, maxp))) { + +if (dwc3_calc_trbs_left (dep) <2 ) + goto out; + req->needs_extra_trb = true;/* prepare normal TRB */
@@ -1215,8 +1240,14 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,dwc3_prepare_one_trb (dep, req, req->direction ?0 : maxp, false,1 , true); }else { +if (!dwc3_calc_trbs_left (dep)) + goto out; +dwc3_prepare_one_trb (dep, req, length, false,0 , false); } + +out: +return req->num_trbs - num_trbs; }/*
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 7/10 usb: dwc3: gadget: Check for number of TRBs prepared
In reply to Thinh NguyenBy returning the number of TRBs prepared, we know whether to execute __dwc3_gadget_kick_transfer(). This allows us to check if we ran out of TRBs when extra TRBs are needed for OUT transfers. It also allows us to properly handle usb_gadget_map_request_by_dev() error.
--- drivers/usb/dwc3/gadget.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-)
drivers/usb/dwc3/gadget.c +22 -15
@@ -1257,10 +1257,13 @@ static int dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,* 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. +* +* Returns the number of TRBs prepared or negative errno. */ -static void dwc3_prepare_trbs (struct dwc3_ep *dep) +static int dwc3_prepare_trbs (struct dwc3_ep *dep) {struct dwc3_request *req, *n; +int ret =0 ;BUILD_BUG_ON_NOT_POWER_OF_2 (DWC3_TRB_NUM );
@@ -1275,11 +1278,14 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)* break things. */ list_for_each_entry (req, &dep->started_list, list) { -if (req->num_pending_sgs >0 ) -dwc3_prepare_one_trb_sg (dep, req); +if (req->num_pending_sgs >0 ) { + ret =dwc3_prepare_one_trb_sg (dep, req); +if (!ret) +return ret; + }if (!dwc3_calc_trbs_left (dep)) -return ; +return ret;/* * Don't prepare beyond a transfer. In DWC_usb32, its transfer
@@ -1287,17 +1293,16 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)* active transfer instead of stopping. */ if (dep->stream_capable && req->request.is_last) -return ; +return ret; }list_for_each_entry_safe (req, n, &dep->pending_list, list) {struct dwc3 *dwc = dep->dwc; -int ret; ret =usb_gadget_map_request_by_dev (dwc->sysdev, &req->request, dep->direction);if (ret) -return ; +return ret; req->sg = req->request.sg; req->start_sg = req->sg;
@@ -1305,12 +1310,12 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) req->num_pending_sgs = req->request.num_mapped_sgs;if (req->num_pending_sgs >0 ) -dwc3_prepare_one_trb_sg (dep, req); + ret =dwc3_prepare_one_trb_sg (dep, req);else -dwc3_prepare_one_trb_linear (dep, req); + ret =dwc3_prepare_one_trb_linear (dep, req); -if (!dwc3_calc_trbs_left (dep)) -return ; +if (!ret || !dwc3_calc_trbs_left (dep)) +return ret;/* * Don't prepare beyond a transfer. In DWC_usb32, its transfer
@@ -1318,8 +1323,10 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)* active transfer instead of stopping. */ if (dep->stream_capable && req->request.is_last) -return ; +return ret; } + +return ret; }static void dwc3_gadget_ep_cleanup_cancelled_requests (struct dwc3_ep *dep);
@@ -1332,12 +1339,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)int ret;u32 cmd; -if (!dwc3_calc_trbs_left (dep)) -return 0 ; + ret =dwc3_prepare_trbs (dep); +if (ret <=0 ) +return ret; starting = !(dep->flags &DWC3_EP_TRANSFER_STARTED ); -dwc3_prepare_trbs (dep); req =next_request (&dep->started_list);if (!req) { dep->flags |=DWC3_EP_PENDING_REQUEST ;
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 8/10 usb: dwc3: gadget: Set IOC if not enough for extra TRBs
In reply to Thinh NguyenIf we run out of TRBs because we need extra TRBs, make sure to set the IOC bit for the previously prepared TRB to get completion notification to free up TRBs to resume later.
--- drivers/usb/dwc3/gadget.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
drivers/usb/dwc3/gadget.c +20 -0
@@ -1197,7 +1197,27 @@ static int dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,break ; } +return req->num_trbs - num_trbs; + out: +/* +* If we run out of TRBs for MPS alignment setup, then set IOC on the +* previous TRB to get notified for TRB completion to resume when more +* TRBs are available. +* +* Note: normally we shouldn't update the TRB after the HWO bit is set. +* However, the controller doesn't update its internal cache to handle +* the newly prepared TRBs until UPDATE_TRANSFER or START_TRANSFER +* command is executed. At this point, it doesn't happen yet, so we +* should be fine modifying it here. +*/ +if (i) { +struct dwc3_trb *trb; + + trb =dwc3_ep_prev_trb (dep, dep->trb_enqueue); + trb->ctrl |=DWC3_TRB_CTRL_IOC ; + } +return req->num_trbs - num_trbs; }
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 9/10 usb: dwc3: gadget: Refactor preparing last TRBs
In reply to Thinh NguyenThere are a lot of common codes for preparing SG and linear TRBs. Refactor them for easier read.
--- drivers/usb/dwc3/gadget.c | 129 ++++++++++++++------------------------ 1 file changed, 48 insertions(+), 81 deletions(-)
drivers/usb/dwc3/gadget.c +48 -81
@@ -1094,6 +1094,47 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, stream_id, short_not_ok, no_interrupt, is_last); } +/** +* dwc3_prepare_last_sg - prepare TRBs for the last SG entry +* @dep: The endpoint that the request belongs to +* @req: The request to prepare +* @entry_length: The last SG entry size +* @node: Indicates whether this is not the first entry (for isoc only) +* +* Return the number of TRBs prepared. +*/ +static int dwc3_prepare_last_sg (struct dwc3_ep *dep, +struct dwc3_request *req,unsigned int entry_length, +unsigned int node) +{ +unsigned int maxp =usb_endpoint_maxp (dep->endpoint.desc); +unsigned int rem = req->request.length % maxp; +unsigned int num_trbs =1 ; + +if ((req->request.length && req->request.zero && !rem && + !usb_endpoint_xfer_isoc (dep->endpoint.desc)) || + (!req->direction && rem)) + num_trbs++; + +if (dwc3_calc_trbs_left (dep) < num_trbs) +return 0 ; + + req->needs_extra_trb = num_trbs >1 ; + +/* Prepare a normal TRB */ +if (req->direction || req->request.length) +dwc3_prepare_one_trb (dep, req, entry_length, + req->needs_extra_trb, node, false); + +/* Prepare extra TRBs for ZLP and MPS OUT transfer alignment */ +if ((!req->direction && !req->request.length) || req->needs_extra_trb) +dwc3_prepare_one_trb (dep, req, + req->direction ?0 : maxp - rem, + false,1 , true); + +return num_trbs; +} +static int dwc3_prepare_one_trb_sg (struct dwc3_ep *dep,struct dwc3_request *req) {
@@ -1101,8 +1142,6 @@ static int dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,struct scatterlist *s;int i;unsigned int length = req->request.length; -unsigned int maxp =usb_endpoint_maxp (dep->endpoint.desc); -unsigned int rem = length % maxp;unsigned int remaining = req->request.num_mapped_sgs - req->num_queued_sgs;unsigned int num_trbs = req->num_trbs;
@@ -1116,7 +1155,7 @@ static int dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,for_each_sg (sg, s, remaining, i) {unsigned int trb_length; -unsigned int chain = true; +bool last_sg = false; trb_length = min_t(unsigned int, length, sg_dma_len(s));
@@ -1130,45 +1169,16 @@ static int dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,* mapped sg. */ if ((i == remaining -1 ) || !length) - chain = false; + last_sg = true;if (!dwc3_calc_trbs_left (dep))break ; -if (rem &&usb_endpoint_dir_out (dep->endpoint.desc) && !chain) { -/* prepare normal TRB */ -if (req->request.length) { -if (dwc3_calc_trbs_left (dep) <2 ) - goto out; - - req->needs_extra_trb = true; -dwc3_prepare_one_trb (dep, req, trb_length, - true, i, false); - } - -/* Now prepare one extra TRB to align transfer size */ -dwc3_prepare_one_trb (dep, req, maxp - rem, - false,1 , true); - }else if (req->request.zero && req->request.length && - !usb_endpoint_xfer_isoc (dep->endpoint.desc) && - !rem && !chain) { - -if (dwc3_calc_trbs_left (dep) <2 ) +if (last_sg) { +if (!dwc3_prepare_last_sg (dep, req, trb_length, i)) goto out; - - req->needs_extra_trb = true; - -/* Prepare normal TRB */ -dwc3_prepare_one_trb (dep, req, trb_length, - true, i, false); - -/* Prepare one extra TRB to handle ZLP */ -dwc3_prepare_one_trb (dep, req, - req->direction ?0 : maxp, - false,1 , true); }else { -dwc3_prepare_one_trb (dep, req, trb_length, - chain, i, false); +dwc3_prepare_one_trb (dep, req, trb_length,1 , i, false); }/*
@@ -1178,7 +1188,7 @@ static int dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,* we have free trbs we can continue queuing from where we * previously stopped */ -if (chain) +if (!last_sg) req->start_sg =sg_next (s); req->num_queued_sgs++;
@@ -1224,50 +1234,7 @@ static int dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,static int dwc3_prepare_one_trb_linear (struct dwc3_ep *dep,struct dwc3_request *req) { -unsigned int length = req->request.length; -unsigned int maxp =usb_endpoint_maxp (dep->endpoint.desc); -unsigned int rem = length % maxp; -unsigned int num_trbs = req->num_trbs; - -if (!dwc3_calc_trbs_left (dep)) - goto out; - -if ((!length || rem) &&usb_endpoint_dir_out (dep->endpoint.desc)) { -/* prepare normal TRB */ -if (req->request.length) { -if (dwc3_calc_trbs_left (dep) <2 ) - goto out; - - req->needs_extra_trb = true; -dwc3_prepare_one_trb (dep, req, length, true,0 , false); - } - -/* Now prepare one extra TRB to align transfer size */ -dwc3_prepare_one_trb (dep, req, maxp - rem, false,1 , true); - }else if (req->request.zero && req->request.length && - !usb_endpoint_xfer_isoc (dep->endpoint.desc) && - (IS_ALIGNED (req->request.length, maxp))) { - -if (dwc3_calc_trbs_left (dep) <2 ) - goto out; - - req->needs_extra_trb = true; - -/* prepare normal TRB */ -dwc3_prepare_one_trb (dep, req, length, true,0 , false); - -/* Prepare one extra TRB to handle ZLP */ -dwc3_prepare_one_trb (dep, req, req->direction ?0 : maxp, - false,1 , true); - }else { -if (!dwc3_calc_trbs_left (dep)) - goto out; - -dwc3_prepare_one_trb (dep, req, length, false,0 , false); - } - -out: -return req->num_trbs - num_trbs; +return dwc3_prepare_last_sg (dep, req, req->request.length,0 ); }/*
Signature · 1 line
2.28.0
Thinh Nguyen
maintainerPATCH 10/10 usb: dwc3: gadget: Rename misleading function names
In reply to Thinh NguyenThe functions dwc3_prepare_one_trb_sg and dwc3_prepare_one_trb_linear are not necessarily preparing "one" TRB, it can prepare multiple TRBs. Rename these functions as follow:
dwc3_prepare_one_trb_sg -> dwc3_prepare_trbs_sg dwc3_prepare_one_trb_linear -> dwc3_prepare_trbs_linear
--- drivers/usb/dwc3/gadget.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/usb/dwc3/gadget.c +5 -5
@@ -1135,7 +1135,7 @@ static int dwc3_prepare_last_sg(struct dwc3_ep *dep,return num_trbs; } -static int dwc3_prepare_one_trb_sg (struct dwc3_ep *dep, +static int dwc3_prepare_trbs_sg (struct dwc3_ep *dep,struct dwc3_request *req) {struct scatterlist *sg = req->start_sg;
@@ -1231,7 +1231,7 @@ static int dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,return req->num_trbs - num_trbs; } -static int dwc3_prepare_one_trb_linear (struct dwc3_ep *dep, +static int dwc3_prepare_trbs_linear (struct dwc3_ep *dep,struct dwc3_request *req) {return dwc3_prepare_last_sg (dep, req, req->request.length,0 );
@@ -1266,7 +1266,7 @@ static int dwc3_prepare_trbs(struct dwc3_ep *dep)*/ list_for_each_entry (req, &dep->started_list, list) {if (req->num_pending_sgs >0 ) { - ret =dwc3_prepare_one_trb_sg (dep, req); + ret =dwc3_prepare_trbs_sg (dep, req);if (!ret)return ret; }
@@ -1297,9 +1297,9 @@ static int dwc3_prepare_trbs(struct dwc3_ep *dep) req->num_pending_sgs = req->request.num_mapped_sgs;if (req->num_pending_sgs >0 ) - ret =dwc3_prepare_one_trb_sg (dep, req); + ret =dwc3_prepare_trbs_sg (dep, req);else - ret =dwc3_prepare_one_trb_linear (dep, req); + ret =dwc3_prepare_trbs_linear (dep, req);if (!ret || !dwc3_calc_trbs_left (dep))return ret;
Signature · 1 line
2.28.0