RE: [PATCH v1 2/3] usb: dwc2: Change ISOC DDMA flow

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Minas:

>-----Original Message-----
>From: Minas Harutyunyan [mailto:Minas.Harutyunyan@xxxxxxxxxxxx]
>Sent: Wednesday, March 21, 2018 4:08 PM
>To: Zengtao (B) <prime.zeng@xxxxxxxxxxxxx>; Minas Harutyunyan
><Minas.Harutyunyan@xxxxxxxxxxxx>; John Youn <John.Youn@xxxxxxxxxxxx>;
>Felipe Balbi <balbi@xxxxxxxxxx>; Greg Kroah-Hartman
><gregkh@xxxxxxxxxxxxxxxxxxx>; linux-usb@xxxxxxxxxxxxxxx
>Subject: Re: [PATCH v1 2/3] usb: dwc2: Change ISOC DDMA flow
>
>Hi Zengtao,
>
>On 3/21/2018 6:17 AM, Zengtao (B) wrote:
>>> -----Original Message-----
>>
>>> From: linux-usb-owner@xxxxxxxxxxxxxxx
>>
>>> [mailto:linux-usb-owner@xxxxxxxxxxxxxxx] On Behalf Of Minas
>>> Harutyunyan
>>
>>> Sent: Tuesday, March 20, 2018 10:40 PM
>>
>>> To: Zengtao (B) <prime.zeng@xxxxxxxxxxxxx>; Minas Harutyunyan
>>
>>> <Minas.Harutyunyan@xxxxxxxxxxxx>; John Youn
><John.Youn@xxxxxxxxxxxx>;
>>
>>> Felipe Balbi <balbi@xxxxxxxxxx>; Greg Kroah-Hartman
>>
>>> <gregkh@xxxxxxxxxxxxxxxxxxx>; linux-usb@xxxxxxxxxxxxxxx
>>
>>> Subject: Re: [PATCH v1 2/3] usb: dwc2: Change ISOC DDMA flow
>>
>>>
>>
>>> Hi Zengtao,
>>
>>>
>>
>>> On 3/20/2018 6:01 AM, Zengtao (B) wrote:
>>
>>>> Hi Minas:
>>
>>>>
>>
>>>>
>>
>>>>
>>
>>>> A few minor comments:
>>
>>>>
>>
>>>>
>>
>>>>
>>
>>>>> -----Original Message-----
>>
>>>>
>>
>>>>> From: linux-usb-owner@xxxxxxxxxxxxxxx
>>
>>>>
>>
>>>>> [mailto:linux-usb-owner@xxxxxxxxxxxxxxx] On Behalf Of Minas
>>
>>>>> Harutyunyan
>>
>>>>
>>
>>>>> Sent: Saturday, March 17, 2018 5:10 PM
>>
>>>>
>>
>>>>> To: John Youn <John.Youn@xxxxxxxxxxxx>; Felipe Balbi
>>
>>>>> <balbi@xxxxxxxxxx>;
>>
>>>>
>>
>>>>> Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>;
>>
>>>>> linux-usb@xxxxxxxxxxxxxxx
>>
>>>>
>>
>>>>> Cc: Minas Harutyunyan <Minas.Harutyunyan@xxxxxxxxxxxx>
>>
>>>>
>>
>>>>> Subject: [PATCH v1 2/3] usb: dwc2: Change ISOC DDMA flow
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> Changed existing two descriptor-chain flow to one chain.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> In two-chain implementation BNA interrupt used for switching
>>>>> between
>>
>>>>> two
>>
>>>>
>>
>>>>> chains. BNA interrupt asserted because of returning to beginning of
>>
>>>>> the chain
>>
>>>>
>>
>>>>> based on L-bit of last descriptor.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> Because of that we lose packets. This issue resolved by using one
>desc-chain.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> Removed all staff related to two desc-chain flow from DDMA ISOC
>>
>>>>> related
>>
>>>>
>>
>>>>> functions.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> Removed request length checking from dwc2_gadget_fill_isoc_desc()
>>
>>> function.
>>
>>>>
>>
>>>>> Request length checking added to dwc2_hsotg_ep_queue() function. If
>>
>>>>> request
>>
>>>>
>>
>>>>> length greater than descriptor limits then request not added to queue.
>>
>>>>
>>
>>>>> Additional checking done for High Bandwidth ISOC OUT's which not
>>
>>>>> supported by
>>
>>>>
>>
>>>>> driver. In
>>
>>>>
>>
>>>>> dwc2_gadget_fill_isoc_desc() function also checked desc-chain
>>>>> status
>>
>>>>> (full or not)
>>
>>>>
>>
>>>>> to avoid of reusing not yet processed descriptors.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> In dwc2_gadget_start_isoc_ddma() function creation of desc-chain
>>
>>>>> always
>>
>>>>
>>
>>>>> started from descriptor 0. Before filling descriptors, they were
>>
>>>>> initialized by
>>
>>>>
>>
>>>>> HOST BUSY status.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> In dwc2_gadget_complete_isoc_request_ddma() added checking for
>>
>>>>> desc-chain
>>
>>>>
>>
>>>>> rollover. Also added checking completion status.
>>
>>>>
>>
>>>>> Request completed successfully if DEV_DMA_STS is DEV_DMA_STS_SUCC,
>>
>>>>
>>
>>>>> otherwise complete with -ETIMEDOUT.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> Actually removed dwc2_gadget_start_next_isoc_ddma() function
>>>>> because
>>
>>>>> now
>>
>>>>
>>
>>>>> driver use only one desc-chain and instead that function added
>>
>>>>
>>
>>>>> dwc2_gadget_handle_isoc_bna() function for handling BNA interrupts.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> Handling BNA interrupt done by flushing TxFIFOs for OUT EPs,
>>
>>>>> completing
>>
>>>>
>>
>>>>> request with -EIO and resetting desc-chain number and target frame
>>>>> to
>>
>>>>> initial
>>
>>>>
>>
>>>>> values for restarting transfers.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> On handling NAK request completed with -ENODATA. Incremented target
>>
>>>>> frame
>>
>>>>
>>
>>>>> to allow fill desc chain and start transfers.
>>
>>>>
>>
>>>>> In DDMA mode avoided of frame number incrementing, because tracking
>>
>>>>> of
>>
>>>>
>>
>>>>> frame number performed in dwc2_gadget_fill_isoc_desc() function.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> When core assert XferCompl along with BNA, we should ignore
>>>>> XferCompl
>>
>>>>> in
>>
>>>>
>>
>>>>> dwc2_hsotg_epint() function.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> On BNA interrupt replaced dwc2_gadget_start_next_isoc_ddma() by
>>>>> above
>>
>>>>
>>
>>>>> mentioned BNA handler.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> In dwc2_hsotg_ep_enable() function added sanity check of bInterval
>>
>>>>> for ISOC IN
>>
>>>>
>>
>>>>> in DDMA mode, because HW not supported EP's with bInterval more than
>12.
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> Signed-off-by: Minas Harutyunyan <hminas@xxxxxxxxxxxx>
>>
>>>>
>>
>>>>> ---
>>
>>>>
>>
>>>>> drivers/usb/dwc2/core.h   |   2 -
>>
>>>>
>>
>>>>> drivers/usb/dwc2/gadget.c | 235
>>
>>>>> ++++++++++++++++++++++------------------------
>>
>>>>
>>
>>>>> 2 files changed, 113 insertions(+), 124 deletions(-)
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
>>>>> index
>>
>>>>
>>
>>>>> d83be5651f87..093d078adaf4 100644
>>
>>>>
>>
>>>>> --- a/drivers/usb/dwc2/core.h
>>
>>>>
>>
>>>>> +++ b/drivers/usb/dwc2/core.h
>>
>>>>
>>
>>>>> @@ -178,7 +178,6 @@ struct dwc2_hsotg_req;
>>
>>>>
>>
>>>>>    * @desc_list_dma: The DMA address of descriptor chain currently in
>use.
>>
>>>>
>>
>>>>>    * @desc_list: Pointer to descriptor DMA chain head currently in use.
>>
>>>>
>>
>>>>>    * @desc_count: Count of entries within the DMA descriptor chain of
>EP.
>>
>>>>
>>
>>>>> - * @isoc_chain_num: Number of ISOC chain currently in use - either 0 or 1.
>>
>>>>
>>
>>>>>    * @next_desc: index of next free descriptor in the ISOC chain
>>>>> under
>>
>>>>> SW
>>
>>>>
>>
>>>>> control.
>>
>>>>
>>
>>>>>    * @total_data: The total number of data bytes done.
>>
>>>>
>>
>>>>>    * @fifo_size: The size of the FIFO (for periodic IN endpoints)
>>>>> @@
>>
>>>>> -231,7
>>
>>>>
>>
>>>>> +230,6 @@ struct dwc2_hsotg_ep {
>>
>>>>
>>
>>>>> 	struct dwc2_dma_desc	*desc_list;
>>
>>>>
>>
>>>>> 	u8			desc_count;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> -	unsigned char		isoc_chain_num;
>>
>>>>
>>
>>>>> 	unsigned int		next_desc;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	char                    name[10];
>>
>>>>
>>
>>>>> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
>>
>>>>> index
>>
>>>>
>>
>>>>> c231321656f9..1b9c84cb58fb 100644
>>
>>>>
>>
>>>>> --- a/drivers/usb/dwc2/gadget.c
>>
>>>>
>>
>>>>> +++ b/drivers/usb/dwc2/gadget.c
>>
>>>>
>>
>>>>> @@ -793,9 +793,7 @@ static void
>>
>>>>
>>
>>>>> dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep,
>>
>>>>
>>
>>>>>    * @dma_buff: usb requests dma buffer.
>>
>>>>
>>
>>>>>    * @len: usb request transfer length.
>>
>>>>
>>
>>>>>    *
>>
>>>>
>>
>>>>> - * Finds out index of first free entry either in the bottom or up
>>
>>>>> half of
>>
>>>>
>>
>>>>> - * descriptor chain depend on which is under SW control and not
>>
>>>>> processed
>>
>>>>
>>
>>>>> - * by HW. Then fills that descriptor with the data of the arrived
>>
>>>>> usb request,
>>
>>>>
>>
>>>>> + * Fills next free descriptor with the data of the arrived usb
>>
>>>>> + request,
>>
>>>>
>>
>>>>>    * frame info, sets Last and IOC bits increments next_desc. If
>>
>>>>> filled
>>
>>>>
>>
>>>>>    * descriptor is not the first one, removes L bit from the
>>>>> previous
>>
>>>>> descriptor
>>
>>>>
>>
>>>>>    * status.
>>
>>>>
>>
>>>>> @@ -810,34 +808,17 @@ static int dwc2_gadget_fill_isoc_desc(struct
>>
>>>>
>>
>>>>> dwc2_hsotg_ep *hs_ep,
>>
>>>>
>>
>>>>> 	u32 mask = 0;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask);
>>
>>>>
>>
>>>>> -	if (len > maxsize) {
>>
>>>>
>>
>>>>> -		dev_err(hsotg->dev, "wrong len %d\n", len);
>>
>>>>
>>
>>>>> -		return -EINVAL;
>>
>>>>
>>
>>>>> -	}
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> -	/*
>>
>>>>
>>
>>>>> -	 * If SW has already filled half of chain, then return and wait for
>>
>>>>
>>
>>>>> -	 * the other chain to be processed by HW.
>>
>>>>
>>
>>>>> -	 */
>>
>>>>
>>
>>>>> -	if (hs_ep->next_desc == MAX_DMA_DESC_NUM_GENERIC / 2)
>>
>>>>
>>
>>>>> -		return -EBUSY;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> -	/* Increment frame number by interval for IN */
>>
>>>>
>>
>>>>> -	if (hs_ep->dir_in)
>>
>>>>
>>
>>>>> -		dwc2_gadget_incr_frame_num(hs_ep);
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> -	index = (MAX_DMA_DESC_NUM_GENERIC / 2) *
>hs_ep->isoc_chain_num +
>>
>>>>
>>
>>>>> -		 hs_ep->next_desc;
>>
>>>>
>>
>>>>> +	index = hs_ep->next_desc;
>>
>>>>
>>
>>>>> +	desc = &hs_ep->desc_list[index];
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> -	/* Sanity check of calculated index */
>>
>>>>
>>
>>>>> -	if ((hs_ep->isoc_chain_num && index >
>MAX_DMA_DESC_NUM_GENERIC)
>>
>>>>
>>
>>>>> ||
>>
>>>>
>>
>>>>> -	    (!hs_ep->isoc_chain_num && index >
>>
>>>>
>>
>>>>> MAX_DMA_DESC_NUM_GENERIC / 2)) {
>>
>>>>
>>
>>>>> -		dev_err(hsotg->dev, "wrong index %d for iso chain\n", index);
>>
>>>>
>>
>>>>> -		return -EINVAL;
>>
>>>>
>>
>>>>> +	/* 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;
>>
>>>>
>>
>>>>> 	}
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> -	desc = &hs_ep->desc_list[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; @@ -865,8
>>
>>>>
>>
>>>>
>>
>>>>
>>
>>>> When changing the status of the desc, How to sync the SW with the HW?
>>
>>>>
>>
>>>> Since the HW and SW is working on the same desc synchronously.
>>
>>>
>>
>>> Not clear for what you mean: HW and SW working on same desc
>synchronously?
>>
>>> Descriptor list is like Producer(SW)/Consumer(HW) list.
>>
>>> Index management allow always keep gap between Producer and Consumer
>>
>>> indexes. Producer index should be always more than Consumer index. In
>>> some
>>
>>> cases when Consumer index achieved Producer index, which mean no more
>>
>>> ready descriptor to process then BNA interrupt will be asserted, i.e
>>> SW can't
>>
>>> enough bandwidth to submit new requests.
>>
>>>
>>
>>
>>
>> About my question,
>>
>> I mean when you clear the DEV_DMA_L bit of last desc in the chain, the
>> HW may be
>>
>> accessing this particular desc at the same time, so perhaps the
>> DEV_DMA_L bit
>>
>> clear action is not sync to the HW, and the HW can't work as we want.
>>
>>
>Core always fetching 1 descriptor based on:
>1. ISOC IN - one uf before target uf.
>2. ISOC OUT - RxFIFO NonEmpty, EP enabled.
>As I mentioned before, between producer and consumer indexes should be
>enough gap. If not, then BNA will be asserted, EP will be disabled and will need
>to restart transfers from scratch based on IN-NAK (ISOC IN) or OUT-EPDis (ISOC
>OUT) interrupts.
>>

How do you ensure enough gap between the producer and consumer?
The producer fill new desc at random time, and when clearing the DEV_DMA_L bit
of the last desc in the chain, interrupts is disabled and we may delay or miss the
BNA interrupt. 
Linux is not a real time system, so I think we should consider such corner cases.

>> Per your comment, you mentioned the producer and consumer, but
>>
>> How do you do the synchronization between the producer and consumer?
>>
>Actually, as soon as consumer complete some desc then dwc2 complete
>appropriate producers request to function driver then function driver queuing
>new request. So, initial gap will be kept.
>>

It is not mandatary for the function driver to queuing new request in the complete
handler. we can't depend on the function driver to keep the gap.

>>
>>>>
>>
>>>>>
>>
>>>>> +846,14 @@ static int dwc2_gadget_fill_isoc_desc(struct
>>>>> +dwc2_hsotg_ep
>>
>>>>
>>
>>>>> *hs_ep,
>>
>>>>
>>
>>>>> 	desc->status &= ~DEV_DMA_BUFF_STS_MASK;
>>
>>>>
>>
>>>>> 	desc->status |= (DEV_DMA_BUFF_STS_HREADY <<
>>
>>>>
>>
>>>>> DEV_DMA_BUFF_STS_SHIFT);
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> +	/* 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 >= MAX_DMA_DESC_NUM_GENERIC)
>>
>>>>
>>
>>>>> +		hs_ep->next_desc = 0;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	return 0;
>>
>>>>
>>
>>>>> }
>>
>>>>
>>
>>>>> @@ -875,11 +862,8 @@ static int dwc2_gadget_fill_isoc_desc(struct
>>
>>>>
>>
>>>>> dwc2_hsotg_ep *hs_ep,
>>
>>>>
>>
>>>>>    * dwc2_gadget_start_isoc_ddma - start isochronous transfer in
>>>>> DDMA
>>
>>>>
>>
>>>>>    * @hs_ep: The isochronous endpoint.
>>
>>>>
>>
>>>>>    *
>>
>>>>
>>
>>>>> - * Prepare first descriptor chain for isochronous endpoints.
>>
>>>>> Afterwards
>>
>>>>
>>
>>>>> + * Prepare descriptor chain for isochronous endpoints. Afterwards
>>
>>>>
>>
>>>>>    * write DMA address to HW and enable the endpoint.
>>
>>>>
>>
>>>>> - *
>>
>>>>
>>
>>>>> - * Switch between descriptor chains via isoc_chain_num to give SW
>>
>>>>> opportunity
>>
>>>>
>>
>>>>> - * to prepare second descriptor chain while first one is being
>>>>> processed by
>>
>>> HW.
>>
>>>>
>>
>>>>>    */
>>
>>>>
>>
>>>>> static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep
>>>>> *hs_ep)
>>
>>>>
>>
>>>>> { @@ -890,19 +874,27 @@ static void
>>
>>>>> dwc2_gadget_start_isoc_ddma(struct
>>
>>>>
>>
>>>>> dwc2_hsotg_ep *hs_ep)
>>
>>>>
>>
>>>>> 	u32 dma_reg;
>>
>>>>
>>
>>>>> 	u32 depctl;
>>
>>>>
>>
>>>>> 	u32 ctrl;
>>
>>>>
>>
>>>>> +	struct dwc2_dma_desc *desc;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	if (list_empty(&hs_ep->queue)) {
>>
>>>>
>>
>>>>> 		dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__);
>>
>>>>
>>
>>>>> 		return;
>>
>>>>
>>
>>>>> 	}
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> +	/* Initialize descriptor chain by Host Busy status */
>>
>>>>
>>
>>>>> +	for (ret = 0; ret < MAX_DMA_DESC_NUM_GENERIC; ret++) {
>>
>>>>
>>
>>>>> +		desc = &hs_ep->desc_list[ret];
>>
>>>>
>>
>>>>> +		desc->status = 0;
>>
>>>>
>>
>>>>> +		desc->status |= (DEV_DMA_BUFF_STS_HBUSY
>>
>>>>
>>
>>>>> +				    << DEV_DMA_BUFF_STS_SHIFT);
>>
>>>>
>>
>>>>> +	}
>>
>>>>
>>
>>>>> +
>>
>>>>
>>
>>>>
>>
>>>>
>>
>>>> Ret is not a good naming as the loop counter.
>>
>>>>
>>
>>>
>>
>>> Could be, but it just reuse existing variable instead to define new one.
>>
>>>
>>
>>
>>
>>  From the code reader's perspective, it is a bit strange.
>>
>Ok, will declare new variable.
>>
>>
>>>>
>>
>>>>
>>
>>>>> +	hs_ep->next_desc = 0;
>>
>>>>
>>
>>>>> 	list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) {
>>
>>>>
>>
>>>>
>>
>>>>
>>
>>>> Do we really need safe function here? We have already have the spinlock.
>>
>>>>
>>
>>> I left existing list_for_each_entry_safe() not of part of this patch.
>>
>>>
>>
>>>>
>>
>>>>
>>
>>>>> 		ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma,
>>
>>>>
>>
>>>>> 						 hs_req->req.length);
>>
>>>>
>>
>>>>> -		if (ret) {
>>
>>>>
>>
>>>>> -			dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__);
>>
>>>>
>>
>>>>> +		if (ret)
>>
>>>>
>>
>>>>> 			break;
>>
>>>>
>>
>>>>> -		}
>>
>>>>
>>
>>>>> 	}
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); @@
>>>>> -914,10
>>
>>>>
>>
>>>>> +906,6 @@ static void dwc2_gadget_start_isoc_ddma(struct
>>
>>>>> +dwc2_hsotg_ep
>>
>>>>
>>
>>>>> *hs_ep)
>>
>>>>
>>
>>>>> 	ctrl = dwc2_readl(hsotg->regs + depctl);
>>
>>>>
>>
>>>>> 	ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK;
>>
>>>>
>>
>>>>> 	dwc2_writel(ctrl, hsotg->regs + depctl);
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> -	/* Switch ISOC descriptor chain number being processed by SW*/
>>
>>>>
>>
>>>>> -	hs_ep->isoc_chain_num = (hs_ep->isoc_chain_num ^ 1) & 0x1;
>>
>>>>
>>
>>>>> -	hs_ep->next_desc = 0;
>>
>>>>
>>
>>>>> }
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> /**
>>
>>>>
>>
>>>>> @@ -1291,6 +1279,9 @@ static int dwc2_hsotg_ep_queue(struct usb_ep
>>
>>>>> *ep,
>>
>>>>
>>
>>>>> struct usb_request *req,
>>
>>>>
>>
>>>>> 	struct dwc2_hsotg *hs = hs_ep->parent;
>>
>>>>
>>
>>>>> 	bool first;
>>
>>>>
>>
>>>>> 	int ret;
>>
>>>>
>>
>>>>> +	u32 maxsize = 0;
>>
>>>>
>>
>>>>> +	u32 mask = 0;
>>
>>>>
>>
>>>>> +
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d,
>snok=%d\n",
>>
>>>>
>>
>>>>> 		ep->name, req, req->length, req->buf, req->no_interrupt, @@
>>>>> -1308,6
>>
>>>>
>>
>>>>> +1299,24 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep,
>>>>> +struct
>>
>>>>
>>
>>>>> usb_request *req,
>>
>>>>
>>
>>>>> 	req->actual = 0;
>>
>>>>
>>
>>>>> 	req->status = -EINPROGRESS;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> +	/* In DDMA mode for ISOC's don't queue request if length greater
>>
>>>>
>>
>>>>> +	 * than descriptor limits.
>>
>>>>
>>
>>>>> +	 */
>>
>>>>
>>
>>>>> +	if (using_desc_dma(hs) && hs_ep->isochronous) {
>>
>>>>
>>
>>>>> +		maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask);
>>
>>>>
>>
>>>>> +		if (hs_ep->dir_in && req->length > maxsize) {
>>
>>>>
>>
>>>>> +			dev_err(hs->dev, "wrong length %d (maxsize=%d)\n",
>>
>>>>
>>
>>>>> +				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);
>>
>>>>
>>
>>>>> +			return -EINVAL;
>>
>>>>
>>
>>>>> +		}
>>
>>>>
>>
>>>>> +	}
>>
>>>>
>>
>>>>> +
>>
>>>>
>>
>>>>> 	ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req);
>>
>>>>
>>
>>>>> 	if (ret)
>>
>>>>
>>
>>>>> 		return ret;
>>
>>>>
>>
>>>>> @@ -1330,7 +1339,7 @@ static int dwc2_hsotg_ep_queue(struct usb_ep
>>
>>>>> *ep,
>>
>>>>
>>
>>>>> struct usb_request *req,
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	/*
>>
>>>>
>>
>>>>> 	 * Handle DDMA isochronous transfers separately - just add new
>>>>> entry
>>
>>>>
>>
>>>>> -	 * to the half of descriptor chain that is not processed by HW.
>>
>>>>
>>
>>>>> +	 * to the descriptor chain.
>>
>>>>
>>
>>>>> 	 * Transfer will be started once SW gets either one of NAK or
>>
>>>>
>>
>>>>> 	 * OutTknEpDis interrupts.
>>
>>>>
>>
>>>>> 	 */
>>
>>>>
>>
>>>>> @@ -1338,9 +1347,9 @@ static int dwc2_hsotg_ep_queue(struct usb_ep
>>
>>>>> *ep,
>>
>>>>
>>
>>>>> struct usb_request *req,
>>
>>>>
>>
>>>>> 	    hs_ep->target_frame != TARGET_FRAME_INITIAL) {
>>
>>>>
>>
>>>>> 		ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma,
>>
>>>>
>>
>>>>> 						 hs_req->req.length);
>>
>>>>
>>
>>>>> -		if (ret)
>>
>>>>
>>
>>>>> -			dev_dbg(hs->dev, "%s: ISO desc chain full\n", __func__);
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> +		if (ret < 0)
>>
>>>>
>>
>>>>> +			dev_dbg(hs->dev, "%s: failed to fill isoc desc\n",
>>
>>>>
>>
>>>>> +				__func__);
>>
>>>>
>>
>>>>
>>
>>>>
>>
>>>> dwc2_gadget_fill_isoc_desc will never return a negative value, and
>>>> at
>>
>>>> the same
>>
>>>>
>>
>>>> time I think there is no need to check the return value, we can work
>>
>>>> properly even
>>
>>>>
>>
>>>> the desc chain is full.
>>
>>>>
>>
>>> You are rigth. ret is 0 or 1. So, no need to change existing code.
>>> Yes, we can
>>
>>> continue work properly even if the desc chain full. It just debug
>>> message if (ret !=
>>
>>> 0). Do you have objection?
>>
>>>
>>
>>
>>
>> Since we already have debug message inside dwc2_gadget_fill_isoc_desc,
>> so here
>>
>> we don't need additional debug message, what do you think of it?
>>
>>
>Agree with you, will remove.
>>
>>
>>
>>>
>>
>>>>
>>
>>>>
>>
>>>>> 		return 0;
>>
>>>>
>>
>>>>> 	}
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> @@ -2011,10 +2020,9 @@ static void
>>
>>> dwc2_hsotg_complete_request(struct
>>
>>>>
>>
>>>>> dwc2_hsotg *hsotg,
>>
>>>>
>>
>>>>>    * @hs_ep: The endpoint the request was on.
>>
>>>>
>>
>>>>>    *
>>
>>>>
>>
>>>>>    * Get first request from the ep queue, determine descriptor on
>>
>>>>> which
>>
>>>>
>>
>>>>> complete
>>
>>>>
>>
>>>>> - * happened. SW based on isoc_chain_num discovers which half of
>>>>> the
>>
>>>>
>>
>>>>> descriptor
>>
>>>>
>>
>>>>> - * chain is currently in use by HW, adjusts dma_address and
>>
>>>>> calculates index
>>
>>>>
>>
>>>>> - * of completed descriptor based on the value of DEPDMA register.
>>
>>>>> Update
>>
>>>>
>>
>>>>> actual
>>
>>>>
>>
>>>>> - * length of request, giveback to gadget.
>>
>>>>
>>
>>>>> + * happened. SW discovers which descriptor currently in use by HW,
>>
>>>>
>>
>>>>> + adjusts
>>
>>>>
>>
>>>>> + * dma_address and calculates index of completed descriptor based
>>>>> + on
>>
>>>>
>>
>>>>> + the value
>>
>>>>
>>
>>>>> + * of DEPDMA register. Update actual length of request, giveback to
>gadget.
>>
>>>>
>>
>>>>>    */
>>
>>>>
>>
>>>>> static void dwc2_gadget_complete_isoc_request_ddma(struct
>>
>>>>> dwc2_hsotg_ep
>>
>>>>
>>
>>>>> *hs_ep)  { @@ -2037,82 +2045,55 @@ static void
>>
>>>>
>>
>>>>> dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep
>*hs_ep)
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	dma_addr = hs_ep->desc_list_dma;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> -	/*
>>
>>>>
>>
>>>>> -	 * If lower half of  descriptor chain is currently use by SW,
>>
>>>>
>>
>>>>> -	 * that means higher half is being processed by HW, so shift
>>
>>>>
>>
>>>>> -	 * DMA address to higher half of descriptor chain.
>>
>>>>
>>
>>>>> -	 */
>>
>>>>
>>
>>>>> -	if (!hs_ep->isoc_chain_num)
>>
>>>>
>>
>>>>> -		dma_addr += sizeof(struct dwc2_dma_desc) *
>>
>>>>
>>
>>>>> -			    (MAX_DMA_DESC_NUM_GENERIC / 2);
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> 	dma_reg = hs_ep->dir_in ? DIEPDMA(hs_ep->index) :
>>
>>>>
>>
>>>>> DOEPDMA(hs_ep->index);
>>
>>>>
>>
>>>>> 	depdma = dwc2_readl(hsotg->regs + dma_reg);
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	index = (depdma - dma_addr) / sizeof(struct dwc2_dma_desc) - 1;
>>
>>>>
>>
>>>>> -	desc_sts = hs_ep->desc_list[index].status;
>>
>>>>
>>
>>>>> +	/* Check descriptor chain rollover */
>>
>>>>
>>
>>>>> +	if (index < 0)
>>
>>>>
>>
>>>>> +		index = MAX_DMA_DESC_NUM_GENERIC - 1;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>
>>
>>>>
>>
>>>> I don't understand here, why setting the index to
>>
>>>>
>>
>>>>    MAX_DMA_DESC_NUM_GENERIC - 1 when the chain is rollover?
>>
>>>>
>>
>>>> If the chain is rollover, the index should point to the latest
>>
>>>> finished desc,
>>
>>>>
>>
>>>> and all the finished descs should be processed. And even the chain
>>>> is
>>
>>>> rollover,
>>
>>>>
>>
>>>> the count of descs in chain is maybe less then
>>
>>> MAX_DMA_DESC_NUM_GENERIC.
>>
>>>>
>>
>>> If depdma point to first desc in list, that mean the last processed
>>> desc was last
>>
>>> in the chain. In this case index will be negative.
>>
>>> In case of desc count less than MAX_DMA_DESC_NUM_GENERIC then
>>> rollover
>>
>>> can be happen  because of L-bit set. In this case by processing first
>>> desc will be
>>
>>> asserted BNA interrupt but not XferComplete interrupt.
>>
>>>
>>
>>
>>
>> Can we reach here in BNA interrupt, or can we have both BNA and
>> XferComplete
>>
>> Interrupts asserted at the same time?
>>
>> Your conclusion is based on the following assumption:
>>
>> 1.  BNA interrupt handle flow can't go into here.
>>
>> 2.  when the execution flow going to here, only because of XferComplete
>interrupt.
>>
>> 3.  when the XferComplete is asserted, BNA interrupt can't be asserted.
>>
>>
>In case of both interrupt asserted then XferComplete ignored. See
>dwc2_hsotg_epint() function. Actually, in my test cases with bInterval=1 it
>happen on last descriptor and no any new requests from function driver,
>because EP disabled with some latency in core BNA also asserted.
>But its corner case and can be ignored.
>

Then what about adding some assert here to catch the core case? 

>>
>>>>
>>
>>>>
>>
>>>>> -	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 length for ISOC Out if length is not align of 4 */
>>
>>>>
>>
>>>>> -	if (!hs_ep->dir_in && ureq->length & 0x3)
>>
>>>>
>>
>>>>> -		ureq->actual += 4 - (ureq->length & 0x3);
>>
>>>>
>>
>>>>> +	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);
>>
>>>>
>>
>>>>> +		dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
>>
>>>>
>>
>>>>> +	} else {
>>
>>>>
>>
>>>>> +		dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req,
>-ETIMEDOUT);
>>
>>>>
>>
>>>>> +	}
>>
>>>>
>>
>>>>> }
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> /*
>>
>>>>
>>
>>>>> - * dwc2_gadget_start_next_isoc_ddma - start next isoc request, if any.
>>
>>>>
>>
>>>>> - * @hs_ep: The isochronous endpoint to be re-enabled.
>>
>>>>
>>
>>>>> + * dwc2_gadget_handle_isoc_bna - handle BNA interrupt for ISOC.
>>
>>>>
>>
>>>>> + * @hs_ep: The isochronous endpoint.
>>
>>>>
>>
>>>>>    *
>>
>>>>
>>
>>>>> - * If ep has been disabled due to last descriptor servicing (IN endpoint) or
>>
>>>>
>>
>>>>> - * BNA (OUT endpoint) check the status of other half of descriptor chain
>that
>>
>>>>
>>
>>>>> - * was under SW control till HW was busy and restart the endpoint if
>needed.
>>
>>>>
>>
>>>>> + * Complete request with -EIO.
>>
>>>>
>>
>>>>> + * If EP ISOC OUT then need to flush RX FIFO to remove source of BNA
>>
>>>>
>>
>>>>> + * interrupt. Reset target frame and next_desc to allow to start
>>
>>>>
>>
>>>>> + * ISOC's on NAK interrupt for IN direction or on OUTTKNEPDIS
>>
>>>>
>>
>>>>> + * interrupt for OUT direction.
>>
>>>>
>>
>>>>>    */
>>
>>>>
>>
>>>>> -static void dwc2_gadget_start_next_isoc_ddma(struct dwc2_hsotg_ep
>>
>>>>
>>
>>>>> *hs_ep)
>>
>>>>
>>
>>>>> +static void dwc2_gadget_handle_isoc_bna(struct dwc2_hsotg_ep
>*hs_ep)
>>
>>>>
>>
>>>>> {
>>
>>>>
>>
>>>>> 	struct dwc2_hsotg *hsotg = hs_ep->parent;
>>
>>>>
>>
>>>>> -	u32 depctl;
>>
>>>>
>>
>>>>> -	u32 dma_reg;
>>
>>>>
>>
>>>>> -	u32 ctrl;
>>
>>>>
>>
>>>>> -	u32 dma_addr = hs_ep->desc_list_dma;
>>
>>>>
>>
>>>>> -	unsigned char index = hs_ep->index;
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> -	dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index);
>>
>>>>
>>
>>>>> -	depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index);
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> -	ctrl = dwc2_readl(hsotg->regs + depctl);
>>
>>>>
>>
>>>>> +	if (!hs_ep->dir_in)
>>
>>>>
>>
>>>>> +		dwc2_flush_rx_fifo(hsotg);
>>
>>>>
>>
>>>>> +	dwc2_hsotg_complete_request(hsotg, hs_ep, get_ep_head(hs_ep),
>>
>>>>
>>
>>>>> +				    -EIO);
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> -	/*
>>
>>>>
>>
>>>>> -	 * EP was disabled if HW has processed last descriptor or BNA was
>set.
>>
>>>>
>>
>>>>> -	 * So restart ep if SW has prepared new descriptor chain in ep_queue
>>
>>>>
>>
>>>>> -	 * routine while HW was busy.
>>
>>>>
>>
>>>>> -	 */
>>
>>>>
>>
>>>>> -	if (!(ctrl & DXEPCTL_EPENA)) {
>>
>>>>
>>
>>>>> -		if (!hs_ep->next_desc) {
>>
>>>>
>>
>>>>> -			dev_dbg(hsotg->dev, "%s: No more ISOC requests\n",
>>
>>>>
>>
>>>>> -				__func__);
>>
>>>>
>>
>>>>> -			return;
>>
>>>>
>>
>>>>> -		}
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> -		dma_addr += sizeof(struct dwc2_dma_desc) *
>>
>>>>
>>
>>>>> -			    (MAX_DMA_DESC_NUM_GENERIC / 2) *
>>
>>>>
>>
>>>>> -			    hs_ep->isoc_chain_num;
>>
>>>>
>>
>>>>> -		dwc2_writel(dma_addr, hsotg->regs + dma_reg);
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> -		ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK;
>>
>>>>
>>
>>>>> -		dwc2_writel(ctrl, hsotg->regs + depctl);
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> -		/* Switch ISOC descriptor chain number being processed by SW*/
>>
>>>>
>>
>>>>> -		hs_ep->isoc_chain_num = (hs_ep->isoc_chain_num ^ 1) & 0x1;
>>
>>>>
>>
>>>>> -		hs_ep->next_desc = 0;
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> -		dev_dbg(hsotg->dev, "%s: Restarted isochronous endpoint\n",
>>
>>>>
>>
>>>>> -			__func__);
>>
>>>>
>>
>>>>> -	}
>>
>>>>
>>
>>>>> +	hs_ep->target_frame = TARGET_FRAME_INITIAL;
>>
>>>>
>>
>>>>> +	hs_ep->next_desc = 0;
>>
>>>>
>>
>>>>> }
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> /**
>>
>>>>
>>
>>>>> @@ -2816,18 +2797,25 @@ static void dwc2_gadget_handle_nak(struct
>>
>>>>
>>
>>>>> dwc2_hsotg_ep *hs_ep)  {
>>
>>>>
>>
>>>>> 	struct dwc2_hsotg *hsotg = hs_ep->parent;
>>
>>>>
>>
>>>>> 	int dir_in = hs_ep->dir_in;
>>
>>>>
>>
>>>>> +	u32 tmp;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	if (!dir_in || !hs_ep->isochronous)
>>
>>>>
>>
>>>>> 		return;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	if (hs_ep->target_frame == TARGET_FRAME_INITIAL) {
>>
>>>>
>>
>>>>> -		hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg);
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> +		tmp = dwc2_hsotg_read_frameno(hsotg);
>>
>>>>
>>
>>>>
>>
>>>>
>>
>>>> I think there is no need to introduce tmp, and the original is all right.
>>
>>>>
>>
>>> No, tmp required. Reading current frame number should be done as soon as
>>
>>> possible. This is why it's stored in tmp and then used for below cases:
>>
>>> 1. DDMA mode. On dwc2_hsotg_complete_request() function driver
>>
>>> immediatly queued new request and as result target_frame incremented by
>>
>>> interval.
>>
>>> 2. BDMA mode. tmp required if interval > 1.
>>
>>>>
>>
>>
>>
>> So for both DDMA or BDMA mode, hs_ep->target_frame should be updated
>the
>>
>> Current frame number in HW.
>>
>> The original code can cover both branch, right?
>>
>>
>Original code doesn't increment here target frame number (performing in
>fill_isoc) to start transfers from next interval and doesn't complete
>request.
>

Maybe you have misunderstood me, I mean there is no need to add the tmp variable.
Directly update the hs_ep->target_frame using 
"hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); " instead of 
"hs_ep->target_frame = tmp" 
In both branches.

>>
>>>>
>>
>>>>> 		if (using_desc_dma(hsotg)) {
>>
>>>>
>>
>>>>> +			dwc2_hsotg_complete_request(hsotg, hs_ep,
>>
>>>>
>>
>>>>> +						    get_ep_head(hs_ep),
>>
>>>>
>>
>>>>> +						    -ENODATA);
>>
>>>>
>>
>>>>> +			hs_ep->target_frame = tmp;
>>
>>>>
>>
>>>>> +			dwc2_gadget_incr_frame_num(hs_ep);
>>
>>>>
>>
>>>>> 			dwc2_gadget_start_isoc_ddma(hs_ep);
>>
>>>>
>>
>>>>> 			return;
>>
>>>>
>>
>>>>> 		}
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> +		hs_ep->target_frame = tmp;
>>
>>>>
>>
>>>>> 		if (hs_ep->interval > 1) {
>>
>>>>
>>
>>>>> 			u32 ctrl = dwc2_readl(hsotg->regs +
>>
>>>>
>>
>>>>> 					      DIEPCTL(hs_ep->index));
>>
>>>>
>>
>>>>> @@ -2843,7 +2831,8 @@ static void dwc2_gadget_handle_nak(struct
>>
>>>>
>>
>>>>> dwc2_hsotg_ep *hs_ep)
>>
>>>>
>>
>>>>> 					    get_ep_head(hs_ep), 0);
>>
>>>>
>>
>>>>> 	}
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> -	dwc2_gadget_incr_frame_num(hs_ep);
>>
>>>>
>>
>>>>> +	if (!using_desc_dma(hsotg))
>>
>>>>
>>
>>>>> +		dwc2_gadget_incr_frame_num(hs_ep);
>>
>>>>
>>
>>>>> }
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> /**
>>
>>>>
>>
>>>>> @@ -2901,9 +2890,9 @@ static void dwc2_hsotg_epint(struct
>dwc2_hsotg
>>
>>>>
>>
>>>>> *hsotg, unsigned int idx,
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 		/* In DDMA handle isochronous requests separately */
>>
>>>>
>>
>>>>> 		if (using_desc_dma(hsotg) && hs_ep->isochronous) {
>>
>>>>
>>
>>>>> -			dwc2_gadget_complete_isoc_request_ddma(hs_ep);
>>
>>>>
>>
>>>>> -			/* Try to start next isoc request */
>>
>>>>
>>
>>>>> -			dwc2_gadget_start_next_isoc_ddma(hs_ep);
>>
>>>>
>>
>>>>> +			/* XferCompl set along with BNA */
>>
>>>>
>>
>>>>> +			if (!(ints & DXEPINT_BNAINTR))
>>
>>>>
>>
>>>>> +				dwc2_gadget_complete_isoc_request_ddma(hs_ep);
>>
>>>>
>>
>>>>> 		} else if (dir_in) {
>>
>>>>
>>
>>>>> 			/*
>>
>>>>
>>
>>>>> 			 * We get OutDone from the FIFO, so we only @@ -2978,15
>>
>>>>
>>
>>>>> +2967,8 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg,
>>
>>> unsigned
>>
>>>>
>>
>>>>> int idx,
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	if (ints & DXEPINT_BNAINTR) {
>>
>>>>
>>
>>>>> 		dev_dbg(hsotg->dev, "%s: BNA interrupt\n", __func__);
>>
>>>>
>>
>>>>> -
>>
>>>>
>>
>>>>> -		/*
>>
>>>>
>>
>>>>> -		 * Try to start next isoc request, if any.
>>
>>>>
>>
>>>>> -		 * Sometimes the endpoint remains enabled after BNA interrupt
>>
>>>>
>>
>>>>> -		 * assertion, which is not expected, hence we can enter here
>>
>>>>
>>
>>>>> -		 * couple of times.
>>
>>>>
>>
>>>>> -		 */
>>
>>>>
>>
>>>>> 		if (hs_ep->isochronous)
>>
>>>>
>>
>>>>> -			dwc2_gadget_start_next_isoc_ddma(hs_ep);
>>
>>>>
>>
>>>>> +			dwc2_gadget_handle_isoc_bna(hs_ep);
>>
>>>>
>>
>>>>> 	}
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	if (dir_in && !hs_ep->isochronous) {
>>
>>>>
>>
>>>>> @@ -3791,6 +3773,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep
>>
>>> *ep,
>>
>>>>
>>
>>>>> 	unsigned int dir_in;
>>
>>>>
>>
>>>>> 	unsigned int i, val, size;
>>
>>>>
>>
>>>>> 	int ret = 0;
>>
>>>>
>>
>>>>> +	unsigned char ep_type;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> 	dev_dbg(hsotg->dev,
>>
>>>>
>>
>>>>> 		"%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n",
>@@
>>
>>>>
>>
>>>>> -3809,6 +3792,15 @@ static int dwc2_hsotg_ep_enable(struct usb_ep
>*ep,
>>
>>>>
>>
>>>>> 		return -EINVAL;
>>
>>>>
>>
>>>>> 	}
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> +	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;
>>
>>>>
>>
>>>>> +	}
>>
>>>>
>>
>>>>> +
>>
>>>>
>>
>>>>> 	mps = usb_endpoint_maxp(desc);
>>
>>>>
>>
>>>>> 	mc = usb_endpoint_maxp_mult(desc);
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> @@ -3852,14 +3844,13 @@ static int dwc2_hsotg_ep_enable(struct
>usb_ep
>>
>>>>
>>
>>>>> *ep,
>>
>>>>
>>
>>>>> 	hs_ep->halted = 0;
>>
>>>>
>>
>>>>> 	hs_ep->interval = desc->bInterval;
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> -	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
>>
>>>>
>>
>>>>> +	switch (ep_type) {
>>
>>>>
>>
>>>>> 	case USB_ENDPOINT_XFER_ISOC:
>>
>>>>
>>
>>>>> 		epctrl |= DXEPCTL_EPTYPE_ISO;
>>
>>>>
>>
>>>>> 		epctrl |= DXEPCTL_SETEVENFR;
>>
>>>>
>>
>>>>> 		hs_ep->isochronous = 1;
>>
>>>>
>>
>>>>> 		hs_ep->interval = 1 << (desc->bInterval - 1);
>>
>>>>
>>
>>>>> 		hs_ep->target_frame = TARGET_FRAME_INITIAL;
>>
>>>>
>>
>>>>> -		hs_ep->isoc_chain_num = 0;
>>
>>>>
>>
>>>>> 		hs_ep->next_desc = 0;
>>
>>>>
>>
>>>>> 		if (dir_in) {
>>
>>>>
>>
>>>>> 			hs_ep->periodic = 1;
>>
>>>>
>>
>>>>> --
>>
>>>>
>>
>>>>> 2.11.0
>>
>>>>
>>
>>>>>
>>
>>>>
>>
>>>>> --
>>
>>>>
>>
>>>>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in the
>body
>>
>>> of
>>
>>>>
>>
>>>>> a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at
>>
>>>>
>>
>>>>>
>>
>>>
>https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordo
>>
>>>
>mo-2Dinfo.html&d=DwIGaQ&c=DPL6_X_6JkXFx7AXWqB0tg&r=6z9Al9FrHR_Zqb
>>
>>>
>btSAsD16pvOL2S3XHxQnSzq8kusyI&m=aPXXRmF_CWLjH-UpIejOss2qsaYVAMO-
>>
>>> oeSoNd1iTmg&s=RtquFAV3zcz956KK1FiPPWA43kJl9InZKrc3jWQR59s&e=
>>
>>>>
>>
>>>>
>>
>>>
>>
>>> Thank you for review.
>>
>>>
>>
>>> Minas
>>
>>> --
>>
>>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>>
>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>
>>> More majordomo info at
>https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordo
>mo-2Dinfo.html&d=DwIGaQ&c=DPL6_X_6JkXFx7AXWqB0tg&r=6z9Al9FrHR_Zqb
>btSAsD16pvOL2S3XHxQnSzq8kusyI&m=WfGU1k4UBRap5Y7jA2LB6Q9JV5b8FXNr
>mgg3ZvnV7V4&s=ZtDDEAhbXXQqBblOSfwtEDMXZqRRC3_6wLgCJREr2EQ&e=
>>
>>
>Thanks,
>Minas

��.n��������+%������w��{.n�����{���)��jg��������ݢj����G�������j:+v���w�m������w�������h�����٥





[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux