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 "core.h" 7d5c65159SKalle Valo #include "dp_tx.h" 8d5c65159SKalle Valo #include "hal_tx.h" 9d5c65159SKalle Valo #include "debug.h" 10d5c65159SKalle Valo #include "dp_rx.h" 11d5c65159SKalle Valo #include "peer.h" 12d5c65159SKalle Valo 13d5c65159SKalle Valo static void ath11k_dp_htt_htc_tx_complete(struct ath11k_base *ab, 14d5c65159SKalle Valo struct sk_buff *skb) 15d5c65159SKalle Valo { 16d5c65159SKalle Valo dev_kfree_skb_any(skb); 17d5c65159SKalle Valo } 18d5c65159SKalle Valo 19d5c65159SKalle Valo void ath11k_dp_peer_cleanup(struct ath11k *ar, int vdev_id, const u8 *addr) 20d5c65159SKalle Valo { 21d5c65159SKalle Valo struct ath11k_base *ab = ar->ab; 22d5c65159SKalle Valo struct ath11k_peer *peer; 23d5c65159SKalle Valo 24d5c65159SKalle Valo /* TODO: Any other peer specific DP cleanup */ 25d5c65159SKalle Valo 26d5c65159SKalle Valo spin_lock_bh(&ab->base_lock); 27d5c65159SKalle Valo peer = ath11k_peer_find(ab, vdev_id, addr); 28d5c65159SKalle Valo if (!peer) { 29d5c65159SKalle Valo ath11k_warn(ab, "failed to lookup peer %pM on vdev %d\n", 30d5c65159SKalle Valo addr, vdev_id); 31d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 32d5c65159SKalle Valo return; 33d5c65159SKalle Valo } 34d5c65159SKalle Valo 35d5c65159SKalle Valo ath11k_peer_rx_tid_cleanup(ar, peer); 36d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 37d5c65159SKalle Valo } 38d5c65159SKalle Valo 39d5c65159SKalle Valo int ath11k_dp_peer_setup(struct ath11k *ar, int vdev_id, const u8 *addr) 40d5c65159SKalle Valo { 41d5c65159SKalle Valo struct ath11k_base *ab = ar->ab; 42d5c65159SKalle Valo u32 reo_dest; 43d5c65159SKalle Valo int ret; 44d5c65159SKalle Valo 45d5c65159SKalle Valo /* NOTE: reo_dest ring id starts from 1 unlike mac_id which starts from 0 */ 46d5c65159SKalle Valo reo_dest = ar->dp.mac_id + 1; 47d5c65159SKalle Valo ret = ath11k_wmi_set_peer_param(ar, addr, vdev_id, 48d5c65159SKalle Valo WMI_PEER_SET_DEFAULT_ROUTING, 49d5c65159SKalle Valo DP_RX_HASH_ENABLE | (reo_dest << 1)); 50d5c65159SKalle Valo 51d5c65159SKalle Valo if (ret) { 52d5c65159SKalle Valo ath11k_warn(ab, "failed to set default routing %d peer :%pM vdev_id :%d\n", 53d5c65159SKalle Valo ret, addr, vdev_id); 54d5c65159SKalle Valo return ret; 55d5c65159SKalle Valo } 56d5c65159SKalle Valo 57d5c65159SKalle Valo ret = ath11k_peer_rx_tid_setup(ar, addr, vdev_id, 58d5c65159SKalle Valo HAL_DESC_REO_NON_QOS_TID, 1, 0); 59d5c65159SKalle Valo if (ret) { 60d5c65159SKalle Valo ath11k_warn(ab, "failed to setup rxd tid queue for non-qos tid %d\n", 61d5c65159SKalle Valo ret); 62d5c65159SKalle Valo return ret; 63d5c65159SKalle Valo } 64d5c65159SKalle Valo 65d5c65159SKalle Valo ret = ath11k_peer_rx_tid_setup(ar, addr, vdev_id, 0, 1, 0); 66d5c65159SKalle Valo if (ret) { 67d5c65159SKalle Valo ath11k_warn(ab, "failed to setup rxd tid queue for tid 0 %d\n", 68d5c65159SKalle Valo ret); 69d5c65159SKalle Valo return ret; 70d5c65159SKalle Valo } 71d5c65159SKalle Valo 72d5c65159SKalle Valo /* TODO: Setup other peer specific resource used in data path */ 73d5c65159SKalle Valo 74d5c65159SKalle Valo return 0; 75d5c65159SKalle Valo } 76d5c65159SKalle Valo 77d5c65159SKalle Valo void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring) 78d5c65159SKalle Valo { 79d5c65159SKalle Valo if (!ring->vaddr_unaligned) 80d5c65159SKalle Valo return; 81d5c65159SKalle Valo 82d5c65159SKalle Valo dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned, 83d5c65159SKalle Valo ring->paddr_unaligned); 84d5c65159SKalle Valo 85d5c65159SKalle Valo ring->vaddr_unaligned = NULL; 86d5c65159SKalle Valo } 87d5c65159SKalle Valo 88d5c65159SKalle Valo int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, 89d5c65159SKalle Valo enum hal_ring_type type, int ring_num, 90d5c65159SKalle Valo int mac_id, int num_entries) 91d5c65159SKalle Valo { 92d5c65159SKalle Valo struct hal_srng_params params = { 0 }; 93d5c65159SKalle Valo int entry_sz = ath11k_hal_srng_get_entrysize(type); 94d5c65159SKalle Valo int max_entries = ath11k_hal_srng_get_max_entries(type); 95d5c65159SKalle Valo int ret; 96d5c65159SKalle Valo 97d5c65159SKalle Valo if (max_entries < 0 || entry_sz < 0) 98d5c65159SKalle Valo return -EINVAL; 99d5c65159SKalle Valo 100d5c65159SKalle Valo if (num_entries > max_entries) 101d5c65159SKalle Valo num_entries = max_entries; 102d5c65159SKalle Valo 103d5c65159SKalle Valo ring->size = (num_entries * entry_sz) + HAL_RING_BASE_ALIGN - 1; 104d5c65159SKalle Valo ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size, 105d5c65159SKalle Valo &ring->paddr_unaligned, 106d5c65159SKalle Valo GFP_KERNEL); 107d5c65159SKalle Valo if (!ring->vaddr_unaligned) 108d5c65159SKalle Valo return -ENOMEM; 109d5c65159SKalle Valo 110d5c65159SKalle Valo ring->vaddr = PTR_ALIGN(ring->vaddr_unaligned, HAL_RING_BASE_ALIGN); 111d5c65159SKalle Valo ring->paddr = ring->paddr_unaligned + ((unsigned long)ring->vaddr - 112d5c65159SKalle Valo (unsigned long)ring->vaddr_unaligned); 113d5c65159SKalle Valo 114d5c65159SKalle Valo params.ring_base_vaddr = ring->vaddr; 115d5c65159SKalle Valo params.ring_base_paddr = ring->paddr; 116d5c65159SKalle Valo params.num_entries = num_entries; 117d5c65159SKalle Valo 118d5c65159SKalle Valo switch (type) { 119d5c65159SKalle Valo case HAL_REO_DST: 120d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 121d5c65159SKalle Valo HAL_SRNG_INT_BATCH_THRESHOLD_RX; 122d5c65159SKalle Valo params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_RX; 123d5c65159SKalle Valo break; 124d5c65159SKalle Valo case HAL_RXDMA_BUF: 125d5c65159SKalle Valo case HAL_RXDMA_MONITOR_BUF: 126d5c65159SKalle Valo case HAL_RXDMA_MONITOR_STATUS: 127d5c65159SKalle Valo params.low_threshold = num_entries >> 3; 128d5c65159SKalle Valo params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; 129d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 0; 130d5c65159SKalle Valo params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_RX; 131d5c65159SKalle Valo break; 132d5c65159SKalle Valo case HAL_WBM2SW_RELEASE: 133d5c65159SKalle Valo if (ring_num < 3) { 134d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 135d5c65159SKalle Valo HAL_SRNG_INT_BATCH_THRESHOLD_TX; 136d5c65159SKalle Valo params.intr_timer_thres_us = 137d5c65159SKalle Valo HAL_SRNG_INT_TIMER_THRESHOLD_TX; 138d5c65159SKalle Valo break; 139d5c65159SKalle Valo } 140d5c65159SKalle Valo /* follow through when ring_num >= 3 */ 141d5c65159SKalle Valo /* fall through */ 142d5c65159SKalle Valo case HAL_REO_EXCEPTION: 143d5c65159SKalle Valo case HAL_REO_REINJECT: 144d5c65159SKalle Valo case HAL_REO_CMD: 145d5c65159SKalle Valo case HAL_REO_STATUS: 146d5c65159SKalle Valo case HAL_TCL_DATA: 147d5c65159SKalle Valo case HAL_TCL_CMD: 148d5c65159SKalle Valo case HAL_TCL_STATUS: 149d5c65159SKalle Valo case HAL_WBM_IDLE_LINK: 150d5c65159SKalle Valo case HAL_SW2WBM_RELEASE: 151d5c65159SKalle Valo case HAL_RXDMA_DST: 152d5c65159SKalle Valo case HAL_RXDMA_MONITOR_DST: 153d5c65159SKalle Valo case HAL_RXDMA_MONITOR_DESC: 154d5c65159SKalle Valo case HAL_RXDMA_DIR_BUF: 155d5c65159SKalle Valo params.intr_batch_cntr_thres_entries = 156d5c65159SKalle Valo HAL_SRNG_INT_BATCH_THRESHOLD_OTHER; 157d5c65159SKalle Valo params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_OTHER; 158d5c65159SKalle Valo break; 159d5c65159SKalle Valo default: 160d5c65159SKalle Valo ath11k_warn(ab, "Not a valid ring type in dp :%d\n", type); 161d5c65159SKalle Valo return -EINVAL; 162d5c65159SKalle Valo } 163d5c65159SKalle Valo 164d5c65159SKalle Valo ret = ath11k_hal_srng_setup(ab, type, ring_num, mac_id, ¶ms); 165d5c65159SKalle Valo if (ret < 0) { 166d5c65159SKalle Valo ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n", 167d5c65159SKalle Valo ret, ring_num); 168d5c65159SKalle Valo return ret; 169d5c65159SKalle Valo } 170d5c65159SKalle Valo 171d5c65159SKalle Valo ring->ring_id = ret; 172d5c65159SKalle Valo 173d5c65159SKalle Valo return 0; 174d5c65159SKalle Valo } 175d5c65159SKalle Valo 176d5c65159SKalle Valo static void ath11k_dp_srng_common_cleanup(struct ath11k_base *ab) 177d5c65159SKalle Valo { 178d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 179d5c65159SKalle Valo int i; 180d5c65159SKalle Valo 181d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->wbm_desc_rel_ring); 182d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->tcl_cmd_ring); 183d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->tcl_status_ring); 184d5c65159SKalle Valo for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { 185d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_data_ring); 186d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_comp_ring); 187d5c65159SKalle Valo } 188d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->reo_reinject_ring); 189d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->rx_rel_ring); 190d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->reo_except_ring); 191d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->reo_cmd_ring); 192d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, &dp->reo_status_ring); 193d5c65159SKalle Valo } 194d5c65159SKalle Valo 195d5c65159SKalle Valo static int ath11k_dp_srng_common_setup(struct ath11k_base *ab) 196d5c65159SKalle Valo { 197d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 198d5c65159SKalle Valo struct hal_srng *srng; 199d5c65159SKalle Valo int i, ret; 200d5c65159SKalle Valo 201d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->wbm_desc_rel_ring, 202d5c65159SKalle Valo HAL_SW2WBM_RELEASE, 0, 0, 203d5c65159SKalle Valo DP_WBM_RELEASE_RING_SIZE); 204d5c65159SKalle Valo if (ret) { 205d5c65159SKalle Valo ath11k_warn(ab, "failed to set up wbm2sw_release ring :%d\n", 206d5c65159SKalle Valo ret); 207d5c65159SKalle Valo goto err; 208d5c65159SKalle Valo } 209d5c65159SKalle Valo 210d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->tcl_cmd_ring, HAL_TCL_CMD, 0, 0, 211d5c65159SKalle Valo DP_TCL_CMD_RING_SIZE); 212d5c65159SKalle Valo if (ret) { 213d5c65159SKalle Valo ath11k_warn(ab, "failed to set up tcl_cmd ring :%d\n", ret); 214d5c65159SKalle Valo goto err; 215d5c65159SKalle Valo } 216d5c65159SKalle Valo 217d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->tcl_status_ring, HAL_TCL_STATUS, 218d5c65159SKalle Valo 0, 0, DP_TCL_STATUS_RING_SIZE); 219d5c65159SKalle Valo if (ret) { 220d5c65159SKalle Valo ath11k_warn(ab, "failed to set up tcl_status ring :%d\n", ret); 221d5c65159SKalle Valo goto err; 222d5c65159SKalle Valo } 223d5c65159SKalle Valo 224d5c65159SKalle Valo for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { 225d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_data_ring, 226d5c65159SKalle Valo HAL_TCL_DATA, i, 0, 227d5c65159SKalle Valo DP_TCL_DATA_RING_SIZE); 228d5c65159SKalle Valo if (ret) { 229d5c65159SKalle Valo ath11k_warn(ab, "failed to set up tcl_data ring (%d) :%d\n", 230d5c65159SKalle Valo i, ret); 231d5c65159SKalle Valo goto err; 232d5c65159SKalle Valo } 233d5c65159SKalle Valo 234d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_comp_ring, 235d5c65159SKalle Valo HAL_WBM2SW_RELEASE, i, 0, 236d5c65159SKalle Valo DP_TX_COMP_RING_SIZE); 237d5c65159SKalle Valo if (ret) { 238d5c65159SKalle Valo ath11k_warn(ab, "failed to set up tcl_comp ring ring (%d) :%d\n", 239d5c65159SKalle Valo i, ret); 240d5c65159SKalle Valo goto err; 241d5c65159SKalle Valo } 242d5c65159SKalle Valo 243d5c65159SKalle Valo srng = &ab->hal.srng_list[dp->tx_ring[i].tcl_data_ring.ring_id]; 244d5c65159SKalle Valo ath11k_hal_tx_init_data_ring(ab, srng); 245d5c65159SKalle Valo } 246d5c65159SKalle Valo 247d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->reo_reinject_ring, HAL_REO_REINJECT, 248d5c65159SKalle Valo 0, 0, DP_REO_REINJECT_RING_SIZE); 249d5c65159SKalle Valo if (ret) { 250d5c65159SKalle Valo ath11k_warn(ab, "failed to set up reo_reinject ring :%d\n", 251d5c65159SKalle Valo ret); 252d5c65159SKalle Valo goto err; 253d5c65159SKalle Valo } 254d5c65159SKalle Valo 255d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->rx_rel_ring, HAL_WBM2SW_RELEASE, 256d5c65159SKalle Valo 3, 0, DP_RX_RELEASE_RING_SIZE); 257d5c65159SKalle Valo if (ret) { 258d5c65159SKalle Valo ath11k_warn(ab, "failed to set up rx_rel ring :%d\n", ret); 259d5c65159SKalle Valo goto err; 260d5c65159SKalle Valo } 261d5c65159SKalle Valo 262d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->reo_except_ring, HAL_REO_EXCEPTION, 263d5c65159SKalle Valo 0, 0, DP_REO_EXCEPTION_RING_SIZE); 264d5c65159SKalle Valo if (ret) { 265d5c65159SKalle Valo ath11k_warn(ab, "failed to set up reo_exception ring :%d\n", 266d5c65159SKalle Valo ret); 267d5c65159SKalle Valo goto err; 268d5c65159SKalle Valo } 269d5c65159SKalle Valo 270d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->reo_cmd_ring, HAL_REO_CMD, 271d5c65159SKalle Valo 0, 0, DP_REO_CMD_RING_SIZE); 272d5c65159SKalle Valo if (ret) { 273d5c65159SKalle Valo ath11k_warn(ab, "failed to set up reo_cmd ring :%d\n", ret); 274d5c65159SKalle Valo goto err; 275d5c65159SKalle Valo } 276d5c65159SKalle Valo 277d5c65159SKalle Valo srng = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id]; 278d5c65159SKalle Valo ath11k_hal_reo_init_cmd_ring(ab, srng); 279d5c65159SKalle Valo 280d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->reo_status_ring, HAL_REO_STATUS, 281d5c65159SKalle Valo 0, 0, DP_REO_STATUS_RING_SIZE); 282d5c65159SKalle Valo if (ret) { 283d5c65159SKalle Valo ath11k_warn(ab, "failed to set up reo_status ring :%d\n", ret); 284d5c65159SKalle Valo goto err; 285d5c65159SKalle Valo } 286d5c65159SKalle Valo 287d5c65159SKalle Valo ath11k_hal_reo_hw_setup(ab); 288d5c65159SKalle Valo 289d5c65159SKalle Valo return 0; 290d5c65159SKalle Valo 291d5c65159SKalle Valo err: 292d5c65159SKalle Valo ath11k_dp_srng_common_cleanup(ab); 293d5c65159SKalle Valo 294d5c65159SKalle Valo return ret; 295d5c65159SKalle Valo } 296d5c65159SKalle Valo 297d5c65159SKalle Valo static void ath11k_dp_scatter_idle_link_desc_cleanup(struct ath11k_base *ab) 298d5c65159SKalle Valo { 299d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 300d5c65159SKalle Valo struct hal_wbm_idle_scatter_list *slist = dp->scatter_list; 301d5c65159SKalle Valo int i; 302d5c65159SKalle Valo 303d5c65159SKalle Valo for (i = 0; i < DP_IDLE_SCATTER_BUFS_MAX; i++) { 304d5c65159SKalle Valo if (!slist[i].vaddr) 305d5c65159SKalle Valo continue; 306d5c65159SKalle Valo 307d5c65159SKalle Valo dma_free_coherent(ab->dev, HAL_WBM_IDLE_SCATTER_BUF_SIZE_MAX, 308d5c65159SKalle Valo slist[i].vaddr, slist[i].paddr); 309d5c65159SKalle Valo slist[i].vaddr = NULL; 310d5c65159SKalle Valo } 311d5c65159SKalle Valo } 312d5c65159SKalle Valo 313d5c65159SKalle Valo static int ath11k_dp_scatter_idle_link_desc_setup(struct ath11k_base *ab, 314d5c65159SKalle Valo int size, 315d5c65159SKalle Valo u32 n_link_desc_bank, 316d5c65159SKalle Valo u32 n_link_desc, 317d5c65159SKalle Valo u32 last_bank_sz) 318d5c65159SKalle Valo { 319d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 320d5c65159SKalle Valo struct dp_link_desc_bank *link_desc_banks = dp->link_desc_banks; 321d5c65159SKalle Valo struct hal_wbm_idle_scatter_list *slist = dp->scatter_list; 322d5c65159SKalle Valo u32 n_entries_per_buf; 323d5c65159SKalle Valo int num_scatter_buf, scatter_idx; 324d5c65159SKalle Valo struct hal_wbm_link_desc *scatter_buf; 325d5c65159SKalle Valo int align_bytes, n_entries; 326d5c65159SKalle Valo dma_addr_t paddr; 327d5c65159SKalle Valo int rem_entries; 328d5c65159SKalle Valo int i; 329d5c65159SKalle Valo int ret = 0; 330d5c65159SKalle Valo u32 end_offset; 331d5c65159SKalle Valo 332d5c65159SKalle Valo n_entries_per_buf = HAL_WBM_IDLE_SCATTER_BUF_SIZE / 333d5c65159SKalle Valo ath11k_hal_srng_get_entrysize(HAL_WBM_IDLE_LINK); 334d5c65159SKalle Valo num_scatter_buf = DIV_ROUND_UP(size, HAL_WBM_IDLE_SCATTER_BUF_SIZE); 335d5c65159SKalle Valo 336d5c65159SKalle Valo if (num_scatter_buf > DP_IDLE_SCATTER_BUFS_MAX) 337d5c65159SKalle Valo return -EINVAL; 338d5c65159SKalle Valo 339d5c65159SKalle Valo for (i = 0; i < num_scatter_buf; i++) { 340d5c65159SKalle Valo slist[i].vaddr = dma_alloc_coherent(ab->dev, 341d5c65159SKalle Valo HAL_WBM_IDLE_SCATTER_BUF_SIZE_MAX, 342d5c65159SKalle Valo &slist[i].paddr, GFP_KERNEL); 343d5c65159SKalle Valo if (!slist[i].vaddr) { 344d5c65159SKalle Valo ret = -ENOMEM; 345d5c65159SKalle Valo goto err; 346d5c65159SKalle Valo } 347d5c65159SKalle Valo } 348d5c65159SKalle Valo 349d5c65159SKalle Valo scatter_idx = 0; 350d5c65159SKalle Valo scatter_buf = slist[scatter_idx].vaddr; 351d5c65159SKalle Valo rem_entries = n_entries_per_buf; 352d5c65159SKalle Valo 353d5c65159SKalle Valo for (i = 0; i < n_link_desc_bank; i++) { 354d5c65159SKalle Valo align_bytes = link_desc_banks[i].vaddr - 355d5c65159SKalle Valo link_desc_banks[i].vaddr_unaligned; 356d5c65159SKalle Valo n_entries = (DP_LINK_DESC_ALLOC_SIZE_THRESH - align_bytes) / 357d5c65159SKalle Valo HAL_LINK_DESC_SIZE; 358d5c65159SKalle Valo paddr = link_desc_banks[i].paddr; 359d5c65159SKalle Valo while (n_entries) { 360d5c65159SKalle Valo ath11k_hal_set_link_desc_addr(scatter_buf, i, paddr); 361d5c65159SKalle Valo n_entries--; 362d5c65159SKalle Valo paddr += HAL_LINK_DESC_SIZE; 363d5c65159SKalle Valo if (rem_entries) { 364d5c65159SKalle Valo rem_entries--; 365d5c65159SKalle Valo scatter_buf++; 366d5c65159SKalle Valo continue; 367d5c65159SKalle Valo } 368d5c65159SKalle Valo 369d5c65159SKalle Valo rem_entries = n_entries_per_buf; 370d5c65159SKalle Valo scatter_idx++; 371d5c65159SKalle Valo scatter_buf = slist[scatter_idx].vaddr; 372d5c65159SKalle Valo } 373d5c65159SKalle Valo } 374d5c65159SKalle Valo 375d5c65159SKalle Valo end_offset = (scatter_buf - slist[scatter_idx].vaddr) * 376d5c65159SKalle Valo sizeof(struct hal_wbm_link_desc); 377d5c65159SKalle Valo ath11k_hal_setup_link_idle_list(ab, slist, num_scatter_buf, 378d5c65159SKalle Valo n_link_desc, end_offset); 379d5c65159SKalle Valo 380d5c65159SKalle Valo return 0; 381d5c65159SKalle Valo 382d5c65159SKalle Valo err: 383d5c65159SKalle Valo ath11k_dp_scatter_idle_link_desc_cleanup(ab); 384d5c65159SKalle Valo 385d5c65159SKalle Valo return ret; 386d5c65159SKalle Valo } 387d5c65159SKalle Valo 388d5c65159SKalle Valo static void 389d5c65159SKalle Valo ath11k_dp_link_desc_bank_free(struct ath11k_base *ab, 390d5c65159SKalle Valo struct dp_link_desc_bank *link_desc_banks) 391d5c65159SKalle Valo { 392d5c65159SKalle Valo int i; 393d5c65159SKalle Valo 394d5c65159SKalle Valo for (i = 0; i < DP_LINK_DESC_BANKS_MAX; i++) { 395d5c65159SKalle Valo if (link_desc_banks[i].vaddr_unaligned) { 396d5c65159SKalle Valo dma_free_coherent(ab->dev, 397d5c65159SKalle Valo link_desc_banks[i].size, 398d5c65159SKalle Valo link_desc_banks[i].vaddr_unaligned, 399d5c65159SKalle Valo link_desc_banks[i].paddr_unaligned); 400d5c65159SKalle Valo link_desc_banks[i].vaddr_unaligned = NULL; 401d5c65159SKalle Valo } 402d5c65159SKalle Valo } 403d5c65159SKalle Valo } 404d5c65159SKalle Valo 405d5c65159SKalle Valo static int ath11k_dp_link_desc_bank_alloc(struct ath11k_base *ab, 406d5c65159SKalle Valo struct dp_link_desc_bank *desc_bank, 407d5c65159SKalle Valo int n_link_desc_bank, 408d5c65159SKalle Valo int last_bank_sz) 409d5c65159SKalle Valo { 410d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 411d5c65159SKalle Valo int i; 412d5c65159SKalle Valo int ret = 0; 413d5c65159SKalle Valo int desc_sz = DP_LINK_DESC_ALLOC_SIZE_THRESH; 414d5c65159SKalle Valo 415d5c65159SKalle Valo for (i = 0; i < n_link_desc_bank; i++) { 416d5c65159SKalle Valo if (i == (n_link_desc_bank - 1) && last_bank_sz) 417d5c65159SKalle Valo desc_sz = last_bank_sz; 418d5c65159SKalle Valo 419d5c65159SKalle Valo desc_bank[i].vaddr_unaligned = 420d5c65159SKalle Valo dma_alloc_coherent(ab->dev, desc_sz, 421d5c65159SKalle Valo &desc_bank[i].paddr_unaligned, 422d5c65159SKalle Valo GFP_KERNEL); 423d5c65159SKalle Valo if (!desc_bank[i].vaddr_unaligned) { 424d5c65159SKalle Valo ret = -ENOMEM; 425d5c65159SKalle Valo goto err; 426d5c65159SKalle Valo } 427d5c65159SKalle Valo 428d5c65159SKalle Valo desc_bank[i].vaddr = PTR_ALIGN(desc_bank[i].vaddr_unaligned, 429d5c65159SKalle Valo HAL_LINK_DESC_ALIGN); 430d5c65159SKalle Valo desc_bank[i].paddr = desc_bank[i].paddr_unaligned + 431d5c65159SKalle Valo ((unsigned long)desc_bank[i].vaddr - 432d5c65159SKalle Valo (unsigned long)desc_bank[i].vaddr_unaligned); 433d5c65159SKalle Valo desc_bank[i].size = desc_sz; 434d5c65159SKalle Valo } 435d5c65159SKalle Valo 436d5c65159SKalle Valo return 0; 437d5c65159SKalle Valo 438d5c65159SKalle Valo err: 439d5c65159SKalle Valo ath11k_dp_link_desc_bank_free(ab, dp->link_desc_banks); 440d5c65159SKalle Valo 441d5c65159SKalle Valo return ret; 442d5c65159SKalle Valo } 443d5c65159SKalle Valo 444d5c65159SKalle Valo void ath11k_dp_link_desc_cleanup(struct ath11k_base *ab, 445d5c65159SKalle Valo struct dp_link_desc_bank *desc_bank, 446d5c65159SKalle Valo u32 ring_type, struct dp_srng *ring) 447d5c65159SKalle Valo { 448d5c65159SKalle Valo ath11k_dp_link_desc_bank_free(ab, desc_bank); 449d5c65159SKalle Valo 450d5c65159SKalle Valo if (ring_type != HAL_RXDMA_MONITOR_DESC) { 451d5c65159SKalle Valo ath11k_dp_srng_cleanup(ab, ring); 452d5c65159SKalle Valo ath11k_dp_scatter_idle_link_desc_cleanup(ab); 453d5c65159SKalle Valo } 454d5c65159SKalle Valo } 455d5c65159SKalle Valo 456d5c65159SKalle Valo static int ath11k_wbm_idle_ring_setup(struct ath11k_base *ab, u32 *n_link_desc) 457d5c65159SKalle Valo { 458d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 459d5c65159SKalle Valo u32 n_mpdu_link_desc, n_mpdu_queue_desc; 460d5c65159SKalle Valo u32 n_tx_msdu_link_desc, n_rx_msdu_link_desc; 461d5c65159SKalle Valo int ret = 0; 462d5c65159SKalle Valo 463d5c65159SKalle Valo n_mpdu_link_desc = (DP_NUM_TIDS_MAX * DP_AVG_MPDUS_PER_TID_MAX) / 464d5c65159SKalle Valo HAL_NUM_MPDUS_PER_LINK_DESC; 465d5c65159SKalle Valo 466d5c65159SKalle Valo n_mpdu_queue_desc = n_mpdu_link_desc / 467d5c65159SKalle Valo HAL_NUM_MPDU_LINKS_PER_QUEUE_DESC; 468d5c65159SKalle Valo 469d5c65159SKalle Valo n_tx_msdu_link_desc = (DP_NUM_TIDS_MAX * DP_AVG_FLOWS_PER_TID * 470d5c65159SKalle Valo DP_AVG_MSDUS_PER_FLOW) / 471d5c65159SKalle Valo HAL_NUM_TX_MSDUS_PER_LINK_DESC; 472d5c65159SKalle Valo 473d5c65159SKalle Valo n_rx_msdu_link_desc = (DP_NUM_TIDS_MAX * DP_AVG_MPDUS_PER_TID_MAX * 474d5c65159SKalle Valo DP_AVG_MSDUS_PER_MPDU) / 475d5c65159SKalle Valo HAL_NUM_RX_MSDUS_PER_LINK_DESC; 476d5c65159SKalle Valo 477d5c65159SKalle Valo *n_link_desc = n_mpdu_link_desc + n_mpdu_queue_desc + 478d5c65159SKalle Valo n_tx_msdu_link_desc + n_rx_msdu_link_desc; 479d5c65159SKalle Valo 480051cefa4SVasanthakumar Thiagarajan if (*n_link_desc & (*n_link_desc - 1)) 481051cefa4SVasanthakumar Thiagarajan *n_link_desc = 1 << fls(*n_link_desc); 482051cefa4SVasanthakumar Thiagarajan 483d5c65159SKalle Valo ret = ath11k_dp_srng_setup(ab, &dp->wbm_idle_ring, 484d5c65159SKalle Valo HAL_WBM_IDLE_LINK, 0, 0, *n_link_desc); 485d5c65159SKalle Valo if (ret) { 486d5c65159SKalle Valo ath11k_warn(ab, "failed to setup wbm_idle_ring: %d\n", ret); 487d5c65159SKalle Valo return ret; 488d5c65159SKalle Valo } 489d5c65159SKalle Valo return ret; 490d5c65159SKalle Valo } 491d5c65159SKalle Valo 492d5c65159SKalle Valo int ath11k_dp_link_desc_setup(struct ath11k_base *ab, 493d5c65159SKalle Valo struct dp_link_desc_bank *link_desc_banks, 494d5c65159SKalle Valo u32 ring_type, struct hal_srng *srng, 495d5c65159SKalle Valo u32 n_link_desc) 496d5c65159SKalle Valo { 497d5c65159SKalle Valo u32 tot_mem_sz; 498d5c65159SKalle Valo u32 n_link_desc_bank, last_bank_sz; 499d5c65159SKalle Valo u32 entry_sz, align_bytes, n_entries; 500d5c65159SKalle Valo u32 paddr; 501d5c65159SKalle Valo u32 *desc; 502d5c65159SKalle Valo int i, ret; 503d5c65159SKalle Valo 504d5c65159SKalle Valo tot_mem_sz = n_link_desc * HAL_LINK_DESC_SIZE; 505d5c65159SKalle Valo tot_mem_sz += HAL_LINK_DESC_ALIGN; 506d5c65159SKalle Valo 507d5c65159SKalle Valo if (tot_mem_sz <= DP_LINK_DESC_ALLOC_SIZE_THRESH) { 508d5c65159SKalle Valo n_link_desc_bank = 1; 509d5c65159SKalle Valo last_bank_sz = tot_mem_sz; 510d5c65159SKalle Valo } else { 511d5c65159SKalle Valo n_link_desc_bank = tot_mem_sz / 512d5c65159SKalle Valo (DP_LINK_DESC_ALLOC_SIZE_THRESH - 513d5c65159SKalle Valo HAL_LINK_DESC_ALIGN); 514d5c65159SKalle Valo last_bank_sz = tot_mem_sz % 515d5c65159SKalle Valo (DP_LINK_DESC_ALLOC_SIZE_THRESH - 516d5c65159SKalle Valo HAL_LINK_DESC_ALIGN); 517d5c65159SKalle Valo 518d5c65159SKalle Valo if (last_bank_sz) 519d5c65159SKalle Valo n_link_desc_bank += 1; 520d5c65159SKalle Valo } 521d5c65159SKalle Valo 522d5c65159SKalle Valo if (n_link_desc_bank > DP_LINK_DESC_BANKS_MAX) 523d5c65159SKalle Valo return -EINVAL; 524d5c65159SKalle Valo 525d5c65159SKalle Valo ret = ath11k_dp_link_desc_bank_alloc(ab, link_desc_banks, 526d5c65159SKalle Valo n_link_desc_bank, last_bank_sz); 527d5c65159SKalle Valo if (ret) 528d5c65159SKalle Valo return ret; 529d5c65159SKalle Valo 530d5c65159SKalle Valo /* Setup link desc idle list for HW internal usage */ 531d5c65159SKalle Valo entry_sz = ath11k_hal_srng_get_entrysize(ring_type); 532d5c65159SKalle Valo tot_mem_sz = entry_sz * n_link_desc; 533d5c65159SKalle Valo 534d5c65159SKalle Valo /* Setup scatter desc list when the total memory requirement is more */ 535d5c65159SKalle Valo if (tot_mem_sz > DP_LINK_DESC_ALLOC_SIZE_THRESH && 536d5c65159SKalle Valo ring_type != HAL_RXDMA_MONITOR_DESC) { 537d5c65159SKalle Valo ret = ath11k_dp_scatter_idle_link_desc_setup(ab, tot_mem_sz, 538d5c65159SKalle Valo n_link_desc_bank, 539d5c65159SKalle Valo n_link_desc, 540d5c65159SKalle Valo last_bank_sz); 541d5c65159SKalle Valo if (ret) { 542d5c65159SKalle Valo ath11k_warn(ab, "failed to setup scatting idle list descriptor :%d\n", 543d5c65159SKalle Valo ret); 544d5c65159SKalle Valo goto fail_desc_bank_free; 545d5c65159SKalle Valo } 546d5c65159SKalle Valo 547d5c65159SKalle Valo return 0; 548d5c65159SKalle Valo } 549d5c65159SKalle Valo 550d5c65159SKalle Valo spin_lock_bh(&srng->lock); 551d5c65159SKalle Valo 552d5c65159SKalle Valo ath11k_hal_srng_access_begin(ab, srng); 553d5c65159SKalle Valo 554d5c65159SKalle Valo for (i = 0; i < n_link_desc_bank; i++) { 555d5c65159SKalle Valo align_bytes = link_desc_banks[i].vaddr - 556d5c65159SKalle Valo link_desc_banks[i].vaddr_unaligned; 557d5c65159SKalle Valo n_entries = (link_desc_banks[i].size - align_bytes) / 558d5c65159SKalle Valo HAL_LINK_DESC_SIZE; 559d5c65159SKalle Valo paddr = link_desc_banks[i].paddr; 560d5c65159SKalle Valo while (n_entries && 561d5c65159SKalle Valo (desc = ath11k_hal_srng_src_get_next_entry(ab, srng))) { 562d5c65159SKalle Valo ath11k_hal_set_link_desc_addr((struct hal_wbm_link_desc *)desc, 563d5c65159SKalle Valo i, paddr); 564d5c65159SKalle Valo n_entries--; 565d5c65159SKalle Valo paddr += HAL_LINK_DESC_SIZE; 566d5c65159SKalle Valo } 567d5c65159SKalle Valo } 568d5c65159SKalle Valo 569d5c65159SKalle Valo ath11k_hal_srng_access_end(ab, srng); 570d5c65159SKalle Valo 571d5c65159SKalle Valo spin_unlock_bh(&srng->lock); 572d5c65159SKalle Valo 573d5c65159SKalle Valo return 0; 574d5c65159SKalle Valo 575d5c65159SKalle Valo fail_desc_bank_free: 576d5c65159SKalle Valo ath11k_dp_link_desc_bank_free(ab, link_desc_banks); 577d5c65159SKalle Valo 578d5c65159SKalle Valo return ret; 579d5c65159SKalle Valo } 580d5c65159SKalle Valo 581d5c65159SKalle Valo int ath11k_dp_service_srng(struct ath11k_base *ab, 582d5c65159SKalle Valo struct ath11k_ext_irq_grp *irq_grp, 583d5c65159SKalle Valo int budget) 584d5c65159SKalle Valo { 585d5c65159SKalle Valo struct napi_struct *napi = &irq_grp->napi; 586d5c65159SKalle Valo int grp_id = irq_grp->grp_id; 587d5c65159SKalle Valo int work_done = 0; 588d5c65159SKalle Valo int i = 0; 589d5c65159SKalle Valo int tot_work_done = 0; 590d5c65159SKalle Valo 591d5c65159SKalle Valo while (ath11k_tx_ring_mask[grp_id] >> i) { 592d5c65159SKalle Valo if (ath11k_tx_ring_mask[grp_id] & BIT(i)) 593d5c65159SKalle Valo ath11k_dp_tx_completion_handler(ab, i); 594d5c65159SKalle Valo i++; 595d5c65159SKalle Valo } 596d5c65159SKalle Valo 597d5c65159SKalle Valo if (ath11k_rx_err_ring_mask[grp_id]) { 598d5c65159SKalle Valo work_done = ath11k_dp_process_rx_err(ab, napi, budget); 599d5c65159SKalle Valo budget -= work_done; 600d5c65159SKalle Valo tot_work_done += work_done; 601d5c65159SKalle Valo if (budget <= 0) 602d5c65159SKalle Valo goto done; 603d5c65159SKalle Valo } 604d5c65159SKalle Valo 605d5c65159SKalle Valo if (ath11k_rx_wbm_rel_ring_mask[grp_id]) { 606d5c65159SKalle Valo work_done = ath11k_dp_rx_process_wbm_err(ab, 607d5c65159SKalle Valo napi, 608d5c65159SKalle Valo budget); 609d5c65159SKalle Valo budget -= work_done; 610d5c65159SKalle Valo tot_work_done += work_done; 611d5c65159SKalle Valo 612d5c65159SKalle Valo if (budget <= 0) 613d5c65159SKalle Valo goto done; 614d5c65159SKalle Valo } 615d5c65159SKalle Valo 616d5c65159SKalle Valo if (ath11k_rx_ring_mask[grp_id]) { 617d5c65159SKalle Valo for (i = 0; i < ab->num_radios; i++) { 618d5c65159SKalle Valo if (ath11k_rx_ring_mask[grp_id] & BIT(i)) { 619d5c65159SKalle Valo work_done = ath11k_dp_process_rx(ab, i, napi, 620d5c65159SKalle Valo &irq_grp->pending_q, 621d5c65159SKalle Valo budget); 622d5c65159SKalle Valo budget -= work_done; 623d5c65159SKalle Valo tot_work_done += work_done; 624d5c65159SKalle Valo } 625d5c65159SKalle Valo if (budget <= 0) 626d5c65159SKalle Valo goto done; 627d5c65159SKalle Valo } 628d5c65159SKalle Valo } 629d5c65159SKalle Valo 630d5c65159SKalle Valo if (rx_mon_status_ring_mask[grp_id]) { 631d5c65159SKalle Valo for (i = 0; i < ab->num_radios; i++) { 632d5c65159SKalle Valo if (rx_mon_status_ring_mask[grp_id] & BIT(i)) { 633d5c65159SKalle Valo work_done = 634d5c65159SKalle Valo ath11k_dp_rx_process_mon_rings(ab, 635d5c65159SKalle Valo i, napi, 636d5c65159SKalle Valo budget); 637d5c65159SKalle Valo budget -= work_done; 638d5c65159SKalle Valo tot_work_done += work_done; 639d5c65159SKalle Valo } 640d5c65159SKalle Valo if (budget <= 0) 641d5c65159SKalle Valo goto done; 642d5c65159SKalle Valo } 643d5c65159SKalle Valo } 644d5c65159SKalle Valo 645d5c65159SKalle Valo if (ath11k_reo_status_ring_mask[grp_id]) 646d5c65159SKalle Valo ath11k_dp_process_reo_status(ab); 647d5c65159SKalle Valo 648d5c65159SKalle Valo for (i = 0; i < ab->num_radios; i++) { 649d5c65159SKalle Valo if (ath11k_rxdma2host_ring_mask[grp_id] & BIT(i)) { 650d5c65159SKalle Valo work_done = ath11k_dp_process_rxdma_err(ab, i, budget); 651d5c65159SKalle Valo budget -= work_done; 652d5c65159SKalle Valo tot_work_done += work_done; 653d5c65159SKalle Valo } 654d5c65159SKalle Valo 655d5c65159SKalle Valo if (budget <= 0) 656d5c65159SKalle Valo goto done; 657d5c65159SKalle Valo 658d5c65159SKalle Valo if (ath11k_host2rxdma_ring_mask[grp_id] & BIT(i)) { 659d5c65159SKalle Valo struct ath11k_pdev_dp *dp = &ab->pdevs[i].ar->dp; 660d5c65159SKalle Valo struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; 661d5c65159SKalle Valo 662d5c65159SKalle Valo ath11k_dp_rxbufs_replenish(ab, i, rx_ring, 0, 663d5c65159SKalle Valo HAL_RX_BUF_RBM_SW3_BM, 664d5c65159SKalle Valo GFP_ATOMIC); 665d5c65159SKalle Valo } 666d5c65159SKalle Valo } 667d5c65159SKalle Valo /* TODO: Implement handler for other interrupts */ 668d5c65159SKalle Valo 669d5c65159SKalle Valo done: 670d5c65159SKalle Valo return tot_work_done; 671d5c65159SKalle Valo } 672d5c65159SKalle Valo 673d5c65159SKalle Valo void ath11k_dp_pdev_free(struct ath11k_base *ab) 674d5c65159SKalle Valo { 675d5c65159SKalle Valo struct ath11k *ar; 676d5c65159SKalle Valo int i; 677d5c65159SKalle Valo 678d5c65159SKalle Valo for (i = 0; i < ab->num_radios; i++) { 679d5c65159SKalle Valo ar = ab->pdevs[i].ar; 680d5c65159SKalle Valo ath11k_dp_rx_pdev_free(ab, i); 681d5c65159SKalle Valo ath11k_debug_unregister(ar); 682d5c65159SKalle Valo ath11k_dp_rx_pdev_mon_detach(ar); 683d5c65159SKalle Valo } 684d5c65159SKalle Valo } 685d5c65159SKalle Valo 6869c57d7e3SVasanthakumar Thiagarajan void ath11k_dp_pdev_pre_alloc(struct ath11k_base *ab) 687d5c65159SKalle Valo { 688d5c65159SKalle Valo struct ath11k *ar; 689d5c65159SKalle Valo struct ath11k_pdev_dp *dp; 690d5c65159SKalle Valo int i; 691d5c65159SKalle Valo 692d5c65159SKalle Valo for (i = 0; i < ab->num_radios; i++) { 693d5c65159SKalle Valo ar = ab->pdevs[i].ar; 694d5c65159SKalle Valo dp = &ar->dp; 695d5c65159SKalle Valo dp->mac_id = i; 696d5c65159SKalle Valo idr_init(&dp->rx_refill_buf_ring.bufs_idr); 697d5c65159SKalle Valo spin_lock_init(&dp->rx_refill_buf_ring.idr_lock); 698d5c65159SKalle Valo atomic_set(&dp->num_tx_pending, 0); 699d5c65159SKalle Valo init_waitqueue_head(&dp->tx_empty_waitq); 700d5c65159SKalle Valo idr_init(&dp->rx_mon_status_refill_ring.bufs_idr); 701d5c65159SKalle Valo spin_lock_init(&dp->rx_mon_status_refill_ring.idr_lock); 702d5c65159SKalle Valo idr_init(&dp->rxdma_mon_buf_ring.bufs_idr); 703d5c65159SKalle Valo spin_lock_init(&dp->rxdma_mon_buf_ring.idr_lock); 704d5c65159SKalle Valo } 7059c57d7e3SVasanthakumar Thiagarajan } 7069c57d7e3SVasanthakumar Thiagarajan 7079c57d7e3SVasanthakumar Thiagarajan int ath11k_dp_pdev_alloc(struct ath11k_base *ab) 7089c57d7e3SVasanthakumar Thiagarajan { 7099c57d7e3SVasanthakumar Thiagarajan struct ath11k *ar; 7109c57d7e3SVasanthakumar Thiagarajan int ret; 7119c57d7e3SVasanthakumar Thiagarajan int i; 712d5c65159SKalle Valo 713d5c65159SKalle Valo /* TODO:Per-pdev rx ring unlike tx ring which is mapped to different AC's */ 714d5c65159SKalle Valo for (i = 0; i < ab->num_radios; i++) { 715d5c65159SKalle Valo ar = ab->pdevs[i].ar; 716d5c65159SKalle Valo ret = ath11k_dp_rx_pdev_alloc(ab, i); 717d5c65159SKalle Valo if (ret) { 718d5c65159SKalle Valo ath11k_warn(ab, "failed to allocate pdev rx for pdev_id :%d\n", 719d5c65159SKalle Valo i); 720d5c65159SKalle Valo goto err; 721d5c65159SKalle Valo } 722d5c65159SKalle Valo ret = ath11k_dp_rx_pdev_mon_attach(ar); 723d5c65159SKalle Valo if (ret) { 724d5c65159SKalle Valo ath11k_warn(ab, "failed to initialize mon pdev %d\n", 725d5c65159SKalle Valo i); 726d5c65159SKalle Valo goto err; 727d5c65159SKalle Valo } 728d5c65159SKalle Valo } 729d5c65159SKalle Valo 730d5c65159SKalle Valo return 0; 731d5c65159SKalle Valo 732d5c65159SKalle Valo err: 733d5c65159SKalle Valo ath11k_dp_pdev_free(ab); 734d5c65159SKalle Valo 735d5c65159SKalle Valo return ret; 736d5c65159SKalle Valo } 737d5c65159SKalle Valo 738d5c65159SKalle Valo int ath11k_dp_htt_connect(struct ath11k_dp *dp) 739d5c65159SKalle Valo { 740d5c65159SKalle Valo struct ath11k_htc_svc_conn_req conn_req; 741d5c65159SKalle Valo struct ath11k_htc_svc_conn_resp conn_resp; 742d5c65159SKalle Valo int status; 743d5c65159SKalle Valo 744d5c65159SKalle Valo memset(&conn_req, 0, sizeof(conn_req)); 745d5c65159SKalle Valo memset(&conn_resp, 0, sizeof(conn_resp)); 746d5c65159SKalle Valo 747d5c65159SKalle Valo conn_req.ep_ops.ep_tx_complete = ath11k_dp_htt_htc_tx_complete; 748d5c65159SKalle Valo conn_req.ep_ops.ep_rx_complete = ath11k_dp_htt_htc_t2h_msg_handler; 749d5c65159SKalle Valo 750d5c65159SKalle Valo /* connect to control service */ 751d5c65159SKalle Valo conn_req.service_id = ATH11K_HTC_SVC_ID_HTT_DATA_MSG; 752d5c65159SKalle Valo 753d5c65159SKalle Valo status = ath11k_htc_connect_service(&dp->ab->htc, &conn_req, 754d5c65159SKalle Valo &conn_resp); 755d5c65159SKalle Valo 756d5c65159SKalle Valo if (status) 757d5c65159SKalle Valo return status; 758d5c65159SKalle Valo 759d5c65159SKalle Valo dp->eid = conn_resp.eid; 760d5c65159SKalle Valo 761d5c65159SKalle Valo return 0; 762d5c65159SKalle Valo } 763d5c65159SKalle Valo 764d5c65159SKalle Valo static void ath11k_dp_update_vdev_search(struct ath11k_vif *arvif) 765d5c65159SKalle Valo { 7660f37fbf4SAnilkumar Kolli /* For STA mode, enable address search index, 7670f37fbf4SAnilkumar Kolli * tcl uses ast_hash value in the descriptor. 768d5c65159SKalle Valo */ 769d5c65159SKalle Valo switch (arvif->vdev_type) { 770d5c65159SKalle Valo case WMI_VDEV_TYPE_STA: 7710f37fbf4SAnilkumar Kolli arvif->hal_addr_search_flags = HAL_TX_ADDRX_EN; 772d5c65159SKalle Valo arvif->search_type = HAL_TX_ADDR_SEARCH_INDEX; 773d5c65159SKalle Valo break; 774d5c65159SKalle Valo case WMI_VDEV_TYPE_AP: 775d5c65159SKalle Valo case WMI_VDEV_TYPE_IBSS: 776d5c65159SKalle Valo arvif->hal_addr_search_flags = HAL_TX_ADDRX_EN; 777d5c65159SKalle Valo arvif->search_type = HAL_TX_ADDR_SEARCH_DEFAULT; 778d5c65159SKalle Valo break; 779d5c65159SKalle Valo case WMI_VDEV_TYPE_MONITOR: 780d5c65159SKalle Valo default: 781d5c65159SKalle Valo return; 782d5c65159SKalle Valo } 783d5c65159SKalle Valo } 784d5c65159SKalle Valo 785d5c65159SKalle Valo void ath11k_dp_vdev_tx_attach(struct ath11k *ar, struct ath11k_vif *arvif) 786d5c65159SKalle Valo { 787d5c65159SKalle Valo arvif->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 1) | 788d5c65159SKalle Valo FIELD_PREP(HTT_TCL_META_DATA_VDEV_ID, 789d5c65159SKalle Valo arvif->vdev_id) | 790d5c65159SKalle Valo FIELD_PREP(HTT_TCL_META_DATA_PDEV_ID, 791d5c65159SKalle Valo ar->pdev->pdev_id); 792d5c65159SKalle Valo 793d5c65159SKalle Valo /* set HTT extension valid bit to 0 by default */ 794d5c65159SKalle Valo arvif->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT; 795d5c65159SKalle Valo 796d5c65159SKalle Valo ath11k_dp_update_vdev_search(arvif); 797d5c65159SKalle Valo } 798d5c65159SKalle Valo 799d5c65159SKalle Valo static int ath11k_dp_tx_pending_cleanup(int buf_id, void *skb, void *ctx) 800d5c65159SKalle Valo { 801d5c65159SKalle Valo struct ath11k_base *ab = (struct ath11k_base *)ctx; 802d5c65159SKalle Valo struct sk_buff *msdu = skb; 803d5c65159SKalle Valo 804d5c65159SKalle Valo dma_unmap_single(ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len, 805d5c65159SKalle Valo DMA_TO_DEVICE); 806d5c65159SKalle Valo 807d5c65159SKalle Valo dev_kfree_skb_any(msdu); 808d5c65159SKalle Valo 809d5c65159SKalle Valo return 0; 810d5c65159SKalle Valo } 811d5c65159SKalle Valo 812d5c65159SKalle Valo void ath11k_dp_free(struct ath11k_base *ab) 813d5c65159SKalle Valo { 814d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 815d5c65159SKalle Valo int i; 816d5c65159SKalle Valo 817d5c65159SKalle Valo ath11k_dp_link_desc_cleanup(ab, dp->link_desc_banks, 818d5c65159SKalle Valo HAL_WBM_IDLE_LINK, &dp->wbm_idle_ring); 819d5c65159SKalle Valo 820d5c65159SKalle Valo ath11k_dp_srng_common_cleanup(ab); 821d5c65159SKalle Valo 822d5c65159SKalle Valo ath11k_dp_reo_cmd_list_cleanup(ab); 823d5c65159SKalle Valo 824d5c65159SKalle Valo for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { 825d5c65159SKalle Valo spin_lock_bh(&dp->tx_ring[i].tx_idr_lock); 826d5c65159SKalle Valo idr_for_each(&dp->tx_ring[i].txbuf_idr, 827d5c65159SKalle Valo ath11k_dp_tx_pending_cleanup, ab); 828d5c65159SKalle Valo idr_destroy(&dp->tx_ring[i].txbuf_idr); 829d5c65159SKalle Valo spin_unlock_bh(&dp->tx_ring[i].tx_idr_lock); 830*d0998eb8SJohn Crispin kfree(dp->tx_ring[i].tx_status); 831d5c65159SKalle Valo } 832d5c65159SKalle Valo 833d5c65159SKalle Valo /* Deinit any SOC level resource */ 834d5c65159SKalle Valo } 835d5c65159SKalle Valo 836d5c65159SKalle Valo int ath11k_dp_alloc(struct ath11k_base *ab) 837d5c65159SKalle Valo { 838d5c65159SKalle Valo struct ath11k_dp *dp = &ab->dp; 839d5c65159SKalle Valo struct hal_srng *srng = NULL; 840d5c65159SKalle Valo size_t size = 0; 841d5c65159SKalle Valo u32 n_link_desc = 0; 842d5c65159SKalle Valo int ret; 843d5c65159SKalle Valo int i; 844d5c65159SKalle Valo 845d5c65159SKalle Valo dp->ab = ab; 846d5c65159SKalle Valo 847d5c65159SKalle Valo INIT_LIST_HEAD(&dp->reo_cmd_list); 848d5c65159SKalle Valo INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list); 849d5c65159SKalle Valo spin_lock_init(&dp->reo_cmd_lock); 850d5c65159SKalle Valo 851d5c65159SKalle Valo ret = ath11k_wbm_idle_ring_setup(ab, &n_link_desc); 852d5c65159SKalle Valo if (ret) { 853d5c65159SKalle Valo ath11k_warn(ab, "failed to setup wbm_idle_ring: %d\n", ret); 854d5c65159SKalle Valo return ret; 855d5c65159SKalle Valo } 856d5c65159SKalle Valo 857d5c65159SKalle Valo srng = &ab->hal.srng_list[dp->wbm_idle_ring.ring_id]; 858d5c65159SKalle Valo 859d5c65159SKalle Valo ret = ath11k_dp_link_desc_setup(ab, dp->link_desc_banks, 860d5c65159SKalle Valo HAL_WBM_IDLE_LINK, srng, n_link_desc); 861d5c65159SKalle Valo if (ret) { 862d5c65159SKalle Valo ath11k_warn(ab, "failed to setup link desc: %d\n", ret); 863d5c65159SKalle Valo return ret; 864d5c65159SKalle Valo } 865d5c65159SKalle Valo 866d5c65159SKalle Valo ret = ath11k_dp_srng_common_setup(ab); 867d5c65159SKalle Valo if (ret) 868d5c65159SKalle Valo goto fail_link_desc_cleanup; 869d5c65159SKalle Valo 870*d0998eb8SJohn Crispin size = sizeof(struct hal_wbm_release_ring) * DP_TX_COMP_RING_SIZE; 871d5c65159SKalle Valo 872d5c65159SKalle Valo for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { 873d5c65159SKalle Valo idr_init(&dp->tx_ring[i].txbuf_idr); 874d5c65159SKalle Valo spin_lock_init(&dp->tx_ring[i].tx_idr_lock); 875d5c65159SKalle Valo dp->tx_ring[i].tcl_data_ring_id = i; 876d5c65159SKalle Valo 877*d0998eb8SJohn Crispin dp->tx_ring[i].tx_status_head = 0; 878*d0998eb8SJohn Crispin dp->tx_ring[i].tx_status_tail = DP_TX_COMP_RING_SIZE - 1; 879*d0998eb8SJohn Crispin dp->tx_ring[i].tx_status = kmalloc(size, GFP_KERNEL); 880*d0998eb8SJohn Crispin if (!dp->tx_ring[i].tx_status) 881d5c65159SKalle Valo goto fail_cmn_srng_cleanup; 882d5c65159SKalle Valo } 883d5c65159SKalle Valo 884d5c65159SKalle Valo for (i = 0; i < HAL_DSCP_TID_MAP_TBL_NUM_ENTRIES_MAX; i++) 885d5c65159SKalle Valo ath11k_hal_tx_set_dscp_tid_map(ab, i); 886d5c65159SKalle Valo 887d5c65159SKalle Valo /* Init any SOC level resource for DP */ 888d5c65159SKalle Valo 889d5c65159SKalle Valo return 0; 890d5c65159SKalle Valo 891d5c65159SKalle Valo fail_cmn_srng_cleanup: 892d5c65159SKalle Valo ath11k_dp_srng_common_cleanup(ab); 893d5c65159SKalle Valo 894d5c65159SKalle Valo fail_link_desc_cleanup: 895d5c65159SKalle Valo ath11k_dp_link_desc_cleanup(ab, dp->link_desc_banks, 896d5c65159SKalle Valo HAL_WBM_IDLE_LINK, &dp->wbm_idle_ring); 897d5c65159SKalle Valo 898d5c65159SKalle Valo return ret; 899d5c65159SKalle Valo } 900