usb: cdns3: improve the sg use case
Subsystems (3)
v2 cover usb: cdns3: improve the sg use case
For sg use cases, there will be serveral TRBs in TD, and the short transfer may occur during the TD, current code doesn't handle it well, improve it through this series. Tested by Android MTP and ADB use case.
Changes for v2:
- Fix some coding style and typo issues. [Patch 1, 2, 3, 5]
- Improve the comments [Patch 6,8]
Peter Chen (8):
usb: cdns3: gadget: using correct sg operations
usb: cdns3: gadget: improve the dump TRB operation at
cdns3_ep_run_transfer
usb: cdns3: gadget: calculate TDL correctly
usb: cdns3: gadget: add CHAIN and ISP bit for sg list use case
usb: cdns3: gadget: handle sg list use case at completion correctly
usb: cdns3: gadget: need to handle sg case for workaround 2 case
usb: cdns3: gadget: sg_support is only for DEV_VER_V2 or above
usb: cdns3: gadget: enlarge the TRB ring length
drivers/usb/cdns3/gadget.c | 202 +++++++++++++++++++++++++------------ drivers/usb/cdns3/gadget.h | 11 +- 2 files changed, 149 insertions(+), 64 deletions(-)
Signature · 1 line
2.17.1
PATCH v2 1/8 usb: cdns3: gadget: using correct sg operations
It needs to use request->num_mapped_sgs to indicate mapped sg number, the request->num_sgs is the sg number before the mapping. These two entries have different values for the platforms which iommu or swiotlb is used. Besides, it needs to use correct sg APIs for mapped sg list for TRB assignment.
--- drivers/usb/cdns3/gadget.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-)
drivers/usb/cdns3/gadget.c +15 -7
@@ -1098,11 +1098,13 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,u32 control;int pcs;u16 total_tdl =0 ; +struct scatterlist *s =NULL ; +bool sg_supported = !!(request->num_mapped_sgs);if (priv_ep->type ==USB_ENDPOINT_XFER_ISOC ) num_trb = priv_ep->interval;else - num_trb = request->num_sgs ? request->num_sgs :1 ; + num_trb = sg_supported ? request->num_mapped_sgs :1 ;if (num_trb > priv_ep->free_trbs) { priv_ep->flags |=EP_RING_FULL ;
@@ -1162,6 +1164,9 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,if (priv_dev->dev_ver <=DEV_VER_V2 ) togle_pcs =cdns3_wa1_update_guard (priv_ep, trb); +if (sg_supported) + s = request->sg; +/* set incorrect Cycle Bit for first trb*/ control = priv_ep->pcs ?0 :TRB_CYCLE ;
@@ -1171,13 +1176,13 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,/* fill TRB */ control |=TRB_TYPE (TRB_NORMAL ); - trb->buffer =cpu_to_le32 (TRB_BUFFER (request->num_sgs ==0 - ? trb_dma : request->sg[sg_iter].dma_address)); - -if (likely (!request->num_sgs)) +if (sg_supported) { + trb->buffer =cpu_to_le32 (TRB_BUFFER (sg_dma_address (s))); + length =sg_dma_len (s); + }else { + trb->buffer =cpu_to_le32 (TRB_BUFFER (trb_dma)); length = request->length; -else - length = request->sg[sg_iter].length; + }if (likely (priv_dev->dev_ver >=DEV_VER_V2 )) td_size = DIV_ROUND_UP(length,
@@ -1215,6 +1220,9 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,else priv_req->trb->control =cpu_to_le32 (control); +if (sg_supported) + s =sg_next (s); + control =0 ; ++sg_iter; priv_req->end_trb = priv_ep->enqueue;
Signature · 1 line
2.17.1
Re: [PATCH v2 1/8] usb: cdns3: gadget: using correct sg operations
Quoted 7 lines · Peter Chen
It needs to use
request->num_mapped_sgsto indicate mapped sg number, therequest->num_sgsis the sg number before the mapping. These two entries have different values for the platforms which iommu or swiotlb is used. Besides, it needs to use correct sg APIs for mapped sg list for TRB assignment.Signed-off-by Peter Chen <[email protected]>
fails to apply to my testing/next
checking file drivers/usb/cdns3/gadget.c
Hunk #1 succeeded at 1099 (offset 1 line). Hunk #2 succeeded at 1165 (offset 1 line). Hunk #3 FAILED at 1176.
Hunk #4 succeeded at 1221 with fuzz 2 (offset 1 line). 1 out of 4 hunks FAILED
Signature · 1 line
balbi
RE: [PATCH v2 1/8] usb: cdns3: gadget: using correct sg operations
Quoted 12 lines
Quoted 7 lines · Peter Chen
It needs to use
request->num_mapped_sgsto indicate mapped sg number, therequest->num_sgsis the sg number before the mapping. These two entries have different values for the platforms which iommu or swiotlb is used. Besides, it needs to use correct sg APIs for mapped sg list for TRB assignment.Signed-off-by Peter Chen <[email protected]>
Quoted 9 lines
fails to apply to my testing/next
checking file
drivers/usb/cdns3/gadget.cHunk #1 succeeded at 1099 (offset 1 line).
Hunk #2 succeeded at 1165 (offset 1 line).
Hunk #3 FAILED at 1176.
Hunk #4 succeeded at 1221 with fuzz 2 (offset 1 line).
1 out of 4 hunks FAILED
It could work now, I think the possible reason is you have already applied other cdns3 patches during these two hours. My git log likes below:
ca71afbe0c52 (HEAD -> felipe_testing_next) usb: cdns3: gadget: enlarge the TRB ring length 50599e28f626 usb: cdns3: gadget: sg_support is only for DEV_VER_V2 or above ed1e5b0fe5b2 usb: cdns3: gadget: need to handle sg case for workaround 2 case 95c952507262 usb: cdns3: gadget: handle sg list use case at completion correctly 9d45b67cf0c3 usb: cdns3: gadget: add CHAIN and ISP bit for sg list use case 28e5fd2c3fae usb: cdns3: gadget: calculate TDL correctlyf57692f1a9a4 usb: cdns3: gadget: improve the dump TRB operation at cdns3_ep_run_transfer 5f94832916b5 usb: cdns3: gadget: using correct sg operationsbed7c9e9a5aa (felipe/testing/next) usb: dwc3: gadget: Rename misleading function names 3d7ce113c2d0 usb: dwc3: gadget: Refactor preparing last TRBs43365b1e90af usb: dwc3: gadget: Set IOC if not enough for extra TRBs ea52ca3fdefb usb: dwc3: gadget: Check for number of TRBs prepared e6ccecf58b1b usb: dwc3: gadget: Return the number of prepared TRBs
Thanks,
Peter
Re: [PATCH v2 1/8] usb: cdns3: gadget: using correct sg operations
Quoted 40 lines · Peter Chen
Quoted 13 lines
Quoted 7 lines · Peter Chen
It needs to use
request->num_mapped_sgsto indicate mapped sg number, therequest->num_sgsis the sg number before the mapping. These two entries have different values for the platforms which iommu or swiotlb is used. Besides, it needs to use correct sg APIs for mapped sg list for TRB assignment.Signed-off-by Peter Chen <[email protected]>Quoted 9 lines
fails to apply to my testing/next
checking file
drivers/usb/cdns3/gadget.cHunk #1 succeeded at 1099 (offset 1 line).
Hunk #2 succeeded at 1165 (offset 1 line).
Hunk #3 FAILED at 1176.
Hunk #4 succeeded at 1221 with fuzz 2 (offset 1 line).
1 out of 4 hunks FAILEDIt could work now, I think the possible reason is you have already applied other cdns3 patches during these two hours. My git log likes below:
ca71afbe0c52(HEAD ->felipe_testing_next) usb: cdns3: gadget: enlarge the TRB ring length50599e28f626usb: cdns3: gadget:sg_supportis only forDEV_VER_V2or aboveed1e5b0fe5b2usb: cdns3: gadget: need to handle sg case for workaround 2 case95c952507262usb: cdns3: gadget: handle sg list use case at completion correctly9d45b67cf0c3usb: cdns3: gadget: add CHAIN and ISP bit for sg list use case28e5fd2c3faeusb: cdns3: gadget: calculate TDL correctlyf57692f1a9a4usb: cdns3: gadget: improve the dump TRB operation atcdns3_ep_run_transfer5f94832916b5usb: cdns3: gadget: using correct sg operationsbed7c9e9a5aa(felipe/testing/next) usb: dwc3: gadget: Rename misleading function names3d7ce113c2d0usb: dwc3: gadget: Refactor preparing last TRBs43365b1e90afusb: dwc3: gadget: Set IOC if not enough for extra TRBsea52ca3fdefbusb: dwc3: gadget: Check for number of TRBs preparede6ccecf58b1busb: dwc3: gadget: Return the number of prepared TRBs
Quoted 2 lines
Thanks,
Peter
Hi Felipe,
I have still not seen these patches on your tree, would you please help to queue them for v5.10-rc1?
Peter
Re: [PATCH v2 1/8] usb: cdns3: gadget: using correct sg operations
Hi,
Quoted 35 lines · Peter Chen
Quoted 35 lines
Quoted 8 lines
Quoted 7 lines
It needs to use
request->num_mapped_sgsto indicate mapped sg number, therequest->num_sgsis the sg number before the mapping. These two entries have different values for the platforms which iommu or swiotlb is used. Besides, it needs to use correct sg APIs for mapped sg list for TRB assignment.Signed-off-by Peter Chen <[email protected]>Quoted 9 lines
fails to apply to my testing/next
checking file
drivers/usb/cdns3/gadget.cHunk #1 succeeded at 1099 (offset 1 line).
Hunk #2 succeeded at 1165 (offset 1 line).
Hunk #3 FAILED at 1176.
Hunk #4 succeeded at 1221 with fuzz 2 (offset 1 line).
1 out of 4 hunks FAILEDIt could work now, I think the possible reason is you have already applied other cdns3 patches during these two hours. My git log likes below:
ca71afbe0c52(HEAD ->felipe_testing_next) usb: cdns3: gadget: enlarge the TRB ring length50599e28f626usb: cdns3: gadget:sg_supportis only forDEV_VER_V2or aboveed1e5b0fe5b2usb: cdns3: gadget: need to handle sg case for workaround 2 case95c952507262usb: cdns3: gadget: handle sg list use case at completion correctly9d45b67cf0c3usb: cdns3: gadget: add CHAIN and ISP bit for sg list use case28e5fd2c3faeusb: cdns3: gadget: calculate TDL correctlyf57692f1a9a4usb: cdns3: gadget: improve the dump TRB operation atcdns3_ep_run_transfer5f94832916b5usb: cdns3: gadget: using correct sg operationsbed7c9e9a5aa(felipe/testing/next) usb: dwc3: gadget: Rename misleading function names3d7ce113c2d0usb: dwc3: gadget: Refactor preparing last TRBs43365b1e90afusb: dwc3: gadget: Set IOC if not enough for extra TRBsea52ca3fdefbusb: dwc3: gadget: Check for number of TRBs preparede6ccecf58b1busb: dwc3: gadget: Return the number of prepared TRBs
Quoted 7 lines
Quoted 2 lines
Thanks,
PeterHi Felipe,
I have still not seen these patches on your tree, would you please help to queue them for v5.10-rc1?
Should be in testing/next now
Signature · 1 line
balbi
PATCH v2 2/8 usb: cdns3: gadget: improve the dump TRB operation at cdns3_ep_run_transfer
In reply to Peter ChenIt only dumps the first TRB per request, it is not useful if only dump the first TRB when there are several TRBs per request. We improve it by dumpping all TRBs per request in this commit.
--- drivers/usb/cdns3/gadget.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
drivers/usb/cdns3/gadget.c +17 -2
@@ -1090,6 +1090,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,struct cdns3_device *priv_dev = priv_ep->cdns3_dev;struct cdns3_request *priv_req;struct cdns3_trb *trb; +struct cdns3_trb *link_trb;dma_addr_t trb_dma;u32 togle_pcs =1 ;int sg_iter =0 ;
@@ -1130,7 +1131,6 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,/* prepare ring */ if ((priv_ep->enqueue + num_trb) >= (priv_ep->num_trbs -1 )) { -struct cdns3_trb *link_trb;int doorbell, dma_index;u32 ch_bit =0 ;
@@ -1266,7 +1266,22 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,if (priv_dev->dev_ver <=DEV_VER_V2 )cdns3_wa1_tray_restore_cycle_bit (priv_dev, priv_ep); -trace_cdns3_prepare_trb (priv_ep, priv_req->trb); +if (num_trb >1 ) { +int i =0 ; + +while (i < num_trb) { +trace_cdns3_prepare_trb (priv_ep, trb + i); +if (trb + i == link_trb) { + trb = priv_ep->trb_pool; + num_trb = num_trb - i; + i =0 ; + }else { + i++; + } + } + }else { +trace_cdns3_prepare_trb (priv_ep, priv_req->trb); + }/* * Memory barrier - Cycle Bit must be set before trb->length and
Signature · 1 line
2.17.1
PATCH v2 3/8 usb: cdns3: gadget: calculate TDL correctly
In reply to Peter ChenTDL is for TD length, so we need to calculate this value for TD (request), but not for TRB, the TDL value is only needed to stored at the first TRB in TD.
--- drivers/usb/cdns3/gadget.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/usb/cdns3/gadget.c +12 -11
@@ -1101,6 +1101,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,u16 total_tdl =0 ;struct scatterlist *s =NULL ;bool sg_supported = !!(request->num_mapped_sgs); +u16 td_size =0 ;if (priv_ep->type ==USB_ENDPOINT_XFER_ISOC ) num_trb = priv_ep->interval;
@@ -1169,10 +1170,17 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,/* set incorrect Cycle Bit for first trb*/ control = priv_ep->pcs ?0 :TRB_CYCLE ; + trb->length =0 ; +if (priv_dev->dev_ver >=DEV_VER_V2 ) { + td_size =DIV_ROUND_UP (request->length, priv_ep->endpoint.maxpacket); +if (priv_dev->gadget.speed ==USB_SPEED_SUPER ) + trb->length =TRB_TDL_SS_SIZE (td_size); +else + control |=TRB_TDL_HS_SIZE (td_size); + } do { u32 length; - u16 td_size = 0; /* fill TRB */ control |= TRB_TYPE(TRB_NORMAL);
@@ -1184,20 +1192,12 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, length = request->length; } -if (likely (priv_dev->dev_ver >=DEV_VER_V2 )) - td_size =DIV_ROUND_UP (length, - priv_ep->endpoint.maxpacket); -else if (priv_ep->flags &EP_TDLCHK_EN ) +if (priv_ep->flags &EP_TDLCHK_EN ) total_tdl +=DIV_ROUND_UP (length, priv_ep->endpoint.maxpacket); - trb->length =cpu_to_le32 (TRB_BURST_LEN (priv_ep->trb_burst_size) | + trb->length |=cpu_to_le32 (TRB_BURST_LEN (priv_ep->trb_burst_size) |TRB_LEN (length)); -if (priv_dev->gadget.speed ==USB_SPEED_SUPER ) - trb->length |=cpu_to_le32 (TRB_TDL_SS_SIZE (td_size)); -else - control |=TRB_TDL_HS_SIZE (td_size); - pcs = priv_ep->pcs ?TRB_CYCLE :0 ;/*
@@ -1228,6 +1228,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, priv_req->end_trb = priv_ep->enqueue;cdns3_ep_inc_enq (priv_ep); trb = priv_ep->trb_pool + priv_ep->enqueue; + trb->length =0 ; }while (sg_iter < num_trb); trb = priv_req->trb;
Signature · 1 line
2.17.1
PATCH v2 4/8 usb: cdns3: gadget: add CHAIN and ISP bit for sg list use case
In reply to Peter ChenFor sg buffer list use case, we need to add ISP for each TRB, and add CHAIN bit for each TRB except for the last TRB.
--- drivers/usb/cdns3/gadget.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/usb/cdns3/gadget.c +7 -1
@@ -1220,8 +1220,14 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,else priv_req->trb->control =cpu_to_le32 (control); -if (sg_supported) +if (sg_supported) { + trb->control |=TRB_ISP ; +/* Don't set chain bit for last TRB */ +if (sg_iter < num_trb -1 ) + trb->control |=TRB_CHAIN ; + s =sg_next (s); + } control =0 ; ++sg_iter;
Signature · 1 line
2.17.1
PATCH v2 5/8 usb: cdns3: gadget: handle sg list use case at completion correctly
In reply to Peter Chen- Judge each TRB has been handled at cdns3_trb_handled, since the DMA pointer may be at the middle of the TD, we can't consider this TD has finished at that time.
- Calculate req->actual according to finished TRBs.
- Handle short transfer for sg list use case correctly. When the short transfer occurs, we check OUT_SMM at TRB to see if it is the last TRB.
--- drivers/usb/cdns3/gadget.c | 85 +++++++++++++++++++++++++------------- drivers/usb/cdns3/gadget.h | 9 ++++ 2 files changed, 65 insertions(+), 29 deletions(-)
drivers/usb/cdns3/gadget.c +56 -29
@@ -817,6 +817,8 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, request->length); priv_req->flags &= ~(REQUEST_PENDING |REQUEST_UNALIGNED ); +/* All TRBs have finished, clear the counter */ + priv_req->finished_trb =0 ;trace_cdns3_gadget_giveback (priv_req);if (priv_dev->dev_ver <DEV_VER_V2 ) {
@@ -1240,6 +1242,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, trb = priv_req->trb; priv_req->flags |=REQUEST_PENDING ; + priv_req->num_of_trb = num_trb;if (sg_iter ==1 ) trb->control |=cpu_to_le32 (TRB_IOC |TRB_ISP );
@@ -1361,7 +1364,7 @@ void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) }/** -* cdns3_request_handled - check whether request has been handled by DMA +* cdns3_trb_handled - check whether trb has been handled by DMA * * @priv_ep: extended endpoint object. * @priv_req: request object for checking
@@ -1378,32 +1381,28 @@ void cdns3_set_hw_configuration(struct cdns3_device *priv_dev)* ET = priv_req->end_trb - index of last TRB in transfer ring * CI = current_index - index of processed TRB by DMA. * -* As first step, function checks if cycle bit for priv_req->start_trb is -* correct. +* As first step, we check if the TRB between the ST and ET. +* Then, we check if cycle bit for index priv_ep->dequeue +* is correct. * * some rules: -* 1. priv_ep->dequeue never exceed current_index. +* 1. priv_ep->dequeue never equals to current_index. * 2 priv_ep->enqueue never exceed priv_ep->dequeue * 3. exception: priv_ep->enqueue == priv_ep->dequeue * and priv_ep->free_trbs is zero. * This case indicate that TR is full. * -* Then We can split recognition into two parts: +* At below two cases, the request have been handled. * Case 1 - priv_ep->dequeue < current_index * SR ... EQ ... DQ ... CI ... ER * SR ... DQ ... CI ... EQ ... ER * -* Request has been handled by DMA if ST and ET is between DQ and CI. -* * Case 2 - priv_ep->dequeue > current_index -* This situation take place when CI go through the LINK TRB at the end of +* This situation takes place when CI go through the LINK TRB at the end of * transfer ring. * SR ... CI ... EQ ... DQ ... ER -* -* Request has been handled by DMA if ET is less then CI or -* ET is greater or equal DQ. */ -static bool cdns3_request_handled (struct cdns3_endpoint *priv_ep, +static bool cdns3_trb_handled (struct cdns3_endpoint *priv_ep,struct cdns3_request *priv_req) {struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
@@ -1415,7 +1414,25 @@ static bool cdns3_request_handled(struct cdns3_endpoint *priv_ep, current_index =cdns3_get_dma_pos (priv_dev, priv_ep); doorbell = !!(readl (&priv_dev->regs->ep_cmd) &EP_CMD_DRDY ); - trb = &priv_ep->trb_pool[priv_req->start_trb]; +/* current trb doesn't belong to this request */ +if (priv_req->start_trb < priv_req->end_trb) { +if (priv_ep->dequeue > priv_req->end_trb) + goto finish; + +if (priv_ep->dequeue < priv_req->start_trb) + goto finish; + } + +if ((priv_req->start_trb > priv_req->end_trb) && + (priv_ep->dequeue > priv_req->end_trb) && + (priv_ep->dequeue < priv_req->start_trb)) + goto finish; + +if ((priv_req->start_trb == priv_req->end_trb) && + (priv_ep->dequeue != priv_req->end_trb)) + goto finish; + + trb = &priv_ep->trb_pool[priv_ep->dequeue];if ((le32_to_cpu (trb->control) &TRB_CYCLE ) != priv_ep->ccs) goto finish;
@@ -1437,12 +1454,8 @@ static bool cdns3_request_handled(struct cdns3_endpoint *priv_ep, !priv_ep->dequeue) goto finish; -if (priv_req->end_trb >= priv_ep->dequeue && - priv_req->end_trb < current_index) - handled =1 ; + handled =1 ; }else if (priv_ep->dequeue > current_index) { -if (priv_req->end_trb < current_index || - priv_req->end_trb >= priv_ep->dequeue) handled =1 ; }
@@ -1458,6 +1471,8 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,struct cdns3_request *priv_req;struct usb_request *request;struct cdns3_trb *trb; +bool request_handled = false; +bool transfer_end = false;while (!list_empty (&priv_ep->pending_req_list)) { request =cdns3_next_request (&priv_ep->pending_req_list);
@@ -1477,20 +1492,32 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,*/ cdns3_select_ep (priv_dev, priv_ep->endpoint.address); -if (!cdns3_request_handled (priv_ep, priv_req)) - goto prepare_next_td; +while (cdns3_trb_handled (priv_ep, priv_req)) { + priv_req->finished_trb++; +if (priv_req->finished_trb >= priv_req->num_of_trb) + request_handled = true; - trb = priv_ep->trb_pool + priv_ep->dequeue; -trace_cdns3_complete_trb (priv_ep, trb); + trb = priv_ep->trb_pool + priv_ep->dequeue; +trace_cdns3_complete_trb (priv_ep, trb); -if (trb != priv_req->trb) -dev_warn (priv_dev->dev, -"request_trb=0x%p, queue_trb=0x%p\n" , - priv_req->trb, trb); +if (!transfer_end) + request->actual += +TRB_LEN (le32_to_cpu (trb->length)); - request->actual =TRB_LEN (le32_to_cpu (trb->length)); -cdns3_move_deq_to_next_trb (priv_req); -cdns3_gadget_giveback (priv_ep, priv_req,0 ); +if (priv_req->num_of_trb >1 && +le32_to_cpu (trb->control) &TRB_SMM ) + transfer_end = true; + +cdns3_ep_inc_deq (priv_ep); + } + +if (request_handled) { +cdns3_gadget_giveback (priv_ep, priv_req,0 ); + request_handled = false; + transfer_end = false; + }else { + goto prepare_next_td; + }if (priv_ep->type !=USB_ENDPOINT_XFER_ISOC &&TRBS_PER_SEGMENT ==2 )
drivers/usb/cdns3/gadget.h +9 -0
@@ -1030,6 +1030,11 @@ struct cdns3_trb {* When set to '1', the device will toggle its interpretation of the Cycle bit */ #define TRB_TOGGLE BIT(1) +/* +* The controller will set it if OUTSMM (OUT size mismatch) is detected, +* this bit is for normal TRB +*/ +#define TRB_SMM BIT(1)/* * Short Packet (SP). OUT EPs at DMULT=1 only. Indicates if the TRB was
@@ -1215,6 +1220,8 @@ struct cdns3_aligned_buf {* this endpoint * @flags: flag specifying special usage of request * @list: used by internally allocated request to add to wa2_descmiss_req_list. +* @finished_trb: number of trb has already finished per request +* @num_of_trb: how many trbs in this request */ struct cdns3_request {struct usb_request request;
@@ -1230,6 +1237,8 @@ struct cdns3_request {#define REQUEST_UNALIGNED BIT(4)u32 flags;struct list_head list; +int finished_trb; +int num_of_trb; };#define to_cdns3_request (r) (container_of(r, struct cdns3_request, request))
Signature · 1 line
2.17.1
PATCH v2 6/8 usb: cdns3: gadget: need to handle sg case for workaround 2 case
In reply to Peter ChenAdd sg case for workaround 2, the workaround 2 is described at the beginning of this file.
--- drivers/usb/cdns3/gadget.c | 44 +++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-)
drivers/usb/cdns3/gadget.c +31 -13
@@ -462,6 +462,36 @@ static int cdns3_start_all_request(struct cdns3_device *priv_dev, (reg) |=EP_STS_EN_DESCMISEN ; \ } }while (0 ) +static void __cdns3_descmiss_copy_data(struct usb_request *request, +struct usb_request *descmiss_req) +{ +int length = request->actual + descmiss_req->actual; +struct scatterlist *s = request->sg; + +if (!s) { +if (length <= request->length) { +memcpy (&((u8 *)request->buf)[request->actual], + descmiss_req->buf, + descmiss_req->actual); + request->actual = length; + }else { +/* It should never occures */ + request->status = -ENOMEM ; + } + }else { +if (length <=sg_dma_len (s)) { +void *p =phys_to_virt (sg_dma_address (s)); + +memcpy (&((u8 *)p)[request->actual], + descmiss_req->buf, + descmiss_req->actual); + request->actual = length; + }else { + request->status = -ENOMEM ; + } + } +} +/** * cdns3_wa2_descmiss_copy_data copy data from internal requests to * request queued by class driver.
@@ -488,21 +518,9 @@ static void cdns3_wa2_descmiss_copy_data(struct cdns3_endpoint *priv_ep, chunk_end = descmiss_priv_req->flags &REQUEST_INTERNAL_CH ; length = request->actual + descmiss_req->actual; - request->status = descmiss_req->status; - -if (length <= request->length) { -memcpy (&((u8 *)request->buf)[request->actual], - descmiss_req->buf, - descmiss_req->actual); - request->actual = length; - }else { -/* It should never occures */ - request->status = -ENOMEM ; - } - +__cdns3_descmiss_copy_data (request, descmiss_req);list_del_init (&descmiss_priv_req->list); -kfree (descmiss_req->buf);cdns3_gadget_ep_free_request (&priv_ep->endpoint, descmiss_req); --priv_ep->wa2_counter;
Signature · 1 line
2.17.1
PATCH v2 7/8 usb: cdns3: gadget: sg_support is only for DEV_VER_V2 or above
In reply to Peter ChenThe scatter buffer list support earlier than DEV_VER_V2 is not good enough, software can't know well about short transfer for it.
--- drivers/usb/cdns3/gadget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/cdns3/gadget.c +2 -1
@@ -3160,7 +3160,6 @@ static int cdns3_gadget_start(struct cdns3 *cdns) priv_dev->gadget.speed =USB_SPEED_UNKNOWN ; priv_dev->gadget.ops = &cdns3_gadget_ops; priv_dev->gadget.name ="usb-ss-gadget" ; - priv_dev->gadget.sg_supported =1 ; priv_dev->gadget.quirk_avoids_skb_reserve =1 ; priv_dev->gadget.irq = cdns->dev_irq;
@@ -3199,6 +3198,8 @@ static int cdns3_gadget_start(struct cdns3 *cdns) readl(&priv_dev->regs->usb_cap2)); priv_dev->dev_ver =GET_DEV_BASE_VERSION (priv_dev->dev_ver); +if (priv_dev->dev_ver >=DEV_VER_V2 ) + priv_dev->gadget.sg_supported =1 ; priv_dev->zlp_buf =kzalloc (CDNS3_EP_ZLP_BUF_SIZE ,GFP_KERNEL );if (!priv_dev->zlp_buf) {
Signature · 1 line
2.17.1
PATCH v2 8/8 usb: cdns3: gadget: enlarge the TRB ring length
In reply to Peter ChenAt Android ADB and MTP use case, it uses f_fs which supports scatter list, it means one request may need several TRBs for it. Besides, TRB consumes very fast compared to TRB has prepared for above use case, there are at most 120 pending requests, the date size is 16KB for each request, so four TRBs (4KB per TRB) per sg entry at worst case. so we need to enlarge the TRB ring length to avoid "no free TRB error". Since each TRB only consumes 12 bytes (3 * 32 bits), we enlarge the TRB length to 600, it leaves some buffers for potential "no free TRB error", and only increases a little memory cost.
--- drivers/usb/cdns3/gadget.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/cdns3/gadget.h +1 -1
@@ -966,7 +966,7 @@ struct cdns3_usb_regs {/* * USBSS-DEV DMA interface. */ -#define TRBS_PER_SEGMENT 40 +#define TRBS_PER_SEGMENT 600#define ISO_MAX_INTERVAL 10
Signature · 1 line
2.17.1