diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath12k/dp.c')
-rw-r--r-- | drivers/net/wireless/ath/ath12k/dp.c | 456 |
1 files changed, 328 insertions, 128 deletions
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index a6f81f2f97ef..6317c6d4c043 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <crypto/hash.h> @@ -14,6 +14,11 @@ #include "peer.h" #include "dp_mon.h" +enum ath12k_dp_desc_type { + ATH12K_DP_TX_DESC, + ATH12K_DP_RX_DESC, +}; + static void ath12k_dp_htt_htc_tx_complete(struct ath12k_base *ab, struct sk_buff *skb) { @@ -36,6 +41,11 @@ void ath12k_dp_peer_cleanup(struct ath12k *ar, int vdev_id, const u8 *addr) return; } + if (!peer->primary_link) { + spin_unlock_bh(&ab->base_lock); + return; + } + ath12k_dp_rx_peer_tid_cleanup(ar, peer); crypto_free_shash(peer->tfm_mmic); peer->dp_setup_done = false; @@ -127,7 +137,9 @@ static int ath12k_dp_srng_find_ring_in_mask(int ring_num, const u8 *grp_mask) static int ath12k_dp_srng_calculate_msi_group(struct ath12k_base *ab, enum hal_ring_type type, int ring_num) { + const struct ath12k_hal_tcl_to_wbm_rbm_map *map; const u8 *grp_mask; + int i; switch (type) { case HAL_WBM2SW_RELEASE: @@ -135,6 +147,14 @@ static int ath12k_dp_srng_calculate_msi_group(struct ath12k_base *ab, grp_mask = &ab->hw_params->ring_mask->rx_wbm_rel[0]; ring_num = 0; } else { + map = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map; + for (i = 0; i < ab->hw_params->max_tx_ring; i++) { + if (ring_num == map[i].wbm_ring_num) { + ring_num = i; + break; + } + } + grp_mask = &ab->hw_params->ring_mask->tx[0]; } break; @@ -148,6 +168,8 @@ static int ath12k_dp_srng_calculate_msi_group(struct ath12k_base *ab, grp_mask = &ab->hw_params->ring_mask->reo_status[0]; break; case HAL_RXDMA_MONITOR_STATUS: + grp_mask = &ab->hw_params->ring_mask->rx_mon_status[0]; + break; case HAL_RXDMA_MONITOR_DST: grp_mask = &ab->hw_params->ring_mask->rx_mon_dest[0]; break; @@ -254,12 +276,17 @@ int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring, break; case HAL_RXDMA_BUF: case HAL_RXDMA_MONITOR_BUF: - case HAL_RXDMA_MONITOR_STATUS: params.low_threshold = num_entries >> 3; params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; params.intr_batch_cntr_thres_entries = 0; params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_RX; break; + case HAL_RXDMA_MONITOR_STATUS: + params.low_threshold = num_entries >> 3; + params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; + params.intr_batch_cntr_thres_entries = 1; + params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_RX; + break; case HAL_TX_MONITOR_DST: params.low_threshold = DP_TX_MONITOR_BUF_SIZE_MAX >> 3; params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN; @@ -312,27 +339,32 @@ int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring, } static -u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif *arvif) +u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, + struct ath12k_link_vif *arvif) { u32 bank_config = 0; + struct ath12k_vif *ahvif = arvif->ahvif; /* Only valid for raw frames with HW crypto enabled. * With SW crypto, mac80211 sets key per packet */ - if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && + if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) bank_config |= - u32_encode_bits(ath12k_dp_tx_get_encrypt_type(arvif->key_cipher), + u32_encode_bits(ath12k_dp_tx_get_encrypt_type(ahvif->key_cipher), HAL_TX_BANK_CONFIG_ENCRYPT_TYPE); - bank_config |= u32_encode_bits(arvif->tx_encap_type, + bank_config |= u32_encode_bits(ahvif->tx_encap_type, HAL_TX_BANK_CONFIG_ENCAP_TYPE); bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_SRC_BUFFER_SWAP) | u32_encode_bits(0, HAL_TX_BANK_CONFIG_LINK_META_SWAP) | u32_encode_bits(0, HAL_TX_BANK_CONFIG_EPD); /* only valid if idx_lookup_override is not set in tcl_data_cmd */ - bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_INDEX_LOOKUP_EN); + if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) + bank_config |= u32_encode_bits(1, HAL_TX_BANK_CONFIG_INDEX_LOOKUP_EN); + else + bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_INDEX_LOOKUP_EN); bank_config |= u32_encode_bits(arvif->hal_addr_search_flags & HAL_TX_ADDRX_EN, HAL_TX_BANK_CONFIG_ADDRX_EN) | @@ -340,7 +372,7 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif HAL_TX_ADDRY_EN), HAL_TX_BANK_CONFIG_ADDRY_EN); - bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(arvif->vif) ? 3 : 0, + bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(ahvif->vif) ? 3 : 0, HAL_TX_BANK_CONFIG_MESH_EN) | u32_encode_bits(arvif->vdev_id_check_en, HAL_TX_BANK_CONFIG_VDEV_ID_CHECK_EN); @@ -350,7 +382,8 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif return bank_config; } -static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab, struct ath12k_vif *arvif, +static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab, + struct ath12k_link_vif *arvif, struct ath12k_dp *dp) { int bank_id = DP_INVALID_BANK_ID; @@ -452,8 +485,6 @@ static void ath12k_dp_srng_common_cleanup(struct ath12k_base *ab) ath12k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_comp_ring); ath12k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_data_ring); } - ath12k_dp_srng_cleanup(ab, &dp->tcl_status_ring); - ath12k_dp_srng_cleanup(ab, &dp->tcl_cmd_ring); ath12k_dp_srng_cleanup(ab, &dp->wbm_desc_rel_ring); } @@ -474,20 +505,6 @@ static int ath12k_dp_srng_common_setup(struct ath12k_base *ab) goto err; } - ret = ath12k_dp_srng_setup(ab, &dp->tcl_cmd_ring, HAL_TCL_CMD, 0, 0, - DP_TCL_CMD_RING_SIZE); - if (ret) { - ath12k_warn(ab, "failed to set up tcl_cmd ring :%d\n", ret); - goto err; - } - - ret = ath12k_dp_srng_setup(ab, &dp->tcl_status_ring, HAL_TCL_STATUS, - 0, 0, DP_TCL_STATUS_RING_SIZE); - if (ret) { - ath12k_warn(ab, "failed to set up tcl_status ring :%d\n", ret); - goto err; - } - for (i = 0; i < ab->hw_params->max_tx_ring; i++) { map = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map; tx_comp_ring_num = map[i].wbm_ring_num; @@ -611,6 +628,7 @@ static int ath12k_dp_scatter_idle_link_desc_setup(struct ath12k_base *ab, int i; int ret = 0; u32 end_offset, cookie; + enum hal_rx_buf_return_buf_manager rbm = dp->idle_link_rbm; n_entries_per_buf = HAL_WBM_IDLE_SCATTER_BUF_SIZE / ath12k_hal_srng_get_entrysize(ab, HAL_WBM_IDLE_LINK); @@ -641,7 +659,8 @@ static int ath12k_dp_scatter_idle_link_desc_setup(struct ath12k_base *ab, paddr = link_desc_banks[i].paddr; while (n_entries) { cookie = DP_LINK_DESC_COOKIE_SET(n_entries, i); - ath12k_hal_set_link_desc_addr(scatter_buf, cookie, paddr); + ath12k_hal_set_link_desc_addr(scatter_buf, cookie, + paddr, rbm); n_entries--; paddr += HAL_LINK_DESC_SIZE; if (rem_entries) { @@ -785,6 +804,7 @@ int ath12k_dp_link_desc_setup(struct ath12k_base *ab, u32 paddr; int i, ret; u32 cookie; + enum hal_rx_buf_return_buf_manager rbm = ab->dp.idle_link_rbm; tot_mem_sz = n_link_desc * HAL_LINK_DESC_SIZE; tot_mem_sz += HAL_LINK_DESC_ALIGN; @@ -845,8 +865,7 @@ int ath12k_dp_link_desc_setup(struct ath12k_base *ab, while (n_entries && (desc = ath12k_hal_srng_src_get_next_entry(ab, srng))) { cookie = DP_LINK_DESC_COOKIE_SET(n_entries, i); - ath12k_hal_set_link_desc_addr(desc, - cookie, paddr); + ath12k_hal_set_link_desc_addr(desc, cookie, paddr, rbm); n_entries--; paddr += HAL_LINK_DESC_SIZE; } @@ -876,11 +895,9 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, enum dp_monitor_mode monitor_mode; u8 ring_mask; - while (i < ab->hw_params->max_tx_ring) { - if (ab->hw_params->ring_mask->tx[grp_id] & - BIT(ab->hw_params->hal_ops->tcl_to_wbm_rbm_map[i].wbm_ring_num)) - ath12k_dp_tx_completion_handler(ab, i); - i++; + if (ab->hw_params->ring_mask->tx[grp_id]) { + i = fls(ab->hw_params->ring_mask->tx[grp_id]) - 1; + ath12k_dp_tx_completion_handler(ab, i); } if (ab->hw_params->ring_mask->rx_err[grp_id]) { @@ -912,12 +929,31 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, goto done; } + if (ab->hw_params->ring_mask->rx_mon_status[grp_id]) { + ring_mask = ab->hw_params->ring_mask->rx_mon_status[grp_id]; + for (i = 0; i < ab->num_radios; i++) { + for (j = 0; j < ab->hw_params->num_rxdma_per_pdev; j++) { + int id = i * ab->hw_params->num_rxdma_per_pdev + j; + + if (ring_mask & BIT(id)) { + work_done = + ath12k_dp_mon_process_ring(ab, id, napi, budget, + 0); + budget -= work_done; + tot_work_done += work_done; + if (budget <= 0) + goto done; + } + } + } + } + if (ab->hw_params->ring_mask->rx_mon_dest[grp_id]) { monitor_mode = ATH12K_DP_RX_MONITOR_MODE; ring_mask = ab->hw_params->ring_mask->rx_mon_dest[grp_id]; for (i = 0; i < ab->num_radios; i++) { - for (j = 0; j < ab->hw_params->num_rxmda_per_pdev; j++) { - int id = i * ab->hw_params->num_rxmda_per_pdev + j; + for (j = 0; j < ab->hw_params->num_rxdma_per_pdev; j++) { + int id = i * ab->hw_params->num_rxdma_per_pdev + j; if (ring_mask & BIT(id)) { work_done = @@ -937,8 +973,8 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, monitor_mode = ATH12K_DP_TX_MONITOR_MODE; ring_mask = ab->hw_params->ring_mask->tx_mon_dest[grp_id]; for (i = 0; i < ab->num_radios; i++) { - for (j = 0; j < ab->hw_params->num_rxmda_per_pdev; j++) { - int id = i * ab->hw_params->num_rxmda_per_pdev + j; + for (j = 0; j < ab->hw_params->num_rxdma_per_pdev; j++) { + int id = i * ab->hw_params->num_rxdma_per_pdev + j; if (ring_mask & BIT(id)) { work_done = @@ -960,8 +996,9 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, if (ab->hw_params->ring_mask->host2rxdma[grp_id]) { struct ath12k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; + LIST_HEAD(list); - ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, &list, 0); } /* TODO: Implement handler for other interrupts */ @@ -974,48 +1011,41 @@ void ath12k_dp_pdev_free(struct ath12k_base *ab) { int i; - del_timer_sync(&ab->mon_reap_timer); - for (i = 0; i < ab->num_radios; i++) ath12k_dp_rx_pdev_free(ab, i); } -void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab) +void ath12k_dp_pdev_pre_alloc(struct ath12k *ar) { - struct ath12k *ar; - struct ath12k_pdev_dp *dp; - int i; - - for (i = 0; i < ab->num_radios; i++) { - ar = ab->pdevs[i].ar; - dp = &ar->dp; - dp->mac_id = i; - atomic_set(&dp->num_tx_pending, 0); - init_waitqueue_head(&dp->tx_empty_waitq); + struct ath12k_pdev_dp *dp = &ar->dp; - /* TODO: Add any RXDMA setup required per pdev */ - } + dp->mac_id = ar->pdev_idx; + atomic_set(&dp->num_tx_pending, 0); + init_waitqueue_head(&dp->tx_empty_waitq); + /* TODO: Add any RXDMA setup required per pdev */ } -static void ath12k_dp_service_mon_ring(struct timer_list *t) +bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab) { - struct ath12k_base *ab = from_timer(ab, t, mon_reap_timer); - int i; - - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) - ath12k_dp_mon_process_ring(ab, i, NULL, DP_MON_SERVICE_BUDGET, - ATH12K_DP_RX_MONITOR_MODE); - - mod_timer(&ab->mon_reap_timer, jiffies + - msecs_to_jiffies(ATH12K_MON_TIMER_INTERVAL)); + if (test_bit(WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS, ab->wmi_ab.svc_map) && + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_mpdu_start && + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_msdu_end && + ab->hw_params->hal_ops->get_hal_rx_compact_ops) { + return true; + } + return false; } -static void ath12k_dp_mon_reap_timer_init(struct ath12k_base *ab) +void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab) { - if (ab->hw_params->rxdma1_enable) - return; - - timer_setup(&ab->mon_reap_timer, ath12k_dp_service_mon_ring, 0); + if (ath12k_dp_wmask_compaction_rx_tlv_supported(ab)) { + /* RX TLVS compaction is supported, hence change the hal_rx_ops + * to compact hal_rx_ops. + */ + ab->hal_rx_ops = ab->hw_params->hal_ops->get_hal_rx_compact_ops(); + } + ab->hal.hal_desc_sz = + ab->hal_rx_ops->rx_desc_get_desc_size(); } int ath12k_dp_pdev_alloc(struct ath12k_base *ab) @@ -1028,8 +1058,6 @@ int ath12k_dp_pdev_alloc(struct ath12k_base *ab) if (ret) goto out; - ath12k_dp_mon_reap_timer_init(ab); - /* TODO: Per-pdev rx ring unlike tx ring which is mapped to different AC's */ for (i = 0; i < ab->num_radios; i++) { ar = ab->pdevs[i].ar; @@ -1076,15 +1104,12 @@ int ath12k_dp_htt_connect(struct ath12k_dp *dp) return 0; } -static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif) +static void ath12k_dp_update_vdev_search(struct ath12k_link_vif *arvif) { - switch (arvif->vdev_type) { + switch (arvif->ahvif->vdev_type) { case WMI_VDEV_TYPE_STA: - /* TODO: Verify the search type and flags since ast hash - * is not part of peer mapv3 - */ arvif->hal_addr_search_flags = HAL_TX_ADDRY_EN; - arvif->search_type = HAL_TX_ADDR_SEARCH_DEFAULT; + arvif->search_type = HAL_TX_ADDR_SEARCH_INDEX; break; case WMI_VDEV_TYPE_AP: case WMI_VDEV_TYPE_IBSS: @@ -1097,7 +1122,7 @@ static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif) } } -void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif) +void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif) { struct ath12k_base *ab = ar->ab; @@ -1123,11 +1148,13 @@ void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif) static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) { - struct ath12k_rx_desc_info *desc_info, *tmp; + struct ath12k_rx_desc_info *desc_info; struct ath12k_tx_desc_info *tx_desc_info, *tmp1; struct ath12k_dp *dp = &ab->dp; + struct ath12k_skb_cb *skb_cb; struct sk_buff *skb; - int i; + struct ath12k *ar; + int i, j; u32 pool_id, tx_spt_page; if (!dp->spt_info) @@ -1136,24 +1163,31 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) /* RX Descriptor cleanup */ spin_lock_bh(&dp->rx_desc_lock); - list_for_each_entry_safe(desc_info, tmp, &dp->rx_desc_used_list, list) { - list_del(&desc_info->list); - skb = desc_info->skb; + for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { + desc_info = dp->rxbaddr[i]; - if (!skb) - continue; + for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { + if (!desc_info[j].in_use) { + list_del(&desc_info[j].list); + continue; + } - dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr, - skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); + skb = desc_info[j].skb; + if (!skb) + continue; + + dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr, + skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + } } for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { - if (!dp->spt_info->rxbaddr[i]) + if (!dp->rxbaddr[i]) continue; - kfree(dp->spt_info->rxbaddr[i]); - dp->spt_info->rxbaddr[i] = NULL; + kfree(dp->rxbaddr[i]); + dp->rxbaddr[i] = NULL; } spin_unlock_bh(&dp->rx_desc_lock); @@ -1170,6 +1204,25 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) if (!skb) continue; + skb_cb = ATH12K_SKB_CB(skb); + if (skb_cb->paddr_ext_desc) { + dma_unmap_single(ab->dev, + skb_cb->paddr_ext_desc, + tx_desc_info->skb_ext_desc->len, + DMA_TO_DEVICE); + dev_kfree_skb_any(tx_desc_info->skb_ext_desc); + } + + /* if we are unregistering, hw would've been destroyed and + * ar is no longer valid. + */ + if (!(test_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags))) { + ar = skb_cb->ar; + + if (atomic_dec_and_test(&ar->dp.num_tx_pending)) + wake_up(&ar->dp.tx_empty_waitq); + } + dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); @@ -1183,11 +1236,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) { tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; - if (!dp->spt_info->txbaddr[tx_spt_page]) + if (!dp->txbaddr[tx_spt_page]) continue; - kfree(dp->spt_info->txbaddr[tx_spt_page]); - dp->spt_info->txbaddr[tx_spt_page] = NULL; + kfree(dp->txbaddr[tx_spt_page]); + dp->txbaddr[tx_spt_page] = NULL; } spin_unlock_bh(&dp->tx_desc_lock[pool_id]); @@ -1204,6 +1257,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) } kfree(dp->spt_info); + dp->spt_info = NULL; } static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab) @@ -1213,15 +1267,25 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab) if (!ab->hw_params->reoq_lut_support) return; - if (!dp->reoq_lut.vaddr) - return; - - dma_free_coherent(ab->dev, DP_REOQ_LUT_SIZE, - dp->reoq_lut.vaddr, dp->reoq_lut.paddr); - dp->reoq_lut.vaddr = NULL; + if (dp->reoq_lut.vaddr_unaligned) { + ath12k_hif_write32(ab, + HAL_SEQ_WCSS_UMAC_REO_REG + + HAL_REO1_QDESC_LUT_BASE0(ab), 0); + dma_free_coherent(ab->dev, dp->reoq_lut.size, + dp->reoq_lut.vaddr_unaligned, + dp->reoq_lut.paddr_unaligned); + dp->reoq_lut.vaddr_unaligned = NULL; + } - ath12k_hif_write32(ab, - HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_LUT_BASE0(ab), 0); + if (dp->ml_reoq_lut.vaddr_unaligned) { + ath12k_hif_write32(ab, + HAL_SEQ_WCSS_UMAC_REO_REG + + HAL_REO1_QDESC_LUT_BASE1(ab), 0); + dma_free_coherent(ab->dev, dp->ml_reoq_lut.size, + dp->ml_reoq_lut.vaddr_unaligned, + dp->ml_reoq_lut.paddr_unaligned); + dp->ml_reoq_lut.vaddr_unaligned = NULL; + } } void ath12k_dp_free(struct ath12k_base *ab) @@ -1229,6 +1293,9 @@ void ath12k_dp_free(struct ath12k_base *ab) struct ath12k_dp *dp = &ab->dp; int i; + if (!dp->ab) + return; + ath12k_dp_link_desc_cleanup(ab, dp->link_desc_banks, HAL_WBM_IDLE_LINK, &dp->wbm_idle_ring); @@ -1239,11 +1306,14 @@ void ath12k_dp_free(struct ath12k_base *ab) ath12k_dp_rx_reo_cmd_list_cleanup(ab); - for (i = 0; i < ab->hw_params->max_tx_ring; i++) + for (i = 0; i < ab->hw_params->max_tx_ring; i++) { kfree(dp->tx_ring[i].tx_status); + dp->tx_ring[i].tx_status = NULL; + } ath12k_dp_rx_free(ab); /* Deinit any SOC level resource */ + dp->ab = NULL; } void ath12k_dp_cc_config(struct ath12k_base *ab) @@ -1253,6 +1323,9 @@ void ath12k_dp_cc_config(struct ath12k_base *ab) u32 wbm_base = HAL_SEQ_WCSS_UMAC_WBM_REG; u32 val = 0; + if (ath12k_ftm_mode) + return; + ath12k_hif_write32(ab, reo_base + HAL_REO1_SW_COOKIE_CFG0(ab), cmem_base); val |= u32_encode_bits(ATH12K_CMEM_ADDR_MSB, @@ -1312,16 +1385,22 @@ static inline void *ath12k_dp_cc_get_desc_addr_ptr(struct ath12k_base *ab, struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, u32 cookie) { + struct ath12k_dp *dp = &ab->dp; struct ath12k_rx_desc_info **desc_addr_ptr; - u16 ppt_idx, spt_idx; + u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx; ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT); - spt_idx = u32_get_bits(cookie, ATH12k_DP_CC_COOKIE_SPT); + spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT); + + start_ppt_idx = dp->rx_ppt_base + ATH12K_RX_SPT_PAGE_OFFSET; + end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES; - if (ppt_idx > ATH12K_NUM_RX_SPT_PAGES || + if (ppt_idx < start_ppt_idx || + ppt_idx >= end_ppt_idx || spt_idx > ATH12K_MAX_SPT_ENTRIES) return NULL; + ppt_idx = ppt_idx - dp->rx_ppt_base; desc_addr_ptr = ath12k_dp_cc_get_desc_addr_ptr(ab, ppt_idx, spt_idx); return *desc_addr_ptr; @@ -1331,13 +1410,17 @@ struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab, u32 cookie) { struct ath12k_tx_desc_info **desc_addr_ptr; - u16 ppt_idx, spt_idx; + u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx; ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT); - spt_idx = u32_get_bits(cookie, ATH12k_DP_CC_COOKIE_SPT); + spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT); - if (ppt_idx < ATH12K_NUM_RX_SPT_PAGES || - ppt_idx > ab->dp.num_spt_pages || + start_ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET; + end_ppt_idx = start_ppt_idx + + (ATH12K_TX_SPT_PAGES_PER_POOL * ATH12K_HW_MAX_QUEUES); + + if (ppt_idx < start_ppt_idx || + ppt_idx >= end_ppt_idx || spt_idx > ATH12K_MAX_SPT_ENTRIES) return NULL; @@ -1352,7 +1435,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) struct ath12k_rx_desc_info *rx_descs, **rx_desc_addr; struct ath12k_tx_desc_info *tx_descs, **tx_desc_addr; u32 i, j, pool_id, tx_spt_page; - u32 ppt_idx; + u32 ppt_idx, cookie_ppt_idx; spin_lock_bh(&dp->rx_desc_lock); @@ -1366,15 +1449,18 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return -ENOMEM; } - dp->spt_info->rxbaddr[i] = &rx_descs[0]; + ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET + i; + cookie_ppt_idx = dp->rx_ppt_base + ppt_idx; + dp->rxbaddr[i] = &rx_descs[0]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { - rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(i, j); + rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(cookie_ppt_idx, j); rx_descs[j].magic = ATH12K_DP_RX_DESC_MAGIC; + rx_descs[j].device_id = ab->device_id; list_add_tail(&rx_descs[j].list, &dp->rx_desc_free_list); /* Update descriptor VA in SPT */ - rx_desc_addr = ath12k_dp_cc_get_desc_addr_ptr(ab, i, j); + rx_desc_addr = ath12k_dp_cc_get_desc_addr_ptr(ab, ppt_idx, j); *rx_desc_addr = &rx_descs[j]; } } @@ -1394,10 +1480,11 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) } tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; - dp->spt_info->txbaddr[tx_spt_page] = &tx_descs[0]; + ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET + tx_spt_page; + + dp->txbaddr[tx_spt_page] = &tx_descs[0]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { - ppt_idx = ATH12K_NUM_RX_SPT_PAGES + tx_spt_page; tx_descs[j].desc_id = ath12k_dp_cc_cookie_gen(ppt_idx, j); tx_descs[j].pool_id = pool_id; list_add_tail(&tx_descs[j].list, @@ -1414,14 +1501,57 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return 0; } +static int ath12k_dp_cmem_init(struct ath12k_base *ab, + struct ath12k_dp *dp, + enum ath12k_dp_desc_type type) +{ + u32 cmem_base; + int i, start, end; + + cmem_base = ab->qmi.dev_mem[ATH12K_QMI_DEVMEM_CMEM_INDEX].start; + + switch (type) { + case ATH12K_DP_TX_DESC: + start = ATH12K_TX_SPT_PAGE_OFFSET; + end = start + ATH12K_NUM_TX_SPT_PAGES; + break; + case ATH12K_DP_RX_DESC: + cmem_base += ATH12K_PPT_ADDR_OFFSET(dp->rx_ppt_base); + start = ATH12K_RX_SPT_PAGE_OFFSET; + end = start + ATH12K_NUM_RX_SPT_PAGES; + break; + default: + ath12k_err(ab, "invalid descriptor type %d in cmem init\n", type); + return -EINVAL; + } + + /* Write to PPT in CMEM */ + for (i = start; i < end; i++) + ath12k_hif_write32(ab, cmem_base + ATH12K_PPT_ADDR_OFFSET(i), + dp->spt_info[i].paddr >> ATH12K_SPT_4K_ALIGN_OFFSET); + + return 0; +} + +void ath12k_dp_partner_cc_init(struct ath12k_base *ab) +{ + struct ath12k_hw_group *ag = ab->ag; + int i; + + for (i = 0; i < ag->num_devices; i++) { + if (ag->ab[i] == ab) + continue; + + ath12k_dp_cmem_init(ab, &ag->ab[i]->dp, ATH12K_DP_RX_DESC); + } +} + static int ath12k_dp_cc_init(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; int i, ret = 0; - u32 cmem_base; INIT_LIST_HEAD(&dp->rx_desc_free_list); - INIT_LIST_HEAD(&dp->rx_desc_used_list); spin_lock_init(&dp->rx_desc_lock); for (i = 0; i < ATH12K_HW_MAX_QUEUES; i++) { @@ -1442,7 +1572,7 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) return -ENOMEM; } - cmem_base = ab->qmi.dev_mem[ATH12K_QMI_DEVMEM_CMEM_INDEX].start; + dp->rx_ppt_base = ab->device_id * ATH12K_NUM_RX_SPT_PAGES; for (i = 0; i < dp->num_spt_pages; i++) { dp->spt_info[i].vaddr = dma_alloc_coherent(ab->dev, @@ -1460,10 +1590,18 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) ret = -EINVAL; goto free; } + } - /* Write to PPT in CMEM */ - ath12k_hif_write32(ab, cmem_base + ATH12K_PPT_ADDR_OFFSET(i), - dp->spt_info[i].paddr >> ATH12K_SPT_4K_ALIGN_OFFSET); + ret = ath12k_dp_cmem_init(ab, dp, ATH12K_DP_TX_DESC); + if (ret) { + ath12k_warn(ab, "HW CC Tx cmem init failed %d", ret); + goto free; + } + + ret = ath12k_dp_cmem_init(ab, dp, ATH12K_DP_RX_DESC); + if (ret) { + ath12k_warn(ab, "HW CC Rx cmem init failed %d", ret); + goto free; } ret = ath12k_dp_cc_desc_init(ab); @@ -1478,27 +1616,88 @@ free: return ret; } +static int ath12k_dp_alloc_reoq_lut(struct ath12k_base *ab, + struct ath12k_reo_q_addr_lut *lut) +{ + lut->size = DP_REOQ_LUT_SIZE + HAL_REO_QLUT_ADDR_ALIGN - 1; + lut->vaddr_unaligned = dma_alloc_coherent(ab->dev, lut->size, + &lut->paddr_unaligned, + GFP_KERNEL | __GFP_ZERO); + if (!lut->vaddr_unaligned) + return -ENOMEM; + + lut->vaddr = PTR_ALIGN(lut->vaddr_unaligned, HAL_REO_QLUT_ADDR_ALIGN); + lut->paddr = lut->paddr_unaligned + + ((unsigned long)lut->vaddr - (unsigned long)lut->vaddr_unaligned); + return 0; +} + static int ath12k_dp_reoq_lut_setup(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; + u32 val; + int ret; if (!ab->hw_params->reoq_lut_support) return 0; - dp->reoq_lut.vaddr = dma_alloc_coherent(ab->dev, - DP_REOQ_LUT_SIZE, - &dp->reoq_lut.paddr, - GFP_KERNEL | __GFP_ZERO); - if (!dp->reoq_lut.vaddr) { + ret = ath12k_dp_alloc_reoq_lut(ab, &dp->reoq_lut); + if (ret) { ath12k_warn(ab, "failed to allocate memory for reoq table"); - return -ENOMEM; + return ret; } + ret = ath12k_dp_alloc_reoq_lut(ab, &dp->ml_reoq_lut); + if (ret) { + ath12k_warn(ab, "failed to allocate memory for ML reoq table"); + dma_free_coherent(ab->dev, dp->reoq_lut.size, + dp->reoq_lut.vaddr_unaligned, + dp->reoq_lut.paddr_unaligned); + dp->reoq_lut.vaddr_unaligned = NULL; + return ret; + } + + /* Bits in the register have address [39:8] LUT base address to be + * allocated such that LSBs are assumed to be zero. Also, current + * design supports paddr up to 4 GB max hence it fits in 32 bit + * register only + */ + ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_LUT_BASE0(ab), - dp->reoq_lut.paddr); + dp->reoq_lut.paddr >> 8); + + ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_LUT_BASE1(ab), + dp->ml_reoq_lut.paddr >> 8); + + val = ath12k_hif_read32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_ADDR(ab)); + + ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_ADDR(ab), + val | HAL_REO_QDESC_ADDR_READ_LUT_ENABLE); + + ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_MAX_PEERID(ab), + HAL_REO_QDESC_MAX_PEERID); + return 0; } +static enum hal_rx_buf_return_buf_manager +ath12k_dp_get_idle_link_rbm(struct ath12k_base *ab) +{ + switch (ab->device_id) { + case 0: + return HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST; + case 1: + return HAL_RX_BUF_RBM_WBM_DEV1_IDLE_DESC_LIST; + case 2: + return HAL_RX_BUF_RBM_WBM_DEV2_IDLE_DESC_LIST; + default: + ath12k_warn(ab, "invalid %d device id, so choose default rbm\n", + ab->device_id); + WARN_ON(1); + return HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST; + } +} + int ath12k_dp_alloc(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; @@ -1515,6 +1714,7 @@ int ath12k_dp_alloc(struct ath12k_base *ab) spin_lock_init(&dp->reo_cmd_lock); dp->reo_cmd_cache_flush_count = 0; + dp->idle_link_rbm = ath12k_dp_get_idle_link_rbm(ab); ret = ath12k_wbm_idle_ring_setup(ab, &n_link_desc); if (ret) { |