18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "dp_rx.h" 78c2ecf20Sopenharmony_ci#include "debug.h" 88c2ecf20Sopenharmony_ci#include "hif.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ciconst struct ce_attr ath11k_host_ce_config_ipq8074[] = { 118c2ecf20Sopenharmony_ci /* CE0: host->target HTC control and raw streams */ 128c2ecf20Sopenharmony_ci { 138c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 148c2ecf20Sopenharmony_ci .src_nentries = 16, 158c2ecf20Sopenharmony_ci .src_sz_max = 2048, 168c2ecf20Sopenharmony_ci .dest_nentries = 0, 178c2ecf20Sopenharmony_ci }, 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci /* CE1: target->host HTT + HTC control */ 208c2ecf20Sopenharmony_ci { 218c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 228c2ecf20Sopenharmony_ci .src_nentries = 0, 238c2ecf20Sopenharmony_ci .src_sz_max = 2048, 248c2ecf20Sopenharmony_ci .dest_nentries = 512, 258c2ecf20Sopenharmony_ci .recv_cb = ath11k_htc_rx_completion_handler, 268c2ecf20Sopenharmony_ci }, 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* CE2: target->host WMI */ 298c2ecf20Sopenharmony_ci { 308c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 318c2ecf20Sopenharmony_ci .src_nentries = 0, 328c2ecf20Sopenharmony_ci .src_sz_max = 2048, 338c2ecf20Sopenharmony_ci .dest_nentries = 512, 348c2ecf20Sopenharmony_ci .recv_cb = ath11k_htc_rx_completion_handler, 358c2ecf20Sopenharmony_ci }, 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci /* CE3: host->target WMI (mac0) */ 388c2ecf20Sopenharmony_ci { 398c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 408c2ecf20Sopenharmony_ci .src_nentries = 32, 418c2ecf20Sopenharmony_ci .src_sz_max = 2048, 428c2ecf20Sopenharmony_ci .dest_nentries = 0, 438c2ecf20Sopenharmony_ci }, 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* CE4: host->target HTT */ 468c2ecf20Sopenharmony_ci { 478c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 488c2ecf20Sopenharmony_ci .src_nentries = 2048, 498c2ecf20Sopenharmony_ci .src_sz_max = 256, 508c2ecf20Sopenharmony_ci .dest_nentries = 0, 518c2ecf20Sopenharmony_ci }, 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* CE5: target->host pktlog */ 548c2ecf20Sopenharmony_ci { 558c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 568c2ecf20Sopenharmony_ci .src_nentries = 0, 578c2ecf20Sopenharmony_ci .src_sz_max = 2048, 588c2ecf20Sopenharmony_ci .dest_nentries = 512, 598c2ecf20Sopenharmony_ci .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, 608c2ecf20Sopenharmony_ci }, 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* CE6: target autonomous hif_memcpy */ 638c2ecf20Sopenharmony_ci { 648c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 658c2ecf20Sopenharmony_ci .src_nentries = 0, 668c2ecf20Sopenharmony_ci .src_sz_max = 0, 678c2ecf20Sopenharmony_ci .dest_nentries = 0, 688c2ecf20Sopenharmony_ci }, 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* CE7: host->target WMI (mac1) */ 718c2ecf20Sopenharmony_ci { 728c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 738c2ecf20Sopenharmony_ci .src_nentries = 32, 748c2ecf20Sopenharmony_ci .src_sz_max = 2048, 758c2ecf20Sopenharmony_ci .dest_nentries = 0, 768c2ecf20Sopenharmony_ci }, 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* CE8: target autonomous hif_memcpy */ 798c2ecf20Sopenharmony_ci { 808c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 818c2ecf20Sopenharmony_ci .src_nentries = 0, 828c2ecf20Sopenharmony_ci .src_sz_max = 0, 838c2ecf20Sopenharmony_ci .dest_nentries = 0, 848c2ecf20Sopenharmony_ci }, 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* CE9: host->target WMI (mac2) */ 878c2ecf20Sopenharmony_ci { 888c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 898c2ecf20Sopenharmony_ci .src_nentries = 32, 908c2ecf20Sopenharmony_ci .src_sz_max = 2048, 918c2ecf20Sopenharmony_ci .dest_nentries = 0, 928c2ecf20Sopenharmony_ci }, 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* CE10: target->host HTT */ 958c2ecf20Sopenharmony_ci { 968c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 978c2ecf20Sopenharmony_ci .src_nentries = 0, 988c2ecf20Sopenharmony_ci .src_sz_max = 2048, 998c2ecf20Sopenharmony_ci .dest_nentries = 512, 1008c2ecf20Sopenharmony_ci .recv_cb = ath11k_htc_rx_completion_handler, 1018c2ecf20Sopenharmony_ci }, 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* CE11: Not used */ 1048c2ecf20Sopenharmony_ci { 1058c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1068c2ecf20Sopenharmony_ci .src_nentries = 0, 1078c2ecf20Sopenharmony_ci .src_sz_max = 0, 1088c2ecf20Sopenharmony_ci .dest_nentries = 0, 1098c2ecf20Sopenharmony_ci }, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciconst struct ce_attr ath11k_host_ce_config_qca6390[] = { 1138c2ecf20Sopenharmony_ci /* CE0: host->target HTC control and raw streams */ 1148c2ecf20Sopenharmony_ci { 1158c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1168c2ecf20Sopenharmony_ci .src_nentries = 16, 1178c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1188c2ecf20Sopenharmony_ci .dest_nentries = 0, 1198c2ecf20Sopenharmony_ci }, 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* CE1: target->host HTT + HTC control */ 1228c2ecf20Sopenharmony_ci { 1238c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1248c2ecf20Sopenharmony_ci .src_nentries = 0, 1258c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1268c2ecf20Sopenharmony_ci .dest_nentries = 512, 1278c2ecf20Sopenharmony_ci .recv_cb = ath11k_htc_rx_completion_handler, 1288c2ecf20Sopenharmony_ci }, 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* CE2: target->host WMI */ 1318c2ecf20Sopenharmony_ci { 1328c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1338c2ecf20Sopenharmony_ci .src_nentries = 0, 1348c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1358c2ecf20Sopenharmony_ci .dest_nentries = 512, 1368c2ecf20Sopenharmony_ci .recv_cb = ath11k_htc_rx_completion_handler, 1378c2ecf20Sopenharmony_ci }, 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* CE3: host->target WMI (mac0) */ 1408c2ecf20Sopenharmony_ci { 1418c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1428c2ecf20Sopenharmony_ci .src_nentries = 32, 1438c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1448c2ecf20Sopenharmony_ci .dest_nentries = 0, 1458c2ecf20Sopenharmony_ci }, 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* CE4: host->target HTT */ 1488c2ecf20Sopenharmony_ci { 1498c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 1508c2ecf20Sopenharmony_ci .src_nentries = 2048, 1518c2ecf20Sopenharmony_ci .src_sz_max = 256, 1528c2ecf20Sopenharmony_ci .dest_nentries = 0, 1538c2ecf20Sopenharmony_ci }, 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* CE5: target->host pktlog */ 1568c2ecf20Sopenharmony_ci { 1578c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1588c2ecf20Sopenharmony_ci .src_nentries = 0, 1598c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1608c2ecf20Sopenharmony_ci .dest_nentries = 512, 1618c2ecf20Sopenharmony_ci .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, 1628c2ecf20Sopenharmony_ci }, 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* CE6: target autonomous hif_memcpy */ 1658c2ecf20Sopenharmony_ci { 1668c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 1678c2ecf20Sopenharmony_ci .src_nentries = 0, 1688c2ecf20Sopenharmony_ci .src_sz_max = 0, 1698c2ecf20Sopenharmony_ci .dest_nentries = 0, 1708c2ecf20Sopenharmony_ci }, 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* CE7: host->target WMI (mac1) */ 1738c2ecf20Sopenharmony_ci { 1748c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1758c2ecf20Sopenharmony_ci .src_nentries = 32, 1768c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1778c2ecf20Sopenharmony_ci .dest_nentries = 0, 1788c2ecf20Sopenharmony_ci }, 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* CE8: target autonomous hif_memcpy */ 1818c2ecf20Sopenharmony_ci { 1828c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1838c2ecf20Sopenharmony_ci .src_nentries = 0, 1848c2ecf20Sopenharmony_ci .src_sz_max = 0, 1858c2ecf20Sopenharmony_ci .dest_nentries = 0, 1868c2ecf20Sopenharmony_ci }, 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci}; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic bool ath11k_ce_need_shadow_fix(int ce_id) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci /* only ce4 needs shadow workaroud*/ 1938c2ecf20Sopenharmony_ci if (ce_id == 4) 1948c2ecf20Sopenharmony_ci return true; 1958c2ecf20Sopenharmony_ci return false; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci int i; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (!ab->hw_params.supports_shadow_regs) 2038c2ecf20Sopenharmony_ci return; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.ce_count; i++) 2068c2ecf20Sopenharmony_ci if (ath11k_ce_need_shadow_fix(i)) 2078c2ecf20Sopenharmony_ci ath11k_dp_shadow_stop_timer(ab, &ab->ce.hp_timer[i]); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int ath11k_ce_rx_buf_enqueue_pipe(struct ath11k_ce_pipe *pipe, 2118c2ecf20Sopenharmony_ci struct sk_buff *skb, dma_addr_t paddr) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct ath11k_base *ab = pipe->ab; 2148c2ecf20Sopenharmony_ci struct ath11k_ce_ring *ring = pipe->dest_ring; 2158c2ecf20Sopenharmony_ci struct hal_srng *srng; 2168c2ecf20Sopenharmony_ci unsigned int write_index; 2178c2ecf20Sopenharmony_ci unsigned int nentries_mask = ring->nentries_mask; 2188c2ecf20Sopenharmony_ci u32 *desc; 2198c2ecf20Sopenharmony_ci int ret; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci lockdep_assert_held(&ab->ce.ce_lock); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci write_index = ring->write_index; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[ring->hal_ring_id]; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) { 2328c2ecf20Sopenharmony_ci ret = -ENOSPC; 2338c2ecf20Sopenharmony_ci goto exit; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 2378c2ecf20Sopenharmony_ci if (!desc) { 2388c2ecf20Sopenharmony_ci ret = -ENOSPC; 2398c2ecf20Sopenharmony_ci goto exit; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ath11k_hal_ce_dst_set_desc(desc, paddr); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ring->skb[write_index] = skb; 2458c2ecf20Sopenharmony_ci write_index = CE_RING_IDX_INCR(nentries_mask, write_index); 2468c2ecf20Sopenharmony_ci ring->write_index = write_index; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci pipe->rx_buf_needed--; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ret = 0; 2518c2ecf20Sopenharmony_ciexit: 2528c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return ret; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int ath11k_ce_rx_post_pipe(struct ath11k_ce_pipe *pipe) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct ath11k_base *ab = pipe->ab; 2628c2ecf20Sopenharmony_ci struct sk_buff *skb; 2638c2ecf20Sopenharmony_ci dma_addr_t paddr; 2648c2ecf20Sopenharmony_ci int ret = 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (!(pipe->dest_ring || pipe->status_ring)) 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci spin_lock_bh(&ab->ce.ce_lock); 2708c2ecf20Sopenharmony_ci while (pipe->rx_buf_needed) { 2718c2ecf20Sopenharmony_ci skb = dev_alloc_skb(pipe->buf_sz); 2728c2ecf20Sopenharmony_ci if (!skb) { 2738c2ecf20Sopenharmony_ci ret = -ENOMEM; 2748c2ecf20Sopenharmony_ci goto exit; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4)); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci paddr = dma_map_single(ab->dev, skb->data, 2808c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 2818c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 2828c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(ab->dev, paddr))) { 2838c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to dma map ce rx buf\n"); 2848c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 2858c2ecf20Sopenharmony_ci ret = -EIO; 2868c2ecf20Sopenharmony_ci goto exit; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci ATH11K_SKB_RXCB(skb)->paddr = paddr; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci ret = ath11k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (ret) { 2948c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to enqueue rx buf: %d\n", ret); 2958c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, paddr, 2968c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 2978c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 2988c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 2998c2ecf20Sopenharmony_ci goto exit; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ciexit: 3048c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->ce.ce_lock); 3058c2ecf20Sopenharmony_ci return ret; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int ath11k_ce_completed_recv_next(struct ath11k_ce_pipe *pipe, 3098c2ecf20Sopenharmony_ci struct sk_buff **skb, int *nbytes) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct ath11k_base *ab = pipe->ab; 3128c2ecf20Sopenharmony_ci struct hal_srng *srng; 3138c2ecf20Sopenharmony_ci unsigned int sw_index; 3148c2ecf20Sopenharmony_ci unsigned int nentries_mask; 3158c2ecf20Sopenharmony_ci u32 *desc; 3168c2ecf20Sopenharmony_ci int ret = 0; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci spin_lock_bh(&ab->ce.ce_lock); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci sw_index = pipe->dest_ring->sw_index; 3218c2ecf20Sopenharmony_ci nentries_mask = pipe->dest_ring->nentries_mask; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[pipe->status_ring->hal_ring_id]; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci desc = ath11k_hal_srng_dst_get_next_entry(ab, srng); 3308c2ecf20Sopenharmony_ci if (!desc) { 3318c2ecf20Sopenharmony_ci ret = -EIO; 3328c2ecf20Sopenharmony_ci goto err; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci *nbytes = ath11k_hal_ce_dst_status_get_length(desc); 3368c2ecf20Sopenharmony_ci if (*nbytes == 0) { 3378c2ecf20Sopenharmony_ci ret = -EIO; 3388c2ecf20Sopenharmony_ci goto err; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci *skb = pipe->dest_ring->skb[sw_index]; 3428c2ecf20Sopenharmony_ci pipe->dest_ring->skb[sw_index] = NULL; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); 3458c2ecf20Sopenharmony_ci pipe->dest_ring->sw_index = sw_index; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci pipe->rx_buf_needed++; 3488c2ecf20Sopenharmony_cierr: 3498c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->ce.ce_lock); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return ret; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic void ath11k_ce_recv_process_cb(struct ath11k_ce_pipe *pipe) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct ath11k_base *ab = pipe->ab; 3618c2ecf20Sopenharmony_ci struct sk_buff *skb; 3628c2ecf20Sopenharmony_ci struct sk_buff_head list; 3638c2ecf20Sopenharmony_ci unsigned int nbytes, max_nbytes; 3648c2ecf20Sopenharmony_ci int ret; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci __skb_queue_head_init(&list); 3678c2ecf20Sopenharmony_ci while (ath11k_ce_completed_recv_next(pipe, &skb, &nbytes) == 0) { 3688c2ecf20Sopenharmony_ci max_nbytes = skb->len + skb_tailroom(skb); 3698c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 3708c2ecf20Sopenharmony_ci max_nbytes, DMA_FROM_DEVICE); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (unlikely(max_nbytes < nbytes)) { 3738c2ecf20Sopenharmony_ci ath11k_warn(ab, "rxed more than expected (nbytes %d, max %d)", 3748c2ecf20Sopenharmony_ci nbytes, max_nbytes); 3758c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 3768c2ecf20Sopenharmony_ci continue; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci skb_put(skb, nbytes); 3808c2ecf20Sopenharmony_ci __skb_queue_tail(&list, skb); 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&list))) { 3848c2ecf20Sopenharmony_ci ath11k_dbg(ab, ATH11K_DBG_AHB, "rx ce pipe %d len %d\n", 3858c2ecf20Sopenharmony_ci pipe->pipe_num, skb->len); 3868c2ecf20Sopenharmony_ci pipe->recv_cb(ab, skb); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci ret = ath11k_ce_rx_post_pipe(pipe); 3908c2ecf20Sopenharmony_ci if (ret && ret != -ENOSPC) { 3918c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n", 3928c2ecf20Sopenharmony_ci pipe->pipe_num, ret); 3938c2ecf20Sopenharmony_ci mod_timer(&ab->rx_replenish_retry, 3948c2ecf20Sopenharmony_ci jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic struct sk_buff *ath11k_ce_completed_send_next(struct ath11k_ce_pipe *pipe) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct ath11k_base *ab = pipe->ab; 4018c2ecf20Sopenharmony_ci struct hal_srng *srng; 4028c2ecf20Sopenharmony_ci unsigned int sw_index; 4038c2ecf20Sopenharmony_ci unsigned int nentries_mask; 4048c2ecf20Sopenharmony_ci struct sk_buff *skb; 4058c2ecf20Sopenharmony_ci u32 *desc; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci spin_lock_bh(&ab->ce.ce_lock); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci sw_index = pipe->src_ring->sw_index; 4108c2ecf20Sopenharmony_ci nentries_mask = pipe->src_ring->nentries_mask; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id]; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci desc = ath11k_hal_srng_src_reap_next(ab, srng); 4198c2ecf20Sopenharmony_ci if (!desc) { 4208c2ecf20Sopenharmony_ci skb = ERR_PTR(-EIO); 4218c2ecf20Sopenharmony_ci goto err_unlock; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci skb = pipe->src_ring->skb[sw_index]; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci pipe->src_ring->skb[sw_index] = NULL; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); 4298c2ecf20Sopenharmony_ci pipe->src_ring->sw_index = sw_index; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cierr_unlock: 4328c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->ce.ce_lock); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return skb; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct ath11k_base *ab = pipe->ab; 4428c2ecf20Sopenharmony_ci struct sk_buff *skb; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci while (!IS_ERR(skb = ath11k_ce_completed_send_next(pipe))) { 4458c2ecf20Sopenharmony_ci if (!skb) 4468c2ecf20Sopenharmony_ci continue; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len, 4498c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 4508c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic void ath11k_ce_srng_msi_ring_params_setup(struct ath11k_base *ab, u32 ce_id, 4558c2ecf20Sopenharmony_ci struct hal_srng_params *ring_params) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci u32 msi_data_start; 4588c2ecf20Sopenharmony_ci u32 msi_data_count; 4598c2ecf20Sopenharmony_ci u32 msi_irq_start; 4608c2ecf20Sopenharmony_ci u32 addr_lo; 4618c2ecf20Sopenharmony_ci u32 addr_hi; 4628c2ecf20Sopenharmony_ci int ret; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci ret = ath11k_get_user_msi_vector(ab, "CE", 4658c2ecf20Sopenharmony_ci &msi_data_count, &msi_data_start, 4668c2ecf20Sopenharmony_ci &msi_irq_start); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (ret) 4698c2ecf20Sopenharmony_ci return; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci ath11k_get_msi_address(ab, &addr_lo, &addr_hi); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci ring_params->msi_addr = addr_lo; 4748c2ecf20Sopenharmony_ci ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32); 4758c2ecf20Sopenharmony_ci ring_params->msi_data = (ce_id % msi_data_count) + msi_data_start; 4768c2ecf20Sopenharmony_ci ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int ath11k_ce_init_ring(struct ath11k_base *ab, 4808c2ecf20Sopenharmony_ci struct ath11k_ce_ring *ce_ring, 4818c2ecf20Sopenharmony_ci int ce_id, enum hal_ring_type type) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct hal_srng_params params = { 0 }; 4848c2ecf20Sopenharmony_ci int ret; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci params.ring_base_paddr = ce_ring->base_addr_ce_space; 4878c2ecf20Sopenharmony_ci params.ring_base_vaddr = ce_ring->base_addr_owner_space; 4888c2ecf20Sopenharmony_ci params.num_entries = ce_ring->nentries; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) 4918c2ecf20Sopenharmony_ci ath11k_ce_srng_msi_ring_params_setup(ab, ce_id, ¶ms); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci switch (type) { 4948c2ecf20Sopenharmony_ci case HAL_CE_SRC: 4958c2ecf20Sopenharmony_ci if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) 4968c2ecf20Sopenharmony_ci params.intr_batch_cntr_thres_entries = 1; 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci case HAL_CE_DST: 4998c2ecf20Sopenharmony_ci params.max_buffer_len = ab->hw_params.host_ce_config[ce_id].src_sz_max; 5008c2ecf20Sopenharmony_ci if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { 5018c2ecf20Sopenharmony_ci params.intr_timer_thres_us = 1024; 5028c2ecf20Sopenharmony_ci params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; 5038c2ecf20Sopenharmony_ci params.low_threshold = ce_ring->nentries - 3; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci case HAL_CE_DST_STATUS: 5078c2ecf20Sopenharmony_ci if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { 5088c2ecf20Sopenharmony_ci params.intr_batch_cntr_thres_entries = 1; 5098c2ecf20Sopenharmony_ci params.intr_timer_thres_us = 0x1000; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci default: 5138c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid CE ring type %d\n", type); 5148c2ecf20Sopenharmony_ci return -EINVAL; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* TODO: Init other params needed by HAL to init the ring */ 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci ret = ath11k_hal_srng_setup(ab, type, ce_id, 0, ¶ms); 5208c2ecf20Sopenharmony_ci if (ret < 0) { 5218c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n", 5228c2ecf20Sopenharmony_ci ret, ce_id); 5238c2ecf20Sopenharmony_ci return ret; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci ce_ring->hal_ring_id = ret; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (ab->hw_params.supports_shadow_regs && 5298c2ecf20Sopenharmony_ci ath11k_ce_need_shadow_fix(ce_id)) 5308c2ecf20Sopenharmony_ci ath11k_dp_shadow_init_timer(ab, &ab->ce.hp_timer[ce_id], 5318c2ecf20Sopenharmony_ci ATH11K_SHADOW_CTRL_TIMER_INTERVAL, 5328c2ecf20Sopenharmony_ci ce_ring->hal_ring_id); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return 0; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic struct ath11k_ce_ring * 5388c2ecf20Sopenharmony_ciath11k_ce_alloc_ring(struct ath11k_base *ab, int nentries, int desc_sz) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct ath11k_ce_ring *ce_ring; 5418c2ecf20Sopenharmony_ci dma_addr_t base_addr; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci ce_ring = kzalloc(struct_size(ce_ring, skb, nentries), GFP_KERNEL); 5448c2ecf20Sopenharmony_ci if (ce_ring == NULL) 5458c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ce_ring->nentries = nentries; 5488c2ecf20Sopenharmony_ci ce_ring->nentries_mask = nentries - 1; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Legacy platforms that do not support cache 5518c2ecf20Sopenharmony_ci * coherent DMA are unsupported 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_ci ce_ring->base_addr_owner_space_unaligned = 5548c2ecf20Sopenharmony_ci dma_alloc_coherent(ab->dev, 5558c2ecf20Sopenharmony_ci nentries * desc_sz + CE_DESC_RING_ALIGN, 5568c2ecf20Sopenharmony_ci &base_addr, GFP_KERNEL); 5578c2ecf20Sopenharmony_ci if (!ce_ring->base_addr_owner_space_unaligned) { 5588c2ecf20Sopenharmony_ci kfree(ce_ring); 5598c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci ce_ring->base_addr_ce_space_unaligned = base_addr; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci ce_ring->base_addr_owner_space = PTR_ALIGN( 5658c2ecf20Sopenharmony_ci ce_ring->base_addr_owner_space_unaligned, 5668c2ecf20Sopenharmony_ci CE_DESC_RING_ALIGN); 5678c2ecf20Sopenharmony_ci ce_ring->base_addr_ce_space = ALIGN( 5688c2ecf20Sopenharmony_ci ce_ring->base_addr_ce_space_unaligned, 5698c2ecf20Sopenharmony_ci CE_DESC_RING_ALIGN); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return ce_ring; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; 5778c2ecf20Sopenharmony_ci const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id]; 5788c2ecf20Sopenharmony_ci struct ath11k_ce_ring *ring; 5798c2ecf20Sopenharmony_ci int nentries; 5808c2ecf20Sopenharmony_ci int desc_sz; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci pipe->attr_flags = attr->flags; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (attr->src_nentries) { 5858c2ecf20Sopenharmony_ci pipe->send_cb = ath11k_ce_send_done_cb; 5868c2ecf20Sopenharmony_ci nentries = roundup_pow_of_two(attr->src_nentries); 5878c2ecf20Sopenharmony_ci desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); 5888c2ecf20Sopenharmony_ci ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 5898c2ecf20Sopenharmony_ci if (IS_ERR(ring)) 5908c2ecf20Sopenharmony_ci return PTR_ERR(ring); 5918c2ecf20Sopenharmony_ci pipe->src_ring = ring; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (attr->dest_nentries) { 5958c2ecf20Sopenharmony_ci pipe->recv_cb = attr->recv_cb; 5968c2ecf20Sopenharmony_ci nentries = roundup_pow_of_two(attr->dest_nentries); 5978c2ecf20Sopenharmony_ci desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); 5988c2ecf20Sopenharmony_ci ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 5998c2ecf20Sopenharmony_ci if (IS_ERR(ring)) 6008c2ecf20Sopenharmony_ci return PTR_ERR(ring); 6018c2ecf20Sopenharmony_ci pipe->dest_ring = ring; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); 6048c2ecf20Sopenharmony_ci ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 6058c2ecf20Sopenharmony_ci if (IS_ERR(ring)) 6068c2ecf20Sopenharmony_ci return PTR_ERR(ring); 6078c2ecf20Sopenharmony_ci pipe->status_ring = ring; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_civoid ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (pipe->send_cb) 6188c2ecf20Sopenharmony_ci pipe->send_cb(pipe); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (pipe->recv_cb) 6218c2ecf20Sopenharmony_ci ath11k_ce_recv_process_cb(pipe); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_civoid ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb) 6298c2ecf20Sopenharmony_ci pipe->send_cb(pipe); 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath11k_ce_per_engine_service); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ciint ath11k_ce_send(struct ath11k_base *ab, struct sk_buff *skb, u8 pipe_id, 6348c2ecf20Sopenharmony_ci u16 transfer_id) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; 6378c2ecf20Sopenharmony_ci struct hal_srng *srng; 6388c2ecf20Sopenharmony_ci u32 *desc; 6398c2ecf20Sopenharmony_ci unsigned int write_index, sw_index; 6408c2ecf20Sopenharmony_ci unsigned int nentries_mask; 6418c2ecf20Sopenharmony_ci int ret = 0; 6428c2ecf20Sopenharmony_ci u8 byte_swap_data = 0; 6438c2ecf20Sopenharmony_ci int num_used; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Check if some entries could be regained by handling tx completion if 6468c2ecf20Sopenharmony_ci * the CE has interrupts disabled and the used entries is more than the 6478c2ecf20Sopenharmony_ci * defined usage threshold. 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_ci if (pipe->attr_flags & CE_ATTR_DIS_INTR) { 6508c2ecf20Sopenharmony_ci spin_lock_bh(&ab->ce.ce_lock); 6518c2ecf20Sopenharmony_ci write_index = pipe->src_ring->write_index; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci sw_index = pipe->src_ring->sw_index; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (write_index >= sw_index) 6568c2ecf20Sopenharmony_ci num_used = write_index - sw_index; 6578c2ecf20Sopenharmony_ci else 6588c2ecf20Sopenharmony_ci num_used = pipe->src_ring->nentries - sw_index + 6598c2ecf20Sopenharmony_ci write_index; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->ce.ce_lock); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (num_used > ATH11K_CE_USAGE_THRESHOLD) 6648c2ecf20Sopenharmony_ci ath11k_ce_poll_send_completed(ab, pipe->pipe_num); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)) 6688c2ecf20Sopenharmony_ci return -ESHUTDOWN; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci spin_lock_bh(&ab->ce.ce_lock); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci write_index = pipe->src_ring->write_index; 6738c2ecf20Sopenharmony_ci nentries_mask = pipe->src_ring->nentries_mask; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id]; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci spin_lock_bh(&srng->lock); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci ath11k_hal_srng_access_begin(ab, srng); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) { 6828c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 6838c2ecf20Sopenharmony_ci ret = -ENOBUFS; 6848c2ecf20Sopenharmony_ci goto err_unlock; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci desc = ath11k_hal_srng_src_get_next_reaped(ab, srng); 6888c2ecf20Sopenharmony_ci if (!desc) { 6898c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 6908c2ecf20Sopenharmony_ci ret = -ENOBUFS; 6918c2ecf20Sopenharmony_ci goto err_unlock; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (pipe->attr_flags & CE_ATTR_BYTE_SWAP_DATA) 6958c2ecf20Sopenharmony_ci byte_swap_data = 1; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci ath11k_hal_ce_src_set_desc(desc, ATH11K_SKB_CB(skb)->paddr, 6988c2ecf20Sopenharmony_ci skb->len, transfer_id, byte_swap_data); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci pipe->src_ring->skb[write_index] = skb; 7018c2ecf20Sopenharmony_ci pipe->src_ring->write_index = CE_RING_IDX_INCR(nentries_mask, 7028c2ecf20Sopenharmony_ci write_index); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci ath11k_hal_srng_access_end(ab, srng); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (ath11k_ce_need_shadow_fix(pipe_id)) 7078c2ecf20Sopenharmony_ci ath11k_dp_shadow_start_timer(ab, srng, &ab->ce.hp_timer[pipe_id]); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->ce.ce_lock); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci return 0; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cierr_unlock: 7168c2ecf20Sopenharmony_ci spin_unlock_bh(&srng->lock); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->ce.ce_lock); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci return ret; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic void ath11k_ce_rx_pipe_cleanup(struct ath11k_ce_pipe *pipe) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct ath11k_base *ab = pipe->ab; 7268c2ecf20Sopenharmony_ci struct ath11k_ce_ring *ring = pipe->dest_ring; 7278c2ecf20Sopenharmony_ci struct sk_buff *skb; 7288c2ecf20Sopenharmony_ci int i; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (!(ring && pipe->buf_sz)) 7318c2ecf20Sopenharmony_ci return; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci for (i = 0; i < ring->nentries; i++) { 7348c2ecf20Sopenharmony_ci skb = ring->skb[i]; 7358c2ecf20Sopenharmony_ci if (!skb) 7368c2ecf20Sopenharmony_ci continue; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci ring->skb[i] = NULL; 7398c2ecf20Sopenharmony_ci dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 7408c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); 7418c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic void ath11k_ce_shadow_config(struct ath11k_base *ab) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci int i; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.ce_count; i++) { 7508c2ecf20Sopenharmony_ci if (ab->hw_params.host_ce_config[i].src_nentries) 7518c2ecf20Sopenharmony_ci ath11k_hal_srng_update_shadow_config(ab, 7528c2ecf20Sopenharmony_ci HAL_CE_SRC, i); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (ab->hw_params.host_ce_config[i].dest_nentries) { 7558c2ecf20Sopenharmony_ci ath11k_hal_srng_update_shadow_config(ab, 7568c2ecf20Sopenharmony_ci HAL_CE_DST, i); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci ath11k_hal_srng_update_shadow_config(ab, 7598c2ecf20Sopenharmony_ci HAL_CE_DST_STATUS, i); 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_civoid ath11k_ce_get_shadow_config(struct ath11k_base *ab, 7658c2ecf20Sopenharmony_ci u32 **shadow_cfg, u32 *shadow_cfg_len) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci if (!ab->hw_params.supports_shadow_regs) 7688c2ecf20Sopenharmony_ci return; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci ath11k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* shadow is already configured */ 7738c2ecf20Sopenharmony_ci if (*shadow_cfg_len) 7748c2ecf20Sopenharmony_ci return; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* shadow isn't configured yet, configure now. 7778c2ecf20Sopenharmony_ci * non-CE srngs are configured firstly, then 7788c2ecf20Sopenharmony_ci * all CE srngs. 7798c2ecf20Sopenharmony_ci */ 7808c2ecf20Sopenharmony_ci ath11k_hal_srng_shadow_config(ab); 7818c2ecf20Sopenharmony_ci ath11k_ce_shadow_config(ab); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* get the shadow configuration */ 7848c2ecf20Sopenharmony_ci ath11k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len); 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath11k_ce_get_shadow_config); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_civoid ath11k_ce_cleanup_pipes(struct ath11k_base *ab) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci struct ath11k_ce_pipe *pipe; 7918c2ecf20Sopenharmony_ci int pipe_num; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci ath11k_ce_stop_shadow_timers(ab); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci for (pipe_num = 0; pipe_num < ab->hw_params.ce_count; pipe_num++) { 7968c2ecf20Sopenharmony_ci pipe = &ab->ce.ce_pipe[pipe_num]; 7978c2ecf20Sopenharmony_ci ath11k_ce_rx_pipe_cleanup(pipe); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* Cleanup any src CE's which have interrupts disabled */ 8008c2ecf20Sopenharmony_ci ath11k_ce_poll_send_completed(ab, pipe_num); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci /* NOTE: Should we also clean up tx buffer in all pipes? */ 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath11k_ce_cleanup_pipes); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_civoid ath11k_ce_rx_post_buf(struct ath11k_base *ab) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct ath11k_ce_pipe *pipe; 8108c2ecf20Sopenharmony_ci int i; 8118c2ecf20Sopenharmony_ci int ret; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.ce_count; i++) { 8148c2ecf20Sopenharmony_ci pipe = &ab->ce.ce_pipe[i]; 8158c2ecf20Sopenharmony_ci ret = ath11k_ce_rx_post_pipe(pipe); 8168c2ecf20Sopenharmony_ci if (ret) { 8178c2ecf20Sopenharmony_ci if (ret == -ENOSPC) 8188c2ecf20Sopenharmony_ci continue; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n", 8218c2ecf20Sopenharmony_ci i, ret); 8228c2ecf20Sopenharmony_ci mod_timer(&ab->rx_replenish_retry, 8238c2ecf20Sopenharmony_ci jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci return; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath11k_ce_rx_post_buf); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_civoid ath11k_ce_rx_replenish_retry(struct timer_list *t) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct ath11k_base *ab = from_timer(ab, t, rx_replenish_retry); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci ath11k_ce_rx_post_buf(ab); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ciint ath11k_ce_init_pipes(struct ath11k_base *ab) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci struct ath11k_ce_pipe *pipe; 8418c2ecf20Sopenharmony_ci int i; 8428c2ecf20Sopenharmony_ci int ret; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci ath11k_ce_get_shadow_config(ab, &ab->qmi.ce_cfg.shadow_reg_v2, 8458c2ecf20Sopenharmony_ci &ab->qmi.ce_cfg.shadow_reg_v2_len); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.ce_count; i++) { 8488c2ecf20Sopenharmony_ci pipe = &ab->ce.ce_pipe[i]; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (pipe->src_ring) { 8518c2ecf20Sopenharmony_ci ret = ath11k_ce_init_ring(ab, pipe->src_ring, i, 8528c2ecf20Sopenharmony_ci HAL_CE_SRC); 8538c2ecf20Sopenharmony_ci if (ret) { 8548c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to init src ring: %d\n", 8558c2ecf20Sopenharmony_ci ret); 8568c2ecf20Sopenharmony_ci /* Should we clear any partial init */ 8578c2ecf20Sopenharmony_ci return ret; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci pipe->src_ring->write_index = 0; 8618c2ecf20Sopenharmony_ci pipe->src_ring->sw_index = 0; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (pipe->dest_ring) { 8658c2ecf20Sopenharmony_ci ret = ath11k_ce_init_ring(ab, pipe->dest_ring, i, 8668c2ecf20Sopenharmony_ci HAL_CE_DST); 8678c2ecf20Sopenharmony_ci if (ret) { 8688c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to init dest ring: %d\n", 8698c2ecf20Sopenharmony_ci ret); 8708c2ecf20Sopenharmony_ci /* Should we clear any partial init */ 8718c2ecf20Sopenharmony_ci return ret; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci pipe->rx_buf_needed = pipe->dest_ring->nentries ? 8758c2ecf20Sopenharmony_ci pipe->dest_ring->nentries - 2 : 0; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci pipe->dest_ring->write_index = 0; 8788c2ecf20Sopenharmony_ci pipe->dest_ring->sw_index = 0; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (pipe->status_ring) { 8828c2ecf20Sopenharmony_ci ret = ath11k_ce_init_ring(ab, pipe->status_ring, i, 8838c2ecf20Sopenharmony_ci HAL_CE_DST_STATUS); 8848c2ecf20Sopenharmony_ci if (ret) { 8858c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to init dest status ing: %d\n", 8868c2ecf20Sopenharmony_ci ret); 8878c2ecf20Sopenharmony_ci /* Should we clear any partial init */ 8888c2ecf20Sopenharmony_ci return ret; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci pipe->status_ring->write_index = 0; 8928c2ecf20Sopenharmony_ci pipe->status_ring->sw_index = 0; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci return 0; 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_civoid ath11k_ce_free_pipes(struct ath11k_base *ab) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci struct ath11k_ce_pipe *pipe; 9028c2ecf20Sopenharmony_ci int desc_sz; 9038c2ecf20Sopenharmony_ci int i; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.ce_count; i++) { 9068c2ecf20Sopenharmony_ci pipe = &ab->ce.ce_pipe[i]; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (ath11k_ce_need_shadow_fix(i)) 9098c2ecf20Sopenharmony_ci ath11k_dp_shadow_stop_timer(ab, &ab->ce.hp_timer[i]); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (pipe->src_ring) { 9128c2ecf20Sopenharmony_ci desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); 9138c2ecf20Sopenharmony_ci dma_free_coherent(ab->dev, 9148c2ecf20Sopenharmony_ci pipe->src_ring->nentries * desc_sz + 9158c2ecf20Sopenharmony_ci CE_DESC_RING_ALIGN, 9168c2ecf20Sopenharmony_ci pipe->src_ring->base_addr_owner_space, 9178c2ecf20Sopenharmony_ci pipe->src_ring->base_addr_ce_space); 9188c2ecf20Sopenharmony_ci kfree(pipe->src_ring); 9198c2ecf20Sopenharmony_ci pipe->src_ring = NULL; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (pipe->dest_ring) { 9238c2ecf20Sopenharmony_ci desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); 9248c2ecf20Sopenharmony_ci dma_free_coherent(ab->dev, 9258c2ecf20Sopenharmony_ci pipe->dest_ring->nentries * desc_sz + 9268c2ecf20Sopenharmony_ci CE_DESC_RING_ALIGN, 9278c2ecf20Sopenharmony_ci pipe->dest_ring->base_addr_owner_space, 9288c2ecf20Sopenharmony_ci pipe->dest_ring->base_addr_ce_space); 9298c2ecf20Sopenharmony_ci kfree(pipe->dest_ring); 9308c2ecf20Sopenharmony_ci pipe->dest_ring = NULL; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (pipe->status_ring) { 9348c2ecf20Sopenharmony_ci desc_sz = 9358c2ecf20Sopenharmony_ci ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); 9368c2ecf20Sopenharmony_ci dma_free_coherent(ab->dev, 9378c2ecf20Sopenharmony_ci pipe->status_ring->nentries * desc_sz + 9388c2ecf20Sopenharmony_ci CE_DESC_RING_ALIGN, 9398c2ecf20Sopenharmony_ci pipe->status_ring->base_addr_owner_space, 9408c2ecf20Sopenharmony_ci pipe->status_ring->base_addr_ce_space); 9418c2ecf20Sopenharmony_ci kfree(pipe->status_ring); 9428c2ecf20Sopenharmony_ci pipe->status_ring = NULL; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath11k_ce_free_pipes); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ciint ath11k_ce_alloc_pipes(struct ath11k_base *ab) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct ath11k_ce_pipe *pipe; 9518c2ecf20Sopenharmony_ci int i; 9528c2ecf20Sopenharmony_ci int ret; 9538c2ecf20Sopenharmony_ci const struct ce_attr *attr; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci spin_lock_init(&ab->ce.ce_lock); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci for (i = 0; i < ab->hw_params.ce_count; i++) { 9588c2ecf20Sopenharmony_ci attr = &ab->hw_params.host_ce_config[i]; 9598c2ecf20Sopenharmony_ci pipe = &ab->ce.ce_pipe[i]; 9608c2ecf20Sopenharmony_ci pipe->pipe_num = i; 9618c2ecf20Sopenharmony_ci pipe->ab = ab; 9628c2ecf20Sopenharmony_ci pipe->buf_sz = attr->src_sz_max; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci ret = ath11k_ce_alloc_pipe(ab, i); 9658c2ecf20Sopenharmony_ci if (ret) { 9668c2ecf20Sopenharmony_ci /* Free any parial successful allocation */ 9678c2ecf20Sopenharmony_ci ath11k_ce_free_pipes(ab); 9688c2ecf20Sopenharmony_ci return ret; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return 0; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath11k_ce_alloc_pipes); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci/* For Big Endian Host, Copy Engine byte_swap is enabled 9778c2ecf20Sopenharmony_ci * When Copy Engine does byte_swap, need to byte swap again for the 9788c2ecf20Sopenharmony_ci * Host to get/put buffer content in the correct byte order 9798c2ecf20Sopenharmony_ci */ 9808c2ecf20Sopenharmony_civoid ath11k_ce_byte_swap(void *mem, u32 len) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci int i; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) { 9858c2ecf20Sopenharmony_ci if (!mem) 9868c2ecf20Sopenharmony_ci return; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci for (i = 0; i < (len / 4); i++) { 9898c2ecf20Sopenharmony_ci *(u32 *)mem = swab32(*(u32 *)mem); 9908c2ecf20Sopenharmony_ci mem += 4; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ciint ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci if (ce_id >= ab->hw_params.ce_count) 9988c2ecf20Sopenharmony_ci return -EINVAL; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci return ab->hw_params.host_ce_config[ce_id].flags; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath11k_ce_get_attr_flags); 1003