1d5c65159SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear 2d5c65159SKalle Valo /* 3d5c65159SKalle Valo * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. 4d5c65159SKalle Valo */ 5d5c65159SKalle Valo 6d5c65159SKalle Valo #include "dp_rx.h" 7d5c65159SKalle Valo #include "debug.h" 8c4eacabeSGovind Singh #include "hif.h" 9d5c65159SKalle Valo 10e3396b8bSCarl Huang const struct ce_attr ath11k_host_ce_config_ipq8074[] = { 11d5c65159SKalle Valo /* CE0: host->target HTC control and raw streams */ 12d5c65159SKalle Valo { 13d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 14d5c65159SKalle Valo .src_nentries = 16, 15d5c65159SKalle Valo .src_sz_max = 2048, 16d5c65159SKalle Valo .dest_nentries = 0, 17*f951380aSP Praneesh .send_cb = ath11k_htc_tx_completion_handler, 18d5c65159SKalle Valo }, 19d5c65159SKalle Valo 20d5c65159SKalle Valo /* CE1: target->host HTT + HTC control */ 21d5c65159SKalle Valo { 22d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 23d5c65159SKalle Valo .src_nentries = 0, 24d5c65159SKalle Valo .src_sz_max = 2048, 25d5c65159SKalle Valo .dest_nentries = 512, 26d5c65159SKalle Valo .recv_cb = ath11k_htc_rx_completion_handler, 27d5c65159SKalle Valo }, 28d5c65159SKalle Valo 29d5c65159SKalle Valo /* CE2: target->host WMI */ 30d5c65159SKalle Valo { 31d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 32d5c65159SKalle Valo .src_nentries = 0, 33d5c65159SKalle Valo .src_sz_max = 2048, 34d5c65159SKalle Valo .dest_nentries = 512, 35d5c65159SKalle Valo .recv_cb = ath11k_htc_rx_completion_handler, 36d5c65159SKalle Valo }, 37d5c65159SKalle Valo 38d5c65159SKalle Valo /* CE3: host->target WMI (mac0) */ 39d5c65159SKalle Valo { 40d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 41d5c65159SKalle Valo .src_nentries = 32, 42d5c65159SKalle Valo .src_sz_max = 2048, 43d5c65159SKalle Valo .dest_nentries = 0, 44*f951380aSP Praneesh .send_cb = ath11k_htc_tx_completion_handler, 45d5c65159SKalle Valo }, 46d5c65159SKalle Valo 47d5c65159SKalle Valo /* CE4: host->target HTT */ 48d5c65159SKalle Valo { 49d5c65159SKalle Valo .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 50d5c65159SKalle Valo .src_nentries = 2048, 51d5c65159SKalle Valo .src_sz_max = 256, 52d5c65159SKalle Valo .dest_nentries = 0, 53d5c65159SKalle Valo }, 54d5c65159SKalle Valo 55d5c65159SKalle Valo /* CE5: target->host pktlog */ 56d5c65159SKalle Valo { 57d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 58d5c65159SKalle Valo .src_nentries = 0, 59d5c65159SKalle Valo .src_sz_max = 2048, 60d5c65159SKalle Valo .dest_nentries = 512, 61d5c65159SKalle Valo .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, 62d5c65159SKalle Valo }, 63d5c65159SKalle Valo 64d5c65159SKalle Valo /* CE6: target autonomous hif_memcpy */ 65d5c65159SKalle Valo { 66d5c65159SKalle Valo .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 67d5c65159SKalle Valo .src_nentries = 0, 68d5c65159SKalle Valo .src_sz_max = 0, 69d5c65159SKalle Valo .dest_nentries = 0, 70d5c65159SKalle Valo }, 71d5c65159SKalle Valo 72d5c65159SKalle Valo /* CE7: host->target WMI (mac1) */ 73d5c65159SKalle Valo { 74d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 75d5c65159SKalle Valo .src_nentries = 32, 76d5c65159SKalle Valo .src_sz_max = 2048, 77d5c65159SKalle Valo .dest_nentries = 0, 78*f951380aSP Praneesh .send_cb = ath11k_htc_tx_completion_handler, 79d5c65159SKalle Valo }, 80d5c65159SKalle Valo 81d5c65159SKalle Valo /* CE8: target autonomous hif_memcpy */ 82d5c65159SKalle Valo { 832c5545bfSP Praneesh .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 84d5c65159SKalle Valo .src_nentries = 0, 85d5c65159SKalle Valo .src_sz_max = 0, 86d5c65159SKalle Valo .dest_nentries = 0, 87d5c65159SKalle Valo }, 88d5c65159SKalle Valo 89d5c65159SKalle Valo /* CE9: host->target WMI (mac2) */ 90d5c65159SKalle Valo { 91d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 92d5c65159SKalle Valo .src_nentries = 32, 93d5c65159SKalle Valo .src_sz_max = 2048, 94d5c65159SKalle Valo .dest_nentries = 0, 95*f951380aSP Praneesh .send_cb = ath11k_htc_tx_completion_handler, 96d5c65159SKalle Valo }, 97d5c65159SKalle Valo 98d5c65159SKalle Valo /* CE10: target->host HTT */ 99d5c65159SKalle Valo { 100d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 101d5c65159SKalle Valo .src_nentries = 0, 102d5c65159SKalle Valo .src_sz_max = 2048, 103d5c65159SKalle Valo .dest_nentries = 512, 104d5c65159SKalle Valo .recv_cb = ath11k_htc_rx_completion_handler, 105d5c65159SKalle Valo }, 106d5c65159SKalle Valo 107d5c65159SKalle Valo /* CE11: Not used */ 108d5c65159SKalle Valo { 109d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 110d5c65159SKalle Valo .src_nentries = 0, 111d5c65159SKalle Valo .src_sz_max = 0, 112d5c65159SKalle Valo .dest_nentries = 0, 113d5c65159SKalle Valo }, 114d5c65159SKalle Valo }; 115d5c65159SKalle Valo 116e3396b8bSCarl Huang const struct ce_attr ath11k_host_ce_config_qca6390[] = { 117e3396b8bSCarl Huang /* CE0: host->target HTC control and raw streams */ 118e3396b8bSCarl Huang { 119e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 120e3396b8bSCarl Huang .src_nentries = 16, 121e3396b8bSCarl Huang .src_sz_max = 2048, 122e3396b8bSCarl Huang .dest_nentries = 0, 123e3396b8bSCarl Huang }, 124e3396b8bSCarl Huang 125e3396b8bSCarl Huang /* CE1: target->host HTT + HTC control */ 126e3396b8bSCarl Huang { 127e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 128e3396b8bSCarl Huang .src_nentries = 0, 129e3396b8bSCarl Huang .src_sz_max = 2048, 130e3396b8bSCarl Huang .dest_nentries = 512, 131e3396b8bSCarl Huang .recv_cb = ath11k_htc_rx_completion_handler, 132e3396b8bSCarl Huang }, 133e3396b8bSCarl Huang 134e3396b8bSCarl Huang /* CE2: target->host WMI */ 135e3396b8bSCarl Huang { 136e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 137e3396b8bSCarl Huang .src_nentries = 0, 138e3396b8bSCarl Huang .src_sz_max = 2048, 139e3396b8bSCarl Huang .dest_nentries = 512, 140e3396b8bSCarl Huang .recv_cb = ath11k_htc_rx_completion_handler, 141e3396b8bSCarl Huang }, 142e3396b8bSCarl Huang 143e3396b8bSCarl Huang /* CE3: host->target WMI (mac0) */ 144e3396b8bSCarl Huang { 145e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 146e3396b8bSCarl Huang .src_nentries = 32, 147e3396b8bSCarl Huang .src_sz_max = 2048, 148e3396b8bSCarl Huang .dest_nentries = 0, 149*f951380aSP Praneesh .send_cb = ath11k_htc_tx_completion_handler, 150e3396b8bSCarl Huang }, 151e3396b8bSCarl Huang 152e3396b8bSCarl Huang /* CE4: host->target HTT */ 153e3396b8bSCarl Huang { 154e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 155e3396b8bSCarl Huang .src_nentries = 2048, 156e3396b8bSCarl Huang .src_sz_max = 256, 157e3396b8bSCarl Huang .dest_nentries = 0, 158e3396b8bSCarl Huang }, 159e3396b8bSCarl Huang 160e3396b8bSCarl Huang /* CE5: target->host pktlog */ 161e3396b8bSCarl Huang { 162e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 163e3396b8bSCarl Huang .src_nentries = 0, 164e3396b8bSCarl Huang .src_sz_max = 2048, 165e3396b8bSCarl Huang .dest_nentries = 512, 166e3396b8bSCarl Huang .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, 167e3396b8bSCarl Huang }, 168e3396b8bSCarl Huang 169e3396b8bSCarl Huang /* CE6: target autonomous hif_memcpy */ 170e3396b8bSCarl Huang { 171e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 172e3396b8bSCarl Huang .src_nentries = 0, 173e3396b8bSCarl Huang .src_sz_max = 0, 174e3396b8bSCarl Huang .dest_nentries = 0, 175e3396b8bSCarl Huang }, 176e3396b8bSCarl Huang 177e3396b8bSCarl Huang /* CE7: host->target WMI (mac1) */ 178e3396b8bSCarl Huang { 179e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 180e3396b8bSCarl Huang .src_nentries = 32, 181e3396b8bSCarl Huang .src_sz_max = 2048, 182e3396b8bSCarl Huang .dest_nentries = 0, 183*f951380aSP Praneesh .send_cb = ath11k_htc_tx_completion_handler, 184e3396b8bSCarl Huang }, 185e3396b8bSCarl Huang 186e3396b8bSCarl Huang /* CE8: target autonomous hif_memcpy */ 187e3396b8bSCarl Huang { 188e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 189e3396b8bSCarl Huang .src_nentries = 0, 190e3396b8bSCarl Huang .src_sz_max = 0, 191e3396b8bSCarl Huang .dest_nentries = 0, 192e3396b8bSCarl Huang }, 193e3396b8bSCarl Huang 194e3396b8bSCarl Huang }; 195e3396b8bSCarl Huang 1966289ac2bSKarthikeyan Periyasamy const struct ce_attr ath11k_host_ce_config_qcn9074[] = { 1976289ac2bSKarthikeyan Periyasamy /* CE0: host->target HTC control and raw streams */ 1986289ac2bSKarthikeyan Periyasamy { 1996289ac2bSKarthikeyan Periyasamy .flags = CE_ATTR_FLAGS, 2006289ac2bSKarthikeyan Periyasamy .src_nentries = 16, 2016289ac2bSKarthikeyan Periyasamy .src_sz_max = 2048, 2026289ac2bSKarthikeyan Periyasamy .dest_nentries = 0, 2036289ac2bSKarthikeyan Periyasamy }, 2046289ac2bSKarthikeyan Periyasamy 2056289ac2bSKarthikeyan Periyasamy /* CE1: target->host HTT + HTC control */ 2066289ac2bSKarthikeyan Periyasamy { 2076289ac2bSKarthikeyan Periyasamy .flags = CE_ATTR_FLAGS, 2086289ac2bSKarthikeyan Periyasamy .src_nentries = 0, 2096289ac2bSKarthikeyan Periyasamy .src_sz_max = 2048, 2106289ac2bSKarthikeyan Periyasamy .dest_nentries = 512, 2116289ac2bSKarthikeyan Periyasamy .recv_cb = ath11k_htc_rx_completion_handler, 2126289ac2bSKarthikeyan Periyasamy }, 2136289ac2bSKarthikeyan Periyasamy 2146289ac2bSKarthikeyan Periyasamy /* CE2: target->host WMI */ 2156289ac2bSKarthikeyan Periyasamy { 2166289ac2bSKarthikeyan Periyasamy .flags = CE_ATTR_FLAGS, 2176289ac2bSKarthikeyan Periyasamy .src_nentries = 0, 2186289ac2bSKarthikeyan Periyasamy .src_sz_max = 2048, 2196289ac2bSKarthikeyan Periyasamy .dest_nentries = 32, 2206289ac2bSKarthikeyan Periyasamy .recv_cb = ath11k_htc_rx_completion_handler, 2216289ac2bSKarthikeyan Periyasamy }, 2226289ac2bSKarthikeyan Periyasamy 2236289ac2bSKarthikeyan Periyasamy /* CE3: host->target WMI (mac0) */ 2246289ac2bSKarthikeyan Periyasamy { 2256289ac2bSKarthikeyan Periyasamy .flags = CE_ATTR_FLAGS, 2266289ac2bSKarthikeyan Periyasamy .src_nentries = 32, 2276289ac2bSKarthikeyan Periyasamy .src_sz_max = 2048, 2286289ac2bSKarthikeyan Periyasamy .dest_nentries = 0, 229*f951380aSP Praneesh .send_cb = ath11k_htc_tx_completion_handler, 2306289ac2bSKarthikeyan Periyasamy }, 2316289ac2bSKarthikeyan Periyasamy 2326289ac2bSKarthikeyan Periyasamy /* CE4: host->target HTT */ 2336289ac2bSKarthikeyan Periyasamy { 2346289ac2bSKarthikeyan Periyasamy .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 2356289ac2bSKarthikeyan Periyasamy .src_nentries = 2048, 2366289ac2bSKarthikeyan Periyasamy .src_sz_max = 256, 2376289ac2bSKarthikeyan Periyasamy .dest_nentries = 0, 2386289ac2bSKarthikeyan Periyasamy }, 2396289ac2bSKarthikeyan Periyasamy 2406289ac2bSKarthikeyan Periyasamy /* CE5: target->host pktlog */ 2416289ac2bSKarthikeyan Periyasamy { 2426289ac2bSKarthikeyan Periyasamy .flags = CE_ATTR_FLAGS, 2436289ac2bSKarthikeyan Periyasamy .src_nentries = 0, 2446289ac2bSKarthikeyan Periyasamy .src_sz_max = 2048, 2456289ac2bSKarthikeyan Periyasamy .dest_nentries = 512, 2466289ac2bSKarthikeyan Periyasamy .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, 2476289ac2bSKarthikeyan Periyasamy }, 2486289ac2bSKarthikeyan Periyasamy }; 2496289ac2bSKarthikeyan Periyasamy 2509b309970SCarl Huang static bool ath11k_ce_need_shadow_fix(int ce_id) 2519b309970SCarl Huang { 2529b309970SCarl Huang /* only ce4 needs shadow workaroud*/ 2539b309970SCarl Huang if (ce_id == 4) 2549b309970SCarl Huang return true; 2559b309970SCarl Huang return false; 2569b309970SCarl Huang } 2579b309970SCarl Huang 258d1b0c338SCarl Huang void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab) 2599b309970SCarl Huang { 2609b309970SCarl Huang int i; 2619b309970SCarl Huang 2629b309970SCarl Huang if (!ab->hw_params.supports_shadow_regs) 2639b309970SCarl Huang return; 2649b309970SCarl Huang 2659b309970SCarl Huang for (i = 0; i < ab->hw_params.ce_count; i++) 2669b309970SCarl Huang if (ath11k_ce_need_shadow_fix(i)) 2679b309970SCarl Huang ath11k_dp_shadow_stop_timer(ab, &ab->ce.hp_timer[i]); 2689b309970SCarl Huang } 2699b309970SCarl Huang 270d5c65159SKalle Valo static int ath11k_ce_rx_buf_enqueue_pipe(struct ath11k_ce_pipe *pipe, 271d5c65159SKalle Valo struct sk_buff *skb, dma_addr_t paddr) 272d5c65159SKalle Valo { 273d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 274d5c65159SKalle Valo struct ath11k_ce_ring *ring = pipe->dest_ring; 275d5c65159SKalle Valo struct hal_srng *srng; 276d5c65159SKalle Valo unsigned int write_index; 277d5c65159SKalle Valo unsigned int nentries_mask = ring->nentries_mask; 278d5c65159SKalle Valo u32 *desc; 279d5c65159SKalle Valo int ret; 280d5c65159SKalle Valo 281d5c65159SKalle Valo lockdep_assert_held(&ab->ce.ce_lock); 282d5c65159SKalle Valo 283d5c65159SKalle Valo write_index = ring->write_index; 284d5c65159SKalle Valo 285d5c65159SKalle Valo srng = &ab->hal.srng_list[ring->hal_ring_id]; 286d5c65159SKalle Valo 287d5c65159SKalle Valo spin_lock_bh(&srng->lock); 288d5c65159SKalle Valo 289d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 290d5c65159SKalle Valo 291d5c65159SKalle Valo if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) { 292d5c65159SKalle Valo ret = -ENOSPC; 293d5c65159SKalle Valo goto exit; 294d5c65159SKalle Valo } 295d5c65159SKalle Valo 296d5c65159SKalle Valo desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 297d5c65159SKalle Valo if (!desc) { 298d5c65159SKalle Valo ret = -ENOSPC; 299d5c65159SKalle Valo goto exit; 300d5c65159SKalle Valo } 301d5c65159SKalle Valo 302d5c65159SKalle Valo ath11k_hal_ce_dst_set_desc(desc, paddr); 303d5c65159SKalle Valo 304d5c65159SKalle Valo ring->skb[write_index] = skb; 305d5c65159SKalle Valo write_index = CE_RING_IDX_INCR(nentries_mask, write_index); 306d5c65159SKalle Valo ring->write_index = write_index; 307d5c65159SKalle Valo 308d5c65159SKalle Valo pipe->rx_buf_needed--; 309d5c65159SKalle Valo 310d5c65159SKalle Valo ret = 0; 311d5c65159SKalle Valo exit: 312d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 313d5c65159SKalle Valo 314d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 315d5c65159SKalle Valo 316d5c65159SKalle Valo return ret; 317d5c65159SKalle Valo } 318d5c65159SKalle Valo 319d5c65159SKalle Valo static int ath11k_ce_rx_post_pipe(struct ath11k_ce_pipe *pipe) 320d5c65159SKalle Valo { 321d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 322d5c65159SKalle Valo struct sk_buff *skb; 323d5c65159SKalle Valo dma_addr_t paddr; 324d5c65159SKalle Valo int ret = 0; 325d5c65159SKalle Valo 326d5c65159SKalle Valo if (!(pipe->dest_ring || pipe->status_ring)) 327d5c65159SKalle Valo return 0; 328d5c65159SKalle Valo 329d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 330d5c65159SKalle Valo while (pipe->rx_buf_needed) { 331d5c65159SKalle Valo skb = dev_alloc_skb(pipe->buf_sz); 332d5c65159SKalle Valo if (!skb) { 333d5c65159SKalle Valo ret = -ENOMEM; 334d5c65159SKalle Valo goto exit; 335d5c65159SKalle Valo } 336d5c65159SKalle Valo 337d5c65159SKalle Valo WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4)); 338d5c65159SKalle Valo 339d5c65159SKalle Valo paddr = dma_map_single(ab->dev, skb->data, 340d5c65159SKalle Valo skb->len + skb_tailroom(skb), 341d5c65159SKalle Valo DMA_FROM_DEVICE); 342d5c65159SKalle Valo if (unlikely(dma_mapping_error(ab->dev, paddr))) { 343d5c65159SKalle Valo ath11k_warn(ab, "failed to dma map ce rx buf\n"); 344d5c65159SKalle Valo dev_kfree_skb_any(skb); 345d5c65159SKalle Valo ret = -EIO; 346d5c65159SKalle Valo goto exit; 347d5c65159SKalle Valo } 348d5c65159SKalle Valo 349d5c65159SKalle Valo ATH11K_SKB_RXCB(skb)->paddr = paddr; 350d5c65159SKalle Valo 351d5c65159SKalle Valo ret = ath11k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr); 352d5c65159SKalle Valo 353d5c65159SKalle Valo if (ret) { 354d5c65159SKalle Valo ath11k_warn(ab, "failed to enqueue rx buf: %d\n", ret); 355d5c65159SKalle Valo dma_unmap_single(ab->dev, paddr, 356d5c65159SKalle Valo skb->len + skb_tailroom(skb), 357d5c65159SKalle Valo DMA_FROM_DEVICE); 358d5c65159SKalle Valo dev_kfree_skb_any(skb); 359d5c65159SKalle Valo goto exit; 360d5c65159SKalle Valo } 361d5c65159SKalle Valo } 362d5c65159SKalle Valo 363d5c65159SKalle Valo exit: 364d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 365d5c65159SKalle Valo return ret; 366d5c65159SKalle Valo } 367d5c65159SKalle Valo 368d5c65159SKalle Valo static int ath11k_ce_completed_recv_next(struct ath11k_ce_pipe *pipe, 369d5c65159SKalle Valo struct sk_buff **skb, int *nbytes) 370d5c65159SKalle Valo { 371d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 372d5c65159SKalle Valo struct hal_srng *srng; 373d5c65159SKalle Valo unsigned int sw_index; 374d5c65159SKalle Valo unsigned int nentries_mask; 375d5c65159SKalle Valo u32 *desc; 376d5c65159SKalle Valo int ret = 0; 377d5c65159SKalle Valo 378d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 379d5c65159SKalle Valo 380d5c65159SKalle Valo sw_index = pipe->dest_ring->sw_index; 381d5c65159SKalle Valo nentries_mask = pipe->dest_ring->nentries_mask; 382d5c65159SKalle Valo 383d5c65159SKalle Valo srng = &ab->hal.srng_list[pipe->status_ring->hal_ring_id]; 384d5c65159SKalle Valo 385d5c65159SKalle Valo spin_lock_bh(&srng->lock); 386d5c65159SKalle Valo 387d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 388d5c65159SKalle Valo 389d5c65159SKalle Valo desc = ath11k_hal_srng_dst_get_next_entry(ab, srng); 390d5c65159SKalle Valo if (!desc) { 391d5c65159SKalle Valo ret = -EIO; 392d5c65159SKalle Valo goto err; 393d5c65159SKalle Valo } 394d5c65159SKalle Valo 395d5c65159SKalle Valo *nbytes = ath11k_hal_ce_dst_status_get_length(desc); 396d5c65159SKalle Valo if (*nbytes == 0) { 397d5c65159SKalle Valo ret = -EIO; 398d5c65159SKalle Valo goto err; 399d5c65159SKalle Valo } 400d5c65159SKalle Valo 401d5c65159SKalle Valo *skb = pipe->dest_ring->skb[sw_index]; 402d5c65159SKalle Valo pipe->dest_ring->skb[sw_index] = NULL; 403d5c65159SKalle Valo 404d5c65159SKalle Valo sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); 405d5c65159SKalle Valo pipe->dest_ring->sw_index = sw_index; 406d5c65159SKalle Valo 407d5c65159SKalle Valo pipe->rx_buf_needed++; 408d5c65159SKalle Valo err: 409d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 410d5c65159SKalle Valo 411d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 412d5c65159SKalle Valo 413d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 414d5c65159SKalle Valo 415d5c65159SKalle Valo return ret; 416d5c65159SKalle Valo } 417d5c65159SKalle Valo 418d5c65159SKalle Valo static void ath11k_ce_recv_process_cb(struct ath11k_ce_pipe *pipe) 419d5c65159SKalle Valo { 420d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 421d5c65159SKalle Valo struct sk_buff *skb; 422d5c65159SKalle Valo struct sk_buff_head list; 423d5c65159SKalle Valo unsigned int nbytes, max_nbytes; 424d5c65159SKalle Valo int ret; 425d5c65159SKalle Valo 426d5c65159SKalle Valo __skb_queue_head_init(&list); 427d5c65159SKalle Valo while (ath11k_ce_completed_recv_next(pipe, &skb, &nbytes) == 0) { 428d5c65159SKalle Valo max_nbytes = skb->len + skb_tailroom(skb); 429d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 430d5c65159SKalle Valo max_nbytes, DMA_FROM_DEVICE); 431d5c65159SKalle Valo 432d5c65159SKalle Valo if (unlikely(max_nbytes < nbytes)) { 433d5c65159SKalle Valo ath11k_warn(ab, "rxed more than expected (nbytes %d, max %d)", 434d5c65159SKalle Valo nbytes, max_nbytes); 435d5c65159SKalle Valo dev_kfree_skb_any(skb); 436d5c65159SKalle Valo continue; 437d5c65159SKalle Valo } 438d5c65159SKalle Valo 439d5c65159SKalle Valo skb_put(skb, nbytes); 440d5c65159SKalle Valo __skb_queue_tail(&list, skb); 441d5c65159SKalle Valo } 442d5c65159SKalle Valo 443d5c65159SKalle Valo while ((skb = __skb_dequeue(&list))) { 444d5c65159SKalle Valo ath11k_dbg(ab, ATH11K_DBG_AHB, "rx ce pipe %d len %d\n", 445d5c65159SKalle Valo pipe->pipe_num, skb->len); 446d5c65159SKalle Valo pipe->recv_cb(ab, skb); 447d5c65159SKalle Valo } 448d5c65159SKalle Valo 449d5c65159SKalle Valo ret = ath11k_ce_rx_post_pipe(pipe); 450d5c65159SKalle Valo if (ret && ret != -ENOSPC) { 451d5c65159SKalle Valo ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n", 452d5c65159SKalle Valo pipe->pipe_num, ret); 453d5c65159SKalle Valo mod_timer(&ab->rx_replenish_retry, 454d5c65159SKalle Valo jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES); 455d5c65159SKalle Valo } 456d5c65159SKalle Valo } 457d5c65159SKalle Valo 458d5c65159SKalle Valo static struct sk_buff *ath11k_ce_completed_send_next(struct ath11k_ce_pipe *pipe) 459d5c65159SKalle Valo { 460d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 461d5c65159SKalle Valo struct hal_srng *srng; 462d5c65159SKalle Valo unsigned int sw_index; 463d5c65159SKalle Valo unsigned int nentries_mask; 464d5c65159SKalle Valo struct sk_buff *skb; 465d5c65159SKalle Valo u32 *desc; 466d5c65159SKalle Valo 467d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 468d5c65159SKalle Valo 469d5c65159SKalle Valo sw_index = pipe->src_ring->sw_index; 470d5c65159SKalle Valo nentries_mask = pipe->src_ring->nentries_mask; 471d5c65159SKalle Valo 472d5c65159SKalle Valo srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id]; 473d5c65159SKalle Valo 474d5c65159SKalle Valo spin_lock_bh(&srng->lock); 475d5c65159SKalle Valo 476d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 477d5c65159SKalle Valo 478d5c65159SKalle Valo desc = ath11k_hal_srng_src_reap_next(ab, srng); 479d5c65159SKalle Valo if (!desc) { 480d5c65159SKalle Valo skb = ERR_PTR(-EIO); 481d5c65159SKalle Valo goto err_unlock; 482d5c65159SKalle Valo } 483d5c65159SKalle Valo 484d5c65159SKalle Valo skb = pipe->src_ring->skb[sw_index]; 485d5c65159SKalle Valo 486d5c65159SKalle Valo pipe->src_ring->skb[sw_index] = NULL; 487d5c65159SKalle Valo 488d5c65159SKalle Valo sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); 489d5c65159SKalle Valo pipe->src_ring->sw_index = sw_index; 490d5c65159SKalle Valo 491d5c65159SKalle Valo err_unlock: 492d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 493d5c65159SKalle Valo 494d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 495d5c65159SKalle Valo 496d5c65159SKalle Valo return skb; 497d5c65159SKalle Valo } 498d5c65159SKalle Valo 499*f951380aSP Praneesh static void ath11k_ce_tx_process_cb(struct ath11k_ce_pipe *pipe) 500d5c65159SKalle Valo { 501d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 502d5c65159SKalle Valo struct sk_buff *skb; 503*f951380aSP Praneesh struct sk_buff_head list; 504d5c65159SKalle Valo 505*f951380aSP Praneesh __skb_queue_head_init(&list); 506d5c65159SKalle Valo while (!IS_ERR(skb = ath11k_ce_completed_send_next(pipe))) { 507d5c65159SKalle Valo if (!skb) 508d5c65159SKalle Valo continue; 509d5c65159SKalle Valo 510d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len, 511d5c65159SKalle Valo DMA_TO_DEVICE); 512*f951380aSP Praneesh 513*f951380aSP Praneesh if ((!pipe->send_cb) || ab->hw_params.credit_flow) { 514d5c65159SKalle Valo dev_kfree_skb_any(skb); 515*f951380aSP Praneesh continue; 516*f951380aSP Praneesh } 517*f951380aSP Praneesh 518*f951380aSP Praneesh __skb_queue_tail(&list, skb); 519*f951380aSP Praneesh } 520*f951380aSP Praneesh 521*f951380aSP Praneesh while ((skb = __skb_dequeue(&list))) { 522*f951380aSP Praneesh ath11k_dbg(ab, ATH11K_DBG_AHB, "tx ce pipe %d len %d\n", 523*f951380aSP Praneesh pipe->pipe_num, skb->len); 524*f951380aSP Praneesh pipe->send_cb(ab, skb); 525d5c65159SKalle Valo } 526d5c65159SKalle Valo } 527d5c65159SKalle Valo 528c4eacabeSGovind Singh static void ath11k_ce_srng_msi_ring_params_setup(struct ath11k_base *ab, u32 ce_id, 529c4eacabeSGovind Singh struct hal_srng_params *ring_params) 530c4eacabeSGovind Singh { 531c4eacabeSGovind Singh u32 msi_data_start; 5326289ac2bSKarthikeyan Periyasamy u32 msi_data_count, msi_data_idx; 533c4eacabeSGovind Singh u32 msi_irq_start; 534c4eacabeSGovind Singh u32 addr_lo; 535c4eacabeSGovind Singh u32 addr_hi; 536c4eacabeSGovind Singh int ret; 537c4eacabeSGovind Singh 538c4eacabeSGovind Singh ret = ath11k_get_user_msi_vector(ab, "CE", 539c4eacabeSGovind Singh &msi_data_count, &msi_data_start, 540c4eacabeSGovind Singh &msi_irq_start); 541c4eacabeSGovind Singh 542c4eacabeSGovind Singh if (ret) 543c4eacabeSGovind Singh return; 544c4eacabeSGovind Singh 545c4eacabeSGovind Singh ath11k_get_msi_address(ab, &addr_lo, &addr_hi); 5466289ac2bSKarthikeyan Periyasamy ath11k_get_ce_msi_idx(ab, ce_id, &msi_data_idx); 547c4eacabeSGovind Singh 548c4eacabeSGovind Singh ring_params->msi_addr = addr_lo; 549c4eacabeSGovind Singh ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32); 5506289ac2bSKarthikeyan Periyasamy ring_params->msi_data = (msi_data_idx % msi_data_count) + msi_data_start; 551c4eacabeSGovind Singh ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR; 552c4eacabeSGovind Singh } 553c4eacabeSGovind Singh 554d5c65159SKalle Valo static int ath11k_ce_init_ring(struct ath11k_base *ab, 555d5c65159SKalle Valo struct ath11k_ce_ring *ce_ring, 556d5c65159SKalle Valo int ce_id, enum hal_ring_type type) 557d5c65159SKalle Valo { 558d5c65159SKalle Valo struct hal_srng_params params = { 0 }; 559d5c65159SKalle Valo int ret; 560d5c65159SKalle Valo 561d5c65159SKalle Valo params.ring_base_paddr = ce_ring->base_addr_ce_space; 562d5c65159SKalle Valo params.ring_base_vaddr = ce_ring->base_addr_owner_space; 563d5c65159SKalle Valo params.num_entries = ce_ring->nentries; 564d5c65159SKalle Valo 5651a05ed37SCarl Huang if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) 5661a05ed37SCarl Huang ath11k_ce_srng_msi_ring_params_setup(ab, ce_id, ¶ms); 5671a05ed37SCarl Huang 568d5c65159SKalle Valo switch (type) { 569d5c65159SKalle Valo case HAL_CE_SRC: 5706e5e9f59SKalle Valo if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) 571d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 1; 572d5c65159SKalle Valo break; 573d5c65159SKalle Valo case HAL_CE_DST: 5746e5e9f59SKalle Valo params.max_buffer_len = ab->hw_params.host_ce_config[ce_id].src_sz_max; 5756e5e9f59SKalle Valo if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { 576d5c65159SKalle Valo params.intr_timer_thres_us = 1024; 577d5c65159SKalle Valo params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; 578d5c65159SKalle Valo params.low_threshold = ce_ring->nentries - 3; 579d5c65159SKalle Valo } 580d5c65159SKalle Valo break; 581d5c65159SKalle Valo case HAL_CE_DST_STATUS: 5826e5e9f59SKalle Valo if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { 583d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 1; 584d5c65159SKalle Valo params.intr_timer_thres_us = 0x1000; 585d5c65159SKalle Valo } 586d5c65159SKalle Valo break; 587d5c65159SKalle Valo default: 588d5c65159SKalle Valo ath11k_warn(ab, "Invalid CE ring type %d\n", type); 589d5c65159SKalle Valo return -EINVAL; 590d5c65159SKalle Valo } 591d5c65159SKalle Valo 592d5c65159SKalle Valo /* TODO: Init other params needed by HAL to init the ring */ 593d5c65159SKalle Valo 594d5c65159SKalle Valo ret = ath11k_hal_srng_setup(ab, type, ce_id, 0, ¶ms); 595d5c65159SKalle Valo if (ret < 0) { 596d5c65159SKalle Valo ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n", 597d5c65159SKalle Valo ret, ce_id); 598d5c65159SKalle Valo return ret; 599d5c65159SKalle Valo } 600c4eacabeSGovind Singh 601d5c65159SKalle Valo ce_ring->hal_ring_id = ret; 602d5c65159SKalle Valo 6039b309970SCarl Huang if (ab->hw_params.supports_shadow_regs && 6049b309970SCarl Huang ath11k_ce_need_shadow_fix(ce_id)) 6059b309970SCarl Huang ath11k_dp_shadow_init_timer(ab, &ab->ce.hp_timer[ce_id], 6069b309970SCarl Huang ATH11K_SHADOW_CTRL_TIMER_INTERVAL, 6079b309970SCarl Huang ce_ring->hal_ring_id); 6089b309970SCarl Huang 609d5c65159SKalle Valo return 0; 610d5c65159SKalle Valo } 611d5c65159SKalle Valo 612d5c65159SKalle Valo static struct ath11k_ce_ring * 613d5c65159SKalle Valo ath11k_ce_alloc_ring(struct ath11k_base *ab, int nentries, int desc_sz) 614d5c65159SKalle Valo { 615d5c65159SKalle Valo struct ath11k_ce_ring *ce_ring; 616d5c65159SKalle Valo dma_addr_t base_addr; 617d5c65159SKalle Valo 618d5c65159SKalle Valo ce_ring = kzalloc(struct_size(ce_ring, skb, nentries), GFP_KERNEL); 619d5c65159SKalle Valo if (ce_ring == NULL) 620d5c65159SKalle Valo return ERR_PTR(-ENOMEM); 621d5c65159SKalle Valo 622d5c65159SKalle Valo ce_ring->nentries = nentries; 623d5c65159SKalle Valo ce_ring->nentries_mask = nentries - 1; 624d5c65159SKalle Valo 625d5c65159SKalle Valo /* Legacy platforms that do not support cache 626d5c65159SKalle Valo * coherent DMA are unsupported 627d5c65159SKalle Valo */ 628d5c65159SKalle Valo ce_ring->base_addr_owner_space_unaligned = 629d5c65159SKalle Valo dma_alloc_coherent(ab->dev, 630d5c65159SKalle Valo nentries * desc_sz + CE_DESC_RING_ALIGN, 631d5c65159SKalle Valo &base_addr, GFP_KERNEL); 632d5c65159SKalle Valo if (!ce_ring->base_addr_owner_space_unaligned) { 633d5c65159SKalle Valo kfree(ce_ring); 634d5c65159SKalle Valo return ERR_PTR(-ENOMEM); 635d5c65159SKalle Valo } 636d5c65159SKalle Valo 637d5c65159SKalle Valo ce_ring->base_addr_ce_space_unaligned = base_addr; 638d5c65159SKalle Valo 639d5c65159SKalle Valo ce_ring->base_addr_owner_space = PTR_ALIGN( 640d5c65159SKalle Valo ce_ring->base_addr_owner_space_unaligned, 641d5c65159SKalle Valo CE_DESC_RING_ALIGN); 642d5c65159SKalle Valo ce_ring->base_addr_ce_space = ALIGN( 643d5c65159SKalle Valo ce_ring->base_addr_ce_space_unaligned, 644d5c65159SKalle Valo CE_DESC_RING_ALIGN); 645d5c65159SKalle Valo 646d5c65159SKalle Valo return ce_ring; 647d5c65159SKalle Valo } 648d5c65159SKalle Valo 649d5c65159SKalle Valo static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) 650d5c65159SKalle Valo { 651d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; 6526e5e9f59SKalle Valo const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id]; 653c76fa846SDan Carpenter struct ath11k_ce_ring *ring; 654d5c65159SKalle Valo int nentries; 655d5c65159SKalle Valo int desc_sz; 656d5c65159SKalle Valo 657d5c65159SKalle Valo pipe->attr_flags = attr->flags; 658d5c65159SKalle Valo 659d5c65159SKalle Valo if (attr->src_nentries) { 660*f951380aSP Praneesh pipe->send_cb = attr->send_cb; 661d5c65159SKalle Valo nentries = roundup_pow_of_two(attr->src_nentries); 662d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); 663c76fa846SDan Carpenter ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 664c76fa846SDan Carpenter if (IS_ERR(ring)) 665c76fa846SDan Carpenter return PTR_ERR(ring); 666c76fa846SDan Carpenter pipe->src_ring = ring; 667d5c65159SKalle Valo } 668d5c65159SKalle Valo 669d5c65159SKalle Valo if (attr->dest_nentries) { 670d5c65159SKalle Valo pipe->recv_cb = attr->recv_cb; 671d5c65159SKalle Valo nentries = roundup_pow_of_two(attr->dest_nentries); 672d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); 673c76fa846SDan Carpenter ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 674c76fa846SDan Carpenter if (IS_ERR(ring)) 675c76fa846SDan Carpenter return PTR_ERR(ring); 676c76fa846SDan Carpenter pipe->dest_ring = ring; 677d5c65159SKalle Valo 678d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); 679c76fa846SDan Carpenter ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 680c76fa846SDan Carpenter if (IS_ERR(ring)) 681c76fa846SDan Carpenter return PTR_ERR(ring); 682c76fa846SDan Carpenter pipe->status_ring = ring; 683d5c65159SKalle Valo } 684d5c65159SKalle Valo 685d5c65159SKalle Valo return 0; 686d5c65159SKalle Valo } 687d5c65159SKalle Valo 688d5c65159SKalle Valo void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id) 689d5c65159SKalle Valo { 690d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; 691*f951380aSP Praneesh const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id]; 692d5c65159SKalle Valo 693*f951380aSP Praneesh if (attr->src_nentries) 694*f951380aSP Praneesh ath11k_ce_tx_process_cb(pipe); 695d5c65159SKalle Valo 696d5c65159SKalle Valo if (pipe->recv_cb) 697d5c65159SKalle Valo ath11k_ce_recv_process_cb(pipe); 698d5c65159SKalle Valo } 699d5c65159SKalle Valo 700d5c65159SKalle Valo void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id) 701d5c65159SKalle Valo { 702d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; 703*f951380aSP Praneesh const struct ce_attr *attr = &ab->hw_params.host_ce_config[pipe_id]; 704d5c65159SKalle Valo 705*f951380aSP Praneesh if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && attr->src_nentries) 706*f951380aSP Praneesh ath11k_ce_tx_process_cb(pipe); 707d5c65159SKalle Valo } 7082c3960c2SGovind Singh EXPORT_SYMBOL(ath11k_ce_per_engine_service); 709d5c65159SKalle Valo 710d5c65159SKalle Valo int ath11k_ce_send(struct ath11k_base *ab, struct sk_buff *skb, u8 pipe_id, 711d5c65159SKalle Valo u16 transfer_id) 712d5c65159SKalle Valo { 713d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; 714d5c65159SKalle Valo struct hal_srng *srng; 715d5c65159SKalle Valo u32 *desc; 716d5c65159SKalle Valo unsigned int write_index, sw_index; 717d5c65159SKalle Valo unsigned int nentries_mask; 718d5c65159SKalle Valo int ret = 0; 719d5c65159SKalle Valo u8 byte_swap_data = 0; 720d5c65159SKalle Valo int num_used; 721d5c65159SKalle Valo 722d5c65159SKalle Valo /* Check if some entries could be regained by handling tx completion if 723d5c65159SKalle Valo * the CE has interrupts disabled and the used entries is more than the 724d5c65159SKalle Valo * defined usage threshold. 725d5c65159SKalle Valo */ 726d5c65159SKalle Valo if (pipe->attr_flags & CE_ATTR_DIS_INTR) { 727d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 728d5c65159SKalle Valo write_index = pipe->src_ring->write_index; 729d5c65159SKalle Valo 730d5c65159SKalle Valo sw_index = pipe->src_ring->sw_index; 731d5c65159SKalle Valo 732d5c65159SKalle Valo if (write_index >= sw_index) 733d5c65159SKalle Valo num_used = write_index - sw_index; 734d5c65159SKalle Valo else 735d5c65159SKalle Valo num_used = pipe->src_ring->nentries - sw_index + 736d5c65159SKalle Valo write_index; 737d5c65159SKalle Valo 738d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 739d5c65159SKalle Valo 740d5c65159SKalle Valo if (num_used > ATH11K_CE_USAGE_THRESHOLD) 741d5c65159SKalle Valo ath11k_ce_poll_send_completed(ab, pipe->pipe_num); 742d5c65159SKalle Valo } 743d5c65159SKalle Valo 744d5c65159SKalle Valo if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)) 745d5c65159SKalle Valo return -ESHUTDOWN; 746d5c65159SKalle Valo 747d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 748d5c65159SKalle Valo 749d5c65159SKalle Valo write_index = pipe->src_ring->write_index; 750d5c65159SKalle Valo nentries_mask = pipe->src_ring->nentries_mask; 751d5c65159SKalle Valo 752d5c65159SKalle Valo srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id]; 753d5c65159SKalle Valo 754d5c65159SKalle Valo spin_lock_bh(&srng->lock); 755d5c65159SKalle Valo 756d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 757d5c65159SKalle Valo 758d5c65159SKalle Valo if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) { 759d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 760d5c65159SKalle Valo ret = -ENOBUFS; 761d5c65159SKalle Valo goto err_unlock; 762d5c65159SKalle Valo } 763d5c65159SKalle Valo 764d5c65159SKalle Valo desc = ath11k_hal_srng_src_get_next_reaped(ab, srng); 765d5c65159SKalle Valo if (!desc) { 766d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 767d5c65159SKalle Valo ret = -ENOBUFS; 768d5c65159SKalle Valo goto err_unlock; 769d5c65159SKalle Valo } 770d5c65159SKalle Valo 771d5c65159SKalle Valo if (pipe->attr_flags & CE_ATTR_BYTE_SWAP_DATA) 772d5c65159SKalle Valo byte_swap_data = 1; 773d5c65159SKalle Valo 774d5c65159SKalle Valo ath11k_hal_ce_src_set_desc(desc, ATH11K_SKB_CB(skb)->paddr, 775d5c65159SKalle Valo skb->len, transfer_id, byte_swap_data); 776d5c65159SKalle Valo 777d5c65159SKalle Valo pipe->src_ring->skb[write_index] = skb; 778d5c65159SKalle Valo pipe->src_ring->write_index = CE_RING_IDX_INCR(nentries_mask, 779d5c65159SKalle Valo write_index); 780d5c65159SKalle Valo 781d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 782d5c65159SKalle Valo 7839b309970SCarl Huang if (ath11k_ce_need_shadow_fix(pipe_id)) 7849b309970SCarl Huang ath11k_dp_shadow_start_timer(ab, srng, &ab->ce.hp_timer[pipe_id]); 7859b309970SCarl Huang 786d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 787d5c65159SKalle Valo 788d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 789d5c65159SKalle Valo 790d5c65159SKalle Valo return 0; 791d5c65159SKalle Valo 792d5c65159SKalle Valo err_unlock: 793d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 794d5c65159SKalle Valo 795d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 796d5c65159SKalle Valo 797d5c65159SKalle Valo return ret; 798d5c65159SKalle Valo } 799d5c65159SKalle Valo 800d5c65159SKalle Valo static void ath11k_ce_rx_pipe_cleanup(struct ath11k_ce_pipe *pipe) 801d5c65159SKalle Valo { 802d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 803d5c65159SKalle Valo struct ath11k_ce_ring *ring = pipe->dest_ring; 804d5c65159SKalle Valo struct sk_buff *skb; 805d5c65159SKalle Valo int i; 806d5c65159SKalle Valo 807d5c65159SKalle Valo if (!(ring && pipe->buf_sz)) 808d5c65159SKalle Valo return; 809d5c65159SKalle Valo 810d5c65159SKalle Valo for (i = 0; i < ring->nentries; i++) { 811d5c65159SKalle Valo skb = ring->skb[i]; 812d5c65159SKalle Valo if (!skb) 813d5c65159SKalle Valo continue; 814d5c65159SKalle Valo 815d5c65159SKalle Valo ring->skb[i] = NULL; 816d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 817d5c65159SKalle Valo skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); 818d5c65159SKalle Valo dev_kfree_skb_any(skb); 819d5c65159SKalle Valo } 820d5c65159SKalle Valo } 821d5c65159SKalle Valo 822e838c14aSCarl Huang static void ath11k_ce_shadow_config(struct ath11k_base *ab) 823e838c14aSCarl Huang { 824e838c14aSCarl Huang int i; 825e838c14aSCarl Huang 826e838c14aSCarl Huang for (i = 0; i < ab->hw_params.ce_count; i++) { 827e838c14aSCarl Huang if (ab->hw_params.host_ce_config[i].src_nentries) 828e838c14aSCarl Huang ath11k_hal_srng_update_shadow_config(ab, 829e838c14aSCarl Huang HAL_CE_SRC, i); 830e838c14aSCarl Huang 831e838c14aSCarl Huang if (ab->hw_params.host_ce_config[i].dest_nentries) { 832e838c14aSCarl Huang ath11k_hal_srng_update_shadow_config(ab, 833e838c14aSCarl Huang HAL_CE_DST, i); 834e838c14aSCarl Huang 835e838c14aSCarl Huang ath11k_hal_srng_update_shadow_config(ab, 836e838c14aSCarl Huang HAL_CE_DST_STATUS, i); 837e838c14aSCarl Huang } 838e838c14aSCarl Huang } 839e838c14aSCarl Huang } 840e838c14aSCarl Huang 841e838c14aSCarl Huang void ath11k_ce_get_shadow_config(struct ath11k_base *ab, 842e838c14aSCarl Huang u32 **shadow_cfg, u32 *shadow_cfg_len) 843e838c14aSCarl Huang { 844e838c14aSCarl Huang if (!ab->hw_params.supports_shadow_regs) 845e838c14aSCarl Huang return; 846e838c14aSCarl Huang 847e838c14aSCarl Huang ath11k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len); 848e838c14aSCarl Huang 849e838c14aSCarl Huang /* shadow is already configured */ 850e838c14aSCarl Huang if (*shadow_cfg_len) 851e838c14aSCarl Huang return; 852e838c14aSCarl Huang 853e838c14aSCarl Huang /* shadow isn't configured yet, configure now. 854e838c14aSCarl Huang * non-CE srngs are configured firstly, then 855e838c14aSCarl Huang * all CE srngs. 856e838c14aSCarl Huang */ 857e838c14aSCarl Huang ath11k_hal_srng_shadow_config(ab); 858e838c14aSCarl Huang ath11k_ce_shadow_config(ab); 859e838c14aSCarl Huang 860e838c14aSCarl Huang /* get the shadow configuration */ 861e838c14aSCarl Huang ath11k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len); 862e838c14aSCarl Huang } 863e838c14aSCarl Huang EXPORT_SYMBOL(ath11k_ce_get_shadow_config); 864e838c14aSCarl Huang 865d5c65159SKalle Valo void ath11k_ce_cleanup_pipes(struct ath11k_base *ab) 866d5c65159SKalle Valo { 867d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 868d5c65159SKalle Valo int pipe_num; 869d5c65159SKalle Valo 8709b309970SCarl Huang ath11k_ce_stop_shadow_timers(ab); 8719b309970SCarl Huang 872d9d4b5f3SKalle Valo for (pipe_num = 0; pipe_num < ab->hw_params.ce_count; pipe_num++) { 873d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[pipe_num]; 874d5c65159SKalle Valo ath11k_ce_rx_pipe_cleanup(pipe); 875d5c65159SKalle Valo 876d5c65159SKalle Valo /* Cleanup any src CE's which have interrupts disabled */ 877d5c65159SKalle Valo ath11k_ce_poll_send_completed(ab, pipe_num); 878d5c65159SKalle Valo 879d5c65159SKalle Valo /* NOTE: Should we also clean up tx buffer in all pipes? */ 880d5c65159SKalle Valo } 881d5c65159SKalle Valo } 8827f4beda2SGovind Singh EXPORT_SYMBOL(ath11k_ce_cleanup_pipes); 883d5c65159SKalle Valo 884d5c65159SKalle Valo void ath11k_ce_rx_post_buf(struct ath11k_base *ab) 885d5c65159SKalle Valo { 886d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 887d5c65159SKalle Valo int i; 888d5c65159SKalle Valo int ret; 889d5c65159SKalle Valo 890d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 891d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 892d5c65159SKalle Valo ret = ath11k_ce_rx_post_pipe(pipe); 893d5c65159SKalle Valo if (ret) { 894d5c65159SKalle Valo if (ret == -ENOSPC) 895d5c65159SKalle Valo continue; 896d5c65159SKalle Valo 897d5c65159SKalle Valo ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n", 898d5c65159SKalle Valo i, ret); 899d5c65159SKalle Valo mod_timer(&ab->rx_replenish_retry, 900d5c65159SKalle Valo jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES); 901d5c65159SKalle Valo 902d5c65159SKalle Valo return; 903d5c65159SKalle Valo } 904d5c65159SKalle Valo } 905d5c65159SKalle Valo } 9062c3960c2SGovind Singh EXPORT_SYMBOL(ath11k_ce_rx_post_buf); 907d5c65159SKalle Valo 908d5c65159SKalle Valo void ath11k_ce_rx_replenish_retry(struct timer_list *t) 909d5c65159SKalle Valo { 910d5c65159SKalle Valo struct ath11k_base *ab = from_timer(ab, t, rx_replenish_retry); 911d5c65159SKalle Valo 912d5c65159SKalle Valo ath11k_ce_rx_post_buf(ab); 913d5c65159SKalle Valo } 914d5c65159SKalle Valo 915d5c65159SKalle Valo int ath11k_ce_init_pipes(struct ath11k_base *ab) 916d5c65159SKalle Valo { 917d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 918d5c65159SKalle Valo int i; 919d5c65159SKalle Valo int ret; 920d5c65159SKalle Valo 921e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &ab->qmi.ce_cfg.shadow_reg_v2, 922e838c14aSCarl Huang &ab->qmi.ce_cfg.shadow_reg_v2_len); 923e838c14aSCarl Huang 924d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 925d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 926d5c65159SKalle Valo 927d5c65159SKalle Valo if (pipe->src_ring) { 928d5c65159SKalle Valo ret = ath11k_ce_init_ring(ab, pipe->src_ring, i, 929d5c65159SKalle Valo HAL_CE_SRC); 930d5c65159SKalle Valo if (ret) { 931d5c65159SKalle Valo ath11k_warn(ab, "failed to init src ring: %d\n", 932d5c65159SKalle Valo ret); 933d5c65159SKalle Valo /* Should we clear any partial init */ 934d5c65159SKalle Valo return ret; 935d5c65159SKalle Valo } 936d5c65159SKalle Valo 937d5c65159SKalle Valo pipe->src_ring->write_index = 0; 938d5c65159SKalle Valo pipe->src_ring->sw_index = 0; 939d5c65159SKalle Valo } 940d5c65159SKalle Valo 941d5c65159SKalle Valo if (pipe->dest_ring) { 942d5c65159SKalle Valo ret = ath11k_ce_init_ring(ab, pipe->dest_ring, i, 943d5c65159SKalle Valo HAL_CE_DST); 944d5c65159SKalle Valo if (ret) { 945d5c65159SKalle Valo ath11k_warn(ab, "failed to init dest ring: %d\n", 946d5c65159SKalle Valo ret); 947d5c65159SKalle Valo /* Should we clear any partial init */ 948d5c65159SKalle Valo return ret; 949d5c65159SKalle Valo } 950d5c65159SKalle Valo 951d5c65159SKalle Valo pipe->rx_buf_needed = pipe->dest_ring->nentries ? 952d5c65159SKalle Valo pipe->dest_ring->nentries - 2 : 0; 953d5c65159SKalle Valo 954d5c65159SKalle Valo pipe->dest_ring->write_index = 0; 955d5c65159SKalle Valo pipe->dest_ring->sw_index = 0; 956d5c65159SKalle Valo } 957d5c65159SKalle Valo 958d5c65159SKalle Valo if (pipe->status_ring) { 959d5c65159SKalle Valo ret = ath11k_ce_init_ring(ab, pipe->status_ring, i, 960d5c65159SKalle Valo HAL_CE_DST_STATUS); 961d5c65159SKalle Valo if (ret) { 962d5c65159SKalle Valo ath11k_warn(ab, "failed to init dest status ing: %d\n", 963d5c65159SKalle Valo ret); 964d5c65159SKalle Valo /* Should we clear any partial init */ 965d5c65159SKalle Valo return ret; 966d5c65159SKalle Valo } 967d5c65159SKalle Valo 968d5c65159SKalle Valo pipe->status_ring->write_index = 0; 969d5c65159SKalle Valo pipe->status_ring->sw_index = 0; 970d5c65159SKalle Valo } 971d5c65159SKalle Valo } 972d5c65159SKalle Valo 973d5c65159SKalle Valo return 0; 974d5c65159SKalle Valo } 975d5c65159SKalle Valo 976d5c65159SKalle Valo void ath11k_ce_free_pipes(struct ath11k_base *ab) 977d5c65159SKalle Valo { 978d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 97931aeaf54SKarthikeyan Periyasamy struct ath11k_ce_ring *ce_ring; 980d5c65159SKalle Valo int desc_sz; 981d5c65159SKalle Valo int i; 982d5c65159SKalle Valo 983d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 984d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 985d5c65159SKalle Valo 9869b309970SCarl Huang if (ath11k_ce_need_shadow_fix(i)) 9879b309970SCarl Huang ath11k_dp_shadow_stop_timer(ab, &ab->ce.hp_timer[i]); 9889b309970SCarl Huang 989d5c65159SKalle Valo if (pipe->src_ring) { 990d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); 99131aeaf54SKarthikeyan Periyasamy ce_ring = pipe->src_ring; 992d5c65159SKalle Valo dma_free_coherent(ab->dev, 993d5c65159SKalle Valo pipe->src_ring->nentries * desc_sz + 994d5c65159SKalle Valo CE_DESC_RING_ALIGN, 99531aeaf54SKarthikeyan Periyasamy ce_ring->base_addr_owner_space_unaligned, 99631aeaf54SKarthikeyan Periyasamy ce_ring->base_addr_ce_space_unaligned); 997d5c65159SKalle Valo kfree(pipe->src_ring); 998d5c65159SKalle Valo pipe->src_ring = NULL; 999d5c65159SKalle Valo } 1000d5c65159SKalle Valo 1001d5c65159SKalle Valo if (pipe->dest_ring) { 1002d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); 100331aeaf54SKarthikeyan Periyasamy ce_ring = pipe->dest_ring; 1004d5c65159SKalle Valo dma_free_coherent(ab->dev, 1005d5c65159SKalle Valo pipe->dest_ring->nentries * desc_sz + 1006d5c65159SKalle Valo CE_DESC_RING_ALIGN, 100731aeaf54SKarthikeyan Periyasamy ce_ring->base_addr_owner_space_unaligned, 100831aeaf54SKarthikeyan Periyasamy ce_ring->base_addr_ce_space_unaligned); 1009d5c65159SKalle Valo kfree(pipe->dest_ring); 1010d5c65159SKalle Valo pipe->dest_ring = NULL; 1011d5c65159SKalle Valo } 1012d5c65159SKalle Valo 1013d5c65159SKalle Valo if (pipe->status_ring) { 1014d5c65159SKalle Valo desc_sz = 1015d5c65159SKalle Valo ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); 101631aeaf54SKarthikeyan Periyasamy ce_ring = pipe->status_ring; 1017d5c65159SKalle Valo dma_free_coherent(ab->dev, 1018d5c65159SKalle Valo pipe->status_ring->nentries * desc_sz + 1019d5c65159SKalle Valo CE_DESC_RING_ALIGN, 102031aeaf54SKarthikeyan Periyasamy ce_ring->base_addr_owner_space_unaligned, 102131aeaf54SKarthikeyan Periyasamy ce_ring->base_addr_ce_space_unaligned); 1022d5c65159SKalle Valo kfree(pipe->status_ring); 1023d5c65159SKalle Valo pipe->status_ring = NULL; 1024d5c65159SKalle Valo } 1025d5c65159SKalle Valo } 1026d5c65159SKalle Valo } 10276e0355afSGovind Singh EXPORT_SYMBOL(ath11k_ce_free_pipes); 1028d5c65159SKalle Valo 1029d5c65159SKalle Valo int ath11k_ce_alloc_pipes(struct ath11k_base *ab) 1030d5c65159SKalle Valo { 1031d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 1032d5c65159SKalle Valo int i; 1033d5c65159SKalle Valo int ret; 1034d5c65159SKalle Valo const struct ce_attr *attr; 1035d5c65159SKalle Valo 1036d5c65159SKalle Valo spin_lock_init(&ab->ce.ce_lock); 1037d5c65159SKalle Valo 1038d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 10396e5e9f59SKalle Valo attr = &ab->hw_params.host_ce_config[i]; 1040d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 1041d5c65159SKalle Valo pipe->pipe_num = i; 1042d5c65159SKalle Valo pipe->ab = ab; 1043d5c65159SKalle Valo pipe->buf_sz = attr->src_sz_max; 1044d5c65159SKalle Valo 1045d5c65159SKalle Valo ret = ath11k_ce_alloc_pipe(ab, i); 1046d5c65159SKalle Valo if (ret) { 1047d5c65159SKalle Valo /* Free any parial successful allocation */ 1048d5c65159SKalle Valo ath11k_ce_free_pipes(ab); 1049d5c65159SKalle Valo return ret; 1050d5c65159SKalle Valo } 1051d5c65159SKalle Valo } 1052d5c65159SKalle Valo 1053d5c65159SKalle Valo return 0; 1054d5c65159SKalle Valo } 10557f4beda2SGovind Singh EXPORT_SYMBOL(ath11k_ce_alloc_pipes); 1056d5c65159SKalle Valo 1057d5c65159SKalle Valo /* For Big Endian Host, Copy Engine byte_swap is enabled 1058d5c65159SKalle Valo * When Copy Engine does byte_swap, need to byte swap again for the 1059d5c65159SKalle Valo * Host to get/put buffer content in the correct byte order 1060d5c65159SKalle Valo */ 1061d5c65159SKalle Valo void ath11k_ce_byte_swap(void *mem, u32 len) 1062d5c65159SKalle Valo { 1063d5c65159SKalle Valo int i; 1064d5c65159SKalle Valo 1065d5c65159SKalle Valo if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) { 1066d5c65159SKalle Valo if (!mem) 1067d5c65159SKalle Valo return; 1068d5c65159SKalle Valo 1069d5c65159SKalle Valo for (i = 0; i < (len / 4); i++) { 1070d5c65159SKalle Valo *(u32 *)mem = swab32(*(u32 *)mem); 1071d5c65159SKalle Valo mem += 4; 1072d5c65159SKalle Valo } 1073d5c65159SKalle Valo } 1074d5c65159SKalle Valo } 1075d5c65159SKalle Valo 1076e3396b8bSCarl Huang int ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id) 1077d5c65159SKalle Valo { 1078d9d4b5f3SKalle Valo if (ce_id >= ab->hw_params.ce_count) 1079d5c65159SKalle Valo return -EINVAL; 1080d5c65159SKalle Valo 10816e5e9f59SKalle Valo return ab->hw_params.host_ce_config[ce_id].flags; 1082d5c65159SKalle Valo } 10836e0355afSGovind Singh EXPORT_SYMBOL(ath11k_ce_get_attr_flags); 1084