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" 8d5c65159SKalle Valo 9d5c65159SKalle Valo static const struct ce_attr host_ce_config_wlan[] = { 10d5c65159SKalle Valo /* CE0: host->target HTC control and raw streams */ 11d5c65159SKalle Valo { 12d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 13d5c65159SKalle Valo .src_nentries = 16, 14d5c65159SKalle Valo .src_sz_max = 2048, 15d5c65159SKalle Valo .dest_nentries = 0, 16d5c65159SKalle Valo }, 17d5c65159SKalle Valo 18d5c65159SKalle Valo /* CE1: target->host HTT + HTC control */ 19d5c65159SKalle Valo { 20d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 21d5c65159SKalle Valo .src_nentries = 0, 22d5c65159SKalle Valo .src_sz_max = 2048, 23d5c65159SKalle Valo .dest_nentries = 512, 24d5c65159SKalle Valo .recv_cb = ath11k_htc_rx_completion_handler, 25d5c65159SKalle Valo }, 26d5c65159SKalle Valo 27d5c65159SKalle Valo /* CE2: target->host WMI */ 28d5c65159SKalle Valo { 29d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 30d5c65159SKalle Valo .src_nentries = 0, 31d5c65159SKalle Valo .src_sz_max = 2048, 32d5c65159SKalle Valo .dest_nentries = 512, 33d5c65159SKalle Valo .recv_cb = ath11k_htc_rx_completion_handler, 34d5c65159SKalle Valo }, 35d5c65159SKalle Valo 36d5c65159SKalle Valo /* CE3: host->target WMI (mac0) */ 37d5c65159SKalle Valo { 38d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 39d5c65159SKalle Valo .src_nentries = 32, 40d5c65159SKalle Valo .src_sz_max = 2048, 41d5c65159SKalle Valo .dest_nentries = 0, 42d5c65159SKalle Valo }, 43d5c65159SKalle Valo 44d5c65159SKalle Valo /* CE4: host->target HTT */ 45d5c65159SKalle Valo { 46d5c65159SKalle Valo .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 47d5c65159SKalle Valo .src_nentries = 2048, 48d5c65159SKalle Valo .src_sz_max = 256, 49d5c65159SKalle Valo .dest_nentries = 0, 50d5c65159SKalle Valo }, 51d5c65159SKalle Valo 52d5c65159SKalle Valo /* CE5: target->host pktlog */ 53d5c65159SKalle Valo { 54d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 55d5c65159SKalle Valo .src_nentries = 0, 56d5c65159SKalle Valo .src_sz_max = 2048, 57d5c65159SKalle Valo .dest_nentries = 512, 58d5c65159SKalle Valo .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler, 59d5c65159SKalle Valo }, 60d5c65159SKalle Valo 61d5c65159SKalle Valo /* CE6: target autonomous hif_memcpy */ 62d5c65159SKalle Valo { 63d5c65159SKalle Valo .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 64d5c65159SKalle Valo .src_nentries = 0, 65d5c65159SKalle Valo .src_sz_max = 0, 66d5c65159SKalle Valo .dest_nentries = 0, 67d5c65159SKalle Valo }, 68d5c65159SKalle Valo 69d5c65159SKalle Valo /* CE7: host->target WMI (mac1) */ 70d5c65159SKalle Valo { 71d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 72d5c65159SKalle Valo .src_nentries = 32, 73d5c65159SKalle Valo .src_sz_max = 2048, 74d5c65159SKalle Valo .dest_nentries = 0, 75d5c65159SKalle Valo }, 76d5c65159SKalle Valo 77d5c65159SKalle Valo /* CE8: target autonomous hif_memcpy */ 78d5c65159SKalle Valo { 79d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 80d5c65159SKalle Valo .src_nentries = 0, 81d5c65159SKalle Valo .src_sz_max = 0, 82d5c65159SKalle Valo .dest_nentries = 0, 83d5c65159SKalle Valo }, 84d5c65159SKalle Valo 85d5c65159SKalle Valo /* CE9: host->target WMI (mac2) */ 86d5c65159SKalle Valo { 87d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 88d5c65159SKalle Valo .src_nentries = 32, 89d5c65159SKalle Valo .src_sz_max = 2048, 90d5c65159SKalle Valo .dest_nentries = 0, 91d5c65159SKalle Valo }, 92d5c65159SKalle Valo 93d5c65159SKalle Valo /* CE10: target->host HTT */ 94d5c65159SKalle Valo { 95d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 96d5c65159SKalle Valo .src_nentries = 0, 97d5c65159SKalle Valo .src_sz_max = 2048, 98d5c65159SKalle Valo .dest_nentries = 512, 99d5c65159SKalle Valo .recv_cb = ath11k_htc_rx_completion_handler, 100d5c65159SKalle Valo }, 101d5c65159SKalle Valo 102d5c65159SKalle Valo /* CE11: Not used */ 103d5c65159SKalle Valo { 104d5c65159SKalle Valo .flags = CE_ATTR_FLAGS, 105d5c65159SKalle Valo .src_nentries = 0, 106d5c65159SKalle Valo .src_sz_max = 0, 107d5c65159SKalle Valo .dest_nentries = 0, 108d5c65159SKalle Valo }, 109d5c65159SKalle Valo }; 110d5c65159SKalle Valo 111d5c65159SKalle Valo static int ath11k_ce_rx_buf_enqueue_pipe(struct ath11k_ce_pipe *pipe, 112d5c65159SKalle Valo struct sk_buff *skb, dma_addr_t paddr) 113d5c65159SKalle Valo { 114d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 115d5c65159SKalle Valo struct ath11k_ce_ring *ring = pipe->dest_ring; 116d5c65159SKalle Valo struct hal_srng *srng; 117d5c65159SKalle Valo unsigned int write_index; 118d5c65159SKalle Valo unsigned int nentries_mask = ring->nentries_mask; 119d5c65159SKalle Valo u32 *desc; 120d5c65159SKalle Valo int ret; 121d5c65159SKalle Valo 122d5c65159SKalle Valo lockdep_assert_held(&ab->ce.ce_lock); 123d5c65159SKalle Valo 124d5c65159SKalle Valo write_index = ring->write_index; 125d5c65159SKalle Valo 126d5c65159SKalle Valo srng = &ab->hal.srng_list[ring->hal_ring_id]; 127d5c65159SKalle Valo 128d5c65159SKalle Valo spin_lock_bh(&srng->lock); 129d5c65159SKalle Valo 130d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 131d5c65159SKalle Valo 132d5c65159SKalle Valo if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) { 133d5c65159SKalle Valo ret = -ENOSPC; 134d5c65159SKalle Valo goto exit; 135d5c65159SKalle Valo } 136d5c65159SKalle Valo 137d5c65159SKalle Valo desc = ath11k_hal_srng_src_get_next_entry(ab, srng); 138d5c65159SKalle Valo if (!desc) { 139d5c65159SKalle Valo ret = -ENOSPC; 140d5c65159SKalle Valo goto exit; 141d5c65159SKalle Valo } 142d5c65159SKalle Valo 143d5c65159SKalle Valo ath11k_hal_ce_dst_set_desc(desc, paddr); 144d5c65159SKalle Valo 145d5c65159SKalle Valo ring->skb[write_index] = skb; 146d5c65159SKalle Valo write_index = CE_RING_IDX_INCR(nentries_mask, write_index); 147d5c65159SKalle Valo ring->write_index = write_index; 148d5c65159SKalle Valo 149d5c65159SKalle Valo pipe->rx_buf_needed--; 150d5c65159SKalle Valo 151d5c65159SKalle Valo ret = 0; 152d5c65159SKalle Valo exit: 153d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 154d5c65159SKalle Valo 155d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 156d5c65159SKalle Valo 157d5c65159SKalle Valo return ret; 158d5c65159SKalle Valo } 159d5c65159SKalle Valo 160d5c65159SKalle Valo static int ath11k_ce_rx_post_pipe(struct ath11k_ce_pipe *pipe) 161d5c65159SKalle Valo { 162d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 163d5c65159SKalle Valo struct sk_buff *skb; 164d5c65159SKalle Valo dma_addr_t paddr; 165d5c65159SKalle Valo int ret = 0; 166d5c65159SKalle Valo 167d5c65159SKalle Valo if (!(pipe->dest_ring || pipe->status_ring)) 168d5c65159SKalle Valo return 0; 169d5c65159SKalle Valo 170d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 171d5c65159SKalle Valo while (pipe->rx_buf_needed) { 172d5c65159SKalle Valo skb = dev_alloc_skb(pipe->buf_sz); 173d5c65159SKalle Valo if (!skb) { 174d5c65159SKalle Valo ret = -ENOMEM; 175d5c65159SKalle Valo goto exit; 176d5c65159SKalle Valo } 177d5c65159SKalle Valo 178d5c65159SKalle Valo WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4)); 179d5c65159SKalle Valo 180d5c65159SKalle Valo paddr = dma_map_single(ab->dev, skb->data, 181d5c65159SKalle Valo skb->len + skb_tailroom(skb), 182d5c65159SKalle Valo DMA_FROM_DEVICE); 183d5c65159SKalle Valo if (unlikely(dma_mapping_error(ab->dev, paddr))) { 184d5c65159SKalle Valo ath11k_warn(ab, "failed to dma map ce rx buf\n"); 185d5c65159SKalle Valo dev_kfree_skb_any(skb); 186d5c65159SKalle Valo ret = -EIO; 187d5c65159SKalle Valo goto exit; 188d5c65159SKalle Valo } 189d5c65159SKalle Valo 190d5c65159SKalle Valo ATH11K_SKB_RXCB(skb)->paddr = paddr; 191d5c65159SKalle Valo 192d5c65159SKalle Valo ret = ath11k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr); 193d5c65159SKalle Valo 194d5c65159SKalle Valo if (ret) { 195d5c65159SKalle Valo ath11k_warn(ab, "failed to enqueue rx buf: %d\n", ret); 196d5c65159SKalle Valo dma_unmap_single(ab->dev, paddr, 197d5c65159SKalle Valo skb->len + skb_tailroom(skb), 198d5c65159SKalle Valo DMA_FROM_DEVICE); 199d5c65159SKalle Valo dev_kfree_skb_any(skb); 200d5c65159SKalle Valo goto exit; 201d5c65159SKalle Valo } 202d5c65159SKalle Valo } 203d5c65159SKalle Valo 204d5c65159SKalle Valo exit: 205d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 206d5c65159SKalle Valo return ret; 207d5c65159SKalle Valo } 208d5c65159SKalle Valo 209d5c65159SKalle Valo static int ath11k_ce_completed_recv_next(struct ath11k_ce_pipe *pipe, 210d5c65159SKalle Valo struct sk_buff **skb, int *nbytes) 211d5c65159SKalle Valo { 212d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 213d5c65159SKalle Valo struct hal_srng *srng; 214d5c65159SKalle Valo unsigned int sw_index; 215d5c65159SKalle Valo unsigned int nentries_mask; 216d5c65159SKalle Valo u32 *desc; 217d5c65159SKalle Valo int ret = 0; 218d5c65159SKalle Valo 219d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 220d5c65159SKalle Valo 221d5c65159SKalle Valo sw_index = pipe->dest_ring->sw_index; 222d5c65159SKalle Valo nentries_mask = pipe->dest_ring->nentries_mask; 223d5c65159SKalle Valo 224d5c65159SKalle Valo srng = &ab->hal.srng_list[pipe->status_ring->hal_ring_id]; 225d5c65159SKalle Valo 226d5c65159SKalle Valo spin_lock_bh(&srng->lock); 227d5c65159SKalle Valo 228d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 229d5c65159SKalle Valo 230d5c65159SKalle Valo desc = ath11k_hal_srng_dst_get_next_entry(ab, srng); 231d5c65159SKalle Valo if (!desc) { 232d5c65159SKalle Valo ret = -EIO; 233d5c65159SKalle Valo goto err; 234d5c65159SKalle Valo } 235d5c65159SKalle Valo 236d5c65159SKalle Valo *nbytes = ath11k_hal_ce_dst_status_get_length(desc); 237d5c65159SKalle Valo if (*nbytes == 0) { 238d5c65159SKalle Valo ret = -EIO; 239d5c65159SKalle Valo goto err; 240d5c65159SKalle Valo } 241d5c65159SKalle Valo 242d5c65159SKalle Valo *skb = pipe->dest_ring->skb[sw_index]; 243d5c65159SKalle Valo pipe->dest_ring->skb[sw_index] = NULL; 244d5c65159SKalle Valo 245d5c65159SKalle Valo sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); 246d5c65159SKalle Valo pipe->dest_ring->sw_index = sw_index; 247d5c65159SKalle Valo 248d5c65159SKalle Valo pipe->rx_buf_needed++; 249d5c65159SKalle Valo err: 250d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 251d5c65159SKalle Valo 252d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 253d5c65159SKalle Valo 254d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 255d5c65159SKalle Valo 256d5c65159SKalle Valo return ret; 257d5c65159SKalle Valo } 258d5c65159SKalle Valo 259d5c65159SKalle Valo static void ath11k_ce_recv_process_cb(struct ath11k_ce_pipe *pipe) 260d5c65159SKalle Valo { 261d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 262d5c65159SKalle Valo struct sk_buff *skb; 263d5c65159SKalle Valo struct sk_buff_head list; 264d5c65159SKalle Valo unsigned int nbytes, max_nbytes; 265d5c65159SKalle Valo int ret; 266d5c65159SKalle Valo 267d5c65159SKalle Valo __skb_queue_head_init(&list); 268d5c65159SKalle Valo while (ath11k_ce_completed_recv_next(pipe, &skb, &nbytes) == 0) { 269d5c65159SKalle Valo max_nbytes = skb->len + skb_tailroom(skb); 270d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 271d5c65159SKalle Valo max_nbytes, DMA_FROM_DEVICE); 272d5c65159SKalle Valo 273d5c65159SKalle Valo if (unlikely(max_nbytes < nbytes)) { 274d5c65159SKalle Valo ath11k_warn(ab, "rxed more than expected (nbytes %d, max %d)", 275d5c65159SKalle Valo nbytes, max_nbytes); 276d5c65159SKalle Valo dev_kfree_skb_any(skb); 277d5c65159SKalle Valo continue; 278d5c65159SKalle Valo } 279d5c65159SKalle Valo 280d5c65159SKalle Valo skb_put(skb, nbytes); 281d5c65159SKalle Valo __skb_queue_tail(&list, skb); 282d5c65159SKalle Valo } 283d5c65159SKalle Valo 284d5c65159SKalle Valo while ((skb = __skb_dequeue(&list))) { 285d5c65159SKalle Valo ath11k_dbg(ab, ATH11K_DBG_AHB, "rx ce pipe %d len %d\n", 286d5c65159SKalle Valo pipe->pipe_num, skb->len); 287d5c65159SKalle Valo pipe->recv_cb(ab, skb); 288d5c65159SKalle Valo } 289d5c65159SKalle Valo 290d5c65159SKalle Valo ret = ath11k_ce_rx_post_pipe(pipe); 291d5c65159SKalle Valo if (ret && ret != -ENOSPC) { 292d5c65159SKalle Valo ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n", 293d5c65159SKalle Valo pipe->pipe_num, ret); 294d5c65159SKalle Valo mod_timer(&ab->rx_replenish_retry, 295d5c65159SKalle Valo jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES); 296d5c65159SKalle Valo } 297d5c65159SKalle Valo } 298d5c65159SKalle Valo 299d5c65159SKalle Valo static struct sk_buff *ath11k_ce_completed_send_next(struct ath11k_ce_pipe *pipe) 300d5c65159SKalle Valo { 301d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 302d5c65159SKalle Valo struct hal_srng *srng; 303d5c65159SKalle Valo unsigned int sw_index; 304d5c65159SKalle Valo unsigned int nentries_mask; 305d5c65159SKalle Valo struct sk_buff *skb; 306d5c65159SKalle Valo u32 *desc; 307d5c65159SKalle Valo 308d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 309d5c65159SKalle Valo 310d5c65159SKalle Valo sw_index = pipe->src_ring->sw_index; 311d5c65159SKalle Valo nentries_mask = pipe->src_ring->nentries_mask; 312d5c65159SKalle Valo 313d5c65159SKalle Valo srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id]; 314d5c65159SKalle Valo 315d5c65159SKalle Valo spin_lock_bh(&srng->lock); 316d5c65159SKalle Valo 317d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 318d5c65159SKalle Valo 319d5c65159SKalle Valo desc = ath11k_hal_srng_src_reap_next(ab, srng); 320d5c65159SKalle Valo if (!desc) { 321d5c65159SKalle Valo skb = ERR_PTR(-EIO); 322d5c65159SKalle Valo goto err_unlock; 323d5c65159SKalle Valo } 324d5c65159SKalle Valo 325d5c65159SKalle Valo skb = pipe->src_ring->skb[sw_index]; 326d5c65159SKalle Valo 327d5c65159SKalle Valo pipe->src_ring->skb[sw_index] = NULL; 328d5c65159SKalle Valo 329d5c65159SKalle Valo sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); 330d5c65159SKalle Valo pipe->src_ring->sw_index = sw_index; 331d5c65159SKalle Valo 332d5c65159SKalle Valo err_unlock: 333d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 334d5c65159SKalle Valo 335d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 336d5c65159SKalle Valo 337d5c65159SKalle Valo return skb; 338d5c65159SKalle Valo } 339d5c65159SKalle Valo 340d5c65159SKalle Valo static void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe) 341d5c65159SKalle Valo { 342d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 343d5c65159SKalle Valo struct sk_buff *skb; 344d5c65159SKalle Valo 345d5c65159SKalle Valo while (!IS_ERR(skb = ath11k_ce_completed_send_next(pipe))) { 346d5c65159SKalle Valo if (!skb) 347d5c65159SKalle Valo continue; 348d5c65159SKalle Valo 349d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len, 350d5c65159SKalle Valo DMA_TO_DEVICE); 351d5c65159SKalle Valo dev_kfree_skb_any(skb); 352d5c65159SKalle Valo } 353d5c65159SKalle Valo } 354d5c65159SKalle Valo 355d5c65159SKalle Valo static int ath11k_ce_init_ring(struct ath11k_base *ab, 356d5c65159SKalle Valo struct ath11k_ce_ring *ce_ring, 357d5c65159SKalle Valo int ce_id, enum hal_ring_type type) 358d5c65159SKalle Valo { 359d5c65159SKalle Valo struct hal_srng_params params = { 0 }; 360d5c65159SKalle Valo int ret; 361d5c65159SKalle Valo 362d5c65159SKalle Valo params.ring_base_paddr = ce_ring->base_addr_ce_space; 363d5c65159SKalle Valo params.ring_base_vaddr = ce_ring->base_addr_owner_space; 364d5c65159SKalle Valo params.num_entries = ce_ring->nentries; 365d5c65159SKalle Valo 366d5c65159SKalle Valo switch (type) { 367d5c65159SKalle Valo case HAL_CE_SRC: 368d5c65159SKalle Valo if (!(CE_ATTR_DIS_INTR & host_ce_config_wlan[ce_id].flags)) 369d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 1; 370d5c65159SKalle Valo break; 371d5c65159SKalle Valo case HAL_CE_DST: 372d5c65159SKalle Valo params.max_buffer_len = host_ce_config_wlan[ce_id].src_sz_max; 373d5c65159SKalle Valo if (!(host_ce_config_wlan[ce_id].flags & CE_ATTR_DIS_INTR)) { 374d5c65159SKalle Valo params.intr_timer_thres_us = 1024; 375d5c65159SKalle Valo params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; 376d5c65159SKalle Valo params.low_threshold = ce_ring->nentries - 3; 377d5c65159SKalle Valo } 378d5c65159SKalle Valo break; 379d5c65159SKalle Valo case HAL_CE_DST_STATUS: 380d5c65159SKalle Valo if (!(host_ce_config_wlan[ce_id].flags & CE_ATTR_DIS_INTR)) { 381d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 1; 382d5c65159SKalle Valo params.intr_timer_thres_us = 0x1000; 383d5c65159SKalle Valo } 384d5c65159SKalle Valo break; 385d5c65159SKalle Valo default: 386d5c65159SKalle Valo ath11k_warn(ab, "Invalid CE ring type %d\n", type); 387d5c65159SKalle Valo return -EINVAL; 388d5c65159SKalle Valo } 389d5c65159SKalle Valo 390d5c65159SKalle Valo /* TODO: Init other params needed by HAL to init the ring */ 391d5c65159SKalle Valo 392d5c65159SKalle Valo ret = ath11k_hal_srng_setup(ab, type, ce_id, 0, ¶ms); 393d5c65159SKalle Valo if (ret < 0) { 394d5c65159SKalle Valo ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n", 395d5c65159SKalle Valo ret, ce_id); 396d5c65159SKalle Valo return ret; 397d5c65159SKalle Valo } 398d5c65159SKalle Valo ce_ring->hal_ring_id = ret; 399d5c65159SKalle Valo 400d5c65159SKalle Valo return 0; 401d5c65159SKalle Valo } 402d5c65159SKalle Valo 403d5c65159SKalle Valo static struct ath11k_ce_ring * 404d5c65159SKalle Valo ath11k_ce_alloc_ring(struct ath11k_base *ab, int nentries, int desc_sz) 405d5c65159SKalle Valo { 406d5c65159SKalle Valo struct ath11k_ce_ring *ce_ring; 407d5c65159SKalle Valo dma_addr_t base_addr; 408d5c65159SKalle Valo 409d5c65159SKalle Valo ce_ring = kzalloc(struct_size(ce_ring, skb, nentries), GFP_KERNEL); 410d5c65159SKalle Valo if (ce_ring == NULL) 411d5c65159SKalle Valo return ERR_PTR(-ENOMEM); 412d5c65159SKalle Valo 413d5c65159SKalle Valo ce_ring->nentries = nentries; 414d5c65159SKalle Valo ce_ring->nentries_mask = nentries - 1; 415d5c65159SKalle Valo 416d5c65159SKalle Valo /* Legacy platforms that do not support cache 417d5c65159SKalle Valo * coherent DMA are unsupported 418d5c65159SKalle Valo */ 419d5c65159SKalle Valo ce_ring->base_addr_owner_space_unaligned = 420d5c65159SKalle Valo dma_alloc_coherent(ab->dev, 421d5c65159SKalle Valo nentries * desc_sz + CE_DESC_RING_ALIGN, 422d5c65159SKalle Valo &base_addr, GFP_KERNEL); 423d5c65159SKalle Valo if (!ce_ring->base_addr_owner_space_unaligned) { 424d5c65159SKalle Valo kfree(ce_ring); 425d5c65159SKalle Valo return ERR_PTR(-ENOMEM); 426d5c65159SKalle Valo } 427d5c65159SKalle Valo 428d5c65159SKalle Valo ce_ring->base_addr_ce_space_unaligned = base_addr; 429d5c65159SKalle Valo 430d5c65159SKalle Valo ce_ring->base_addr_owner_space = PTR_ALIGN( 431d5c65159SKalle Valo ce_ring->base_addr_owner_space_unaligned, 432d5c65159SKalle Valo CE_DESC_RING_ALIGN); 433d5c65159SKalle Valo ce_ring->base_addr_ce_space = ALIGN( 434d5c65159SKalle Valo ce_ring->base_addr_ce_space_unaligned, 435d5c65159SKalle Valo CE_DESC_RING_ALIGN); 436d5c65159SKalle Valo 437d5c65159SKalle Valo return ce_ring; 438d5c65159SKalle Valo } 439d5c65159SKalle Valo 440d5c65159SKalle Valo static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) 441d5c65159SKalle Valo { 442d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; 443d5c65159SKalle Valo const struct ce_attr *attr = &host_ce_config_wlan[ce_id]; 444*c76fa846SDan Carpenter struct ath11k_ce_ring *ring; 445d5c65159SKalle Valo int nentries; 446d5c65159SKalle Valo int desc_sz; 447d5c65159SKalle Valo 448d5c65159SKalle Valo pipe->attr_flags = attr->flags; 449d5c65159SKalle Valo 450d5c65159SKalle Valo if (attr->src_nentries) { 451d5c65159SKalle Valo pipe->send_cb = ath11k_ce_send_done_cb; 452d5c65159SKalle Valo nentries = roundup_pow_of_two(attr->src_nentries); 453d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); 454*c76fa846SDan Carpenter ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 455*c76fa846SDan Carpenter if (IS_ERR(ring)) 456*c76fa846SDan Carpenter return PTR_ERR(ring); 457*c76fa846SDan Carpenter pipe->src_ring = ring; 458d5c65159SKalle Valo } 459d5c65159SKalle Valo 460d5c65159SKalle Valo if (attr->dest_nentries) { 461d5c65159SKalle Valo pipe->recv_cb = attr->recv_cb; 462d5c65159SKalle Valo nentries = roundup_pow_of_two(attr->dest_nentries); 463d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); 464*c76fa846SDan Carpenter ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 465*c76fa846SDan Carpenter if (IS_ERR(ring)) 466*c76fa846SDan Carpenter return PTR_ERR(ring); 467*c76fa846SDan Carpenter pipe->dest_ring = ring; 468d5c65159SKalle Valo 469d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); 470*c76fa846SDan Carpenter ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); 471*c76fa846SDan Carpenter if (IS_ERR(ring)) 472*c76fa846SDan Carpenter return PTR_ERR(ring); 473*c76fa846SDan Carpenter pipe->status_ring = ring; 474d5c65159SKalle Valo } 475d5c65159SKalle Valo 476d5c65159SKalle Valo return 0; 477d5c65159SKalle Valo } 478d5c65159SKalle Valo 479d5c65159SKalle Valo void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id) 480d5c65159SKalle Valo { 481d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; 482d5c65159SKalle Valo 483d5c65159SKalle Valo if (pipe->send_cb) 484d5c65159SKalle Valo pipe->send_cb(pipe); 485d5c65159SKalle Valo 486d5c65159SKalle Valo if (pipe->recv_cb) 487d5c65159SKalle Valo ath11k_ce_recv_process_cb(pipe); 488d5c65159SKalle Valo } 489d5c65159SKalle Valo 490d5c65159SKalle Valo void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id) 491d5c65159SKalle Valo { 492d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; 493d5c65159SKalle Valo 494d5c65159SKalle Valo if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb) 495d5c65159SKalle Valo pipe->send_cb(pipe); 496d5c65159SKalle Valo } 497d5c65159SKalle Valo 498d5c65159SKalle Valo int ath11k_ce_send(struct ath11k_base *ab, struct sk_buff *skb, u8 pipe_id, 499d5c65159SKalle Valo u16 transfer_id) 500d5c65159SKalle Valo { 501d5c65159SKalle Valo struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id]; 502d5c65159SKalle Valo struct hal_srng *srng; 503d5c65159SKalle Valo u32 *desc; 504d5c65159SKalle Valo unsigned int write_index, sw_index; 505d5c65159SKalle Valo unsigned int nentries_mask; 506d5c65159SKalle Valo int ret = 0; 507d5c65159SKalle Valo u8 byte_swap_data = 0; 508d5c65159SKalle Valo int num_used; 509d5c65159SKalle Valo 510d5c65159SKalle Valo /* Check if some entries could be regained by handling tx completion if 511d5c65159SKalle Valo * the CE has interrupts disabled and the used entries is more than the 512d5c65159SKalle Valo * defined usage threshold. 513d5c65159SKalle Valo */ 514d5c65159SKalle Valo if (pipe->attr_flags & CE_ATTR_DIS_INTR) { 515d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 516d5c65159SKalle Valo write_index = pipe->src_ring->write_index; 517d5c65159SKalle Valo 518d5c65159SKalle Valo sw_index = pipe->src_ring->sw_index; 519d5c65159SKalle Valo 520d5c65159SKalle Valo if (write_index >= sw_index) 521d5c65159SKalle Valo num_used = write_index - sw_index; 522d5c65159SKalle Valo else 523d5c65159SKalle Valo num_used = pipe->src_ring->nentries - sw_index + 524d5c65159SKalle Valo write_index; 525d5c65159SKalle Valo 526d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 527d5c65159SKalle Valo 528d5c65159SKalle Valo if (num_used > ATH11K_CE_USAGE_THRESHOLD) 529d5c65159SKalle Valo ath11k_ce_poll_send_completed(ab, pipe->pipe_num); 530d5c65159SKalle Valo } 531d5c65159SKalle Valo 532d5c65159SKalle Valo if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)) 533d5c65159SKalle Valo return -ESHUTDOWN; 534d5c65159SKalle Valo 535d5c65159SKalle Valo spin_lock_bh(&ab->ce.ce_lock); 536d5c65159SKalle Valo 537d5c65159SKalle Valo write_index = pipe->src_ring->write_index; 538d5c65159SKalle Valo nentries_mask = pipe->src_ring->nentries_mask; 539d5c65159SKalle Valo 540d5c65159SKalle Valo srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id]; 541d5c65159SKalle Valo 542d5c65159SKalle Valo spin_lock_bh(&srng->lock); 543d5c65159SKalle Valo 544d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 545d5c65159SKalle Valo 546d5c65159SKalle Valo if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) { 547d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 548d5c65159SKalle Valo ret = -ENOBUFS; 549d5c65159SKalle Valo goto err_unlock; 550d5c65159SKalle Valo } 551d5c65159SKalle Valo 552d5c65159SKalle Valo desc = ath11k_hal_srng_src_get_next_reaped(ab, srng); 553d5c65159SKalle Valo if (!desc) { 554d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 555d5c65159SKalle Valo ret = -ENOBUFS; 556d5c65159SKalle Valo goto err_unlock; 557d5c65159SKalle Valo } 558d5c65159SKalle Valo 559d5c65159SKalle Valo if (pipe->attr_flags & CE_ATTR_BYTE_SWAP_DATA) 560d5c65159SKalle Valo byte_swap_data = 1; 561d5c65159SKalle Valo 562d5c65159SKalle Valo ath11k_hal_ce_src_set_desc(desc, ATH11K_SKB_CB(skb)->paddr, 563d5c65159SKalle Valo skb->len, transfer_id, byte_swap_data); 564d5c65159SKalle Valo 565d5c65159SKalle Valo pipe->src_ring->skb[write_index] = skb; 566d5c65159SKalle Valo pipe->src_ring->write_index = CE_RING_IDX_INCR(nentries_mask, 567d5c65159SKalle Valo write_index); 568d5c65159SKalle Valo 569d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 570d5c65159SKalle Valo 571d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 572d5c65159SKalle Valo 573d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 574d5c65159SKalle Valo 575d5c65159SKalle Valo return 0; 576d5c65159SKalle Valo 577d5c65159SKalle Valo err_unlock: 578d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 579d5c65159SKalle Valo 580d5c65159SKalle Valo spin_unlock_bh(&ab->ce.ce_lock); 581d5c65159SKalle Valo 582d5c65159SKalle Valo return ret; 583d5c65159SKalle Valo } 584d5c65159SKalle Valo 585d5c65159SKalle Valo static void ath11k_ce_rx_pipe_cleanup(struct ath11k_ce_pipe *pipe) 586d5c65159SKalle Valo { 587d5c65159SKalle Valo struct ath11k_base *ab = pipe->ab; 588d5c65159SKalle Valo struct ath11k_ce_ring *ring = pipe->dest_ring; 589d5c65159SKalle Valo struct sk_buff *skb; 590d5c65159SKalle Valo int i; 591d5c65159SKalle Valo 592d5c65159SKalle Valo if (!(ring && pipe->buf_sz)) 593d5c65159SKalle Valo return; 594d5c65159SKalle Valo 595d5c65159SKalle Valo for (i = 0; i < ring->nentries; i++) { 596d5c65159SKalle Valo skb = ring->skb[i]; 597d5c65159SKalle Valo if (!skb) 598d5c65159SKalle Valo continue; 599d5c65159SKalle Valo 600d5c65159SKalle Valo ring->skb[i] = NULL; 601d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, 602d5c65159SKalle Valo skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); 603d5c65159SKalle Valo dev_kfree_skb_any(skb); 604d5c65159SKalle Valo } 605d5c65159SKalle Valo } 606d5c65159SKalle Valo 607d5c65159SKalle Valo void ath11k_ce_cleanup_pipes(struct ath11k_base *ab) 608d5c65159SKalle Valo { 609d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 610d5c65159SKalle Valo int pipe_num; 611d5c65159SKalle Valo 612d5c65159SKalle Valo for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { 613d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[pipe_num]; 614d5c65159SKalle Valo ath11k_ce_rx_pipe_cleanup(pipe); 615d5c65159SKalle Valo 616d5c65159SKalle Valo /* Cleanup any src CE's which have interrupts disabled */ 617d5c65159SKalle Valo ath11k_ce_poll_send_completed(ab, pipe_num); 618d5c65159SKalle Valo 619d5c65159SKalle Valo /* NOTE: Should we also clean up tx buffer in all pipes? */ 620d5c65159SKalle Valo } 621d5c65159SKalle Valo } 622d5c65159SKalle Valo 623d5c65159SKalle Valo void ath11k_ce_rx_post_buf(struct ath11k_base *ab) 624d5c65159SKalle Valo { 625d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 626d5c65159SKalle Valo int i; 627d5c65159SKalle Valo int ret; 628d5c65159SKalle Valo 629d5c65159SKalle Valo for (i = 0; i < CE_COUNT; i++) { 630d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 631d5c65159SKalle Valo ret = ath11k_ce_rx_post_pipe(pipe); 632d5c65159SKalle Valo if (ret) { 633d5c65159SKalle Valo if (ret == -ENOSPC) 634d5c65159SKalle Valo continue; 635d5c65159SKalle Valo 636d5c65159SKalle Valo ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n", 637d5c65159SKalle Valo i, ret); 638d5c65159SKalle Valo mod_timer(&ab->rx_replenish_retry, 639d5c65159SKalle Valo jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES); 640d5c65159SKalle Valo 641d5c65159SKalle Valo return; 642d5c65159SKalle Valo } 643d5c65159SKalle Valo } 644d5c65159SKalle Valo } 645d5c65159SKalle Valo 646d5c65159SKalle Valo void ath11k_ce_rx_replenish_retry(struct timer_list *t) 647d5c65159SKalle Valo { 648d5c65159SKalle Valo struct ath11k_base *ab = from_timer(ab, t, rx_replenish_retry); 649d5c65159SKalle Valo 650d5c65159SKalle Valo ath11k_ce_rx_post_buf(ab); 651d5c65159SKalle Valo } 652d5c65159SKalle Valo 653d5c65159SKalle Valo int ath11k_ce_init_pipes(struct ath11k_base *ab) 654d5c65159SKalle Valo { 655d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 656d5c65159SKalle Valo int i; 657d5c65159SKalle Valo int ret; 658d5c65159SKalle Valo 659d5c65159SKalle Valo for (i = 0; i < CE_COUNT; i++) { 660d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 661d5c65159SKalle Valo 662d5c65159SKalle Valo if (pipe->src_ring) { 663d5c65159SKalle Valo ret = ath11k_ce_init_ring(ab, pipe->src_ring, i, 664d5c65159SKalle Valo HAL_CE_SRC); 665d5c65159SKalle Valo if (ret) { 666d5c65159SKalle Valo ath11k_warn(ab, "failed to init src ring: %d\n", 667d5c65159SKalle Valo ret); 668d5c65159SKalle Valo /* Should we clear any partial init */ 669d5c65159SKalle Valo return ret; 670d5c65159SKalle Valo } 671d5c65159SKalle Valo 672d5c65159SKalle Valo pipe->src_ring->write_index = 0; 673d5c65159SKalle Valo pipe->src_ring->sw_index = 0; 674d5c65159SKalle Valo } 675d5c65159SKalle Valo 676d5c65159SKalle Valo if (pipe->dest_ring) { 677d5c65159SKalle Valo ret = ath11k_ce_init_ring(ab, pipe->dest_ring, i, 678d5c65159SKalle Valo HAL_CE_DST); 679d5c65159SKalle Valo if (ret) { 680d5c65159SKalle Valo ath11k_warn(ab, "failed to init dest ring: %d\n", 681d5c65159SKalle Valo ret); 682d5c65159SKalle Valo /* Should we clear any partial init */ 683d5c65159SKalle Valo return ret; 684d5c65159SKalle Valo } 685d5c65159SKalle Valo 686d5c65159SKalle Valo pipe->rx_buf_needed = pipe->dest_ring->nentries ? 687d5c65159SKalle Valo pipe->dest_ring->nentries - 2 : 0; 688d5c65159SKalle Valo 689d5c65159SKalle Valo pipe->dest_ring->write_index = 0; 690d5c65159SKalle Valo pipe->dest_ring->sw_index = 0; 691d5c65159SKalle Valo } 692d5c65159SKalle Valo 693d5c65159SKalle Valo if (pipe->status_ring) { 694d5c65159SKalle Valo ret = ath11k_ce_init_ring(ab, pipe->status_ring, i, 695d5c65159SKalle Valo HAL_CE_DST_STATUS); 696d5c65159SKalle Valo if (ret) { 697d5c65159SKalle Valo ath11k_warn(ab, "failed to init dest status ing: %d\n", 698d5c65159SKalle Valo ret); 699d5c65159SKalle Valo /* Should we clear any partial init */ 700d5c65159SKalle Valo return ret; 701d5c65159SKalle Valo } 702d5c65159SKalle Valo 703d5c65159SKalle Valo pipe->status_ring->write_index = 0; 704d5c65159SKalle Valo pipe->status_ring->sw_index = 0; 705d5c65159SKalle Valo } 706d5c65159SKalle Valo } 707d5c65159SKalle Valo 708d5c65159SKalle Valo return 0; 709d5c65159SKalle Valo } 710d5c65159SKalle Valo 711d5c65159SKalle Valo void ath11k_ce_free_pipes(struct ath11k_base *ab) 712d5c65159SKalle Valo { 713d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 714d5c65159SKalle Valo int desc_sz; 715d5c65159SKalle Valo int i; 716d5c65159SKalle Valo 717d5c65159SKalle Valo for (i = 0; i < CE_COUNT; i++) { 718d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 719d5c65159SKalle Valo 720d5c65159SKalle Valo if (pipe->src_ring) { 721d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); 722d5c65159SKalle Valo dma_free_coherent(ab->dev, 723d5c65159SKalle Valo pipe->src_ring->nentries * desc_sz + 724d5c65159SKalle Valo CE_DESC_RING_ALIGN, 725d5c65159SKalle Valo pipe->src_ring->base_addr_owner_space, 726d5c65159SKalle Valo pipe->src_ring->base_addr_ce_space); 727d5c65159SKalle Valo kfree(pipe->src_ring); 728d5c65159SKalle Valo pipe->src_ring = NULL; 729d5c65159SKalle Valo } 730d5c65159SKalle Valo 731d5c65159SKalle Valo if (pipe->dest_ring) { 732d5c65159SKalle Valo desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); 733d5c65159SKalle Valo dma_free_coherent(ab->dev, 734d5c65159SKalle Valo pipe->dest_ring->nentries * desc_sz + 735d5c65159SKalle Valo CE_DESC_RING_ALIGN, 736d5c65159SKalle Valo pipe->dest_ring->base_addr_owner_space, 737d5c65159SKalle Valo pipe->dest_ring->base_addr_ce_space); 738d5c65159SKalle Valo kfree(pipe->dest_ring); 739d5c65159SKalle Valo pipe->dest_ring = NULL; 740d5c65159SKalle Valo } 741d5c65159SKalle Valo 742d5c65159SKalle Valo if (pipe->status_ring) { 743d5c65159SKalle Valo desc_sz = 744d5c65159SKalle Valo ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); 745d5c65159SKalle Valo dma_free_coherent(ab->dev, 746d5c65159SKalle Valo pipe->status_ring->nentries * desc_sz + 747d5c65159SKalle Valo CE_DESC_RING_ALIGN, 748d5c65159SKalle Valo pipe->status_ring->base_addr_owner_space, 749d5c65159SKalle Valo pipe->status_ring->base_addr_ce_space); 750d5c65159SKalle Valo kfree(pipe->status_ring); 751d5c65159SKalle Valo pipe->status_ring = NULL; 752d5c65159SKalle Valo } 753d5c65159SKalle Valo } 754d5c65159SKalle Valo } 755d5c65159SKalle Valo 756d5c65159SKalle Valo int ath11k_ce_alloc_pipes(struct ath11k_base *ab) 757d5c65159SKalle Valo { 758d5c65159SKalle Valo struct ath11k_ce_pipe *pipe; 759d5c65159SKalle Valo int i; 760d5c65159SKalle Valo int ret; 761d5c65159SKalle Valo const struct ce_attr *attr; 762d5c65159SKalle Valo 763d5c65159SKalle Valo spin_lock_init(&ab->ce.ce_lock); 764d5c65159SKalle Valo 765d5c65159SKalle Valo for (i = 0; i < CE_COUNT; i++) { 766d5c65159SKalle Valo attr = &host_ce_config_wlan[i]; 767d5c65159SKalle Valo pipe = &ab->ce.ce_pipe[i]; 768d5c65159SKalle Valo pipe->pipe_num = i; 769d5c65159SKalle Valo pipe->ab = ab; 770d5c65159SKalle Valo pipe->buf_sz = attr->src_sz_max; 771d5c65159SKalle Valo 772d5c65159SKalle Valo ret = ath11k_ce_alloc_pipe(ab, i); 773d5c65159SKalle Valo if (ret) { 774d5c65159SKalle Valo /* Free any parial successful allocation */ 775d5c65159SKalle Valo ath11k_ce_free_pipes(ab); 776d5c65159SKalle Valo return ret; 777d5c65159SKalle Valo } 778d5c65159SKalle Valo } 779d5c65159SKalle Valo 780d5c65159SKalle Valo return 0; 781d5c65159SKalle Valo } 782d5c65159SKalle Valo 783d5c65159SKalle Valo /* For Big Endian Host, Copy Engine byte_swap is enabled 784d5c65159SKalle Valo * When Copy Engine does byte_swap, need to byte swap again for the 785d5c65159SKalle Valo * Host to get/put buffer content in the correct byte order 786d5c65159SKalle Valo */ 787d5c65159SKalle Valo void ath11k_ce_byte_swap(void *mem, u32 len) 788d5c65159SKalle Valo { 789d5c65159SKalle Valo int i; 790d5c65159SKalle Valo 791d5c65159SKalle Valo if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) { 792d5c65159SKalle Valo if (!mem) 793d5c65159SKalle Valo return; 794d5c65159SKalle Valo 795d5c65159SKalle Valo for (i = 0; i < (len / 4); i++) { 796d5c65159SKalle Valo *(u32 *)mem = swab32(*(u32 *)mem); 797d5c65159SKalle Valo mem += 4; 798d5c65159SKalle Valo } 799d5c65159SKalle Valo } 800d5c65159SKalle Valo } 801d5c65159SKalle Valo 802d5c65159SKalle Valo int ath11k_ce_get_attr_flags(int ce_id) 803d5c65159SKalle Valo { 804d5c65159SKalle Valo if (ce_id >= CE_COUNT) 805d5c65159SKalle Valo return -EINVAL; 806d5c65159SKalle Valo 807d5c65159SKalle Valo return host_ce_config_wlan[ce_id].flags; 808d5c65159SKalle Valo } 809