162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * hcd_ddma.c - DesignWare HS OTG Controller descriptor DMA routines
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * This file contains the Descriptor DMA implementation for Host mode
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/spinlock.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1662306a36Sopenharmony_ci#include <linux/io.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/usb.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/usb/hcd.h>
2162306a36Sopenharmony_ci#include <linux/usb/ch11.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "core.h"
2462306a36Sopenharmony_ci#include "hcd.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic u16 dwc2_frame_list_idx(u16 frame)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	return frame & (FRLISTEN_64_SIZE - 1);
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic u16 dwc2_desclist_idx_inc(u16 idx, u16 inc, u8 speed)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	return (idx + inc) &
3462306a36Sopenharmony_ci		((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC :
3562306a36Sopenharmony_ci		  MAX_DMA_DESC_NUM_GENERIC) - 1);
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic u16 dwc2_desclist_idx_dec(u16 idx, u16 inc, u8 speed)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	return (idx - inc) &
4162306a36Sopenharmony_ci		((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC :
4262306a36Sopenharmony_ci		  MAX_DMA_DESC_NUM_GENERIC) - 1);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic u16 dwc2_max_desc_num(struct dwc2_qh *qh)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	return (qh->ep_type == USB_ENDPOINT_XFER_ISOC &&
4862306a36Sopenharmony_ci		qh->dev_speed == USB_SPEED_HIGH) ?
4962306a36Sopenharmony_ci		MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic u16 dwc2_frame_incr_val(struct dwc2_qh *qh)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	return qh->dev_speed == USB_SPEED_HIGH ?
5562306a36Sopenharmony_ci	       (qh->host_interval + 8 - 1) / 8 : qh->host_interval;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
5962306a36Sopenharmony_ci				gfp_t flags)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct kmem_cache *desc_cache;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (qh->ep_type == USB_ENDPOINT_XFER_ISOC &&
6462306a36Sopenharmony_ci	    qh->dev_speed == USB_SPEED_HIGH)
6562306a36Sopenharmony_ci		desc_cache = hsotg->desc_hsisoc_cache;
6662306a36Sopenharmony_ci	else
6762306a36Sopenharmony_ci		desc_cache = hsotg->desc_gen_cache;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	qh->desc_list_sz = sizeof(struct dwc2_dma_desc) *
7062306a36Sopenharmony_ci						dwc2_max_desc_num(qh);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	qh->desc_list = kmem_cache_zalloc(desc_cache, flags | GFP_DMA);
7362306a36Sopenharmony_ci	if (!qh->desc_list)
7462306a36Sopenharmony_ci		return -ENOMEM;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	qh->desc_list_dma = dma_map_single(hsotg->dev, qh->desc_list,
7762306a36Sopenharmony_ci					   qh->desc_list_sz,
7862306a36Sopenharmony_ci					   DMA_TO_DEVICE);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	qh->n_bytes = kcalloc(dwc2_max_desc_num(qh), sizeof(u32), flags);
8162306a36Sopenharmony_ci	if (!qh->n_bytes) {
8262306a36Sopenharmony_ci		dma_unmap_single(hsotg->dev, qh->desc_list_dma,
8362306a36Sopenharmony_ci				 qh->desc_list_sz,
8462306a36Sopenharmony_ci				 DMA_FROM_DEVICE);
8562306a36Sopenharmony_ci		kmem_cache_free(desc_cache, qh->desc_list);
8662306a36Sopenharmony_ci		qh->desc_list = NULL;
8762306a36Sopenharmony_ci		return -ENOMEM;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return 0;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct kmem_cache *desc_cache;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (qh->ep_type == USB_ENDPOINT_XFER_ISOC &&
9862306a36Sopenharmony_ci	    qh->dev_speed == USB_SPEED_HIGH)
9962306a36Sopenharmony_ci		desc_cache = hsotg->desc_hsisoc_cache;
10062306a36Sopenharmony_ci	else
10162306a36Sopenharmony_ci		desc_cache = hsotg->desc_gen_cache;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (qh->desc_list) {
10462306a36Sopenharmony_ci		dma_unmap_single(hsotg->dev, qh->desc_list_dma,
10562306a36Sopenharmony_ci				 qh->desc_list_sz, DMA_FROM_DEVICE);
10662306a36Sopenharmony_ci		kmem_cache_free(desc_cache, qh->desc_list);
10762306a36Sopenharmony_ci		qh->desc_list = NULL;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	kfree(qh->n_bytes);
11162306a36Sopenharmony_ci	qh->n_bytes = NULL;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic int dwc2_frame_list_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	if (hsotg->frame_list)
11762306a36Sopenharmony_ci		return 0;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	hsotg->frame_list_sz = 4 * FRLISTEN_64_SIZE;
12062306a36Sopenharmony_ci	hsotg->frame_list = kzalloc(hsotg->frame_list_sz, GFP_ATOMIC | GFP_DMA);
12162306a36Sopenharmony_ci	if (!hsotg->frame_list)
12262306a36Sopenharmony_ci		return -ENOMEM;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	hsotg->frame_list_dma = dma_map_single(hsotg->dev, hsotg->frame_list,
12562306a36Sopenharmony_ci					       hsotg->frame_list_sz,
12662306a36Sopenharmony_ci					       DMA_TO_DEVICE);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return 0;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic void dwc2_frame_list_free(struct dwc2_hsotg *hsotg)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	unsigned long flags;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (!hsotg->frame_list) {
13862306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
13962306a36Sopenharmony_ci		return;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	dma_unmap_single(hsotg->dev, hsotg->frame_list_dma,
14362306a36Sopenharmony_ci			 hsotg->frame_list_sz, DMA_FROM_DEVICE);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	kfree(hsotg->frame_list);
14662306a36Sopenharmony_ci	hsotg->frame_list = NULL;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	u32 hcfg;
15462306a36Sopenharmony_ci	unsigned long flags;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	hcfg = dwc2_readl(hsotg, HCFG);
15962306a36Sopenharmony_ci	if (hcfg & HCFG_PERSCHEDENA) {
16062306a36Sopenharmony_ci		/* already enabled */
16162306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
16262306a36Sopenharmony_ci		return;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	dwc2_writel(hsotg, hsotg->frame_list_dma, HFLBADDR);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	hcfg &= ~HCFG_FRLISTEN_MASK;
16862306a36Sopenharmony_ci	hcfg |= fr_list_en | HCFG_PERSCHEDENA;
16962306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n");
17062306a36Sopenharmony_ci	dwc2_writel(hsotg, hcfg, HCFG);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	u32 hcfg;
17862306a36Sopenharmony_ci	unsigned long flags;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	hcfg = dwc2_readl(hsotg, HCFG);
18362306a36Sopenharmony_ci	if (!(hcfg & HCFG_PERSCHEDENA)) {
18462306a36Sopenharmony_ci		/* already disabled */
18562306a36Sopenharmony_ci		spin_unlock_irqrestore(&hsotg->lock, flags);
18662306a36Sopenharmony_ci		return;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	hcfg &= ~HCFG_PERSCHEDENA;
19062306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n");
19162306a36Sopenharmony_ci	dwc2_writel(hsotg, hcfg, HCFG);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/*
19762306a36Sopenharmony_ci * Activates/Deactivates FrameList entries for the channel based on endpoint
19862306a36Sopenharmony_ci * servicing period
19962306a36Sopenharmony_ci */
20062306a36Sopenharmony_cistatic void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
20162306a36Sopenharmony_ci				   int enable)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct dwc2_host_chan *chan;
20462306a36Sopenharmony_ci	u16 i, j, inc;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (!hsotg) {
20762306a36Sopenharmony_ci		pr_err("hsotg = %p\n", hsotg);
20862306a36Sopenharmony_ci		return;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (!qh->channel) {
21262306a36Sopenharmony_ci		dev_err(hsotg->dev, "qh->channel = %p\n", qh->channel);
21362306a36Sopenharmony_ci		return;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (!hsotg->frame_list) {
21762306a36Sopenharmony_ci		dev_err(hsotg->dev, "hsotg->frame_list = %p\n",
21862306a36Sopenharmony_ci			hsotg->frame_list);
21962306a36Sopenharmony_ci		return;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	chan = qh->channel;
22362306a36Sopenharmony_ci	inc = dwc2_frame_incr_val(qh);
22462306a36Sopenharmony_ci	if (qh->ep_type == USB_ENDPOINT_XFER_ISOC)
22562306a36Sopenharmony_ci		i = dwc2_frame_list_idx(qh->next_active_frame);
22662306a36Sopenharmony_ci	else
22762306a36Sopenharmony_ci		i = 0;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	j = i;
23062306a36Sopenharmony_ci	do {
23162306a36Sopenharmony_ci		if (enable)
23262306a36Sopenharmony_ci			hsotg->frame_list[j] |= 1 << chan->hc_num;
23362306a36Sopenharmony_ci		else
23462306a36Sopenharmony_ci			hsotg->frame_list[j] &= ~(1 << chan->hc_num);
23562306a36Sopenharmony_ci		j = (j + inc) & (FRLISTEN_64_SIZE - 1);
23662306a36Sopenharmony_ci	} while (j != i);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/*
23962306a36Sopenharmony_ci	 * Sync frame list since controller will access it if periodic
24062306a36Sopenharmony_ci	 * channel is currently enabled.
24162306a36Sopenharmony_ci	 */
24262306a36Sopenharmony_ci	dma_sync_single_for_device(hsotg->dev,
24362306a36Sopenharmony_ci				   hsotg->frame_list_dma,
24462306a36Sopenharmony_ci				   hsotg->frame_list_sz,
24562306a36Sopenharmony_ci				   DMA_TO_DEVICE);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (!enable)
24862306a36Sopenharmony_ci		return;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	chan->schinfo = 0;
25162306a36Sopenharmony_ci	if (chan->speed == USB_SPEED_HIGH && qh->host_interval) {
25262306a36Sopenharmony_ci		j = 1;
25362306a36Sopenharmony_ci		/* TODO - check this */
25462306a36Sopenharmony_ci		inc = (8 + qh->host_interval - 1) / qh->host_interval;
25562306a36Sopenharmony_ci		for (i = 0; i < inc; i++) {
25662306a36Sopenharmony_ci			chan->schinfo |= j;
25762306a36Sopenharmony_ci			j = j << qh->host_interval;
25862306a36Sopenharmony_ci		}
25962306a36Sopenharmony_ci	} else {
26062306a36Sopenharmony_ci		chan->schinfo = 0xff;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg,
26562306a36Sopenharmony_ci				      struct dwc2_qh *qh)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct dwc2_host_chan *chan = qh->channel;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (dwc2_qh_is_non_per(qh)) {
27062306a36Sopenharmony_ci		if (hsotg->params.uframe_sched)
27162306a36Sopenharmony_ci			hsotg->available_host_channels++;
27262306a36Sopenharmony_ci		else
27362306a36Sopenharmony_ci			hsotg->non_periodic_channels--;
27462306a36Sopenharmony_ci	} else {
27562306a36Sopenharmony_ci		dwc2_update_frame_list(hsotg, qh, 0);
27662306a36Sopenharmony_ci		hsotg->available_host_channels++;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/*
28062306a36Sopenharmony_ci	 * The condition is added to prevent double cleanup try in case of
28162306a36Sopenharmony_ci	 * device disconnect. See channel cleanup in dwc2_hcd_disconnect().
28262306a36Sopenharmony_ci	 */
28362306a36Sopenharmony_ci	if (chan->qh) {
28462306a36Sopenharmony_ci		if (!list_empty(&chan->hc_list_entry))
28562306a36Sopenharmony_ci			list_del(&chan->hc_list_entry);
28662306a36Sopenharmony_ci		dwc2_hc_cleanup(hsotg, chan);
28762306a36Sopenharmony_ci		list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
28862306a36Sopenharmony_ci		chan->qh = NULL;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	qh->channel = NULL;
29262306a36Sopenharmony_ci	qh->ntd = 0;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (qh->desc_list)
29562306a36Sopenharmony_ci		memset(qh->desc_list, 0, sizeof(struct dwc2_dma_desc) *
29662306a36Sopenharmony_ci		       dwc2_max_desc_num(qh));
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/**
30062306a36Sopenharmony_ci * dwc2_hcd_qh_init_ddma() - Initializes a QH structure's Descriptor DMA
30162306a36Sopenharmony_ci * related members
30262306a36Sopenharmony_ci *
30362306a36Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
30462306a36Sopenharmony_ci * @qh:    The QH to init
30562306a36Sopenharmony_ci * @mem_flags: Indicates the type of memory allocation
30662306a36Sopenharmony_ci *
30762306a36Sopenharmony_ci * Return: 0 if successful, negative error code otherwise
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Allocates memory for the descriptor list. For the first periodic QH,
31062306a36Sopenharmony_ci * allocates memory for the FrameList and enables periodic scheduling.
31162306a36Sopenharmony_ci */
31262306a36Sopenharmony_ciint dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
31362306a36Sopenharmony_ci			  gfp_t mem_flags)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	int retval;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (qh->do_split) {
31862306a36Sopenharmony_ci		dev_err(hsotg->dev,
31962306a36Sopenharmony_ci			"SPLIT Transfers are not supported in Descriptor DMA mode.\n");
32062306a36Sopenharmony_ci		retval = -EINVAL;
32162306a36Sopenharmony_ci		goto err0;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	retval = dwc2_desc_list_alloc(hsotg, qh, mem_flags);
32562306a36Sopenharmony_ci	if (retval)
32662306a36Sopenharmony_ci		goto err0;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
32962306a36Sopenharmony_ci	    qh->ep_type == USB_ENDPOINT_XFER_INT) {
33062306a36Sopenharmony_ci		if (!hsotg->frame_list) {
33162306a36Sopenharmony_ci			retval = dwc2_frame_list_alloc(hsotg, mem_flags);
33262306a36Sopenharmony_ci			if (retval)
33362306a36Sopenharmony_ci				goto err1;
33462306a36Sopenharmony_ci			/* Enable periodic schedule on first periodic QH */
33562306a36Sopenharmony_ci			dwc2_per_sched_enable(hsotg, HCFG_FRLISTEN_64);
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	qh->ntd = 0;
34062306a36Sopenharmony_ci	return 0;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cierr1:
34362306a36Sopenharmony_ci	dwc2_desc_list_free(hsotg, qh);
34462306a36Sopenharmony_cierr0:
34562306a36Sopenharmony_ci	return retval;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/**
34962306a36Sopenharmony_ci * dwc2_hcd_qh_free_ddma() - Frees a QH structure's Descriptor DMA related
35062306a36Sopenharmony_ci * members
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
35362306a36Sopenharmony_ci * @qh:    The QH to free
35462306a36Sopenharmony_ci *
35562306a36Sopenharmony_ci * Frees descriptor list memory associated with the QH. If QH is periodic and
35662306a36Sopenharmony_ci * the last, frees FrameList memory and disables periodic scheduling.
35762306a36Sopenharmony_ci */
35862306a36Sopenharmony_civoid dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	unsigned long flags;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	dwc2_desc_list_free(hsotg, qh);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/*
36562306a36Sopenharmony_ci	 * Channel still assigned due to some reasons.
36662306a36Sopenharmony_ci	 * Seen on Isoc URB dequeue. Channel halted but no subsequent
36762306a36Sopenharmony_ci	 * ChHalted interrupt to release the channel. Afterwards
36862306a36Sopenharmony_ci	 * when it comes here from endpoint disable routine
36962306a36Sopenharmony_ci	 * channel remains assigned.
37062306a36Sopenharmony_ci	 */
37162306a36Sopenharmony_ci	spin_lock_irqsave(&hsotg->lock, flags);
37262306a36Sopenharmony_ci	if (qh->channel)
37362306a36Sopenharmony_ci		dwc2_release_channel_ddma(hsotg, qh);
37462306a36Sopenharmony_ci	spin_unlock_irqrestore(&hsotg->lock, flags);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
37762306a36Sopenharmony_ci	     qh->ep_type == USB_ENDPOINT_XFER_INT) &&
37862306a36Sopenharmony_ci	    (hsotg->params.uframe_sched ||
37962306a36Sopenharmony_ci	     !hsotg->periodic_channels) && hsotg->frame_list) {
38062306a36Sopenharmony_ci		dwc2_per_sched_disable(hsotg);
38162306a36Sopenharmony_ci		dwc2_frame_list_free(hsotg);
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic u8 dwc2_frame_to_desc_idx(struct dwc2_qh *qh, u16 frame_idx)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	if (qh->dev_speed == USB_SPEED_HIGH)
38862306a36Sopenharmony_ci		/* Descriptor set (8 descriptors) index which is 8-aligned */
38962306a36Sopenharmony_ci		return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
39062306a36Sopenharmony_ci	else
39162306a36Sopenharmony_ci		return frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci/*
39562306a36Sopenharmony_ci * Determine starting frame for Isochronous transfer.
39662306a36Sopenharmony_ci * Few frames skipped to prevent race condition with HC.
39762306a36Sopenharmony_ci */
39862306a36Sopenharmony_cistatic u16 dwc2_calc_starting_frame(struct dwc2_hsotg *hsotg,
39962306a36Sopenharmony_ci				    struct dwc2_qh *qh, u16 *skip_frames)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	u16 frame;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/*
40662306a36Sopenharmony_ci	 * next_active_frame is always frame number (not uFrame) both in FS
40762306a36Sopenharmony_ci	 * and HS!
40862306a36Sopenharmony_ci	 */
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/*
41162306a36Sopenharmony_ci	 * skip_frames is used to limit activated descriptors number
41262306a36Sopenharmony_ci	 * to avoid the situation when HC services the last activated
41362306a36Sopenharmony_ci	 * descriptor firstly.
41462306a36Sopenharmony_ci	 * Example for FS:
41562306a36Sopenharmony_ci	 * Current frame is 1, scheduled frame is 3. Since HC always fetches
41662306a36Sopenharmony_ci	 * the descriptor corresponding to curr_frame+1, the descriptor
41762306a36Sopenharmony_ci	 * corresponding to frame 2 will be fetched. If the number of
41862306a36Sopenharmony_ci	 * descriptors is max=64 (or greather) the list will be fully programmed
41962306a36Sopenharmony_ci	 * with Active descriptors and it is possible case (rare) that the
42062306a36Sopenharmony_ci	 * latest descriptor(considering rollback) corresponding to frame 2 will
42162306a36Sopenharmony_ci	 * be serviced first. HS case is more probable because, in fact, up to
42262306a36Sopenharmony_ci	 * 11 uframes (16 in the code) may be skipped.
42362306a36Sopenharmony_ci	 */
42462306a36Sopenharmony_ci	if (qh->dev_speed == USB_SPEED_HIGH) {
42562306a36Sopenharmony_ci		/*
42662306a36Sopenharmony_ci		 * Consider uframe counter also, to start xfer asap. If half of
42762306a36Sopenharmony_ci		 * the frame elapsed skip 2 frames otherwise just 1 frame.
42862306a36Sopenharmony_ci		 * Starting descriptor index must be 8-aligned, so if the
42962306a36Sopenharmony_ci		 * current frame is near to complete the next one is skipped as
43062306a36Sopenharmony_ci		 * well.
43162306a36Sopenharmony_ci		 */
43262306a36Sopenharmony_ci		if (dwc2_micro_frame_num(hsotg->frame_number) >= 5) {
43362306a36Sopenharmony_ci			*skip_frames = 2 * 8;
43462306a36Sopenharmony_ci			frame = dwc2_frame_num_inc(hsotg->frame_number,
43562306a36Sopenharmony_ci						   *skip_frames);
43662306a36Sopenharmony_ci		} else {
43762306a36Sopenharmony_ci			*skip_frames = 1 * 8;
43862306a36Sopenharmony_ci			frame = dwc2_frame_num_inc(hsotg->frame_number,
43962306a36Sopenharmony_ci						   *skip_frames);
44062306a36Sopenharmony_ci		}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		frame = dwc2_full_frame_num(frame);
44362306a36Sopenharmony_ci	} else {
44462306a36Sopenharmony_ci		/*
44562306a36Sopenharmony_ci		 * Two frames are skipped for FS - the current and the next.
44662306a36Sopenharmony_ci		 * But for descriptor programming, 1 frame (descriptor) is
44762306a36Sopenharmony_ci		 * enough, see example above.
44862306a36Sopenharmony_ci		 */
44962306a36Sopenharmony_ci		*skip_frames = 1;
45062306a36Sopenharmony_ci		frame = dwc2_frame_num_inc(hsotg->frame_number, 2);
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	return frame;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci/*
45762306a36Sopenharmony_ci * Calculate initial descriptor index for isochronous transfer based on
45862306a36Sopenharmony_ci * scheduled frame
45962306a36Sopenharmony_ci */
46062306a36Sopenharmony_cistatic u16 dwc2_recalc_initial_desc_idx(struct dwc2_hsotg *hsotg,
46162306a36Sopenharmony_ci					struct dwc2_qh *qh)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	u16 frame, fr_idx, fr_idx_tmp, skip_frames;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/*
46662306a36Sopenharmony_ci	 * With current ISOC processing algorithm the channel is being released
46762306a36Sopenharmony_ci	 * when no more QTDs in the list (qh->ntd == 0). Thus this function is
46862306a36Sopenharmony_ci	 * called only when qh->ntd == 0 and qh->channel == 0.
46962306a36Sopenharmony_ci	 *
47062306a36Sopenharmony_ci	 * So qh->channel != NULL branch is not used and just not removed from
47162306a36Sopenharmony_ci	 * the source file. It is required for another possible approach which
47262306a36Sopenharmony_ci	 * is, do not disable and release the channel when ISOC session
47362306a36Sopenharmony_ci	 * completed, just move QH to inactive schedule until new QTD arrives.
47462306a36Sopenharmony_ci	 * On new QTD, the QH moved back to 'ready' schedule, starting frame and
47562306a36Sopenharmony_ci	 * therefore starting desc_index are recalculated. In this case channel
47662306a36Sopenharmony_ci	 * is released only on ep_disable.
47762306a36Sopenharmony_ci	 */
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/*
48062306a36Sopenharmony_ci	 * Calculate starting descriptor index. For INTERRUPT endpoint it is
48162306a36Sopenharmony_ci	 * always 0.
48262306a36Sopenharmony_ci	 */
48362306a36Sopenharmony_ci	if (qh->channel) {
48462306a36Sopenharmony_ci		frame = dwc2_calc_starting_frame(hsotg, qh, &skip_frames);
48562306a36Sopenharmony_ci		/*
48662306a36Sopenharmony_ci		 * Calculate initial descriptor index based on FrameList current
48762306a36Sopenharmony_ci		 * bitmap and servicing period
48862306a36Sopenharmony_ci		 */
48962306a36Sopenharmony_ci		fr_idx_tmp = dwc2_frame_list_idx(frame);
49062306a36Sopenharmony_ci		fr_idx = (FRLISTEN_64_SIZE +
49162306a36Sopenharmony_ci			  dwc2_frame_list_idx(qh->next_active_frame) -
49262306a36Sopenharmony_ci			  fr_idx_tmp) % dwc2_frame_incr_val(qh);
49362306a36Sopenharmony_ci		fr_idx = (fr_idx + fr_idx_tmp) % FRLISTEN_64_SIZE;
49462306a36Sopenharmony_ci	} else {
49562306a36Sopenharmony_ci		qh->next_active_frame = dwc2_calc_starting_frame(hsotg, qh,
49662306a36Sopenharmony_ci							   &skip_frames);
49762306a36Sopenharmony_ci		fr_idx = dwc2_frame_list_idx(qh->next_active_frame);
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	qh->td_first = qh->td_last = dwc2_frame_to_desc_idx(qh, fr_idx);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	return skip_frames;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci#define ISOC_URB_GIVEBACK_ASAP
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci#define MAX_ISOC_XFER_SIZE_FS	1023
50862306a36Sopenharmony_ci#define MAX_ISOC_XFER_SIZE_HS	3072
50962306a36Sopenharmony_ci#define DESCNUM_THRESHOLD	4
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
51262306a36Sopenharmony_ci					 struct dwc2_qtd *qtd,
51362306a36Sopenharmony_ci					 struct dwc2_qh *qh, u32 max_xfer_size,
51462306a36Sopenharmony_ci					 u16 idx)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct dwc2_dma_desc *dma_desc = &qh->desc_list[idx];
51762306a36Sopenharmony_ci	struct dwc2_hcd_iso_packet_desc *frame_desc;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	memset(dma_desc, 0, sizeof(*dma_desc));
52062306a36Sopenharmony_ci	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (frame_desc->length > max_xfer_size)
52362306a36Sopenharmony_ci		qh->n_bytes[idx] = max_xfer_size;
52462306a36Sopenharmony_ci	else
52562306a36Sopenharmony_ci		qh->n_bytes[idx] = frame_desc->length;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
52862306a36Sopenharmony_ci	dma_desc->status = qh->n_bytes[idx] << HOST_DMA_ISOC_NBYTES_SHIFT &
52962306a36Sopenharmony_ci			   HOST_DMA_ISOC_NBYTES_MASK;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* Set active bit */
53262306a36Sopenharmony_ci	dma_desc->status |= HOST_DMA_A;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	qh->ntd++;
53562306a36Sopenharmony_ci	qtd->isoc_frame_index_last++;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci#ifdef ISOC_URB_GIVEBACK_ASAP
53862306a36Sopenharmony_ci	/* Set IOC for each descriptor corresponding to last frame of URB */
53962306a36Sopenharmony_ci	if (qtd->isoc_frame_index_last == qtd->urb->packet_count)
54062306a36Sopenharmony_ci		dma_desc->status |= HOST_DMA_IOC;
54162306a36Sopenharmony_ci#endif
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	dma_sync_single_for_device(hsotg->dev,
54462306a36Sopenharmony_ci				   qh->desc_list_dma +
54562306a36Sopenharmony_ci			(idx * sizeof(struct dwc2_dma_desc)),
54662306a36Sopenharmony_ci			sizeof(struct dwc2_dma_desc),
54762306a36Sopenharmony_ci			DMA_TO_DEVICE);
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
55162306a36Sopenharmony_ci				    struct dwc2_qh *qh, u16 skip_frames)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct dwc2_qtd *qtd;
55462306a36Sopenharmony_ci	u32 max_xfer_size;
55562306a36Sopenharmony_ci	u16 idx, inc, n_desc = 0, ntd_max = 0;
55662306a36Sopenharmony_ci	u16 cur_idx;
55762306a36Sopenharmony_ci	u16 next_idx;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	idx = qh->td_last;
56062306a36Sopenharmony_ci	inc = qh->host_interval;
56162306a36Sopenharmony_ci	hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
56262306a36Sopenharmony_ci	cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
56362306a36Sopenharmony_ci	next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/*
56662306a36Sopenharmony_ci	 * Ensure current frame number didn't overstep last scheduled
56762306a36Sopenharmony_ci	 * descriptor. If it happens, the only way to recover is to move
56862306a36Sopenharmony_ci	 * qh->td_last to current frame number + 1.
56962306a36Sopenharmony_ci	 * So that next isoc descriptor will be scheduled on frame number + 1
57062306a36Sopenharmony_ci	 * and not on a past frame.
57162306a36Sopenharmony_ci	 */
57262306a36Sopenharmony_ci	if (dwc2_frame_idx_num_gt(cur_idx, next_idx) || (cur_idx == next_idx)) {
57362306a36Sopenharmony_ci		if (inc < 32) {
57462306a36Sopenharmony_ci			dev_vdbg(hsotg->dev,
57562306a36Sopenharmony_ci				 "current frame number overstep last descriptor\n");
57662306a36Sopenharmony_ci			qh->td_last = dwc2_desclist_idx_inc(cur_idx, inc,
57762306a36Sopenharmony_ci							    qh->dev_speed);
57862306a36Sopenharmony_ci			idx = qh->td_last;
57962306a36Sopenharmony_ci		}
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (qh->host_interval) {
58362306a36Sopenharmony_ci		ntd_max = (dwc2_max_desc_num(qh) + qh->host_interval - 1) /
58462306a36Sopenharmony_ci				qh->host_interval;
58562306a36Sopenharmony_ci		if (skip_frames && !qh->channel)
58662306a36Sopenharmony_ci			ntd_max -= skip_frames / qh->host_interval;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	max_xfer_size = qh->dev_speed == USB_SPEED_HIGH ?
59062306a36Sopenharmony_ci			MAX_ISOC_XFER_SIZE_HS : MAX_ISOC_XFER_SIZE_FS;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
59362306a36Sopenharmony_ci		if (qtd->in_process &&
59462306a36Sopenharmony_ci		    qtd->isoc_frame_index_last ==
59562306a36Sopenharmony_ci		    qtd->urb->packet_count)
59662306a36Sopenharmony_ci			continue;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci		qtd->isoc_td_first = idx;
59962306a36Sopenharmony_ci		while (qh->ntd < ntd_max && qtd->isoc_frame_index_last <
60062306a36Sopenharmony_ci						qtd->urb->packet_count) {
60162306a36Sopenharmony_ci			dwc2_fill_host_isoc_dma_desc(hsotg, qtd, qh,
60262306a36Sopenharmony_ci						     max_xfer_size, idx);
60362306a36Sopenharmony_ci			idx = dwc2_desclist_idx_inc(idx, inc, qh->dev_speed);
60462306a36Sopenharmony_ci			n_desc++;
60562306a36Sopenharmony_ci		}
60662306a36Sopenharmony_ci		qtd->isoc_td_last = idx;
60762306a36Sopenharmony_ci		qtd->in_process = 1;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	qh->td_last = idx;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci#ifdef ISOC_URB_GIVEBACK_ASAP
61362306a36Sopenharmony_ci	/* Set IOC for last descriptor if descriptor list is full */
61462306a36Sopenharmony_ci	if (qh->ntd == ntd_max) {
61562306a36Sopenharmony_ci		idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
61662306a36Sopenharmony_ci		qh->desc_list[idx].status |= HOST_DMA_IOC;
61762306a36Sopenharmony_ci		dma_sync_single_for_device(hsotg->dev,
61862306a36Sopenharmony_ci					   qh->desc_list_dma + (idx *
61962306a36Sopenharmony_ci					   sizeof(struct dwc2_dma_desc)),
62062306a36Sopenharmony_ci					   sizeof(struct dwc2_dma_desc),
62162306a36Sopenharmony_ci					   DMA_TO_DEVICE);
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci#else
62462306a36Sopenharmony_ci	/*
62562306a36Sopenharmony_ci	 * Set IOC bit only for one descriptor. Always try to be ahead of HW
62662306a36Sopenharmony_ci	 * processing, i.e. on IOC generation driver activates next descriptor
62762306a36Sopenharmony_ci	 * but core continues to process descriptors following the one with IOC
62862306a36Sopenharmony_ci	 * set.
62962306a36Sopenharmony_ci	 */
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (n_desc > DESCNUM_THRESHOLD)
63262306a36Sopenharmony_ci		/*
63362306a36Sopenharmony_ci		 * Move IOC "up". Required even if there is only one QTD
63462306a36Sopenharmony_ci		 * in the list, because QTDs might continue to be queued,
63562306a36Sopenharmony_ci		 * but during the activation it was only one queued.
63662306a36Sopenharmony_ci		 * Actually more than one QTD might be in the list if this
63762306a36Sopenharmony_ci		 * function called from XferCompletion - QTDs was queued during
63862306a36Sopenharmony_ci		 * HW processing of the previous descriptor chunk.
63962306a36Sopenharmony_ci		 */
64062306a36Sopenharmony_ci		idx = dwc2_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2),
64162306a36Sopenharmony_ci					    qh->dev_speed);
64262306a36Sopenharmony_ci	else
64362306a36Sopenharmony_ci		/*
64462306a36Sopenharmony_ci		 * Set the IOC for the latest descriptor if either number of
64562306a36Sopenharmony_ci		 * descriptors is not greater than threshold or no more new
64662306a36Sopenharmony_ci		 * descriptors activated
64762306a36Sopenharmony_ci		 */
64862306a36Sopenharmony_ci		idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	qh->desc_list[idx].status |= HOST_DMA_IOC;
65162306a36Sopenharmony_ci	dma_sync_single_for_device(hsotg->dev,
65262306a36Sopenharmony_ci				   qh->desc_list_dma +
65362306a36Sopenharmony_ci				   (idx * sizeof(struct dwc2_dma_desc)),
65462306a36Sopenharmony_ci				   sizeof(struct dwc2_dma_desc),
65562306a36Sopenharmony_ci				   DMA_TO_DEVICE);
65662306a36Sopenharmony_ci#endif
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg,
66062306a36Sopenharmony_ci				    struct dwc2_host_chan *chan,
66162306a36Sopenharmony_ci				    struct dwc2_qtd *qtd, struct dwc2_qh *qh,
66262306a36Sopenharmony_ci				    int n_desc)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	struct dwc2_dma_desc *dma_desc = &qh->desc_list[n_desc];
66562306a36Sopenharmony_ci	int len = chan->xfer_len;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	if (len > HOST_DMA_NBYTES_LIMIT - (chan->max_packet - 1))
66862306a36Sopenharmony_ci		len = HOST_DMA_NBYTES_LIMIT - (chan->max_packet - 1);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	if (chan->ep_is_in) {
67162306a36Sopenharmony_ci		int num_packets;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		if (len > 0 && chan->max_packet)
67462306a36Sopenharmony_ci			num_packets = (len + chan->max_packet - 1)
67562306a36Sopenharmony_ci					/ chan->max_packet;
67662306a36Sopenharmony_ci		else
67762306a36Sopenharmony_ci			/* Need 1 packet for transfer length of 0 */
67862306a36Sopenharmony_ci			num_packets = 1;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		/* Always program an integral # of packets for IN transfers */
68162306a36Sopenharmony_ci		len = num_packets * chan->max_packet;
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	dma_desc->status = len << HOST_DMA_NBYTES_SHIFT & HOST_DMA_NBYTES_MASK;
68562306a36Sopenharmony_ci	qh->n_bytes[n_desc] = len;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL &&
68862306a36Sopenharmony_ci	    qtd->control_phase == DWC2_CONTROL_SETUP)
68962306a36Sopenharmony_ci		dma_desc->status |= HOST_DMA_SUP;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	dma_desc->buf = (u32)chan->xfer_dma;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	dma_sync_single_for_device(hsotg->dev,
69462306a36Sopenharmony_ci				   qh->desc_list_dma +
69562306a36Sopenharmony_ci				   (n_desc * sizeof(struct dwc2_dma_desc)),
69662306a36Sopenharmony_ci				   sizeof(struct dwc2_dma_desc),
69762306a36Sopenharmony_ci				   DMA_TO_DEVICE);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/*
70062306a36Sopenharmony_ci	 * Last (or only) descriptor of IN transfer with actual size less
70162306a36Sopenharmony_ci	 * than MaxPacket
70262306a36Sopenharmony_ci	 */
70362306a36Sopenharmony_ci	if (len > chan->xfer_len) {
70462306a36Sopenharmony_ci		chan->xfer_len = 0;
70562306a36Sopenharmony_ci	} else {
70662306a36Sopenharmony_ci		chan->xfer_dma += len;
70762306a36Sopenharmony_ci		chan->xfer_len -= len;
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg,
71262306a36Sopenharmony_ci					struct dwc2_qh *qh)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct dwc2_qtd *qtd;
71562306a36Sopenharmony_ci	struct dwc2_host_chan *chan = qh->channel;
71662306a36Sopenharmony_ci	int n_desc = 0;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "%s(): qh=%p dma=%08lx len=%d\n", __func__, qh,
71962306a36Sopenharmony_ci		 (unsigned long)chan->xfer_dma, chan->xfer_len);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	/*
72262306a36Sopenharmony_ci	 * Start with chan->xfer_dma initialized in assign_and_init_hc(), then
72362306a36Sopenharmony_ci	 * if SG transfer consists of multiple URBs, this pointer is re-assigned
72462306a36Sopenharmony_ci	 * to the buffer of the currently processed QTD. For non-SG request
72562306a36Sopenharmony_ci	 * there is always one QTD active.
72662306a36Sopenharmony_ci	 */
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
72962306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "qtd=%p\n", qtd);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		if (n_desc) {
73262306a36Sopenharmony_ci			/* SG request - more than 1 QTD */
73362306a36Sopenharmony_ci			chan->xfer_dma = qtd->urb->dma +
73462306a36Sopenharmony_ci					qtd->urb->actual_length;
73562306a36Sopenharmony_ci			chan->xfer_len = qtd->urb->length -
73662306a36Sopenharmony_ci					qtd->urb->actual_length;
73762306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "buf=%08lx len=%d\n",
73862306a36Sopenharmony_ci				 (unsigned long)chan->xfer_dma, chan->xfer_len);
73962306a36Sopenharmony_ci		}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci		qtd->n_desc = 0;
74262306a36Sopenharmony_ci		do {
74362306a36Sopenharmony_ci			if (n_desc > 1) {
74462306a36Sopenharmony_ci				qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
74562306a36Sopenharmony_ci				dev_vdbg(hsotg->dev,
74662306a36Sopenharmony_ci					 "set A bit in desc %d (%p)\n",
74762306a36Sopenharmony_ci					 n_desc - 1,
74862306a36Sopenharmony_ci					 &qh->desc_list[n_desc - 1]);
74962306a36Sopenharmony_ci				dma_sync_single_for_device(hsotg->dev,
75062306a36Sopenharmony_ci							   qh->desc_list_dma +
75162306a36Sopenharmony_ci					((n_desc - 1) *
75262306a36Sopenharmony_ci					sizeof(struct dwc2_dma_desc)),
75362306a36Sopenharmony_ci					sizeof(struct dwc2_dma_desc),
75462306a36Sopenharmony_ci					DMA_TO_DEVICE);
75562306a36Sopenharmony_ci			}
75662306a36Sopenharmony_ci			dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc);
75762306a36Sopenharmony_ci			dev_vdbg(hsotg->dev,
75862306a36Sopenharmony_ci				 "desc %d (%p) buf=%08x status=%08x\n",
75962306a36Sopenharmony_ci				 n_desc, &qh->desc_list[n_desc],
76062306a36Sopenharmony_ci				 qh->desc_list[n_desc].buf,
76162306a36Sopenharmony_ci				 qh->desc_list[n_desc].status);
76262306a36Sopenharmony_ci			qtd->n_desc++;
76362306a36Sopenharmony_ci			n_desc++;
76462306a36Sopenharmony_ci		} while (chan->xfer_len > 0 &&
76562306a36Sopenharmony_ci			 n_desc != MAX_DMA_DESC_NUM_GENERIC);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "n_desc=%d\n", n_desc);
76862306a36Sopenharmony_ci		qtd->in_process = 1;
76962306a36Sopenharmony_ci		if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL)
77062306a36Sopenharmony_ci			break;
77162306a36Sopenharmony_ci		if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
77262306a36Sopenharmony_ci			break;
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (n_desc) {
77662306a36Sopenharmony_ci		qh->desc_list[n_desc - 1].status |=
77762306a36Sopenharmony_ci				HOST_DMA_IOC | HOST_DMA_EOL | HOST_DMA_A;
77862306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "set IOC/EOL/A bits in desc %d (%p)\n",
77962306a36Sopenharmony_ci			 n_desc - 1, &qh->desc_list[n_desc - 1]);
78062306a36Sopenharmony_ci		dma_sync_single_for_device(hsotg->dev,
78162306a36Sopenharmony_ci					   qh->desc_list_dma + (n_desc - 1) *
78262306a36Sopenharmony_ci					   sizeof(struct dwc2_dma_desc),
78362306a36Sopenharmony_ci					   sizeof(struct dwc2_dma_desc),
78462306a36Sopenharmony_ci					   DMA_TO_DEVICE);
78562306a36Sopenharmony_ci		if (n_desc > 1) {
78662306a36Sopenharmony_ci			qh->desc_list[0].status |= HOST_DMA_A;
78762306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n",
78862306a36Sopenharmony_ci				 &qh->desc_list[0]);
78962306a36Sopenharmony_ci			dma_sync_single_for_device(hsotg->dev,
79062306a36Sopenharmony_ci						   qh->desc_list_dma,
79162306a36Sopenharmony_ci					sizeof(struct dwc2_dma_desc),
79262306a36Sopenharmony_ci					DMA_TO_DEVICE);
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci		chan->ntd = n_desc;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci/**
79962306a36Sopenharmony_ci * dwc2_hcd_start_xfer_ddma() - Starts a transfer in Descriptor DMA mode
80062306a36Sopenharmony_ci *
80162306a36Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller
80262306a36Sopenharmony_ci * @qh:    The QH to init
80362306a36Sopenharmony_ci *
80462306a36Sopenharmony_ci * Return: 0 if successful, negative error code otherwise
80562306a36Sopenharmony_ci *
80662306a36Sopenharmony_ci * For Control and Bulk endpoints, initializes descriptor list and starts the
80762306a36Sopenharmony_ci * transfer. For Interrupt and Isochronous endpoints, initializes descriptor
80862306a36Sopenharmony_ci * list then updates FrameList, marking appropriate entries as active.
80962306a36Sopenharmony_ci *
81062306a36Sopenharmony_ci * For Isochronous endpoints the starting descriptor index is calculated based
81162306a36Sopenharmony_ci * on the scheduled frame, but only on the first transfer descriptor within a
81262306a36Sopenharmony_ci * session. Then the transfer is started via enabling the channel.
81362306a36Sopenharmony_ci *
81462306a36Sopenharmony_ci * For Isochronous endpoints the channel is not halted on XferComplete
81562306a36Sopenharmony_ci * interrupt so remains assigned to the endpoint(QH) until session is done.
81662306a36Sopenharmony_ci */
81762306a36Sopenharmony_civoid dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	/* Channel is already assigned */
82062306a36Sopenharmony_ci	struct dwc2_host_chan *chan = qh->channel;
82162306a36Sopenharmony_ci	u16 skip_frames = 0;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	switch (chan->ep_type) {
82462306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_CONTROL:
82562306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_BULK:
82662306a36Sopenharmony_ci		dwc2_init_non_isoc_dma_desc(hsotg, qh);
82762306a36Sopenharmony_ci		dwc2_hc_start_transfer_ddma(hsotg, chan);
82862306a36Sopenharmony_ci		break;
82962306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_INT:
83062306a36Sopenharmony_ci		dwc2_init_non_isoc_dma_desc(hsotg, qh);
83162306a36Sopenharmony_ci		dwc2_update_frame_list(hsotg, qh, 1);
83262306a36Sopenharmony_ci		dwc2_hc_start_transfer_ddma(hsotg, chan);
83362306a36Sopenharmony_ci		break;
83462306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_ISOC:
83562306a36Sopenharmony_ci		if (!qh->ntd)
83662306a36Sopenharmony_ci			skip_frames = dwc2_recalc_initial_desc_idx(hsotg, qh);
83762306a36Sopenharmony_ci		dwc2_init_isoc_dma_desc(hsotg, qh, skip_frames);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci		if (!chan->xfer_started) {
84062306a36Sopenharmony_ci			dwc2_update_frame_list(hsotg, qh, 1);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci			/*
84362306a36Sopenharmony_ci			 * Always set to max, instead of actual size. Otherwise
84462306a36Sopenharmony_ci			 * ntd will be changed with channel being enabled. Not
84562306a36Sopenharmony_ci			 * recommended.
84662306a36Sopenharmony_ci			 */
84762306a36Sopenharmony_ci			chan->ntd = dwc2_max_desc_num(qh);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci			/* Enable channel only once for ISOC */
85062306a36Sopenharmony_ci			dwc2_hc_start_transfer_ddma(hsotg, chan);
85162306a36Sopenharmony_ci		}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci		break;
85462306a36Sopenharmony_ci	default:
85562306a36Sopenharmony_ci		break;
85662306a36Sopenharmony_ci	}
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci#define DWC2_CMPL_DONE		1
86062306a36Sopenharmony_ci#define DWC2_CMPL_STOP		2
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
86362306a36Sopenharmony_ci					struct dwc2_host_chan *chan,
86462306a36Sopenharmony_ci					struct dwc2_qtd *qtd,
86562306a36Sopenharmony_ci					struct dwc2_qh *qh, u16 idx)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	struct dwc2_dma_desc *dma_desc;
86862306a36Sopenharmony_ci	struct dwc2_hcd_iso_packet_desc *frame_desc;
86962306a36Sopenharmony_ci	u16 remain = 0;
87062306a36Sopenharmony_ci	int rc = 0;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	if (!qtd->urb)
87362306a36Sopenharmony_ci		return -EINVAL;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	dma_sync_single_for_cpu(hsotg->dev, qh->desc_list_dma + (idx *
87662306a36Sopenharmony_ci				sizeof(struct dwc2_dma_desc)),
87762306a36Sopenharmony_ci				sizeof(struct dwc2_dma_desc),
87862306a36Sopenharmony_ci				DMA_FROM_DEVICE);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	dma_desc = &qh->desc_list[idx];
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
88362306a36Sopenharmony_ci	dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
88462306a36Sopenharmony_ci	if (chan->ep_is_in)
88562306a36Sopenharmony_ci		remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >>
88662306a36Sopenharmony_ci			 HOST_DMA_ISOC_NBYTES_SHIFT;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
88962306a36Sopenharmony_ci		/*
89062306a36Sopenharmony_ci		 * XactError, or unable to complete all the transactions
89162306a36Sopenharmony_ci		 * in the scheduled micro-frame/frame, both indicated by
89262306a36Sopenharmony_ci		 * HOST_DMA_STS_PKTERR
89362306a36Sopenharmony_ci		 */
89462306a36Sopenharmony_ci		qtd->urb->error_count++;
89562306a36Sopenharmony_ci		frame_desc->actual_length = qh->n_bytes[idx] - remain;
89662306a36Sopenharmony_ci		frame_desc->status = -EPROTO;
89762306a36Sopenharmony_ci	} else {
89862306a36Sopenharmony_ci		/* Success */
89962306a36Sopenharmony_ci		frame_desc->actual_length = qh->n_bytes[idx] - remain;
90062306a36Sopenharmony_ci		frame_desc->status = 0;
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
90462306a36Sopenharmony_ci		/*
90562306a36Sopenharmony_ci		 * urb->status is not used for isoc transfers here. The
90662306a36Sopenharmony_ci		 * individual frame_desc status are used instead.
90762306a36Sopenharmony_ci		 */
90862306a36Sopenharmony_ci		dwc2_host_complete(hsotg, qtd, 0);
90962306a36Sopenharmony_ci		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci		/*
91262306a36Sopenharmony_ci		 * This check is necessary because urb_dequeue can be called
91362306a36Sopenharmony_ci		 * from urb complete callback (sound driver for example). All
91462306a36Sopenharmony_ci		 * pending URBs are dequeued there, so no need for further
91562306a36Sopenharmony_ci		 * processing.
91662306a36Sopenharmony_ci		 */
91762306a36Sopenharmony_ci		if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE)
91862306a36Sopenharmony_ci			return -1;
91962306a36Sopenharmony_ci		rc = DWC2_CMPL_DONE;
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	qh->ntd--;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	/* Stop if IOC requested descriptor reached */
92562306a36Sopenharmony_ci	if (dma_desc->status & HOST_DMA_IOC)
92662306a36Sopenharmony_ci		rc = DWC2_CMPL_STOP;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	return rc;
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_cistatic void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
93262306a36Sopenharmony_ci					 struct dwc2_host_chan *chan,
93362306a36Sopenharmony_ci					 enum dwc2_halt_status halt_status)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci	struct dwc2_hcd_iso_packet_desc *frame_desc;
93662306a36Sopenharmony_ci	struct dwc2_qtd *qtd, *qtd_tmp;
93762306a36Sopenharmony_ci	struct dwc2_qh *qh;
93862306a36Sopenharmony_ci	u16 idx;
93962306a36Sopenharmony_ci	int rc;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	qh = chan->qh;
94262306a36Sopenharmony_ci	idx = qh->td_first;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
94562306a36Sopenharmony_ci		list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry)
94662306a36Sopenharmony_ci			qtd->in_process = 0;
94762306a36Sopenharmony_ci		return;
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	if (halt_status == DWC2_HC_XFER_AHB_ERR ||
95162306a36Sopenharmony_ci	    halt_status == DWC2_HC_XFER_BABBLE_ERR) {
95262306a36Sopenharmony_ci		/*
95362306a36Sopenharmony_ci		 * Channel is halted in these error cases, considered as serious
95462306a36Sopenharmony_ci		 * issues.
95562306a36Sopenharmony_ci		 * Complete all URBs marking all frames as failed, irrespective
95662306a36Sopenharmony_ci		 * whether some of the descriptors (frames) succeeded or not.
95762306a36Sopenharmony_ci		 * Pass error code to completion routine as well, to update
95862306a36Sopenharmony_ci		 * urb->status, some of class drivers might use it to stop
95962306a36Sopenharmony_ci		 * queing transfer requests.
96062306a36Sopenharmony_ci		 */
96162306a36Sopenharmony_ci		int err = halt_status == DWC2_HC_XFER_AHB_ERR ?
96262306a36Sopenharmony_ci			  -EIO : -EOVERFLOW;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci		list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
96562306a36Sopenharmony_ci					 qtd_list_entry) {
96662306a36Sopenharmony_ci			if (qtd->urb) {
96762306a36Sopenharmony_ci				for (idx = 0; idx < qtd->urb->packet_count;
96862306a36Sopenharmony_ci				     idx++) {
96962306a36Sopenharmony_ci					frame_desc = &qtd->urb->iso_descs[idx];
97062306a36Sopenharmony_ci					frame_desc->status = err;
97162306a36Sopenharmony_ci				}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci				dwc2_host_complete(hsotg, qtd, err);
97462306a36Sopenharmony_ci			}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
97762306a36Sopenharmony_ci		}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci		return;
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
98362306a36Sopenharmony_ci		if (!qtd->in_process)
98462306a36Sopenharmony_ci			break;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci		/*
98762306a36Sopenharmony_ci		 * Ensure idx corresponds to descriptor where first urb of this
98862306a36Sopenharmony_ci		 * qtd was added. In fact, during isoc desc init, dwc2 may skip
98962306a36Sopenharmony_ci		 * an index if current frame number is already over this index.
99062306a36Sopenharmony_ci		 */
99162306a36Sopenharmony_ci		if (idx != qtd->isoc_td_first) {
99262306a36Sopenharmony_ci			dev_vdbg(hsotg->dev,
99362306a36Sopenharmony_ci				 "try to complete %d instead of %d\n",
99462306a36Sopenharmony_ci				 idx, qtd->isoc_td_first);
99562306a36Sopenharmony_ci			idx = qtd->isoc_td_first;
99662306a36Sopenharmony_ci		}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci		do {
99962306a36Sopenharmony_ci			struct dwc2_qtd *qtd_next;
100062306a36Sopenharmony_ci			u16 cur_idx;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci			rc = dwc2_cmpl_host_isoc_dma_desc(hsotg, chan, qtd, qh,
100362306a36Sopenharmony_ci							  idx);
100462306a36Sopenharmony_ci			if (rc < 0)
100562306a36Sopenharmony_ci				return;
100662306a36Sopenharmony_ci			idx = dwc2_desclist_idx_inc(idx, qh->host_interval,
100762306a36Sopenharmony_ci						    chan->speed);
100862306a36Sopenharmony_ci			if (!rc)
100962306a36Sopenharmony_ci				continue;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci			if (rc == DWC2_CMPL_DONE)
101262306a36Sopenharmony_ci				break;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci			/* rc == DWC2_CMPL_STOP */
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci			if (qh->host_interval >= 32)
101762306a36Sopenharmony_ci				goto stop_scan;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci			qh->td_first = idx;
102062306a36Sopenharmony_ci			cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
102162306a36Sopenharmony_ci			qtd_next = list_first_entry(&qh->qtd_list,
102262306a36Sopenharmony_ci						    struct dwc2_qtd,
102362306a36Sopenharmony_ci						    qtd_list_entry);
102462306a36Sopenharmony_ci			if (dwc2_frame_idx_num_gt(cur_idx,
102562306a36Sopenharmony_ci						  qtd_next->isoc_td_last))
102662306a36Sopenharmony_ci				break;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci			goto stop_scan;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci		} while (idx != qh->td_first);
103162306a36Sopenharmony_ci	}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_cistop_scan:
103462306a36Sopenharmony_ci	qh->td_first = idx;
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg,
103862306a36Sopenharmony_ci					       struct dwc2_host_chan *chan,
103962306a36Sopenharmony_ci					struct dwc2_qtd *qtd,
104062306a36Sopenharmony_ci					struct dwc2_dma_desc *dma_desc,
104162306a36Sopenharmony_ci					enum dwc2_halt_status halt_status,
104262306a36Sopenharmony_ci					u32 n_bytes, int *xfer_done)
104362306a36Sopenharmony_ci{
104462306a36Sopenharmony_ci	struct dwc2_hcd_urb *urb = qtd->urb;
104562306a36Sopenharmony_ci	u16 remain = 0;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	if (chan->ep_is_in)
104862306a36Sopenharmony_ci		remain = (dma_desc->status & HOST_DMA_NBYTES_MASK) >>
104962306a36Sopenharmony_ci			 HOST_DMA_NBYTES_SHIFT;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "remain=%d dwc2_urb=%p\n", remain, urb);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	if (halt_status == DWC2_HC_XFER_AHB_ERR) {
105462306a36Sopenharmony_ci		dev_err(hsotg->dev, "EIO\n");
105562306a36Sopenharmony_ci		urb->status = -EIO;
105662306a36Sopenharmony_ci		return 1;
105762306a36Sopenharmony_ci	}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
106062306a36Sopenharmony_ci		switch (halt_status) {
106162306a36Sopenharmony_ci		case DWC2_HC_XFER_STALL:
106262306a36Sopenharmony_ci			dev_vdbg(hsotg->dev, "Stall\n");
106362306a36Sopenharmony_ci			urb->status = -EPIPE;
106462306a36Sopenharmony_ci			break;
106562306a36Sopenharmony_ci		case DWC2_HC_XFER_BABBLE_ERR:
106662306a36Sopenharmony_ci			dev_err(hsotg->dev, "Babble\n");
106762306a36Sopenharmony_ci			urb->status = -EOVERFLOW;
106862306a36Sopenharmony_ci			break;
106962306a36Sopenharmony_ci		case DWC2_HC_XFER_XACT_ERR:
107062306a36Sopenharmony_ci			dev_err(hsotg->dev, "XactErr\n");
107162306a36Sopenharmony_ci			urb->status = -EPROTO;
107262306a36Sopenharmony_ci			break;
107362306a36Sopenharmony_ci		default:
107462306a36Sopenharmony_ci			dev_err(hsotg->dev,
107562306a36Sopenharmony_ci				"%s: Unhandled descriptor error status (%d)\n",
107662306a36Sopenharmony_ci				__func__, halt_status);
107762306a36Sopenharmony_ci			break;
107862306a36Sopenharmony_ci		}
107962306a36Sopenharmony_ci		return 1;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	if (dma_desc->status & HOST_DMA_A) {
108362306a36Sopenharmony_ci		dev_vdbg(hsotg->dev,
108462306a36Sopenharmony_ci			 "Active descriptor encountered on channel %d\n",
108562306a36Sopenharmony_ci			 chan->hc_num);
108662306a36Sopenharmony_ci		return 0;
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL) {
109062306a36Sopenharmony_ci		if (qtd->control_phase == DWC2_CONTROL_DATA) {
109162306a36Sopenharmony_ci			urb->actual_length += n_bytes - remain;
109262306a36Sopenharmony_ci			if (remain || urb->actual_length >= urb->length) {
109362306a36Sopenharmony_ci				/*
109462306a36Sopenharmony_ci				 * For Control Data stage do not set urb->status
109562306a36Sopenharmony_ci				 * to 0, to prevent URB callback. Set it when
109662306a36Sopenharmony_ci				 * Status phase is done. See below.
109762306a36Sopenharmony_ci				 */
109862306a36Sopenharmony_ci				*xfer_done = 1;
109962306a36Sopenharmony_ci			}
110062306a36Sopenharmony_ci		} else if (qtd->control_phase == DWC2_CONTROL_STATUS) {
110162306a36Sopenharmony_ci			urb->status = 0;
110262306a36Sopenharmony_ci			*xfer_done = 1;
110362306a36Sopenharmony_ci		}
110462306a36Sopenharmony_ci		/* No handling for SETUP stage */
110562306a36Sopenharmony_ci	} else {
110662306a36Sopenharmony_ci		/* BULK and INTR */
110762306a36Sopenharmony_ci		urb->actual_length += n_bytes - remain;
110862306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "length=%d actual=%d\n", urb->length,
110962306a36Sopenharmony_ci			 urb->actual_length);
111062306a36Sopenharmony_ci		if (remain || urb->actual_length >= urb->length) {
111162306a36Sopenharmony_ci			urb->status = 0;
111262306a36Sopenharmony_ci			*xfer_done = 1;
111362306a36Sopenharmony_ci		}
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return 0;
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
112062306a36Sopenharmony_ci				      struct dwc2_host_chan *chan,
112162306a36Sopenharmony_ci				      int chnum, struct dwc2_qtd *qtd,
112262306a36Sopenharmony_ci				      int desc_num,
112362306a36Sopenharmony_ci				      enum dwc2_halt_status halt_status,
112462306a36Sopenharmony_ci				      int *xfer_done)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	struct dwc2_qh *qh = chan->qh;
112762306a36Sopenharmony_ci	struct dwc2_hcd_urb *urb = qtd->urb;
112862306a36Sopenharmony_ci	struct dwc2_dma_desc *dma_desc;
112962306a36Sopenharmony_ci	u32 n_bytes;
113062306a36Sopenharmony_ci	int failed;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	dev_vdbg(hsotg->dev, "%s()\n", __func__);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (!urb)
113562306a36Sopenharmony_ci		return -EINVAL;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	dma_sync_single_for_cpu(hsotg->dev,
113862306a36Sopenharmony_ci				qh->desc_list_dma + (desc_num *
113962306a36Sopenharmony_ci				sizeof(struct dwc2_dma_desc)),
114062306a36Sopenharmony_ci				sizeof(struct dwc2_dma_desc),
114162306a36Sopenharmony_ci				DMA_FROM_DEVICE);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	dma_desc = &qh->desc_list[desc_num];
114462306a36Sopenharmony_ci	n_bytes = qh->n_bytes[desc_num];
114562306a36Sopenharmony_ci	dev_vdbg(hsotg->dev,
114662306a36Sopenharmony_ci		 "qtd=%p dwc2_urb=%p desc_num=%d desc=%p n_bytes=%d\n",
114762306a36Sopenharmony_ci		 qtd, urb, desc_num, dma_desc, n_bytes);
114862306a36Sopenharmony_ci	failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc,
114962306a36Sopenharmony_ci						     halt_status, n_bytes,
115062306a36Sopenharmony_ci						     xfer_done);
115162306a36Sopenharmony_ci	if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
115262306a36Sopenharmony_ci		dwc2_host_complete(hsotg, qtd, urb->status);
115362306a36Sopenharmony_ci		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
115462306a36Sopenharmony_ci		dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x\n",
115562306a36Sopenharmony_ci			 failed, *xfer_done);
115662306a36Sopenharmony_ci		return failed;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL) {
116062306a36Sopenharmony_ci		switch (qtd->control_phase) {
116162306a36Sopenharmony_ci		case DWC2_CONTROL_SETUP:
116262306a36Sopenharmony_ci			if (urb->length > 0)
116362306a36Sopenharmony_ci				qtd->control_phase = DWC2_CONTROL_DATA;
116462306a36Sopenharmony_ci			else
116562306a36Sopenharmony_ci				qtd->control_phase = DWC2_CONTROL_STATUS;
116662306a36Sopenharmony_ci			dev_vdbg(hsotg->dev,
116762306a36Sopenharmony_ci				 "  Control setup transaction done\n");
116862306a36Sopenharmony_ci			break;
116962306a36Sopenharmony_ci		case DWC2_CONTROL_DATA:
117062306a36Sopenharmony_ci			if (*xfer_done) {
117162306a36Sopenharmony_ci				qtd->control_phase = DWC2_CONTROL_STATUS;
117262306a36Sopenharmony_ci				dev_vdbg(hsotg->dev,
117362306a36Sopenharmony_ci					 "  Control data transfer done\n");
117462306a36Sopenharmony_ci			} else if (desc_num + 1 == qtd->n_desc) {
117562306a36Sopenharmony_ci				/*
117662306a36Sopenharmony_ci				 * Last descriptor for Control data stage which
117762306a36Sopenharmony_ci				 * is not completed yet
117862306a36Sopenharmony_ci				 */
117962306a36Sopenharmony_ci				dwc2_hcd_save_data_toggle(hsotg, chan, chnum,
118062306a36Sopenharmony_ci							  qtd);
118162306a36Sopenharmony_ci			}
118262306a36Sopenharmony_ci			break;
118362306a36Sopenharmony_ci		default:
118462306a36Sopenharmony_ci			break;
118562306a36Sopenharmony_ci		}
118662306a36Sopenharmony_ci	}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	return 0;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_cistatic void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
119262306a36Sopenharmony_ci					     struct dwc2_host_chan *chan,
119362306a36Sopenharmony_ci					     int chnum,
119462306a36Sopenharmony_ci					     enum dwc2_halt_status halt_status)
119562306a36Sopenharmony_ci{
119662306a36Sopenharmony_ci	struct list_head *qtd_item, *qtd_tmp;
119762306a36Sopenharmony_ci	struct dwc2_qh *qh = chan->qh;
119862306a36Sopenharmony_ci	struct dwc2_qtd *qtd = NULL;
119962306a36Sopenharmony_ci	int xfer_done;
120062306a36Sopenharmony_ci	int desc_num = 0;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
120362306a36Sopenharmony_ci		list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry)
120462306a36Sopenharmony_ci			qtd->in_process = 0;
120562306a36Sopenharmony_ci		return;
120662306a36Sopenharmony_ci	}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	list_for_each_safe(qtd_item, qtd_tmp, &qh->qtd_list) {
120962306a36Sopenharmony_ci		int i;
121062306a36Sopenharmony_ci		int qtd_desc_count;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci		qtd = list_entry(qtd_item, struct dwc2_qtd, qtd_list_entry);
121362306a36Sopenharmony_ci		xfer_done = 0;
121462306a36Sopenharmony_ci		qtd_desc_count = qtd->n_desc;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci		for (i = 0; i < qtd_desc_count; i++) {
121762306a36Sopenharmony_ci			if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd,
121862306a36Sopenharmony_ci						       desc_num, halt_status,
121962306a36Sopenharmony_ci						       &xfer_done)) {
122062306a36Sopenharmony_ci				qtd = NULL;
122162306a36Sopenharmony_ci				goto stop_scan;
122262306a36Sopenharmony_ci			}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci			desc_num++;
122562306a36Sopenharmony_ci		}
122662306a36Sopenharmony_ci	}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistop_scan:
122962306a36Sopenharmony_ci	if (qh->ep_type != USB_ENDPOINT_XFER_CONTROL) {
123062306a36Sopenharmony_ci		/*
123162306a36Sopenharmony_ci		 * Resetting the data toggle for bulk and interrupt endpoints
123262306a36Sopenharmony_ci		 * in case of stall. See handle_hc_stall_intr().
123362306a36Sopenharmony_ci		 */
123462306a36Sopenharmony_ci		if (halt_status == DWC2_HC_XFER_STALL)
123562306a36Sopenharmony_ci			qh->data_toggle = DWC2_HC_PID_DATA0;
123662306a36Sopenharmony_ci		else
123762306a36Sopenharmony_ci			dwc2_hcd_save_data_toggle(hsotg, chan, chnum, NULL);
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	if (halt_status == DWC2_HC_XFER_COMPLETE) {
124162306a36Sopenharmony_ci		if (chan->hcint & HCINTMSK_NYET) {
124262306a36Sopenharmony_ci			/*
124362306a36Sopenharmony_ci			 * Got a NYET on the last transaction of the transfer.
124462306a36Sopenharmony_ci			 * It means that the endpoint should be in the PING
124562306a36Sopenharmony_ci			 * state at the beginning of the next transfer.
124662306a36Sopenharmony_ci			 */
124762306a36Sopenharmony_ci			qh->ping_state = 1;
124862306a36Sopenharmony_ci		}
124962306a36Sopenharmony_ci	}
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci/**
125362306a36Sopenharmony_ci * dwc2_hcd_complete_xfer_ddma() - Scans the descriptor list, updates URB's
125462306a36Sopenharmony_ci * status and calls completion routine for the URB if it's done. Called from
125562306a36Sopenharmony_ci * interrupt handlers.
125662306a36Sopenharmony_ci *
125762306a36Sopenharmony_ci * @hsotg:       The HCD state structure for the DWC OTG controller
125862306a36Sopenharmony_ci * @chan:        Host channel the transfer is completed on
125962306a36Sopenharmony_ci * @chnum:       Index of Host channel registers
126062306a36Sopenharmony_ci * @halt_status: Reason the channel is being halted or just XferComplete
126162306a36Sopenharmony_ci *               for isochronous transfers
126262306a36Sopenharmony_ci *
126362306a36Sopenharmony_ci * Releases the channel to be used by other transfers.
126462306a36Sopenharmony_ci * In case of Isochronous endpoint the channel is not halted until the end of
126562306a36Sopenharmony_ci * the session, i.e. QTD list is empty.
126662306a36Sopenharmony_ci * If periodic channel released the FrameList is updated accordingly.
126762306a36Sopenharmony_ci * Calls transaction selection routines to activate pending transfers.
126862306a36Sopenharmony_ci */
126962306a36Sopenharmony_civoid dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
127062306a36Sopenharmony_ci				 struct dwc2_host_chan *chan, int chnum,
127162306a36Sopenharmony_ci				 enum dwc2_halt_status halt_status)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	struct dwc2_qh *qh = chan->qh;
127462306a36Sopenharmony_ci	int continue_isoc_xfer = 0;
127562306a36Sopenharmony_ci	enum dwc2_transaction_type tr_type;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	if (chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
127862306a36Sopenharmony_ci		dwc2_complete_isoc_xfer_ddma(hsotg, chan, halt_status);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci		/* Release the channel if halted or session completed */
128162306a36Sopenharmony_ci		if (halt_status != DWC2_HC_XFER_COMPLETE ||
128262306a36Sopenharmony_ci		    list_empty(&qh->qtd_list)) {
128362306a36Sopenharmony_ci			struct dwc2_qtd *qtd, *qtd_tmp;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci			/*
128662306a36Sopenharmony_ci			 * Kill all remainings QTDs since channel has been
128762306a36Sopenharmony_ci			 * halted.
128862306a36Sopenharmony_ci			 */
128962306a36Sopenharmony_ci			list_for_each_entry_safe(qtd, qtd_tmp,
129062306a36Sopenharmony_ci						 &qh->qtd_list,
129162306a36Sopenharmony_ci						 qtd_list_entry) {
129262306a36Sopenharmony_ci				dwc2_host_complete(hsotg, qtd,
129362306a36Sopenharmony_ci						   -ECONNRESET);
129462306a36Sopenharmony_ci				dwc2_hcd_qtd_unlink_and_free(hsotg,
129562306a36Sopenharmony_ci							     qtd, qh);
129662306a36Sopenharmony_ci			}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci			/* Halt the channel if session completed */
129962306a36Sopenharmony_ci			if (halt_status == DWC2_HC_XFER_COMPLETE)
130062306a36Sopenharmony_ci				dwc2_hc_halt(hsotg, chan, halt_status);
130162306a36Sopenharmony_ci			dwc2_release_channel_ddma(hsotg, qh);
130262306a36Sopenharmony_ci			dwc2_hcd_qh_unlink(hsotg, qh);
130362306a36Sopenharmony_ci		} else {
130462306a36Sopenharmony_ci			/* Keep in assigned schedule to continue transfer */
130562306a36Sopenharmony_ci			list_move_tail(&qh->qh_list_entry,
130662306a36Sopenharmony_ci				       &hsotg->periodic_sched_assigned);
130762306a36Sopenharmony_ci			/*
130862306a36Sopenharmony_ci			 * If channel has been halted during giveback of urb
130962306a36Sopenharmony_ci			 * then prevent any new scheduling.
131062306a36Sopenharmony_ci			 */
131162306a36Sopenharmony_ci			if (!chan->halt_status)
131262306a36Sopenharmony_ci				continue_isoc_xfer = 1;
131362306a36Sopenharmony_ci		}
131462306a36Sopenharmony_ci		/*
131562306a36Sopenharmony_ci		 * Todo: Consider the case when period exceeds FrameList size.
131662306a36Sopenharmony_ci		 * Frame Rollover interrupt should be used.
131762306a36Sopenharmony_ci		 */
131862306a36Sopenharmony_ci	} else {
131962306a36Sopenharmony_ci		/*
132062306a36Sopenharmony_ci		 * Scan descriptor list to complete the URB(s), then release
132162306a36Sopenharmony_ci		 * the channel
132262306a36Sopenharmony_ci		 */
132362306a36Sopenharmony_ci		dwc2_complete_non_isoc_xfer_ddma(hsotg, chan, chnum,
132462306a36Sopenharmony_ci						 halt_status);
132562306a36Sopenharmony_ci		dwc2_release_channel_ddma(hsotg, qh);
132662306a36Sopenharmony_ci		dwc2_hcd_qh_unlink(hsotg, qh);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci		if (!list_empty(&qh->qtd_list)) {
132962306a36Sopenharmony_ci			/*
133062306a36Sopenharmony_ci			 * Add back to inactive non-periodic schedule on normal
133162306a36Sopenharmony_ci			 * completion
133262306a36Sopenharmony_ci			 */
133362306a36Sopenharmony_ci			dwc2_hcd_qh_add(hsotg, qh);
133462306a36Sopenharmony_ci		}
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	tr_type = dwc2_hcd_select_transactions(hsotg);
133862306a36Sopenharmony_ci	if (tr_type != DWC2_TRANSACTION_NONE || continue_isoc_xfer) {
133962306a36Sopenharmony_ci		if (continue_isoc_xfer) {
134062306a36Sopenharmony_ci			if (tr_type == DWC2_TRANSACTION_NONE)
134162306a36Sopenharmony_ci				tr_type = DWC2_TRANSACTION_PERIODIC;
134262306a36Sopenharmony_ci			else if (tr_type == DWC2_TRANSACTION_NON_PERIODIC)
134362306a36Sopenharmony_ci				tr_type = DWC2_TRANSACTION_ALL;
134462306a36Sopenharmony_ci		}
134562306a36Sopenharmony_ci		dwc2_hcd_queue_transactions(hsotg, tr_type);
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci}
1348