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