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, 17d5c65159SKalle Valo }, 18d5c65159SKalle Valo 19d5c65159SKalle Valo /* CE1: target->host HTT + HTC control */ 20d5c65159SKalle Valo { 21d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 22d5c65159SKalle Valo .src_nentries = 0, 23d5c65159SKalle Valo .src_sz_max = 2048, 24d5c65159SKalle Valo .dest_nentries = 512, 25d5c65159SKalle Valo .recv_cb = ath11k_htc_rx_completion_handler, 26d5c65159SKalle Valo }, 27d5c65159SKalle Valo 28d5c65159SKalle Valo /* CE2: target->host WMI */ 29d5c65159SKalle Valo { 30d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 31d5c65159SKalle Valo .src_nentries = 0, 32d5c65159SKalle Valo .src_sz_max = 2048, 33d5c65159SKalle Valo .dest_nentries = 512, 34d5c65159SKalle Valo .recv_cb = ath11k_htc_rx_completion_handler, 35d5c65159SKalle Valo }, 36d5c65159SKalle Valo 37d5c65159SKalle Valo /* CE3: host->target WMI (mac0) */ 38d5c65159SKalle Valo { 39d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 40d5c65159SKalle Valo .src_nentries = 32, 41d5c65159SKalle Valo .src_sz_max = 2048, 42d5c65159SKalle Valo .dest_nentries = 0, 43d5c65159SKalle Valo }, 44d5c65159SKalle Valo 45d5c65159SKalle Valo /* CE4: host->target HTT */ 46d5c65159SKalle Valo { 47d5c65159SKalle Valo .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 48d5c65159SKalle Valo .src_nentries = 2048, 49d5c65159SKalle Valo .src_sz_max = 256, 50d5c65159SKalle Valo .dest_nentries = 0, 51d5c65159SKalle Valo }, 52d5c65159SKalle Valo 53d5c65159SKalle Valo /* CE5: target->host pktlog */ 54d5c65159SKalle Valo { 55d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 56d5c65159SKalle Valo .src_nentries = 0, 57d5c65159SKalle Valo .src_sz_max = 2048, 58d5c65159SKalle Valo .dest_nentries = 512, 59d5c65159SKalle Valo .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, 60d5c65159SKalle Valo }, 61d5c65159SKalle Valo 62d5c65159SKalle Valo /* CE6: target autonomous hif_memcpy */ 63d5c65159SKalle Valo { 64d5c65159SKalle Valo .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 65d5c65159SKalle Valo .src_nentries = 0, 66d5c65159SKalle Valo .src_sz_max = 0, 67d5c65159SKalle Valo .dest_nentries = 0, 68d5c65159SKalle Valo }, 69d5c65159SKalle Valo 70d5c65159SKalle Valo /* CE7: host->target WMI (mac1) */ 71d5c65159SKalle Valo { 72d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 73d5c65159SKalle Valo .src_nentries = 32, 74d5c65159SKalle Valo .src_sz_max = 2048, 75d5c65159SKalle Valo .dest_nentries = 0, 76d5c65159SKalle Valo }, 77d5c65159SKalle Valo 78d5c65159SKalle Valo /* CE8: target autonomous hif_memcpy */ 79d5c65159SKalle Valo { 80d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 81d5c65159SKalle Valo .src_nentries = 0, 82d5c65159SKalle Valo .src_sz_max = 0, 83d5c65159SKalle Valo .dest_nentries = 0, 84d5c65159SKalle Valo }, 85d5c65159SKalle Valo 86d5c65159SKalle Valo /* CE9: host->target WMI (mac2) */ 87d5c65159SKalle Valo { 88d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 89d5c65159SKalle Valo .src_nentries = 32, 90d5c65159SKalle Valo .src_sz_max = 2048, 91d5c65159SKalle Valo .dest_nentries = 0, 92d5c65159SKalle Valo }, 93d5c65159SKalle Valo 94d5c65159SKalle Valo /* CE10: target->host HTT */ 95d5c65159SKalle Valo { 96d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 97d5c65159SKalle Valo .src_nentries = 0, 98d5c65159SKalle Valo .src_sz_max = 2048, 99d5c65159SKalle Valo .dest_nentries = 512, 100d5c65159SKalle Valo .recv_cb = ath11k_htc_rx_completion_handler, 101d5c65159SKalle Valo }, 102d5c65159SKalle Valo 103d5c65159SKalle Valo /* CE11: Not used */ 104d5c65159SKalle Valo { 105d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 106d5c65159SKalle Valo .src_nentries = 0, 107d5c65159SKalle Valo .src_sz_max = 0, 108d5c65159SKalle Valo .dest_nentries = 0, 109d5c65159SKalle Valo }, 110d5c65159SKalle Valo }; 111d5c65159SKalle Valo 112e3396b8bSCarl Huang const struct ce_attr ath11k_host_ce_config_qca6390[] = { 113e3396b8bSCarl Huang /* CE0: host->target HTC control and raw streams */ 114e3396b8bSCarl Huang { 115e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 116e3396b8bSCarl Huang .src_nentries = 16, 117e3396b8bSCarl Huang .src_sz_max = 2048, 118e3396b8bSCarl Huang .dest_nentries = 0, 119e3396b8bSCarl Huang }, 120e3396b8bSCarl Huang 121e3396b8bSCarl Huang /* CE1: target->host HTT + HTC control */ 122e3396b8bSCarl Huang { 123e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 124e3396b8bSCarl Huang .src_nentries = 0, 125e3396b8bSCarl Huang .src_sz_max = 2048, 126e3396b8bSCarl Huang .dest_nentries = 512, 127e3396b8bSCarl Huang .recv_cb = ath11k_htc_rx_completion_handler, 128e3396b8bSCarl Huang }, 129e3396b8bSCarl Huang 130e3396b8bSCarl Huang /* CE2: target->host WMI */ 131e3396b8bSCarl Huang { 132e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 133e3396b8bSCarl Huang .src_nentries = 0, 134e3396b8bSCarl Huang .src_sz_max = 2048, 135e3396b8bSCarl Huang .dest_nentries = 512, 136e3396b8bSCarl Huang .recv_cb = ath11k_htc_rx_completion_handler, 137e3396b8bSCarl Huang }, 138e3396b8bSCarl Huang 139e3396b8bSCarl Huang /* CE3: host->target WMI (mac0) */ 140e3396b8bSCarl Huang { 141e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 142e3396b8bSCarl Huang .src_nentries = 32, 143e3396b8bSCarl Huang .src_sz_max = 2048, 144e3396b8bSCarl Huang .dest_nentries = 0, 145e3396b8bSCarl Huang }, 146e3396b8bSCarl Huang 147e3396b8bSCarl Huang /* CE4: host->target HTT */ 148e3396b8bSCarl Huang { 149e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 150e3396b8bSCarl Huang .src_nentries = 2048, 151e3396b8bSCarl Huang .src_sz_max = 256, 152e3396b8bSCarl Huang .dest_nentries = 0, 153e3396b8bSCarl Huang }, 154e3396b8bSCarl Huang 155e3396b8bSCarl Huang /* CE5: target->host pktlog */ 156e3396b8bSCarl Huang { 157e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 158e3396b8bSCarl Huang .src_nentries = 0, 159e3396b8bSCarl Huang .src_sz_max = 2048, 160e3396b8bSCarl Huang .dest_nentries = 512, 161e3396b8bSCarl Huang .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, 162e3396b8bSCarl Huang }, 163e3396b8bSCarl Huang 164e3396b8bSCarl Huang /* CE6: target autonomous hif_memcpy */ 165e3396b8bSCarl Huang { 166e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 167e3396b8bSCarl Huang .src_nentries = 0, 168e3396b8bSCarl Huang .src_sz_max = 0, 169e3396b8bSCarl Huang .dest_nentries = 0, 170e3396b8bSCarl Huang }, 171e3396b8bSCarl Huang 172e3396b8bSCarl Huang /* CE7: host->target WMI (mac1) */ 173e3396b8bSCarl Huang { 174e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 175e3396b8bSCarl Huang .src_nentries = 32, 176e3396b8bSCarl Huang .src_sz_max = 2048, 177e3396b8bSCarl Huang .dest_nentries = 0, 178e3396b8bSCarl Huang }, 179e3396b8bSCarl Huang 180e3396b8bSCarl Huang /* CE8: target autonomous hif_memcpy */ 181e3396b8bSCarl Huang { 182e3396b8bSCarl Huang .flags = CE_ATTR_FLAGS, 183e3396b8bSCarl Huang .src_nentries = 0, 184e3396b8bSCarl Huang .src_sz_max = 0, 185e3396b8bSCarl Huang .dest_nentries = 0, 186e3396b8bSCarl Huang }, 187e3396b8bSCarl Huang 188e3396b8bSCarl Huang }; 189e3396b8bSCarl Huang 1909b309970SCarl Huang static bool ath11k_ce_need_shadow_fix(int ce_id) 1919b309970SCarl Huang { 1929b309970SCarl Huang /* only ce4 needs shadow workaroud*/ 1939b309970SCarl Huang if (ce_id == 4) 1949b309970SCarl Huang return true; 1959b309970SCarl Huang return false; 1969b309970SCarl Huang } 1979b309970SCarl Huang 198*d1b0c338SCarl Huang void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab) 1999b309970SCarl Huang { 2009b309970SCarl Huang int i; 2019b309970SCarl Huang 2029b309970SCarl Huang if (!ab->hw_params.supports_shadow_regs) 2039b309970SCarl Huang return; 2049b309970SCarl Huang 2059b309970SCarl Huang for (i = 0; i < ab->hw_params.ce_count; i++) 2069b309970SCarl Huang if (ath11k_ce_need_shadow_fix(i)) 2079b309970SCarl Huang ath11k_dp_shadow_stop_timer(ab, &ab->ce.hp_timer[i]); 2089b309970SCarl Huang } 2099b309970SCarl Huang 210d5c65159SKalle Valo static int ath11k_ce_rx_buf_enqueue_pipe(struct ath11k_ce_pipe *pipe, 211d5c65159SKalle Valo struct sk_buff *skb, dma_addr_t paddr) 212d5c65159SKalle Valo { 213d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 214d5c65159SKalle Valo struct ath11k_ce_ring *ring = pipe->dest_ring; 215d5c65159SKalle Valo struct hal_srng *srng; 216d5c65159SKalle Valo unsigned int write_index; 217d5c65159SKalle Valo unsigned int nentries_mask = ring->nentries_mask; 218d5c65159SKalle Valo u32 *desc; 219d5c65159SKalle Valo int ret; 220d5c65159SKalle Valo 221d5c65159SKalle Valo lockdep_assert_held(&ab->ce.ce_lock); 222d5c65159SKalle Valo 223d5c65159SKalle Valo write_index = ring->write_index; 224d5c65159SKalle Valo 225d5c65159SKalle Valo srng = &ab->hal.srng_list[ring->hal_ring_id]; 226d5c65159SKalle Valo 227d5c65159SKalle Valo spin_lock_bh(&srng->lock); 228d5c65159SKalle Valo 229d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 230d5c65159SKalle Valo 231d5c65159SKalle Valo if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) { 232d5c65159SKalle Valo ret = -ENOSPC; 233d5c65159SKalle Valo goto exit; 234d5c65159SKalle Valo } 235d5c65159SKalle Valo 236d5c65159SKalle Valo desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 237d5c65159SKalle Valo if (!desc) { 238d5c65159SKalle Valo ret = -ENOSPC; 239d5c65159SKalle Valo goto exit; 240d5c65159SKalle Valo } 241d5c65159SKalle Valo 242d5c65159SKalle Valo ath11k_hal_ce_dst_set_desc(desc, paddr); 243d5c65159SKalle Valo 244d5c65159SKalle Valo ring->skb[write_index] = skb; 245d5c65159SKalle Valo write_index = CE_RING_IDX_INCR(nentries_mask, write_index); 246d5c65159SKalle Valo ring->write_index = write_index; 247d5c65159SKalle Valo 248d5c65159SKalle Valo pipe->rx_buf_needed--; 249d5c65159SKalle Valo 250d5c65159SKalle Valo ret = 0; 251d5c65159SKalle Valo exit: 252d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 253d5c65159SKalle Valo 254d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 255d5c65159SKalle Valo 256d5c65159SKalle Valo return ret; 257d5c65159SKalle Valo } 258d5c65159SKalle Valo 259d5c65159SKalle Valo static int ath11k_ce_rx_post_pipe(struct ath11k_ce_pipe *pipe) 260d5c65159SKalle Valo { 261d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 262d5c65159SKalle Valo struct sk_buff *skb; 263d5c65159SKalle Valo dma_addr_t paddr; 264d5c65159SKalle Valo int ret = 0; 265d5c65159SKalle Valo 266d5c65159SKalle Valo if (!(pipe->dest_ring || pipe->status_ring)) 267d5c65159SKalle Valo return 0; 268d5c65159SKalle Valo 269d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 270d5c65159SKalle Valo while (pipe->rx_buf_needed) { 271d5c65159SKalle Valo skb = dev_alloc_skb(pipe->buf_sz); 272d5c65159SKalle Valo if (!skb) { 273d5c65159SKalle Valo ret = -ENOMEM; 274d5c65159SKalle Valo goto exit; 275d5c65159SKalle Valo } 276d5c65159SKalle Valo 277d5c65159SKalle Valo WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4)); 278d5c65159SKalle Valo 279d5c65159SKalle Valo paddr = dma_map_single(ab->dev, skb->data, 280d5c65159SKalle Valo skb->len + skb_tailroom(skb), 281d5c65159SKalle Valo DMA_FROM_DEVICE); 282d5c65159SKalle Valo if (unlikely(dma_mapping_error(ab->dev, paddr))) { 283d5c65159SKalle Valo ath11k_warn(ab, "failed to dma map ce rx buf\n"); 284d5c65159SKalle Valo dev_kfree_skb_any(skb); 285d5c65159SKalle Valo ret = -EIO; 286d5c65159SKalle Valo goto exit; 287d5c65159SKalle Valo } 288d5c65159SKalle Valo 289d5c65159SKalle Valo ATH11K_SKB_RXCB(skb)->paddr = paddr; 290d5c65159SKalle Valo 291d5c65159SKalle Valo ret = ath11k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr); 292d5c65159SKalle Valo 293d5c65159SKalle Valo if (ret) { 294d5c65159SKalle Valo ath11k_warn(ab, "failed to enqueue rx buf: %d\n", ret); 295d5c65159SKalle Valo dma_unmap_single(ab->dev, paddr, 296d5c65159SKalle Valo skb->len + skb_tailroom(skb), 297d5c65159SKalle Valo DMA_FROM_DEVICE); 298d5c65159SKalle Valo dev_kfree_skb_any(skb); 299d5c65159SKalle Valo goto exit; 300d5c65159SKalle Valo } 301d5c65159SKalle Valo } 302d5c65159SKalle Valo 303d5c65159SKalle Valo exit: 304d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 305d5c65159SKalle Valo return ret; 306d5c65159SKalle Valo } 307d5c65159SKalle Valo 308d5c65159SKalle Valo static int ath11k_ce_completed_recv_next(struct ath11k_ce_pipe *pipe, 309d5c65159SKalle Valo struct sk_buff **skb, int *nbytes) 310d5c65159SKalle Valo { 311d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 312d5c65159SKalle Valo struct hal_srng *srng; 313d5c65159SKalle Valo unsigned int sw_index; 314d5c65159SKalle Valo unsigned int nentries_mask; 315d5c65159SKalle Valo u32 *desc; 316d5c65159SKalle Valo int ret = 0; 317d5c65159SKalle Valo 318d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 319d5c65159SKalle Valo 320d5c65159SKalle Valo sw_index = pipe->dest_ring->sw_index; 321d5c65159SKalle Valo nentries_mask = pipe->dest_ring->nentries_mask; 322d5c65159SKalle Valo 323d5c65159SKalle Valo srng = &ab->hal.srng_list[pipe->status_ring->hal_ring_id]; 324d5c65159SKalle Valo 325d5c65159SKalle Valo spin_lock_bh(&srng->lock); 326d5c65159SKalle Valo 327d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 328d5c65159SKalle Valo 329d5c65159SKalle Valo desc = ath11k_hal_srng_dst_get_next_entry(ab, srng); 330d5c65159SKalle Valo if (!desc) { 331d5c65159SKalle Valo ret = -EIO; 332d5c65159SKalle Valo goto err; 333d5c65159SKalle Valo } 334d5c65159SKalle Valo 335d5c65159SKalle Valo *nbytes = ath11k_hal_ce_dst_status_get_length(desc); 336d5c65159SKalle Valo if (*nbytes == 0) { 337d5c65159SKalle Valo ret = -EIO; 338d5c65159SKalle Valo goto err; 339d5c65159SKalle Valo } 340d5c65159SKalle Valo 341d5c65159SKalle Valo *skb = pipe->dest_ring->skb[sw_index]; 342d5c65159SKalle Valo pipe->dest_ring->skb[sw_index] = NULL; 343d5c65159SKalle Valo 344d5c65159SKalle Valo sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); 345d5c65159SKalle Valo pipe->dest_ring->sw_index = sw_index; 346d5c65159SKalle Valo 347d5c65159SKalle Valo pipe->rx_buf_needed++; 348d5c65159SKalle Valo err: 349d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 350d5c65159SKalle Valo 351d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 352d5c65159SKalle Valo 353d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 354d5c65159SKalle Valo 355d5c65159SKalle Valo return ret; 356d5c65159SKalle Valo } 357d5c65159SKalle Valo 358d5c65159SKalle Valo static void ath11k_ce_recv_process_cb(struct ath11k_ce_pipe *pipe) 359d5c65159SKalle Valo { 360d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 361d5c65159SKalle Valo struct sk_buff *skb; 362d5c65159SKalle Valo struct sk_buff_head list; 363d5c65159SKalle Valo unsigned int nbytes, max_nbytes; 364d5c65159SKalle Valo int ret; 365d5c65159SKalle Valo 366d5c65159SKalle Valo __skb_queue_head_init(&list); 367d5c65159SKalle Valo while (ath11k_ce_completed_recv_next(pipe, &skb, &nbytes) == 0) { 368d5c65159SKalle Valo max_nbytes = skb->len + skb_tailroom(skb); 369d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 370d5c65159SKalle Valo max_nbytes, DMA_FROM_DEVICE); 371d5c65159SKalle Valo 372d5c65159SKalle Valo if (unlikely(max_nbytes < nbytes)) { 373d5c65159SKalle Valo ath11k_warn(ab, "rxed more than expected (nbytes %d, max %d)", 374d5c65159SKalle Valo nbytes, max_nbytes); 375d5c65159SKalle Valo dev_kfree_skb_any(skb); 376d5c65159SKalle Valo continue; 377d5c65159SKalle Valo } 378d5c65159SKalle Valo 379d5c65159SKalle Valo skb_put(skb, nbytes); 380d5c65159SKalle Valo __skb_queue_tail(&list, skb); 381d5c65159SKalle Valo } 382d5c65159SKalle Valo 383d5c65159SKalle Valo while ((skb = __skb_dequeue(&list))) { 384d5c65159SKalle Valo ath11k_dbg(ab, ATH11K_DBG_AHB, "rx ce pipe %d len %d\n", 385d5c65159SKalle Valo pipe->pipe_num, skb->len); 386d5c65159SKalle Valo pipe->recv_cb(ab, skb); 387d5c65159SKalle Valo } 388d5c65159SKalle Valo 389d5c65159SKalle Valo ret = ath11k_ce_rx_post_pipe(pipe); 390d5c65159SKalle Valo if (ret && ret != -ENOSPC) { 391d5c65159SKalle Valo ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n", 392d5c65159SKalle Valo pipe->pipe_num, ret); 393d5c65159SKalle Valo mod_timer(&ab->rx_replenish_retry, 394d5c65159SKalle Valo jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES); 395d5c65159SKalle Valo } 396d5c65159SKalle Valo } 397d5c65159SKalle Valo 398d5c65159SKalle Valo static struct sk_buff *ath11k_ce_completed_send_next(struct ath11k_ce_pipe *pipe) 399d5c65159SKalle Valo { 400d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 401d5c65159SKalle Valo struct hal_srng *srng; 402d5c65159SKalle Valo unsigned int sw_index; 403d5c65159SKalle Valo unsigned int nentries_mask; 404d5c65159SKalle Valo struct sk_buff *skb; 405d5c65159SKalle Valo u32 *desc; 406d5c65159SKalle Valo 407d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 408d5c65159SKalle Valo 409d5c65159SKalle Valo sw_index = pipe->src_ring->sw_index; 410d5c65159SKalle Valo nentries_mask = pipe->src_ring->nentries_mask; 411d5c65159SKalle Valo 412d5c65159SKalle Valo srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id]; 413d5c65159SKalle Valo 414d5c65159SKalle Valo spin_lock_bh(&srng->lock); 415d5c65159SKalle Valo 416d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 417d5c65159SKalle Valo 418d5c65159SKalle Valo desc = ath11k_hal_srng_src_reap_next(ab, srng); 419d5c65159SKalle Valo if (!desc) { 420d5c65159SKalle Valo skb = ERR_PTR(-EIO); 421d5c65159SKalle Valo goto err_unlock; 422d5c65159SKalle Valo } 423d5c65159SKalle Valo 424d5c65159SKalle Valo skb = pipe->src_ring->skb[sw_index]; 425d5c65159SKalle Valo 426d5c65159SKalle Valo pipe->src_ring->skb[sw_index] = NULL; 427d5c65159SKalle Valo 428d5c65159SKalle Valo sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); 429d5c65159SKalle Valo pipe->src_ring->sw_index = sw_index; 430d5c65159SKalle Valo 431d5c65159SKalle Valo err_unlock: 432d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 433d5c65159SKalle Valo 434d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 435d5c65159SKalle Valo 436d5c65159SKalle Valo return skb; 437d5c65159SKalle Valo } 438d5c65159SKalle Valo 439d5c65159SKalle Valo static void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe) 440d5c65159SKalle Valo { 441d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 442d5c65159SKalle Valo struct sk_buff *skb; 443d5c65159SKalle Valo 444d5c65159SKalle Valo while (!IS_ERR(skb = ath11k_ce_completed_send_next(pipe))) { 445d5c65159SKalle Valo if (!skb) 446d5c65159SKalle Valo continue; 447d5c65159SKalle Valo 448d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len, 449d5c65159SKalle Valo DMA_TO_DEVICE); 450d5c65159SKalle Valo dev_kfree_skb_any(skb); 451d5c65159SKalle Valo } 452d5c65159SKalle Valo } 453d5c65159SKalle Valo 454c4eacabeSGovind Singh static void ath11k_ce_srng_msi_ring_params_setup(struct ath11k_base *ab, u32 ce_id, 455c4eacabeSGovind Singh struct hal_srng_params *ring_params) 456c4eacabeSGovind Singh { 457c4eacabeSGovind Singh u32 msi_data_start; 458c4eacabeSGovind Singh u32 msi_data_count; 459c4eacabeSGovind Singh u32 msi_irq_start; 460c4eacabeSGovind Singh u32 addr_lo; 461c4eacabeSGovind Singh u32 addr_hi; 462c4eacabeSGovind Singh int ret; 463c4eacabeSGovind Singh 464c4eacabeSGovind Singh ret = ath11k_get_user_msi_vector(ab, "CE", 465c4eacabeSGovind Singh &msi_data_count, &msi_data_start, 466c4eacabeSGovind Singh &msi_irq_start); 467c4eacabeSGovind Singh 468c4eacabeSGovind Singh if (ret) 469c4eacabeSGovind Singh return; 470c4eacabeSGovind Singh 471c4eacabeSGovind Singh ath11k_get_msi_address(ab, &addr_lo, &addr_hi); 472c4eacabeSGovind Singh 473c4eacabeSGovind Singh ring_params->msi_addr = addr_lo; 474c4eacabeSGovind Singh ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32); 475c4eacabeSGovind Singh ring_params->msi_data = (ce_id % msi_data_count) + msi_data_start; 476c4eacabeSGovind Singh ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR; 477c4eacabeSGovind Singh } 478c4eacabeSGovind Singh 479d5c65159SKalle Valo static int ath11k_ce_init_ring(struct ath11k_base *ab, 480d5c65159SKalle Valo struct ath11k_ce_ring *ce_ring, 481d5c65159SKalle Valo int ce_id, enum hal_ring_type type) 482d5c65159SKalle Valo { 483d5c65159SKalle Valo struct hal_srng_params params = { 0 }; 484d5c65159SKalle Valo int ret; 485d5c65159SKalle Valo 486d5c65159SKalle Valo params.ring_base_paddr = ce_ring->base_addr_ce_space; 487d5c65159SKalle Valo params.ring_base_vaddr = ce_ring->base_addr_owner_space; 488d5c65159SKalle Valo params.num_entries = ce_ring->nentries; 489d5c65159SKalle Valo 4901a05ed37SCarl Huang if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) 4911a05ed37SCarl Huang ath11k_ce_srng_msi_ring_params_setup(ab, ce_id, ¶ms); 4921a05ed37SCarl Huang 493d5c65159SKalle Valo switch (type) { 494d5c65159SKalle Valo case HAL_CE_SRC: 4956e5e9f59SKalle Valo if (!(CE_ATTR_DIS_INTR & ab->hw_params.host_ce_config[ce_id].flags)) 496d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 1; 497d5c65159SKalle Valo break; 498d5c65159SKalle Valo case HAL_CE_DST: 4996e5e9f59SKalle Valo params.max_buffer_len = ab->hw_params.host_ce_config[ce_id].src_sz_max; 5006e5e9f59SKalle Valo if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { 501d5c65159SKalle Valo params.intr_timer_thres_us = 1024; 502d5c65159SKalle Valo params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; 503d5c65159SKalle Valo params.low_threshold = ce_ring->nentries - 3; 504d5c65159SKalle Valo } 505d5c65159SKalle Valo break; 506d5c65159SKalle Valo case HAL_CE_DST_STATUS: 5076e5e9f59SKalle Valo if (!(ab->hw_params.host_ce_config[ce_id].flags & CE_ATTR_DIS_INTR)) { 508d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 1; 509d5c65159SKalle Valo params.intr_timer_thres_us = 0x1000; 510d5c65159SKalle Valo } 511d5c65159SKalle Valo break; 512d5c65159SKalle Valo default: 513d5c65159SKalle Valo ath11k_warn(ab, "Invalid CE ring type %d\n", type); 514d5c65159SKalle Valo return -EINVAL; 515d5c65159SKalle Valo } 516d5c65159SKalle Valo 517d5c65159SKalle Valo /* TODO: Init other params needed by HAL to init the ring */ 518d5c65159SKalle Valo 519d5c65159SKalle Valo ret = ath11k_hal_srng_setup(ab, type, ce_id, 0, ¶ms); 520d5c65159SKalle Valo if (ret < 0) { 521d5c65159SKalle Valo ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n", 522d5c65159SKalle Valo ret, ce_id); 523d5c65159SKalle Valo return ret; 524d5c65159SKalle Valo } 525c4eacabeSGovind Singh 526d5c65159SKalle Valo ce_ring->hal_ring_id = ret; 527d5c65159SKalle Valo 5289b309970SCarl Huang if (ab->hw_params.supports_shadow_regs && 5299b309970SCarl Huang ath11k_ce_need_shadow_fix(ce_id)) 5309b309970SCarl Huang ath11k_dp_shadow_init_timer(ab, &ab->ce.hp_timer[ce_id], 5319b309970SCarl Huang ATH11K_SHADOW_CTRL_TIMER_INTERVAL, 5329b309970SCarl Huang ce_ring->hal_ring_id); 5339b309970SCarl Huang 534d5c65159SKalle Valo return 0; 535d5c65159SKalle Valo } 536d5c65159SKalle Valo 537d5c65159SKalle Valo static struct ath11k_ce_ring * 538d5c65159SKalle Valo ath11k_ce_alloc_ring(struct ath11k_base *ab, int nentries, int desc_sz) 539d5c65159SKalle Valo { 540d5c65159SKalle Valo struct ath11k_ce_ring *ce_ring; 541d5c65159SKalle Valo dma_addr_t base_addr; 542d5c65159SKalle Valo 543d5c65159SKalle Valo ce_ring = kzalloc(struct_size(ce_ring, skb, nentries), GFP_KERNEL); 544d5c65159SKalle Valo if (ce_ring == NULL) 545d5c65159SKalle Valo return ERR_PTR(-ENOMEM); 546d5c65159SKalle Valo 547d5c65159SKalle Valo ce_ring->nentries = nentries; 548d5c65159SKalle Valo ce_ring->nentries_mask = nentries - 1; 549d5c65159SKalle Valo 550d5c65159SKalle Valo /* Legacy platforms that do not support cache 551d5c65159SKalle Valo * coherent DMA are unsupported 552d5c65159SKalle Valo */ 553d5c65159SKalle Valo ce_ring->base_addr_owner_space_unaligned = 554d5c65159SKalle Valo dma_alloc_coherent(ab->dev, 555d5c65159SKalle Valo nentries * desc_sz + CE_DESC_RING_ALIGN, 556d5c65159SKalle Valo &base_addr, GFP_KERNEL); 557d5c65159SKalle Valo if (!ce_ring->base_addr_owner_space_unaligned) { 558d5c65159SKalle Valo kfree(ce_ring); 559d5c65159SKalle Valo return ERR_PTR(-ENOMEM); 560d5c65159SKalle Valo } 561d5c65159SKalle Valo 562d5c65159SKalle Valo ce_ring->base_addr_ce_space_unaligned = base_addr; 563d5c65159SKalle Valo 564d5c65159SKalle Valo ce_ring->base_addr_owner_space = PTR_ALIGN( 565d5c65159SKalle Valo ce_ring->base_addr_owner_space_unaligned, 566d5c65159SKalle Valo CE_DESC_RING_ALIGN); 567d5c65159SKalle Valo ce_ring->base_addr_ce_space = ALIGN( 568d5c65159SKalle Valo ce_ring->base_addr_ce_space_unaligned, 569d5c65159SKalle Valo CE_DESC_RING_ALIGN); 570d5c65159SKalle Valo 571d5c65159SKalle Valo return ce_ring; 572d5c65159SKalle Valo } 573d5c65159SKalle Valo 574d5c65159SKalle Valo static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) 575d5c65159SKalle Valo { 576d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; 5776e5e9f59SKalle Valo const struct ce_attr *attr = &ab->hw_params.host_ce_config[ce_id]; 578c76fa846SDan Carpenter struct ath11k_ce_ring *ring; 579d5c65159SKalle Valo int nentries; 580d5c65159SKalle Valo int desc_sz; 581d5c65159SKalle Valo 582d5c65159SKalle Valo pipe->attr_flags = attr->flags; 583d5c65159SKalle Valo 584d5c65159SKalle Valo if (attr->src_nentries) { 585d5c65159SKalle Valo pipe->send_cb = ath11k_ce_send_done_cb; 586d5c65159SKalle Valo nentries = roundup_pow_of_two(attr->src_nentries); 587d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); 588c76fa846SDan Carpenter ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 589c76fa846SDan Carpenter if (IS_ERR(ring)) 590c76fa846SDan Carpenter return PTR_ERR(ring); 591c76fa846SDan Carpenter pipe->src_ring = ring; 592d5c65159SKalle Valo } 593d5c65159SKalle Valo 594d5c65159SKalle Valo if (attr->dest_nentries) { 595d5c65159SKalle Valo pipe->recv_cb = attr->recv_cb; 596d5c65159SKalle Valo nentries = roundup_pow_of_two(attr->dest_nentries); 597d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); 598c76fa846SDan Carpenter ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 599c76fa846SDan Carpenter if (IS_ERR(ring)) 600c76fa846SDan Carpenter return PTR_ERR(ring); 601c76fa846SDan Carpenter pipe->dest_ring = ring; 602d5c65159SKalle Valo 603d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); 604c76fa846SDan Carpenter ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 605c76fa846SDan Carpenter if (IS_ERR(ring)) 606c76fa846SDan Carpenter return PTR_ERR(ring); 607c76fa846SDan Carpenter pipe->status_ring = ring; 608d5c65159SKalle Valo } 609d5c65159SKalle Valo 610d5c65159SKalle Valo return 0; 611d5c65159SKalle Valo } 612d5c65159SKalle Valo 613d5c65159SKalle Valo void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id) 614d5c65159SKalle Valo { 615d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; 616d5c65159SKalle Valo 617d5c65159SKalle Valo if (pipe->send_cb) 618d5c65159SKalle Valo pipe->send_cb(pipe); 619d5c65159SKalle Valo 620d5c65159SKalle Valo if (pipe->recv_cb) 621d5c65159SKalle Valo ath11k_ce_recv_process_cb(pipe); 622d5c65159SKalle Valo } 623d5c65159SKalle Valo 624d5c65159SKalle Valo void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id) 625d5c65159SKalle Valo { 626d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; 627d5c65159SKalle Valo 628d5c65159SKalle Valo if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb) 629d5c65159SKalle Valo pipe->send_cb(pipe); 630d5c65159SKalle Valo } 6312c3960c2SGovind Singh EXPORT_SYMBOL(ath11k_ce_per_engine_service); 632d5c65159SKalle Valo 633d5c65159SKalle Valo int ath11k_ce_send(struct ath11k_base *ab, struct sk_buff *skb, u8 pipe_id, 634d5c65159SKalle Valo u16 transfer_id) 635d5c65159SKalle Valo { 636d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; 637d5c65159SKalle Valo struct hal_srng *srng; 638d5c65159SKalle Valo u32 *desc; 639d5c65159SKalle Valo unsigned int write_index, sw_index; 640d5c65159SKalle Valo unsigned int nentries_mask; 641d5c65159SKalle Valo int ret = 0; 642d5c65159SKalle Valo u8 byte_swap_data = 0; 643d5c65159SKalle Valo int num_used; 644d5c65159SKalle Valo 645d5c65159SKalle Valo /* Check if some entries could be regained by handling tx completion if 646d5c65159SKalle Valo * the CE has interrupts disabled and the used entries is more than the 647d5c65159SKalle Valo * defined usage threshold. 648d5c65159SKalle Valo */ 649d5c65159SKalle Valo if (pipe->attr_flags & CE_ATTR_DIS_INTR) { 650d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 651d5c65159SKalle Valo write_index = pipe->src_ring->write_index; 652d5c65159SKalle Valo 653d5c65159SKalle Valo sw_index = pipe->src_ring->sw_index; 654d5c65159SKalle Valo 655d5c65159SKalle Valo if (write_index >= sw_index) 656d5c65159SKalle Valo num_used = write_index - sw_index; 657d5c65159SKalle Valo else 658d5c65159SKalle Valo num_used = pipe->src_ring->nentries - sw_index + 659d5c65159SKalle Valo write_index; 660d5c65159SKalle Valo 661d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 662d5c65159SKalle Valo 663d5c65159SKalle Valo if (num_used > ATH11K_CE_USAGE_THRESHOLD) 664d5c65159SKalle Valo ath11k_ce_poll_send_completed(ab, pipe->pipe_num); 665d5c65159SKalle Valo } 666d5c65159SKalle Valo 667d5c65159SKalle Valo if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)) 668d5c65159SKalle Valo return -ESHUTDOWN; 669d5c65159SKalle Valo 670d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 671d5c65159SKalle Valo 672d5c65159SKalle Valo write_index = pipe->src_ring->write_index; 673d5c65159SKalle Valo nentries_mask = pipe->src_ring->nentries_mask; 674d5c65159SKalle Valo 675d5c65159SKalle Valo srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id]; 676d5c65159SKalle Valo 677d5c65159SKalle Valo spin_lock_bh(&srng->lock); 678d5c65159SKalle Valo 679d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 680d5c65159SKalle Valo 681d5c65159SKalle Valo if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) { 682d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 683d5c65159SKalle Valo ret = -ENOBUFS; 684d5c65159SKalle Valo goto err_unlock; 685d5c65159SKalle Valo } 686d5c65159SKalle Valo 687d5c65159SKalle Valo desc = ath11k_hal_srng_src_get_next_reaped(ab, srng); 688d5c65159SKalle Valo if (!desc) { 689d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 690d5c65159SKalle Valo ret = -ENOBUFS; 691d5c65159SKalle Valo goto err_unlock; 692d5c65159SKalle Valo } 693d5c65159SKalle Valo 694d5c65159SKalle Valo if (pipe->attr_flags & CE_ATTR_BYTE_SWAP_DATA) 695d5c65159SKalle Valo byte_swap_data = 1; 696d5c65159SKalle Valo 697d5c65159SKalle Valo ath11k_hal_ce_src_set_desc(desc, ATH11K_SKB_CB(skb)->paddr, 698d5c65159SKalle Valo skb->len, transfer_id, byte_swap_data); 699d5c65159SKalle Valo 700d5c65159SKalle Valo pipe->src_ring->skb[write_index] = skb; 701d5c65159SKalle Valo pipe->src_ring->write_index = CE_RING_IDX_INCR(nentries_mask, 702d5c65159SKalle Valo write_index); 703d5c65159SKalle Valo 704d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 705d5c65159SKalle Valo 7069b309970SCarl Huang if (ath11k_ce_need_shadow_fix(pipe_id)) 7079b309970SCarl Huang ath11k_dp_shadow_start_timer(ab, srng, &ab->ce.hp_timer[pipe_id]); 7089b309970SCarl Huang 709d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 710d5c65159SKalle Valo 711d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 712d5c65159SKalle Valo 713d5c65159SKalle Valo return 0; 714d5c65159SKalle Valo 715d5c65159SKalle Valo err_unlock: 716d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 717d5c65159SKalle Valo 718d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 719d5c65159SKalle Valo 720d5c65159SKalle Valo return ret; 721d5c65159SKalle Valo } 722d5c65159SKalle Valo 723d5c65159SKalle Valo static void ath11k_ce_rx_pipe_cleanup(struct ath11k_ce_pipe *pipe) 724d5c65159SKalle Valo { 725d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 726d5c65159SKalle Valo struct ath11k_ce_ring *ring = pipe->dest_ring; 727d5c65159SKalle Valo struct sk_buff *skb; 728d5c65159SKalle Valo int i; 729d5c65159SKalle Valo 730d5c65159SKalle Valo if (!(ring && pipe->buf_sz)) 731d5c65159SKalle Valo return; 732d5c65159SKalle Valo 733d5c65159SKalle Valo for (i = 0; i < ring->nentries; i++) { 734d5c65159SKalle Valo skb = ring->skb[i]; 735d5c65159SKalle Valo if (!skb) 736d5c65159SKalle Valo continue; 737d5c65159SKalle Valo 738d5c65159SKalle Valo ring->skb[i] = NULL; 739d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 740d5c65159SKalle Valo skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); 741d5c65159SKalle Valo dev_kfree_skb_any(skb); 742d5c65159SKalle Valo } 743d5c65159SKalle Valo } 744d5c65159SKalle Valo 745e838c14aSCarl Huang static void ath11k_ce_shadow_config(struct ath11k_base *ab) 746e838c14aSCarl Huang { 747e838c14aSCarl Huang int i; 748e838c14aSCarl Huang 749e838c14aSCarl Huang for (i = 0; i < ab->hw_params.ce_count; i++) { 750e838c14aSCarl Huang if (ab->hw_params.host_ce_config[i].src_nentries) 751e838c14aSCarl Huang ath11k_hal_srng_update_shadow_config(ab, 752e838c14aSCarl Huang HAL_CE_SRC, i); 753e838c14aSCarl Huang 754e838c14aSCarl Huang if (ab->hw_params.host_ce_config[i].dest_nentries) { 755e838c14aSCarl Huang ath11k_hal_srng_update_shadow_config(ab, 756e838c14aSCarl Huang HAL_CE_DST, i); 757e838c14aSCarl Huang 758e838c14aSCarl Huang ath11k_hal_srng_update_shadow_config(ab, 759e838c14aSCarl Huang HAL_CE_DST_STATUS, i); 760e838c14aSCarl Huang } 761e838c14aSCarl Huang } 762e838c14aSCarl Huang } 763e838c14aSCarl Huang 764e838c14aSCarl Huang void ath11k_ce_get_shadow_config(struct ath11k_base *ab, 765e838c14aSCarl Huang u32 **shadow_cfg, u32 *shadow_cfg_len) 766e838c14aSCarl Huang { 767e838c14aSCarl Huang if (!ab->hw_params.supports_shadow_regs) 768e838c14aSCarl Huang return; 769e838c14aSCarl Huang 770e838c14aSCarl Huang ath11k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len); 771e838c14aSCarl Huang 772e838c14aSCarl Huang /* shadow is already configured */ 773e838c14aSCarl Huang if (*shadow_cfg_len) 774e838c14aSCarl Huang return; 775e838c14aSCarl Huang 776e838c14aSCarl Huang /* shadow isn't configured yet, configure now. 777e838c14aSCarl Huang * non-CE srngs are configured firstly, then 778e838c14aSCarl Huang * all CE srngs. 779e838c14aSCarl Huang */ 780e838c14aSCarl Huang ath11k_hal_srng_shadow_config(ab); 781e838c14aSCarl Huang ath11k_ce_shadow_config(ab); 782e838c14aSCarl Huang 783e838c14aSCarl Huang /* get the shadow configuration */ 784e838c14aSCarl Huang ath11k_hal_srng_get_shadow_config(ab, shadow_cfg, shadow_cfg_len); 785e838c14aSCarl Huang } 786e838c14aSCarl Huang EXPORT_SYMBOL(ath11k_ce_get_shadow_config); 787e838c14aSCarl Huang 788d5c65159SKalle Valo void ath11k_ce_cleanup_pipes(struct ath11k_base *ab) 789d5c65159SKalle Valo { 790d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 791d5c65159SKalle Valo int pipe_num; 792d5c65159SKalle Valo 7939b309970SCarl Huang ath11k_ce_stop_shadow_timers(ab); 7949b309970SCarl Huang 795d9d4b5f3SKalle Valo for (pipe_num = 0; pipe_num < ab->hw_params.ce_count; pipe_num++) { 796d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[pipe_num]; 797d5c65159SKalle Valo ath11k_ce_rx_pipe_cleanup(pipe); 798d5c65159SKalle Valo 799d5c65159SKalle Valo /* Cleanup any src CE's which have interrupts disabled */ 800d5c65159SKalle Valo ath11k_ce_poll_send_completed(ab, pipe_num); 801d5c65159SKalle Valo 802d5c65159SKalle Valo /* NOTE: Should we also clean up tx buffer in all pipes? */ 803d5c65159SKalle Valo } 804d5c65159SKalle Valo } 8057f4beda2SGovind Singh EXPORT_SYMBOL(ath11k_ce_cleanup_pipes); 806d5c65159SKalle Valo 807d5c65159SKalle Valo void ath11k_ce_rx_post_buf(struct ath11k_base *ab) 808d5c65159SKalle Valo { 809d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 810d5c65159SKalle Valo int i; 811d5c65159SKalle Valo int ret; 812d5c65159SKalle Valo 813d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 814d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 815d5c65159SKalle Valo ret = ath11k_ce_rx_post_pipe(pipe); 816d5c65159SKalle Valo if (ret) { 817d5c65159SKalle Valo if (ret == -ENOSPC) 818d5c65159SKalle Valo continue; 819d5c65159SKalle Valo 820d5c65159SKalle Valo ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n", 821d5c65159SKalle Valo i, ret); 822d5c65159SKalle Valo mod_timer(&ab->rx_replenish_retry, 823d5c65159SKalle Valo jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES); 824d5c65159SKalle Valo 825d5c65159SKalle Valo return; 826d5c65159SKalle Valo } 827d5c65159SKalle Valo } 828d5c65159SKalle Valo } 8292c3960c2SGovind Singh EXPORT_SYMBOL(ath11k_ce_rx_post_buf); 830d5c65159SKalle Valo 831d5c65159SKalle Valo void ath11k_ce_rx_replenish_retry(struct timer_list *t) 832d5c65159SKalle Valo { 833d5c65159SKalle Valo struct ath11k_base *ab = from_timer(ab, t, rx_replenish_retry); 834d5c65159SKalle Valo 835d5c65159SKalle Valo ath11k_ce_rx_post_buf(ab); 836d5c65159SKalle Valo } 837d5c65159SKalle Valo 838d5c65159SKalle Valo int ath11k_ce_init_pipes(struct ath11k_base *ab) 839d5c65159SKalle Valo { 840d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 841d5c65159SKalle Valo int i; 842d5c65159SKalle Valo int ret; 843d5c65159SKalle Valo 844e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &ab->qmi.ce_cfg.shadow_reg_v2, 845e838c14aSCarl Huang &ab->qmi.ce_cfg.shadow_reg_v2_len); 846e838c14aSCarl Huang 847d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 848d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 849d5c65159SKalle Valo 850d5c65159SKalle Valo if (pipe->src_ring) { 851d5c65159SKalle Valo ret = ath11k_ce_init_ring(ab, pipe->src_ring, i, 852d5c65159SKalle Valo HAL_CE_SRC); 853d5c65159SKalle Valo if (ret) { 854d5c65159SKalle Valo ath11k_warn(ab, "failed to init src ring: %d\n", 855d5c65159SKalle Valo ret); 856d5c65159SKalle Valo /* Should we clear any partial init */ 857d5c65159SKalle Valo return ret; 858d5c65159SKalle Valo } 859d5c65159SKalle Valo 860d5c65159SKalle Valo pipe->src_ring->write_index = 0; 861d5c65159SKalle Valo pipe->src_ring->sw_index = 0; 862d5c65159SKalle Valo } 863d5c65159SKalle Valo 864d5c65159SKalle Valo if (pipe->dest_ring) { 865d5c65159SKalle Valo ret = ath11k_ce_init_ring(ab, pipe->dest_ring, i, 866d5c65159SKalle Valo HAL_CE_DST); 867d5c65159SKalle Valo if (ret) { 868d5c65159SKalle Valo ath11k_warn(ab, "failed to init dest ring: %d\n", 869d5c65159SKalle Valo ret); 870d5c65159SKalle Valo /* Should we clear any partial init */ 871d5c65159SKalle Valo return ret; 872d5c65159SKalle Valo } 873d5c65159SKalle Valo 874d5c65159SKalle Valo pipe->rx_buf_needed = pipe->dest_ring->nentries ? 875d5c65159SKalle Valo pipe->dest_ring->nentries - 2 : 0; 876d5c65159SKalle Valo 877d5c65159SKalle Valo pipe->dest_ring->write_index = 0; 878d5c65159SKalle Valo pipe->dest_ring->sw_index = 0; 879d5c65159SKalle Valo } 880d5c65159SKalle Valo 881d5c65159SKalle Valo if (pipe->status_ring) { 882d5c65159SKalle Valo ret = ath11k_ce_init_ring(ab, pipe->status_ring, i, 883d5c65159SKalle Valo HAL_CE_DST_STATUS); 884d5c65159SKalle Valo if (ret) { 885d5c65159SKalle Valo ath11k_warn(ab, "failed to init dest status ing: %d\n", 886d5c65159SKalle Valo ret); 887d5c65159SKalle Valo /* Should we clear any partial init */ 888d5c65159SKalle Valo return ret; 889d5c65159SKalle Valo } 890d5c65159SKalle Valo 891d5c65159SKalle Valo pipe->status_ring->write_index = 0; 892d5c65159SKalle Valo pipe->status_ring->sw_index = 0; 893d5c65159SKalle Valo } 894d5c65159SKalle Valo } 895d5c65159SKalle Valo 896d5c65159SKalle Valo return 0; 897d5c65159SKalle Valo } 898d5c65159SKalle Valo 899d5c65159SKalle Valo void ath11k_ce_free_pipes(struct ath11k_base *ab) 900d5c65159SKalle Valo { 901d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 902d5c65159SKalle Valo int desc_sz; 903d5c65159SKalle Valo int i; 904d5c65159SKalle Valo 905d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 906d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 907d5c65159SKalle Valo 9089b309970SCarl Huang if (ath11k_ce_need_shadow_fix(i)) 9099b309970SCarl Huang ath11k_dp_shadow_stop_timer(ab, &ab->ce.hp_timer[i]); 9109b309970SCarl Huang 911d5c65159SKalle Valo if (pipe->src_ring) { 912d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); 913d5c65159SKalle Valo dma_free_coherent(ab->dev, 914d5c65159SKalle Valo pipe->src_ring->nentries * desc_sz + 915d5c65159SKalle Valo CE_DESC_RING_ALIGN, 916d5c65159SKalle Valo pipe->src_ring->base_addr_owner_space, 917d5c65159SKalle Valo pipe->src_ring->base_addr_ce_space); 918d5c65159SKalle Valo kfree(pipe->src_ring); 919d5c65159SKalle Valo pipe->src_ring = NULL; 920d5c65159SKalle Valo } 921d5c65159SKalle Valo 922d5c65159SKalle Valo if (pipe->dest_ring) { 923d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); 924d5c65159SKalle Valo dma_free_coherent(ab->dev, 925d5c65159SKalle Valo pipe->dest_ring->nentries * desc_sz + 926d5c65159SKalle Valo CE_DESC_RING_ALIGN, 927d5c65159SKalle Valo pipe->dest_ring->base_addr_owner_space, 928d5c65159SKalle Valo pipe->dest_ring->base_addr_ce_space); 929d5c65159SKalle Valo kfree(pipe->dest_ring); 930d5c65159SKalle Valo pipe->dest_ring = NULL; 931d5c65159SKalle Valo } 932d5c65159SKalle Valo 933d5c65159SKalle Valo if (pipe->status_ring) { 934d5c65159SKalle Valo desc_sz = 935d5c65159SKalle Valo ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); 936d5c65159SKalle Valo dma_free_coherent(ab->dev, 937d5c65159SKalle Valo pipe->status_ring->nentries * desc_sz + 938d5c65159SKalle Valo CE_DESC_RING_ALIGN, 939d5c65159SKalle Valo pipe->status_ring->base_addr_owner_space, 940d5c65159SKalle Valo pipe->status_ring->base_addr_ce_space); 941d5c65159SKalle Valo kfree(pipe->status_ring); 942d5c65159SKalle Valo pipe->status_ring = NULL; 943d5c65159SKalle Valo } 944d5c65159SKalle Valo } 945d5c65159SKalle Valo } 9466e0355afSGovind Singh EXPORT_SYMBOL(ath11k_ce_free_pipes); 947d5c65159SKalle Valo 948d5c65159SKalle Valo int ath11k_ce_alloc_pipes(struct ath11k_base *ab) 949d5c65159SKalle Valo { 950d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 951d5c65159SKalle Valo int i; 952d5c65159SKalle Valo int ret; 953d5c65159SKalle Valo const struct ce_attr *attr; 954d5c65159SKalle Valo 955d5c65159SKalle Valo spin_lock_init(&ab->ce.ce_lock); 956d5c65159SKalle Valo 957d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 9586e5e9f59SKalle Valo attr = &ab->hw_params.host_ce_config[i]; 959d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 960d5c65159SKalle Valo pipe->pipe_num = i; 961d5c65159SKalle Valo pipe->ab = ab; 962d5c65159SKalle Valo pipe->buf_sz = attr->src_sz_max; 963d5c65159SKalle Valo 964d5c65159SKalle Valo ret = ath11k_ce_alloc_pipe(ab, i); 965d5c65159SKalle Valo if (ret) { 966d5c65159SKalle Valo /* Free any parial successful allocation */ 967d5c65159SKalle Valo ath11k_ce_free_pipes(ab); 968d5c65159SKalle Valo return ret; 969d5c65159SKalle Valo } 970d5c65159SKalle Valo } 971d5c65159SKalle Valo 972d5c65159SKalle Valo return 0; 973d5c65159SKalle Valo } 9747f4beda2SGovind Singh EXPORT_SYMBOL(ath11k_ce_alloc_pipes); 975d5c65159SKalle Valo 976d5c65159SKalle Valo /* For Big Endian Host, Copy Engine byte_swap is enabled 977d5c65159SKalle Valo * When Copy Engine does byte_swap, need to byte swap again for the 978d5c65159SKalle Valo * Host to get/put buffer content in the correct byte order 979d5c65159SKalle Valo */ 980d5c65159SKalle Valo void ath11k_ce_byte_swap(void *mem, u32 len) 981d5c65159SKalle Valo { 982d5c65159SKalle Valo int i; 983d5c65159SKalle Valo 984d5c65159SKalle Valo if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) { 985d5c65159SKalle Valo if (!mem) 986d5c65159SKalle Valo return; 987d5c65159SKalle Valo 988d5c65159SKalle Valo for (i = 0; i < (len / 4); i++) { 989d5c65159SKalle Valo *(u32 *)mem = swab32(*(u32 *)mem); 990d5c65159SKalle Valo mem += 4; 991d5c65159SKalle Valo } 992d5c65159SKalle Valo } 993d5c65159SKalle Valo } 994d5c65159SKalle Valo 995e3396b8bSCarl Huang int ath11k_ce_get_attr_flags(struct ath11k_base *ab, int ce_id) 996d5c65159SKalle Valo { 997d9d4b5f3SKalle Valo if (ce_id >= ab->hw_params.ce_count) 998d5c65159SKalle Valo return -EINVAL; 999d5c65159SKalle Valo 10006e5e9f59SKalle Valo return ab->hw_params.host_ce_config[ce_id].flags; 1001d5c65159SKalle Valo } 10026e0355afSGovind Singh EXPORT_SYMBOL(ath11k_ce_get_attr_flags); 1003