All of lore.kernel.org
 help / color / mirror / Atom feed
* [3/3] usb: dwc2: Add High Bandwidth ISOC OUT support
@ 2018-03-16 18:07 kbuild test robot
  0 siblings, 0 replies; 2+ messages in thread
From: kbuild test robot @ 2018-03-16 18:07 UTC (permalink / raw)
  To: Minas Harutyunyan
  Cc: kbuild-all, John Youn, Felipe Balbi, Greg Kroah-Hartman, linux-usb

Hi Minas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on next-20180309]
[cannot apply to v4.16-rc4 v4.16-rc3 v4.16-rc2 v4.16-rc5]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Minas-Harutyunyan/usb-dwc2-gadget-Update-ISOC-DDMA-flow/20180317-012732
config: i386-randconfig-x075-201810 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   drivers/usb/dwc2/gadget.c: In function 'dwc2_gadget_start_isoc_ddma':
>> drivers/usb/dwc2/gadget.c:944:3: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
      if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
      ^~
   drivers/usb/dwc2/gadget.c:948:4: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
       dwc2_writel(DXEPINT_OUTTKNEPDIS,
       ^~~~~~~~~~~
   drivers/usb/dwc2/gadget.c: In function 'dwc2_gadget_complete_isoc_request_ddma':
   drivers/usb/dwc2/gadget.c:2233:4: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
       if (sumofpid != 0)
       ^~
   drivers/usb/dwc2/gadget.c:2235:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
        break;
        ^~~~~
   drivers/usb/dwc2/gadget.c:2237:4: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
       if (sumofpid != 5)
       ^~
   drivers/usb/dwc2/gadget.c:2239:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
        break;
        ^~~~~
   drivers/usb/dwc2/gadget.c:2241:4: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
       if (sumofpid != 7)
       ^~
   drivers/usb/dwc2/gadget.c:2243:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
        break;
        ^~~~~

vim +/if +944 drivers/usb/dwc2/gadget.c

   887	
   888	/*
   889	 * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA
   890	 * @hs_ep: The isochronous endpoint.
   891	 *
   892	 * Prepare descriptor chain for isochronous endpoints. Afterwards
   893	 * write DMA address to HW and enable the endpoint.
   894	 */
   895	static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep)
   896	{
   897		struct dwc2_hsotg *hsotg = hs_ep->parent;
   898		struct dwc2_hsotg_req *hs_req, *treq;
   899		int index = hs_ep->index;
   900		int ret;
   901		u32 dma_reg;
   902		u32 depctl;
   903		u32 ctrl;
   904		struct dwc2_dma_desc *desc;
   905		int dpi;
   906	
   907		if (list_empty(&hs_ep->queue)) {
   908			hs_ep->target_frame = TARGET_FRAME_INITIAL;
   909			dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__);
   910			return;
   911		}
   912	
   913		/* Descriptor count per interval (dpi): for IN set to 1, for OUT
   914		 * set to mult, i.e. 1 descritor per each packet in frame
   915		 */
   916		dpi = 1;
   917		if (!hs_ep->dir_in)
   918			dpi = hs_ep->mc;
   919	
   920		/* Initialize descriptor chain by Host Busy status */
   921		for (ret = 0; ret < dpi * MAX_DMA_DESC_NUM_GENERIC; ret++) {
   922			desc = &hs_ep->desc_list[ret];
   923			desc->status = 0;
   924			desc->status |= (DEV_DMA_BUFF_STS_HBUSY
   925					    << DEV_DMA_BUFF_STS_SHIFT);
   926		}
   927	
   928		hs_ep->next_desc = 0;
   929		list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) {
   930			ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma,
   931							 hs_req->req.length);
   932			if (ret)
   933				break;
   934		}
   935	
   936		depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index);
   937		dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index);
   938	
   939		/* write descriptor chain address to control register */
   940		dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg);
   941	
   942		/* Wait for EOPF interrupt for current (u)frame */
   943		if (dpi > 1) {
 > 944			if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
   945						    GINTSTS_EOPF, 100))
   946				dev_warn(hsotg->dev,
   947					 "%s: timeout GINTSTS.EOPF\n", __func__);
   948				dwc2_writel(DXEPINT_OUTTKNEPDIS,
   949					    hsotg->regs + DOEPINT(hs_ep->index));
   950		}
   951	
   952		ctrl = dwc2_readl(hsotg->regs + depctl);
   953		ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK;
   954		dwc2_writel(ctrl, hsotg->regs + depctl);
   955	}
   956
---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [3/3] usb: dwc2: Add High Bandwidth ISOC OUT support
@ 2018-03-16  8:09 Minas Harutyunyan
  0 siblings, 0 replies; 2+ messages in thread
From: Minas Harutyunyan @ 2018-03-16  8:09 UTC (permalink / raw)
  To: John Youn, Felipe Balbi, Greg Kroah-Hartman, linux-usb; +Cc: Minas Harutyunyan

Updated checking of chain full condition based on  mult count.
For each packet in uframe (dpi) created new desc by
setting size of transfer to mps. Buffer addresses in descs
differ by mps in function dwc2_gadget_fill_isoc_desc().

In function dwc2_gadget_start_isoc_ddma() upadted loop
boundaries according to desc chain length.

In function dwc2_hsotg_ep_queue() added request length
checking for HB ISOC OUT transfers. Added dword aligned
limitation on maxpacket size for HB ISOC OUT's.

In function dwc2_gadget_complete_isoc_request_ddma()
separated processing of descs for HB ISOC OUT.
If completed descs PID equal MDATA do nothing, else
get remaining for frame descs and process them.
Actual length accumulated based on descs. Break
execution of the loop if data packet PID not MDATA.
If host sends less than mult data packets then skipping
unused desc for current uframe by restarting ISOC transfers.

In function dwc2_hsotg_ep_enable() desc chain allocation/
deallocation increased by mult times. Added bInterval
limit checking for HB ISOC OUT because on completion frame
number from desc used to check frame elapsed or no.

Signed-off-by: Minas Harutyunyan <hminas@synopsys.com>
---
 drivers/usb/dwc2/gadget.c | 348 +++++++++++++++++++++++++++++++++++++---------
 1 file changed, 284 insertions(+), 64 deletions(-)

diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 1b9c84cb58fb..6f081b456e61 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -806,55 +806,82 @@ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep,
 	u32 index;
 	u32 maxsize = 0;
 	u32 mask = 0;
+	int dpi, i;
 
+	/* Get descritor length limits */
 	maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask);
 
 	index = hs_ep->next_desc;
-	desc = &hs_ep->desc_list[index];
+
+	dpi = 1;
+	if (!hs_ep->dir_in)
+		dpi = hs_ep->mc;
 
 	/* Check if descriptor chain full */
-	if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) ==
-	    DEV_DMA_BUFF_STS_HREADY) {
-		dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__);
-		return 1;
+	for (i = 0; i < dpi; i++) {
+		/* Check descriptor chain rollover */
+		if ((index + i) >= dpi * MAX_DMA_DESC_NUM_GENERIC)
+			index = -1;
+
+		desc = &hs_ep->desc_list[index + i];
+		if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) ==
+		    DEV_DMA_BUFF_STS_HREADY) {
+			dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__);
+			return 1;
+		}
 	}
 
-	/* Clear L bit of previous desc if more than one entries in the chain */
-	if (hs_ep->next_desc)
-		hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L;
+	for (i = 0; i < dpi; i++) {
+		index = hs_ep->next_desc;
 
-	dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n",
-		__func__, hs_ep->index, hs_ep->dir_in ? "in" : "out", index);
+		/* Clear L bit of previous desc if more
+		 * than one entries in the chain
+		 */
+		if (hs_ep->next_desc)
+			hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L;
 
-	desc->status = 0;
-	desc->status |= (DEV_DMA_BUFF_STS_HBUSY	<< DEV_DMA_BUFF_STS_SHIFT);
+		desc = &hs_ep->desc_list[index];
 
-	desc->buf = dma_buff;
-	desc->status |= (DEV_DMA_L | DEV_DMA_IOC |
-			 ((len << DEV_DMA_NBYTES_SHIFT) & mask));
+		dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n",
+			__func__, hs_ep->index, hs_ep->dir_in ? "in" : "out",
+			index);
 
-	if (hs_ep->dir_in) {
-		desc->status |= ((hs_ep->mc << DEV_DMA_ISOC_PID_SHIFT) &
-				 DEV_DMA_ISOC_PID_MASK) |
-				((len % hs_ep->ep.maxpacket) ?
-				 DEV_DMA_SHORT : 0) |
-				((hs_ep->target_frame <<
-				  DEV_DMA_ISOC_FRNUM_SHIFT) &
-				 DEV_DMA_ISOC_FRNUM_MASK);
-	}
+		desc->status = 0;
+		desc->status |= (DEV_DMA_BUFF_STS_HBUSY <<
+				DEV_DMA_BUFF_STS_SHIFT);
 
-	desc->status &= ~DEV_DMA_BUFF_STS_MASK;
-	desc->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT);
+		desc->buf = dma_buff + i * hs_ep->ep.maxpacket;
+		desc->status |= (DEV_DMA_L | DEV_DMA_IOC);
+		if (hs_ep->dir_in)
+			desc->status |= ((len << DEV_DMA_NBYTES_SHIFT)
+					& mask);
+		else
+			desc->status |= ((hs_ep->ep.maxpacket <<
+					DEV_DMA_NBYTES_SHIFT) & mask);
+
+		if (hs_ep->dir_in) {
+			desc->status |= ((hs_ep->mc << DEV_DMA_ISOC_PID_SHIFT) &
+					 DEV_DMA_ISOC_PID_MASK) |
+					((len % hs_ep->ep.maxpacket) ?
+					 DEV_DMA_SHORT : 0) |
+					((hs_ep->target_frame <<
+					  DEV_DMA_ISOC_FRNUM_SHIFT) &
+					 DEV_DMA_ISOC_FRNUM_MASK);
+		}
 
-	/* Increment frame number by interval for IN */
-	if (hs_ep->dir_in)
-		dwc2_gadget_incr_frame_num(hs_ep);
+		desc->status &= ~DEV_DMA_BUFF_STS_MASK;
+		desc->status |= (DEV_DMA_BUFF_STS_HREADY
+				 << DEV_DMA_BUFF_STS_SHIFT);
 
-	/* Update index of last configured entry in the chain */
-	hs_ep->next_desc++;
-	if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_GENERIC)
-		hs_ep->next_desc = 0;
+		/* Increment frame number by interval for IN */
+		if (hs_ep->dir_in)
+			dwc2_gadget_incr_frame_num(hs_ep);
 
+		/* Update index of last configured entry in the chain */
+		hs_ep->next_desc++;
+		if (hs_ep->next_desc >= dpi * MAX_DMA_DESC_NUM_GENERIC)
+			hs_ep->next_desc = 0;
+	}
 	return 0;
 }
 
@@ -875,14 +902,23 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep)
 	u32 depctl;
 	u32 ctrl;
 	struct dwc2_dma_desc *desc;
+	int dpi;
 
 	if (list_empty(&hs_ep->queue)) {
+		hs_ep->target_frame = TARGET_FRAME_INITIAL;
 		dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__);
 		return;
 	}
 
+	/* Descriptor count per interval (dpi): for IN set to 1, for OUT
+	 * set to mult, i.e. 1 descritor per each packet in frame
+	 */
+	dpi = 1;
+	if (!hs_ep->dir_in)
+		dpi = hs_ep->mc;
+
 	/* Initialize descriptor chain by Host Busy status */
-	for (ret = 0; ret < MAX_DMA_DESC_NUM_GENERIC; ret++) {
+	for (ret = 0; ret < dpi * MAX_DMA_DESC_NUM_GENERIC; ret++) {
 		desc = &hs_ep->desc_list[ret];
 		desc->status = 0;
 		desc->status |= (DEV_DMA_BUFF_STS_HBUSY
@@ -903,6 +939,16 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep)
 	/* write descriptor chain address to control register */
 	dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg);
 
+	/* Wait for EOPF interrupt for current (u)frame */
+	if (dpi > 1) {
+		if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
+					    GINTSTS_EOPF, 100))
+			dev_warn(hsotg->dev,
+				 "%s: timeout GINTSTS.EOPF\n", __func__);
+			dwc2_writel(DXEPINT_OUTTKNEPDIS,
+				    hsotg->regs + DOEPINT(hs_ep->index));
+	}
+
 	ctrl = dwc2_readl(hsotg->regs + depctl);
 	ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK;
 	dwc2_writel(ctrl, hsotg->regs + depctl);
@@ -1309,10 +1355,17 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
 				req->length, maxsize);
 			return -EINVAL;
 		}
-		/* ISOC OUT high bandwidth not supported */
-		if (!hs_ep->dir_in && req->length > hs_ep->ep.maxpacket) {
-			dev_err(hs->dev, "ISOC OUT: wrong length %d (mps=%d)\n",
-				req->length, hs_ep->ep.maxpacket);
+		/* Checkings for ISOC OUT including high bandwidth */
+		if (!hs_ep->dir_in &&
+		    hs_ep->mc > 1 && (hs_ep->ep.maxpacket % 4)) {
+			dev_err(hs->dev, "mps not a dword aligned:%d\n",
+				hs_ep->ep.maxpacket);
+			return -EINVAL;
+		}
+		if (!hs_ep->dir_in &&
+		    (req->length > (hs_ep->mc * hs_ep->ep.maxpacket))) {
+			dev_err(hs->dev, "wrong len %d > mult*mps=%d\n",
+				req->length, hs_ep->mc * hs_ep->ep.maxpacket);
 			return -EINVAL;
 		}
 	}
@@ -2015,6 +2068,9 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg,
 		dwc2_gadget_start_next_request(hs_ep);
 }
 
+static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
+				   struct dwc2_hsotg_ep *hs_ep);
+
 /*
  * dwc2_gadget_complete_isoc_request_ddma - complete an isoc request in DDMA
  * @hs_ep: The endpoint the request was on.
@@ -2029,18 +2085,28 @@ static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep)
 	struct dwc2_hsotg *hsotg = hs_ep->parent;
 	struct dwc2_hsotg_req *hs_req;
 	struct usb_request *ureq;
-	int index;
+	int index, idx;
 	dma_addr_t dma_addr;
 	u32 dma_reg;
 	u32 depdma;
 	u32 desc_sts;
 	u32 mask;
+	int dpi;
+	int ret;
+	int sumofpid;
+
+	dpi = 1;
+	if (!hs_ep->dir_in)
+		dpi = hs_ep->mc;
 
 	hs_req = get_ep_head(hs_ep);
 	if (!hs_req) {
+		hs_ep->target_frame = TARGET_FRAME_INITIAL;
+		dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
 		dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__);
 		return;
 	}
+
 	ureq = &hs_req->req;
 
 	dma_addr = hs_ep->desc_list_dma;
@@ -2051,25 +2117,162 @@ static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep)
 	index = (depdma - dma_addr) / sizeof(struct dwc2_dma_desc) - 1;
 	/* Check descriptor chain rollover */
 	if (index < 0)
-		index = MAX_DMA_DESC_NUM_GENERIC - 1;
+		index = dpi * MAX_DMA_DESC_NUM_GENERIC - 1;
 
 	desc_sts = hs_ep->desc_list[index].status;
-	/* Check completion status */
-	if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT ==
-	    DEV_DMA_STS_SUCC) {
-		mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK :
-		       DEV_DMA_ISOC_RX_NBYTES_MASK;
-		ureq->actual = ureq->length -
-			       ((desc_sts & mask) >>
-				DEV_DMA_ISOC_NBYTES_SHIFT);
-
-		/* Adjust actual len for ISOC Out if len is not align of 4 */
-		if (!hs_ep->dir_in && ureq->length & 0x3)
-			ureq->actual += 4 - (ureq->length & 0x3);
 
-		dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+	if (dpi == 1) {
+		/* Check completion status for not High Bandwidth ISOC Out */
+		if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT ==
+		    DEV_DMA_STS_SUCC) {
+			mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK :
+			       DEV_DMA_ISOC_RX_NBYTES_MASK;
+			ureq->actual = ureq->length -
+				       ((desc_sts & mask) >>
+					DEV_DMA_ISOC_NBYTES_SHIFT);
+
+			/* Adjust actual len for ISOC Out if len is
+			 * not align of 4.
+			 */
+			if (!hs_ep->dir_in && dpi == 1 && ureq->length & 0x3)
+				ureq->actual += 4 - (ureq->length & 0x3);
+
+			dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+		} else {
+			dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req,
+						    -ETIMEDOUT);
+		}
 	} else {
-		dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ETIMEDOUT);
+		/* Check completion status for High Bandwidth ISOC Out. */
+		ret = 0;
+		/* Ignore interrupt if it not last in uframe. */
+		if (((desc_sts & DEV_DMA_ISOC_PID_MASK) >>
+		      DEV_DMA_ISOC_PID_SHIFT) == DEV_DMA_ISOC_PID_MDATA)
+			return;
+
+		idx = 0;
+		/* Complete requests with NODATA if some uframes are skiped */
+		while (hs_ep->target_frame !=
+		       (desc_sts & DEV_DMA_ISOC_FRNUM_MASK)
+			>> DEV_DMA_ISOC_FRNUM_SHIFT) {
+			idx++;
+			dwc2_hsotg_complete_request(hsotg, hs_ep,
+						    hs_req, -ENODATA);
+			hs_req = get_ep_head(hs_ep);
+			if (!hs_req) {
+				hs_ep->target_frame = TARGET_FRAME_INITIAL;
+				dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
+				dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n",
+					 __func__);
+				/* Clear late XFERCOMPL interrupts if any */
+				dwc2_writel(DXEPINT_XFERCOMPL, hsotg->regs +
+					DOEPINT(hs_ep->index));
+				return;
+			}
+
+			ureq = &hs_req->req;
+
+			dwc2_gadget_incr_frame_num(hs_ep);
+			hs_ep->target_frame &= (DEV_DMA_ISOC_FRNUM_MASK >>
+				DEV_DMA_ISOC_FRNUM_SHIFT);
+		}
+		/* Increment 1 more to set target to next uframe */
+		hs_ep->target_frame = (desc_sts & DEV_DMA_ISOC_FRNUM_MASK) >>
+			DEV_DMA_ISOC_FRNUM_SHIFT;
+		dwc2_gadget_incr_frame_num(hs_ep);
+		hs_ep->target_frame &= (DEV_DMA_ISOC_FRNUM_MASK >>
+			DEV_DMA_ISOC_FRNUM_SHIFT);
+
+		/* Need to restart if any request completed in above loop */
+		if (idx) {
+			dwc2_hsotg_complete_request(hsotg, hs_ep,
+						    hs_req, -ENODATA);
+			hs_req = get_ep_head(hs_ep);
+			if (!hs_req) {
+				hs_ep->target_frame = TARGET_FRAME_INITIAL;
+				dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
+				dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n",
+					 __func__);
+				/* Clear any late XFERCOMPL interrupts if any */
+				dwc2_writel(DXEPINT_XFERCOMPL, hsotg->regs +
+					DOEPINT(hs_ep->index));
+				return;
+			}
+			goto out;
+		}
+		ureq = &hs_req->req;
+
+		/* Because of interrupt latency after receiving interrupt
+		 * for 1st descriptor and when start handling the descriptor
+		 * index can be shifted to second or third descriptor.
+		 * On last descriptor (for uframe) completion process all
+		 * descritors for current uframe.
+		 */
+		sumofpid = 0;
+
+		for (idx = (index / dpi) * dpi; idx <= index; idx++) {
+			desc_sts = hs_ep->desc_list[idx].status;
+
+			if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT
+			     == DEV_DMA_STS_SUCC) {
+				ureq->actual += hs_ep->ep.maxpacket -
+						((desc_sts &
+						  DEV_DMA_ISOC_RX_NBYTES_MASK) >>
+						  DEV_DMA_ISOC_NBYTES_SHIFT);
+				sumofpid += (desc_sts & DEV_DMA_ISOC_PID_MASK)
+					     >> DEV_DMA_ISOC_PID_SHIFT;
+				} else {
+					ret = -ETIMEDOUT;
+					break;
+				}
+		}
+
+		/* Safety check packets PID sequence based on sumofpids:
+		 * if packet count = 1 then sumofpid should be 0
+		 * if packet count = 2 then sumofpid should be 3+2=5
+		 * if packet count = 3 then sumofpid should be 3+3+1=7
+		 */
+		switch (index - (index / dpi) * dpi + 1) {
+		case 1:
+			if (sumofpid != 0)
+				ret = -ETIMEDOUT;
+				break;
+		case 2:
+			if (sumofpid != 5)
+				ret = -ETIMEDOUT;
+				break;
+		case 3:
+			if (sumofpid != 7)
+				ret = -ETIMEDOUT;
+				break;
+		default:
+			dev_dbg(hsotg->dev, "%s: wrong sum of PID's %d\n",
+				__func__, sumofpid);
+		}
+
+		/* Clear EOPF intr for frame if some descs should be skiped */
+		if ((index - (index / dpi) * dpi + 1) < dpi)
+			dwc2_writel(GINTSTS_EOPF, hsotg->regs + GINTSTS);
+
+		/* Safety check */
+		if (ureq->actual > ureq->length)
+			ureq->actual = ureq->length;
+
+		dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, ret);
+
+		/* If packet count in current uframe less than mult then need
+		 * to skip unused for uframe descrioptors by restarting xfers
+		 */
+		idx = dpi - (index % dpi) - 1;
+out:
+		if (idx > 0) {
+			dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
+			dwc2_gadget_start_isoc_ddma(hs_ep);
+		}
+
+		/* Clear late XFERCOMPL and OUTTKNEPDIS interrupts if any */
+		dwc2_writel(DXEPINT_XFERCOMPL || DXEPINT_OUTTKNEPDIS,
+			    hsotg->regs + DOEPINT(hs_ep->index));
 	}
 }
 
@@ -2744,12 +2947,17 @@ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep)
 	 */
 	tmp = dwc2_hsotg_read_frameno(hsotg);
 
-	dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), -ENODATA);
-
 	if (using_desc_dma(hsotg)) {
 		if (ep->target_frame == TARGET_FRAME_INITIAL) {
+			dwc2_hsotg_complete_request(hsotg, ep,
+						    get_ep_head(ep), -ENODATA);
 			/* Start first ISO Out */
 			ep->target_frame = tmp;
+			dwc2_gadget_incr_frame_num(ep);
+			ep->target_frame &= (DEV_DMA_ISOC_FRNUM_MASK >>
+				DEV_DMA_ISOC_FRNUM_SHIFT);
+			/* Clear EOPF interrupt */
+			dwc2_writel(GINTSTS_EOPF, hsotg->regs + GINTSTS);
 			dwc2_gadget_start_isoc_ddma(ep);
 		}
 		return;
@@ -3774,6 +3982,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
 	unsigned int i, val, size;
 	int ret = 0;
 	unsigned char ep_type;
+	int dpi;
 
 	dev_dbg(hsotg->dev,
 		"%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n",
@@ -3792,17 +4001,20 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
 		return -EINVAL;
 	}
 
+	mc = usb_endpoint_maxp_mult(desc);
+
 	ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
 	/* ISOC DDMA supported bInterval up to 12 */
-	if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC &&
-	    dir_in && desc->bInterval > 12) {
-		dev_err(hsotg->dev,
-			"%s: ISOC IN: bInterval>12 not supported!\n", __func__);
-		return -EINVAL;
+	if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC) {
+		if ((dir_in || (!dir_in && mc > 1)) && desc->bInterval > 12) {
+			dev_err(hsotg->dev,
+				"%s: ISOC IN/OUT(HB): bInterval>12 not supported!\n",
+				__func__);
+			return -EINVAL;
+		}
 	}
 
 	mps = usb_endpoint_maxp(desc);
-	mc = usb_endpoint_maxp_mult(desc);
 
 	/* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */
 
@@ -3812,10 +4024,18 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
 	dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
 		__func__, epctrl, epctrl_reg);
 
+	/* ISOC Descriptor count per interval (dpi): for IN set to 1,
+	 * for OUT set to mult, i.e. 1 descritor per each packet in frame
+	 */
+	dpi = 1;
+	if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC &&
+	    !dir_in)
+		dpi = mc;
+
 	/* Allocate DMA descriptor chain for non-ctrl endpoints */
 	if (using_desc_dma(hsotg) && !hs_ep->desc_list) {
 		hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev,
-			MAX_DMA_DESC_NUM_GENERIC *
+			dpi * MAX_DMA_DESC_NUM_GENERIC *
 			sizeof(struct dwc2_dma_desc),
 			&hs_ep->desc_list_dma, GFP_ATOMIC);
 		if (!hs_ep->desc_list) {
@@ -3936,7 +4156,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
 
 error2:
 	if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) {
-		dmam_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC *
+		dmam_free_coherent(hsotg->dev, dpi * MAX_DMA_DESC_NUM_GENERIC *
 			sizeof(struct dwc2_dma_desc),
 			hs_ep->desc_list, hs_ep->desc_list_dma);
 		hs_ep->desc_list = NULL;

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-03-16 18:07 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-16 18:07 [3/3] usb: dwc2: Add High Bandwidth ISOC OUT support kbuild test robot
  -- strict thread matches above, loose matches on Subject: below --
2018-03-16  8:09 Minas Harutyunyan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.