18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * hcd_ddma.c - DesignWare HS OTG Controller descriptor DMA routines 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 98c2ecf20Sopenharmony_ci * are met: 108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 118c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 128c2ecf20Sopenharmony_ci * without modification. 138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 148c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 158c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 168c2ecf20Sopenharmony_ci * 3. The names of the above-listed copyright holders may not be used 178c2ecf20Sopenharmony_ci * to endorse or promote products derived from this software without 188c2ecf20Sopenharmony_ci * specific prior written permission. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the 218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software 228c2ecf20Sopenharmony_ci * Foundation; either version 2 of the License, or (at your option) any 238c2ecf20Sopenharmony_ci * later version. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 268c2ecf20Sopenharmony_ci * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 278c2ecf20Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 288c2ecf20Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 298c2ecf20Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 308c2ecf20Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 318c2ecf20Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 328c2ecf20Sopenharmony_ci * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 338c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 348c2ecf20Sopenharmony_ci * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 358c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * This file contains the Descriptor DMA implementation for Host mode 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci#include <linux/kernel.h> 428c2ecf20Sopenharmony_ci#include <linux/module.h> 438c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 448c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 458c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 468c2ecf20Sopenharmony_ci#include <linux/io.h> 478c2ecf20Sopenharmony_ci#include <linux/slab.h> 488c2ecf20Sopenharmony_ci#include <linux/usb.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h> 518c2ecf20Sopenharmony_ci#include <linux/usb/ch11.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include "core.h" 548c2ecf20Sopenharmony_ci#include "hcd.h" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic u16 dwc2_frame_list_idx(u16 frame) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci return frame & (FRLISTEN_64_SIZE - 1); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic u16 dwc2_desclist_idx_inc(u16 idx, u16 inc, u8 speed) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci return (idx + inc) & 648c2ecf20Sopenharmony_ci ((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC : 658c2ecf20Sopenharmony_ci MAX_DMA_DESC_NUM_GENERIC) - 1); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic u16 dwc2_desclist_idx_dec(u16 idx, u16 inc, u8 speed) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return (idx - inc) & 718c2ecf20Sopenharmony_ci ((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC : 728c2ecf20Sopenharmony_ci MAX_DMA_DESC_NUM_GENERIC) - 1); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic u16 dwc2_max_desc_num(struct dwc2_qh *qh) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci return (qh->ep_type == USB_ENDPOINT_XFER_ISOC && 788c2ecf20Sopenharmony_ci qh->dev_speed == USB_SPEED_HIGH) ? 798c2ecf20Sopenharmony_ci MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic u16 dwc2_frame_incr_val(struct dwc2_qh *qh) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci return qh->dev_speed == USB_SPEED_HIGH ? 858c2ecf20Sopenharmony_ci (qh->host_interval + 8 - 1) / 8 : qh->host_interval; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, 898c2ecf20Sopenharmony_ci gfp_t flags) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct kmem_cache *desc_cache; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (qh->ep_type == USB_ENDPOINT_XFER_ISOC && 948c2ecf20Sopenharmony_ci qh->dev_speed == USB_SPEED_HIGH) 958c2ecf20Sopenharmony_ci desc_cache = hsotg->desc_hsisoc_cache; 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci desc_cache = hsotg->desc_gen_cache; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci qh->desc_list_sz = sizeof(struct dwc2_dma_desc) * 1008c2ecf20Sopenharmony_ci dwc2_max_desc_num(qh); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci qh->desc_list = kmem_cache_zalloc(desc_cache, flags | GFP_DMA); 1038c2ecf20Sopenharmony_ci if (!qh->desc_list) 1048c2ecf20Sopenharmony_ci return -ENOMEM; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci qh->desc_list_dma = dma_map_single(hsotg->dev, qh->desc_list, 1078c2ecf20Sopenharmony_ci qh->desc_list_sz, 1088c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci qh->n_bytes = kcalloc(dwc2_max_desc_num(qh), sizeof(u32), flags); 1118c2ecf20Sopenharmony_ci if (!qh->n_bytes) { 1128c2ecf20Sopenharmony_ci dma_unmap_single(hsotg->dev, qh->desc_list_dma, 1138c2ecf20Sopenharmony_ci qh->desc_list_sz, 1148c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 1158c2ecf20Sopenharmony_ci kmem_cache_free(desc_cache, qh->desc_list); 1168c2ecf20Sopenharmony_ci qh->desc_list = NULL; 1178c2ecf20Sopenharmony_ci return -ENOMEM; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct kmem_cache *desc_cache; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (qh->ep_type == USB_ENDPOINT_XFER_ISOC && 1288c2ecf20Sopenharmony_ci qh->dev_speed == USB_SPEED_HIGH) 1298c2ecf20Sopenharmony_ci desc_cache = hsotg->desc_hsisoc_cache; 1308c2ecf20Sopenharmony_ci else 1318c2ecf20Sopenharmony_ci desc_cache = hsotg->desc_gen_cache; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (qh->desc_list) { 1348c2ecf20Sopenharmony_ci dma_unmap_single(hsotg->dev, qh->desc_list_dma, 1358c2ecf20Sopenharmony_ci qh->desc_list_sz, DMA_FROM_DEVICE); 1368c2ecf20Sopenharmony_ci kmem_cache_free(desc_cache, qh->desc_list); 1378c2ecf20Sopenharmony_ci qh->desc_list = NULL; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci kfree(qh->n_bytes); 1418c2ecf20Sopenharmony_ci qh->n_bytes = NULL; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int dwc2_frame_list_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci if (hsotg->frame_list) 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci hsotg->frame_list_sz = 4 * FRLISTEN_64_SIZE; 1508c2ecf20Sopenharmony_ci hsotg->frame_list = kzalloc(hsotg->frame_list_sz, GFP_ATOMIC | GFP_DMA); 1518c2ecf20Sopenharmony_ci if (!hsotg->frame_list) 1528c2ecf20Sopenharmony_ci return -ENOMEM; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci hsotg->frame_list_dma = dma_map_single(hsotg->dev, hsotg->frame_list, 1558c2ecf20Sopenharmony_ci hsotg->frame_list_sz, 1568c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void dwc2_frame_list_free(struct dwc2_hsotg *hsotg) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci unsigned long flags; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (!hsotg->frame_list) { 1688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 1698c2ecf20Sopenharmony_ci return; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci dma_unmap_single(hsotg->dev, hsotg->frame_list_dma, 1738c2ecf20Sopenharmony_ci hsotg->frame_list_sz, DMA_FROM_DEVICE); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci kfree(hsotg->frame_list); 1768c2ecf20Sopenharmony_ci hsotg->frame_list = NULL; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci u32 hcfg; 1848c2ecf20Sopenharmony_ci unsigned long flags; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci hcfg = dwc2_readl(hsotg, HCFG); 1898c2ecf20Sopenharmony_ci if (hcfg & HCFG_PERSCHEDENA) { 1908c2ecf20Sopenharmony_ci /* already enabled */ 1918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 1928c2ecf20Sopenharmony_ci return; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hsotg->frame_list_dma, HFLBADDR); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci hcfg &= ~HCFG_FRLISTEN_MASK; 1988c2ecf20Sopenharmony_ci hcfg |= fr_list_en | HCFG_PERSCHEDENA; 1998c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n"); 2008c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hcfg, HCFG); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci u32 hcfg; 2088c2ecf20Sopenharmony_ci unsigned long flags; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci hcfg = dwc2_readl(hsotg, HCFG); 2138c2ecf20Sopenharmony_ci if (!(hcfg & HCFG_PERSCHEDENA)) { 2148c2ecf20Sopenharmony_ci /* already disabled */ 2158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 2168c2ecf20Sopenharmony_ci return; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci hcfg &= ~HCFG_PERSCHEDENA; 2208c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n"); 2218c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hcfg, HCFG); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/* 2278c2ecf20Sopenharmony_ci * Activates/Deactivates FrameList entries for the channel based on endpoint 2288c2ecf20Sopenharmony_ci * servicing period 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_cistatic void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, 2318c2ecf20Sopenharmony_ci int enable) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan; 2348c2ecf20Sopenharmony_ci u16 i, j, inc; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (!hsotg) { 2378c2ecf20Sopenharmony_ci pr_err("hsotg = %p\n", hsotg); 2388c2ecf20Sopenharmony_ci return; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (!qh->channel) { 2428c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "qh->channel = %p\n", qh->channel); 2438c2ecf20Sopenharmony_ci return; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!hsotg->frame_list) { 2478c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "hsotg->frame_list = %p\n", 2488c2ecf20Sopenharmony_ci hsotg->frame_list); 2498c2ecf20Sopenharmony_ci return; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci chan = qh->channel; 2538c2ecf20Sopenharmony_ci inc = dwc2_frame_incr_val(qh); 2548c2ecf20Sopenharmony_ci if (qh->ep_type == USB_ENDPOINT_XFER_ISOC) 2558c2ecf20Sopenharmony_ci i = dwc2_frame_list_idx(qh->next_active_frame); 2568c2ecf20Sopenharmony_ci else 2578c2ecf20Sopenharmony_ci i = 0; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci j = i; 2608c2ecf20Sopenharmony_ci do { 2618c2ecf20Sopenharmony_ci if (enable) 2628c2ecf20Sopenharmony_ci hsotg->frame_list[j] |= 1 << chan->hc_num; 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci hsotg->frame_list[j] &= ~(1 << chan->hc_num); 2658c2ecf20Sopenharmony_ci j = (j + inc) & (FRLISTEN_64_SIZE - 1); 2668c2ecf20Sopenharmony_ci } while (j != i); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Sync frame list since controller will access it if periodic 2708c2ecf20Sopenharmony_ci * channel is currently enabled. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci dma_sync_single_for_device(hsotg->dev, 2738c2ecf20Sopenharmony_ci hsotg->frame_list_dma, 2748c2ecf20Sopenharmony_ci hsotg->frame_list_sz, 2758c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (!enable) 2788c2ecf20Sopenharmony_ci return; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci chan->schinfo = 0; 2818c2ecf20Sopenharmony_ci if (chan->speed == USB_SPEED_HIGH && qh->host_interval) { 2828c2ecf20Sopenharmony_ci j = 1; 2838c2ecf20Sopenharmony_ci /* TODO - check this */ 2848c2ecf20Sopenharmony_ci inc = (8 + qh->host_interval - 1) / qh->host_interval; 2858c2ecf20Sopenharmony_ci for (i = 0; i < inc; i++) { 2868c2ecf20Sopenharmony_ci chan->schinfo |= j; 2878c2ecf20Sopenharmony_ci j = j << qh->host_interval; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } else { 2908c2ecf20Sopenharmony_ci chan->schinfo = 0xff; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg, 2958c2ecf20Sopenharmony_ci struct dwc2_qh *qh) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan = qh->channel; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (dwc2_qh_is_non_per(qh)) { 3008c2ecf20Sopenharmony_ci if (hsotg->params.uframe_sched) 3018c2ecf20Sopenharmony_ci hsotg->available_host_channels++; 3028c2ecf20Sopenharmony_ci else 3038c2ecf20Sopenharmony_ci hsotg->non_periodic_channels--; 3048c2ecf20Sopenharmony_ci } else { 3058c2ecf20Sopenharmony_ci dwc2_update_frame_list(hsotg, qh, 0); 3068c2ecf20Sopenharmony_ci hsotg->available_host_channels++; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* 3108c2ecf20Sopenharmony_ci * The condition is added to prevent double cleanup try in case of 3118c2ecf20Sopenharmony_ci * device disconnect. See channel cleanup in dwc2_hcd_disconnect(). 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_ci if (chan->qh) { 3148c2ecf20Sopenharmony_ci if (!list_empty(&chan->hc_list_entry)) 3158c2ecf20Sopenharmony_ci list_del(&chan->hc_list_entry); 3168c2ecf20Sopenharmony_ci dwc2_hc_cleanup(hsotg, chan); 3178c2ecf20Sopenharmony_ci list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list); 3188c2ecf20Sopenharmony_ci chan->qh = NULL; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci qh->channel = NULL; 3228c2ecf20Sopenharmony_ci qh->ntd = 0; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (qh->desc_list) 3258c2ecf20Sopenharmony_ci memset(qh->desc_list, 0, sizeof(struct dwc2_dma_desc) * 3268c2ecf20Sopenharmony_ci dwc2_max_desc_num(qh)); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/** 3308c2ecf20Sopenharmony_ci * dwc2_hcd_qh_init_ddma() - Initializes a QH structure's Descriptor DMA 3318c2ecf20Sopenharmony_ci * related members 3328c2ecf20Sopenharmony_ci * 3338c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller 3348c2ecf20Sopenharmony_ci * @qh: The QH to init 3358c2ecf20Sopenharmony_ci * @mem_flags: Indicates the type of memory allocation 3368c2ecf20Sopenharmony_ci * 3378c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise 3388c2ecf20Sopenharmony_ci * 3398c2ecf20Sopenharmony_ci * Allocates memory for the descriptor list. For the first periodic QH, 3408c2ecf20Sopenharmony_ci * allocates memory for the FrameList and enables periodic scheduling. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ciint dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, 3438c2ecf20Sopenharmony_ci gfp_t mem_flags) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci int retval; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (qh->do_split) { 3488c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 3498c2ecf20Sopenharmony_ci "SPLIT Transfers are not supported in Descriptor DMA mode.\n"); 3508c2ecf20Sopenharmony_ci retval = -EINVAL; 3518c2ecf20Sopenharmony_ci goto err0; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci retval = dwc2_desc_list_alloc(hsotg, qh, mem_flags); 3558c2ecf20Sopenharmony_ci if (retval) 3568c2ecf20Sopenharmony_ci goto err0; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (qh->ep_type == USB_ENDPOINT_XFER_ISOC || 3598c2ecf20Sopenharmony_ci qh->ep_type == USB_ENDPOINT_XFER_INT) { 3608c2ecf20Sopenharmony_ci if (!hsotg->frame_list) { 3618c2ecf20Sopenharmony_ci retval = dwc2_frame_list_alloc(hsotg, mem_flags); 3628c2ecf20Sopenharmony_ci if (retval) 3638c2ecf20Sopenharmony_ci goto err1; 3648c2ecf20Sopenharmony_ci /* Enable periodic schedule on first periodic QH */ 3658c2ecf20Sopenharmony_ci dwc2_per_sched_enable(hsotg, HCFG_FRLISTEN_64); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci qh->ntd = 0; 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cierr1: 3738c2ecf20Sopenharmony_ci dwc2_desc_list_free(hsotg, qh); 3748c2ecf20Sopenharmony_cierr0: 3758c2ecf20Sopenharmony_ci return retval; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci/** 3798c2ecf20Sopenharmony_ci * dwc2_hcd_qh_free_ddma() - Frees a QH structure's Descriptor DMA related 3808c2ecf20Sopenharmony_ci * members 3818c2ecf20Sopenharmony_ci * 3828c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller 3838c2ecf20Sopenharmony_ci * @qh: The QH to free 3848c2ecf20Sopenharmony_ci * 3858c2ecf20Sopenharmony_ci * Frees descriptor list memory associated with the QH. If QH is periodic and 3868c2ecf20Sopenharmony_ci * the last, frees FrameList memory and disables periodic scheduling. 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_civoid dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci unsigned long flags; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci dwc2_desc_list_free(hsotg, qh); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* 3958c2ecf20Sopenharmony_ci * Channel still assigned due to some reasons. 3968c2ecf20Sopenharmony_ci * Seen on Isoc URB dequeue. Channel halted but no subsequent 3978c2ecf20Sopenharmony_ci * ChHalted interrupt to release the channel. Afterwards 3988c2ecf20Sopenharmony_ci * when it comes here from endpoint disable routine 3998c2ecf20Sopenharmony_ci * channel remains assigned. 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 4028c2ecf20Sopenharmony_ci if (qh->channel) 4038c2ecf20Sopenharmony_ci dwc2_release_channel_ddma(hsotg, qh); 4048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC || 4078c2ecf20Sopenharmony_ci qh->ep_type == USB_ENDPOINT_XFER_INT) && 4088c2ecf20Sopenharmony_ci (hsotg->params.uframe_sched || 4098c2ecf20Sopenharmony_ci !hsotg->periodic_channels) && hsotg->frame_list) { 4108c2ecf20Sopenharmony_ci dwc2_per_sched_disable(hsotg); 4118c2ecf20Sopenharmony_ci dwc2_frame_list_free(hsotg); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic u8 dwc2_frame_to_desc_idx(struct dwc2_qh *qh, u16 frame_idx) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci if (qh->dev_speed == USB_SPEED_HIGH) 4188c2ecf20Sopenharmony_ci /* Descriptor set (8 descriptors) index which is 8-aligned */ 4198c2ecf20Sopenharmony_ci return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8; 4208c2ecf20Sopenharmony_ci else 4218c2ecf20Sopenharmony_ci return frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1); 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci/* 4258c2ecf20Sopenharmony_ci * Determine starting frame for Isochronous transfer. 4268c2ecf20Sopenharmony_ci * Few frames skipped to prevent race condition with HC. 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_cistatic u16 dwc2_calc_starting_frame(struct dwc2_hsotg *hsotg, 4298c2ecf20Sopenharmony_ci struct dwc2_qh *qh, u16 *skip_frames) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci u16 frame; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* 4368c2ecf20Sopenharmony_ci * next_active_frame is always frame number (not uFrame) both in FS 4378c2ecf20Sopenharmony_ci * and HS! 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* 4418c2ecf20Sopenharmony_ci * skip_frames is used to limit activated descriptors number 4428c2ecf20Sopenharmony_ci * to avoid the situation when HC services the last activated 4438c2ecf20Sopenharmony_ci * descriptor firstly. 4448c2ecf20Sopenharmony_ci * Example for FS: 4458c2ecf20Sopenharmony_ci * Current frame is 1, scheduled frame is 3. Since HC always fetches 4468c2ecf20Sopenharmony_ci * the descriptor corresponding to curr_frame+1, the descriptor 4478c2ecf20Sopenharmony_ci * corresponding to frame 2 will be fetched. If the number of 4488c2ecf20Sopenharmony_ci * descriptors is max=64 (or greather) the list will be fully programmed 4498c2ecf20Sopenharmony_ci * with Active descriptors and it is possible case (rare) that the 4508c2ecf20Sopenharmony_ci * latest descriptor(considering rollback) corresponding to frame 2 will 4518c2ecf20Sopenharmony_ci * be serviced first. HS case is more probable because, in fact, up to 4528c2ecf20Sopenharmony_ci * 11 uframes (16 in the code) may be skipped. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_ci if (qh->dev_speed == USB_SPEED_HIGH) { 4558c2ecf20Sopenharmony_ci /* 4568c2ecf20Sopenharmony_ci * Consider uframe counter also, to start xfer asap. If half of 4578c2ecf20Sopenharmony_ci * the frame elapsed skip 2 frames otherwise just 1 frame. 4588c2ecf20Sopenharmony_ci * Starting descriptor index must be 8-aligned, so if the 4598c2ecf20Sopenharmony_ci * current frame is near to complete the next one is skipped as 4608c2ecf20Sopenharmony_ci * well. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_ci if (dwc2_micro_frame_num(hsotg->frame_number) >= 5) { 4638c2ecf20Sopenharmony_ci *skip_frames = 2 * 8; 4648c2ecf20Sopenharmony_ci frame = dwc2_frame_num_inc(hsotg->frame_number, 4658c2ecf20Sopenharmony_ci *skip_frames); 4668c2ecf20Sopenharmony_ci } else { 4678c2ecf20Sopenharmony_ci *skip_frames = 1 * 8; 4688c2ecf20Sopenharmony_ci frame = dwc2_frame_num_inc(hsotg->frame_number, 4698c2ecf20Sopenharmony_ci *skip_frames); 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci frame = dwc2_full_frame_num(frame); 4738c2ecf20Sopenharmony_ci } else { 4748c2ecf20Sopenharmony_ci /* 4758c2ecf20Sopenharmony_ci * Two frames are skipped for FS - the current and the next. 4768c2ecf20Sopenharmony_ci * But for descriptor programming, 1 frame (descriptor) is 4778c2ecf20Sopenharmony_ci * enough, see example above. 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci *skip_frames = 1; 4808c2ecf20Sopenharmony_ci frame = dwc2_frame_num_inc(hsotg->frame_number, 2); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return frame; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/* 4878c2ecf20Sopenharmony_ci * Calculate initial descriptor index for isochronous transfer based on 4888c2ecf20Sopenharmony_ci * scheduled frame 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_cistatic u16 dwc2_recalc_initial_desc_idx(struct dwc2_hsotg *hsotg, 4918c2ecf20Sopenharmony_ci struct dwc2_qh *qh) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci u16 frame, fr_idx, fr_idx_tmp, skip_frames; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* 4968c2ecf20Sopenharmony_ci * With current ISOC processing algorithm the channel is being released 4978c2ecf20Sopenharmony_ci * when no more QTDs in the list (qh->ntd == 0). Thus this function is 4988c2ecf20Sopenharmony_ci * called only when qh->ntd == 0 and qh->channel == 0. 4998c2ecf20Sopenharmony_ci * 5008c2ecf20Sopenharmony_ci * So qh->channel != NULL branch is not used and just not removed from 5018c2ecf20Sopenharmony_ci * the source file. It is required for another possible approach which 5028c2ecf20Sopenharmony_ci * is, do not disable and release the channel when ISOC session 5038c2ecf20Sopenharmony_ci * completed, just move QH to inactive schedule until new QTD arrives. 5048c2ecf20Sopenharmony_ci * On new QTD, the QH moved back to 'ready' schedule, starting frame and 5058c2ecf20Sopenharmony_ci * therefore starting desc_index are recalculated. In this case channel 5068c2ecf20Sopenharmony_ci * is released only on ep_disable. 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* 5108c2ecf20Sopenharmony_ci * Calculate starting descriptor index. For INTERRUPT endpoint it is 5118c2ecf20Sopenharmony_ci * always 0. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_ci if (qh->channel) { 5148c2ecf20Sopenharmony_ci frame = dwc2_calc_starting_frame(hsotg, qh, &skip_frames); 5158c2ecf20Sopenharmony_ci /* 5168c2ecf20Sopenharmony_ci * Calculate initial descriptor index based on FrameList current 5178c2ecf20Sopenharmony_ci * bitmap and servicing period 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_ci fr_idx_tmp = dwc2_frame_list_idx(frame); 5208c2ecf20Sopenharmony_ci fr_idx = (FRLISTEN_64_SIZE + 5218c2ecf20Sopenharmony_ci dwc2_frame_list_idx(qh->next_active_frame) - 5228c2ecf20Sopenharmony_ci fr_idx_tmp) % dwc2_frame_incr_val(qh); 5238c2ecf20Sopenharmony_ci fr_idx = (fr_idx + fr_idx_tmp) % FRLISTEN_64_SIZE; 5248c2ecf20Sopenharmony_ci } else { 5258c2ecf20Sopenharmony_ci qh->next_active_frame = dwc2_calc_starting_frame(hsotg, qh, 5268c2ecf20Sopenharmony_ci &skip_frames); 5278c2ecf20Sopenharmony_ci fr_idx = dwc2_frame_list_idx(qh->next_active_frame); 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci qh->td_first = qh->td_last = dwc2_frame_to_desc_idx(qh, fr_idx); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return skip_frames; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci#define ISOC_URB_GIVEBACK_ASAP 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci#define MAX_ISOC_XFER_SIZE_FS 1023 5388c2ecf20Sopenharmony_ci#define MAX_ISOC_XFER_SIZE_HS 3072 5398c2ecf20Sopenharmony_ci#define DESCNUM_THRESHOLD 4 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, 5428c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, 5438c2ecf20Sopenharmony_ci struct dwc2_qh *qh, u32 max_xfer_size, 5448c2ecf20Sopenharmony_ci u16 idx) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct dwc2_dma_desc *dma_desc = &qh->desc_list[idx]; 5478c2ecf20Sopenharmony_ci struct dwc2_hcd_iso_packet_desc *frame_desc; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci memset(dma_desc, 0, sizeof(*dma_desc)); 5508c2ecf20Sopenharmony_ci frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last]; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (frame_desc->length > max_xfer_size) 5538c2ecf20Sopenharmony_ci qh->n_bytes[idx] = max_xfer_size; 5548c2ecf20Sopenharmony_ci else 5558c2ecf20Sopenharmony_ci qh->n_bytes[idx] = frame_desc->length; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset); 5588c2ecf20Sopenharmony_ci dma_desc->status = qh->n_bytes[idx] << HOST_DMA_ISOC_NBYTES_SHIFT & 5598c2ecf20Sopenharmony_ci HOST_DMA_ISOC_NBYTES_MASK; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* Set active bit */ 5628c2ecf20Sopenharmony_ci dma_desc->status |= HOST_DMA_A; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci qh->ntd++; 5658c2ecf20Sopenharmony_ci qtd->isoc_frame_index_last++; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci#ifdef ISOC_URB_GIVEBACK_ASAP 5688c2ecf20Sopenharmony_ci /* Set IOC for each descriptor corresponding to last frame of URB */ 5698c2ecf20Sopenharmony_ci if (qtd->isoc_frame_index_last == qtd->urb->packet_count) 5708c2ecf20Sopenharmony_ci dma_desc->status |= HOST_DMA_IOC; 5718c2ecf20Sopenharmony_ci#endif 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci dma_sync_single_for_device(hsotg->dev, 5748c2ecf20Sopenharmony_ci qh->desc_list_dma + 5758c2ecf20Sopenharmony_ci (idx * sizeof(struct dwc2_dma_desc)), 5768c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 5778c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg, 5818c2ecf20Sopenharmony_ci struct dwc2_qh *qh, u16 skip_frames) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd; 5848c2ecf20Sopenharmony_ci u32 max_xfer_size; 5858c2ecf20Sopenharmony_ci u16 idx, inc, n_desc = 0, ntd_max = 0; 5868c2ecf20Sopenharmony_ci u16 cur_idx; 5878c2ecf20Sopenharmony_ci u16 next_idx; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci idx = qh->td_last; 5908c2ecf20Sopenharmony_ci inc = qh->host_interval; 5918c2ecf20Sopenharmony_ci hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg); 5928c2ecf20Sopenharmony_ci cur_idx = dwc2_frame_list_idx(hsotg->frame_number); 5938c2ecf20Sopenharmony_ci next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* 5968c2ecf20Sopenharmony_ci * Ensure current frame number didn't overstep last scheduled 5978c2ecf20Sopenharmony_ci * descriptor. If it happens, the only way to recover is to move 5988c2ecf20Sopenharmony_ci * qh->td_last to current frame number + 1. 5998c2ecf20Sopenharmony_ci * So that next isoc descriptor will be scheduled on frame number + 1 6008c2ecf20Sopenharmony_ci * and not on a past frame. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci if (dwc2_frame_idx_num_gt(cur_idx, next_idx) || (cur_idx == next_idx)) { 6038c2ecf20Sopenharmony_ci if (inc < 32) { 6048c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 6058c2ecf20Sopenharmony_ci "current frame number overstep last descriptor\n"); 6068c2ecf20Sopenharmony_ci qh->td_last = dwc2_desclist_idx_inc(cur_idx, inc, 6078c2ecf20Sopenharmony_ci qh->dev_speed); 6088c2ecf20Sopenharmony_ci idx = qh->td_last; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (qh->host_interval) { 6138c2ecf20Sopenharmony_ci ntd_max = (dwc2_max_desc_num(qh) + qh->host_interval - 1) / 6148c2ecf20Sopenharmony_ci qh->host_interval; 6158c2ecf20Sopenharmony_ci if (skip_frames && !qh->channel) 6168c2ecf20Sopenharmony_ci ntd_max -= skip_frames / qh->host_interval; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci max_xfer_size = qh->dev_speed == USB_SPEED_HIGH ? 6208c2ecf20Sopenharmony_ci MAX_ISOC_XFER_SIZE_HS : MAX_ISOC_XFER_SIZE_FS; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) { 6238c2ecf20Sopenharmony_ci if (qtd->in_process && 6248c2ecf20Sopenharmony_ci qtd->isoc_frame_index_last == 6258c2ecf20Sopenharmony_ci qtd->urb->packet_count) 6268c2ecf20Sopenharmony_ci continue; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci qtd->isoc_td_first = idx; 6298c2ecf20Sopenharmony_ci while (qh->ntd < ntd_max && qtd->isoc_frame_index_last < 6308c2ecf20Sopenharmony_ci qtd->urb->packet_count) { 6318c2ecf20Sopenharmony_ci dwc2_fill_host_isoc_dma_desc(hsotg, qtd, qh, 6328c2ecf20Sopenharmony_ci max_xfer_size, idx); 6338c2ecf20Sopenharmony_ci idx = dwc2_desclist_idx_inc(idx, inc, qh->dev_speed); 6348c2ecf20Sopenharmony_ci n_desc++; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci qtd->isoc_td_last = idx; 6378c2ecf20Sopenharmony_ci qtd->in_process = 1; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci qh->td_last = idx; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci#ifdef ISOC_URB_GIVEBACK_ASAP 6438c2ecf20Sopenharmony_ci /* Set IOC for last descriptor if descriptor list is full */ 6448c2ecf20Sopenharmony_ci if (qh->ntd == ntd_max) { 6458c2ecf20Sopenharmony_ci idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed); 6468c2ecf20Sopenharmony_ci qh->desc_list[idx].status |= HOST_DMA_IOC; 6478c2ecf20Sopenharmony_ci dma_sync_single_for_device(hsotg->dev, 6488c2ecf20Sopenharmony_ci qh->desc_list_dma + (idx * 6498c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc)), 6508c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 6518c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci#else 6548c2ecf20Sopenharmony_ci /* 6558c2ecf20Sopenharmony_ci * Set IOC bit only for one descriptor. Always try to be ahead of HW 6568c2ecf20Sopenharmony_ci * processing, i.e. on IOC generation driver activates next descriptor 6578c2ecf20Sopenharmony_ci * but core continues to process descriptors following the one with IOC 6588c2ecf20Sopenharmony_ci * set. 6598c2ecf20Sopenharmony_ci */ 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (n_desc > DESCNUM_THRESHOLD) 6628c2ecf20Sopenharmony_ci /* 6638c2ecf20Sopenharmony_ci * Move IOC "up". Required even if there is only one QTD 6648c2ecf20Sopenharmony_ci * in the list, because QTDs might continue to be queued, 6658c2ecf20Sopenharmony_ci * but during the activation it was only one queued. 6668c2ecf20Sopenharmony_ci * Actually more than one QTD might be in the list if this 6678c2ecf20Sopenharmony_ci * function called from XferCompletion - QTDs was queued during 6688c2ecf20Sopenharmony_ci * HW processing of the previous descriptor chunk. 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci idx = dwc2_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), 6718c2ecf20Sopenharmony_ci qh->dev_speed); 6728c2ecf20Sopenharmony_ci else 6738c2ecf20Sopenharmony_ci /* 6748c2ecf20Sopenharmony_ci * Set the IOC for the latest descriptor if either number of 6758c2ecf20Sopenharmony_ci * descriptors is not greater than threshold or no more new 6768c2ecf20Sopenharmony_ci * descriptors activated 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci qh->desc_list[idx].status |= HOST_DMA_IOC; 6818c2ecf20Sopenharmony_ci dma_sync_single_for_device(hsotg->dev, 6828c2ecf20Sopenharmony_ci qh->desc_list_dma + 6838c2ecf20Sopenharmony_ci (idx * sizeof(struct dwc2_dma_desc)), 6848c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 6858c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6868c2ecf20Sopenharmony_ci#endif 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg, 6908c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, 6918c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, struct dwc2_qh *qh, 6928c2ecf20Sopenharmony_ci int n_desc) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct dwc2_dma_desc *dma_desc = &qh->desc_list[n_desc]; 6958c2ecf20Sopenharmony_ci int len = chan->xfer_len; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (len > HOST_DMA_NBYTES_LIMIT - (chan->max_packet - 1)) 6988c2ecf20Sopenharmony_ci len = HOST_DMA_NBYTES_LIMIT - (chan->max_packet - 1); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (chan->ep_is_in) { 7018c2ecf20Sopenharmony_ci int num_packets; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (len > 0 && chan->max_packet) 7048c2ecf20Sopenharmony_ci num_packets = (len + chan->max_packet - 1) 7058c2ecf20Sopenharmony_ci / chan->max_packet; 7068c2ecf20Sopenharmony_ci else 7078c2ecf20Sopenharmony_ci /* Need 1 packet for transfer length of 0 */ 7088c2ecf20Sopenharmony_ci num_packets = 1; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* Always program an integral # of packets for IN transfers */ 7118c2ecf20Sopenharmony_ci len = num_packets * chan->max_packet; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci dma_desc->status = len << HOST_DMA_NBYTES_SHIFT & HOST_DMA_NBYTES_MASK; 7158c2ecf20Sopenharmony_ci qh->n_bytes[n_desc] = len; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL && 7188c2ecf20Sopenharmony_ci qtd->control_phase == DWC2_CONTROL_SETUP) 7198c2ecf20Sopenharmony_ci dma_desc->status |= HOST_DMA_SUP; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci dma_desc->buf = (u32)chan->xfer_dma; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci dma_sync_single_for_device(hsotg->dev, 7248c2ecf20Sopenharmony_ci qh->desc_list_dma + 7258c2ecf20Sopenharmony_ci (n_desc * sizeof(struct dwc2_dma_desc)), 7268c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 7278c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* 7308c2ecf20Sopenharmony_ci * Last (or only) descriptor of IN transfer with actual size less 7318c2ecf20Sopenharmony_ci * than MaxPacket 7328c2ecf20Sopenharmony_ci */ 7338c2ecf20Sopenharmony_ci if (len > chan->xfer_len) { 7348c2ecf20Sopenharmony_ci chan->xfer_len = 0; 7358c2ecf20Sopenharmony_ci } else { 7368c2ecf20Sopenharmony_ci chan->xfer_dma += len; 7378c2ecf20Sopenharmony_ci chan->xfer_len -= len; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg, 7428c2ecf20Sopenharmony_ci struct dwc2_qh *qh) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd; 7458c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan = qh->channel; 7468c2ecf20Sopenharmony_ci int n_desc = 0; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "%s(): qh=%p dma=%08lx len=%d\n", __func__, qh, 7498c2ecf20Sopenharmony_ci (unsigned long)chan->xfer_dma, chan->xfer_len); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* 7528c2ecf20Sopenharmony_ci * Start with chan->xfer_dma initialized in assign_and_init_hc(), then 7538c2ecf20Sopenharmony_ci * if SG transfer consists of multiple URBs, this pointer is re-assigned 7548c2ecf20Sopenharmony_ci * to the buffer of the currently processed QTD. For non-SG request 7558c2ecf20Sopenharmony_ci * there is always one QTD active. 7568c2ecf20Sopenharmony_ci */ 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) { 7598c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "qtd=%p\n", qtd); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (n_desc) { 7628c2ecf20Sopenharmony_ci /* SG request - more than 1 QTD */ 7638c2ecf20Sopenharmony_ci chan->xfer_dma = qtd->urb->dma + 7648c2ecf20Sopenharmony_ci qtd->urb->actual_length; 7658c2ecf20Sopenharmony_ci chan->xfer_len = qtd->urb->length - 7668c2ecf20Sopenharmony_ci qtd->urb->actual_length; 7678c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "buf=%08lx len=%d\n", 7688c2ecf20Sopenharmony_ci (unsigned long)chan->xfer_dma, chan->xfer_len); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci qtd->n_desc = 0; 7728c2ecf20Sopenharmony_ci do { 7738c2ecf20Sopenharmony_ci if (n_desc > 1) { 7748c2ecf20Sopenharmony_ci qh->desc_list[n_desc - 1].status |= HOST_DMA_A; 7758c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 7768c2ecf20Sopenharmony_ci "set A bit in desc %d (%p)\n", 7778c2ecf20Sopenharmony_ci n_desc - 1, 7788c2ecf20Sopenharmony_ci &qh->desc_list[n_desc - 1]); 7798c2ecf20Sopenharmony_ci dma_sync_single_for_device(hsotg->dev, 7808c2ecf20Sopenharmony_ci qh->desc_list_dma + 7818c2ecf20Sopenharmony_ci ((n_desc - 1) * 7828c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc)), 7838c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 7848c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc); 7878c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 7888c2ecf20Sopenharmony_ci "desc %d (%p) buf=%08x status=%08x\n", 7898c2ecf20Sopenharmony_ci n_desc, &qh->desc_list[n_desc], 7908c2ecf20Sopenharmony_ci qh->desc_list[n_desc].buf, 7918c2ecf20Sopenharmony_ci qh->desc_list[n_desc].status); 7928c2ecf20Sopenharmony_ci qtd->n_desc++; 7938c2ecf20Sopenharmony_ci n_desc++; 7948c2ecf20Sopenharmony_ci } while (chan->xfer_len > 0 && 7958c2ecf20Sopenharmony_ci n_desc != MAX_DMA_DESC_NUM_GENERIC); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "n_desc=%d\n", n_desc); 7988c2ecf20Sopenharmony_ci qtd->in_process = 1; 7998c2ecf20Sopenharmony_ci if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL) 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci if (n_desc == MAX_DMA_DESC_NUM_GENERIC) 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (n_desc) { 8068c2ecf20Sopenharmony_ci qh->desc_list[n_desc - 1].status |= 8078c2ecf20Sopenharmony_ci HOST_DMA_IOC | HOST_DMA_EOL | HOST_DMA_A; 8088c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "set IOC/EOL/A bits in desc %d (%p)\n", 8098c2ecf20Sopenharmony_ci n_desc - 1, &qh->desc_list[n_desc - 1]); 8108c2ecf20Sopenharmony_ci dma_sync_single_for_device(hsotg->dev, 8118c2ecf20Sopenharmony_ci qh->desc_list_dma + (n_desc - 1) * 8128c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 8138c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 8148c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 8158c2ecf20Sopenharmony_ci if (n_desc > 1) { 8168c2ecf20Sopenharmony_ci qh->desc_list[0].status |= HOST_DMA_A; 8178c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n", 8188c2ecf20Sopenharmony_ci &qh->desc_list[0]); 8198c2ecf20Sopenharmony_ci dma_sync_single_for_device(hsotg->dev, 8208c2ecf20Sopenharmony_ci qh->desc_list_dma, 8218c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 8228c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci chan->ntd = n_desc; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci/** 8298c2ecf20Sopenharmony_ci * dwc2_hcd_start_xfer_ddma() - Starts a transfer in Descriptor DMA mode 8308c2ecf20Sopenharmony_ci * 8318c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller 8328c2ecf20Sopenharmony_ci * @qh: The QH to init 8338c2ecf20Sopenharmony_ci * 8348c2ecf20Sopenharmony_ci * Return: 0 if successful, negative error code otherwise 8358c2ecf20Sopenharmony_ci * 8368c2ecf20Sopenharmony_ci * For Control and Bulk endpoints, initializes descriptor list and starts the 8378c2ecf20Sopenharmony_ci * transfer. For Interrupt and Isochronous endpoints, initializes descriptor 8388c2ecf20Sopenharmony_ci * list then updates FrameList, marking appropriate entries as active. 8398c2ecf20Sopenharmony_ci * 8408c2ecf20Sopenharmony_ci * For Isochronous endpoints the starting descriptor index is calculated based 8418c2ecf20Sopenharmony_ci * on the scheduled frame, but only on the first transfer descriptor within a 8428c2ecf20Sopenharmony_ci * session. Then the transfer is started via enabling the channel. 8438c2ecf20Sopenharmony_ci * 8448c2ecf20Sopenharmony_ci * For Isochronous endpoints the channel is not halted on XferComplete 8458c2ecf20Sopenharmony_ci * interrupt so remains assigned to the endpoint(QH) until session is done. 8468c2ecf20Sopenharmony_ci */ 8478c2ecf20Sopenharmony_civoid dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci /* Channel is already assigned */ 8508c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan = qh->channel; 8518c2ecf20Sopenharmony_ci u16 skip_frames = 0; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci switch (chan->ep_type) { 8548c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 8558c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 8568c2ecf20Sopenharmony_ci dwc2_init_non_isoc_dma_desc(hsotg, qh); 8578c2ecf20Sopenharmony_ci dwc2_hc_start_transfer_ddma(hsotg, chan); 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 8608c2ecf20Sopenharmony_ci dwc2_init_non_isoc_dma_desc(hsotg, qh); 8618c2ecf20Sopenharmony_ci dwc2_update_frame_list(hsotg, qh, 1); 8628c2ecf20Sopenharmony_ci dwc2_hc_start_transfer_ddma(hsotg, chan); 8638c2ecf20Sopenharmony_ci break; 8648c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 8658c2ecf20Sopenharmony_ci if (!qh->ntd) 8668c2ecf20Sopenharmony_ci skip_frames = dwc2_recalc_initial_desc_idx(hsotg, qh); 8678c2ecf20Sopenharmony_ci dwc2_init_isoc_dma_desc(hsotg, qh, skip_frames); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (!chan->xfer_started) { 8708c2ecf20Sopenharmony_ci dwc2_update_frame_list(hsotg, qh, 1); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* 8738c2ecf20Sopenharmony_ci * Always set to max, instead of actual size. Otherwise 8748c2ecf20Sopenharmony_ci * ntd will be changed with channel being enabled. Not 8758c2ecf20Sopenharmony_ci * recommended. 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_ci chan->ntd = dwc2_max_desc_num(qh); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci /* Enable channel only once for ISOC */ 8808c2ecf20Sopenharmony_ci dwc2_hc_start_transfer_ddma(hsotg, chan); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci break; 8848c2ecf20Sopenharmony_ci default: 8858c2ecf20Sopenharmony_ci break; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci#define DWC2_CMPL_DONE 1 8908c2ecf20Sopenharmony_ci#define DWC2_CMPL_STOP 2 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, 8938c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, 8948c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, 8958c2ecf20Sopenharmony_ci struct dwc2_qh *qh, u16 idx) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct dwc2_dma_desc *dma_desc; 8988c2ecf20Sopenharmony_ci struct dwc2_hcd_iso_packet_desc *frame_desc; 8998c2ecf20Sopenharmony_ci u16 remain = 0; 9008c2ecf20Sopenharmony_ci int rc = 0; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (!qtd->urb) 9038c2ecf20Sopenharmony_ci return -EINVAL; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(hsotg->dev, qh->desc_list_dma + (idx * 9068c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc)), 9078c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 9088c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci dma_desc = &qh->desc_list[idx]; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last]; 9138c2ecf20Sopenharmony_ci dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset); 9148c2ecf20Sopenharmony_ci if (chan->ep_is_in) 9158c2ecf20Sopenharmony_ci remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >> 9168c2ecf20Sopenharmony_ci HOST_DMA_ISOC_NBYTES_SHIFT; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) { 9198c2ecf20Sopenharmony_ci /* 9208c2ecf20Sopenharmony_ci * XactError, or unable to complete all the transactions 9218c2ecf20Sopenharmony_ci * in the scheduled micro-frame/frame, both indicated by 9228c2ecf20Sopenharmony_ci * HOST_DMA_STS_PKTERR 9238c2ecf20Sopenharmony_ci */ 9248c2ecf20Sopenharmony_ci qtd->urb->error_count++; 9258c2ecf20Sopenharmony_ci frame_desc->actual_length = qh->n_bytes[idx] - remain; 9268c2ecf20Sopenharmony_ci frame_desc->status = -EPROTO; 9278c2ecf20Sopenharmony_ci } else { 9288c2ecf20Sopenharmony_ci /* Success */ 9298c2ecf20Sopenharmony_ci frame_desc->actual_length = qh->n_bytes[idx] - remain; 9308c2ecf20Sopenharmony_ci frame_desc->status = 0; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (++qtd->isoc_frame_index == qtd->urb->packet_count) { 9348c2ecf20Sopenharmony_ci /* 9358c2ecf20Sopenharmony_ci * urb->status is not used for isoc transfers here. The 9368c2ecf20Sopenharmony_ci * individual frame_desc status are used instead. 9378c2ecf20Sopenharmony_ci */ 9388c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, 0); 9398c2ecf20Sopenharmony_ci dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* 9428c2ecf20Sopenharmony_ci * This check is necessary because urb_dequeue can be called 9438c2ecf20Sopenharmony_ci * from urb complete callback (sound driver for example). All 9448c2ecf20Sopenharmony_ci * pending URBs are dequeued there, so no need for further 9458c2ecf20Sopenharmony_ci * processing. 9468c2ecf20Sopenharmony_ci */ 9478c2ecf20Sopenharmony_ci if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) 9488c2ecf20Sopenharmony_ci return -1; 9498c2ecf20Sopenharmony_ci rc = DWC2_CMPL_DONE; 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci qh->ntd--; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci /* Stop if IOC requested descriptor reached */ 9558c2ecf20Sopenharmony_ci if (dma_desc->status & HOST_DMA_IOC) 9568c2ecf20Sopenharmony_ci rc = DWC2_CMPL_STOP; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci return rc; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg, 9628c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, 9638c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci struct dwc2_hcd_iso_packet_desc *frame_desc; 9668c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, *qtd_tmp; 9678c2ecf20Sopenharmony_ci struct dwc2_qh *qh; 9688c2ecf20Sopenharmony_ci u16 idx; 9698c2ecf20Sopenharmony_ci int rc; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci qh = chan->qh; 9728c2ecf20Sopenharmony_ci idx = qh->td_first; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) { 9758c2ecf20Sopenharmony_ci list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) 9768c2ecf20Sopenharmony_ci qtd->in_process = 0; 9778c2ecf20Sopenharmony_ci return; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (halt_status == DWC2_HC_XFER_AHB_ERR || 9818c2ecf20Sopenharmony_ci halt_status == DWC2_HC_XFER_BABBLE_ERR) { 9828c2ecf20Sopenharmony_ci /* 9838c2ecf20Sopenharmony_ci * Channel is halted in these error cases, considered as serious 9848c2ecf20Sopenharmony_ci * issues. 9858c2ecf20Sopenharmony_ci * Complete all URBs marking all frames as failed, irrespective 9868c2ecf20Sopenharmony_ci * whether some of the descriptors (frames) succeeded or not. 9878c2ecf20Sopenharmony_ci * Pass error code to completion routine as well, to update 9888c2ecf20Sopenharmony_ci * urb->status, some of class drivers might use it to stop 9898c2ecf20Sopenharmony_ci * queing transfer requests. 9908c2ecf20Sopenharmony_ci */ 9918c2ecf20Sopenharmony_ci int err = halt_status == DWC2_HC_XFER_AHB_ERR ? 9928c2ecf20Sopenharmony_ci -EIO : -EOVERFLOW; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, 9958c2ecf20Sopenharmony_ci qtd_list_entry) { 9968c2ecf20Sopenharmony_ci if (qtd->urb) { 9978c2ecf20Sopenharmony_ci for (idx = 0; idx < qtd->urb->packet_count; 9988c2ecf20Sopenharmony_ci idx++) { 9998c2ecf20Sopenharmony_ci frame_desc = &qtd->urb->iso_descs[idx]; 10008c2ecf20Sopenharmony_ci frame_desc->status = err; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, err); 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci return; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) { 10138c2ecf20Sopenharmony_ci if (!qtd->in_process) 10148c2ecf20Sopenharmony_ci break; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci /* 10178c2ecf20Sopenharmony_ci * Ensure idx corresponds to descriptor where first urb of this 10188c2ecf20Sopenharmony_ci * qtd was added. In fact, during isoc desc init, dwc2 may skip 10198c2ecf20Sopenharmony_ci * an index if current frame number is already over this index. 10208c2ecf20Sopenharmony_ci */ 10218c2ecf20Sopenharmony_ci if (idx != qtd->isoc_td_first) { 10228c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 10238c2ecf20Sopenharmony_ci "try to complete %d instead of %d\n", 10248c2ecf20Sopenharmony_ci idx, qtd->isoc_td_first); 10258c2ecf20Sopenharmony_ci idx = qtd->isoc_td_first; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci do { 10298c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd_next; 10308c2ecf20Sopenharmony_ci u16 cur_idx; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci rc = dwc2_cmpl_host_isoc_dma_desc(hsotg, chan, qtd, qh, 10338c2ecf20Sopenharmony_ci idx); 10348c2ecf20Sopenharmony_ci if (rc < 0) 10358c2ecf20Sopenharmony_ci return; 10368c2ecf20Sopenharmony_ci idx = dwc2_desclist_idx_inc(idx, qh->host_interval, 10378c2ecf20Sopenharmony_ci chan->speed); 10388c2ecf20Sopenharmony_ci if (!rc) 10398c2ecf20Sopenharmony_ci continue; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (rc == DWC2_CMPL_DONE) 10428c2ecf20Sopenharmony_ci break; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* rc == DWC2_CMPL_STOP */ 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (qh->host_interval >= 32) 10478c2ecf20Sopenharmony_ci goto stop_scan; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci qh->td_first = idx; 10508c2ecf20Sopenharmony_ci cur_idx = dwc2_frame_list_idx(hsotg->frame_number); 10518c2ecf20Sopenharmony_ci qtd_next = list_first_entry(&qh->qtd_list, 10528c2ecf20Sopenharmony_ci struct dwc2_qtd, 10538c2ecf20Sopenharmony_ci qtd_list_entry); 10548c2ecf20Sopenharmony_ci if (dwc2_frame_idx_num_gt(cur_idx, 10558c2ecf20Sopenharmony_ci qtd_next->isoc_td_last)) 10568c2ecf20Sopenharmony_ci break; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci goto stop_scan; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci } while (idx != qh->td_first); 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_cistop_scan: 10648c2ecf20Sopenharmony_ci qh->td_first = idx; 10658c2ecf20Sopenharmony_ci} 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cistatic int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg, 10688c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, 10698c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, 10708c2ecf20Sopenharmony_ci struct dwc2_dma_desc *dma_desc, 10718c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status, 10728c2ecf20Sopenharmony_ci u32 n_bytes, int *xfer_done) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci struct dwc2_hcd_urb *urb = qtd->urb; 10758c2ecf20Sopenharmony_ci u16 remain = 0; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (chan->ep_is_in) 10788c2ecf20Sopenharmony_ci remain = (dma_desc->status & HOST_DMA_NBYTES_MASK) >> 10798c2ecf20Sopenharmony_ci HOST_DMA_NBYTES_SHIFT; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "remain=%d dwc2_urb=%p\n", remain, urb); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci if (halt_status == DWC2_HC_XFER_AHB_ERR) { 10848c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "EIO\n"); 10858c2ecf20Sopenharmony_ci urb->status = -EIO; 10868c2ecf20Sopenharmony_ci return 1; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) { 10908c2ecf20Sopenharmony_ci switch (halt_status) { 10918c2ecf20Sopenharmony_ci case DWC2_HC_XFER_STALL: 10928c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "Stall\n"); 10938c2ecf20Sopenharmony_ci urb->status = -EPIPE; 10948c2ecf20Sopenharmony_ci break; 10958c2ecf20Sopenharmony_ci case DWC2_HC_XFER_BABBLE_ERR: 10968c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "Babble\n"); 10978c2ecf20Sopenharmony_ci urb->status = -EOVERFLOW; 10988c2ecf20Sopenharmony_ci break; 10998c2ecf20Sopenharmony_ci case DWC2_HC_XFER_XACT_ERR: 11008c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "XactErr\n"); 11018c2ecf20Sopenharmony_ci urb->status = -EPROTO; 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci default: 11048c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 11058c2ecf20Sopenharmony_ci "%s: Unhandled descriptor error status (%d)\n", 11068c2ecf20Sopenharmony_ci __func__, halt_status); 11078c2ecf20Sopenharmony_ci break; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci return 1; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (dma_desc->status & HOST_DMA_A) { 11138c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 11148c2ecf20Sopenharmony_ci "Active descriptor encountered on channel %d\n", 11158c2ecf20Sopenharmony_ci chan->hc_num); 11168c2ecf20Sopenharmony_ci return 0; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL) { 11208c2ecf20Sopenharmony_ci if (qtd->control_phase == DWC2_CONTROL_DATA) { 11218c2ecf20Sopenharmony_ci urb->actual_length += n_bytes - remain; 11228c2ecf20Sopenharmony_ci if (remain || urb->actual_length >= urb->length) { 11238c2ecf20Sopenharmony_ci /* 11248c2ecf20Sopenharmony_ci * For Control Data stage do not set urb->status 11258c2ecf20Sopenharmony_ci * to 0, to prevent URB callback. Set it when 11268c2ecf20Sopenharmony_ci * Status phase is done. See below. 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_ci *xfer_done = 1; 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci } else if (qtd->control_phase == DWC2_CONTROL_STATUS) { 11318c2ecf20Sopenharmony_ci urb->status = 0; 11328c2ecf20Sopenharmony_ci *xfer_done = 1; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci /* No handling for SETUP stage */ 11358c2ecf20Sopenharmony_ci } else { 11368c2ecf20Sopenharmony_ci /* BULK and INTR */ 11378c2ecf20Sopenharmony_ci urb->actual_length += n_bytes - remain; 11388c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "length=%d actual=%d\n", urb->length, 11398c2ecf20Sopenharmony_ci urb->actual_length); 11408c2ecf20Sopenharmony_ci if (remain || urb->actual_length >= urb->length) { 11418c2ecf20Sopenharmony_ci urb->status = 0; 11428c2ecf20Sopenharmony_ci *xfer_done = 1; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci return 0; 11478c2ecf20Sopenharmony_ci} 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistatic int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg, 11508c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, 11518c2ecf20Sopenharmony_ci int chnum, struct dwc2_qtd *qtd, 11528c2ecf20Sopenharmony_ci int desc_num, 11538c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status, 11548c2ecf20Sopenharmony_ci int *xfer_done) 11558c2ecf20Sopenharmony_ci{ 11568c2ecf20Sopenharmony_ci struct dwc2_qh *qh = chan->qh; 11578c2ecf20Sopenharmony_ci struct dwc2_hcd_urb *urb = qtd->urb; 11588c2ecf20Sopenharmony_ci struct dwc2_dma_desc *dma_desc; 11598c2ecf20Sopenharmony_ci u32 n_bytes; 11608c2ecf20Sopenharmony_ci int failed; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "%s()\n", __func__); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (!urb) 11658c2ecf20Sopenharmony_ci return -EINVAL; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(hsotg->dev, 11688c2ecf20Sopenharmony_ci qh->desc_list_dma + (desc_num * 11698c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc)), 11708c2ecf20Sopenharmony_ci sizeof(struct dwc2_dma_desc), 11718c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci dma_desc = &qh->desc_list[desc_num]; 11748c2ecf20Sopenharmony_ci n_bytes = qh->n_bytes[desc_num]; 11758c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 11768c2ecf20Sopenharmony_ci "qtd=%p dwc2_urb=%p desc_num=%d desc=%p n_bytes=%d\n", 11778c2ecf20Sopenharmony_ci qtd, urb, desc_num, dma_desc, n_bytes); 11788c2ecf20Sopenharmony_ci failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc, 11798c2ecf20Sopenharmony_ci halt_status, n_bytes, 11808c2ecf20Sopenharmony_ci xfer_done); 11818c2ecf20Sopenharmony_ci if (failed || (*xfer_done && urb->status != -EINPROGRESS)) { 11828c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, urb->status); 11838c2ecf20Sopenharmony_ci dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); 11848c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x\n", 11858c2ecf20Sopenharmony_ci failed, *xfer_done); 11868c2ecf20Sopenharmony_ci return failed; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL) { 11908c2ecf20Sopenharmony_ci switch (qtd->control_phase) { 11918c2ecf20Sopenharmony_ci case DWC2_CONTROL_SETUP: 11928c2ecf20Sopenharmony_ci if (urb->length > 0) 11938c2ecf20Sopenharmony_ci qtd->control_phase = DWC2_CONTROL_DATA; 11948c2ecf20Sopenharmony_ci else 11958c2ecf20Sopenharmony_ci qtd->control_phase = DWC2_CONTROL_STATUS; 11968c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 11978c2ecf20Sopenharmony_ci " Control setup transaction done\n"); 11988c2ecf20Sopenharmony_ci break; 11998c2ecf20Sopenharmony_ci case DWC2_CONTROL_DATA: 12008c2ecf20Sopenharmony_ci if (*xfer_done) { 12018c2ecf20Sopenharmony_ci qtd->control_phase = DWC2_CONTROL_STATUS; 12028c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 12038c2ecf20Sopenharmony_ci " Control data transfer done\n"); 12048c2ecf20Sopenharmony_ci } else if (desc_num + 1 == qtd->n_desc) { 12058c2ecf20Sopenharmony_ci /* 12068c2ecf20Sopenharmony_ci * Last descriptor for Control data stage which 12078c2ecf20Sopenharmony_ci * is not completed yet 12088c2ecf20Sopenharmony_ci */ 12098c2ecf20Sopenharmony_ci dwc2_hcd_save_data_toggle(hsotg, chan, chnum, 12108c2ecf20Sopenharmony_ci qtd); 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci break; 12138c2ecf20Sopenharmony_ci default: 12148c2ecf20Sopenharmony_ci break; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci return 0; 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_cistatic void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg, 12228c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, 12238c2ecf20Sopenharmony_ci int chnum, 12248c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci struct list_head *qtd_item, *qtd_tmp; 12278c2ecf20Sopenharmony_ci struct dwc2_qh *qh = chan->qh; 12288c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd = NULL; 12298c2ecf20Sopenharmony_ci int xfer_done; 12308c2ecf20Sopenharmony_ci int desc_num = 0; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) { 12338c2ecf20Sopenharmony_ci list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) 12348c2ecf20Sopenharmony_ci qtd->in_process = 0; 12358c2ecf20Sopenharmony_ci return; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci list_for_each_safe(qtd_item, qtd_tmp, &qh->qtd_list) { 12398c2ecf20Sopenharmony_ci int i; 12408c2ecf20Sopenharmony_ci int qtd_desc_count; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci qtd = list_entry(qtd_item, struct dwc2_qtd, qtd_list_entry); 12438c2ecf20Sopenharmony_ci xfer_done = 0; 12448c2ecf20Sopenharmony_ci qtd_desc_count = qtd->n_desc; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci for (i = 0; i < qtd_desc_count; i++) { 12478c2ecf20Sopenharmony_ci if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd, 12488c2ecf20Sopenharmony_ci desc_num, halt_status, 12498c2ecf20Sopenharmony_ci &xfer_done)) { 12508c2ecf20Sopenharmony_ci qtd = NULL; 12518c2ecf20Sopenharmony_ci goto stop_scan; 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci desc_num++; 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistop_scan: 12598c2ecf20Sopenharmony_ci if (qh->ep_type != USB_ENDPOINT_XFER_CONTROL) { 12608c2ecf20Sopenharmony_ci /* 12618c2ecf20Sopenharmony_ci * Resetting the data toggle for bulk and interrupt endpoints 12628c2ecf20Sopenharmony_ci * in case of stall. See handle_hc_stall_intr(). 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_ci if (halt_status == DWC2_HC_XFER_STALL) 12658c2ecf20Sopenharmony_ci qh->data_toggle = DWC2_HC_PID_DATA0; 12668c2ecf20Sopenharmony_ci else 12678c2ecf20Sopenharmony_ci dwc2_hcd_save_data_toggle(hsotg, chan, chnum, NULL); 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (halt_status == DWC2_HC_XFER_COMPLETE) { 12718c2ecf20Sopenharmony_ci if (chan->hcint & HCINTMSK_NYET) { 12728c2ecf20Sopenharmony_ci /* 12738c2ecf20Sopenharmony_ci * Got a NYET on the last transaction of the transfer. 12748c2ecf20Sopenharmony_ci * It means that the endpoint should be in the PING 12758c2ecf20Sopenharmony_ci * state at the beginning of the next transfer. 12768c2ecf20Sopenharmony_ci */ 12778c2ecf20Sopenharmony_ci qh->ping_state = 1; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci/** 12838c2ecf20Sopenharmony_ci * dwc2_hcd_complete_xfer_ddma() - Scans the descriptor list, updates URB's 12848c2ecf20Sopenharmony_ci * status and calls completion routine for the URB if it's done. Called from 12858c2ecf20Sopenharmony_ci * interrupt handlers. 12868c2ecf20Sopenharmony_ci * 12878c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure for the DWC OTG controller 12888c2ecf20Sopenharmony_ci * @chan: Host channel the transfer is completed on 12898c2ecf20Sopenharmony_ci * @chnum: Index of Host channel registers 12908c2ecf20Sopenharmony_ci * @halt_status: Reason the channel is being halted or just XferComplete 12918c2ecf20Sopenharmony_ci * for isochronous transfers 12928c2ecf20Sopenharmony_ci * 12938c2ecf20Sopenharmony_ci * Releases the channel to be used by other transfers. 12948c2ecf20Sopenharmony_ci * In case of Isochronous endpoint the channel is not halted until the end of 12958c2ecf20Sopenharmony_ci * the session, i.e. QTD list is empty. 12968c2ecf20Sopenharmony_ci * If periodic channel released the FrameList is updated accordingly. 12978c2ecf20Sopenharmony_ci * Calls transaction selection routines to activate pending transfers. 12988c2ecf20Sopenharmony_ci */ 12998c2ecf20Sopenharmony_civoid dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg, 13008c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 13018c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci struct dwc2_qh *qh = chan->qh; 13048c2ecf20Sopenharmony_ci int continue_isoc_xfer = 0; 13058c2ecf20Sopenharmony_ci enum dwc2_transaction_type tr_type; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci if (chan->ep_type == USB_ENDPOINT_XFER_ISOC) { 13088c2ecf20Sopenharmony_ci dwc2_complete_isoc_xfer_ddma(hsotg, chan, halt_status); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci /* Release the channel if halted or session completed */ 13118c2ecf20Sopenharmony_ci if (halt_status != DWC2_HC_XFER_COMPLETE || 13128c2ecf20Sopenharmony_ci list_empty(&qh->qtd_list)) { 13138c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, *qtd_tmp; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* 13168c2ecf20Sopenharmony_ci * Kill all remainings QTDs since channel has been 13178c2ecf20Sopenharmony_ci * halted. 13188c2ecf20Sopenharmony_ci */ 13198c2ecf20Sopenharmony_ci list_for_each_entry_safe(qtd, qtd_tmp, 13208c2ecf20Sopenharmony_ci &qh->qtd_list, 13218c2ecf20Sopenharmony_ci qtd_list_entry) { 13228c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, 13238c2ecf20Sopenharmony_ci -ECONNRESET); 13248c2ecf20Sopenharmony_ci dwc2_hcd_qtd_unlink_and_free(hsotg, 13258c2ecf20Sopenharmony_ci qtd, qh); 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci /* Halt the channel if session completed */ 13298c2ecf20Sopenharmony_ci if (halt_status == DWC2_HC_XFER_COMPLETE) 13308c2ecf20Sopenharmony_ci dwc2_hc_halt(hsotg, chan, halt_status); 13318c2ecf20Sopenharmony_ci dwc2_release_channel_ddma(hsotg, qh); 13328c2ecf20Sopenharmony_ci dwc2_hcd_qh_unlink(hsotg, qh); 13338c2ecf20Sopenharmony_ci } else { 13348c2ecf20Sopenharmony_ci /* Keep in assigned schedule to continue transfer */ 13358c2ecf20Sopenharmony_ci list_move_tail(&qh->qh_list_entry, 13368c2ecf20Sopenharmony_ci &hsotg->periodic_sched_assigned); 13378c2ecf20Sopenharmony_ci /* 13388c2ecf20Sopenharmony_ci * If channel has been halted during giveback of urb 13398c2ecf20Sopenharmony_ci * then prevent any new scheduling. 13408c2ecf20Sopenharmony_ci */ 13418c2ecf20Sopenharmony_ci if (!chan->halt_status) 13428c2ecf20Sopenharmony_ci continue_isoc_xfer = 1; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci /* 13458c2ecf20Sopenharmony_ci * Todo: Consider the case when period exceeds FrameList size. 13468c2ecf20Sopenharmony_ci * Frame Rollover interrupt should be used. 13478c2ecf20Sopenharmony_ci */ 13488c2ecf20Sopenharmony_ci } else { 13498c2ecf20Sopenharmony_ci /* 13508c2ecf20Sopenharmony_ci * Scan descriptor list to complete the URB(s), then release 13518c2ecf20Sopenharmony_ci * the channel 13528c2ecf20Sopenharmony_ci */ 13538c2ecf20Sopenharmony_ci dwc2_complete_non_isoc_xfer_ddma(hsotg, chan, chnum, 13548c2ecf20Sopenharmony_ci halt_status); 13558c2ecf20Sopenharmony_ci dwc2_release_channel_ddma(hsotg, qh); 13568c2ecf20Sopenharmony_ci dwc2_hcd_qh_unlink(hsotg, qh); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (!list_empty(&qh->qtd_list)) { 13598c2ecf20Sopenharmony_ci /* 13608c2ecf20Sopenharmony_ci * Add back to inactive non-periodic schedule on normal 13618c2ecf20Sopenharmony_ci * completion 13628c2ecf20Sopenharmony_ci */ 13638c2ecf20Sopenharmony_ci dwc2_hcd_qh_add(hsotg, qh); 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci tr_type = dwc2_hcd_select_transactions(hsotg); 13688c2ecf20Sopenharmony_ci if (tr_type != DWC2_TRANSACTION_NONE || continue_isoc_xfer) { 13698c2ecf20Sopenharmony_ci if (continue_isoc_xfer) { 13708c2ecf20Sopenharmony_ci if (tr_type == DWC2_TRANSACTION_NONE) 13718c2ecf20Sopenharmony_ci tr_type = DWC2_TRANSACTION_PERIODIC; 13728c2ecf20Sopenharmony_ci else if (tr_type == DWC2_TRANSACTION_NON_PERIODIC) 13738c2ecf20Sopenharmony_ci tr_type = DWC2_TRANSACTION_ALL; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci dwc2_hcd_queue_transactions(hsotg, tr_type); 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci} 1378