162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2021, MediaTek Inc. 462306a36Sopenharmony_ci * Copyright (c) 2021-2022, Intel Corporation. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Authors: 762306a36Sopenharmony_ci * Amir Hanania <amir.hanania@intel.com> 862306a36Sopenharmony_ci * Haijun Liu <haijun.liu@mediatek.com> 962306a36Sopenharmony_ci * Moises Veleta <moises.veleta@intel.com> 1062306a36Sopenharmony_ci * Ricardo Martinez <ricardo.martinez@linux.intel.com> 1162306a36Sopenharmony_ci * Sreehari Kancharla <sreehari.kancharla@intel.com> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Contributors: 1462306a36Sopenharmony_ci * Andy Shevchenko <andriy.shevchenko@linux.intel.com> 1562306a36Sopenharmony_ci * Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com> 1662306a36Sopenharmony_ci * Eliot Lee <eliot.lee@intel.com> 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/bits.h> 2062306a36Sopenharmony_ci#include <linux/bitops.h> 2162306a36Sopenharmony_ci#include <linux/delay.h> 2262306a36Sopenharmony_ci#include <linux/device.h> 2362306a36Sopenharmony_ci#include <linux/dmapool.h> 2462306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2562306a36Sopenharmony_ci#include <linux/dma-direction.h> 2662306a36Sopenharmony_ci#include <linux/gfp.h> 2762306a36Sopenharmony_ci#include <linux/io.h> 2862306a36Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 2962306a36Sopenharmony_ci#include <linux/iopoll.h> 3062306a36Sopenharmony_ci#include <linux/irqreturn.h> 3162306a36Sopenharmony_ci#include <linux/kernel.h> 3262306a36Sopenharmony_ci#include <linux/kthread.h> 3362306a36Sopenharmony_ci#include <linux/list.h> 3462306a36Sopenharmony_ci#include <linux/netdevice.h> 3562306a36Sopenharmony_ci#include <linux/pci.h> 3662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3762306a36Sopenharmony_ci#include <linux/sched.h> 3862306a36Sopenharmony_ci#include <linux/skbuff.h> 3962306a36Sopenharmony_ci#include <linux/slab.h> 4062306a36Sopenharmony_ci#include <linux/spinlock.h> 4162306a36Sopenharmony_ci#include <linux/types.h> 4262306a36Sopenharmony_ci#include <linux/wait.h> 4362306a36Sopenharmony_ci#include <linux/workqueue.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "t7xx_cldma.h" 4662306a36Sopenharmony_ci#include "t7xx_hif_cldma.h" 4762306a36Sopenharmony_ci#include "t7xx_mhccif.h" 4862306a36Sopenharmony_ci#include "t7xx_pci.h" 4962306a36Sopenharmony_ci#include "t7xx_pcie_mac.h" 5062306a36Sopenharmony_ci#include "t7xx_port_proxy.h" 5162306a36Sopenharmony_ci#include "t7xx_reg.h" 5262306a36Sopenharmony_ci#include "t7xx_state_monitor.h" 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define MAX_TX_BUDGET 16 5562306a36Sopenharmony_ci#define MAX_RX_BUDGET 16 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define CHECK_Q_STOP_TIMEOUT_US 1000000 5862306a36Sopenharmony_ci#define CHECK_Q_STOP_STEP_US 10000 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define CLDMA_JUMBO_BUFF_SZ (63 * 1024 + sizeof(struct ccci_header)) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void md_cd_queue_struct_reset(struct cldma_queue *queue, struct cldma_ctrl *md_ctrl, 6362306a36Sopenharmony_ci enum mtk_txrx tx_rx, unsigned int index) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci queue->dir = tx_rx; 6662306a36Sopenharmony_ci queue->index = index; 6762306a36Sopenharmony_ci queue->md_ctrl = md_ctrl; 6862306a36Sopenharmony_ci queue->tr_ring = NULL; 6962306a36Sopenharmony_ci queue->tr_done = NULL; 7062306a36Sopenharmony_ci queue->tx_next = NULL; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void md_cd_queue_struct_init(struct cldma_queue *queue, struct cldma_ctrl *md_ctrl, 7462306a36Sopenharmony_ci enum mtk_txrx tx_rx, unsigned int index) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci md_cd_queue_struct_reset(queue, md_ctrl, tx_rx, index); 7762306a36Sopenharmony_ci init_waitqueue_head(&queue->req_wq); 7862306a36Sopenharmony_ci spin_lock_init(&queue->ring_lock); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic void t7xx_cldma_gpd_set_data_ptr(struct cldma_gpd *gpd, dma_addr_t data_ptr) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci gpd->data_buff_bd_ptr_h = cpu_to_le32(upper_32_bits(data_ptr)); 8462306a36Sopenharmony_ci gpd->data_buff_bd_ptr_l = cpu_to_le32(lower_32_bits(data_ptr)); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void t7xx_cldma_gpd_set_next_ptr(struct cldma_gpd *gpd, dma_addr_t next_ptr) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci gpd->next_gpd_ptr_h = cpu_to_le32(upper_32_bits(next_ptr)); 9062306a36Sopenharmony_ci gpd->next_gpd_ptr_l = cpu_to_le32(lower_32_bits(next_ptr)); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int t7xx_cldma_alloc_and_map_skb(struct cldma_ctrl *md_ctrl, struct cldma_request *req, 9462306a36Sopenharmony_ci size_t size, gfp_t gfp_mask) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci req->skb = __dev_alloc_skb(size, gfp_mask); 9762306a36Sopenharmony_ci if (!req->skb) 9862306a36Sopenharmony_ci return -ENOMEM; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci req->mapped_buff = dma_map_single(md_ctrl->dev, req->skb->data, size, DMA_FROM_DEVICE); 10162306a36Sopenharmony_ci if (dma_mapping_error(md_ctrl->dev, req->mapped_buff)) { 10262306a36Sopenharmony_ci dev_kfree_skb_any(req->skb); 10362306a36Sopenharmony_ci req->skb = NULL; 10462306a36Sopenharmony_ci req->mapped_buff = 0; 10562306a36Sopenharmony_ci dev_err(md_ctrl->dev, "DMA mapping failed\n"); 10662306a36Sopenharmony_ci return -ENOMEM; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int t7xx_cldma_gpd_rx_from_q(struct cldma_queue *queue, int budget, bool *over_budget) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = queue->md_ctrl; 11562306a36Sopenharmony_ci unsigned int hwo_polling_count = 0; 11662306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info; 11762306a36Sopenharmony_ci bool rx_not_done = true; 11862306a36Sopenharmony_ci unsigned long flags; 11962306a36Sopenharmony_ci int count = 0; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci hw_info = &md_ctrl->hw_info; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci do { 12462306a36Sopenharmony_ci struct cldma_request *req; 12562306a36Sopenharmony_ci struct cldma_gpd *gpd; 12662306a36Sopenharmony_ci struct sk_buff *skb; 12762306a36Sopenharmony_ci int ret; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci req = queue->tr_done; 13062306a36Sopenharmony_ci if (!req) 13162306a36Sopenharmony_ci return -ENODATA; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci gpd = req->gpd; 13462306a36Sopenharmony_ci if ((gpd->flags & GPD_FLAGS_HWO) || !req->skb) { 13562306a36Sopenharmony_ci dma_addr_t gpd_addr; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (!pci_device_is_present(to_pci_dev(md_ctrl->dev))) { 13862306a36Sopenharmony_ci dev_err(md_ctrl->dev, "PCIe Link disconnected\n"); 13962306a36Sopenharmony_ci return -ENODEV; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci gpd_addr = ioread64(hw_info->ap_pdn_base + REG_CLDMA_DL_CURRENT_ADDRL_0 + 14362306a36Sopenharmony_ci queue->index * sizeof(u64)); 14462306a36Sopenharmony_ci if (req->gpd_addr == gpd_addr || hwo_polling_count++ >= 100) 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci udelay(1); 14862306a36Sopenharmony_ci continue; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci hwo_polling_count = 0; 15262306a36Sopenharmony_ci skb = req->skb; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (req->mapped_buff) { 15562306a36Sopenharmony_ci dma_unmap_single(md_ctrl->dev, req->mapped_buff, 15662306a36Sopenharmony_ci queue->tr_ring->pkt_size, DMA_FROM_DEVICE); 15762306a36Sopenharmony_ci req->mapped_buff = 0; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci skb->len = 0; 16162306a36Sopenharmony_ci skb_reset_tail_pointer(skb); 16262306a36Sopenharmony_ci skb_put(skb, le16_to_cpu(gpd->data_buff_len)); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci ret = md_ctrl->recv_skb(queue, skb); 16562306a36Sopenharmony_ci /* Break processing, will try again later */ 16662306a36Sopenharmony_ci if (ret < 0) 16762306a36Sopenharmony_ci return ret; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci req->skb = NULL; 17062306a36Sopenharmony_ci t7xx_cldma_gpd_set_data_ptr(gpd, 0); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci spin_lock_irqsave(&queue->ring_lock, flags); 17362306a36Sopenharmony_ci queue->tr_done = list_next_entry_circular(req, &queue->tr_ring->gpd_ring, entry); 17462306a36Sopenharmony_ci spin_unlock_irqrestore(&queue->ring_lock, flags); 17562306a36Sopenharmony_ci req = queue->rx_refill; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci ret = t7xx_cldma_alloc_and_map_skb(md_ctrl, req, queue->tr_ring->pkt_size, GFP_KERNEL); 17862306a36Sopenharmony_ci if (ret) 17962306a36Sopenharmony_ci return ret; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci gpd = req->gpd; 18262306a36Sopenharmony_ci t7xx_cldma_gpd_set_data_ptr(gpd, req->mapped_buff); 18362306a36Sopenharmony_ci gpd->data_buff_len = 0; 18462306a36Sopenharmony_ci gpd->flags = GPD_FLAGS_IOC | GPD_FLAGS_HWO; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci spin_lock_irqsave(&queue->ring_lock, flags); 18762306a36Sopenharmony_ci queue->rx_refill = list_next_entry_circular(req, &queue->tr_ring->gpd_ring, entry); 18862306a36Sopenharmony_ci spin_unlock_irqrestore(&queue->ring_lock, flags); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci rx_not_done = ++count < budget || !need_resched(); 19162306a36Sopenharmony_ci } while (rx_not_done); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci *over_budget = true; 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int t7xx_cldma_gpd_rx_collect(struct cldma_queue *queue, int budget) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = queue->md_ctrl; 20062306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info; 20162306a36Sopenharmony_ci unsigned int pending_rx_int; 20262306a36Sopenharmony_ci bool over_budget = false; 20362306a36Sopenharmony_ci unsigned long flags; 20462306a36Sopenharmony_ci int ret; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci hw_info = &md_ctrl->hw_info; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci do { 20962306a36Sopenharmony_ci ret = t7xx_cldma_gpd_rx_from_q(queue, budget, &over_budget); 21062306a36Sopenharmony_ci if (ret == -ENODATA) 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci else if (ret) 21362306a36Sopenharmony_ci return ret; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci pending_rx_int = 0; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 21862306a36Sopenharmony_ci if (md_ctrl->rxq_active & BIT(queue->index)) { 21962306a36Sopenharmony_ci if (!t7xx_cldma_hw_queue_status(hw_info, queue->index, MTK_RX)) 22062306a36Sopenharmony_ci t7xx_cldma_hw_resume_queue(hw_info, queue->index, MTK_RX); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci pending_rx_int = t7xx_cldma_hw_int_status(hw_info, BIT(queue->index), 22362306a36Sopenharmony_ci MTK_RX); 22462306a36Sopenharmony_ci if (pending_rx_int) { 22562306a36Sopenharmony_ci t7xx_cldma_hw_rx_done(hw_info, pending_rx_int); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (over_budget) { 22862306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 22962306a36Sopenharmony_ci return -EAGAIN; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 23462306a36Sopenharmony_ci } while (pending_rx_int); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic void t7xx_cldma_rx_done(struct work_struct *work) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct cldma_queue *queue = container_of(work, struct cldma_queue, cldma_work); 24262306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = queue->md_ctrl; 24362306a36Sopenharmony_ci int value; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci value = t7xx_cldma_gpd_rx_collect(queue, queue->budget); 24662306a36Sopenharmony_ci if (value && md_ctrl->rxq_active & BIT(queue->index)) { 24762306a36Sopenharmony_ci queue_work(queue->worker, &queue->cldma_work); 24862306a36Sopenharmony_ci return; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci t7xx_cldma_clear_ip_busy(&md_ctrl->hw_info); 25262306a36Sopenharmony_ci t7xx_cldma_hw_irq_en_txrx(&md_ctrl->hw_info, queue->index, MTK_RX); 25362306a36Sopenharmony_ci t7xx_cldma_hw_irq_en_eq(&md_ctrl->hw_info, queue->index, MTK_RX); 25462306a36Sopenharmony_ci pm_runtime_mark_last_busy(md_ctrl->dev); 25562306a36Sopenharmony_ci pm_runtime_put_autosuspend(md_ctrl->dev); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int t7xx_cldma_gpd_tx_collect(struct cldma_queue *queue) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = queue->md_ctrl; 26162306a36Sopenharmony_ci unsigned int dma_len, count = 0; 26262306a36Sopenharmony_ci struct cldma_request *req; 26362306a36Sopenharmony_ci struct cldma_gpd *gpd; 26462306a36Sopenharmony_ci unsigned long flags; 26562306a36Sopenharmony_ci dma_addr_t dma_free; 26662306a36Sopenharmony_ci struct sk_buff *skb; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci while (!kthread_should_stop()) { 26962306a36Sopenharmony_ci spin_lock_irqsave(&queue->ring_lock, flags); 27062306a36Sopenharmony_ci req = queue->tr_done; 27162306a36Sopenharmony_ci if (!req) { 27262306a36Sopenharmony_ci spin_unlock_irqrestore(&queue->ring_lock, flags); 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci gpd = req->gpd; 27662306a36Sopenharmony_ci if ((gpd->flags & GPD_FLAGS_HWO) || !req->skb) { 27762306a36Sopenharmony_ci spin_unlock_irqrestore(&queue->ring_lock, flags); 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci queue->budget++; 28162306a36Sopenharmony_ci dma_free = req->mapped_buff; 28262306a36Sopenharmony_ci dma_len = le16_to_cpu(gpd->data_buff_len); 28362306a36Sopenharmony_ci skb = req->skb; 28462306a36Sopenharmony_ci req->skb = NULL; 28562306a36Sopenharmony_ci queue->tr_done = list_next_entry_circular(req, &queue->tr_ring->gpd_ring, entry); 28662306a36Sopenharmony_ci spin_unlock_irqrestore(&queue->ring_lock, flags); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci count++; 28962306a36Sopenharmony_ci dma_unmap_single(md_ctrl->dev, dma_free, dma_len, DMA_TO_DEVICE); 29062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (count) 29462306a36Sopenharmony_ci wake_up_nr(&queue->req_wq, count); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return count; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void t7xx_cldma_txq_empty_hndl(struct cldma_queue *queue) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = queue->md_ctrl; 30262306a36Sopenharmony_ci struct cldma_request *req; 30362306a36Sopenharmony_ci dma_addr_t ul_curr_addr; 30462306a36Sopenharmony_ci unsigned long flags; 30562306a36Sopenharmony_ci bool pending_gpd; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (!(md_ctrl->txq_active & BIT(queue->index))) 30862306a36Sopenharmony_ci return; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci spin_lock_irqsave(&queue->ring_lock, flags); 31162306a36Sopenharmony_ci req = list_prev_entry_circular(queue->tx_next, &queue->tr_ring->gpd_ring, entry); 31262306a36Sopenharmony_ci spin_unlock_irqrestore(&queue->ring_lock, flags); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci pending_gpd = (req->gpd->flags & GPD_FLAGS_HWO) && req->skb; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 31762306a36Sopenharmony_ci if (pending_gpd) { 31862306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Check current processing TGPD, 64-bit address is in a table by Q index */ 32162306a36Sopenharmony_ci ul_curr_addr = ioread64(hw_info->ap_pdn_base + REG_CLDMA_UL_CURRENT_ADDRL_0 + 32262306a36Sopenharmony_ci queue->index * sizeof(u64)); 32362306a36Sopenharmony_ci if (req->gpd_addr != ul_curr_addr) { 32462306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 32562306a36Sopenharmony_ci dev_err(md_ctrl->dev, "CLDMA%d queue %d is not empty\n", 32662306a36Sopenharmony_ci md_ctrl->hif_id, queue->index); 32762306a36Sopenharmony_ci return; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci t7xx_cldma_hw_resume_queue(hw_info, queue->index, MTK_TX); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void t7xx_cldma_tx_done(struct work_struct *work) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct cldma_queue *queue = container_of(work, struct cldma_queue, cldma_work); 33862306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = queue->md_ctrl; 33962306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info; 34062306a36Sopenharmony_ci unsigned int l2_tx_int; 34162306a36Sopenharmony_ci unsigned long flags; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci hw_info = &md_ctrl->hw_info; 34462306a36Sopenharmony_ci t7xx_cldma_gpd_tx_collect(queue); 34562306a36Sopenharmony_ci l2_tx_int = t7xx_cldma_hw_int_status(hw_info, BIT(queue->index) | EQ_STA_BIT(queue->index), 34662306a36Sopenharmony_ci MTK_TX); 34762306a36Sopenharmony_ci if (l2_tx_int & EQ_STA_BIT(queue->index)) { 34862306a36Sopenharmony_ci t7xx_cldma_hw_tx_done(hw_info, EQ_STA_BIT(queue->index)); 34962306a36Sopenharmony_ci t7xx_cldma_txq_empty_hndl(queue); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (l2_tx_int & BIT(queue->index)) { 35362306a36Sopenharmony_ci t7xx_cldma_hw_tx_done(hw_info, BIT(queue->index)); 35462306a36Sopenharmony_ci queue_work(queue->worker, &queue->cldma_work); 35562306a36Sopenharmony_ci return; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 35962306a36Sopenharmony_ci if (md_ctrl->txq_active & BIT(queue->index)) { 36062306a36Sopenharmony_ci t7xx_cldma_clear_ip_busy(hw_info); 36162306a36Sopenharmony_ci t7xx_cldma_hw_irq_en_eq(hw_info, queue->index, MTK_TX); 36262306a36Sopenharmony_ci t7xx_cldma_hw_irq_en_txrx(hw_info, queue->index, MTK_TX); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci pm_runtime_mark_last_busy(md_ctrl->dev); 36762306a36Sopenharmony_ci pm_runtime_put_autosuspend(md_ctrl->dev); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic void t7xx_cldma_ring_free(struct cldma_ctrl *md_ctrl, 37162306a36Sopenharmony_ci struct cldma_ring *ring, enum dma_data_direction tx_rx) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct cldma_request *req_cur, *req_next; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci list_for_each_entry_safe(req_cur, req_next, &ring->gpd_ring, entry) { 37662306a36Sopenharmony_ci if (req_cur->mapped_buff && req_cur->skb) { 37762306a36Sopenharmony_ci dma_unmap_single(md_ctrl->dev, req_cur->mapped_buff, 37862306a36Sopenharmony_ci ring->pkt_size, tx_rx); 37962306a36Sopenharmony_ci req_cur->mapped_buff = 0; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci dev_kfree_skb_any(req_cur->skb); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (req_cur->gpd) 38562306a36Sopenharmony_ci dma_pool_free(md_ctrl->gpd_dmapool, req_cur->gpd, req_cur->gpd_addr); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci list_del(&req_cur->entry); 38862306a36Sopenharmony_ci kfree(req_cur); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic struct cldma_request *t7xx_alloc_rx_request(struct cldma_ctrl *md_ctrl, size_t pkt_size) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct cldma_request *req; 39562306a36Sopenharmony_ci int val; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci req = kzalloc(sizeof(*req), GFP_KERNEL); 39862306a36Sopenharmony_ci if (!req) 39962306a36Sopenharmony_ci return NULL; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci req->gpd = dma_pool_zalloc(md_ctrl->gpd_dmapool, GFP_KERNEL, &req->gpd_addr); 40262306a36Sopenharmony_ci if (!req->gpd) 40362306a36Sopenharmony_ci goto err_free_req; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci val = t7xx_cldma_alloc_and_map_skb(md_ctrl, req, pkt_size, GFP_KERNEL); 40662306a36Sopenharmony_ci if (val) 40762306a36Sopenharmony_ci goto err_free_pool; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci return req; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cierr_free_pool: 41262306a36Sopenharmony_ci dma_pool_free(md_ctrl->gpd_dmapool, req->gpd, req->gpd_addr); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cierr_free_req: 41562306a36Sopenharmony_ci kfree(req); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return NULL; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int t7xx_cldma_rx_ring_init(struct cldma_ctrl *md_ctrl, struct cldma_ring *ring) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct cldma_request *req; 42362306a36Sopenharmony_ci struct cldma_gpd *gpd; 42462306a36Sopenharmony_ci int i; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci INIT_LIST_HEAD(&ring->gpd_ring); 42762306a36Sopenharmony_ci ring->length = MAX_RX_BUDGET; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci for (i = 0; i < ring->length; i++) { 43062306a36Sopenharmony_ci req = t7xx_alloc_rx_request(md_ctrl, ring->pkt_size); 43162306a36Sopenharmony_ci if (!req) { 43262306a36Sopenharmony_ci t7xx_cldma_ring_free(md_ctrl, ring, DMA_FROM_DEVICE); 43362306a36Sopenharmony_ci return -ENOMEM; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci gpd = req->gpd; 43762306a36Sopenharmony_ci t7xx_cldma_gpd_set_data_ptr(gpd, req->mapped_buff); 43862306a36Sopenharmony_ci gpd->rx_data_allow_len = cpu_to_le16(ring->pkt_size); 43962306a36Sopenharmony_ci gpd->flags = GPD_FLAGS_IOC | GPD_FLAGS_HWO; 44062306a36Sopenharmony_ci INIT_LIST_HEAD(&req->entry); 44162306a36Sopenharmony_ci list_add_tail(&req->entry, &ring->gpd_ring); 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Link previous GPD to next GPD, circular */ 44562306a36Sopenharmony_ci list_for_each_entry(req, &ring->gpd_ring, entry) { 44662306a36Sopenharmony_ci t7xx_cldma_gpd_set_next_ptr(gpd, req->gpd_addr); 44762306a36Sopenharmony_ci gpd = req->gpd; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return 0; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic struct cldma_request *t7xx_alloc_tx_request(struct cldma_ctrl *md_ctrl) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct cldma_request *req; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci req = kzalloc(sizeof(*req), GFP_KERNEL); 45862306a36Sopenharmony_ci if (!req) 45962306a36Sopenharmony_ci return NULL; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci req->gpd = dma_pool_zalloc(md_ctrl->gpd_dmapool, GFP_KERNEL, &req->gpd_addr); 46262306a36Sopenharmony_ci if (!req->gpd) { 46362306a36Sopenharmony_ci kfree(req); 46462306a36Sopenharmony_ci return NULL; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return req; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int t7xx_cldma_tx_ring_init(struct cldma_ctrl *md_ctrl, struct cldma_ring *ring) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct cldma_request *req; 47362306a36Sopenharmony_ci struct cldma_gpd *gpd; 47462306a36Sopenharmony_ci int i; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci INIT_LIST_HEAD(&ring->gpd_ring); 47762306a36Sopenharmony_ci ring->length = MAX_TX_BUDGET; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci for (i = 0; i < ring->length; i++) { 48062306a36Sopenharmony_ci req = t7xx_alloc_tx_request(md_ctrl); 48162306a36Sopenharmony_ci if (!req) { 48262306a36Sopenharmony_ci t7xx_cldma_ring_free(md_ctrl, ring, DMA_TO_DEVICE); 48362306a36Sopenharmony_ci return -ENOMEM; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci gpd = req->gpd; 48762306a36Sopenharmony_ci gpd->flags = GPD_FLAGS_IOC; 48862306a36Sopenharmony_ci INIT_LIST_HEAD(&req->entry); 48962306a36Sopenharmony_ci list_add_tail(&req->entry, &ring->gpd_ring); 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Link previous GPD to next GPD, circular */ 49362306a36Sopenharmony_ci list_for_each_entry(req, &ring->gpd_ring, entry) { 49462306a36Sopenharmony_ci t7xx_cldma_gpd_set_next_ptr(gpd, req->gpd_addr); 49562306a36Sopenharmony_ci gpd = req->gpd; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return 0; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/** 50262306a36Sopenharmony_ci * t7xx_cldma_q_reset() - Reset CLDMA request pointers to their initial values. 50362306a36Sopenharmony_ci * @queue: Pointer to the queue structure. 50462306a36Sopenharmony_ci * 50562306a36Sopenharmony_ci * Called with ring_lock (unless called during initialization phase) 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_cistatic void t7xx_cldma_q_reset(struct cldma_queue *queue) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct cldma_request *req; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci req = list_first_entry(&queue->tr_ring->gpd_ring, struct cldma_request, entry); 51262306a36Sopenharmony_ci queue->tr_done = req; 51362306a36Sopenharmony_ci queue->budget = queue->tr_ring->length; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (queue->dir == MTK_TX) 51662306a36Sopenharmony_ci queue->tx_next = req; 51762306a36Sopenharmony_ci else 51862306a36Sopenharmony_ci queue->rx_refill = req; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic void t7xx_cldma_rxq_init(struct cldma_queue *queue) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = queue->md_ctrl; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci queue->dir = MTK_RX; 52662306a36Sopenharmony_ci queue->tr_ring = &md_ctrl->rx_ring[queue->index]; 52762306a36Sopenharmony_ci t7xx_cldma_q_reset(queue); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic void t7xx_cldma_txq_init(struct cldma_queue *queue) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = queue->md_ctrl; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci queue->dir = MTK_TX; 53562306a36Sopenharmony_ci queue->tr_ring = &md_ctrl->tx_ring[queue->index]; 53662306a36Sopenharmony_ci t7xx_cldma_q_reset(queue); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic void t7xx_cldma_enable_irq(struct cldma_ctrl *md_ctrl) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci t7xx_pcie_mac_set_int(md_ctrl->t7xx_dev, md_ctrl->hw_info.phy_interrupt_id); 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic void t7xx_cldma_disable_irq(struct cldma_ctrl *md_ctrl) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci t7xx_pcie_mac_clear_int(md_ctrl->t7xx_dev, md_ctrl->hw_info.phy_interrupt_id); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic void t7xx_cldma_irq_work_cb(struct cldma_ctrl *md_ctrl) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci unsigned long l2_tx_int_msk, l2_rx_int_msk, l2_tx_int, l2_rx_int, val; 55262306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 55362306a36Sopenharmony_ci int i; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* L2 raw interrupt status */ 55662306a36Sopenharmony_ci l2_tx_int = ioread32(hw_info->ap_pdn_base + REG_CLDMA_L2TISAR0); 55762306a36Sopenharmony_ci l2_rx_int = ioread32(hw_info->ap_pdn_base + REG_CLDMA_L2RISAR0); 55862306a36Sopenharmony_ci l2_tx_int_msk = ioread32(hw_info->ap_pdn_base + REG_CLDMA_L2TIMR0); 55962306a36Sopenharmony_ci l2_rx_int_msk = ioread32(hw_info->ap_ao_base + REG_CLDMA_L2RIMR0); 56062306a36Sopenharmony_ci l2_tx_int &= ~l2_tx_int_msk; 56162306a36Sopenharmony_ci l2_rx_int &= ~l2_rx_int_msk; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (l2_tx_int) { 56462306a36Sopenharmony_ci if (l2_tx_int & (TQ_ERR_INT_BITMASK | TQ_ACTIVE_START_ERR_INT_BITMASK)) { 56562306a36Sopenharmony_ci /* Read and clear L3 TX interrupt status */ 56662306a36Sopenharmony_ci val = ioread32(hw_info->ap_pdn_base + REG_CLDMA_L3TISAR0); 56762306a36Sopenharmony_ci iowrite32(val, hw_info->ap_pdn_base + REG_CLDMA_L3TISAR0); 56862306a36Sopenharmony_ci val = ioread32(hw_info->ap_pdn_base + REG_CLDMA_L3TISAR1); 56962306a36Sopenharmony_ci iowrite32(val, hw_info->ap_pdn_base + REG_CLDMA_L3TISAR1); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci t7xx_cldma_hw_tx_done(hw_info, l2_tx_int); 57362306a36Sopenharmony_ci if (l2_tx_int & (TXRX_STATUS_BITMASK | EMPTY_STATUS_BITMASK)) { 57462306a36Sopenharmony_ci for_each_set_bit(i, &l2_tx_int, L2_INT_BIT_COUNT) { 57562306a36Sopenharmony_ci if (i < CLDMA_TXQ_NUM) { 57662306a36Sopenharmony_ci pm_runtime_get(md_ctrl->dev); 57762306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_eq(hw_info, i, MTK_TX); 57862306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_txrx(hw_info, i, MTK_TX); 57962306a36Sopenharmony_ci queue_work(md_ctrl->txq[i].worker, 58062306a36Sopenharmony_ci &md_ctrl->txq[i].cldma_work); 58162306a36Sopenharmony_ci } else { 58262306a36Sopenharmony_ci t7xx_cldma_txq_empty_hndl(&md_ctrl->txq[i - CLDMA_TXQ_NUM]); 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (l2_rx_int) { 58962306a36Sopenharmony_ci if (l2_rx_int & (RQ_ERR_INT_BITMASK | RQ_ACTIVE_START_ERR_INT_BITMASK)) { 59062306a36Sopenharmony_ci /* Read and clear L3 RX interrupt status */ 59162306a36Sopenharmony_ci val = ioread32(hw_info->ap_pdn_base + REG_CLDMA_L3RISAR0); 59262306a36Sopenharmony_ci iowrite32(val, hw_info->ap_pdn_base + REG_CLDMA_L3RISAR0); 59362306a36Sopenharmony_ci val = ioread32(hw_info->ap_pdn_base + REG_CLDMA_L3RISAR1); 59462306a36Sopenharmony_ci iowrite32(val, hw_info->ap_pdn_base + REG_CLDMA_L3RISAR1); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci t7xx_cldma_hw_rx_done(hw_info, l2_rx_int); 59862306a36Sopenharmony_ci if (l2_rx_int & (TXRX_STATUS_BITMASK | EMPTY_STATUS_BITMASK)) { 59962306a36Sopenharmony_ci l2_rx_int |= l2_rx_int >> CLDMA_RXQ_NUM; 60062306a36Sopenharmony_ci for_each_set_bit(i, &l2_rx_int, CLDMA_RXQ_NUM) { 60162306a36Sopenharmony_ci pm_runtime_get(md_ctrl->dev); 60262306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_eq(hw_info, i, MTK_RX); 60362306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_txrx(hw_info, i, MTK_RX); 60462306a36Sopenharmony_ci queue_work(md_ctrl->rxq[i].worker, &md_ctrl->rxq[i].cldma_work); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic bool t7xx_cldma_qs_are_active(struct cldma_ctrl *md_ctrl) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 61362306a36Sopenharmony_ci unsigned int tx_active; 61462306a36Sopenharmony_ci unsigned int rx_active; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (!pci_device_is_present(to_pci_dev(md_ctrl->dev))) 61762306a36Sopenharmony_ci return false; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci tx_active = t7xx_cldma_hw_queue_status(hw_info, CLDMA_ALL_Q, MTK_TX); 62062306a36Sopenharmony_ci rx_active = t7xx_cldma_hw_queue_status(hw_info, CLDMA_ALL_Q, MTK_RX); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return tx_active || rx_active; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci/** 62662306a36Sopenharmony_ci * t7xx_cldma_stop() - Stop CLDMA. 62762306a36Sopenharmony_ci * @md_ctrl: CLDMA context structure. 62862306a36Sopenharmony_ci * 62962306a36Sopenharmony_ci * Stop TX and RX queues. Disable L1 and L2 interrupts. 63062306a36Sopenharmony_ci * Clear status registers. 63162306a36Sopenharmony_ci * 63262306a36Sopenharmony_ci * Return: 63362306a36Sopenharmony_ci * * 0 - Success. 63462306a36Sopenharmony_ci * * -ERROR - Error code from polling cldma_queues_active. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ciint t7xx_cldma_stop(struct cldma_ctrl *md_ctrl) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 63962306a36Sopenharmony_ci bool active; 64062306a36Sopenharmony_ci int i, ret; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci md_ctrl->rxq_active = 0; 64362306a36Sopenharmony_ci t7xx_cldma_hw_stop_all_qs(hw_info, MTK_RX); 64462306a36Sopenharmony_ci md_ctrl->txq_active = 0; 64562306a36Sopenharmony_ci t7xx_cldma_hw_stop_all_qs(hw_info, MTK_TX); 64662306a36Sopenharmony_ci md_ctrl->txq_started = 0; 64762306a36Sopenharmony_ci t7xx_cldma_disable_irq(md_ctrl); 64862306a36Sopenharmony_ci t7xx_cldma_hw_stop(hw_info, MTK_RX); 64962306a36Sopenharmony_ci t7xx_cldma_hw_stop(hw_info, MTK_TX); 65062306a36Sopenharmony_ci t7xx_cldma_hw_tx_done(hw_info, CLDMA_L2TISAR0_ALL_INT_MASK); 65162306a36Sopenharmony_ci t7xx_cldma_hw_rx_done(hw_info, CLDMA_L2RISAR0_ALL_INT_MASK); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (md_ctrl->is_late_init) { 65462306a36Sopenharmony_ci for (i = 0; i < CLDMA_TXQ_NUM; i++) 65562306a36Sopenharmony_ci flush_work(&md_ctrl->txq[i].cldma_work); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci for (i = 0; i < CLDMA_RXQ_NUM; i++) 65862306a36Sopenharmony_ci flush_work(&md_ctrl->rxq[i].cldma_work); 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci ret = read_poll_timeout(t7xx_cldma_qs_are_active, active, !active, CHECK_Q_STOP_STEP_US, 66262306a36Sopenharmony_ci CHECK_Q_STOP_TIMEOUT_US, true, md_ctrl); 66362306a36Sopenharmony_ci if (ret) 66462306a36Sopenharmony_ci dev_err(md_ctrl->dev, "Could not stop CLDMA%d queues", md_ctrl->hif_id); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci return ret; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic void t7xx_cldma_late_release(struct cldma_ctrl *md_ctrl) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci int i; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (!md_ctrl->is_late_init) 67462306a36Sopenharmony_ci return; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci for (i = 0; i < CLDMA_TXQ_NUM; i++) 67762306a36Sopenharmony_ci t7xx_cldma_ring_free(md_ctrl, &md_ctrl->tx_ring[i], DMA_TO_DEVICE); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci for (i = 0; i < CLDMA_RXQ_NUM; i++) 68062306a36Sopenharmony_ci t7xx_cldma_ring_free(md_ctrl, &md_ctrl->rx_ring[i], DMA_FROM_DEVICE); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci dma_pool_destroy(md_ctrl->gpd_dmapool); 68362306a36Sopenharmony_ci md_ctrl->gpd_dmapool = NULL; 68462306a36Sopenharmony_ci md_ctrl->is_late_init = false; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_civoid t7xx_cldma_reset(struct cldma_ctrl *md_ctrl) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci unsigned long flags; 69062306a36Sopenharmony_ci int i; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 69362306a36Sopenharmony_ci md_ctrl->txq_active = 0; 69462306a36Sopenharmony_ci md_ctrl->rxq_active = 0; 69562306a36Sopenharmony_ci t7xx_cldma_disable_irq(md_ctrl); 69662306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci for (i = 0; i < CLDMA_TXQ_NUM; i++) { 69962306a36Sopenharmony_ci cancel_work_sync(&md_ctrl->txq[i].cldma_work); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 70262306a36Sopenharmony_ci md_cd_queue_struct_reset(&md_ctrl->txq[i], md_ctrl, MTK_TX, i); 70362306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci for (i = 0; i < CLDMA_RXQ_NUM; i++) { 70762306a36Sopenharmony_ci cancel_work_sync(&md_ctrl->rxq[i].cldma_work); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 71062306a36Sopenharmony_ci md_cd_queue_struct_reset(&md_ctrl->rxq[i], md_ctrl, MTK_RX, i); 71162306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci t7xx_cldma_late_release(md_ctrl); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/** 71862306a36Sopenharmony_ci * t7xx_cldma_start() - Start CLDMA. 71962306a36Sopenharmony_ci * @md_ctrl: CLDMA context structure. 72062306a36Sopenharmony_ci * 72162306a36Sopenharmony_ci * Set TX/RX start address. 72262306a36Sopenharmony_ci * Start all RX queues and enable L2 interrupt. 72362306a36Sopenharmony_ci */ 72462306a36Sopenharmony_civoid t7xx_cldma_start(struct cldma_ctrl *md_ctrl) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci unsigned long flags; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 72962306a36Sopenharmony_ci if (md_ctrl->is_late_init) { 73062306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 73162306a36Sopenharmony_ci int i; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci t7xx_cldma_enable_irq(md_ctrl); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci for (i = 0; i < CLDMA_TXQ_NUM; i++) { 73662306a36Sopenharmony_ci if (md_ctrl->txq[i].tr_done) 73762306a36Sopenharmony_ci t7xx_cldma_hw_set_start_addr(hw_info, i, 73862306a36Sopenharmony_ci md_ctrl->txq[i].tr_done->gpd_addr, 73962306a36Sopenharmony_ci MTK_TX); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci for (i = 0; i < CLDMA_RXQ_NUM; i++) { 74362306a36Sopenharmony_ci if (md_ctrl->rxq[i].tr_done) 74462306a36Sopenharmony_ci t7xx_cldma_hw_set_start_addr(hw_info, i, 74562306a36Sopenharmony_ci md_ctrl->rxq[i].tr_done->gpd_addr, 74662306a36Sopenharmony_ci MTK_RX); 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* Enable L2 interrupt */ 75062306a36Sopenharmony_ci t7xx_cldma_hw_start_queue(hw_info, CLDMA_ALL_Q, MTK_RX); 75162306a36Sopenharmony_ci t7xx_cldma_hw_start(hw_info); 75262306a36Sopenharmony_ci md_ctrl->txq_started = 0; 75362306a36Sopenharmony_ci md_ctrl->txq_active |= TXRX_STATUS_BITMASK; 75462306a36Sopenharmony_ci md_ctrl->rxq_active |= TXRX_STATUS_BITMASK; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic void t7xx_cldma_clear_txq(struct cldma_ctrl *md_ctrl, int qnum) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct cldma_queue *txq = &md_ctrl->txq[qnum]; 76262306a36Sopenharmony_ci struct cldma_request *req; 76362306a36Sopenharmony_ci struct cldma_gpd *gpd; 76462306a36Sopenharmony_ci unsigned long flags; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci spin_lock_irqsave(&txq->ring_lock, flags); 76762306a36Sopenharmony_ci t7xx_cldma_q_reset(txq); 76862306a36Sopenharmony_ci list_for_each_entry(req, &txq->tr_ring->gpd_ring, entry) { 76962306a36Sopenharmony_ci gpd = req->gpd; 77062306a36Sopenharmony_ci gpd->flags &= ~GPD_FLAGS_HWO; 77162306a36Sopenharmony_ci t7xx_cldma_gpd_set_data_ptr(gpd, 0); 77262306a36Sopenharmony_ci gpd->data_buff_len = 0; 77362306a36Sopenharmony_ci dev_kfree_skb_any(req->skb); 77462306a36Sopenharmony_ci req->skb = NULL; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci spin_unlock_irqrestore(&txq->ring_lock, flags); 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic int t7xx_cldma_clear_rxq(struct cldma_ctrl *md_ctrl, int qnum) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci struct cldma_queue *rxq = &md_ctrl->rxq[qnum]; 78262306a36Sopenharmony_ci struct cldma_request *req; 78362306a36Sopenharmony_ci struct cldma_gpd *gpd; 78462306a36Sopenharmony_ci unsigned long flags; 78562306a36Sopenharmony_ci int ret = 0; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci spin_lock_irqsave(&rxq->ring_lock, flags); 78862306a36Sopenharmony_ci t7xx_cldma_q_reset(rxq); 78962306a36Sopenharmony_ci list_for_each_entry(req, &rxq->tr_ring->gpd_ring, entry) { 79062306a36Sopenharmony_ci gpd = req->gpd; 79162306a36Sopenharmony_ci gpd->flags = GPD_FLAGS_IOC | GPD_FLAGS_HWO; 79262306a36Sopenharmony_ci gpd->data_buff_len = 0; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (req->skb) { 79562306a36Sopenharmony_ci req->skb->len = 0; 79662306a36Sopenharmony_ci skb_reset_tail_pointer(req->skb); 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci list_for_each_entry(req, &rxq->tr_ring->gpd_ring, entry) { 80162306a36Sopenharmony_ci if (req->skb) 80262306a36Sopenharmony_ci continue; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci ret = t7xx_cldma_alloc_and_map_skb(md_ctrl, req, rxq->tr_ring->pkt_size, GFP_ATOMIC); 80562306a36Sopenharmony_ci if (ret) 80662306a36Sopenharmony_ci break; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci t7xx_cldma_gpd_set_data_ptr(req->gpd, req->mapped_buff); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci spin_unlock_irqrestore(&rxq->ring_lock, flags); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return ret; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_civoid t7xx_cldma_clear_all_qs(struct cldma_ctrl *md_ctrl, enum mtk_txrx tx_rx) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci int i; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (tx_rx == MTK_TX) { 82062306a36Sopenharmony_ci for (i = 0; i < CLDMA_TXQ_NUM; i++) 82162306a36Sopenharmony_ci t7xx_cldma_clear_txq(md_ctrl, i); 82262306a36Sopenharmony_ci } else { 82362306a36Sopenharmony_ci for (i = 0; i < CLDMA_RXQ_NUM; i++) 82462306a36Sopenharmony_ci t7xx_cldma_clear_rxq(md_ctrl, i); 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_civoid t7xx_cldma_stop_all_qs(struct cldma_ctrl *md_ctrl, enum mtk_txrx tx_rx) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 83162306a36Sopenharmony_ci unsigned long flags; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 83462306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_eq(hw_info, CLDMA_ALL_Q, tx_rx); 83562306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_txrx(hw_info, CLDMA_ALL_Q, tx_rx); 83662306a36Sopenharmony_ci if (tx_rx == MTK_RX) 83762306a36Sopenharmony_ci md_ctrl->rxq_active &= ~TXRX_STATUS_BITMASK; 83862306a36Sopenharmony_ci else 83962306a36Sopenharmony_ci md_ctrl->txq_active &= ~TXRX_STATUS_BITMASK; 84062306a36Sopenharmony_ci t7xx_cldma_hw_stop_all_qs(hw_info, tx_rx); 84162306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic int t7xx_cldma_gpd_handle_tx_request(struct cldma_queue *queue, struct cldma_request *tx_req, 84562306a36Sopenharmony_ci struct sk_buff *skb) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = queue->md_ctrl; 84862306a36Sopenharmony_ci struct cldma_gpd *gpd = tx_req->gpd; 84962306a36Sopenharmony_ci unsigned long flags; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* Update GPD */ 85262306a36Sopenharmony_ci tx_req->mapped_buff = dma_map_single(md_ctrl->dev, skb->data, skb->len, DMA_TO_DEVICE); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (dma_mapping_error(md_ctrl->dev, tx_req->mapped_buff)) { 85562306a36Sopenharmony_ci dev_err(md_ctrl->dev, "DMA mapping failed\n"); 85662306a36Sopenharmony_ci return -ENOMEM; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci t7xx_cldma_gpd_set_data_ptr(gpd, tx_req->mapped_buff); 86062306a36Sopenharmony_ci gpd->data_buff_len = cpu_to_le16(skb->len); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* This lock must cover TGPD setting, as even without a resume operation, 86362306a36Sopenharmony_ci * CLDMA can send next HWO=1 if last TGPD just finished. 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 86662306a36Sopenharmony_ci if (md_ctrl->txq_active & BIT(queue->index)) 86762306a36Sopenharmony_ci gpd->flags |= GPD_FLAGS_HWO; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci tx_req->skb = skb; 87262306a36Sopenharmony_ci return 0; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci/* Called with cldma_lock */ 87662306a36Sopenharmony_cistatic void t7xx_cldma_hw_start_send(struct cldma_ctrl *md_ctrl, int qno, 87762306a36Sopenharmony_ci struct cldma_request *prev_req) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* Check whether the device was powered off (CLDMA start address is not set) */ 88262306a36Sopenharmony_ci if (!t7xx_cldma_tx_addr_is_set(hw_info, qno)) { 88362306a36Sopenharmony_ci t7xx_cldma_hw_init(hw_info); 88462306a36Sopenharmony_ci t7xx_cldma_hw_set_start_addr(hw_info, qno, prev_req->gpd_addr, MTK_TX); 88562306a36Sopenharmony_ci md_ctrl->txq_started &= ~BIT(qno); 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (!t7xx_cldma_hw_queue_status(hw_info, qno, MTK_TX)) { 88962306a36Sopenharmony_ci if (md_ctrl->txq_started & BIT(qno)) 89062306a36Sopenharmony_ci t7xx_cldma_hw_resume_queue(hw_info, qno, MTK_TX); 89162306a36Sopenharmony_ci else 89262306a36Sopenharmony_ci t7xx_cldma_hw_start_queue(hw_info, qno, MTK_TX); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci md_ctrl->txq_started |= BIT(qno); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci/** 89962306a36Sopenharmony_ci * t7xx_cldma_set_recv_skb() - Set the callback to handle RX packets. 90062306a36Sopenharmony_ci * @md_ctrl: CLDMA context structure. 90162306a36Sopenharmony_ci * @recv_skb: Receiving skb callback. 90262306a36Sopenharmony_ci */ 90362306a36Sopenharmony_civoid t7xx_cldma_set_recv_skb(struct cldma_ctrl *md_ctrl, 90462306a36Sopenharmony_ci int (*recv_skb)(struct cldma_queue *queue, struct sk_buff *skb)) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci md_ctrl->recv_skb = recv_skb; 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci/** 91062306a36Sopenharmony_ci * t7xx_cldma_send_skb() - Send control data to modem. 91162306a36Sopenharmony_ci * @md_ctrl: CLDMA context structure. 91262306a36Sopenharmony_ci * @qno: Queue number. 91362306a36Sopenharmony_ci * @skb: Socket buffer. 91462306a36Sopenharmony_ci * 91562306a36Sopenharmony_ci * Return: 91662306a36Sopenharmony_ci * * 0 - Success. 91762306a36Sopenharmony_ci * * -ENOMEM - Allocation failure. 91862306a36Sopenharmony_ci * * -EINVAL - Invalid queue request. 91962306a36Sopenharmony_ci * * -EIO - Queue is not active. 92062306a36Sopenharmony_ci * * -ETIMEDOUT - Timeout waiting for the device to wake up. 92162306a36Sopenharmony_ci */ 92262306a36Sopenharmony_ciint t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci struct cldma_request *tx_req; 92562306a36Sopenharmony_ci struct cldma_queue *queue; 92662306a36Sopenharmony_ci unsigned long flags; 92762306a36Sopenharmony_ci int ret; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (qno >= CLDMA_TXQ_NUM) 93062306a36Sopenharmony_ci return -EINVAL; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(md_ctrl->dev); 93362306a36Sopenharmony_ci if (ret < 0 && ret != -EACCES) 93462306a36Sopenharmony_ci return ret; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci t7xx_pci_disable_sleep(md_ctrl->t7xx_dev); 93762306a36Sopenharmony_ci queue = &md_ctrl->txq[qno]; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 94062306a36Sopenharmony_ci if (!(md_ctrl->txq_active & BIT(qno))) { 94162306a36Sopenharmony_ci ret = -EIO; 94262306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 94362306a36Sopenharmony_ci goto allow_sleep; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci do { 94862306a36Sopenharmony_ci spin_lock_irqsave(&queue->ring_lock, flags); 94962306a36Sopenharmony_ci tx_req = queue->tx_next; 95062306a36Sopenharmony_ci if (queue->budget > 0 && !tx_req->skb) { 95162306a36Sopenharmony_ci struct list_head *gpd_ring = &queue->tr_ring->gpd_ring; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci queue->budget--; 95462306a36Sopenharmony_ci t7xx_cldma_gpd_handle_tx_request(queue, tx_req, skb); 95562306a36Sopenharmony_ci queue->tx_next = list_next_entry_circular(tx_req, gpd_ring, entry); 95662306a36Sopenharmony_ci spin_unlock_irqrestore(&queue->ring_lock, flags); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (!t7xx_pci_sleep_disable_complete(md_ctrl->t7xx_dev)) { 95962306a36Sopenharmony_ci ret = -ETIMEDOUT; 96062306a36Sopenharmony_ci break; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* Protect the access to the modem for queues operations (resume/start) 96462306a36Sopenharmony_ci * which access shared locations by all the queues. 96562306a36Sopenharmony_ci * cldma_lock is independent of ring_lock which is per queue. 96662306a36Sopenharmony_ci */ 96762306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 96862306a36Sopenharmony_ci t7xx_cldma_hw_start_send(md_ctrl, qno, tx_req); 96962306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci break; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci spin_unlock_irqrestore(&queue->ring_lock, flags); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (!t7xx_pci_sleep_disable_complete(md_ctrl->t7xx_dev)) { 97662306a36Sopenharmony_ci ret = -ETIMEDOUT; 97762306a36Sopenharmony_ci break; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (!t7xx_cldma_hw_queue_status(&md_ctrl->hw_info, qno, MTK_TX)) { 98162306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 98262306a36Sopenharmony_ci t7xx_cldma_hw_resume_queue(&md_ctrl->hw_info, qno, MTK_TX); 98362306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci ret = wait_event_interruptible_exclusive(queue->req_wq, queue->budget > 0); 98762306a36Sopenharmony_ci } while (!ret); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ciallow_sleep: 99062306a36Sopenharmony_ci t7xx_pci_enable_sleep(md_ctrl->t7xx_dev); 99162306a36Sopenharmony_ci pm_runtime_mark_last_busy(md_ctrl->dev); 99262306a36Sopenharmony_ci pm_runtime_put_autosuspend(md_ctrl->dev); 99362306a36Sopenharmony_ci return ret; 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic int t7xx_cldma_late_init(struct cldma_ctrl *md_ctrl) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci char dma_pool_name[32]; 99962306a36Sopenharmony_ci int i, j, ret; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (md_ctrl->is_late_init) { 100262306a36Sopenharmony_ci dev_err(md_ctrl->dev, "CLDMA late init was already done\n"); 100362306a36Sopenharmony_ci return -EALREADY; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci snprintf(dma_pool_name, sizeof(dma_pool_name), "cldma_req_hif%d", md_ctrl->hif_id); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci md_ctrl->gpd_dmapool = dma_pool_create(dma_pool_name, md_ctrl->dev, 100962306a36Sopenharmony_ci sizeof(struct cldma_gpd), GPD_DMAPOOL_ALIGN, 0); 101062306a36Sopenharmony_ci if (!md_ctrl->gpd_dmapool) { 101162306a36Sopenharmony_ci dev_err(md_ctrl->dev, "DMA pool alloc fail\n"); 101262306a36Sopenharmony_ci return -ENOMEM; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci for (i = 0; i < CLDMA_TXQ_NUM; i++) { 101662306a36Sopenharmony_ci ret = t7xx_cldma_tx_ring_init(md_ctrl, &md_ctrl->tx_ring[i]); 101762306a36Sopenharmony_ci if (ret) { 101862306a36Sopenharmony_ci dev_err(md_ctrl->dev, "control TX ring init fail\n"); 101962306a36Sopenharmony_ci goto err_free_tx_ring; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci md_ctrl->tx_ring[i].pkt_size = CLDMA_MTU; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci for (j = 0; j < CLDMA_RXQ_NUM; j++) { 102662306a36Sopenharmony_ci md_ctrl->rx_ring[j].pkt_size = CLDMA_MTU; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (j == CLDMA_RXQ_NUM - 1) 102962306a36Sopenharmony_ci md_ctrl->rx_ring[j].pkt_size = CLDMA_JUMBO_BUFF_SZ; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci ret = t7xx_cldma_rx_ring_init(md_ctrl, &md_ctrl->rx_ring[j]); 103262306a36Sopenharmony_ci if (ret) { 103362306a36Sopenharmony_ci dev_err(md_ctrl->dev, "Control RX ring init fail\n"); 103462306a36Sopenharmony_ci goto err_free_rx_ring; 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci for (i = 0; i < CLDMA_TXQ_NUM; i++) 103962306a36Sopenharmony_ci t7xx_cldma_txq_init(&md_ctrl->txq[i]); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci for (j = 0; j < CLDMA_RXQ_NUM; j++) 104262306a36Sopenharmony_ci t7xx_cldma_rxq_init(&md_ctrl->rxq[j]); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci md_ctrl->is_late_init = true; 104562306a36Sopenharmony_ci return 0; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cierr_free_rx_ring: 104862306a36Sopenharmony_ci while (j--) 104962306a36Sopenharmony_ci t7xx_cldma_ring_free(md_ctrl, &md_ctrl->rx_ring[j], DMA_FROM_DEVICE); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_cierr_free_tx_ring: 105262306a36Sopenharmony_ci while (i--) 105362306a36Sopenharmony_ci t7xx_cldma_ring_free(md_ctrl, &md_ctrl->tx_ring[i], DMA_TO_DEVICE); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci return ret; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic void __iomem *t7xx_pcie_addr_transfer(void __iomem *addr, u32 addr_trs1, u32 phy_addr) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci return addr + phy_addr - addr_trs1; 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_cistatic void t7xx_hw_info_init(struct cldma_ctrl *md_ctrl) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci struct t7xx_addr_base *pbase = &md_ctrl->t7xx_dev->base_addr; 106662306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 106762306a36Sopenharmony_ci u32 phy_ao_base, phy_pd_base; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci hw_info->hw_mode = MODE_BIT_64; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (md_ctrl->hif_id == CLDMA_ID_MD) { 107262306a36Sopenharmony_ci phy_ao_base = CLDMA1_AO_BASE; 107362306a36Sopenharmony_ci phy_pd_base = CLDMA1_PD_BASE; 107462306a36Sopenharmony_ci hw_info->phy_interrupt_id = CLDMA1_INT; 107562306a36Sopenharmony_ci } else { 107662306a36Sopenharmony_ci phy_ao_base = CLDMA0_AO_BASE; 107762306a36Sopenharmony_ci phy_pd_base = CLDMA0_PD_BASE; 107862306a36Sopenharmony_ci hw_info->phy_interrupt_id = CLDMA0_INT; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci hw_info->ap_ao_base = t7xx_pcie_addr_transfer(pbase->pcie_ext_reg_base, 108262306a36Sopenharmony_ci pbase->pcie_dev_reg_trsl_addr, phy_ao_base); 108362306a36Sopenharmony_ci hw_info->ap_pdn_base = t7xx_pcie_addr_transfer(pbase->pcie_ext_reg_base, 108462306a36Sopenharmony_ci pbase->pcie_dev_reg_trsl_addr, phy_pd_base); 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic int t7xx_cldma_default_recv_skb(struct cldma_queue *queue, struct sk_buff *skb) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 109062306a36Sopenharmony_ci return 0; 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ciint t7xx_cldma_alloc(enum cldma_id hif_id, struct t7xx_pci_dev *t7xx_dev) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci struct device *dev = &t7xx_dev->pdev->dev; 109662306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci md_ctrl = devm_kzalloc(dev, sizeof(*md_ctrl), GFP_KERNEL); 109962306a36Sopenharmony_ci if (!md_ctrl) 110062306a36Sopenharmony_ci return -ENOMEM; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci md_ctrl->t7xx_dev = t7xx_dev; 110362306a36Sopenharmony_ci md_ctrl->dev = dev; 110462306a36Sopenharmony_ci md_ctrl->hif_id = hif_id; 110562306a36Sopenharmony_ci md_ctrl->recv_skb = t7xx_cldma_default_recv_skb; 110662306a36Sopenharmony_ci t7xx_hw_info_init(md_ctrl); 110762306a36Sopenharmony_ci t7xx_dev->md->md_ctrl[hif_id] = md_ctrl; 110862306a36Sopenharmony_ci return 0; 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_cistatic void t7xx_cldma_resume_early(struct t7xx_pci_dev *t7xx_dev, void *entity_param) 111262306a36Sopenharmony_ci{ 111362306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = entity_param; 111462306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info; 111562306a36Sopenharmony_ci unsigned long flags; 111662306a36Sopenharmony_ci int qno_t; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci hw_info = &md_ctrl->hw_info; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 112162306a36Sopenharmony_ci t7xx_cldma_hw_restore(hw_info); 112262306a36Sopenharmony_ci for (qno_t = 0; qno_t < CLDMA_TXQ_NUM; qno_t++) { 112362306a36Sopenharmony_ci t7xx_cldma_hw_set_start_addr(hw_info, qno_t, md_ctrl->txq[qno_t].tx_next->gpd_addr, 112462306a36Sopenharmony_ci MTK_TX); 112562306a36Sopenharmony_ci t7xx_cldma_hw_set_start_addr(hw_info, qno_t, md_ctrl->rxq[qno_t].tr_done->gpd_addr, 112662306a36Sopenharmony_ci MTK_RX); 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci t7xx_cldma_enable_irq(md_ctrl); 112962306a36Sopenharmony_ci t7xx_cldma_hw_start_queue(hw_info, CLDMA_ALL_Q, MTK_RX); 113062306a36Sopenharmony_ci md_ctrl->rxq_active |= TXRX_STATUS_BITMASK; 113162306a36Sopenharmony_ci t7xx_cldma_hw_irq_en_eq(hw_info, CLDMA_ALL_Q, MTK_RX); 113262306a36Sopenharmony_ci t7xx_cldma_hw_irq_en_txrx(hw_info, CLDMA_ALL_Q, MTK_RX); 113362306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_cistatic int t7xx_cldma_resume(struct t7xx_pci_dev *t7xx_dev, void *entity_param) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = entity_param; 113962306a36Sopenharmony_ci unsigned long flags; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 114262306a36Sopenharmony_ci md_ctrl->txq_active |= TXRX_STATUS_BITMASK; 114362306a36Sopenharmony_ci t7xx_cldma_hw_irq_en_txrx(&md_ctrl->hw_info, CLDMA_ALL_Q, MTK_TX); 114462306a36Sopenharmony_ci t7xx_cldma_hw_irq_en_eq(&md_ctrl->hw_info, CLDMA_ALL_Q, MTK_TX); 114562306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (md_ctrl->hif_id == CLDMA_ID_MD) 114862306a36Sopenharmony_ci t7xx_mhccif_mask_clr(t7xx_dev, D2H_SW_INT_MASK); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci return 0; 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cistatic void t7xx_cldma_suspend_late(struct t7xx_pci_dev *t7xx_dev, void *entity_param) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = entity_param; 115662306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info; 115762306a36Sopenharmony_ci unsigned long flags; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci hw_info = &md_ctrl->hw_info; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 116262306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_eq(hw_info, CLDMA_ALL_Q, MTK_RX); 116362306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_txrx(hw_info, CLDMA_ALL_Q, MTK_RX); 116462306a36Sopenharmony_ci md_ctrl->rxq_active &= ~TXRX_STATUS_BITMASK; 116562306a36Sopenharmony_ci t7xx_cldma_hw_stop_all_qs(hw_info, MTK_RX); 116662306a36Sopenharmony_ci t7xx_cldma_clear_ip_busy(hw_info); 116762306a36Sopenharmony_ci t7xx_cldma_disable_irq(md_ctrl); 116862306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic int t7xx_cldma_suspend(struct t7xx_pci_dev *t7xx_dev, void *entity_param) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = entity_param; 117462306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info; 117562306a36Sopenharmony_ci unsigned long flags; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (md_ctrl->hif_id == CLDMA_ID_MD) 117862306a36Sopenharmony_ci t7xx_mhccif_mask_set(t7xx_dev, D2H_SW_INT_MASK); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci hw_info = &md_ctrl->hw_info; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 118362306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_eq(hw_info, CLDMA_ALL_Q, MTK_TX); 118462306a36Sopenharmony_ci t7xx_cldma_hw_irq_dis_txrx(hw_info, CLDMA_ALL_Q, MTK_TX); 118562306a36Sopenharmony_ci md_ctrl->txq_active &= ~TXRX_STATUS_BITMASK; 118662306a36Sopenharmony_ci t7xx_cldma_hw_stop_all_qs(hw_info, MTK_TX); 118762306a36Sopenharmony_ci md_ctrl->txq_started = 0; 118862306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci return 0; 119162306a36Sopenharmony_ci} 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_cistatic int t7xx_cldma_pm_init(struct cldma_ctrl *md_ctrl) 119462306a36Sopenharmony_ci{ 119562306a36Sopenharmony_ci md_ctrl->pm_entity = kzalloc(sizeof(*md_ctrl->pm_entity), GFP_KERNEL); 119662306a36Sopenharmony_ci if (!md_ctrl->pm_entity) 119762306a36Sopenharmony_ci return -ENOMEM; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci md_ctrl->pm_entity->entity_param = md_ctrl; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (md_ctrl->hif_id == CLDMA_ID_MD) 120262306a36Sopenharmony_ci md_ctrl->pm_entity->id = PM_ENTITY_ID_CTRL1; 120362306a36Sopenharmony_ci else 120462306a36Sopenharmony_ci md_ctrl->pm_entity->id = PM_ENTITY_ID_CTRL2; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci md_ctrl->pm_entity->suspend = t7xx_cldma_suspend; 120762306a36Sopenharmony_ci md_ctrl->pm_entity->suspend_late = t7xx_cldma_suspend_late; 120862306a36Sopenharmony_ci md_ctrl->pm_entity->resume = t7xx_cldma_resume; 120962306a36Sopenharmony_ci md_ctrl->pm_entity->resume_early = t7xx_cldma_resume_early; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci return t7xx_pci_pm_entity_register(md_ctrl->t7xx_dev, md_ctrl->pm_entity); 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_cistatic int t7xx_cldma_pm_uninit(struct cldma_ctrl *md_ctrl) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci if (!md_ctrl->pm_entity) 121762306a36Sopenharmony_ci return -EINVAL; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci t7xx_pci_pm_entity_unregister(md_ctrl->t7xx_dev, md_ctrl->pm_entity); 122062306a36Sopenharmony_ci kfree(md_ctrl->pm_entity); 122162306a36Sopenharmony_ci md_ctrl->pm_entity = NULL; 122262306a36Sopenharmony_ci return 0; 122362306a36Sopenharmony_ci} 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_civoid t7xx_cldma_hif_hw_init(struct cldma_ctrl *md_ctrl) 122662306a36Sopenharmony_ci{ 122762306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 122862306a36Sopenharmony_ci unsigned long flags; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci spin_lock_irqsave(&md_ctrl->cldma_lock, flags); 123162306a36Sopenharmony_ci t7xx_cldma_hw_stop(hw_info, MTK_TX); 123262306a36Sopenharmony_ci t7xx_cldma_hw_stop(hw_info, MTK_RX); 123362306a36Sopenharmony_ci t7xx_cldma_hw_rx_done(hw_info, EMPTY_STATUS_BITMASK | TXRX_STATUS_BITMASK); 123462306a36Sopenharmony_ci t7xx_cldma_hw_tx_done(hw_info, EMPTY_STATUS_BITMASK | TXRX_STATUS_BITMASK); 123562306a36Sopenharmony_ci t7xx_cldma_hw_init(hw_info); 123662306a36Sopenharmony_ci spin_unlock_irqrestore(&md_ctrl->cldma_lock, flags); 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_cistatic irqreturn_t t7xx_cldma_isr_handler(int irq, void *data) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci struct cldma_ctrl *md_ctrl = data; 124262306a36Sopenharmony_ci u32 interrupt; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci interrupt = md_ctrl->hw_info.phy_interrupt_id; 124562306a36Sopenharmony_ci t7xx_pcie_mac_clear_int(md_ctrl->t7xx_dev, interrupt); 124662306a36Sopenharmony_ci t7xx_cldma_irq_work_cb(md_ctrl); 124762306a36Sopenharmony_ci t7xx_pcie_mac_clear_int_status(md_ctrl->t7xx_dev, interrupt); 124862306a36Sopenharmony_ci t7xx_pcie_mac_set_int(md_ctrl->t7xx_dev, interrupt); 124962306a36Sopenharmony_ci return IRQ_HANDLED; 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic void t7xx_cldma_destroy_wqs(struct cldma_ctrl *md_ctrl) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci int i; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci for (i = 0; i < CLDMA_TXQ_NUM; i++) { 125762306a36Sopenharmony_ci if (md_ctrl->txq[i].worker) { 125862306a36Sopenharmony_ci destroy_workqueue(md_ctrl->txq[i].worker); 125962306a36Sopenharmony_ci md_ctrl->txq[i].worker = NULL; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci for (i = 0; i < CLDMA_RXQ_NUM; i++) { 126462306a36Sopenharmony_ci if (md_ctrl->rxq[i].worker) { 126562306a36Sopenharmony_ci destroy_workqueue(md_ctrl->rxq[i].worker); 126662306a36Sopenharmony_ci md_ctrl->rxq[i].worker = NULL; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci/** 127262306a36Sopenharmony_ci * t7xx_cldma_init() - Initialize CLDMA. 127362306a36Sopenharmony_ci * @md_ctrl: CLDMA context structure. 127462306a36Sopenharmony_ci * 127562306a36Sopenharmony_ci * Allocate and initialize device power management entity. 127662306a36Sopenharmony_ci * Initialize HIF TX/RX queue structure. 127762306a36Sopenharmony_ci * Register CLDMA callback ISR with PCIe driver. 127862306a36Sopenharmony_ci * 127962306a36Sopenharmony_ci * Return: 128062306a36Sopenharmony_ci * * 0 - Success. 128162306a36Sopenharmony_ci * * -ERROR - Error code from failure sub-initializations. 128262306a36Sopenharmony_ci */ 128362306a36Sopenharmony_ciint t7xx_cldma_init(struct cldma_ctrl *md_ctrl) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci struct t7xx_cldma_hw *hw_info = &md_ctrl->hw_info; 128662306a36Sopenharmony_ci int ret, i; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci md_ctrl->txq_active = 0; 128962306a36Sopenharmony_ci md_ctrl->rxq_active = 0; 129062306a36Sopenharmony_ci md_ctrl->is_late_init = false; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci ret = t7xx_cldma_pm_init(md_ctrl); 129362306a36Sopenharmony_ci if (ret) 129462306a36Sopenharmony_ci return ret; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci spin_lock_init(&md_ctrl->cldma_lock); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci for (i = 0; i < CLDMA_TXQ_NUM; i++) { 129962306a36Sopenharmony_ci md_cd_queue_struct_init(&md_ctrl->txq[i], md_ctrl, MTK_TX, i); 130062306a36Sopenharmony_ci md_ctrl->txq[i].worker = 130162306a36Sopenharmony_ci alloc_ordered_workqueue("md_hif%d_tx%d_worker", 130262306a36Sopenharmony_ci WQ_MEM_RECLAIM | (i ? 0 : WQ_HIGHPRI), 130362306a36Sopenharmony_ci md_ctrl->hif_id, i); 130462306a36Sopenharmony_ci if (!md_ctrl->txq[i].worker) 130562306a36Sopenharmony_ci goto err_workqueue; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci INIT_WORK(&md_ctrl->txq[i].cldma_work, t7xx_cldma_tx_done); 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci for (i = 0; i < CLDMA_RXQ_NUM; i++) { 131162306a36Sopenharmony_ci md_cd_queue_struct_init(&md_ctrl->rxq[i], md_ctrl, MTK_RX, i); 131262306a36Sopenharmony_ci INIT_WORK(&md_ctrl->rxq[i].cldma_work, t7xx_cldma_rx_done); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci md_ctrl->rxq[i].worker = 131562306a36Sopenharmony_ci alloc_ordered_workqueue("md_hif%d_rx%d_worker", 131662306a36Sopenharmony_ci WQ_MEM_RECLAIM, 131762306a36Sopenharmony_ci md_ctrl->hif_id, i); 131862306a36Sopenharmony_ci if (!md_ctrl->rxq[i].worker) 131962306a36Sopenharmony_ci goto err_workqueue; 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci t7xx_pcie_mac_clear_int(md_ctrl->t7xx_dev, hw_info->phy_interrupt_id); 132362306a36Sopenharmony_ci md_ctrl->t7xx_dev->intr_handler[hw_info->phy_interrupt_id] = t7xx_cldma_isr_handler; 132462306a36Sopenharmony_ci md_ctrl->t7xx_dev->intr_thread[hw_info->phy_interrupt_id] = NULL; 132562306a36Sopenharmony_ci md_ctrl->t7xx_dev->callback_param[hw_info->phy_interrupt_id] = md_ctrl; 132662306a36Sopenharmony_ci t7xx_pcie_mac_clear_int_status(md_ctrl->t7xx_dev, hw_info->phy_interrupt_id); 132762306a36Sopenharmony_ci return 0; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_cierr_workqueue: 133062306a36Sopenharmony_ci t7xx_cldma_destroy_wqs(md_ctrl); 133162306a36Sopenharmony_ci t7xx_cldma_pm_uninit(md_ctrl); 133262306a36Sopenharmony_ci return -ENOMEM; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_civoid t7xx_cldma_switch_cfg(struct cldma_ctrl *md_ctrl) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci t7xx_cldma_late_release(md_ctrl); 133862306a36Sopenharmony_ci t7xx_cldma_late_init(md_ctrl); 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_civoid t7xx_cldma_exit(struct cldma_ctrl *md_ctrl) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci t7xx_cldma_stop(md_ctrl); 134462306a36Sopenharmony_ci t7xx_cldma_late_release(md_ctrl); 134562306a36Sopenharmony_ci t7xx_cldma_destroy_wqs(md_ctrl); 134662306a36Sopenharmony_ci t7xx_cldma_pm_uninit(md_ctrl); 134762306a36Sopenharmony_ci} 1348