All of lore.kernel.org
 help / color / mirror / Atom feed
* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-21  8:08 Minas Harutyunyan
  0 siblings, 0 replies; 10+ messages in thread
From: Minas Harutyunyan @ 2018-03-21  8:08 UTC (permalink / raw)
  To: Zengtao (B),
	Minas Harutyunyan, John Youn, Felipe Balbi, Greg Kroah-Hartman,
	linux-usb

Hi Zengtao,

On 3/21/2018 6:17 AM, Zengtao (B) wrote:
>> -----Original Message-----
> 
>> From: linux-usb-owner@vger.kernel.org
> 
>> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas Harutyunyan
> 
>> Sent: Tuesday, March 20, 2018 10:40 PM
> 
>> To: Zengtao (B) <prime.zeng@hisilicon.com>; Minas Harutyunyan
> 
>> <Minas.Harutyunyan@synopsys.com>; John Youn <John.Youn@synopsys.com>;
> 
>> Felipe Balbi <balbi@kernel.org>; Greg Kroah-Hartman
> 
>> <gregkh@linuxfoundation.org>; linux-usb@vger.kernel.org
> 
>> 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@vger.kernel.org
> 
>>>
> 
>>>> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas
> 
>>>> Harutyunyan
> 
>>>
> 
>>>> Sent: Saturday, March 17, 2018 5:10 PM
> 
>>>
> 
>>>> To: John Youn <John.Youn@synopsys.com>; Felipe Balbi
> 
>>>> <balbi@kernel.org>;
> 
>>>
> 
>>>> Greg Kroah-Hartman <gregkh@linuxfoundation.org>;
> 
>>>> linux-usb@vger.kernel.org
> 
>>>
> 
>>>> Cc: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
> 
>>>
> 
>>>> 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@synopsys.com>
> 
>>>
> 
>>>> ---
> 
>>>
> 
>>>> 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.
> 
> 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.
> 
> 
>>>
> 
>>>>
> 
>>>> +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.

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

> 
>>>
> 
>>>> 		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@vger.kernel.org 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@vger.kernel.org
> 
>> More majordomo info at  https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIGaQ&c=DPL6_X_6JkXFx7AXWqB0tg&r=6z9Al9FrHR_ZqbbtSAsD16pvOL2S3XHxQnSzq8kusyI&m=WfGU1k4UBRap5Y7jA2LB6Q9JV5b8FXNrmgg3ZvnV7V4&s=ZtDDEAhbXXQqBblOSfwtEDMXZqRRC3_6wLgCJREr2EQ&e=
> 
> 
Thanks,
Minas
---
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-22 11:16 Minas Harutyunyan
  0 siblings, 0 replies; 10+ messages in thread
From: Minas Harutyunyan @ 2018-03-22 11:16 UTC (permalink / raw)
  To: Zengtao (B),
	Minas Harutyunyan, John Youn, Felipe Balbi, Greg Kroah-Hartman,
	linux-usb

Hi Zengtao,

On 3/22/2018 1:36 PM, Zengtao (B) wrote:
> Hi Minas:
> 
>> -----Original Message-----
>> From: Minas Harutyunyan [mailto:Minas.Harutyunyan@synopsys.com]
>> Sent: Thursday, March 22, 2018 4:06 PM
>> To: Zengtao (B) <prime.zeng@hisilicon.com>; Minas Harutyunyan
>> <Minas.Harutyunyan@synopsys.com>; John Youn <John.Youn@synopsys.com>;
>> Felipe Balbi <balbi@kernel.org>; Greg Kroah-Hartman
>> <gregkh@linuxfoundation.org>; linux-usb@vger.kernel.org
>> 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@synopsys.com]
>>>> Sent: Wednesday, March 21, 2018 4:08 PM
>>>> To: Zengtao (B) <prime.zeng@hisilicon.com>; Minas Harutyunyan
>>>> <Minas.Harutyunyan@synopsys.com>; John Youn
>> <John.Youn@synopsys.com>;
>>>> Felipe Balbi <balbi@kernel.org>; Greg Kroah-Hartman
>>>> <gregkh@linuxfoundation.org>; linux-usb@vger.kernel.org
>>>> 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@vger.kernel.org
>>>>>
>>>>>> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas
>>>>>> Harutyunyan
>>>>>
>>>>>> Sent: Tuesday, March 20, 2018 10:40 PM
>>>>>
>>>>>> To: Zengtao (B) <prime.zeng@hisilicon.com>; Minas Harutyunyan
>>>>>
>>>>>> <Minas.Harutyunyan@synopsys.com>; John Youn
>>>> <John.Youn@synopsys.com>;
>>>>>
>>>>>> Felipe Balbi <balbi@kernel.org>; Greg Kroah-Hartman
>>>>>
>>>>>> <gregkh@linuxfoundation.org>; linux-usb@vger.kernel.org
>>>>>
>>>>>> 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@vger.kernel.org
>>>>>
>>>>>>>
>>>>>
>>>>>>>> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas
>>>>>
>>>>>>>> Harutyunyan
>>>>>
>>>>>>>
>>>>>
>>>>>>>> Sent: Saturday, March 17, 2018 5:10 PM
>>>>>
>>>>>>>
>>>>>
>>>>>>>> To: John Youn <John.Youn@synopsys.com>; Felipe Balbi
>>>>>
>>>>>>>> <balbi@kernel.org>;
>>>>>
>>>>>>>
>>>>>
>>>>>>>> Greg Kroah-Hartman <gregkh@linuxfoundation.org>;
>>>>>
>>>>>>>> linux-usb@vger.kernel.org
>>>>>
>>>>>>>
>>>>>
>>>>>>>> Cc: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
>>>>>
>>>>>>>
>>>>>
>>>>>>>> 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@synopsys.com>
>>>>>
>>>>>>>
>>>>>
>>>>>>>> ---
>>>>>
>>>>>>>
>>>>>
>>>>>>>> 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?
> 
Not agree with you. On BNA restart is performing internally in dwc2 and 
function driver should be not aware about it. If dwc2 will return 
-ERESTART it can mean that function driver should restart its internal flow.
Based on Filipe feedback, I think, 0 status code with correct actual 
size (in this case =0) will be best solution. See my feedback in another 
email thread about status codes. Will send shortly.


>> 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?
> 
Please review dwc2_hsotg_ep_queue() function. Only in case if 
"hs_ep->target_frame != TARGET_FRAME_INITIAL" fill_isoc will called and 
target_frame will be incremented inside fill_isoc. This is why dwc2 keep 
target_frame equal to TARGET_FRAME_INITIAL before calling request 
completion function and then change to actual frame number.

Just, FYI. Initially implementation was done as you suggested, but after 
testing we saw that IN packet go to USB bus instead of (N+1) frame in 
(N+2), where N is frame number when NAK asserted.
> 
>>>>>
>>>>>>>
>>>>>
>>>>>>>> 		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@vger.kernel.org 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@vger.kernel.org
>>>>>
>>>>>> 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
>>
> 
>
---
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-22  9:36 Zengtao (B)
  0 siblings, 0 replies; 10+ messages in thread
From: Zengtao (B) @ 2018-03-22  9:36 UTC (permalink / raw)
  To: Minas Harutyunyan, John Youn, Felipe Balbi, Greg Kroah-Hartman,
	linux-usb

SGkgTWluYXM6IA0KDQo+LS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj5Gcm9tOiBNaW5hcyBI
YXJ1dHl1bnlhbiBbbWFpbHRvOk1pbmFzLkhhcnV0eXVueWFuQHN5bm9wc3lzLmNvbV0NCj5TZW50
OiBUaHVyc2RheSwgTWFyY2ggMjIsIDIwMTggNDowNiBQTQ0KPlRvOiBaZW5ndGFvIChCKSA8cHJp
bWUuemVuZ0BoaXNpbGljb24uY29tPjsgTWluYXMgSGFydXR5dW55YW4NCj48TWluYXMuSGFydXR5
dW55YW5Ac3lub3BzeXMuY29tPjsgSm9obiBZb3VuIDxKb2huLllvdW5Ac3lub3BzeXMuY29tPjsN
Cj5GZWxpcGUgQmFsYmkgPGJhbGJpQGtlcm5lbC5vcmc+OyBHcmVnIEtyb2FoLUhhcnRtYW4NCj48
Z3JlZ2toQGxpbnV4Zm91bmRhdGlvbi5vcmc+OyBsaW51eC11c2JAdmdlci5rZXJuZWwub3JnDQo+
U3ViamVjdDogUmU6IFtQQVRDSCB2MSAyLzNdIHVzYjogZHdjMjogQ2hhbmdlIElTT0MgRERNQSBm
bG93DQo+DQo+SGkgWmVuZ3RhbywNCj4NCj5PbiAzLzIxLzIwMTggMjo0NSBQTSwgWmVuZ3RhbyAo
Qikgd3JvdGU6DQo+PiBIaSBNaW5hczoNCj4+DQo+Pj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0t
LS0NCj4+PiBGcm9tOiBNaW5hcyBIYXJ1dHl1bnlhbiBbbWFpbHRvOk1pbmFzLkhhcnV0eXVueWFu
QHN5bm9wc3lzLmNvbV0NCj4+PiBTZW50OiBXZWRuZXNkYXksIE1hcmNoIDIxLCAyMDE4IDQ6MDgg
UE0NCj4+PiBUbzogWmVuZ3RhbyAoQikgPHByaW1lLnplbmdAaGlzaWxpY29uLmNvbT47IE1pbmFz
IEhhcnV0eXVueWFuDQo+Pj4gPE1pbmFzLkhhcnV0eXVueWFuQHN5bm9wc3lzLmNvbT47IEpvaG4g
WW91bg0KPjxKb2huLllvdW5Ac3lub3BzeXMuY29tPjsNCj4+PiBGZWxpcGUgQmFsYmkgPGJhbGJp
QGtlcm5lbC5vcmc+OyBHcmVnIEtyb2FoLUhhcnRtYW4NCj4+PiA8Z3JlZ2toQGxpbnV4Zm91bmRh
dGlvbi5vcmc+OyBsaW51eC11c2JAdmdlci5rZXJuZWwub3JnDQo+Pj4gU3ViamVjdDogUmU6IFtQ
QVRDSCB2MSAyLzNdIHVzYjogZHdjMjogQ2hhbmdlIElTT0MgRERNQSBmbG93DQo+Pj4NCj4+PiBI
aSBaZW5ndGFvLA0KPj4+DQo+Pj4gT24gMy8yMS8yMDE4IDY6MTcgQU0sIFplbmd0YW8gKEIpIHdy
b3RlOg0KPj4+Pj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4+Pj4NCj4+Pj4+IEZyb206
IGxpbnV4LXVzYi1vd25lckB2Z2VyLmtlcm5lbC5vcmcNCj4+Pj4NCj4+Pj4+IFttYWlsdG86bGlu
dXgtdXNiLW93bmVyQHZnZXIua2VybmVsLm9yZ10gT24gQmVoYWxmIE9mIE1pbmFzDQo+Pj4+PiBI
YXJ1dHl1bnlhbg0KPj4+Pg0KPj4+Pj4gU2VudDogVHVlc2RheSwgTWFyY2ggMjAsIDIwMTggMTA6
NDAgUE0NCj4+Pj4NCj4+Pj4+IFRvOiBaZW5ndGFvIChCKSA8cHJpbWUuemVuZ0BoaXNpbGljb24u
Y29tPjsgTWluYXMgSGFydXR5dW55YW4NCj4+Pj4NCj4+Pj4+IDxNaW5hcy5IYXJ1dHl1bnlhbkBz
eW5vcHN5cy5jb20+OyBKb2huIFlvdW4NCj4+PiA8Sm9obi5Zb3VuQHN5bm9wc3lzLmNvbT47DQo+
Pj4+DQo+Pj4+PiBGZWxpcGUgQmFsYmkgPGJhbGJpQGtlcm5lbC5vcmc+OyBHcmVnIEtyb2FoLUhh
cnRtYW4NCj4+Pj4NCj4+Pj4+IDxncmVna2hAbGludXhmb3VuZGF0aW9uLm9yZz47IGxpbnV4LXVz
YkB2Z2VyLmtlcm5lbC5vcmcNCj4+Pj4NCj4+Pj4+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggdjEgMi8z
XSB1c2I6IGR3YzI6IENoYW5nZSBJU09DIERETUEgZmxvdw0KPj4+Pg0KPj4+Pj4NCj4+Pj4NCj4+
Pj4+IEhpIFplbmd0YW8sDQo+Pj4+DQo+Pj4+Pg0KPj4+Pg0KPj4+Pj4gT24gMy8yMC8yMDE4IDY6
MDEgQU0sIFplbmd0YW8gKEIpIHdyb3RlOg0KPj4+Pg0KPj4+Pj4+IEhpIE1pbmFzOg0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+IEEgZmV3IG1p
bm9yIGNvbW1lbnRzOg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0K
Pj4+Pg0KPj4+Pj4+PiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPj4+Pg0KPj4+Pj4+DQo+
Pj4+DQo+Pj4+Pj4+IEZyb206IGxpbnV4LXVzYi1vd25lckB2Z2VyLmtlcm5lbC5vcmcNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBbbWFpbHRvOmxpbnV4LXVzYi1vd25lckB2Z2VyLmtlcm5l
bC5vcmddIE9uIEJlaGFsZiBPZiBNaW5hcw0KPj4+Pg0KPj4+Pj4+PiBIYXJ1dHl1bnlhbg0KPj4+
Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IFNlbnQ6IFNhdHVyZGF5LCBNYXJjaCAxNywgMjAxOCA1
OjEwIFBNDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gVG86IEpvaG4gWW91biA8Sm9obi5Z
b3VuQHN5bm9wc3lzLmNvbT47IEZlbGlwZSBCYWxiaQ0KPj4+Pg0KPj4+Pj4+PiA8YmFsYmlAa2Vy
bmVsLm9yZz47DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gR3JlZyBLcm9haC1IYXJ0bWFu
IDxncmVna2hAbGludXhmb3VuZGF0aW9uLm9yZz47DQo+Pj4+DQo+Pj4+Pj4+IGxpbnV4LXVzYkB2
Z2VyLmtlcm5lbC5vcmcNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBDYzogTWluYXMgSGFy
dXR5dW55YW4gPE1pbmFzLkhhcnV0eXVueWFuQHN5bm9wc3lzLmNvbT4NCj4+Pj4NCj4+Pj4+Pg0K
Pj4+Pg0KPj4+Pj4+PiBTdWJqZWN0OiBbUEFUQ0ggdjEgMi8zXSB1c2I6IGR3YzI6IENoYW5nZSBJ
U09DIERETUEgZmxvdw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gQ2hhbmdlZCBleGlzdGluZyB0d28gZGVzY3JpcHRvci1jaGFpbiBmbG93
IHRvIG9uZSBjaGFpbi4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
DQo+Pj4+DQo+Pj4+Pj4+IEluIHR3by1jaGFpbiBpbXBsZW1lbnRhdGlvbiBCTkEgaW50ZXJydXB0
IHVzZWQgZm9yIHN3aXRjaGluZw0KPj4+Pj4+PiBiZXR3ZWVuDQo+Pj4+DQo+Pj4+Pj4+IHR3bw0K
Pj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IGNoYWlucy4gQk5BIGludGVycnVwdCBhc3NlcnRl
ZCBiZWNhdXNlIG9mIHJldHVybmluZyB0byBiZWdpbm5pbmcNCj4+Pj4+Pj4gb2YNCj4+Pj4NCj4+
Pj4+Pj4gdGhlIGNoYWluDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gYmFzZWQgb24gTC1i
aXQgb2YgbGFzdCBkZXNjcmlwdG9yLg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gQmVjYXVzZSBvZiB0aGF0IHdlIGxvc2UgcGFja2V0cy4g
VGhpcyBpc3N1ZSByZXNvbHZlZCBieSB1c2luZyBvbmUNCj4+PiBkZXNjLWNoYWluLg0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gUmVtb3Zl
ZCBhbGwgc3RhZmYgcmVsYXRlZCB0byB0d28gZGVzYy1jaGFpbiBmbG93IGZyb20gRERNQSBJU09D
DQo+Pj4+DQo+Pj4+Pj4+IHJlbGF0ZWQNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBmdW5j
dGlvbnMuDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+PiBSZW1vdmVkIHJlcXVlc3QgbGVuZ3RoIGNoZWNraW5nIGZyb20gZHdjMl9nYWRnZXRf
ZmlsbF9pc29jX2Rlc2MoKQ0KPj4+Pg0KPj4+Pj4gZnVuY3Rpb24uDQo+Pj4+DQo+Pj4+Pj4NCj4+
Pj4NCj4+Pj4+Pj4gUmVxdWVzdCBsZW5ndGggY2hlY2tpbmcgYWRkZWQgdG8gZHdjMl9oc290Z19l
cF9xdWV1ZSgpIGZ1bmN0aW9uLg0KPj4+Pj4+PiBJZg0KPj4+Pg0KPj4+Pj4+PiByZXF1ZXN0DQo+
Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gbGVuZ3RoIGdyZWF0ZXIgdGhhbiBkZXNjcmlwdG9y
IGxpbWl0cyB0aGVuIHJlcXVlc3Qgbm90IGFkZGVkIHRvIHF1ZXVlLg0KPj4+Pg0KPj4+Pj4+DQo+
Pj4+DQo+Pj4+Pj4+IEFkZGl0aW9uYWwgY2hlY2tpbmcgZG9uZSBmb3IgSGlnaCBCYW5kd2lkdGgg
SVNPQyBPVVQncyB3aGljaCBub3QNCj4+Pj4NCj4+Pj4+Pj4gc3VwcG9ydGVkIGJ5DQo+Pj4+DQo+
Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gZHJpdmVyLiBJbg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+IGR3YzJfZ2FkZ2V0X2ZpbGxfaXNvY19kZXNjKCkgZnVuY3Rpb24gYWxzbyBjaGVja2VkIGRl
c2MtY2hhaW4NCj4+Pj4+Pj4gc3RhdHVzDQo+Pj4+DQo+Pj4+Pj4+IChmdWxsIG9yIG5vdCkNCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiB0byBhdm9pZCBvZiByZXVzaW5nIG5vdCB5ZXQgcHJv
Y2Vzc2VkIGRlc2NyaXB0b3JzLg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gSW4gZHdjMl9nYWRnZXRfc3RhcnRfaXNvY19kZG1hKCkgZnVu
Y3Rpb24gY3JlYXRpb24gb2YgZGVzYy1jaGFpbg0KPj4+Pg0KPj4+Pj4+PiBhbHdheXMNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBzdGFydGVkIGZyb20gZGVzY3JpcHRvciAwLiBCZWZvcmUg
ZmlsbGluZyBkZXNjcmlwdG9ycywgdGhleSB3ZXJlDQo+Pj4+DQo+Pj4+Pj4+IGluaXRpYWxpemVk
IGJ5DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gSE9TVCBCVVNZIHN0YXR1cy4NCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IEluIGR3
YzJfZ2FkZ2V0X2NvbXBsZXRlX2lzb2NfcmVxdWVzdF9kZG1hKCkgYWRkZWQgY2hlY2tpbmcgZm9y
DQo+Pj4+DQo+Pj4+Pj4+IGRlc2MtY2hhaW4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBy
b2xsb3Zlci4gQWxzbyBhZGRlZCBjaGVja2luZyBjb21wbGV0aW9uIHN0YXR1cy4NCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBSZXF1ZXN0IGNvbXBsZXRlZCBzdWNjZXNzZnVsbHkgaWYgREVW
X0RNQV9TVFMgaXMNCj4+Pj4+Pj4gREVWX0RNQV9TVFNfU1VDQywNCj4+Pj4NCj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4+PiBvdGhlcndpc2UgY29tcGxldGUgd2l0aCAtRVRJTUVET1VULg0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gQWN0dWFsbHkg
cmVtb3ZlZCBkd2MyX2dhZGdldF9zdGFydF9uZXh0X2lzb2NfZGRtYSgpIGZ1bmN0aW9uDQo+Pj4+
Pj4+IGJlY2F1c2UNCj4+Pj4NCj4+Pj4+Pj4gbm93DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gZHJpdmVyIHVzZSBvbmx5IG9uZSBkZXNjLWNoYWluIGFuZCBpbnN0ZWFkIHRoYXQgZnVuY3Rp
b24gYWRkZWQNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBkd2MyX2dhZGdldF9oYW5kbGVf
aXNvY19ibmEoKSBmdW5jdGlvbiBmb3IgaGFuZGxpbmcgQk5BIGludGVycnVwdHMuDQo+Pj4+DQo+
Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBIYW5kbGlu
ZyBCTkEgaW50ZXJydXB0IGRvbmUgYnkgZmx1c2hpbmcgVHhGSUZPcyBmb3IgT1VUIEVQcywNCj4+
Pj4NCj4+Pj4+Pj4gY29tcGxldGluZw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IHJlcXVl
c3Qgd2l0aCAtRUlPIGFuZCByZXNldHRpbmcgZGVzYy1jaGFpbiBudW1iZXIgYW5kIHRhcmdldA0K
Pj4+Pj4+PiBmcmFtZSB0bw0KPj4+Pg0KPj4+Pj4+PiBpbml0aWFsDQo+Pj4+DQo+Pj4+Pj4NCj4+
Pj4NCj4+Pj4+Pj4gdmFsdWVzIGZvciByZXN0YXJ0aW5nIHRyYW5zZmVycy4NCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IE9uIGhhbmRsaW5n
IE5BSyByZXF1ZXN0IGNvbXBsZXRlZCB3aXRoIC1FTk9EQVRBLiBJbmNyZW1lbnRlZA0KPj4+Pj4+
PiB0YXJnZXQNCj4+Pj4NCj4+Pj4+Pj4gZnJhbWUNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiB0byBhbGxvdyBmaWxsIGRlc2MgY2hhaW4gYW5kIHN0YXJ0IHRyYW5zZmVycy4NCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBJbiBERE1BIG1vZGUgYXZvaWRlZCBvZiBmcmFtZSBudW1iZXIg
aW5jcmVtZW50aW5nLCBiZWNhdXNlDQo+Pj4+Pj4+IHRyYWNraW5nDQo+Pj4+DQo+Pj4+Pj4+IG9m
DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gZnJhbWUgbnVtYmVyIHBlcmZvcm1lZCBpbiBk
d2MyX2dhZGdldF9maWxsX2lzb2NfZGVzYygpIGZ1bmN0aW9uLg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gV2hlbiBjb3JlIGFzc2VydCBY
ZmVyQ29tcGwgYWxvbmcgd2l0aCBCTkEsIHdlIHNob3VsZCBpZ25vcmUNCj4+Pj4+Pj4gWGZlckNv
bXBsDQo+Pj4+DQo+Pj4+Pj4+IGluDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gZHdjMl9o
c290Z19lcGludCgpIGZ1bmN0aW9uLg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gT24gQk5BIGludGVycnVwdCByZXBsYWNlZCBkd2MyX2dh
ZGdldF9zdGFydF9uZXh0X2lzb2NfZGRtYSgpIGJ5DQo+Pj4+Pj4+IGFib3ZlDQo+Pj4+DQo+Pj4+
Pj4NCj4+Pj4NCj4+Pj4+Pj4gbWVudGlvbmVkIEJOQSBoYW5kbGVyLg0KPj4+Pg0KPj4+Pj4+DQo+
Pj4+DQo+Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gSW4gZHdjMl9oc290Z19l
cF9lbmFibGUoKSBmdW5jdGlvbiBhZGRlZCBzYW5pdHkgY2hlY2sgb2YNCj4+Pj4+Pj4gYkludGVy
dmFsDQo+Pj4+DQo+Pj4+Pj4+IGZvciBJU09DIElODQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gaW4gRERNQSBtb2RlLCBiZWNhdXNlIEhXIG5vdCBzdXBwb3J0ZWQgRVAncyB3aXRoIGJJbnRl
cnZhbCBtb3JlDQo+Pj4+Pj4+IHRoYW4NCj4+PiAxMi4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IFNpZ25lZC1vZmYtYnk6IE1pbmFzIEhh
cnV0eXVueWFuIDxobWluYXNAc3lub3BzeXMuY29tPg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+IC0tLQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IGRyaXZlcnMvdXNiL2R3YzIvY29y
ZS5oICAgfCAgIDIgLQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IGRyaXZlcnMvdXNiL2R3
YzIvZ2FkZ2V0LmMgfCAyMzUNCj4+Pj4NCj4+Pj4+Pj4gKysrKysrKysrKysrKysrKysrKysrKy0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IDIgZmls
ZXMgY2hhbmdlZCwgMTEzIGluc2VydGlvbnMoKyksIDEyNCBkZWxldGlvbnMoLSkNCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IGRpZmYgLS1n
aXQgYS9kcml2ZXJzL3VzYi9kd2MyL2NvcmUuaCBiL2RyaXZlcnMvdXNiL2R3YzIvY29yZS5oDQo+
Pj4+Pj4+IGluZGV4DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gZDgzYmU1NjUxZjg3Li4w
OTNkMDc4YWRhZjQgMTAwNjQ0DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLS0tIGEvZHJp
dmVycy91c2IvZHdjMi9jb3JlLmgNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArKysgYi9k
cml2ZXJzL3VzYi9kd2MyL2NvcmUuaA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IEBAIC0x
NzgsNyArMTc4LDYgQEAgc3RydWN0IGR3YzJfaHNvdGdfcmVxOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+ICAgICAqIEBkZXNjX2xpc3RfZG1hOiBUaGUgRE1BIGFkZHJlc3Mgb2YgZGVzY3Jp
cHRvciBjaGFpbg0KPj4+Pj4+PiBjdXJyZW50bHkgaW4NCj4+PiB1c2UuDQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gICAgICogQGRlc2NfbGlzdDogUG9pbnRlciB0byBkZXNjcmlwdG9yIERN
QSBjaGFpbiBoZWFkIGN1cnJlbnRseSBpbg0KPnVzZS4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiAgICAgKiBAZGVzY19jb3VudDogQ291bnQgb2YgZW50cmllcyB3aXRoaW4gdGhlIERNQSBk
ZXNjcmlwdG9yDQo+Pj4+Pj4+IGNoYWluIG9mDQo+Pj4gRVAuDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4gLSAqIEBpc29jX2NoYWluX251bTogTnVtYmVyIG9mIElTT0MgY2hhaW4gY3VycmVu
dGx5IGluIHVzZSAtIGVpdGhlciAwIG9yDQo+MS4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiAgICAgKiBAbmV4dF9kZXNjOiBpbmRleCBvZiBuZXh0IGZyZWUgZGVzY3JpcHRvciBpbiB0aGUg
SVNPQyBjaGFpbg0KPj4+Pj4+PiB1bmRlcg0KPj4+Pg0KPj4+Pj4+PiBTVw0KPj4+Pg0KPj4+Pj4+
DQo+Pj4+DQo+Pj4+Pj4+IGNvbnRyb2wuDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gICAg
ICogQHRvdGFsX2RhdGE6IFRoZSB0b3RhbCBudW1iZXIgb2YgZGF0YSBieXRlcyBkb25lLg0KPj4+
Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICAgICAqIEBmaWZvX3NpemU6IFRoZSBzaXplIG9mIHRo
ZSBGSUZPIChmb3IgcGVyaW9kaWMgSU4NCj4+Pj4+Pj4gZW5kcG9pbnRzKSBAQA0KPj4+Pg0KPj4+
Pj4+PiAtMjMxLDcNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArMjMwLDYgQEAgc3RydWN0
IGR3YzJfaHNvdGdfZXAgew0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAlzdHJ1Y3QgZHdj
Ml9kbWFfZGVzYwkqZGVzY19saXN0Ow0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAl1OAkJ
CWRlc2NfY291bnQ7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0K
Pj4+Pg0KPj4+Pj4+PiAtCXVuc2lnbmVkIGNoYXIJCWlzb2NfY2hhaW5fbnVtOw0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAl1bnNpZ25lZCBpbnQJCW5leHRfZGVzYzsNCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAljaGFyICAgICAg
ICAgICAgICAgICAgICBuYW1lWzEwXTsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBkaWZm
IC0tZ2l0IGEvZHJpdmVycy91c2IvZHdjMi9nYWRnZXQuYw0KPj4+Pj4+PiBiL2RyaXZlcnMvdXNi
L2R3YzIvZ2FkZ2V0LmMNCj4+Pj4NCj4+Pj4+Pj4gaW5kZXgNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+PiBjMjMxMzIxNjU2ZjkuLjFiOWM4NGNiNThmYiAxMDA2NDQNCj4+Pj4NCj4+Pj4+Pg0K
Pj4+Pg0KPj4+Pj4+PiAtLS0gYS9kcml2ZXJzL3VzYi9kd2MyL2dhZGdldC5jDQo+Pj4+DQo+Pj4+
Pj4NCj4+Pj4NCj4+Pj4+Pj4gKysrIGIvZHJpdmVycy91c2IvZHdjMi9nYWRnZXQuYw0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IEBAIC03OTMsOSArNzkzLDcgQEAgc3RhdGljIHZvaWQNCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBkd2MyX2dhZGdldF9jb25maWdfbm9uaXNvY194ZmVy
X2RkbWEoc3RydWN0IGR3YzJfaHNvdGdfZXANCj4qaHNfZXAsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4gICAgICogQGRtYV9idWZmOiB1c2IgcmVxdWVzdHMgZG1hIGJ1ZmZlci4NCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAgICAgKiBAbGVuOiB1c2IgcmVxdWVzdCB0cmFuc2ZlciBs
ZW5ndGguDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gICAgICoNCj4+Pj4NCj4+Pj4+Pg0K
Pj4+Pg0KPj4+Pj4+PiAtICogRmluZHMgb3V0IGluZGV4IG9mIGZpcnN0IGZyZWUgZW50cnkgZWl0
aGVyIGluIHRoZSBib3R0b20gb3INCj4+Pj4+Pj4gdXANCj4+Pj4NCj4+Pj4+Pj4gaGFsZiBvZg0K
Pj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0gKiBkZXNjcmlwdG9yIGNoYWluIGRlcGVuZCBv
biB3aGljaCBpcyB1bmRlciBTVyBjb250cm9sIGFuZCBub3QNCj4+Pj4NCj4+Pj4+Pj4gcHJvY2Vz
c2VkDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLSAqIGJ5IEhXLiBUaGVuIGZpbGxzIHRo
YXQgZGVzY3JpcHRvciB3aXRoIHRoZSBkYXRhIG9mIHRoZQ0KPj4+Pj4+PiBhcnJpdmVkDQo+Pj4+
DQo+Pj4+Pj4+IHVzYiByZXF1ZXN0LA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsgKiBG
aWxscyBuZXh0IGZyZWUgZGVzY3JpcHRvciB3aXRoIHRoZSBkYXRhIG9mIHRoZSBhcnJpdmVkIHVz
Yg0KPj4+Pg0KPj4+Pj4+PiArIHJlcXVlc3QsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
ICAgICogZnJhbWUgaW5mbywgc2V0cyBMYXN0IGFuZCBJT0MgYml0cyBpbmNyZW1lbnRzIG5leHRf
ZGVzYy4gSWYNCj4+Pj4NCj4+Pj4+Pj4gZmlsbGVkDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gICAgICogZGVzY3JpcHRvciBpcyBub3QgdGhlIGZpcnN0IG9uZSwgcmVtb3ZlcyBMIGJpdCBm
cm9tIHRoZQ0KPj4+Pj4+PiBwcmV2aW91cw0KPj4+Pg0KPj4+Pj4+PiBkZXNjcmlwdG9yDQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gICAgICogc3RhdHVzLg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+IEBAIC04MTAsMzQgKzgwOCwxNyBAQCBzdGF0aWMgaW50DQo+Pj4+Pj4+IGR3YzJf
Z2FkZ2V0X2ZpbGxfaXNvY19kZXNjKHN0cnVjdA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
IGR3YzJfaHNvdGdfZXAgKmhzX2VwLA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAl1MzIg
bWFzayA9IDA7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4+PiAJbWF4c2l6ZSA9IGR3YzJfZ2FkZ2V0X2dldF9kZXNjX3BhcmFtcyhoc19lcCwg
Jm1hc2spOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JaWYgKGxlbiA+IG1heHNpemUp
IHsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQlkZXZfZXJyKGhzb3RnLT5kZXYsICJ3
cm9uZyBsZW4gJWRcbiIsIGxlbik7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkJcmV0
dXJuIC1FSU5WQUw7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQl9DQo+Pj4+DQo+Pj4+
Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JLyoNCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCSAqIElmIFNXIGhhcyBhbHJlYWR5IGZpbGxlZCBo
YWxmIG9mIGNoYWluLCB0aGVuIHJldHVybiBhbmQgd2FpdCBmb3INCj4+Pj4NCj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4+PiAtCSAqIHRoZSBvdGhlciBjaGFpbiB0byBiZSBwcm9jZXNzZWQgYnkgSFcuDQo+
Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkgKi8NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiAtCWlmIChoc19lcC0+bmV4dF9kZXNjID09IE1BWF9ETUFfREVTQ19OVU1fR0VORVJJQyAv
IDIpDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkJcmV0dXJuIC1FQlVTWTsNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JLyog
SW5jcmVtZW50IGZyYW1lIG51bWJlciBieSBpbnRlcnZhbCBmb3IgSU4gKi8NCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAtCWlmIChoc19lcC0+ZGlyX2luKQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+IC0JCWR3YzJfZ2FkZ2V0X2luY3JfZnJhbWVfbnVtKGhzX2VwKTsNCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQlpbmRl
eCA9IChNQVhfRE1BX0RFU0NfTlVNX0dFTkVSSUMgLyAyKSAqDQo+Pj4gaHNfZXAtPmlzb2NfY2hh
aW5fbnVtICsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQkgaHNfZXAtPm5leHRfZGVz
YzsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCWluZGV4ID0gaHNfZXAtPm5leHRfZGVz
YzsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCWRlc2MgPSAmaHNfZXAtPmRlc2NfbGlz
dFtpbmRleF07DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4+PiAtCS8qIFNhbml0eSBjaGVjayBvZiBjYWxjdWxhdGVkIGluZGV4ICovDQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQlpZiAoKGhzX2VwLT5pc29jX2NoYWluX251bSAmJiBp
bmRleCA+DQo+Pj4gTUFYX0RNQV9ERVNDX05VTV9HRU5FUklDKQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+IHx8DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkgICAgKCFoc19lcC0+
aXNvY19jaGFpbl9udW0gJiYgaW5kZXggPg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IE1B
WF9ETUFfREVTQ19OVU1fR0VORVJJQyAvIDIpKSB7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gLQkJZGV2X2Vycihoc290Zy0+ZGV2LCAid3JvbmcgaW5kZXggJWQgZm9yIGlzbyBjaGFpblxu
IiwgaW5kZXgpOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JCXJldHVybiAtRUlOVkFM
Ow0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJLyogQ2hlY2sgaWYgZGVzY3JpcHRvciBj
aGFpbiBmdWxsICovDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwlpZiAoKGRlc2MtPnN0
YXR1cyA+PiBERVZfRE1BX0JVRkZfU1RTX1NISUZUKSA9PQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4+ICsJICAgIERFVl9ETUFfQlVGRl9TVFNfSFJFQURZKSB7DQo+Pj4+DQo+Pj4+Pj4NCj4+
Pj4NCj4+Pj4+Pj4gKwkJZGV2X2RiZyhoc290Zy0+ZGV2LCAiJXM6IGRlc2MgY2hhaW4gZnVsbFxu
IiwgX19mdW5jX18pOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCXJldHVybiAxOw0K
Pj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAl9DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCWRlc2MgPSAmaHNfZXAtPmRlc2NfbGlz
dFtpbmRleF07DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQ0KPj4+Pg0KPj4+Pj4+DQo+
Pj4+DQo+Pj4+Pj4+IAkvKiBDbGVhciBMIGJpdCBvZiBwcmV2aW91cyBkZXNjIGlmIG1vcmUgdGhh
biBvbmUgZW50cmllcyBpbiB0aGUNCj4+Pj4NCj4+Pj4+Pj4gY2hhaW4gKi8NCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAJaWYgKGhzX2VwLT5uZXh0X2Rlc2MpDQo+Pj4+DQo+Pj4+Pj4NCj4+
Pj4NCj4+Pj4+Pj4gCQloc19lcC0+ZGVzY19saXN0W2luZGV4IC0gMV0uc3RhdHVzICY9IH5ERVZf
RE1BX0w7IEBAIC04NjUsOA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+IFdoZW4gY2hhbmdpbmcgdGhlIHN0YXR1cyBvZiB0aGUgZGVzYywgSG93
IHRvIHN5bmMgdGhlIFNXIHdpdGggdGhlIEhXPw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4g
U2luY2UgdGhlIEhXIGFuZCBTVyBpcyB3b3JraW5nIG9uIHRoZSBzYW1lIGRlc2Mgc3luY2hyb25v
dXNseS4NCj4+Pj4NCj4+Pj4+DQo+Pj4+DQo+Pj4+PiBOb3QgY2xlYXIgZm9yIHdoYXQgeW91IG1l
YW46IEhXIGFuZCBTVyB3b3JraW5nIG9uIHNhbWUgZGVzYw0KPj4+IHN5bmNocm9ub3VzbHk/DQo+
Pj4+DQo+Pj4+PiBEZXNjcmlwdG9yIGxpc3QgaXMgbGlrZSBQcm9kdWNlcihTVykvQ29uc3VtZXIo
SFcpIGxpc3QuDQo+Pj4+DQo+Pj4+PiBJbmRleCBtYW5hZ2VtZW50IGFsbG93IGFsd2F5cyBrZWVw
IGdhcCBiZXR3ZWVuIFByb2R1Y2VyIGFuZA0KPj4+Pj4gQ29uc3VtZXINCj4+Pj4NCj4+Pj4+IGlu
ZGV4ZXMuIFByb2R1Y2VyIGluZGV4IHNob3VsZCBiZSBhbHdheXMgbW9yZSB0aGFuIENvbnN1bWVy
IGluZGV4Lg0KPj4+Pj4gSW4gc29tZQ0KPj4+Pg0KPj4+Pj4gY2FzZXMgd2hlbiBDb25zdW1lciBp
bmRleCBhY2hpZXZlZCBQcm9kdWNlciBpbmRleCwgd2hpY2ggbWVhbiBubw0KPj4+Pj4gbW9yZQ0K
Pj4+Pg0KPj4+Pj4gcmVhZHkgZGVzY3JpcHRvciB0byBwcm9jZXNzIHRoZW4gQk5BIGludGVycnVw
dCB3aWxsIGJlIGFzc2VydGVkLA0KPj4+Pj4gaS5lIFNXIGNhbid0DQo+Pj4+DQo+Pj4+PiBlbm91
Z2ggYmFuZHdpZHRoIHRvIHN1Ym1pdCBuZXcgcmVxdWVzdHMuDQo+Pj4+DQo+Pj4+Pg0KPj4+Pg0K
Pj4+Pg0KPj4+Pg0KPj4+PiBBYm91dCBteSBxdWVzdGlvbiwNCj4+Pj4NCj4+Pj4gSSBtZWFuIHdo
ZW4geW91IGNsZWFyIHRoZSBERVZfRE1BX0wgYml0IG9mIGxhc3QgZGVzYyBpbiB0aGUgY2hhaW4s
DQo+Pj4+IHRoZSBIVyBtYXkgYmUNCj4+Pj4NCj4+Pj4gYWNjZXNzaW5nIHRoaXMgcGFydGljdWxh
ciBkZXNjIGF0IHRoZSBzYW1lIHRpbWUsIHNvIHBlcmhhcHMgdGhlDQo+Pj4+IERFVl9ETUFfTCBi
aXQNCj4+Pj4NCj4+Pj4gY2xlYXIgYWN0aW9uIGlzIG5vdCBzeW5jIHRvIHRoZSBIVywgYW5kIHRo
ZSBIVyBjYW4ndCB3b3JrIGFzIHdlIHdhbnQuDQo+Pj4+DQo+Pj4+DQo+Pj4gQ29yZSBhbHdheXMg
ZmV0Y2hpbmcgMSBkZXNjcmlwdG9yIGJhc2VkIG9uOg0KPj4+IDEuIElTT0MgSU4gLSBvbmUgdWYg
YmVmb3JlIHRhcmdldCB1Zi4NCj4+PiAyLiBJU09DIE9VVCAtIFJ4RklGTyBOb25FbXB0eSwgRVAg
ZW5hYmxlZC4NCj4+PiBBcyBJIG1lbnRpb25lZCBiZWZvcmUsIGJldHdlZW4gcHJvZHVjZXIgYW5k
IGNvbnN1bWVyIGluZGV4ZXMgc2hvdWxkDQo+Pj4gYmUgZW5vdWdoIGdhcC4gSWYgbm90LCB0aGVu
IEJOQSB3aWxsIGJlIGFzc2VydGVkLCBFUCB3aWxsIGJlIGRpc2FibGVkDQo+Pj4gYW5kIHdpbGwg
bmVlZCB0byByZXN0YXJ0IHRyYW5zZmVycyBmcm9tIHNjcmF0Y2ggYmFzZWQgb24gSU4tTkFLIChJ
U09DDQo+Pj4gSU4pIG9yIE9VVC1FUERpcyAoSVNPQw0KPj4+IE9VVCkgaW50ZXJydXB0cy4NCj4+
Pj4NCj4+DQo+PiBIb3cgZG8geW91IGVuc3VyZSBlbm91Z2ggZ2FwIGJldHdlZW4gdGhlIHByb2R1
Y2VyIGFuZCBjb25zdW1lcj8NCj4+IFRoZSBwcm9kdWNlciBmaWxsIG5ldyBkZXNjIGF0IHJhbmRv
bSB0aW1lLCBhbmQgd2hlbiBjbGVhcmluZyB0aGUNCj4+IERFVl9ETUFfTCBiaXQgb2YgdGhlIGxh
c3QgZGVzYyBpbiB0aGUgY2hhaW4sIGludGVycnVwdHMgaXMgZGlzYWJsZWQNCj4+IGFuZCB3ZSBt
YXkgZGVsYXkgb3IgbWlzcyB0aGUgQk5BIGludGVycnVwdC4NCj4+IExpbnV4IGlzIG5vdCBhIHJl
YWwgdGltZSBzeXN0ZW0sIHNvIEkgdGhpbmsgd2Ugc2hvdWxkIGNvbnNpZGVyIHN1Y2ggY29ybmVy
DQo+Y2FzZXMuDQo+Pg0KPlN1Y2ggY29ybmVyIGNhc2UgY29uc2lkZXJlZCBpbiBkcml2ZXIgYnkg
aGFuZGxpbmcgQk5BIGFuZCByZXN0YXJ0aW5nIHRyYW5zZmVycw0KPmJhc2VkIG9uIHJlbWFpbmlu
ZyByZXF1ZXN0cyBpbiBxdWV1ZSwgaWYgYW55Lg0KPg0KQk5BIGludGVycnVwdCB3aWxsIHJlcG9y
dCBhbiAtRUlPIGVycm9yIHRvIHRoZSBmdW5jdGlvbiBpbiB5b3VyIDNyZCBwYXRjaCwgc28gSSB0
aGluaw0KdGhpcyBpcyBub3QgYW4gSU8gZXJyb3IgYW5kIHdoYXQgYWJvdXQgcmV0dXJuaW5nIC1F
UkVTVEFSVCh5b3UgaGF2ZSBtZW50aW9uZWQgaW4NCiBhbm90aGVyIG1haWwpLg0KDQpBbmQgdGhl
IHJlc3RhcnQgdHJhbnNmZXIgdGhlIHJlbWFpbmluZyByZXF1ZXN0cyBpbiBxdWV1ZSBpbiB0aGUg
TkFLIGludGVycnVwdCwgcmlnaHQ/DQoNCj5JZiBpdCBoYXBwZW4gdGhlbiB0aGVyZSBpcyBubyBp
bmRleCBnYXAsIGJlY2F1c2UgZnVuY3Rpb24gZHJpdmVyIG5vdCBhYmxlIHRvIHF1ZXVlDQo+bmV3
IHJlcXVlc3RzIG9uIHRpbWUuIElmIG5vIGFueSByZXF1ZXN0cyBpbiBxdWV1ZSB0aGVuDQo+Kmxp
c3QqIG9mIGRlc2NyaXB0b3JzIGNhbid0IGJlIGNyZWF0ZWQgYXQgYWxsLg0KPlRpbWUgZ2FwIGJl
dHdlZW4gMiBuZXcgc3Vic2VxdWVudCByZXF1ZXN0cyBzaG91bGQgYmUgc2ltaWxhciB0byBpbnRl
cnZhbC4gSWYNCj5mdW5jdGlvbiBkcml2ZXIgY2FuJ3QgZG8gaXQgdGhlbiB1c2luZyBkZXNjcmlw
dG9yIERNQSBtb2RlIG5vdCBiZSByZWFzb25hYmxlLA0KPmJ1ZmZlciBETUEgbW9kZSBzaG91bGQg
YmUgdXNlZCBpbnN0ZWFkLg0KPg0KPj4+PiBQZXIgeW91ciBjb21tZW50LCB5b3UgbWVudGlvbmVk
IHRoZSBwcm9kdWNlciBhbmQgY29uc3VtZXIsIGJ1dA0KPj4+Pg0KPj4+PiBIb3cgZG8geW91IGRv
IHRoZSBzeW5jaHJvbml6YXRpb24gYmV0d2VlbiB0aGUgcHJvZHVjZXIgYW5kIGNvbnN1bWVyPw0K
Pj4+Pg0KPj4+IEFjdHVhbGx5LCBhcyBzb29uIGFzIGNvbnN1bWVyIGNvbXBsZXRlIHNvbWUgZGVz
YyB0aGVuIGR3YzIgY29tcGxldGUNCj4+PiBhcHByb3ByaWF0ZSBwcm9kdWNlcnMgcmVxdWVzdCB0
byBmdW5jdGlvbiBkcml2ZXIgdGhlbiBmdW5jdGlvbiBkcml2ZXINCj4+PiBxdWV1aW5nIG5ldyBy
ZXF1ZXN0LiBTbywgaW5pdGlhbCBnYXAgd2lsbCBiZSBrZXB0Lg0KPj4+Pg0KPj4NCj4+IEl0IGlz
IG5vdCBtYW5kYXRhcnkgZm9yIHRoZSBmdW5jdGlvbiBkcml2ZXIgdG8gcXVldWluZyBuZXcgcmVx
dWVzdCBpbg0KPj4gdGhlIGNvbXBsZXRlIGhhbmRsZXIuIHdlIGNhbid0IGRlcGVuZCBvbiB0aGUg
ZnVuY3Rpb24gZHJpdmVyIHRvIGtlZXAgdGhlIGdhcC4NCj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKzg0NiwxNCBAQCBzdGF0aWMgaW50IGR3YzJfZ2FkZ2V0
X2ZpbGxfaXNvY19kZXNjKHN0cnVjdA0KPj4+Pj4+PiArZHdjMl9oc290Z19lcA0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICpoc19lcCwNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJ
ZGVzYy0+c3RhdHVzICY9IH5ERVZfRE1BX0JVRkZfU1RTX01BU0s7DQo+Pj4+DQo+Pj4+Pj4NCj4+
Pj4NCj4+Pj4+Pj4gCWRlc2MtPnN0YXR1cyB8PSAoREVWX0RNQV9CVUZGX1NUU19IUkVBRFkgPDwN
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBERVZfRE1BX0JVRkZfU1RTX1NISUZUKTsNCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJ
LyogSW5jcmVtZW50IGZyYW1lIG51bWJlciBieSBpbnRlcnZhbCBmb3IgSU4gKi8NCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCWlmIChoc19lcC0+ZGlyX2luKQ0KPj4+Pg0KPj4+Pj4+DQo+
Pj4+DQo+Pj4+Pj4+ICsJCWR3YzJfZ2FkZ2V0X2luY3JfZnJhbWVfbnVtKGhzX2VwKTsNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCS8q
IFVwZGF0ZSBpbmRleCBvZiBsYXN0IGNvbmZpZ3VyZWQgZW50cnkgaW4gdGhlIGNoYWluICovDQo+
Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCWhzX2VwLT5uZXh0X2Rlc2MrKzsNCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCWlmIChoc19lcC0+bmV4dF9kZXNjID49IE1BWF9ETUFfREVT
Q19OVU1fR0VORVJJQykNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCQloc19lcC0+bmV4
dF9kZXNjID0gMDsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+
Pj4+DQo+Pj4+Pj4+IAlyZXR1cm4gMDsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiB9DQo+
Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gQEAgLTg3NSwxMSArODYyLDggQEAgc3RhdGljIGlu
dCBkd2MyX2dhZGdldF9maWxsX2lzb2NfZGVzYyhzdHJ1Y3QNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+PiBkd2MyX2hzb3RnX2VwICpoc19lcCwNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiAgICAgKiBkd2MyX2dhZGdldF9zdGFydF9pc29jX2RkbWEgLSBzdGFydCBpc29jaHJvbm91cyB0
cmFuc2ZlciBpbg0KPj4+Pj4+PiBERE1BDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gICAg
ICogQGhzX2VwOiBUaGUgaXNvY2hyb25vdXMgZW5kcG9pbnQuDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4gICAgICoNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtICogUHJlcGFyZSBm
aXJzdCBkZXNjcmlwdG9yIGNoYWluIGZvciBpc29jaHJvbm91cyBlbmRwb2ludHMuDQo+Pj4+DQo+
Pj4+Pj4+IEFmdGVyd2FyZHMNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArICogUHJlcGFy
ZSBkZXNjcmlwdG9yIGNoYWluIGZvciBpc29jaHJvbm91cyBlbmRwb2ludHMuDQo+Pj4+Pj4+ICsg
QWZ0ZXJ3YXJkcw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICAgICAqIHdyaXRlIERNQSBh
ZGRyZXNzIHRvIEhXIGFuZCBlbmFibGUgdGhlIGVuZHBvaW50Lg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+IC0gKg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0gKiBTd2l0Y2ggYmV0
d2VlbiBkZXNjcmlwdG9yIGNoYWlucyB2aWEgaXNvY19jaGFpbl9udW0gdG8gZ2l2ZQ0KPj4+Pj4+
PiBTVw0KPj4+Pg0KPj4+Pj4+PiBvcHBvcnR1bml0eQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+IC0gKiB0byBwcmVwYXJlIHNlY29uZCBkZXNjcmlwdG9yIGNoYWluIHdoaWxlIGZpcnN0IG9u
ZSBpcyBiZWluZw0KPj4+Pj4+PiBwcm9jZXNzZWQgYnkNCj4+Pj4NCj4+Pj4+IEhXLg0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICAgICAqLw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
IHN0YXRpYyB2b2lkIGR3YzJfZ2FkZ2V0X3N0YXJ0X2lzb2NfZGRtYShzdHJ1Y3QgZHdjMl9oc290
Z19lcA0KPj4+Pj4+PiAqaHNfZXApDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4geyBAQCAt
ODkwLDE5ICs4NzQsMjcgQEAgc3RhdGljIHZvaWQNCj4+Pj4NCj4+Pj4+Pj4gZHdjMl9nYWRnZXRf
c3RhcnRfaXNvY19kZG1hKHN0cnVjdA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IGR3YzJf
aHNvdGdfZXAgKmhzX2VwKQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAl1MzIgZG1hX3Jl
ZzsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJdTMyIGRlcGN0bDsNCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAJdTMyIGN0cmw7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
KwlzdHJ1Y3QgZHdjMl9kbWFfZGVzYyAqZGVzYzsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAlpZiAobGlzdF9lbXB0eSgmaHNfZXAtPnF1
ZXVlKSkgew0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAkJZGV2X2RiZyhoc290Zy0+ZGV2
LCAiJXM6IE5vIHJlcXVlc3RzIGluIHF1ZXVlXG4iLCBfX2Z1bmNfXyk7DQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gCQlyZXR1cm47DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCX0N
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
ICsJLyogSW5pdGlhbGl6ZSBkZXNjcmlwdG9yIGNoYWluIGJ5IEhvc3QgQnVzeSBzdGF0dXMgKi8N
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCWZvciAocmV0ID0gMDsgcmV0IDwgTUFYX0RN
QV9ERVNDX05VTV9HRU5FUklDOyByZXQrKykgew0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
ICsJCWRlc2MgPSAmaHNfZXAtPmRlc2NfbGlzdFtyZXRdOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4+ICsJCWRlc2MtPnN0YXR1cyA9IDA7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
KwkJZGVzYy0+c3RhdHVzIHw9IChERVZfRE1BX0JVRkZfU1RTX0hCVVNZDQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gKwkJCQkgICAgPDwgREVWX0RNQV9CVUZGX1NUU19TSElGVCk7DQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwl9DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
Kw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
IFJldCBpcyBub3QgYSBnb29kIG5hbWluZyBhcyB0aGUgbG9vcCBjb3VudGVyLg0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pg0KPj4+Pg0KPj4+Pj4gQ291bGQgYmUsIGJ1dCBpdCBqdXN0IHJldXNl
IGV4aXN0aW5nIHZhcmlhYmxlIGluc3RlYWQgdG8gZGVmaW5lIG5ldyBvbmUuDQo+Pj4+DQo+Pj4+
Pg0KPj4+Pg0KPj4+Pg0KPj4+Pg0KPj4+PiAgIEZyb20gdGhlIGNvZGUgcmVhZGVyJ3MgcGVyc3Bl
Y3RpdmUsIGl0IGlzIGEgYml0IHN0cmFuZ2UuDQo+Pj4+DQo+Pj4gT2ssIHdpbGwgZGVjbGFyZSBu
ZXcgdmFyaWFibGUuDQo+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiArCWhzX2VwLT5uZXh0X2Rlc2MgPSAwOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
IAlsaXN0X2Zvcl9lYWNoX2VudHJ5X3NhZmUoaHNfcmVxLCB0cmVxLCAmaHNfZXAtPnF1ZXVlLCBx
dWV1ZSkgew0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+IERvIHdlIHJlYWxseSBuZWVkIHNhZmUgZnVuY3Rpb24gaGVyZT8gV2UgaGF2ZSBhbHJl
YWR5IGhhdmUgdGhlIHNwaW5sb2NrLg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+PiBJIGxlZnQg
ZXhpc3RpbmcgbGlzdF9mb3JfZWFjaF9lbnRyeV9zYWZlKCkgbm90IG9mIHBhcnQgb2YgdGhpcyBw
YXRjaC4NCj4+Pj4NCj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiAJCXJldCA9IGR3YzJfZ2FkZ2V0X2ZpbGxfaXNvY19kZXNjKGhzX2VwLCBoc19yZXEtPnJl
cS5kbWEsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCQkJCQkJIGhzX3JlcS0+cmVxLmxl
bmd0aCk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkJaWYgKHJldCkgew0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JCQlkZXZfZGJnKGhzb3RnLT5kZXYsICIlczogZGVzYyBj
aGFpbiBmdWxsXG4iLCBfX2Z1bmNfXyk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJ
aWYgKHJldCkNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJCQlicmVhazsNCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQl9DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCX0N
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
IAlkZXBjdGwgPSBoc19lcC0+ZGlyX2luID8gRElFUENUTChpbmRleCkgOiBET0VQQ1RMKGluZGV4
KTsgQEANCj4+Pj4+Pj4gLTkxNCwxMA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICs5MDYs
NiBAQCBzdGF0aWMgdm9pZCBkd2MyX2dhZGdldF9zdGFydF9pc29jX2RkbWEoc3RydWN0DQo+Pj4+
DQo+Pj4+Pj4+ICtkd2MyX2hzb3RnX2VwDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKmhz
X2VwKQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAljdHJsID0gZHdjMl9yZWFkbChoc290
Zy0+cmVncyArIGRlcGN0bCk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCWN0cmwgfD0g
RFhFUENUTF9FUEVOQSB8IERYRVBDVExfQ05BSzsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiAJZHdjMl93cml0ZWwoY3RybCwgaHNvdGctPnJlZ3MgKyBkZXBjdGwpOw0KPj4+Pg0KPj4+Pj4+
DQo+Pj4+DQo+Pj4+Pj4+IC0NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCS8qIFN3aXRj
aCBJU09DIGRlc2NyaXB0b3IgY2hhaW4gbnVtYmVyIGJlaW5nIHByb2Nlc3NlZCBieSBTVyovDQo+
Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQloc19lcC0+aXNvY19jaGFpbl9udW0gPSAoaHNf
ZXAtPmlzb2NfY2hhaW5fbnVtIF4gMSkgJiAweDE7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gLQloc19lcC0+bmV4dF9kZXNjID0gMDsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiB9
DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiAvKioNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBAQCAtMTI5MSw2ICsxMjc5LDkgQEAg
c3RhdGljIGludCBkd2MyX2hzb3RnX2VwX3F1ZXVlKHN0cnVjdA0KPj4+Pj4+PiB1c2JfZXANCj4+
Pj4NCj4+Pj4+Pj4gKmVwLA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IHN0cnVjdCB1c2Jf
cmVxdWVzdCAqcmVxLA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAlzdHJ1Y3QgZHdjMl9o
c290ZyAqaHMgPSBoc19lcC0+cGFyZW50Ow0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAli
b29sIGZpcnN0Ow0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAlpbnQgcmV0Ow0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJdTMyIG1heHNpemUgPSAwOw0KPj4+Pg0KPj4+Pj4+DQo+
Pj4+DQo+Pj4+Pj4+ICsJdTMyIG1hc2sgPSAwOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
ICsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+IAlkZXZfZGJnKGhzLT5kZXYsICIlczogcmVxICVwOiAlZEAlcCwgbm9pPSVkLCB6ZXJvPSVk
LA0KPj4+IHNub2s9JWRcbiIsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCQllcC0+bmFt
ZSwgcmVxLCByZXEtPmxlbmd0aCwgcmVxLT5idWYsIHJlcS0+bm9faW50ZXJydXB0LCBAQA0KPj4+
Pj4+PiAtMTMwOCw2DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKzEyOTksMjQgQEAgc3Rh
dGljIGludCBkd2MyX2hzb3RnX2VwX3F1ZXVlKHN0cnVjdCB1c2JfZXAgKmVwLA0KPj4+Pj4+PiAr
c3RydWN0DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gdXNiX3JlcXVlc3QgKnJlcSwNCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJcmVxLT5hY3R1YWwgPSAwOw0KPj4+Pg0KPj4+Pj4+
DQo+Pj4+DQo+Pj4+Pj4+IAlyZXEtPnN0YXR1cyA9IC1FSU5QUk9HUkVTUzsNCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJLyogSW4gRERN
QSBtb2RlIGZvciBJU09DJ3MgZG9uJ3QgcXVldWUgcmVxdWVzdCBpZiBsZW5ndGgNCj4+Pj4+Pj4g
K2dyZWF0ZXINCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCSAqIHRoYW4gZGVzY3JpcHRv
ciBsaW1pdHMuDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkgKi8NCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiArCWlmICh1c2luZ19kZXNjX2RtYShocykgJiYgaHNfZXAtPmlzb2No
cm9ub3VzKSB7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJbWF4c2l6ZSA9IGR3YzJf
Z2FkZ2V0X2dldF9kZXNjX3BhcmFtcyhoc19lcCwgJm1hc2spOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+ICsJCWlmIChoc19lcC0+ZGlyX2luICYmIHJlcS0+bGVuZ3RoID4gbWF4c2l6ZSkg
ew0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCQlkZXZfZXJyKGhzLT5kZXYsICJ3cm9u
ZyBsZW5ndGggJWQgKG1heHNpemU9JWQpXG4iLA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
ICsJCQkJcmVxLT5sZW5ndGgsIG1heHNpemUpOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
ICsJCQlyZXR1cm4gLUVJTlZBTDsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCQl9DQo+
Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJLyogSVNPQyBPVVQgaGlnaCBiYW5kd2lkdGgg
bm90IHN1cHBvcnRlZCAqLw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCWlmICghaHNf
ZXAtPmRpcl9pbiAmJiByZXEtPmxlbmd0aCA+IGhzX2VwLT5lcC5tYXhwYWNrZXQpIHsNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCQkJZGV2X2Vycihocy0+ZGV2LCAiSVNPQyBPVVQ6IHdy
b25nIGxlbmd0aCAlZCAobXBzPSVkKVxuIiwNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAr
CQkJCXJlcS0+bGVuZ3RoLCBoc19lcC0+ZXAubWF4cGFja2V0KTsNCj4+Pj4NCj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4+PiArCQkJcmV0dXJuIC1FSU5WQUw7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gKwkJfQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJfQ0KPj4+Pg0KPj4+Pj4+DQo+
Pj4+DQo+Pj4+Pj4+ICsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJcmV0ID0gZHdjMl9o
c290Z19oYW5kbGVfdW5hbGlnbmVkX2J1Zl9zdGFydChocywgaHNfZXAsIGhzX3JlcSk7DQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCWlmIChyZXQpDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+
Pj4+Pj4gCQlyZXR1cm4gcmV0Ow0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IEBAIC0xMzMw
LDcgKzEzMzksNyBAQCBzdGF0aWMgaW50IGR3YzJfaHNvdGdfZXBfcXVldWUoc3RydWN0DQo+Pj4+
Pj4+IHVzYl9lcA0KPj4+Pg0KPj4+Pj4+PiAqZXAsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gc3RydWN0IHVzYl9yZXF1ZXN0ICpyZXEsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJLyoNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiAJICogSGFuZGxlIERETUEgaXNvY2hyb25vdXMgdHJhbnNmZXJzIHNlcGFyYXRlbHkgLSBq
dXN0IGFkZCBuZXcNCj4+Pj4+Pj4gZW50cnkNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAt
CSAqIHRvIHRoZSBoYWxmIG9mIGRlc2NyaXB0b3IgY2hhaW4gdGhhdCBpcyBub3QgcHJvY2Vzc2Vk
IGJ5IEhXLg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJICogdG8gdGhlIGRlc2NyaXB0
b3IgY2hhaW4uDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCSAqIFRyYW5zZmVyIHdpbGwg
YmUgc3RhcnRlZCBvbmNlIFNXIGdldHMgZWl0aGVyIG9uZSBvZiBOQUsgb3INCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAJICogT3V0VGtuRXBEaXMgaW50ZXJydXB0cy4NCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAJICovDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gQEAgLTEz
MzgsOSArMTM0Nyw5IEBAIHN0YXRpYyBpbnQgZHdjMl9oc290Z19lcF9xdWV1ZShzdHJ1Y3QNCj4+
Pj4+Pj4gdXNiX2VwDQo+Pj4+DQo+Pj4+Pj4+ICplcCwNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiBzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcSwNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiAJICAgIGhzX2VwLT50YXJnZXRfZnJhbWUgIT0gVEFSR0VUX0ZSQU1FX0lOSVRJQUwpIHsNCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJCXJldCA9IGR3YzJfZ2FkZ2V0X2ZpbGxfaXNvY19k
ZXNjKGhzX2VwLCBoc19yZXEtPnJlcS5kbWEsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
CQkJCQkJIGhzX3JlcS0+cmVxLmxlbmd0aCk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
LQkJaWYgKHJldCkNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQkJZGV2X2RiZyhocy0+
ZGV2LCAiJXM6IElTTyBkZXNjIGNoYWluIGZ1bGxcbiIsIF9fZnVuY19fKTsNCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAtDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJaWYgKHJl
dCA8IDApDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJCWRldl9kYmcoaHMtPmRldiwg
IiVzOiBmYWlsZWQgdG8gZmlsbCBpc29jIGRlc2NcbiIsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+
Pj4+Pj4gKwkJCQlfX2Z1bmNfXyk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4gZHdjMl9nYWRnZXRfZmlsbF9pc29jX2Rlc2Mgd2lsbCBuZXZl
ciByZXR1cm4gYSBuZWdhdGl2ZSB2YWx1ZSwgYW5kDQo+Pj4+Pj4gYXQNCj4+Pj4NCj4+Pj4+PiB0
aGUgc2FtZQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4gdGltZSBJIHRoaW5rIHRoZXJlIGlz
IG5vIG5lZWQgdG8gY2hlY2sgdGhlIHJldHVybiB2YWx1ZSwgd2UgY2FuDQo+Pj4+Pj4gd29yaw0K
Pj4+Pg0KPj4+Pj4+IHByb3Blcmx5IGV2ZW4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+IHRo
ZSBkZXNjIGNoYWluIGlzIGZ1bGwuDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+IFlvdSBhcmUg
cmlndGguIHJldCBpcyAwIG9yIDEuIFNvLCBubyBuZWVkIHRvIGNoYW5nZSBleGlzdGluZyBjb2Rl
Lg0KPj4+Pj4gWWVzLCB3ZSBjYW4NCj4+Pj4NCj4+Pj4+IGNvbnRpbnVlIHdvcmsgcHJvcGVybHkg
ZXZlbiBpZiB0aGUgZGVzYyBjaGFpbiBmdWxsLiBJdCBqdXN0IGRlYnVnDQo+Pj4+PiBtZXNzYWdl
IGlmIChyZXQgIT0NCj4+Pj4NCj4+Pj4+IDApLiBEbyB5b3UgaGF2ZSBvYmplY3Rpb24/DQo+Pj4+
DQo+Pj4+Pg0KPj4+Pg0KPj4+Pg0KPj4+Pg0KPj4+PiBTaW5jZSB3ZSBhbHJlYWR5IGhhdmUgZGVi
dWcgbWVzc2FnZSBpbnNpZGUNCj4+Pj4gZHdjMl9nYWRnZXRfZmlsbF9pc29jX2Rlc2MsIHNvIGhl
cmUNCj4+Pj4NCj4+Pj4gd2UgZG9uJ3QgbmVlZCBhZGRpdGlvbmFsIGRlYnVnIG1lc3NhZ2UsIHdo
YXQgZG8geW91IHRoaW5rIG9mIGl0Pw0KPj4+Pg0KPj4+Pg0KPj4+IEFncmVlIHdpdGggeW91LCB3
aWxsIHJlbW92ZS4NCj4+Pj4NCj4+Pj4NCj4+Pj4NCj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJCXJldHVybiAwOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4+IAl9DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4+PiBAQCAtMjAxMSwxMCArMjAyMCw5IEBAIHN0YXRpYyB2b2lkDQo+Pj4+DQo+Pj4+
PiBkd2MyX2hzb3RnX2NvbXBsZXRlX3JlcXVlc3Qoc3RydWN0DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4gZHdjMl9oc290ZyAqaHNvdGcsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
ICAgICogQGhzX2VwOiBUaGUgZW5kcG9pbnQgdGhlIHJlcXVlc3Qgd2FzIG9uLg0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICAgICAqDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gICAg
ICogR2V0IGZpcnN0IHJlcXVlc3QgZnJvbSB0aGUgZXAgcXVldWUsIGRldGVybWluZSBkZXNjcmlw
dG9yDQo+Pj4+Pj4+IG9uDQo+Pj4+DQo+Pj4+Pj4+IHdoaWNoDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4gY29tcGxldGUNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtICogaGFwcGVu
ZWQuIFNXIGJhc2VkIG9uIGlzb2NfY2hhaW5fbnVtIGRpc2NvdmVycyB3aGljaCBoYWxmIG9mDQo+
Pj4+Pj4+IHRoZQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IGRlc2NyaXB0b3INCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtICogY2hhaW4gaXMgY3VycmVudGx5IGluIHVzZSBieSBI
VywgYWRqdXN0cyBkbWFfYWRkcmVzcyBhbmQNCj4+Pj4NCj4+Pj4+Pj4gY2FsY3VsYXRlcyBpbmRl
eA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0gKiBvZiBjb21wbGV0ZWQgZGVzY3JpcHRv
ciBiYXNlZCBvbiB0aGUgdmFsdWUgb2YgREVQRE1BIHJlZ2lzdGVyLg0KPj4+Pg0KPj4+Pj4+PiBV
cGRhdGUNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBhY3R1YWwNCj4+Pj4NCj4+Pj4+Pg0K
Pj4+Pg0KPj4+Pj4+PiAtICogbGVuZ3RoIG9mIHJlcXVlc3QsIGdpdmViYWNrIHRvIGdhZGdldC4N
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArICogaGFwcGVuZWQuIFNXIGRpc2NvdmVycyB3
aGljaCBkZXNjcmlwdG9yIGN1cnJlbnRseSBpbiB1c2UgYnkNCj4+Pj4+Pj4gKyBIVywNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArIGFkanVzdHMNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiArICogZG1hX2FkZHJlc3MgYW5kIGNhbGN1bGF0ZXMgaW5kZXggb2YgY29tcGxldGVkIGRl
c2NyaXB0b3INCj4+Pj4+Pj4gKyBiYXNlZCBvbg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
ICsgdGhlIHZhbHVlDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKyAqIG9mIERFUERNQSBy
ZWdpc3Rlci4gVXBkYXRlIGFjdHVhbCBsZW5ndGggb2YgcmVxdWVzdCwgZ2l2ZWJhY2sNCj4+Pj4+
Pj4gKyB0bw0KPj4+IGdhZGdldC4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAgICAgKi8N
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBzdGF0aWMgdm9pZCBkd2MyX2dhZGdldF9jb21w
bGV0ZV9pc29jX3JlcXVlc3RfZGRtYShzdHJ1Y3QNCj4+Pj4NCj4+Pj4+Pj4gZHdjMl9oc290Z19l
cA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICpoc19lcCkgIHsgQEAgLTIwMzcsODIgKzIw
NDUsNTUgQEAgc3RhdGljIHZvaWQNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBkd2MyX2dh
ZGdldF9jb21wbGV0ZV9pc29jX3JlcXVlc3RfZGRtYShzdHJ1Y3QgZHdjMl9oc290Z19lcA0KPj4+
ICpoc19lcCkNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+IAlkbWFfYWRkciA9IGhzX2VwLT5kZXNjX2xpc3RfZG1hOw0KPj4+Pg0KPj4+Pj4+
DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkvKg0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JICogSWYgbG93ZXIgaGFsZiBvZiAgZGVzY3JpcHRvciBj
aGFpbiBpcyBjdXJyZW50bHkgdXNlIGJ5IFNXLA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
IC0JICogdGhhdCBtZWFucyBoaWdoZXIgaGFsZiBpcyBiZWluZyBwcm9jZXNzZWQgYnkgSFcsIHNv
IHNoaWZ0DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkgKiBETUEgYWRkcmVzcyB0byBo
aWdoZXIgaGFsZiBvZiBkZXNjcmlwdG9yIGNoYWluLg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+IC0JICovDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQlpZiAoIWhzX2VwLT5pc29j
X2NoYWluX251bSkNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQlkbWFfYWRkciArPSBz
aXplb2Yoc3RydWN0IGR3YzJfZG1hX2Rlc2MpICoNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiAtCQkJICAgIChNQVhfRE1BX0RFU0NfTlVNX0dFTkVSSUMgLyAyKTsNCj4+Pj4NCj4+Pj4+Pg0K
Pj4+Pg0KPj4+Pj4+PiAtDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCWRtYV9yZWcgPSBo
c19lcC0+ZGlyX2luID8gRElFUERNQShoc19lcC0+aW5kZXgpIDoNCj4+Pj4NCj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4+PiBET0VQRE1BKGhzX2VwLT5pbmRleCk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+
Pj4+Pj4gCWRlcGRtYSA9IGR3YzJfcmVhZGwoaHNvdGctPnJlZ3MgKyBkbWFfcmVnKTsNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAlpbmRl
eCA9IChkZXBkbWEgLSBkbWFfYWRkcikgLyBzaXplb2Yoc3RydWN0IGR3YzJfZG1hX2Rlc2MpIC0g
MTsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCWRlc2Nfc3RzID0gaHNfZXAtPmRlc2Nf
bGlzdFtpbmRleF0uc3RhdHVzOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJLyogQ2hl
Y2sgZGVzY3JpcHRvciBjaGFpbiByb2xsb3ZlciAqLw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+ICsJaWYgKGluZGV4IDwgMCkNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCQlpbmRl
eCA9IE1BWF9ETUFfREVTQ19OVU1fR0VORVJJQyAtIDE7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+
Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+
Pj4+PiBJIGRvbid0IHVuZGVyc3RhbmQgaGVyZSwgd2h5IHNldHRpbmcgdGhlIGluZGV4IHRvDQo+
Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+PiAgICAgTUFYX0RNQV9ERVNDX05VTV9HRU5FUklDIC0g
MSB3aGVuIHRoZSBjaGFpbiBpcyByb2xsb3Zlcj8NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
IElmIHRoZSBjaGFpbiBpcyByb2xsb3ZlciwgdGhlIGluZGV4IHNob3VsZCBwb2ludCB0byB0aGUg
bGF0ZXN0DQo+Pj4+DQo+Pj4+Pj4gZmluaXNoZWQgZGVzYywNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+IGFuZCBhbGwgdGhlIGZpbmlzaGVkIGRlc2NzIHNob3VsZCBiZSBwcm9jZXNzZWQuIEFu
ZCBldmVuIHRoZSBjaGFpbg0KPj4+Pj4+IGlzDQo+Pj4+DQo+Pj4+Pj4gcm9sbG92ZXIsDQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+PiB0aGUgY291bnQgb2YgZGVzY3MgaW4gY2hhaW4gaXMgbWF5
YmUgbGVzcyB0aGVuDQo+Pj4+DQo+Pj4+PiBNQVhfRE1BX0RFU0NfTlVNX0dFTkVSSUMuDQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+IElmIGRlcGRtYSBwb2ludCB0byBmaXJzdCBkZXNjIGluIGxp
c3QsIHRoYXQgbWVhbiB0aGUgbGFzdCBwcm9jZXNzZWQNCj4+Pj4+IGRlc2Mgd2FzIGxhc3QNCj4+
Pj4NCj4+Pj4+IGluIHRoZSBjaGFpbi4gSW4gdGhpcyBjYXNlIGluZGV4IHdpbGwgYmUgbmVnYXRp
dmUuDQo+Pj4+DQo+Pj4+PiBJbiBjYXNlIG9mIGRlc2MgY291bnQgbGVzcyB0aGFuIE1BWF9ETUFf
REVTQ19OVU1fR0VORVJJQyB0aGVuDQo+Pj4+PiByb2xsb3Zlcg0KPj4+Pg0KPj4+Pj4gY2FuIGJl
IGhhcHBlbiAgYmVjYXVzZSBvZiBMLWJpdCBzZXQuIEluIHRoaXMgY2FzZSBieSBwcm9jZXNzaW5n
DQo+Pj4+PiBmaXJzdCBkZXNjIHdpbGwgYmUNCj4+Pj4NCj4+Pj4+IGFzc2VydGVkIEJOQSBpbnRl
cnJ1cHQgYnV0IG5vdCBYZmVyQ29tcGxldGUgaW50ZXJydXB0Lg0KPj4+Pg0KPj4+Pj4NCj4+Pj4N
Cj4+Pj4NCj4+Pj4NCj4+Pj4gQ2FuIHdlIHJlYWNoIGhlcmUgaW4gQk5BIGludGVycnVwdCwgb3Ig
Y2FuIHdlIGhhdmUgYm90aCBCTkEgYW5kDQo+Pj4+IFhmZXJDb21wbGV0ZQ0KPj4+Pg0KPj4+PiBJ
bnRlcnJ1cHRzIGFzc2VydGVkIGF0IHRoZSBzYW1lIHRpbWU/DQo+Pj4+DQo+Pj4+IFlvdXIgY29u
Y2x1c2lvbiBpcyBiYXNlZCBvbiB0aGUgZm9sbG93aW5nIGFzc3VtcHRpb246DQo+Pj4+DQo+Pj4+
IDEuICBCTkEgaW50ZXJydXB0IGhhbmRsZSBmbG93IGNhbid0IGdvIGludG8gaGVyZS4NCj4+Pj4N
Cj4+Pj4gMi4gIHdoZW4gdGhlIGV4ZWN1dGlvbiBmbG93IGdvaW5nIHRvIGhlcmUsIG9ubHkgYmVj
YXVzZSBvZg0KPj4+PiBYZmVyQ29tcGxldGUNCj4+PiBpbnRlcnJ1cHQuDQo+Pj4+DQo+Pj4+IDMu
ICB3aGVuIHRoZSBYZmVyQ29tcGxldGUgaXMgYXNzZXJ0ZWQsIEJOQSBpbnRlcnJ1cHQgY2FuJ3Qg
YmUgYXNzZXJ0ZWQuDQo+Pj4+DQo+Pj4+DQo+Pj4gSW4gY2FzZSBvZiBib3RoIGludGVycnVwdCBh
c3NlcnRlZCB0aGVuIFhmZXJDb21wbGV0ZSBpZ25vcmVkLiBTZWUNCj4+PiBkd2MyX2hzb3RnX2Vw
aW50KCkgZnVuY3Rpb24uIEFjdHVhbGx5LCBpbiBteSB0ZXN0IGNhc2VzIHdpdGgNCj4+PiBiSW50
ZXJ2YWw9MSBpdCBoYXBwZW4gb24gbGFzdCBkZXNjcmlwdG9yIGFuZCBubyBhbnkgbmV3IHJlcXVl
c3RzIGZyb20NCj4+PiBmdW5jdGlvbiBkcml2ZXIsIGJlY2F1c2UgRVAgZGlzYWJsZWQgd2l0aCBz
b21lIGxhdGVuY3kgaW4gY29yZSBCTkEgYWxzbw0KPmFzc2VydGVkLg0KPj4+IEJ1dCBpdHMgY29y
bmVyIGNhc2UgYW5kIGNhbiBiZSBpZ25vcmVkLg0KPj4+DQo+Pg0KPj4gVGhlbiB3aGF0IGFib3V0
IGFkZGluZyBzb21lIGFzc2VydCBoZXJlIHRvIGNhdGNoIHRoZSBjb3JlIGNhc2U/DQo+DQo+SWYg
Ym90aCBpbnRlcnJ1cHQgd2lsbCBiZSBhc3NlcnRlZCBzaW11bHRhbm91c2x5IHRoZW4gd2UgY2Fu
J3QgYmUgaGVyZSBiZWNhdXNlDQo+WGZlckNvbXBsZXRlIHdpbGwgYmUgaWdub3JlZCBhbmQgdGhp
cyBmdW5jdGlvbiB3aWxsIG5vdCBjYWxsZWQuDQo+DQo+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQltYXNrID0gaHNfZXAtPmRpcl9pbiA/IERFVl9ETUFfSVNP
Q19UWF9OQllURVNfTUFTSyA6DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkgICAgICAg
REVWX0RNQV9JU09DX1JYX05CWVRFU19NQVNLOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
IC0JdXJlcS0+YWN0dWFsID0gdXJlcS0+bGVuZ3RoIC0NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiAtCQkgICAgICAgKChkZXNjX3N0cyAmIG1hc2spID4+IERFVl9ETUFfSVNPQ19OQllURVNf
U0hJRlQpOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0NCj4+Pj4NCj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4+PiAtCS8qIEFkanVzdCBhY3R1YWwgbGVuZ3RoIGZvciBJU09DIE91dCBpZiBsZW5n
dGggaXMgbm90IGFsaWduIG9mIDQgKi8NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCWlm
ICghaHNfZXAtPmRpcl9pbiAmJiB1cmVxLT5sZW5ndGggJiAweDMpDQo+Pj4+DQo+Pj4+Pj4NCj4+
Pj4NCj4+Pj4+Pj4gLQkJdXJlcS0+YWN0dWFsICs9IDQgLSAodXJlcS0+bGVuZ3RoICYgMHgzKTsN
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCWRlc2Nfc3RzID0gaHNfZXAtPmRlc2NfbGlz
dFtpbmRleF0uc3RhdHVzOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJLyogQ2hlY2sg
Y29tcGxldGlvbiBzdGF0dXMgKi8NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCWlmICgo
ZGVzY19zdHMgJiBERVZfRE1BX1NUU19NQVNLKSA+PiBERVZfRE1BX1NUU19TSElGVCA9PQ0KPj4+
Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJICAgIERFVl9ETUFfU1RTX1NVQ0MpIHsNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCQltYXNrID0gaHNfZXAtPmRpcl9pbiA/IERFVl9ETUFf
SVNPQ19UWF9OQllURVNfTUFTSyA6DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJICAg
ICAgIERFVl9ETUFfSVNPQ19SWF9OQllURVNfTUFTSzsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiArCQl1cmVxLT5hY3R1YWwgPSB1cmVxLT5sZW5ndGggLQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+ICsJCQkgICAgICAgKChkZXNjX3N0cyAmIG1hc2spID4+DQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gKwkJCQlERVZfRE1BX0lTT0NfTkJZVEVTX1NISUZUKTsNCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJLyog
QWRqdXN0IGFjdHVhbCBsZW4gZm9yIElTT0MgT3V0IGlmIGxlbiBpcyBub3QgYWxpZ24gb2YgNCAq
Lw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCWlmICghaHNfZXAtPmRpcl9pbiAmJiB1
cmVxLT5sZW5ndGggJiAweDMpDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJCXVyZXEt
PmFjdHVhbCArPSA0IC0gKHVyZXEtPmxlbmd0aCAmIDB4Myk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCWR3YzJfaHNvdGdfY29tcGxl
dGVfcmVxdWVzdChoc290ZywgaHNfZXAsIGhzX3JlcSwgMCk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4gKwkJZHdjMl9oc290Z19jb21wbGV0ZV9yZXF1ZXN0KGhzb3RnLCBoc19lcCwgaHNf
cmVxLCAwKTsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCX0gZWxzZSB7DQo+Pj4+DQo+
Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJZHdjMl9oc290Z19jb21wbGV0ZV9yZXF1ZXN0KGhzb3Rn
LCBoc19lcCwgaHNfcmVxLA0KPj4+IC1FVElNRURPVVQpOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4+ICsJfQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IH0NCj4+Pj4NCj4+Pj4+Pg0K
Pj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC8qDQo+Pj4+DQo+Pj4+
Pj4NCj4+Pj4NCj4+Pj4+Pj4gLSAqIGR3YzJfZ2FkZ2V0X3N0YXJ0X25leHRfaXNvY19kZG1hIC0g
c3RhcnQgbmV4dCBpc29jIHJlcXVlc3QsIGlmIGFueS4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiAtICogQGhzX2VwOiBUaGUgaXNvY2hyb25vdXMgZW5kcG9pbnQgdG8gYmUgcmUtZW5hYmxl
ZC4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArICogZHdjMl9nYWRnZXRfaGFuZGxlX2lz
b2NfYm5hIC0gaGFuZGxlIEJOQSBpbnRlcnJ1cHQgZm9yIElTT0MuDQo+Pj4+DQo+Pj4+Pj4NCj4+
Pj4NCj4+Pj4+Pj4gKyAqIEBoc19lcDogVGhlIGlzb2Nocm9ub3VzIGVuZHBvaW50Lg0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICAgICAqDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
LSAqIElmIGVwIGhhcyBiZWVuIGRpc2FibGVkIGR1ZSB0byBsYXN0IGRlc2NyaXB0b3Igc2Vydmlj
aW5nIChJTg0KPj4+Pj4+PiBlbmRwb2ludCkgb3INCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiAtICogQk5BIChPVVQgZW5kcG9pbnQpIGNoZWNrIHRoZSBzdGF0dXMgb2Ygb3RoZXIgaGFsZiBv
Zg0KPj4+Pj4+PiBkZXNjcmlwdG9yIGNoYWluDQo+Pj4gdGhhdA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+IC0gKiB3YXMgdW5kZXIgU1cgY29udHJvbCB0aWxsIEhXIHdhcyBidXN5IGFuZCBy
ZXN0YXJ0IHRoZQ0KPj4+Pj4+PiBlbmRwb2ludCBpZg0KPj4+IG5lZWRlZC4NCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiArICogQ29tcGxldGUgcmVxdWVzdCB3aXRoIC1FSU8uDQo+Pj4+DQo+
Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKyAqIElmIEVQIElTT0MgT1VUIHRoZW4gbmVlZCB0byBmbHVz
aCBSWCBGSUZPIHRvIHJlbW92ZSBzb3VyY2Ugb2YNCj4+Pj4+Pj4gKyBCTkENCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiArICogaW50ZXJydXB0LiBSZXNldCB0YXJnZXQgZnJhbWUgYW5kIG5l
eHRfZGVzYyB0byBhbGxvdyB0byBzdGFydA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsg
KiBJU09DJ3Mgb24gTkFLIGludGVycnVwdCBmb3IgSU4gZGlyZWN0aW9uIG9yIG9uIE9VVFRLTkVQ
RElTDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKyAqIGludGVycnVwdCBmb3IgT1VUIGRp
cmVjdGlvbi4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAgICAgKi8NCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAtc3RhdGljIHZvaWQgZHdjMl9nYWRnZXRfc3RhcnRfbmV4dF9pc29j
X2RkbWEoc3RydWN0DQo+Pj4+Pj4+IGR3YzJfaHNvdGdfZXANCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+PiAqaHNfZXApDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gK3N0YXRpYyB2b2lk
IGR3YzJfZ2FkZ2V0X2hhbmRsZV9pc29jX2JuYShzdHJ1Y3QgZHdjMl9oc290Z19lcA0KPj4+ICpo
c19lcCkNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiB7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4gCXN0cnVjdCBkd2MyX2hzb3RnICpoc290ZyA9IGhzX2VwLT5wYXJlbnQ7DQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQl1MzIgZGVwY3RsOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+IC0JdTMyIGRtYV9yZWc7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQl1
MzIgY3RybDsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCXUzMiBkbWFfYWRkciA9IGhz
X2VwLT5kZXNjX2xpc3RfZG1hOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JdW5zaWdu
ZWQgY2hhciBpbmRleCA9IGhzX2VwLT5pbmRleDsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiAtDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQlkbWFfcmVnID0gaHNfZXAtPmRpcl9p
biA/IERJRVBETUEoaW5kZXgpIDogRE9FUERNQShpbmRleCk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4N
Cj4+Pj4+Pj4gLQlkZXBjdGwgPSBoc19lcC0+ZGlyX2luID8gRElFUENUTChpbmRleCkgOiBET0VQ
Q1RMKGluZGV4KTsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+
Pj4+DQo+Pj4+Pj4+IC0JY3RybCA9IGR3YzJfcmVhZGwoaHNvdGctPnJlZ3MgKyBkZXBjdGwpOw0K
Pj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJaWYgKCFoc19lcC0+ZGlyX2luKQ0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCWR3YzJfZmx1c2hfcnhfZmlmbyhoc290Zyk7DQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwlkd2MyX2hzb3RnX2NvbXBsZXRlX3JlcXVlc3QoaHNv
dGcsIGhzX2VwLCBnZXRfZXBfaGVhZChoc19lcCksDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gKwkJCQkgICAgLUVJTyk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCS8qDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkg
KiBFUCB3YXMgZGlzYWJsZWQgaWYgSFcgaGFzIHByb2Nlc3NlZCBsYXN0IGRlc2NyaXB0b3Igb3Ig
Qk5BIHdhcw0KPj4+IHNldC4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCSAqIFNvIHJl
c3RhcnQgZXAgaWYgU1cgaGFzIHByZXBhcmVkIG5ldyBkZXNjcmlwdG9yIGNoYWluIGluIGVwX3F1
ZXVlDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkgKiByb3V0aW5lIHdoaWxlIEhXIHdh
cyBidXN5Lg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JICovDQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gLQlpZiAoIShjdHJsICYgRFhFUENUTF9FUEVOQSkpIHsNCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQlpZiAoIWhzX2VwLT5uZXh0X2Rlc2MpIHsNCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQkJZGV2X2RiZyhoc290Zy0+ZGV2LCAiJXM6IE5vIG1vcmUg
SVNPQyByZXF1ZXN0c1xuIiwNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQkJCV9fZnVu
Y19fKTsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQkJcmV0dXJuOw0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JCX0NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtDQo+
Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkJZG1hX2FkZHIgKz0gc2l6ZW9mKHN0cnVjdCBk
d2MyX2RtYV9kZXNjKSAqDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkJCSAgICAoTUFY
X0RNQV9ERVNDX05VTV9HRU5FUklDIC8gMikgKg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
IC0JCQkgICAgaHNfZXAtPmlzb2NfY2hhaW5fbnVtOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+IC0JCWR3YzJfd3JpdGVsKGRtYV9hZGRyLCBoc290Zy0+cmVncyArIGRtYV9yZWcpOw0KPj4+
Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAt
CQljdHJsIHw9IERYRVBDVExfRVBFTkEgfCBEWEVQQ1RMX0NOQUs7DQo+Pj4+DQo+Pj4+Pj4NCj4+
Pj4NCj4+Pj4+Pj4gLQkJZHdjMl93cml0ZWwoY3RybCwgaHNvdGctPnJlZ3MgKyBkZXBjdGwpOw0K
Pj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
PiAtCQkvKiBTd2l0Y2ggSVNPQyBkZXNjcmlwdG9yIGNoYWluIG51bWJlciBiZWluZyBwcm9jZXNz
ZWQgYnkgU1cqLw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JCWhzX2VwLT5pc29jX2No
YWluX251bSA9IChoc19lcC0+aXNvY19jaGFpbl9udW0gXiAxKSAmIDB4MTsNCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAtCQloc19lcC0+bmV4dF9kZXNjID0gMDsNCj4+Pj4NCj4+Pj4+Pg0K
Pj4+Pg0KPj4+Pj4+PiAtDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkJZGV2X2RiZyho
c290Zy0+ZGV2LCAiJXM6IFJlc3RhcnRlZCBpc29jaHJvbm91cyBlbmRwb2ludFxuIiwNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQkJX19mdW5jX18pOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+IC0JfQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJaHNfZXAtPnRhcmdl
dF9mcmFtZSA9IFRBUkdFVF9GUkFNRV9JTklUSUFMOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+ICsJaHNfZXAtPm5leHRfZGVzYyA9IDA7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
fQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gLyoqDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gQEAgLTI4MTYsMTggKzI3OTcsMjUg
QEAgc3RhdGljIHZvaWQNCj5kd2MyX2dhZGdldF9oYW5kbGVfbmFrKHN0cnVjdA0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pj4+IGR3YzJfaHNvdGdfZXAgKmhzX2VwKSAgew0KPj4+Pg0KPj4+Pj4+
DQo+Pj4+DQo+Pj4+Pj4+IAlzdHJ1Y3QgZHdjMl9oc290ZyAqaHNvdGcgPSBoc19lcC0+cGFyZW50
Ow0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAlpbnQgZGlyX2luID0gaHNfZXAtPmRpcl9p
bjsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCXUzMiB0bXA7DQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJaWYgKCFkaXJfaW4g
fHwgIWhzX2VwLT5pc29jaHJvbm91cykNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJCXJl
dHVybjsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4+IAlpZiAoaHNfZXAtPnRhcmdldF9mcmFtZSA9PSBUQVJHRVRfRlJBTUVfSU5JVElBTCkg
ew0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JCWhzX2VwLT50YXJnZXRfZnJhbWUgPSBk
d2MyX2hzb3RnX3JlYWRfZnJhbWVubyhoc290Zyk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCQl0bXAgPSBkd2MyX2hzb3RnX3JlYWRf
ZnJhbWVubyhoc290Zyk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+
DQo+Pj4+DQo+Pj4+Pj4gSSB0aGluayB0aGVyZSBpcyBubyBuZWVkIHRvIGludHJvZHVjZSB0bXAs
IGFuZCB0aGUgb3JpZ2luYWwgaXMgYWxsIHJpZ2h0Lg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
PiBObywgdG1wIHJlcXVpcmVkLiBSZWFkaW5nIGN1cnJlbnQgZnJhbWUgbnVtYmVyIHNob3VsZCBi
ZSBkb25lIGFzDQo+Pj4+PiBzb29uIGFzDQo+Pj4+DQo+Pj4+PiBwb3NzaWJsZS4gVGhpcyBpcyB3
aHkgaXQncyBzdG9yZWQgaW4gdG1wIGFuZCB0aGVuIHVzZWQgZm9yIGJlbG93IGNhc2VzOg0KPj4+
Pg0KPj4+Pj4gMS4gRERNQSBtb2RlLiBPbiBkd2MyX2hzb3RnX2NvbXBsZXRlX3JlcXVlc3QoKSBm
dW5jdGlvbiBkcml2ZXINCj4+Pj4NCj4+Pj4+IGltbWVkaWF0bHkgcXVldWVkIG5ldyByZXF1ZXN0
IGFuZCBhcyByZXN1bHQgdGFyZ2V0X2ZyYW1lDQo+Pj4+PiBpbmNyZW1lbnRlZCBieQ0KPj4+Pg0K
Pj4+Pj4gaW50ZXJ2YWwuDQo+Pj4+DQo+Pj4+PiAyLiBCRE1BIG1vZGUuIHRtcCByZXF1aXJlZCBp
ZiBpbnRlcnZhbCA+IDEuDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4NCj4+Pj4NCj4+Pj4gU28g
Zm9yIGJvdGggRERNQSBvciBCRE1BIG1vZGUsIGhzX2VwLT50YXJnZXRfZnJhbWUgc2hvdWxkIGJl
IHVwZGF0ZWQNCj4+PiB0aGUNCj4+Pj4NCj4+Pj4gQ3VycmVudCBmcmFtZSBudW1iZXIgaW4gSFcu
DQo+Pj4+DQo+Pj4+IFRoZSBvcmlnaW5hbCBjb2RlIGNhbiBjb3ZlciBib3RoIGJyYW5jaCwgcmln
aHQ/DQo+Pj4+DQo+Pj4+DQo+Pj4gT3JpZ2luYWwgY29kZSBkb2Vzbid0IGluY3JlbWVudCBoZXJl
IHRhcmdldCBmcmFtZSBudW1iZXIgKHBlcmZvcm1pbmcNCj4+PiBpbg0KPj4+IGZpbGxfaXNvYykg
dG8gc3RhcnQgdHJhbnNmZXJzIGZyb20gbmV4dCBpbnRlcnZhbCBhbmQgZG9lc24ndCBjb21wbGV0
ZQ0KPj4+IHJlcXVlc3QuDQo+Pj4NCj4+DQo+PiBNYXliZSB5b3UgaGF2ZSBtaXN1bmRlcnN0b29k
IG1lLCBJIG1lYW4gdGhlcmUgaXMgbm8gbmVlZCB0byBhZGQgdGhlIHRtcA0KPnZhcmlhYmxlLg0K
Pj4gRGlyZWN0bHkgdXBkYXRlIHRoZSBoc19lcC0+dGFyZ2V0X2ZyYW1lIHVzaW5nICJoc19lcC0+
dGFyZ2V0X2ZyYW1lID0NCj4+IGR3YzJfaHNvdGdfcmVhZF9mcmFtZW5vKGhzb3RnKTsgIiBpbnN0
ZWFkIG9mICJoc19lcC0+dGFyZ2V0X2ZyYW1lID0NCj4+IHRtcCINCj4+IEluIGJvdGggYnJhbmNo
ZXMuDQo+Pg0KPg0KPk5vLCBpZiB0YXJnZXQgZnJhbWUgbnVtYmVyIHdpbGwgYmUgc3RvcmVkIGJ5
ICJoc19lcC0+dGFyZ2V0X2ZyYW1lID0NCj5kd2MyX2hzb3RnX3JlYWRfZnJhbWVubyhoc290Zyk7
IiB0aGVuIGFmdGVyIGNhbGxpbmcNCj5kd2MyX2hzb3RnX2NvbXBsZXRlX3JlcXVlc3QoKSwgZnVu
Y3Rpb24gZHJpdmVyIGNhbiBlbnF1ZXVlIG5ldyByZXF1ZXN0DQo+d2hpY2ggaW5jcmVtZW50cyB0
YXJnZXRfZnJhbWUgYnkgb25lIG1vcmUgYWRkaXRpb25hbCBpbnRlcnZhbC4gVGhpcyBpcyB3aHkN
Cj4iaHNfZXAtPnRhcmdldF9mcmFtZSA9IHRtcCIgcGVyZm9ybWluZyBhZnRlciBjYWxsaW5nIGNv
bXBsZXRlIHJlcXVlc3QuDQo+DQoNClRoZW4gSSBnb3QgaXQgLHRoYW5rIHlvdSwgSXQgJ3MgYSBi
aXQgZGlmZmljdWx0IHRvIHVuZGVyc3RhbmQuIEJ1dCB0aGUgZnVuY3Rpb24gZHJpdmVyDQptYXli
ZSBxdWV1ZSBtb3JlIHRoYW4gb25lIHJlcXVlc3QgaW4gdGhlIGNvbXBsZXRlIGNhbGxiYWNrLCBh
bmQgdGFyZ2V0X2ZyYW1lDQp3aWxsIGluY3JlYXNlIG1vcmUgdGhlIG9uZSBpbnRlcnZhbD8gDQoN
Cg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAkJaWYgKHVzaW5nX2Rlc2NfZG1hKGhzb3Rn
KSkgew0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCQlkd2MyX2hzb3RnX2NvbXBsZXRl
X3JlcXVlc3QoaHNvdGcsIGhzX2VwLA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCQkJ
CQkgICAgZ2V0X2VwX2hlYWQoaHNfZXApLA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJ
CQkJCQkgICAgLUVOT0RBVEEpOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCQloc19l
cC0+dGFyZ2V0X2ZyYW1lID0gdG1wOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCQlk
d2MyX2dhZGdldF9pbmNyX2ZyYW1lX251bShoc19lcCk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+
Pj4+Pj4gCQkJZHdjMl9nYWRnZXRfc3RhcnRfaXNvY19kZG1hKGhzX2VwKTsNCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAJCQlyZXR1cm47DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
CQl9DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiArCQloc19lcC0+dGFyZ2V0X2ZyYW1lID0gdG1wOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4+IAkJaWYgKGhzX2VwLT5pbnRlcnZhbCA+IDEpIHsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+PiAJCQl1MzIgY3RybCA9IGR3YzJfcmVhZGwoaHNvdGctPnJlZ3MgKw0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAkJCQkJICAgICAgRElFUENUTChoc19lcC0+aW5kZXgpKTsNCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBAQCAtMjg0Myw3ICsyODMxLDggQEAgc3RhdGljIHZv
aWQgZHdjMl9nYWRnZXRfaGFuZGxlX25hayhzdHJ1Y3QNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+
Pj4+PiBkd2MyX2hzb3RnX2VwICpoc19lcCkNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJ
CQkJCSAgICBnZXRfZXBfaGVhZChoc19lcCksIDApOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+IAl9DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+PiAtCWR3YzJfZ2FkZ2V0X2luY3JfZnJhbWVfbnVtKGhzX2VwKTsNCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiArCWlmICghdXNpbmdfZGVzY19kbWEoaHNvdGcpKQ0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCWR3YzJfZ2FkZ2V0X2luY3JfZnJhbWVfbnVtKGhzX2VwKTsN
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiB9DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAvKioNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+PiBAQCAtMjkwMSw5ICsyODkwLDkgQEAgc3RhdGljIHZvaWQgZHdjMl9oc290Z19lcGlu
dChzdHJ1Y3QNCj4+PiBkd2MyX2hzb3RnDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKmhz
b3RnLCB1bnNpZ25lZCBpbnQgaWR4LA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCQkvKiBJbiBERE1BIGhhbmRsZSBpc29jaHJvbm91cyBy
ZXF1ZXN0cyBzZXBhcmF0ZWx5ICovDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCQlpZiAo
dXNpbmdfZGVzY19kbWEoaHNvdGcpICYmIGhzX2VwLT5pc29jaHJvbm91cykgew0KPj4+Pg0KPj4+
Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JCQlkd2MyX2dhZGdldF9jb21wbGV0ZV9pc29jX3JlcXVlc3Rf
ZGRtYShoc19lcCk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkJCS8qIFRyeSB0byBz
dGFydCBuZXh0IGlzb2MgcmVxdWVzdCAqLw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0J
CQlkd2MyX2dhZGdldF9zdGFydF9uZXh0X2lzb2NfZGRtYShoc19lcCk7DQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gKwkJCS8qIFhmZXJDb21wbCBzZXQgYWxvbmcgd2l0aCBCTkEgKi8NCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCQkJaWYgKCEoaW50cyAmIERYRVBJTlRfQk5BSU5U
UikpDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwkJCQlkd2MyX2dhZGdldF9jb21wbGV0
ZV9pc29jX3JlcXVlc3RfZGRtYShoc19lcCk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
CQl9IGVsc2UgaWYgKGRpcl9pbikgew0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAkJCS8q
DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCQkJICogV2UgZ2V0IE91dERvbmUgZnJvbSB0
aGUgRklGTywgc28gd2Ugb25seSBAQCAtMjk3OCwxNQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+
Pj4+ICsyOTY3LDggQEAgc3RhdGljIHZvaWQgZHdjMl9oc290Z19lcGludChzdHJ1Y3QgZHdjMl9o
c290ZyAqaHNvdGcsDQo+Pj4+DQo+Pj4+PiB1bnNpZ25lZA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4+IGludCBpZHgsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAJaWYgKGludHMgJiBEWEVQSU5UX0JOQUlOVFIpIHsNCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJCWRldl9kYmcoaHNvdGctPmRldiwgIiVzOiBCTkEgaW50ZXJy
dXB0XG4iLCBfX2Z1bmNfXyk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQ0KPj4+Pg0K
Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JCS8qDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
LQkJICogVHJ5IHRvIHN0YXJ0IG5leHQgaXNvYyByZXF1ZXN0LCBpZiBhbnkuDQo+Pj4+DQo+Pj4+
Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQkJICogU29tZXRpbWVzIHRoZSBlbmRwb2ludCByZW1haW5zIGVu
YWJsZWQgYWZ0ZXIgQk5BIGludGVycnVwdA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0J
CSAqIGFzc2VydGlvbiwgd2hpY2ggaXMgbm90IGV4cGVjdGVkLCBoZW5jZSB3ZSBjYW4gZW50ZXIg
aGVyZQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IC0JCSAqIGNvdXBsZSBvZiB0aW1lcy4N
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQkgKi8NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0K
Pj4+Pj4+PiAJCWlmIChoc19lcC0+aXNvY2hyb25vdXMpDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+
Pj4+Pj4gLQkJCWR3YzJfZ2FkZ2V0X3N0YXJ0X25leHRfaXNvY19kZG1hKGhzX2VwKTsNCj4+Pj4N
Cj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCQkJZHdjMl9nYWRnZXRfaGFuZGxlX2lzb2NfYm5hKGhz
X2VwKTsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJfQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCWlmIChkaXJfaW4gJiYgIWhz
X2VwLT5pc29jaHJvbm91cykgew0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IEBAIC0zNzkx
LDYgKzM3NzMsNyBAQCBzdGF0aWMgaW50IGR3YzJfaHNvdGdfZXBfZW5hYmxlKHN0cnVjdA0KPnVz
Yl9lcA0KPj4+Pg0KPj4+Pj4gKmVwLA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAl1bnNp
Z25lZCBpbnQgZGlyX2luOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAl1bnNpZ25lZCBp
bnQgaSwgdmFsLCBzaXplOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAlpbnQgcmV0ID0g
MDsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCXVuc2lnbmVkIGNoYXIgZXBfdHlwZTsN
Cj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+
IAlkZXZfZGJnKGhzb3RnLT5kZXYsDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCQkiJXM6
IGVwICVzOiBhIDB4JTAyeCwgYXR0ciAweCUwMngsIG1wcyAweCUwNHgsIGludHIgJWRcbiIsDQo+
Pj4gQEANCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtMzgwOSw2ICszNzkyLDE1IEBAIHN0
YXRpYyBpbnQgZHdjMl9oc290Z19lcF9lbmFibGUoc3RydWN0IHVzYl9lcA0KPj4+ICplcCwNCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJCXJldHVybiAtRUlOVkFMOw0KPj4+Pg0KPj4+Pj4+
DQo+Pj4+DQo+Pj4+Pj4+IAl9DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4NCj4+Pj4NCj4+
Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCWVwX3R5cGUgPSBkZXNjLT5ibUF0dHJpYnV0ZXMgJiBVU0Jf
RU5EUE9JTlRfWEZFUlRZUEVfTUFTSzsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiArCS8q
IElTT0MgRERNQSBzdXBwb3J0ZWQgYkludGVydmFsIHVwIHRvIDEyICovDQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gKwlpZiAodXNpbmdfZGVzY19kbWEoaHNvdGcpICYmIGVwX3R5cGUgPT0N
Cj4+PiBVU0JfRU5EUE9JTlRfWEZFUl9JU09DICYmDQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+
Pj4gKwkgICAgZGlyX2luICYmIGRlc2MtPmJJbnRlcnZhbCA+IDEyKSB7DQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gKwkJZGV2X2Vycihoc290Zy0+ZGV2LA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+ICsJCQkiJXM6IElTT0MgSU46IGJJbnRlcnZhbD4xMiBub3Qgc3VwcG9ydGVkIVxu
IiwgX19mdW5jX18pOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJCXJldHVybiAtRUlO
VkFMOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+ICsJfQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+
DQo+Pj4+Pj4+ICsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJbXBzID0gdXNiX2VuZHBv
aW50X21heHAoZGVzYyk7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCW1jID0gdXNiX2Vu
ZHBvaW50X21heHBfbXVsdChkZXNjKTsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IEBAIC0zODUyLDE0ICszODQ0LDEzIEBAIHN0YXRpYyBp
bnQgZHdjMl9oc290Z19lcF9lbmFibGUoc3RydWN0DQo+Pj4gdXNiX2VwDQo+Pj4+DQo+Pj4+Pj4N
Cj4+Pj4NCj4+Pj4+Pj4gKmVwLA0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAloc19lcC0+
aGFsdGVkID0gMDsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJaHNfZXAtPmludGVydmFs
ID0gZGVzYy0+YkludGVydmFsOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+DQo+
Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gLQlzd2l0Y2ggKGRlc2MtPmJtQXR0cmlidXRlcyAmIFVTQl9F
TkRQT0lOVF9YRkVSVFlQRV9NQVNLKSB7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gKwlz
d2l0Y2ggKGVwX3R5cGUpIHsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJY2FzZSBVU0Jf
RU5EUE9JTlRfWEZFUl9JU09DOg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAkJZXBjdHJs
IHw9IERYRVBDVExfRVBUWVBFX0lTTzsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJCWVw
Y3RybCB8PSBEWEVQQ1RMX1NFVEVWRU5GUjsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAJ
CWhzX2VwLT5pc29jaHJvbm91cyA9IDE7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCQlo
c19lcC0+aW50ZXJ2YWwgPSAxIDw8IChkZXNjLT5iSW50ZXJ2YWwgLSAxKTsNCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAJCWhzX2VwLT50YXJnZXRfZnJhbWUgPSBUQVJHRVRfRlJBTUVfSU5J
VElBTDsNCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiAtCQloc19lcC0+aXNvY19jaGFpbl9u
dW0gPSAwOw0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IAkJaHNfZXAtPm5leHRfZGVzYyA9
IDA7DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCQlpZiAoZGlyX2luKSB7DQo+Pj4+DQo+
Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4gCQkJaHNfZXAtPnBlcmlvZGljID0gMTsNCj4+Pj4NCj4+Pj4+
Pg0KPj4+Pg0KPj4+Pj4+PiAtLQ0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IDIuMTEuMA0K
Pj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pj4g
LS0NCj4+Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+PiBUbyB1bnN1YnNjcmliZSBmcm9tIHRoaXMg
bGlzdDogc2VuZCB0aGUgbGluZSAidW5zdWJzY3JpYmUgbGludXgtdXNiIiBpbiB0aGUNCj4+PiBi
b2R5DQo+Pj4+DQo+Pj4+PiBvZg0KPj4+Pg0KPj4+Pj4+DQo+Pj4+DQo+Pj4+Pj4+IGEgbWVzc2Fn
ZSB0byBtYWpvcmRvbW9Admdlci5rZXJuZWwub3JnIE1vcmUgbWFqb3Jkb21vIGluZm8gYXQNCj4+
Pj4NCj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4+Pg0KPj4+Pg0KPj4+Pj4NCj4+Pg0KPmh0dHBzOi8vdXJs
ZGVmZW5zZS5wcm9vZnBvaW50LmNvbS92Mi91cmw/dT1odHRwLTNBX192Z2VyLmtlcm5lbC5vcmdf
bWFqb3Jkbw0KPj4+Pg0KPj4+Pj4NCj4+Pg0KPm1vLTJEaW5mby5odG1sJmQ9RHdJR2FRJmM9RFBM
Nl9YXzZKa1hGeDdBWFdxQjB0ZyZyPTZ6OUFsOUZySFJfWnFiDQo+Pj4+DQo+Pj4+Pg0KPj4+DQo+
YnRTQXNEMTZwdk9MMlMzWEh4UW5TenE4a3VzeUkmbT1hUFhYUm1GX0NXTGpILVVwSWVqT3NzMnFz
YVlWQU1PLQ0KPj4+Pg0KPj4+Pj4gb2VTb05kMWlUbWcmcz1SdHF1RkFWM3pjejk1NktLMUZpUFBX
QTQza0psOUluWktyYzNqV1FSNTlzJmU9DQo+Pj4+DQo+Pj4+Pj4NCj4+Pj4NCj4+Pj4+Pg0KPj4+
Pg0KPj4+Pj4NCj4+Pj4NCj4+Pj4+IFRoYW5rIHlvdSBmb3IgcmV2aWV3Lg0KPj4+Pg0KPj4+Pj4N
Cj4+Pj4NCj4+Pj4+IE1pbmFzDQo+Pj4+DQo+Pj4+PiAtLQ0KPj4+Pg0KPj4+Pj4gVG8gdW5zdWJz
Y3JpYmUgZnJvbSB0aGlzIGxpc3Q6IHNlbmQgdGhlIGxpbmUgInVuc3Vic2NyaWJlIGxpbnV4LXVz
YiIgaW4NCj4+Pj4NCj4+Pj4+IHRoZSBib2R5IG9mIGEgbWVzc2FnZSB0byBtYWpvcmRvbW9Admdl
ci5rZXJuZWwub3JnDQo+Pj4+DQo+Pj4+PiBNb3JlIG1ham9yZG9tbyBpbmZvIGF0DQo+Pj4NCj5o
dHRwczovL3VybGRlZmVuc2UucHJvb2Zwb2ludC5jb20vdjIvdXJsP3U9aHR0cC0zQV9fdmdlci5r
ZXJuZWwub3JnX21ham9yZG8NCj4+Pg0KPm1vLTJEaW5mby5odG1sJmQ9RHdJR2FRJmM9RFBMNl9Y
XzZKa1hGeDdBWFdxQjB0ZyZyPTZ6OUFsOUZySFJfWnFiDQo+Pj4NCj5idFNBc0QxNnB2T0wyUzNY
SHhRblN6cThrdXN5SSZtPVdmR1UxazRVQlJhcDVZN2pBMkxCNlE5SlY1YjhGWE5yDQo+Pj4NCj5t
Z2czWnZuVjdWNCZzPVp0RERFQWhiWFhRcUJibE9TZnd0RURNWFpxUlJDM182d0xnQ0pSRXIyRVEm
ZT0NCj4+Pj4NCj4+Pj4NCj4+PiBUaGFua3MsDQo+Pj4gTWluYXMNCj4NCg0K
---
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-22  8:06 Minas Harutyunyan
  0 siblings, 0 replies; 10+ messages in thread
From: Minas Harutyunyan @ 2018-03-22  8:06 UTC (permalink / raw)
  To: Zengtao (B),
	Minas Harutyunyan, John Youn, Felipe Balbi, Greg Kroah-Hartman,
	linux-usb

Hi Zengtao,

On 3/21/2018 2:45 PM, Zengtao (B) wrote:
> Hi Minas:
> 
>> -----Original Message-----
>> From: Minas Harutyunyan [mailto:Minas.Harutyunyan@synopsys.com]
>> Sent: Wednesday, March 21, 2018 4:08 PM
>> To: Zengtao (B) <prime.zeng@hisilicon.com>; Minas Harutyunyan
>> <Minas.Harutyunyan@synopsys.com>; John Youn <John.Youn@synopsys.com>;
>> Felipe Balbi <balbi@kernel.org>; Greg Kroah-Hartman
>> <gregkh@linuxfoundation.org>; linux-usb@vger.kernel.org
>> 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@vger.kernel.org
>>>
>>>> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas
>>>> Harutyunyan
>>>
>>>> Sent: Tuesday, March 20, 2018 10:40 PM
>>>
>>>> To: Zengtao (B) <prime.zeng@hisilicon.com>; Minas Harutyunyan
>>>
>>>> <Minas.Harutyunyan@synopsys.com>; John Youn
>> <John.Youn@synopsys.com>;
>>>
>>>> Felipe Balbi <balbi@kernel.org>; Greg Kroah-Hartman
>>>
>>>> <gregkh@linuxfoundation.org>; linux-usb@vger.kernel.org
>>>
>>>> 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@vger.kernel.org
>>>
>>>>>
>>>
>>>>>> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas
>>>
>>>>>> Harutyunyan
>>>
>>>>>
>>>
>>>>>> Sent: Saturday, March 17, 2018 5:10 PM
>>>
>>>>>
>>>
>>>>>> To: John Youn <John.Youn@synopsys.com>; Felipe Balbi
>>>
>>>>>> <balbi@kernel.org>;
>>>
>>>>>
>>>
>>>>>> Greg Kroah-Hartman <gregkh@linuxfoundation.org>;
>>>
>>>>>> linux-usb@vger.kernel.org
>>>
>>>>>
>>>
>>>>>> Cc: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
>>>
>>>>>
>>>
>>>>>> 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@synopsys.com>
>>>
>>>>>
>>>
>>>>>> ---
>>>
>>>>>
>>>
>>>>>> 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.

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.

>>>
>>>>>
>>>
>>>>>> 		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@vger.kernel.org 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@vger.kernel.org
>>>
>>>> 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
---
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-21 10:45 Zengtao (B)
  0 siblings, 0 replies; 10+ messages in thread
From: Zengtao (B) @ 2018-03-21 10:45 UTC (permalink / raw)
  To: Minas Harutyunyan, John Youn, Felipe Balbi, Greg Kroah-Hartman,
	linux-usb

SGkgTWluYXM6DQoNCj4tLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPkZyb206IE1pbmFzIEhh
cnV0eXVueWFuIFttYWlsdG86TWluYXMuSGFydXR5dW55YW5Ac3lub3BzeXMuY29tXQ0KPlNlbnQ6
IFdlZG5lc2RheSwgTWFyY2ggMjEsIDIwMTggNDowOCBQTQ0KPlRvOiBaZW5ndGFvIChCKSA8cHJp
bWUuemVuZ0BoaXNpbGljb24uY29tPjsgTWluYXMgSGFydXR5dW55YW4NCj48TWluYXMuSGFydXR5
dW55YW5Ac3lub3BzeXMuY29tPjsgSm9obiBZb3VuIDxKb2huLllvdW5Ac3lub3BzeXMuY29tPjsN
Cj5GZWxpcGUgQmFsYmkgPGJhbGJpQGtlcm5lbC5vcmc+OyBHcmVnIEtyb2FoLUhhcnRtYW4NCj48
Z3JlZ2toQGxpbnV4Zm91bmRhdGlvbi5vcmc+OyBsaW51eC11c2JAdmdlci5rZXJuZWwub3JnDQo+
U3ViamVjdDogUmU6IFtQQVRDSCB2MSAyLzNdIHVzYjogZHdjMjogQ2hhbmdlIElTT0MgRERNQSBm
bG93DQo+DQo+SGkgWmVuZ3RhbywNCj4NCj5PbiAzLzIxLzIwMTggNjoxNyBBTSwgWmVuZ3RhbyAo
Qikgd3JvdGU6DQo+Pj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4+DQo+Pj4gRnJvbTog
bGludXgtdXNiLW93bmVyQHZnZXIua2VybmVsLm9yZw0KPj4NCj4+PiBbbWFpbHRvOmxpbnV4LXVz
Yi1vd25lckB2Z2VyLmtlcm5lbC5vcmddIE9uIEJlaGFsZiBPZiBNaW5hcw0KPj4+IEhhcnV0eXVu
eWFuDQo+Pg0KPj4+IFNlbnQ6IFR1ZXNkYXksIE1hcmNoIDIwLCAyMDE4IDEwOjQwIFBNDQo+Pg0K
Pj4+IFRvOiBaZW5ndGFvIChCKSA8cHJpbWUuemVuZ0BoaXNpbGljb24uY29tPjsgTWluYXMgSGFy
dXR5dW55YW4NCj4+DQo+Pj4gPE1pbmFzLkhhcnV0eXVueWFuQHN5bm9wc3lzLmNvbT47IEpvaG4g
WW91bg0KPjxKb2huLllvdW5Ac3lub3BzeXMuY29tPjsNCj4+DQo+Pj4gRmVsaXBlIEJhbGJpIDxi
YWxiaUBrZXJuZWwub3JnPjsgR3JlZyBLcm9haC1IYXJ0bWFuDQo+Pg0KPj4+IDxncmVna2hAbGlu
dXhmb3VuZGF0aW9uLm9yZz47IGxpbnV4LXVzYkB2Z2VyLmtlcm5lbC5vcmcNCj4+DQo+Pj4gU3Vi
amVjdDogUmU6IFtQQVRDSCB2MSAyLzNdIHVzYjogZHdjMjogQ2hhbmdlIElTT0MgRERNQSBmbG93
DQo+Pg0KPj4+DQo+Pg0KPj4+IEhpIFplbmd0YW8sDQo+Pg0KPj4+DQo+Pg0KPj4+IE9uIDMvMjAv
MjAxOCA2OjAxIEFNLCBaZW5ndGFvIChCKSB3cm90ZToNCj4+DQo+Pj4+IEhpIE1pbmFzOg0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4gQSBmZXcgbWlub3IgY29tbWVudHM6
DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLS0tLS1PcmlnaW5hbCBN
ZXNzYWdlLS0tLS0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gRnJvbTogbGludXgtdXNiLW93bmVyQHZn
ZXIua2VybmVsLm9yZw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBbbWFpbHRvOmxpbnV4LXVzYi1vd25l
ckB2Z2VyLmtlcm5lbC5vcmddIE9uIEJlaGFsZiBPZiBNaW5hcw0KPj4NCj4+Pj4+IEhhcnV0eXVu
eWFuDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IFNlbnQ6IFNhdHVyZGF5LCBNYXJjaCAxNywgMjAxOCA1
OjEwIFBNDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IFRvOiBKb2huIFlvdW4gPEpvaG4uWW91bkBzeW5v
cHN5cy5jb20+OyBGZWxpcGUgQmFsYmkNCj4+DQo+Pj4+PiA8YmFsYmlAa2VybmVsLm9yZz47DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+IEdyZWcgS3JvYWgtSGFydG1hbiA8Z3JlZ2toQGxpbnV4Zm91bmRh
dGlvbi5vcmc+Ow0KPj4NCj4+Pj4+IGxpbnV4LXVzYkB2Z2VyLmtlcm5lbC5vcmcNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gQ2M6IE1pbmFzIEhhcnV0eXVueWFuIDxNaW5hcy5IYXJ1dHl1bnlhbkBzeW5v
cHN5cy5jb20+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IFN1YmplY3Q6IFtQQVRDSCB2MSAyLzNdIHVz
YjogZHdjMjogQ2hhbmdlIElTT0MgRERNQSBmbG93DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0K
Pj4+Pg0KPj4NCj4+Pj4+IENoYW5nZWQgZXhpc3RpbmcgdHdvIGRlc2NyaXB0b3ItY2hhaW4gZmxv
dyB0byBvbmUgY2hhaW4uDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+
IEluIHR3by1jaGFpbiBpbXBsZW1lbnRhdGlvbiBCTkEgaW50ZXJydXB0IHVzZWQgZm9yIHN3aXRj
aGluZw0KPj4+Pj4gYmV0d2Vlbg0KPj4NCj4+Pj4+IHR3bw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBj
aGFpbnMuIEJOQSBpbnRlcnJ1cHQgYXNzZXJ0ZWQgYmVjYXVzZSBvZiByZXR1cm5pbmcgdG8gYmVn
aW5uaW5nIG9mDQo+Pg0KPj4+Pj4gdGhlIGNoYWluDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IGJhc2Vk
IG9uIEwtYml0IG9mIGxhc3QgZGVzY3JpcHRvci4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gQmVjYXVzZSBvZiB0aGF0IHdlIGxvc2UgcGFja2V0cy4gVGhpcyBpc3N1
ZSByZXNvbHZlZCBieSB1c2luZyBvbmUNCj5kZXNjLWNoYWluLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+
Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBSZW1vdmVkIGFsbCBzdGFmZiByZWxhdGVkIHRvIHR3byBk
ZXNjLWNoYWluIGZsb3cgZnJvbSBERE1BIElTT0MNCj4+DQo+Pj4+PiByZWxhdGVkDQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+IGZ1bmN0aW9ucy4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gUmVtb3ZlZCByZXF1ZXN0IGxlbmd0aCBjaGVja2luZyBmcm9tIGR3YzJfZ2FkZ2V0
X2ZpbGxfaXNvY19kZXNjKCkNCj4+DQo+Pj4gZnVuY3Rpb24uDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+
IFJlcXVlc3QgbGVuZ3RoIGNoZWNraW5nIGFkZGVkIHRvIGR3YzJfaHNvdGdfZXBfcXVldWUoKSBm
dW5jdGlvbi4gSWYNCj4+DQo+Pj4+PiByZXF1ZXN0DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IGxlbmd0
aCBncmVhdGVyIHRoYW4gZGVzY3JpcHRvciBsaW1pdHMgdGhlbiByZXF1ZXN0IG5vdCBhZGRlZCB0
byBxdWV1ZS4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gQWRkaXRpb25hbCBjaGVja2luZyBkb25lIGZv
ciBIaWdoIEJhbmR3aWR0aCBJU09DIE9VVCdzIHdoaWNoIG5vdA0KPj4NCj4+Pj4+IHN1cHBvcnRl
ZCBieQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBkcml2ZXIuIEluDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+
IGR3YzJfZ2FkZ2V0X2ZpbGxfaXNvY19kZXNjKCkgZnVuY3Rpb24gYWxzbyBjaGVja2VkIGRlc2Mt
Y2hhaW4NCj4+Pj4+IHN0YXR1cw0KPj4NCj4+Pj4+IChmdWxsIG9yIG5vdCkNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gdG8gYXZvaWQgb2YgcmV1c2luZyBub3QgeWV0IHByb2Nlc3NlZCBkZXNjcmlwdG9y
cy4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gSW4gZHdjMl9nYWRn
ZXRfc3RhcnRfaXNvY19kZG1hKCkgZnVuY3Rpb24gY3JlYXRpb24gb2YgZGVzYy1jaGFpbg0KPj4N
Cj4+Pj4+IGFsd2F5cw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBzdGFydGVkIGZyb20gZGVzY3JpcHRv
ciAwLiBCZWZvcmUgZmlsbGluZyBkZXNjcmlwdG9ycywgdGhleSB3ZXJlDQo+Pg0KPj4+Pj4gaW5p
dGlhbGl6ZWQgYnkNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gSE9TVCBCVVNZIHN0YXR1cy4NCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gSW4gZHdjMl9nYWRnZXRfY29tcGxl
dGVfaXNvY19yZXF1ZXN0X2RkbWEoKSBhZGRlZCBjaGVja2luZyBmb3INCj4+DQo+Pj4+PiBkZXNj
LWNoYWluDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IHJvbGxvdmVyLiBBbHNvIGFkZGVkIGNoZWNraW5n
IGNvbXBsZXRpb24gc3RhdHVzLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBSZXF1ZXN0IGNvbXBsZXRl
ZCBzdWNjZXNzZnVsbHkgaWYgREVWX0RNQV9TVFMgaXMgREVWX0RNQV9TVFNfU1VDQywNCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gb3RoZXJ3aXNlIGNvbXBsZXRlIHdpdGggLUVUSU1FRE9VVC4NCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gQWN0dWFsbHkgcmVtb3ZlZCBkd2My
X2dhZGdldF9zdGFydF9uZXh0X2lzb2NfZGRtYSgpIGZ1bmN0aW9uDQo+Pj4+PiBiZWNhdXNlDQo+
Pg0KPj4+Pj4gbm93DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IGRyaXZlciB1c2Ugb25seSBvbmUgZGVz
Yy1jaGFpbiBhbmQgaW5zdGVhZCB0aGF0IGZ1bmN0aW9uIGFkZGVkDQo+Pg0KPj4+Pg0KPj4NCj4+
Pj4+IGR3YzJfZ2FkZ2V0X2hhbmRsZV9pc29jX2JuYSgpIGZ1bmN0aW9uIGZvciBoYW5kbGluZyBC
TkEgaW50ZXJydXB0cy4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
SGFuZGxpbmcgQk5BIGludGVycnVwdCBkb25lIGJ5IGZsdXNoaW5nIFR4RklGT3MgZm9yIE9VVCBF
UHMsDQo+Pg0KPj4+Pj4gY29tcGxldGluZw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiByZXF1ZXN0IHdp
dGggLUVJTyBhbmQgcmVzZXR0aW5nIGRlc2MtY2hhaW4gbnVtYmVyIGFuZCB0YXJnZXQgZnJhbWUN
Cj4+Pj4+IHRvDQo+Pg0KPj4+Pj4gaW5pdGlhbA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiB2YWx1ZXMg
Zm9yIHJlc3RhcnRpbmcgdHJhbnNmZXJzLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiBPbiBoYW5kbGluZyBOQUsgcmVxdWVzdCBjb21wbGV0ZWQgd2l0aCAtRU5PREFU
QS4gSW5jcmVtZW50ZWQgdGFyZ2V0DQo+Pg0KPj4+Pj4gZnJhbWUNCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gdG8gYWxsb3cgZmlsbCBkZXNjIGNoYWluIGFuZCBzdGFydCB0cmFuc2ZlcnMuDQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+IEluIERETUEgbW9kZSBhdm9pZGVkIG9mIGZyYW1lIG51bWJlciBpbmNyZW1l
bnRpbmcsIGJlY2F1c2UgdHJhY2tpbmcNCj4+DQo+Pj4+PiBvZg0KPj4NCj4+Pj4NCj4+DQo+Pj4+
PiBmcmFtZSBudW1iZXIgcGVyZm9ybWVkIGluIGR3YzJfZ2FkZ2V0X2ZpbGxfaXNvY19kZXNjKCkg
ZnVuY3Rpb24uDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IFdoZW4g
Y29yZSBhc3NlcnQgWGZlckNvbXBsIGFsb25nIHdpdGggQk5BLCB3ZSBzaG91bGQgaWdub3JlDQo+
Pj4+PiBYZmVyQ29tcGwNCj4+DQo+Pj4+PiBpbg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBkd2MyX2hz
b3RnX2VwaW50KCkgZnVuY3Rpb24uDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+IE9uIEJOQSBpbnRlcnJ1cHQgcmVwbGFjZWQgZHdjMl9nYWRnZXRfc3RhcnRfbmV4dF9p
c29jX2RkbWEoKSBieQ0KPj4+Pj4gYWJvdmUNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gbWVudGlvbmVk
IEJOQSBoYW5kbGVyLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBJ
biBkd2MyX2hzb3RnX2VwX2VuYWJsZSgpIGZ1bmN0aW9uIGFkZGVkIHNhbml0eSBjaGVjayBvZiBi
SW50ZXJ2YWwNCj4+DQo+Pj4+PiBmb3IgSVNPQyBJTg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBpbiBE
RE1BIG1vZGUsIGJlY2F1c2UgSFcgbm90IHN1cHBvcnRlZCBFUCdzIHdpdGggYkludGVydmFsIG1v
cmUgdGhhbg0KPjEyLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBT
aWduZWQtb2ZmLWJ5OiBNaW5hcyBIYXJ1dHl1bnlhbiA8aG1pbmFzQHN5bm9wc3lzLmNvbT4NCj4+
DQo+Pj4+DQo+Pg0KPj4+Pj4gLS0tDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IGRyaXZlcnMvdXNiL2R3
YzIvY29yZS5oICAgfCAgIDIgLQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBkcml2ZXJzL3VzYi9kd2My
L2dhZGdldC5jIHwgMjM1DQo+Pg0KPj4+Pj4gKysrKysrKysrKysrKysrKysrKysrKy0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAyIGZpbGVzIGNoYW5nZWQsIDEx
MyBpbnNlcnRpb25zKCspLCAxMjQgZGVsZXRpb25zKC0pDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3VzYi9kd2MyL2NvcmUuaCBi
L2RyaXZlcnMvdXNiL2R3YzIvY29yZS5oDQo+Pj4+PiBpbmRleA0KPj4NCj4+Pj4NCj4+DQo+Pj4+
PiBkODNiZTU2NTFmODcuLjA5M2QwNzhhZGFmNCAxMDA2NDQNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
LS0tIGEvZHJpdmVycy91c2IvZHdjMi9jb3JlLmgNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKysrIGIv
ZHJpdmVycy91c2IvZHdjMi9jb3JlLmgNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gQEAgLTE3OCw3ICsx
NzgsNiBAQCBzdHJ1Y3QgZHdjMl9oc290Z19yZXE7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICAgICog
QGRlc2NfbGlzdF9kbWE6IFRoZSBETUEgYWRkcmVzcyBvZiBkZXNjcmlwdG9yIGNoYWluIGN1cnJl
bnRseSBpbg0KPnVzZS4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gICAgKiBAZGVzY19saXN0OiBQb2lu
dGVyIHRvIGRlc2NyaXB0b3IgRE1BIGNoYWluIGhlYWQgY3VycmVudGx5IGluIHVzZS4NCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gICAgKiBAZGVzY19jb3VudDogQ291bnQgb2YgZW50cmllcyB3aXRoaW4g
dGhlIERNQSBkZXNjcmlwdG9yIGNoYWluIG9mDQo+RVAuDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0g
KiBAaXNvY19jaGFpbl9udW06IE51bWJlciBvZiBJU09DIGNoYWluIGN1cnJlbnRseSBpbiB1c2Ug
LSBlaXRoZXIgMCBvciAxLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAgICAqIEBuZXh0X2Rlc2M6IGlu
ZGV4IG9mIG5leHQgZnJlZSBkZXNjcmlwdG9yIGluIHRoZSBJU09DIGNoYWluDQo+Pj4+PiB1bmRl
cg0KPj4NCj4+Pj4+IFNXDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IGNvbnRyb2wuDQo+Pg0KPj4+Pg0K
Pj4NCj4+Pj4+ICAgICogQHRvdGFsX2RhdGE6IFRoZSB0b3RhbCBudW1iZXIgb2YgZGF0YSBieXRl
cyBkb25lLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAgICAqIEBmaWZvX3NpemU6IFRoZSBzaXplIG9m
IHRoZSBGSUZPIChmb3IgcGVyaW9kaWMgSU4gZW5kcG9pbnRzKQ0KPj4+Pj4gQEANCj4+DQo+Pj4+
PiAtMjMxLDcNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKzIzMCw2IEBAIHN0cnVjdCBkd2MyX2hzb3Rn
X2VwIHsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCXN0cnVjdCBkd2MyX2RtYV9kZXNjCSpkZXNjX2xp
c3Q7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAl1OAkJCWRlc2NfY291bnQ7DQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JdW5zaWduZWQgY2hhcgkJaXNvY19jaGFpbl9u
dW07DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAl1bnNpZ25lZCBpbnQJCW5leHRfZGVzYzsNCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCWNoYXIgICAgICAgICAgICAgICAg
ICAgIG5hbWVbMTBdOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBkaWZmIC0tZ2l0IGEvZHJpdmVycy91
c2IvZHdjMi9nYWRnZXQuYyBiL2RyaXZlcnMvdXNiL2R3YzIvZ2FkZ2V0LmMNCj4+DQo+Pj4+PiBp
bmRleA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBjMjMxMzIxNjU2ZjkuLjFiOWM4NGNiNThmYiAxMDA2
NDQNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLS0tIGEvZHJpdmVycy91c2IvZHdjMi9nYWRnZXQuYw0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiArKysgYi9kcml2ZXJzL3VzYi9kd2MyL2dhZGdldC5jDQo+Pg0K
Pj4+Pg0KPj4NCj4+Pj4+IEBAIC03OTMsOSArNzkzLDcgQEAgc3RhdGljIHZvaWQNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gZHdjMl9nYWRnZXRfY29uZmlnX25vbmlzb2NfeGZlcl9kZG1hKHN0cnVjdCBk
d2MyX2hzb3RnX2VwICpoc19lcCwNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gICAgKiBAZG1hX2J1ZmY6
IHVzYiByZXF1ZXN0cyBkbWEgYnVmZmVyLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAgICAqIEBsZW46
IHVzYiByZXF1ZXN0IHRyYW5zZmVyIGxlbmd0aC4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gICAgKg0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiAtICogRmluZHMgb3V0IGluZGV4IG9mIGZpcnN0IGZyZWUgZW50
cnkgZWl0aGVyIGluIHRoZSBib3R0b20gb3IgdXANCj4+DQo+Pj4+PiBoYWxmIG9mDQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+IC0gKiBkZXNjcmlwdG9yIGNoYWluIGRlcGVuZCBvbiB3aGljaCBpcyB1bmRl
ciBTVyBjb250cm9sIGFuZCBub3QNCj4+DQo+Pj4+PiBwcm9jZXNzZWQNCj4+DQo+Pj4+DQo+Pg0K
Pj4+Pj4gLSAqIGJ5IEhXLiBUaGVuIGZpbGxzIHRoYXQgZGVzY3JpcHRvciB3aXRoIHRoZSBkYXRh
IG9mIHRoZSBhcnJpdmVkDQo+Pg0KPj4+Pj4gdXNiIHJlcXVlc3QsDQo+Pg0KPj4+Pg0KPj4NCj4+
Pj4+ICsgKiBGaWxscyBuZXh0IGZyZWUgZGVzY3JpcHRvciB3aXRoIHRoZSBkYXRhIG9mIHRoZSBh
cnJpdmVkIHVzYg0KPj4NCj4+Pj4+ICsgcmVxdWVzdCwNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gICAg
KiBmcmFtZSBpbmZvLCBzZXRzIExhc3QgYW5kIElPQyBiaXRzIGluY3JlbWVudHMgbmV4dF9kZXNj
LiBJZg0KPj4NCj4+Pj4+IGZpbGxlZA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAgICAqIGRlc2NyaXB0
b3IgaXMgbm90IHRoZSBmaXJzdCBvbmUsIHJlbW92ZXMgTCBiaXQgZnJvbSB0aGUNCj4+Pj4+IHBy
ZXZpb3VzDQo+Pg0KPj4+Pj4gZGVzY3JpcHRvcg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAgICAqIHN0
YXR1cy4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gQEAgLTgxMCwzNCArODA4LDE3IEBAIHN0YXRpYyBp
bnQgZHdjMl9nYWRnZXRfZmlsbF9pc29jX2Rlc2Moc3RydWN0DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+
IGR3YzJfaHNvdGdfZXAgKmhzX2VwLA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJdTMyIG1hc2sgPSAw
Ow0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJbWF4c2l6ZSA9IGR3
YzJfZ2FkZ2V0X2dldF9kZXNjX3BhcmFtcyhoc19lcCwgJm1hc2spOw0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiAtCWlmIChsZW4gPiBtYXhzaXplKSB7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JCWRldl9l
cnIoaHNvdGctPmRldiwgIndyb25nIGxlbiAlZFxuIiwgbGVuKTsNCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gLQkJcmV0dXJuIC1FSU5WQUw7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JfQ0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiAtDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JLyoNCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gLQkgKiBJZiBTVyBoYXMgYWxyZWFkeSBmaWxsZWQgaGFsZiBvZiBjaGFpbiwgdGhlbiByZXR1
cm4gYW5kIHdhaXQgZm9yDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JICogdGhlIG90aGVyIGNoYWlu
IHRvIGJlIHByb2Nlc3NlZCBieSBIVy4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkgKi8NCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gLQlpZiAoaHNfZXAtPm5leHRfZGVzYyA9PSBNQVhfRE1BX0RFU0NfTlVN
X0dFTkVSSUMgLyAyKQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQlyZXR1cm4gLUVCVVNZOw0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCS8qIEluY3JlbWVudCBmcmFt
ZSBudW1iZXIgYnkgaW50ZXJ2YWwgZm9yIElOICovDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JaWYg
KGhzX2VwLT5kaXJfaW4pDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JCWR3YzJfZ2FkZ2V0X2luY3Jf
ZnJhbWVfbnVtKGhzX2VwKTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQ0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiAtCWluZGV4ID0gKE1BWF9ETUFfREVTQ19OVU1fR0VORVJJQyAvIDIpICoNCj5oc19lcC0+
aXNvY19jaGFpbl9udW0gKw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQkgaHNfZXAtPm5leHRfZGVz
YzsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwlpbmRleCA9IGhzX2VwLT5uZXh0X2Rlc2M7DQo+Pg0K
Pj4+Pg0KPj4NCj4+Pj4+ICsJZGVzYyA9ICZoc19lcC0+ZGVzY19saXN0W2luZGV4XTsNCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkvKiBTYW5pdHkgY2hlY2sgb2Yg
Y2FsY3VsYXRlZCBpbmRleCAqLw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCWlmICgoaHNfZXAtPmlz
b2NfY2hhaW5fbnVtICYmIGluZGV4ID4NCj5NQVhfRE1BX0RFU0NfTlVNX0dFTkVSSUMpDQo+Pg0K
Pj4+Pg0KPj4NCj4+Pj4+IHx8DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JICAgICghaHNfZXAtPmlz
b2NfY2hhaW5fbnVtICYmIGluZGV4ID4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gTUFYX0RNQV9ERVND
X05VTV9HRU5FUklDIC8gMikpIHsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkJZGV2X2Vycihoc290
Zy0+ZGV2LCAid3JvbmcgaW5kZXggJWQgZm9yIGlzbyBjaGFpblxuIiwgaW5kZXgpOw0KPj4NCj4+
Pj4NCj4+DQo+Pj4+PiAtCQlyZXR1cm4gLUVJTlZBTDsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwkv
KiBDaGVjayBpZiBkZXNjcmlwdG9yIGNoYWluIGZ1bGwgKi8NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
KwlpZiAoKGRlc2MtPnN0YXR1cyA+PiBERVZfRE1BX0JVRkZfU1RTX1NISUZUKSA9PQ0KPj4NCj4+
Pj4NCj4+DQo+Pj4+PiArCSAgICBERVZfRE1BX0JVRkZfU1RTX0hSRUFEWSkgew0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiArCQlkZXZfZGJnKGhzb3RnLT5kZXYsICIlczogZGVzYyBjaGFpbiBmdWxsXG4i
LCBfX2Z1bmNfXyk7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJCXJldHVybiAxOw0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiAJfQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAt
CWRlc2MgPSAmaHNfZXAtPmRlc2NfbGlzdFtpbmRleF07DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0N
Cj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCS8qIENsZWFyIEwgYml0IG9mIHByZXZpb3VzIGRlc2MgaWYg
bW9yZSB0aGFuIG9uZSBlbnRyaWVzIGluIHRoZQ0KPj4NCj4+Pj4+IGNoYWluICovDQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+IAlpZiAoaHNfZXAtPm5leHRfZGVzYykNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
CQloc19lcC0+ZGVzY19saXN0W2luZGV4IC0gMV0uc3RhdHVzICY9IH5ERVZfRE1BX0w7IEBAIC04
NjUsOA0KPj4NCj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4gV2hlbiBjaGFuZ2lu
ZyB0aGUgc3RhdHVzIG9mIHRoZSBkZXNjLCBIb3cgdG8gc3luYyB0aGUgU1cgd2l0aCB0aGUgSFc/
DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4gU2luY2UgdGhlIEhXIGFuZCBTVyBpcyB3b3JraW5nIG9uIHRo
ZSBzYW1lIGRlc2Mgc3luY2hyb25vdXNseS4NCj4+DQo+Pj4NCj4+DQo+Pj4gTm90IGNsZWFyIGZv
ciB3aGF0IHlvdSBtZWFuOiBIVyBhbmQgU1cgd29ya2luZyBvbiBzYW1lIGRlc2MNCj5zeW5jaHJv
bm91c2x5Pw0KPj4NCj4+PiBEZXNjcmlwdG9yIGxpc3QgaXMgbGlrZSBQcm9kdWNlcihTVykvQ29u
c3VtZXIoSFcpIGxpc3QuDQo+Pg0KPj4+IEluZGV4IG1hbmFnZW1lbnQgYWxsb3cgYWx3YXlzIGtl
ZXAgZ2FwIGJldHdlZW4gUHJvZHVjZXIgYW5kIENvbnN1bWVyDQo+Pg0KPj4+IGluZGV4ZXMuIFBy
b2R1Y2VyIGluZGV4IHNob3VsZCBiZSBhbHdheXMgbW9yZSB0aGFuIENvbnN1bWVyIGluZGV4LiBJ
bg0KPj4+IHNvbWUNCj4+DQo+Pj4gY2FzZXMgd2hlbiBDb25zdW1lciBpbmRleCBhY2hpZXZlZCBQ
cm9kdWNlciBpbmRleCwgd2hpY2ggbWVhbiBubyBtb3JlDQo+Pg0KPj4+IHJlYWR5IGRlc2NyaXB0
b3IgdG8gcHJvY2VzcyB0aGVuIEJOQSBpbnRlcnJ1cHQgd2lsbCBiZSBhc3NlcnRlZCwgaS5lDQo+
Pj4gU1cgY2FuJ3QNCj4+DQo+Pj4gZW5vdWdoIGJhbmR3aWR0aCB0byBzdWJtaXQgbmV3IHJlcXVl
c3RzLg0KPj4NCj4+Pg0KPj4NCj4+DQo+Pg0KPj4gQWJvdXQgbXkgcXVlc3Rpb24sDQo+Pg0KPj4g
SSBtZWFuIHdoZW4geW91IGNsZWFyIHRoZSBERVZfRE1BX0wgYml0IG9mIGxhc3QgZGVzYyBpbiB0
aGUgY2hhaW4sIHRoZQ0KPj4gSFcgbWF5IGJlDQo+Pg0KPj4gYWNjZXNzaW5nIHRoaXMgcGFydGlj
dWxhciBkZXNjIGF0IHRoZSBzYW1lIHRpbWUsIHNvIHBlcmhhcHMgdGhlDQo+PiBERVZfRE1BX0wg
Yml0DQo+Pg0KPj4gY2xlYXIgYWN0aW9uIGlzIG5vdCBzeW5jIHRvIHRoZSBIVywgYW5kIHRoZSBI
VyBjYW4ndCB3b3JrIGFzIHdlIHdhbnQuDQo+Pg0KPj4NCj5Db3JlIGFsd2F5cyBmZXRjaGluZyAx
IGRlc2NyaXB0b3IgYmFzZWQgb246DQo+MS4gSVNPQyBJTiAtIG9uZSB1ZiBiZWZvcmUgdGFyZ2V0
IHVmLg0KPjIuIElTT0MgT1VUIC0gUnhGSUZPIE5vbkVtcHR5LCBFUCBlbmFibGVkLg0KPkFzIEkg
bWVudGlvbmVkIGJlZm9yZSwgYmV0d2VlbiBwcm9kdWNlciBhbmQgY29uc3VtZXIgaW5kZXhlcyBz
aG91bGQgYmUNCj5lbm91Z2ggZ2FwLiBJZiBub3QsIHRoZW4gQk5BIHdpbGwgYmUgYXNzZXJ0ZWQs
IEVQIHdpbGwgYmUgZGlzYWJsZWQgYW5kIHdpbGwgbmVlZA0KPnRvIHJlc3RhcnQgdHJhbnNmZXJz
IGZyb20gc2NyYXRjaCBiYXNlZCBvbiBJTi1OQUsgKElTT0MgSU4pIG9yIE9VVC1FUERpcyAoSVNP
Qw0KPk9VVCkgaW50ZXJydXB0cy4NCj4+DQoNCkhvdyBkbyB5b3UgZW5zdXJlIGVub3VnaCBnYXAg
YmV0d2VlbiB0aGUgcHJvZHVjZXIgYW5kIGNvbnN1bWVyPw0KVGhlIHByb2R1Y2VyIGZpbGwgbmV3
IGRlc2MgYXQgcmFuZG9tIHRpbWUsIGFuZCB3aGVuIGNsZWFyaW5nIHRoZSBERVZfRE1BX0wgYml0
DQpvZiB0aGUgbGFzdCBkZXNjIGluIHRoZSBjaGFpbiwgaW50ZXJydXB0cyBpcyBkaXNhYmxlZCBh
bmQgd2UgbWF5IGRlbGF5IG9yIG1pc3MgdGhlDQpCTkEgaW50ZXJydXB0LiANCkxpbnV4IGlzIG5v
dCBhIHJlYWwgdGltZSBzeXN0ZW0sIHNvIEkgdGhpbmsgd2Ugc2hvdWxkIGNvbnNpZGVyIHN1Y2gg
Y29ybmVyIGNhc2VzLg0KDQo+PiBQZXIgeW91ciBjb21tZW50LCB5b3UgbWVudGlvbmVkIHRoZSBw
cm9kdWNlciBhbmQgY29uc3VtZXIsIGJ1dA0KPj4NCj4+IEhvdyBkbyB5b3UgZG8gdGhlIHN5bmNo
cm9uaXphdGlvbiBiZXR3ZWVuIHRoZSBwcm9kdWNlciBhbmQgY29uc3VtZXI/DQo+Pg0KPkFjdHVh
bGx5LCBhcyBzb29uIGFzIGNvbnN1bWVyIGNvbXBsZXRlIHNvbWUgZGVzYyB0aGVuIGR3YzIgY29t
cGxldGUNCj5hcHByb3ByaWF0ZSBwcm9kdWNlcnMgcmVxdWVzdCB0byBmdW5jdGlvbiBkcml2ZXIg
dGhlbiBmdW5jdGlvbiBkcml2ZXIgcXVldWluZw0KPm5ldyByZXF1ZXN0LiBTbywgaW5pdGlhbCBn
YXAgd2lsbCBiZSBrZXB0Lg0KPj4NCg0KSXQgaXMgbm90IG1hbmRhdGFyeSBmb3IgdGhlIGZ1bmN0
aW9uIGRyaXZlciB0byBxdWV1aW5nIG5ldyByZXF1ZXN0IGluIHRoZSBjb21wbGV0ZQ0KaGFuZGxl
ci4gd2UgY2FuJ3QgZGVwZW5kIG9uIHRoZSBmdW5jdGlvbiBkcml2ZXIgdG8ga2VlcCB0aGUgZ2Fw
Lg0KDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pj4gKzg0NiwxNCBAQCBzdGF0aWMgaW50
IGR3YzJfZ2FkZ2V0X2ZpbGxfaXNvY19kZXNjKHN0cnVjdA0KPj4+Pj4gK2R3YzJfaHNvdGdfZXAN
Cj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKmhzX2VwLA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJZGVzYy0+
c3RhdHVzICY9IH5ERVZfRE1BX0JVRkZfU1RTX01BU0s7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAlk
ZXNjLT5zdGF0dXMgfD0gKERFVl9ETUFfQlVGRl9TVFNfSFJFQURZIDw8DQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+IERFVl9ETUFfQlVGRl9TVFNfU0hJRlQpOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+PiArCS8qIEluY3JlbWVudCBmcmFtZSBudW1iZXIgYnkgaW50ZXJ2YWwg
Zm9yIElOICovDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJaWYgKGhzX2VwLT5kaXJfaW4pDQo+Pg0K
Pj4+Pg0KPj4NCj4+Pj4+ICsJCWR3YzJfZ2FkZ2V0X2luY3JfZnJhbWVfbnVtKGhzX2VwKTsNCj4+
DQo+Pj4+DQo+Pg0KPj4+Pj4gKw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJLyogVXBkYXRlIGluZGV4
IG9mIGxhc3QgY29uZmlndXJlZCBlbnRyeSBpbiB0aGUgY2hhaW4gKi8NCj4+DQo+Pj4+DQo+Pg0K
Pj4+Pj4gCWhzX2VwLT5uZXh0X2Rlc2MrKzsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwlpZiAoaHNf
ZXAtPm5leHRfZGVzYyA+PSBNQVhfRE1BX0RFU0NfTlVNX0dFTkVSSUMpDQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+ICsJCWhzX2VwLT5uZXh0X2Rlc2MgPSAwOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+PiAJcmV0dXJuIDA7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IH0NCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gQEAgLTg3NSwxMSArODYyLDggQEAgc3RhdGljIGludCBkd2MyX2dhZGdl
dF9maWxsX2lzb2NfZGVzYyhzdHJ1Y3QNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gZHdjMl9oc290Z19l
cCAqaHNfZXAsDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICAgICogZHdjMl9nYWRnZXRfc3RhcnRfaXNv
Y19kZG1hIC0gc3RhcnQgaXNvY2hyb25vdXMgdHJhbnNmZXIgaW4NCj4+Pj4+IERETUENCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gICAgKiBAaHNfZXA6IFRoZSBpc29jaHJvbm91cyBlbmRwb2ludC4NCj4+
DQo+Pj4+DQo+Pg0KPj4+Pj4gICAgKg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtICogUHJlcGFyZSBm
aXJzdCBkZXNjcmlwdG9yIGNoYWluIGZvciBpc29jaHJvbm91cyBlbmRwb2ludHMuDQo+Pg0KPj4+
Pj4gQWZ0ZXJ3YXJkcw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArICogUHJlcGFyZSBkZXNjcmlwdG9y
IGNoYWluIGZvciBpc29jaHJvbm91cyBlbmRwb2ludHMuIEFmdGVyd2FyZHMNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gICAgKiB3cml0ZSBETUEgYWRkcmVzcyB0byBIVyBhbmQgZW5hYmxlIHRoZSBlbmRw
b2ludC4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLSAqDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0gKiBT
d2l0Y2ggYmV0d2VlbiBkZXNjcmlwdG9yIGNoYWlucyB2aWEgaXNvY19jaGFpbl9udW0gdG8gZ2l2
ZSBTVw0KPj4NCj4+Pj4+IG9wcG9ydHVuaXR5DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0gKiB0byBw
cmVwYXJlIHNlY29uZCBkZXNjcmlwdG9yIGNoYWluIHdoaWxlIGZpcnN0IG9uZSBpcyBiZWluZw0K
Pj4+Pj4gcHJvY2Vzc2VkIGJ5DQo+Pg0KPj4+IEhXLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAgICAq
Lw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBzdGF0aWMgdm9pZCBkd2MyX2dhZGdldF9zdGFydF9pc29j
X2RkbWEoc3RydWN0IGR3YzJfaHNvdGdfZXANCj4+Pj4+ICpoc19lcCkNCj4+DQo+Pj4+DQo+Pg0K
Pj4+Pj4geyBAQCAtODkwLDE5ICs4NzQsMjcgQEAgc3RhdGljIHZvaWQNCj4+DQo+Pj4+PiBkd2My
X2dhZGdldF9zdGFydF9pc29jX2RkbWEoc3RydWN0DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IGR3YzJf
aHNvdGdfZXAgKmhzX2VwKQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJdTMyIGRtYV9yZWc7DQo+Pg0K
Pj4+Pg0KPj4NCj4+Pj4+IAl1MzIgZGVwY3RsOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJdTMyIGN0
cmw7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJc3RydWN0IGR3YzJfZG1hX2Rlc2MgKmRlc2M7DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAlpZiAobGlzdF9lbXB0eSgm
aHNfZXAtPnF1ZXVlKSkgew0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJCWRldl9kYmcoaHNvdGctPmRl
diwgIiVzOiBObyByZXF1ZXN0cyBpbiBxdWV1ZVxuIiwgX19mdW5jX18pOw0KPj4NCj4+Pj4NCj4+
DQo+Pj4+PiAJCXJldHVybjsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCX0NCj4+DQo+Pj4+DQo+Pg0K
Pj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwkvKiBJbml0aWFsaXplIGRlc2NyaXB0b3IgY2hh
aW4gYnkgSG9zdCBCdXN5IHN0YXR1cyAqLw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCWZvciAocmV0
ID0gMDsgcmV0IDwgTUFYX0RNQV9ERVNDX05VTV9HRU5FUklDOyByZXQrKykgew0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiArCQlkZXNjID0gJmhzX2VwLT5kZXNjX2xpc3RbcmV0XTsNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gKwkJZGVzYy0+c3RhdHVzID0gMDsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwkJZGVz
Yy0+c3RhdHVzIHw9IChERVZfRE1BX0JVRkZfU1RTX0hCVVNZDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+
ICsJCQkJICAgIDw8IERFVl9ETUFfQlVGRl9TVFNfU0hJRlQpOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+
PiArCX0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKw0KPj4NCj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4gUmV0IGlzIG5vdCBhIGdvb2QgbmFtaW5nIGFzIHRoZSBsb29wIGNvdW50ZXIu
DQo+Pg0KPj4+Pg0KPj4NCj4+Pg0KPj4NCj4+PiBDb3VsZCBiZSwgYnV0IGl0IGp1c3QgcmV1c2Ug
ZXhpc3RpbmcgdmFyaWFibGUgaW5zdGVhZCB0byBkZWZpbmUgbmV3IG9uZS4NCj4+DQo+Pj4NCj4+
DQo+Pg0KPj4NCj4+ICBGcm9tIHRoZSBjb2RlIHJlYWRlcidzIHBlcnNwZWN0aXZlLCBpdCBpcyBh
IGJpdCBzdHJhbmdlLg0KPj4NCj5Paywgd2lsbCBkZWNsYXJlIG5ldyB2YXJpYWJsZS4NCj4+DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCWhzX2VwLT5uZXh0X2Rlc2MgPSAwOw0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+PiAJbGlzdF9mb3JfZWFjaF9lbnRyeV9zYWZlKGhzX3JlcSwgdHJlcSwg
JmhzX2VwLT5xdWV1ZSwgcXVldWUpIHsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4NCj4+
DQo+Pj4+IERvIHdlIHJlYWxseSBuZWVkIHNhZmUgZnVuY3Rpb24gaGVyZT8gV2UgaGF2ZSBhbHJl
YWR5IGhhdmUgdGhlIHNwaW5sb2NrLg0KPj4NCj4+Pj4NCj4+DQo+Pj4gSSBsZWZ0IGV4aXN0aW5n
IGxpc3RfZm9yX2VhY2hfZW50cnlfc2FmZSgpIG5vdCBvZiBwYXJ0IG9mIHRoaXMgcGF0Y2guDQo+
Pg0KPj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJCXJldCA9IGR3YzJfZ2FkZ2V0
X2ZpbGxfaXNvY19kZXNjKGhzX2VwLCBoc19yZXEtPnJlcS5kbWEsDQo+Pg0KPj4+Pg0KPj4NCj4+
Pj4+IAkJCQkJCSBoc19yZXEtPnJlcS5sZW5ndGgpOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQlp
ZiAocmV0KSB7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JCQlkZXZfZGJnKGhzb3RnLT5kZXYsICIl
czogZGVzYyBjaGFpbiBmdWxsXG4iLCBfX2Z1bmNfXyk7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJ
CWlmIChyZXQpDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJCWJyZWFrOw0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiAtCQl9DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAl9DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+IAlkZXBjdGwgPSBoc19lcC0+ZGlyX2luID8gRElFUENUTChpbmRl
eCkgOiBET0VQQ1RMKGluZGV4KTsgQEANCj4+Pj4+IC05MTQsMTANCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gKzkwNiw2IEBAIHN0YXRpYyB2b2lkIGR3YzJfZ2FkZ2V0X3N0YXJ0X2lzb2NfZGRtYShzdHJ1
Y3QNCj4+DQo+Pj4+PiArZHdjMl9oc290Z19lcA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAqaHNfZXAp
DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAljdHJsID0gZHdjMl9yZWFkbChoc290Zy0+cmVncyArIGRl
cGN0bCk7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAljdHJsIHw9IERYRVBDVExfRVBFTkEgfCBEWEVQ
Q1RMX0NOQUs7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAlkd2MyX3dyaXRlbChjdHJsLCBoc290Zy0+
cmVncyArIGRlcGN0bCk7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0NCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gLQkvKiBTd2l0Y2ggSVNPQyBkZXNjcmlwdG9yIGNoYWluIG51bWJlciBiZWluZyBwcm9jZXNz
ZWQgYnkgU1cqLw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCWhzX2VwLT5pc29jX2NoYWluX251bSA9
IChoc19lcC0+aXNvY19jaGFpbl9udW0gXiAxKSAmIDB4MTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
LQloc19lcC0+bmV4dF9kZXNjID0gMDsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gfQ0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAvKioNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
QEAgLTEyOTEsNiArMTI3OSw5IEBAIHN0YXRpYyBpbnQgZHdjMl9oc290Z19lcF9xdWV1ZShzdHJ1
Y3QgdXNiX2VwDQo+Pg0KPj4+Pj4gKmVwLA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBzdHJ1Y3QgdXNi
X3JlcXVlc3QgKnJlcSwNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCXN0cnVjdCBkd2MyX2hzb3RnICpo
cyA9IGhzX2VwLT5wYXJlbnQ7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAlib29sIGZpcnN0Ow0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+PiAJaW50IHJldDsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwl1MzIgbWF4
c2l6ZSA9IDA7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJdTMyIG1hc2sgPSAwOw0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiArDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAlk
ZXZfZGJnKGhzLT5kZXYsICIlczogcmVxICVwOiAlZEAlcCwgbm9pPSVkLCB6ZXJvPSVkLA0KPnNu
b2s9JWRcbiIsDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJZXAtPm5hbWUsIHJlcSwgcmVxLT5sZW5n
dGgsIHJlcS0+YnVmLCByZXEtPm5vX2ludGVycnVwdCwgQEANCj4+Pj4+IC0xMzA4LDYNCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gKzEyOTksMjQgQEAgc3RhdGljIGludCBkd2MyX2hzb3RnX2VwX3F1ZXVl
KHN0cnVjdCB1c2JfZXAgKmVwLA0KPj4+Pj4gK3N0cnVjdA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiB1
c2JfcmVxdWVzdCAqcmVxLA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJcmVxLT5hY3R1YWwgPSAwOw0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiAJcmVxLT5zdGF0dXMgPSAtRUlOUFJPR1JFU1M7DQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJLyogSW4gRERNQSBtb2RlIGZvciBJ
U09DJ3MgZG9uJ3QgcXVldWUgcmVxdWVzdCBpZiBsZW5ndGggZ3JlYXRlcg0KPj4NCj4+Pj4NCj4+
DQo+Pj4+PiArCSAqIHRoYW4gZGVzY3JpcHRvciBsaW1pdHMuDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+
ICsJICovDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJaWYgKHVzaW5nX2Rlc2NfZG1hKGhzKSAmJiBo
c19lcC0+aXNvY2hyb25vdXMpIHsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwkJbWF4c2l6ZSA9IGR3
YzJfZ2FkZ2V0X2dldF9kZXNjX3BhcmFtcyhoc19lcCwgJm1hc2spOw0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiArCQlpZiAoaHNfZXAtPmRpcl9pbiAmJiByZXEtPmxlbmd0aCA+IG1heHNpemUpIHsNCj4+
DQo+Pj4+DQo+Pg0KPj4+Pj4gKwkJCWRldl9lcnIoaHMtPmRldiwgIndyb25nIGxlbmd0aCAlZCAo
bWF4c2l6ZT0lZClcbiIsDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJCQkJcmVxLT5sZW5ndGgsIG1h
eHNpemUpOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQkJcmV0dXJuIC1FSU5WQUw7DQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+ICsJCX0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwkJLyogSVNPQyBPVVQgaGln
aCBiYW5kd2lkdGggbm90IHN1cHBvcnRlZCAqLw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQlpZiAo
IWhzX2VwLT5kaXJfaW4gJiYgcmVxLT5sZW5ndGggPiBoc19lcC0+ZXAubWF4cGFja2V0KSB7DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJCQlkZXZfZXJyKGhzLT5kZXYsICJJU09DIE9VVDogd3Jvbmcg
bGVuZ3RoICVkIChtcHM9JWQpXG4iLA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQkJCXJlcS0+bGVu
Z3RoLCBoc19lcC0+ZXAubWF4cGFja2V0KTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwkJCXJldHVy
biAtRUlOVkFMOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQl9DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+
ICsJfQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAlyZXQgPSBk
d2MyX2hzb3RnX2hhbmRsZV91bmFsaWduZWRfYnVmX3N0YXJ0KGhzLCBoc19lcCwgaHNfcmVxKTsN
Cj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCWlmIChyZXQpDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJcmV0
dXJuIHJldDsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gQEAgLTEzMzAsNyArMTMzOSw3IEBAIHN0YXRp
YyBpbnQgZHdjMl9oc290Z19lcF9xdWV1ZShzdHJ1Y3QgdXNiX2VwDQo+Pg0KPj4+Pj4gKmVwLA0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiBzdHJ1Y3QgdXNiX3JlcXVlc3QgKnJlcSwNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCS8qDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkg
KiBIYW5kbGUgRERNQSBpc29jaHJvbm91cyB0cmFuc2ZlcnMgc2VwYXJhdGVseSAtIGp1c3QgYWRk
IG5ldw0KPj4+Pj4gZW50cnkNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkgKiB0byB0aGUgaGFsZiBv
ZiBkZXNjcmlwdG9yIGNoYWluIHRoYXQgaXMgbm90IHByb2Nlc3NlZCBieSBIVy4NCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gKwkgKiB0byB0aGUgZGVzY3JpcHRvciBjaGFpbi4NCj4+DQo+Pj4+DQo+Pg0K
Pj4+Pj4gCSAqIFRyYW5zZmVyIHdpbGwgYmUgc3RhcnRlZCBvbmNlIFNXIGdldHMgZWl0aGVyIG9u
ZSBvZiBOQUsgb3INCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCSAqIE91dFRrbkVwRGlzIGludGVycnVw
dHMuDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkgKi8NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gQEAgLTEz
MzgsOSArMTM0Nyw5IEBAIHN0YXRpYyBpbnQgZHdjMl9oc290Z19lcF9xdWV1ZShzdHJ1Y3QgdXNi
X2VwDQo+Pg0KPj4+Pj4gKmVwLA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBzdHJ1Y3QgdXNiX3JlcXVl
c3QgKnJlcSwNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCSAgICBoc19lcC0+dGFyZ2V0X2ZyYW1lICE9
IFRBUkdFVF9GUkFNRV9JTklUSUFMKSB7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJcmV0ID0gZHdj
Ml9nYWRnZXRfZmlsbF9pc29jX2Rlc2MoaHNfZXAsIGhzX3JlcS0+cmVxLmRtYSwNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gCQkJCQkJIGhzX3JlcS0+cmVxLmxlbmd0aCk7DQo+Pg0KPj4+Pg0KPj4NCj4+
Pj4+IC0JCWlmIChyZXQpDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JCQlkZXZfZGJnKGhzLT5kZXYs
ICIlczogSVNPIGRlc2MgY2hhaW4gZnVsbFxuIiwgX19mdW5jX18pOw0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiAtDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJCWlmIChyZXQgPCAwKQ0KPj4NCj4+Pj4NCj4+
DQo+Pj4+PiArCQkJZGV2X2RiZyhocy0+ZGV2LCAiJXM6IGZhaWxlZCB0byBmaWxsIGlzb2MgZGVz
Y1xuIiwNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwkJCQlfX2Z1bmNfXyk7DQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+PiBkd2MyX2dhZGdldF9maWxsX2lzb2NfZGVzYyB3aWxs
IG5ldmVyIHJldHVybiBhIG5lZ2F0aXZlIHZhbHVlLCBhbmQNCj4+Pj4gYXQNCj4+DQo+Pj4+IHRo
ZSBzYW1lDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4gdGltZSBJIHRoaW5rIHRoZXJlIGlzIG5vIG5lZWQg
dG8gY2hlY2sgdGhlIHJldHVybiB2YWx1ZSwgd2UgY2FuIHdvcmsNCj4+DQo+Pj4+IHByb3Blcmx5
IGV2ZW4NCj4+DQo+Pj4+DQo+Pg0KPj4+PiB0aGUgZGVzYyBjaGFpbiBpcyBmdWxsLg0KPj4NCj4+
Pj4NCj4+DQo+Pj4gWW91IGFyZSByaWd0aC4gcmV0IGlzIDAgb3IgMS4gU28sIG5vIG5lZWQgdG8g
Y2hhbmdlIGV4aXN0aW5nIGNvZGUuDQo+Pj4gWWVzLCB3ZSBjYW4NCj4+DQo+Pj4gY29udGludWUg
d29yayBwcm9wZXJseSBldmVuIGlmIHRoZSBkZXNjIGNoYWluIGZ1bGwuIEl0IGp1c3QgZGVidWcN
Cj4+PiBtZXNzYWdlIGlmIChyZXQgIT0NCj4+DQo+Pj4gMCkuIERvIHlvdSBoYXZlIG9iamVjdGlv
bj8NCj4+DQo+Pj4NCj4+DQo+Pg0KPj4NCj4+IFNpbmNlIHdlIGFscmVhZHkgaGF2ZSBkZWJ1ZyBt
ZXNzYWdlIGluc2lkZSBkd2MyX2dhZGdldF9maWxsX2lzb2NfZGVzYywNCj4+IHNvIGhlcmUNCj4+
DQo+PiB3ZSBkb24ndCBuZWVkIGFkZGl0aW9uYWwgZGVidWcgbWVzc2FnZSwgd2hhdCBkbyB5b3Ug
dGhpbmsgb2YgaXQ/DQo+Pg0KPj4NCj5BZ3JlZSB3aXRoIHlvdSwgd2lsbCByZW1vdmUuDQo+Pg0K
Pj4NCj4+DQo+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJcmV0dXJuIDA7DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+IAl9DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+IEBAIC0yMDExLDEwICsyMDIwLDkgQEAgc3RhdGljIHZvaWQNCj4+DQo+Pj4gZHdjMl9o
c290Z19jb21wbGV0ZV9yZXF1ZXN0KHN0cnVjdA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBkd2MyX2hz
b3RnICpoc290ZywNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gICAgKiBAaHNfZXA6IFRoZSBlbmRwb2lu
dCB0aGUgcmVxdWVzdCB3YXMgb24uDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICAgICoNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gICAgKiBHZXQgZmlyc3QgcmVxdWVzdCBmcm9tIHRoZSBlcCBxdWV1ZSwgZGV0
ZXJtaW5lIGRlc2NyaXB0b3Igb24NCj4+DQo+Pj4+PiB3aGljaA0KPj4NCj4+Pj4NCj4+DQo+Pj4+
PiBjb21wbGV0ZQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtICogaGFwcGVuZWQuIFNXIGJhc2VkIG9u
IGlzb2NfY2hhaW5fbnVtIGRpc2NvdmVycyB3aGljaCBoYWxmIG9mDQo+Pj4+PiB0aGUNCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gZGVzY3JpcHRvcg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtICogY2hhaW4g
aXMgY3VycmVudGx5IGluIHVzZSBieSBIVywgYWRqdXN0cyBkbWFfYWRkcmVzcyBhbmQNCj4+DQo+
Pj4+PiBjYWxjdWxhdGVzIGluZGV4DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0gKiBvZiBjb21wbGV0
ZWQgZGVzY3JpcHRvciBiYXNlZCBvbiB0aGUgdmFsdWUgb2YgREVQRE1BIHJlZ2lzdGVyLg0KPj4N
Cj4+Pj4+IFVwZGF0ZQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBhY3R1YWwNCj4+DQo+Pj4+DQo+Pg0K
Pj4+Pj4gLSAqIGxlbmd0aCBvZiByZXF1ZXN0LCBnaXZlYmFjayB0byBnYWRnZXQuDQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+ICsgKiBoYXBwZW5lZC4gU1cgZGlzY292ZXJzIHdoaWNoIGRlc2NyaXB0b3Ig
Y3VycmVudGx5IGluIHVzZSBieSBIVywNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKyBhZGp1c3RzDQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsgKiBkbWFfYWRkcmVzcyBhbmQgY2FsY3VsYXRlcyBpbmRleCBv
ZiBjb21wbGV0ZWQgZGVzY3JpcHRvciBiYXNlZA0KPj4+Pj4gKyBvbg0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiArIHRoZSB2YWx1ZQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArICogb2YgREVQRE1BIHJlZ2lz
dGVyLiBVcGRhdGUgYWN0dWFsIGxlbmd0aCBvZiByZXF1ZXN0LCBnaXZlYmFjayB0bw0KPmdhZGdl
dC4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gICAgKi8NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gc3RhdGlj
IHZvaWQgZHdjMl9nYWRnZXRfY29tcGxldGVfaXNvY19yZXF1ZXN0X2RkbWEoc3RydWN0DQo+Pg0K
Pj4+Pj4gZHdjMl9oc290Z19lcA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAqaHNfZXApICB7IEBAIC0y
MDM3LDgyICsyMDQ1LDU1IEBAIHN0YXRpYyB2b2lkDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IGR3YzJf
Z2FkZ2V0X2NvbXBsZXRlX2lzb2NfcmVxdWVzdF9kZG1hKHN0cnVjdCBkd2MyX2hzb3RnX2VwDQo+
KmhzX2VwKQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJZG1hX2Fk
ZHIgPSBoc19lcC0+ZGVzY19saXN0X2RtYTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gLQkvKg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCSAqIElmIGxvd2VyIGhhbGYg
b2YgIGRlc2NyaXB0b3IgY2hhaW4gaXMgY3VycmVudGx5IHVzZSBieSBTVywNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gLQkgKiB0aGF0IG1lYW5zIGhpZ2hlciBoYWxmIGlzIGJlaW5nIHByb2Nlc3NlZCBi
eSBIVywgc28gc2hpZnQNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkgKiBETUEgYWRkcmVzcyB0byBo
aWdoZXIgaGFsZiBvZiBkZXNjcmlwdG9yIGNoYWluLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCSAq
Lw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCWlmICghaHNfZXAtPmlzb2NfY2hhaW5fbnVtKQ0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+PiAtCQlkbWFfYWRkciArPSBzaXplb2Yoc3RydWN0IGR3YzJfZG1hX2Rl
c2MpICoNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkJCSAgICAoTUFYX0RNQV9ERVNDX05VTV9HRU5F
UklDIC8gMik7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCWRt
YV9yZWcgPSBoc19lcC0+ZGlyX2luID8gRElFUERNQShoc19lcC0+aW5kZXgpIDoNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gRE9FUERNQShoc19lcC0+aW5kZXgpOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJ
ZGVwZG1hID0gZHdjMl9yZWFkbChoc290Zy0+cmVncyArIGRtYV9yZWcpOw0KPj4NCj4+Pj4NCj4+
DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJaW5kZXggPSAoZGVwZG1hIC0gZG1hX2FkZHIp
IC8gc2l6ZW9mKHN0cnVjdCBkd2MyX2RtYV9kZXNjKSAtIDE7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+
IC0JZGVzY19zdHMgPSBoc19lcC0+ZGVzY19saXN0W2luZGV4XS5zdGF0dXM7DQo+Pg0KPj4+Pg0K
Pj4NCj4+Pj4+ICsJLyogQ2hlY2sgZGVzY3JpcHRvciBjaGFpbiByb2xsb3ZlciAqLw0KPj4NCj4+
Pj4NCj4+DQo+Pj4+PiArCWlmIChpbmRleCA8IDApDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJCWlu
ZGV4ID0gTUFYX0RNQV9ERVNDX05VTV9HRU5FUklDIC0gMTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4N
Cj4+DQo+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+IEkgZG9uJ3QgdW5kZXJzdGFu
ZCBoZXJlLCB3aHkgc2V0dGluZyB0aGUgaW5kZXggdG8NCj4+DQo+Pj4+DQo+Pg0KPj4+PiAgICBN
QVhfRE1BX0RFU0NfTlVNX0dFTkVSSUMgLSAxIHdoZW4gdGhlIGNoYWluIGlzIHJvbGxvdmVyPw0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+IElmIHRoZSBjaGFpbiBpcyByb2xsb3ZlciwgdGhlIGluZGV4IHNo
b3VsZCBwb2ludCB0byB0aGUgbGF0ZXN0DQo+Pg0KPj4+PiBmaW5pc2hlZCBkZXNjLA0KPj4NCj4+
Pj4NCj4+DQo+Pj4+IGFuZCBhbGwgdGhlIGZpbmlzaGVkIGRlc2NzIHNob3VsZCBiZSBwcm9jZXNz
ZWQuIEFuZCBldmVuIHRoZSBjaGFpbg0KPj4+PiBpcw0KPj4NCj4+Pj4gcm9sbG92ZXIsDQo+Pg0K
Pj4+Pg0KPj4NCj4+Pj4gdGhlIGNvdW50IG9mIGRlc2NzIGluIGNoYWluIGlzIG1heWJlIGxlc3Mg
dGhlbg0KPj4NCj4+PiBNQVhfRE1BX0RFU0NfTlVNX0dFTkVSSUMuDQo+Pg0KPj4+Pg0KPj4NCj4+
PiBJZiBkZXBkbWEgcG9pbnQgdG8gZmlyc3QgZGVzYyBpbiBsaXN0LCB0aGF0IG1lYW4gdGhlIGxh
c3QgcHJvY2Vzc2VkDQo+Pj4gZGVzYyB3YXMgbGFzdA0KPj4NCj4+PiBpbiB0aGUgY2hhaW4uIElu
IHRoaXMgY2FzZSBpbmRleCB3aWxsIGJlIG5lZ2F0aXZlLg0KPj4NCj4+PiBJbiBjYXNlIG9mIGRl
c2MgY291bnQgbGVzcyB0aGFuIE1BWF9ETUFfREVTQ19OVU1fR0VORVJJQyB0aGVuDQo+Pj4gcm9s
bG92ZXINCj4+DQo+Pj4gY2FuIGJlIGhhcHBlbiAgYmVjYXVzZSBvZiBMLWJpdCBzZXQuIEluIHRo
aXMgY2FzZSBieSBwcm9jZXNzaW5nIGZpcnN0DQo+Pj4gZGVzYyB3aWxsIGJlDQo+Pg0KPj4+IGFz
c2VydGVkIEJOQSBpbnRlcnJ1cHQgYnV0IG5vdCBYZmVyQ29tcGxldGUgaW50ZXJydXB0Lg0KPj4N
Cj4+Pg0KPj4NCj4+DQo+Pg0KPj4gQ2FuIHdlIHJlYWNoIGhlcmUgaW4gQk5BIGludGVycnVwdCwg
b3IgY2FuIHdlIGhhdmUgYm90aCBCTkEgYW5kDQo+PiBYZmVyQ29tcGxldGUNCj4+DQo+PiBJbnRl
cnJ1cHRzIGFzc2VydGVkIGF0IHRoZSBzYW1lIHRpbWU/DQo+Pg0KPj4gWW91ciBjb25jbHVzaW9u
IGlzIGJhc2VkIG9uIHRoZSBmb2xsb3dpbmcgYXNzdW1wdGlvbjoNCj4+DQo+PiAxLiAgQk5BIGlu
dGVycnVwdCBoYW5kbGUgZmxvdyBjYW4ndCBnbyBpbnRvIGhlcmUuDQo+Pg0KPj4gMi4gIHdoZW4g
dGhlIGV4ZWN1dGlvbiBmbG93IGdvaW5nIHRvIGhlcmUsIG9ubHkgYmVjYXVzZSBvZiBYZmVyQ29t
cGxldGUNCj5pbnRlcnJ1cHQuDQo+Pg0KPj4gMy4gIHdoZW4gdGhlIFhmZXJDb21wbGV0ZSBpcyBh
c3NlcnRlZCwgQk5BIGludGVycnVwdCBjYW4ndCBiZSBhc3NlcnRlZC4NCj4+DQo+Pg0KPkluIGNh
c2Ugb2YgYm90aCBpbnRlcnJ1cHQgYXNzZXJ0ZWQgdGhlbiBYZmVyQ29tcGxldGUgaWdub3JlZC4g
U2VlDQo+ZHdjMl9oc290Z19lcGludCgpIGZ1bmN0aW9uLiBBY3R1YWxseSwgaW4gbXkgdGVzdCBj
YXNlcyB3aXRoIGJJbnRlcnZhbD0xIGl0DQo+aGFwcGVuIG9uIGxhc3QgZGVzY3JpcHRvciBhbmQg
bm8gYW55IG5ldyByZXF1ZXN0cyBmcm9tIGZ1bmN0aW9uIGRyaXZlciwNCj5iZWNhdXNlIEVQIGRp
c2FibGVkIHdpdGggc29tZSBsYXRlbmN5IGluIGNvcmUgQk5BIGFsc28gYXNzZXJ0ZWQuDQo+QnV0
IGl0cyBjb3JuZXIgY2FzZSBhbmQgY2FuIGJlIGlnbm9yZWQuDQo+DQoNClRoZW4gd2hhdCBhYm91
dCBhZGRpbmcgc29tZSBhc3NlcnQgaGVyZSB0byBjYXRjaCB0aGUgY29yZSBjYXNlPyANCg0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQltYXNrID0gaHNfZXAtPmRpcl9pbiA/IERFVl9E
TUFfSVNPQ19UWF9OQllURVNfTUFTSyA6DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JICAgICAgIERF
Vl9ETUFfSVNPQ19SWF9OQllURVNfTUFTSzsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQl1cmVxLT5h
Y3R1YWwgPSB1cmVxLT5sZW5ndGggLQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQkgICAgICAgKChk
ZXNjX3N0cyAmIG1hc2spID4+IERFVl9ETUFfSVNPQ19OQllURVNfU0hJRlQpOw0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiAtDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JLyogQWRqdXN0IGFjdHVhbCBsZW5n
dGggZm9yIElTT0MgT3V0IGlmIGxlbmd0aCBpcyBub3QgYWxpZ24gb2YgNCAqLw0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiAtCWlmICghaHNfZXAtPmRpcl9pbiAmJiB1cmVxLT5sZW5ndGggJiAweDMpDQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JCXVyZXEtPmFjdHVhbCArPSA0IC0gKHVyZXEtPmxlbmd0aCAm
IDB4Myk7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJZGVzY19zdHMgPSBoc19lcC0+ZGVzY19saXN0
W2luZGV4XS5zdGF0dXM7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJLyogQ2hlY2sgY29tcGxldGlv
biBzdGF0dXMgKi8NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwlpZiAoKGRlc2Nfc3RzICYgREVWX0RN
QV9TVFNfTUFTSykgPj4gREVWX0RNQV9TVFNfU0hJRlQgPT0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
KwkgICAgREVWX0RNQV9TVFNfU1VDQykgew0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQltYXNrID0g
aHNfZXAtPmRpcl9pbiA/IERFVl9ETUFfSVNPQ19UWF9OQllURVNfTUFTSyA6DQo+Pg0KPj4+Pg0K
Pj4NCj4+Pj4+ICsJCSAgICAgICBERVZfRE1BX0lTT0NfUlhfTkJZVEVTX01BU0s7DQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+ICsJCXVyZXEtPmFjdHVhbCA9IHVyZXEtPmxlbmd0aCAtDQo+Pg0KPj4+Pg0K
Pj4NCj4+Pj4+ICsJCQkgICAgICAgKChkZXNjX3N0cyAmIG1hc2spID4+DQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+ICsJCQkJREVWX0RNQV9JU09DX05CWVRFU19TSElGVCk7DQo+Pg0KPj4+Pg0KPj4NCj4+
Pj4+ICsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwkJLyogQWRqdXN0IGFjdHVhbCBsZW4gZm9yIElT
T0MgT3V0IGlmIGxlbiBpcyBub3QgYWxpZ24gb2YgNCAqLw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAr
CQlpZiAoIWhzX2VwLT5kaXJfaW4gJiYgdXJlcS0+bGVuZ3RoICYgMHgzKQ0KPj4NCj4+Pj4NCj4+
DQo+Pj4+PiArCQkJdXJlcS0+YWN0dWFsICs9IDQgLSAodXJlcS0+bGVuZ3RoICYgMHgzKTsNCj4+
DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQlkd2MyX2hzb3RnX2NvbXBs
ZXRlX3JlcXVlc3QoaHNvdGcsIGhzX2VwLCBoc19yZXEsIDApOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+
PiArCQlkd2MyX2hzb3RnX2NvbXBsZXRlX3JlcXVlc3QoaHNvdGcsIGhzX2VwLCBoc19yZXEsIDAp
Ow0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCX0gZWxzZSB7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJ
CWR3YzJfaHNvdGdfY29tcGxldGVfcmVxdWVzdChoc290ZywgaHNfZXAsIGhzX3JlcSwNCj4tRVRJ
TUVET1VUKTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwl9DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IH0N
Cj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLyoNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gLSAqIGR3YzJfZ2FkZ2V0X3N0YXJ0X25leHRfaXNvY19kZG1hIC0gc3RhcnQgbmV4
dCBpc29jIHJlcXVlc3QsIGlmIGFueS4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLSAqIEBoc19lcDog
VGhlIGlzb2Nocm9ub3VzIGVuZHBvaW50IHRvIGJlIHJlLWVuYWJsZWQuDQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+ICsgKiBkd2MyX2dhZGdldF9oYW5kbGVfaXNvY19ibmEgLSBoYW5kbGUgQk5BIGludGVy
cnVwdCBmb3IgSVNPQy4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKyAqIEBoc19lcDogVGhlIGlzb2No
cm9ub3VzIGVuZHBvaW50Lg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAgICAqDQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+IC0gKiBJZiBlcCBoYXMgYmVlbiBkaXNhYmxlZCBkdWUgdG8gbGFzdCBkZXNjcmlwdG9y
IHNlcnZpY2luZyAoSU4gZW5kcG9pbnQpIG9yDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0gKiBCTkEg
KE9VVCBlbmRwb2ludCkgY2hlY2sgdGhlIHN0YXR1cyBvZiBvdGhlciBoYWxmIG9mIGRlc2NyaXB0
b3IgY2hhaW4NCj50aGF0DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0gKiB3YXMgdW5kZXIgU1cgY29u
dHJvbCB0aWxsIEhXIHdhcyBidXN5IGFuZCByZXN0YXJ0IHRoZSBlbmRwb2ludCBpZg0KPm5lZWRl
ZC4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKyAqIENvbXBsZXRlIHJlcXVlc3Qgd2l0aCAtRUlPLg0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiArICogSWYgRVAgSVNPQyBPVVQgdGhlbiBuZWVkIHRvIGZsdXNo
IFJYIEZJRk8gdG8gcmVtb3ZlIHNvdXJjZSBvZiBCTkENCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKyAq
IGludGVycnVwdC4gUmVzZXQgdGFyZ2V0IGZyYW1lIGFuZCBuZXh0X2Rlc2MgdG8gYWxsb3cgdG8g
c3RhcnQNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKyAqIElTT0MncyBvbiBOQUsgaW50ZXJydXB0IGZv
ciBJTiBkaXJlY3Rpb24gb3Igb24gT1VUVEtORVBESVMNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKyAq
IGludGVycnVwdCBmb3IgT1VUIGRpcmVjdGlvbi4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gICAgKi8N
Cj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLXN0YXRpYyB2b2lkIGR3YzJfZ2FkZ2V0X3N0YXJ0X25leHRf
aXNvY19kZG1hKHN0cnVjdCBkd2MyX2hzb3RnX2VwDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICpoc19l
cCkNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gK3N0YXRpYyB2b2lkIGR3YzJfZ2FkZ2V0X2hhbmRsZV9p
c29jX2JuYShzdHJ1Y3QgZHdjMl9oc290Z19lcA0KPipoc19lcCkNCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gew0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJc3RydWN0IGR3YzJfaHNvdGcgKmhzb3RnID0gaHNf
ZXAtPnBhcmVudDsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQl1MzIgZGVwY3RsOw0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiAtCXUzMiBkbWFfcmVnOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCXUzMiBjdHJs
Ow0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCXUzMiBkbWFfYWRkciA9IGhzX2VwLT5kZXNjX2xpc3Rf
ZG1hOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCXVuc2lnbmVkIGNoYXIgaW5kZXggPSBoc19lcC0+
aW5kZXg7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQlkbWFf
cmVnID0gaHNfZXAtPmRpcl9pbiA/IERJRVBETUEoaW5kZXgpIDogRE9FUERNQShpbmRleCk7DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JZGVwY3RsID0gaHNfZXAtPmRpcl9pbiA/IERJRVBDVEwoaW5k
ZXgpIDogRE9FUENUTChpbmRleCk7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+IC0JY3RybCA9IGR3YzJfcmVhZGwoaHNvdGctPnJlZ3MgKyBkZXBjdGwpOw0KPj4NCj4+
Pj4NCj4+DQo+Pj4+PiArCWlmICghaHNfZXAtPmRpcl9pbikNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
KwkJZHdjMl9mbHVzaF9yeF9maWZvKGhzb3RnKTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwlkd2My
X2hzb3RnX2NvbXBsZXRlX3JlcXVlc3QoaHNvdGcsIGhzX2VwLCBnZXRfZXBfaGVhZChoc19lcCks
DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJCQkJICAgIC1FSU8pOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+
Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCS8qDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JICogRVAg
d2FzIGRpc2FibGVkIGlmIEhXIGhhcyBwcm9jZXNzZWQgbGFzdCBkZXNjcmlwdG9yIG9yIEJOQSB3
YXMNCj5zZXQuDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JICogU28gcmVzdGFydCBlcCBpZiBTVyBo
YXMgcHJlcGFyZWQgbmV3IGRlc2NyaXB0b3IgY2hhaW4gaW4gZXBfcXVldWUNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gLQkgKiByb3V0aW5lIHdoaWxlIEhXIHdhcyBidXN5Lg0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiAtCSAqLw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCWlmICghKGN0cmwgJiBEWEVQQ1RMX0VQ
RU5BKSkgew0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQlpZiAoIWhzX2VwLT5uZXh0X2Rlc2MpIHsN
Cj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkJCWRldl9kYmcoaHNvdGctPmRldiwgIiVzOiBObyBtb3Jl
IElTT0MgcmVxdWVzdHNcbiIsDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JCQkJX19mdW5jX18pOw0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQkJcmV0dXJuOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQl9
DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkJZG1hX2FkZHIg
Kz0gc2l6ZW9mKHN0cnVjdCBkd2MyX2RtYV9kZXNjKSAqDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0J
CQkgICAgKE1BWF9ETUFfREVTQ19OVU1fR0VORVJJQyAvIDIpICoNCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gLQkJCSAgICBoc19lcC0+aXNvY19jaGFpbl9udW07DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0J
CWR3YzJfd3JpdGVsKGRtYV9hZGRyLCBoc290Zy0+cmVncyArIGRtYV9yZWcpOw0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiAtDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JCWN0cmwgfD0gRFhFUENUTF9FUEVO
QSB8IERYRVBDVExfQ05BSzsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkJZHdjMl93cml0ZWwoY3Ry
bCwgaHNvdGctPnJlZ3MgKyBkZXBjdGwpOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtDQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+IC0JCS8qIFN3aXRjaCBJU09DIGRlc2NyaXB0b3IgY2hhaW4gbnVtYmVyIGJl
aW5nIHByb2Nlc3NlZCBieSBTVyovDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JCWhzX2VwLT5pc29j
X2NoYWluX251bSA9IChoc19lcC0+aXNvY19jaGFpbl9udW0gXiAxKSAmIDB4MTsNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gLQkJaHNfZXAtPm5leHRfZGVzYyA9IDA7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+
IC0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkJZGV2X2RiZyhoc290Zy0+ZGV2LCAiJXM6IFJlc3Rh
cnRlZCBpc29jaHJvbm91cyBlbmRwb2ludFxuIiwNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkJCV9f
ZnVuY19fKTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQl9DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJ
aHNfZXAtPnRhcmdldF9mcmFtZSA9IFRBUkdFVF9GUkFNRV9JTklUSUFMOw0KPj4NCj4+Pj4NCj4+
DQo+Pj4+PiArCWhzX2VwLT5uZXh0X2Rlc2MgPSAwOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiB9DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC8qKg0KPj4NCj4+Pj4NCj4+
DQo+Pj4+PiBAQCAtMjgxNiwxOCArMjc5NywyNSBAQCBzdGF0aWMgdm9pZCBkd2MyX2dhZGdldF9o
YW5kbGVfbmFrKHN0cnVjdA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBkd2MyX2hzb3RnX2VwICpoc19l
cCkgIHsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCXN0cnVjdCBkd2MyX2hzb3RnICpoc290ZyA9IGhz
X2VwLT5wYXJlbnQ7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAlpbnQgZGlyX2luID0gaHNfZXAtPmRp
cl9pbjsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwl1MzIgdG1wOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+
Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJaWYgKCFkaXJfaW4gfHwgIWhzX2VwLT5pc29jaHJvbm91
cykNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCQlyZXR1cm47DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+IAlpZiAoaHNfZXAtPnRhcmdldF9mcmFtZSA9PSBUQVJHRVRfRlJB
TUVfSU5JVElBTCkgew0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQloc19lcC0+dGFyZ2V0X2ZyYW1l
ID0gZHdjMl9oc290Z19yZWFkX2ZyYW1lbm8oaHNvdGcpOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQl0bXAgPSBkd2MyX2hzb3RnX3JlYWRfZnJhbWVubyhoc290
Zyk7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+PiBJIHRoaW5rIHRoZXJl
IGlzIG5vIG5lZWQgdG8gaW50cm9kdWNlIHRtcCwgYW5kIHRoZSBvcmlnaW5hbCBpcyBhbGwgcmln
aHQuDQo+Pg0KPj4+Pg0KPj4NCj4+PiBObywgdG1wIHJlcXVpcmVkLiBSZWFkaW5nIGN1cnJlbnQg
ZnJhbWUgbnVtYmVyIHNob3VsZCBiZSBkb25lIGFzIHNvb24gYXMNCj4+DQo+Pj4gcG9zc2libGUu
IFRoaXMgaXMgd2h5IGl0J3Mgc3RvcmVkIGluIHRtcCBhbmQgdGhlbiB1c2VkIGZvciBiZWxvdyBj
YXNlczoNCj4+DQo+Pj4gMS4gRERNQSBtb2RlLiBPbiBkd2MyX2hzb3RnX2NvbXBsZXRlX3JlcXVl
c3QoKSBmdW5jdGlvbiBkcml2ZXINCj4+DQo+Pj4gaW1tZWRpYXRseSBxdWV1ZWQgbmV3IHJlcXVl
c3QgYW5kIGFzIHJlc3VsdCB0YXJnZXRfZnJhbWUgaW5jcmVtZW50ZWQgYnkNCj4+DQo+Pj4gaW50
ZXJ2YWwuDQo+Pg0KPj4+IDIuIEJETUEgbW9kZS4gdG1wIHJlcXVpcmVkIGlmIGludGVydmFsID4g
MS4NCj4+DQo+Pj4+DQo+Pg0KPj4NCj4+DQo+PiBTbyBmb3IgYm90aCBERE1BIG9yIEJETUEgbW9k
ZSwgaHNfZXAtPnRhcmdldF9mcmFtZSBzaG91bGQgYmUgdXBkYXRlZA0KPnRoZQ0KPj4NCj4+IEN1
cnJlbnQgZnJhbWUgbnVtYmVyIGluIEhXLg0KPj4NCj4+IFRoZSBvcmlnaW5hbCBjb2RlIGNhbiBj
b3ZlciBib3RoIGJyYW5jaCwgcmlnaHQ/DQo+Pg0KPj4NCj5PcmlnaW5hbCBjb2RlIGRvZXNuJ3Qg
aW5jcmVtZW50IGhlcmUgdGFyZ2V0IGZyYW1lIG51bWJlciAocGVyZm9ybWluZyBpbg0KPmZpbGxf
aXNvYykgdG8gc3RhcnQgdHJhbnNmZXJzIGZyb20gbmV4dCBpbnRlcnZhbCBhbmQgZG9lc24ndCBj
b21wbGV0ZQ0KPnJlcXVlc3QuDQo+DQoNCk1heWJlIHlvdSBoYXZlIG1pc3VuZGVyc3Rvb2QgbWUs
IEkgbWVhbiB0aGVyZSBpcyBubyBuZWVkIHRvIGFkZCB0aGUgdG1wIHZhcmlhYmxlLg0KRGlyZWN0
bHkgdXBkYXRlIHRoZSBoc19lcC0+dGFyZ2V0X2ZyYW1lIHVzaW5nIA0KImhzX2VwLT50YXJnZXRf
ZnJhbWUgPSBkd2MyX2hzb3RnX3JlYWRfZnJhbWVubyhoc290Zyk7ICIgaW5zdGVhZCBvZiANCiJo
c19lcC0+dGFyZ2V0X2ZyYW1lID0gdG1wIiANCkluIGJvdGggYnJhbmNoZXMuDQoNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gCQlpZiAodXNpbmdfZGVzY19kbWEoaHNvdGcpKSB7DQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+ICsJCQlkd2MyX2hzb3RnX2NvbXBsZXRlX3JlcXVlc3QoaHNvdGcsIGhzX2VwLA0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+PiArCQkJCQkJICAgIGdldF9lcF9oZWFkKGhzX2VwKSwNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gKwkJCQkJCSAgICAtRU5PREFUQSk7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJ
CQloc19lcC0+dGFyZ2V0X2ZyYW1lID0gdG1wOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQkJZHdj
Ml9nYWRnZXRfaW5jcl9mcmFtZV9udW0oaHNfZXApOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJCQlk
d2MyX2dhZGdldF9zdGFydF9pc29jX2RkbWEoaHNfZXApOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJ
CQlyZXR1cm47DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJfQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQloc19lcC0+dGFyZ2V0X2ZyYW1lID0gdG1wOw0KPj4NCj4+
Pj4NCj4+DQo+Pj4+PiAJCWlmIChoc19lcC0+aW50ZXJ2YWwgPiAxKSB7DQo+Pg0KPj4+Pg0KPj4N
Cj4+Pj4+IAkJCXUzMiBjdHJsID0gZHdjMl9yZWFkbChoc290Zy0+cmVncyArDQo+Pg0KPj4+Pg0K
Pj4NCj4+Pj4+IAkJCQkJICAgICAgRElFUENUTChoc19lcC0+aW5kZXgpKTsNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gQEAgLTI4NDMsNyArMjgzMSw4IEBAIHN0YXRpYyB2b2lkIGR3YzJfZ2FkZ2V0X2hh
bmRsZV9uYWsoc3RydWN0DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IGR3YzJfaHNvdGdfZXAgKmhzX2Vw
KQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJCQkJCSAgICBnZXRfZXBfaGVhZChoc19lcCksIDApOw0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiAJfQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+
DQo+Pj4+PiAtCWR3YzJfZ2FkZ2V0X2luY3JfZnJhbWVfbnVtKGhzX2VwKTsNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gKwlpZiAoIXVzaW5nX2Rlc2NfZG1hKGhzb3RnKSkNCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gKwkJZHdjMl9nYWRnZXRfaW5jcl9mcmFtZV9udW0oaHNfZXApOw0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiB9DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC8qKg0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+PiBAQCAtMjkwMSw5ICsyODkwLDkgQEAgc3RhdGljIHZvaWQgZHdjMl9o
c290Z19lcGludChzdHJ1Y3QNCj5kd2MyX2hzb3RnDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICpoc290
ZywgdW5zaWduZWQgaW50IGlkeCwNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0K
Pj4+Pj4gCQkvKiBJbiBERE1BIGhhbmRsZSBpc29jaHJvbm91cyByZXF1ZXN0cyBzZXBhcmF0ZWx5
ICovDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJaWYgKHVzaW5nX2Rlc2NfZG1hKGhzb3RnKSAmJiBo
c19lcC0+aXNvY2hyb25vdXMpIHsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQkJCWR3YzJfZ2FkZ2V0
X2NvbXBsZXRlX2lzb2NfcmVxdWVzdF9kZG1hKGhzX2VwKTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
LQkJCS8qIFRyeSB0byBzdGFydCBuZXh0IGlzb2MgcmVxdWVzdCAqLw0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiAtCQkJZHdjMl9nYWRnZXRfc3RhcnRfbmV4dF9pc29jX2RkbWEoaHNfZXApOw0KPj4NCj4+
Pj4NCj4+DQo+Pj4+PiArCQkJLyogWGZlckNvbXBsIHNldCBhbG9uZyB3aXRoIEJOQSAqLw0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+PiArCQkJaWYgKCEoaW50cyAmIERYRVBJTlRfQk5BSU5UUikpDQo+Pg0K
Pj4+Pg0KPj4NCj4+Pj4+ICsJCQkJZHdjMl9nYWRnZXRfY29tcGxldGVfaXNvY19yZXF1ZXN0X2Rk
bWEoaHNfZXApOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJCX0gZWxzZSBpZiAoZGlyX2luKSB7DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJCS8qDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJCSAqIFdlIGdl
dCBPdXREb25lIGZyb20gdGhlIEZJRk8sIHNvIHdlIG9ubHkgQEAgLTI5NzgsMTUNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gKzI5NjcsOCBAQCBzdGF0aWMgdm9pZCBkd2MyX2hzb3RnX2VwaW50KHN0cnVj
dCBkd2MyX2hzb3RnICpoc290ZywNCj4+DQo+Pj4gdW5zaWduZWQNCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gaW50IGlkeCwNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCWlm
IChpbnRzICYgRFhFUElOVF9CTkFJTlRSKSB7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJZGV2X2Ri
Zyhoc290Zy0+ZGV2LCAiJXM6IEJOQSBpbnRlcnJ1cHRcbiIsIF9fZnVuY19fKTsNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gLQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQkvKg0KPj4NCj4+Pj4NCj4+DQo+
Pj4+PiAtCQkgKiBUcnkgdG8gc3RhcnQgbmV4dCBpc29jIHJlcXVlc3QsIGlmIGFueS4NCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gLQkJICogU29tZXRpbWVzIHRoZSBlbmRwb2ludCByZW1haW5zIGVuYWJs
ZWQgYWZ0ZXIgQk5BIGludGVycnVwdA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQkgKiBhc3NlcnRp
b24sIHdoaWNoIGlzIG5vdCBleHBlY3RlZCwgaGVuY2Ugd2UgY2FuIGVudGVyIGhlcmUNCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gLQkJICogY291cGxlIG9mIHRpbWVzLg0KPj4NCj4+Pj4NCj4+DQo+Pj4+
PiAtCQkgKi8NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCQlpZiAoaHNfZXAtPmlzb2Nocm9ub3VzKQ0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiAtCQkJZHdjMl9nYWRnZXRfc3RhcnRfbmV4dF9pc29jX2RkbWEo
aHNfZXApOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQkJZHdjMl9nYWRnZXRfaGFuZGxlX2lzb2Nf
Ym5hKGhzX2VwKTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCX0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4N
Cj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCWlmIChkaXJfaW4gJiYgIWhzX2VwLT5pc29jaHJvbm91cykg
ew0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBAQCAtMzc5MSw2ICszNzczLDcgQEAgc3RhdGljIGludCBk
d2MyX2hzb3RnX2VwX2VuYWJsZShzdHJ1Y3QgdXNiX2VwDQo+Pg0KPj4+ICplcCwNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gCXVuc2lnbmVkIGludCBkaXJfaW47DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAl1
bnNpZ25lZCBpbnQgaSwgdmFsLCBzaXplOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJaW50IHJldCA9
IDA7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJdW5zaWduZWQgY2hhciBlcF90eXBlOw0KPj4NCj4+
Pj4NCj4+DQo+Pj4+Pg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJZGV2X2RiZyhoc290Zy0+ZGV2LA0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiAJCSIlczogZXAgJXM6IGEgMHglMDJ4LCBhdHRyIDB4JTAyeCwg
bXBzIDB4JTA0eCwgaW50ciAlZFxuIiwNCj5AQA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtMzgwOSw2
ICszNzkyLDE1IEBAIHN0YXRpYyBpbnQgZHdjMl9oc290Z19lcF9lbmFibGUoc3RydWN0IHVzYl9l
cA0KPiplcCwNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCQlyZXR1cm4gLUVJTlZBTDsNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gCX0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4g
KwllcF90eXBlID0gZGVzYy0+Ym1BdHRyaWJ1dGVzICYgVVNCX0VORFBPSU5UX1hGRVJUWVBFX01B
U0s7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJLyogSVNPQyBERE1BIHN1cHBvcnRlZCBiSW50ZXJ2
YWwgdXAgdG8gMTIgKi8NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gKwlpZiAodXNpbmdfZGVzY19kbWEo
aHNvdGcpICYmIGVwX3R5cGUgPT0NCj5VU0JfRU5EUE9JTlRfWEZFUl9JU09DICYmDQo+Pg0KPj4+
Pg0KPj4NCj4+Pj4+ICsJICAgIGRpcl9pbiAmJiBkZXNjLT5iSW50ZXJ2YWwgPiAxMikgew0KPj4N
Cj4+Pj4NCj4+DQo+Pj4+PiArCQlkZXZfZXJyKGhzb3RnLT5kZXYsDQo+Pg0KPj4+Pg0KPj4NCj4+
Pj4+ICsJCQkiJXM6IElTT0MgSU46IGJJbnRlcnZhbD4xMiBub3Qgc3VwcG9ydGVkIVxuIiwgX19m
dW5jX18pOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiArCQlyZXR1cm4gLUVJTlZBTDsNCj4+DQo+Pj4+
DQo+Pg0KPj4+Pj4gKwl9DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsNCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gCW1wcyA9IHVzYl9lbmRwb2ludF9tYXhwKGRlc2MpOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJ
bWMgPSB1c2JfZW5kcG9pbnRfbWF4cF9tdWx0KGRlc2MpOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+Pg0K
Pj4NCj4+Pj4NCj4+DQo+Pj4+PiBAQCAtMzg1MiwxNCArMzg0NCwxMyBAQCBzdGF0aWMgaW50IGR3
YzJfaHNvdGdfZXBfZW5hYmxlKHN0cnVjdA0KPnVzYl9lcA0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAq
ZXAsDQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAloc19lcC0+aGFsdGVkID0gMDsNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4gCWhzX2VwLT5pbnRlcnZhbCA9IGRlc2MtPmJJbnRlcnZhbDsNCj4+DQo+Pj4+DQo+
Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gLQlzd2l0Y2ggKGRlc2MtPmJtQXR0cmlidXRl
cyAmIFVTQl9FTkRQT0lOVF9YRkVSVFlQRV9NQVNLKSB7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+ICsJ
c3dpdGNoIChlcF90eXBlKSB7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAljYXNlIFVTQl9FTkRQT0lO
VF9YRkVSX0lTT0M6DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJZXBjdHJsIHw9IERYRVBDVExfRVBU
WVBFX0lTTzsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCQllcGN0cmwgfD0gRFhFUENUTF9TRVRFVkVO
RlI7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJaHNfZXAtPmlzb2Nocm9ub3VzID0gMTsNCj4+DQo+
Pj4+DQo+Pg0KPj4+Pj4gCQloc19lcC0+aW50ZXJ2YWwgPSAxIDw8IChkZXNjLT5iSW50ZXJ2YWwg
LSAxKTsNCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gCQloc19lcC0+dGFyZ2V0X2ZyYW1lID0gVEFSR0VU
X0ZSQU1FX0lOSVRJQUw7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IC0JCWhzX2VwLT5pc29jX2NoYWlu
X251bSA9IDA7DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJaHNfZXAtPm5leHRfZGVzYyA9IDA7DQo+
Pg0KPj4+Pg0KPj4NCj4+Pj4+IAkJaWYgKGRpcl9pbikgew0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAJ
CQloc19lcC0+cGVyaW9kaWMgPSAxOw0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiAtLQ0KPj4NCj4+Pj4N
Cj4+DQo+Pj4+PiAyLjExLjANCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+
Pj4gLS0NCj4+DQo+Pj4+DQo+Pg0KPj4+Pj4gVG8gdW5zdWJzY3JpYmUgZnJvbSB0aGlzIGxpc3Q6
IHNlbmQgdGhlIGxpbmUgInVuc3Vic2NyaWJlIGxpbnV4LXVzYiIgaW4gdGhlDQo+Ym9keQ0KPj4N
Cj4+PiBvZg0KPj4NCj4+Pj4NCj4+DQo+Pj4+PiBhIG1lc3NhZ2UgdG8gbWFqb3Jkb21vQHZnZXIu
a2VybmVsLm9yZyBNb3JlIG1ham9yZG9tbyBpbmZvIGF0DQo+Pg0KPj4+Pg0KPj4NCj4+Pj4+DQo+
Pg0KPj4+DQo+aHR0cHM6Ly91cmxkZWZlbnNlLnByb29mcG9pbnQuY29tL3YyL3VybD91PWh0dHAt
M0FfX3ZnZXIua2VybmVsLm9yZ19tYWpvcmRvDQo+Pg0KPj4+DQo+bW8tMkRpbmZvLmh0bWwmZD1E
d0lHYVEmYz1EUEw2X1hfNkprWEZ4N0FYV3FCMHRnJnI9Nno5QWw5RnJIUl9acWINCj4+DQo+Pj4N
Cj5idFNBc0QxNnB2T0wyUzNYSHhRblN6cThrdXN5SSZtPWFQWFhSbUZfQ1dMakgtVXBJZWpPc3My
cXNhWVZBTU8tDQo+Pg0KPj4+IG9lU29OZDFpVG1nJnM9UnRxdUZBVjN6Y3o5NTZLSzFGaVBQV0E0
M2tKbDlJblpLcmMzaldRUjU5cyZlPQ0KPj4NCj4+Pj4NCj4+DQo+Pj4+DQo+Pg0KPj4+DQo+Pg0K
Pj4+IFRoYW5rIHlvdSBmb3IgcmV2aWV3Lg0KPj4NCj4+Pg0KPj4NCj4+PiBNaW5hcw0KPj4NCj4+
PiAtLQ0KPj4NCj4+PiBUbyB1bnN1YnNjcmliZSBmcm9tIHRoaXMgbGlzdDogc2VuZCB0aGUgbGlu
ZSAidW5zdWJzY3JpYmUgbGludXgtdXNiIiBpbg0KPj4NCj4+PiB0aGUgYm9keSBvZiBhIG1lc3Nh
Z2UgdG8gbWFqb3Jkb21vQHZnZXIua2VybmVsLm9yZw0KPj4NCj4+PiBNb3JlIG1ham9yZG9tbyBp
bmZvIGF0DQo+aHR0cHM6Ly91cmxkZWZlbnNlLnByb29mcG9pbnQuY29tL3YyL3VybD91PWh0dHAt
M0FfX3ZnZXIua2VybmVsLm9yZ19tYWpvcmRvDQo+bW8tMkRpbmZvLmh0bWwmZD1Ed0lHYVEmYz1E
UEw2X1hfNkprWEZ4N0FYV3FCMHRnJnI9Nno5QWw5RnJIUl9acWINCj5idFNBc0QxNnB2T0wyUzNY
SHhRblN6cThrdXN5SSZtPVdmR1UxazRVQlJhcDVZN2pBMkxCNlE5SlY1YjhGWE5yDQo+bWdnM1p2
blY3VjQmcz1adERERUFoYlhYUXFCYmxPU2Z3dEVETVhacVJSQzNfNndMZ0NKUkVyMkVRJmU9DQo+
Pg0KPj4NCj5UaGFua3MsDQo+TWluYXMNCg0K
---
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-21  2:17 Zengtao (B)
  0 siblings, 0 replies; 10+ messages in thread
From: Zengtao (B) @ 2018-03-21  2:17 UTC (permalink / raw)
  To: Minas Harutyunyan, John Youn, Felipe Balbi, Greg Kroah-Hartman,
	linux-usb

>-----Original Message-----
>From: linux-usb-owner@vger.kernel.org
>[mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas Harutyunyan
>Sent: Tuesday, March 20, 2018 10:40 PM
>To: Zengtao (B) <prime.zeng@hisilicon.com>; Minas Harutyunyan
><Minas.Harutyunyan@synopsys.com>; John Youn <John.Youn@synopsys.com>;
>Felipe Balbi <balbi@kernel.org>; Greg Kroah-Hartman
><gregkh@linuxfoundation.org>; linux-usb@vger.kernel.org
>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@vger.kernel.org
>>
>>> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas
>>> Harutyunyan
>>
>>> Sent: Saturday, March 17, 2018 5:10 PM
>>
>>> To: John Youn <John.Youn@synopsys.com>; Felipe Balbi
>>> <balbi@kernel.org>;
>>
>>> Greg Kroah-Hartman <gregkh@linuxfoundation.org>;
>>> linux-usb@vger.kernel.org
>>
>>> Cc: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
>>
>>> 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@synopsys.com>
>>
>>> ---
>>
>>> 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.

Per your comment, you mentioned the producer and consumer, but
How do you do the synchronization between the producer and consumer? 

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

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


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

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

>>
>>> 		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@vger.kernel.org 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@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-20 14:40 Minas Harutyunyan
  0 siblings, 0 replies; 10+ messages in thread
From: Minas Harutyunyan @ 2018-03-20 14:40 UTC (permalink / raw)
  To: Zengtao (B),
	Minas Harutyunyan, John Youn, Felipe Balbi, Greg Kroah-Hartman,
	linux-usb

Hi Zengtao,

On 3/20/2018 6:01 AM, Zengtao (B) wrote:
> Hi Minas:
> 
> 
> 
> A few minor comments:
> 
> 
> 
>> -----Original Message-----
> 
>> From: linux-usb-owner@vger.kernel.org
> 
>> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas Harutyunyan
> 
>> Sent: Saturday, March 17, 2018 5:10 PM
> 
>> To: John Youn <John.Youn@synopsys.com>; Felipe Balbi <balbi@kernel.org>;
> 
>> Greg Kroah-Hartman <gregkh@linuxfoundation.org>; linux-usb@vger.kernel.org
> 
>> Cc: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
> 
>> 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@synopsys.com>
> 
>> ---
> 
>> 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.

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

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


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

> 
> 
>> -	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.
> 
> 
>> 		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@vger.kernel.org More majordomo info at
> 
>> https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIGaQ&c=DPL6_X_6JkXFx7AXWqB0tg&r=6z9Al9FrHR_ZqbbtSAsD16pvOL2S3XHxQnSzq8kusyI&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@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-20  2:01 Zengtao (B)
  0 siblings, 0 replies; 10+ messages in thread
From: Zengtao (B) @ 2018-03-20  2:01 UTC (permalink / raw)
  To: Minas Harutyunyan, John Youn, Felipe Balbi, Greg Kroah-Hartman,
	linux-usb

Hi Minas:

A few minor comments:

>-----Original Message-----
>From: linux-usb-owner@vger.kernel.org
>[mailto:linux-usb-owner@vger.kernel.org] On Behalf Of Minas Harutyunyan
>Sent: Saturday, March 17, 2018 5:10 PM
>To: John Youn <John.Youn@synopsys.com>; Felipe Balbi <balbi@kernel.org>;
>Greg Kroah-Hartman <gregkh@linuxfoundation.org>; linux-usb@vger.kernel.org
>Cc: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
>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@synopsys.com>
>---
> 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.

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

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

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

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

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

> 		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@vger.kernel.org More majordomo info at
>http://vger.kernel.org/majordomo-info.html

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

* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-19 11:20 Minas Harutyunyan
  0 siblings, 0 replies; 10+ messages in thread
From: Minas Harutyunyan @ 2018-03-19 11:20 UTC (permalink / raw)
  To: Zengtao (B),
	Minas Harutyunyan, John Youn, Felipe Balbi, Greg Kroah-Hartman,
	linux-usb

Hi Zengtao,

You email not received by linux-usb@vger.kernel.org. I suspect it 
rejected due to your email format have some issues, violate 
linux-usb@vger.kernel.org rules. I think you received email from 
linux-usb similar to this:

<linux-usb@vger.kernel.org>: host vger.kernel.org[209.132.180.67] said: 550
     5.7.1 Content-Policy reject msg: Your message is highly unlikely to be
     accepted here BF:<H 0>; S1751783AbeCPIS1 (in reply to end of DATA 
command)

Kindly request you to correct your email and resend. I will reply you as 
soon as will be received by linux-usb and will be seen archive.
It's important that our communication archived.


Thanks,
Minas
---
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [v1,2/3] usb: dwc2: Change ISOC DDMA flow
@ 2018-03-17  9:09 Minas Harutyunyan
  0 siblings, 0 replies; 10+ messages in thread
From: Minas Harutyunyan @ 2018-03-17  9:09 UTC (permalink / raw)
  To: John Youn, Felipe Balbi, Greg Kroah-Hartman, linux-usb; +Cc: Minas Harutyunyan

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@synopsys.com>
---
 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 +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);
+	}
+
+	hs_ep->next_desc = 0;
 	list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) {
 		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__);
 		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;
 
-	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);
 		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;

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

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

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-21  8:08 [v1,2/3] usb: dwc2: Change ISOC DDMA flow Minas Harutyunyan
  -- strict thread matches above, loose matches on Subject: below --
2018-03-22 11:16 Minas Harutyunyan
2018-03-22  9:36 Zengtao (B)
2018-03-22  8:06 Minas Harutyunyan
2018-03-21 10:45 Zengtao (B)
2018-03-21  2:17 Zengtao (B)
2018-03-20 14:40 Minas Harutyunyan
2018-03-20  2:01 Zengtao (B)
2018-03-19 11:20 Minas Harutyunyan
2018-03-17  9: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.