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: Thursday, March 22, 2018 4:06 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 2:45 PM, Zengtao (B) wrote:
>> 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.
>>
>Such corner case considered in driver by handling BNA and restarting transfers
>based on remaining requests in queue, if any.
>
BNA interrupt will report an -EIO error to the function in your 3rd patch, so I think
this is not an IO error and what about returning -ERESTART(you have mentioned in
 another mail).

And the restart transfer the remaining requests in queue in the NAK interrupt, right?

>If it happen then there is no index gap, because function driver not able to queue
>new requests on time. If no any requests in queue then
>*list* of descriptors can't be created at all.
>Time gap between 2 new subsequent requests should be similar to interval. If
>function driver can't do it then using descriptor DMA mode not be reasonable,
>buffer DMA mode should be used instead.
>
>>>> 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?
>
>If both interrupt will be asserted simultanously then we can't be here because
>XferComplete will be ignored and this function will not called.
>
>>
>>>>
>>>>>>
>>>>
>>>>>>
>>>>
>>>>>>> -	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.
>>
>
>No, if target frame number will be stored by "hs_ep->target_frame =
>dwc2_hsotg_read_frameno(hsotg);" then after calling
>dwc2_hsotg_complete_request(), function driver can enqueue new request
>which increments target_frame by one more additional interval. This is why
>"hs_ep->target_frame = tmp" performing after calling complete request.
>

Then I got it ,thank you, It 's a bit difficult to understand. But the function driver
maybe queue more than one request in the complete callback, and target_frame
will increase more the one interval? 


>>>>
>>>>>>
>>>>
>>>>>>> 		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