diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 63a170375e54a..cd73129503d66 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -2296,6 +2296,7 @@ void ath12k_core_deinit(struct ath12k_base *ab) void ath12k_core_free(struct ath12k_base *ab) { timer_delete_sync(&ab->rx_replenish_retry); + ath12k_wmi_free(); destroy_workqueue(ab->workqueue_aux); destroy_workqueue(ab->workqueue); kfree(ab); @@ -2320,6 +2321,9 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, if (!ab->workqueue_aux) goto err_free_wq; + if (ath12k_wmi_alloc() < 0) + goto err_free_wq_aux; + mutex_init(&ab->core_lock); spin_lock_init(&ab->base_lock); init_completion(&ab->reset_complete); @@ -2354,6 +2358,8 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, return ab; +err_free_wq_aux: + destroy_workqueue(ab->workqueue_aux); err_free_wq: destroy_workqueue(ab->workqueue); err_sc_free: diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index ab54c8a84d3e0..53ddb0d188012 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -946,11 +946,11 @@ void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif) dp_link_vif = ath12k_dp_vif_to_dp_link_vif(&ahvif->dp_vif, link_id); - dp_link_vif->tcl_metadata |= u32_encode_bits(1, HTT_TCL_META_DATA_TYPE) | - u32_encode_bits(arvif->vdev_id, - HTT_TCL_META_DATA_VDEV_ID) | - u32_encode_bits(ar->pdev->pdev_id, - HTT_TCL_META_DATA_PDEV_ID); + dp_link_vif->tcl_metadata = u32_encode_bits(1, HTT_TCL_META_DATA_TYPE) | + u32_encode_bits(arvif->vdev_id, + HTT_TCL_META_DATA_VDEV_ID) | + u32_encode_bits(ar->pdev->pdev_id, + HTT_TCL_META_DATA_PDEV_ID); /* set HTT extension valid bit to 0 by default */ dp_link_vif->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT; diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 8bc75ff607b0a..f8cfc7bb29dd7 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -338,13 +338,6 @@ struct ath12k_rx_desc_info { u8 in_use : 1, device_id : 3, reserved : 4; - struct { - __le32 info0; - __le32 peer_meta_data; - } rx_mpdu_info; - struct { - __le32 info0; - } rx_msdu_info; }; struct ath12k_tx_desc_info { diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 737287a9aa462..44c5cff75f169 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -115,13 +115,14 @@ ath12k_dp_mon_fill_rx_rate(struct ath12k_pdev_dp *dp_pdev, bool is_cck; pkt_type = ppdu_info->preamble_type; - rate_mcs = ppdu_info->rate; + rate_mcs = ppdu_info->mcs; nss = ppdu_info->nss; sgi = ppdu_info->gi; switch (pkt_type) { case RX_MSDU_START_PKT_TYPE_11A: case RX_MSDU_START_PKT_TYPE_11B: + rate_mcs = ppdu_info->rate; is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B); if (rx_status->band < NUM_NL80211_BANDS) { struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev); @@ -471,13 +472,10 @@ void ath12k_dp_mon_update_radiotap(struct ath12k_pdev_dp *dp_pdev, rxs->encoding = RX_ENC_HE; ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he)); ath12k_dp_mon_rx_update_radiotap_he(ppduinfo, ptr); - rxs->rate_idx = ppduinfo->rate; } else if (ppduinfo->vht_flags) { rxs->encoding = RX_ENC_VHT; - rxs->rate_idx = ppduinfo->rate; } else if (ppduinfo->ht_flags) { rxs->encoding = RX_ENC_HT; - rxs->rate_idx = ppduinfo->rate; } else { struct ath12k *ar; diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c b/drivers/net/wireless/ath/ath12k/dp_peer.c index 2e66872b55723..caa56942f0334 100644 --- a/drivers/net/wireless/ath/ath12k/dp_peer.c +++ b/drivers/net/wireless/ath/ath12k/dp_peer.c @@ -419,7 +419,7 @@ struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_p RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "ath12k dp peer find by peerid index called without rcu lock"); - if (!peer_id || peer_id >= ATH12K_DP_PEER_ID_INVALID) + if (peer_id >= ATH12K_DP_PEER_ID_INVALID) return NULL; index = ath12k_dp_peer_get_peerid_index(dp, peer_id); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 78d61f7a98ac4..422f90293cf12 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1205,8 +1205,7 @@ ath12k_dp_rx_h_find_link_peer(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *ms lockdep_assert_held(&dp->dp_lock); - if (rxcb->peer_id) - peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, rxcb->peer_id); + peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, rxcb->peer_id); if (peer) return peer; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index 4541d5d4c5ae7..fe13e509033a1 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -84,17 +84,6 @@ struct ath12k_dp_rx_rfc1042_hdr { __be16 snap_type; } __packed; -struct ath12k_dp_rx_proc_ctx { - int device_id; - struct ath12k_dp *dp; - struct ath12k_dp *partner_dp; - int ring_id; - int hw_link_id; - struct sk_buff_head *msdu_list; - int *num_buffs_reaped; - int *total_msdu_reaped; -}; - static inline u32 ath12k_he_gi_to_nl80211_he_gi(u8 sgi) { u32 ret = 0; diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index e531f7d118554..ff0fd07f304d7 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -326,34 +326,6 @@ void *ath12k_hal_srng_dst_peek(struct ath12k_base *ab, struct hal_srng *srng) } EXPORT_SYMBOL(ath12k_hal_srng_dst_peek); -u32 ath12k_hal_srng_dst_get_curr_tp(struct hal_srng *srng) -{ - lockdep_assert_held(&srng->lock); - - return srng->u.dst_ring.tp; -} -EXPORT_SYMBOL(ath12k_hal_srng_dst_get_curr_tp); - -void *ath12k_hal_srng_dst_ring_get_and_update_tp(struct hal_srng *srng, u32 *updated_tp) -{ - void *desc; - - lockdep_assert_held(&srng->lock); - - if (srng->u.dst_ring.tp == srng->u.dst_ring.cached_hp) - return NULL; - - desc = srng->ring_base_vaddr + srng->u.dst_ring.tp; - - srng->u.dst_ring.tp = (srng->u.dst_ring.tp + srng->entry_size) % - srng->ring_size; - if (updated_tp) - *updated_tp = srng->u.dst_ring.tp; - - return desc; -} -EXPORT_SYMBOL(ath12k_hal_srng_dst_ring_get_and_update_tp); - void *ath12k_hal_srng_dst_get_next_entry(struct ath12k_base *ab, struct hal_srng *srng) { @@ -521,14 +493,6 @@ void *ath12k_hal_srng_src_get_next_reaped(struct ath12k_base *ab, return desc; } -void ath12k_hal_srng_update_tp(struct hal_srng *srng, u32 new_tp) -{ - lockdep_assert_held(&srng->lock); - - srng->u.dst_ring.tp = new_tp; -} -EXPORT_SYMBOL(ath12k_hal_srng_update_tp); - void ath12k_hal_srng_access_begin(struct ath12k_base *ab, struct hal_srng *srng) { u32 hp; diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 305d0410ac6fa..21c551d8b2481 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1483,8 +1483,6 @@ int ath12k_hal_srng_get_entrysize(struct ath12k_base *ab, u32 ring_type); int ath12k_hal_srng_get_max_entries(struct ath12k_base *ab, u32 ring_type); void ath12k_hal_srng_get_params(struct ath12k_base *ab, struct hal_srng *srng, struct hal_srng_params *params); -u32 ath12k_hal_srng_dst_get_curr_tp(struct hal_srng *srng); -void *ath12k_hal_srng_dst_ring_get_and_update_tp(struct hal_srng *srng, u32 *updated_tp); void *ath12k_hal_srng_dst_get_next_entry(struct ath12k_base *ab, struct hal_srng *srng); void *ath12k_hal_srng_src_peek(struct ath12k_base *ab, struct hal_srng *srng); @@ -1501,7 +1499,6 @@ void *ath12k_hal_srng_src_get_next_entry(struct ath12k_base *ab, struct hal_srng *srng); int ath12k_hal_srng_src_num_free(struct ath12k_base *ab, struct hal_srng *srng, bool sync_hw_ptr); -void ath12k_hal_srng_update_tp(struct hal_srng *srng, u32 new_tp); void ath12k_hal_srng_access_begin(struct ath12k_base *ab, struct hal_srng *srng); void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng); diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index cb965f001bed0..7ec7638eb0653 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8170,16 +8170,16 @@ int ath12k_mac_op_change_sta_links(struct ieee80211_hw *hw, continue; arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); - arsta = ath12k_mac_alloc_assign_link_sta(ah, ahsta, ahvif, link_id); + if (!arvif || !arvif->is_created) + continue; - if (!arvif || !arsta) { + arsta = ath12k_mac_alloc_assign_link_sta(ah, ahsta, ahvif, link_id); + if (!arsta) { ath12k_hw_warn(ah, "Failed to alloc/assign link sta"); continue; } ar = arvif->ar; - if (!ar) - continue; ret = ath12k_mac_station_add(ar, arvif, arsta); if (ret) { @@ -8515,6 +8515,10 @@ ath12k_create_vht_cap(struct ath12k *ar, u32 rate_cap_tx_chainmask, vht_cap.vht_supported = 1; vht_cap.cap = ar->pdev->cap.vht_cap; + if (ar->pdev->cap.nss_ratio_enabled) + vht_cap.vht_mcs.tx_highest |= + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); + ath12k_set_vht_txbf_cap(ar, &vht_cap.cap); /* 80P80 is not supported */ @@ -10410,7 +10414,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) if (ret) { ath12k_warn(ab, "failed to create WMI vdev %d: %d\n", arvif->vdev_id, ret); - return ret; + goto err; } ar->num_created_vdevs++; @@ -10577,13 +10581,13 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) if (ret) { ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", arvif->vdev_id, arvif->bssid); - goto err; + goto err_dp_peer_del; } ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id, arvif->bssid); if (ret) - goto err_vdev_del; + goto err_dp_peer_del; ar->num_peers--; } @@ -10600,8 +10604,6 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) ath12k_wmi_vdev_delete(ar, arvif->vdev_id); ar->num_created_vdevs--; - arvif->is_created = false; - arvif->ar = NULL; ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); ab->free_vdev_map |= 1LL << arvif->vdev_id; ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id); @@ -10610,6 +10612,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) spin_unlock_bh(&ar->data_lock); err: + arvif->is_created = false; arvif->ar = NULL; return ret; } diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c index 074df2ab6bbf6..795fc4553a64e 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c @@ -1779,8 +1779,7 @@ ath12k_wifi7_dp_mon_rx_parse_status_tlv(struct ath12k_pdev_dp *dp_pdev, info[1] = __le32_to_cpu(mpdu_start->info1); peer_id = u32_get_bits(info[1], HAL_RX_MPDU_START_INFO1_PEERID); - if (peer_id) - ppdu_info->peer_id = peer_id; + ppdu_info->peer_id = peer_id; ppdu_info->mpdu_len += u32_get_bits(info[1], HAL_RX_MPDU_START_INFO2_MPDU_LEN); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c index c4211169cb7bd..f9a8bdab8f1dd 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c @@ -651,31 +651,6 @@ ath12k_wifi7_dp_rx_process_received_packets(struct ath12k_dp *dp, rcu_read_unlock(); } -static void ath12k_dp_rx_process_desc_info(struct ath12k_rx_desc_info *desc_info, - struct ath12k_dp_rx_proc_ctx *ctx) -{ - struct sk_buff *msdu = desc_info->skb; - struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - - dma_unmap_single(ctx->partner_dp->dev, rxcb->paddr, - msdu->len + skb_tailroom(msdu), DMA_FROM_DEVICE); - ctx->num_buffs_reaped[ctx->device_id]++; - ctx->dp->device_stats.reo_rx[ctx->ring_id][ctx->dp->device_id]++; - rxcb->is_first_msdu = !!(le32_to_cpu(desc_info->rx_msdu_info.info0) & - RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); - rxcb->is_last_msdu = !!(le32_to_cpu(desc_info->rx_msdu_info.info0) & - RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); - rxcb->is_continuation = !!(le32_to_cpu(desc_info->rx_msdu_info.info0) & - RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); - rxcb->hw_link_id = ctx->hw_link_id; - rxcb->peer_id = ath12k_wifi7_dp_rx_get_peer_id(ctx->dp, - ctx->dp->peer_metadata_ver, - desc_info->rx_mpdu_info.peer_meta_data); - rxcb->tid = le32_get_bits(desc_info->rx_mpdu_info.info0, RX_MPDU_DESC_INFO0_TID); - __skb_queue_tail(ctx->msdu_list, msdu); - (*ctx->total_msdu_reaped)++; -} - int ath12k_wifi7_dp_rx_process(struct ath12k_dp *dp, int ring_id, struct napi_struct *napi, int budget) { @@ -683,10 +658,10 @@ int ath12k_wifi7_dp_rx_process(struct ath12k_dp *dp, int ring_id, struct ath12k_base *ab = dp->ab; struct ath12k_hal *hal = dp->hal; struct ath12k_dp_hw_group *dp_hw_grp = &ag->dp_hw_grp; - struct list_head rx_desc_used_list[ATH12K_MAX_DEVICES], rx_desc_scat_list; + struct list_head rx_desc_used_list[ATH12K_MAX_DEVICES]; struct ath12k_hw_link *hw_links = ag->hw_links; int num_buffs_reaped[ATH12K_MAX_DEVICES] = {}; - struct ath12k_rx_desc_info *desc_info, *tmp, *scat_desc_info; + struct ath12k_rx_desc_info *desc_info; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; struct hal_reo_dest_ring *desc; struct ath12k_dp *partner_dp; @@ -696,27 +671,24 @@ int ath12k_wifi7_dp_rx_process(struct ath12k_dp *dp, int ring_id, u8 hw_link_id, device_id; struct hal_srng *srng; struct sk_buff *msdu; - struct ath12k_dp_rx_proc_ctx ctx; + bool done = false; u64 desc_va; - u32 last_tp, updated_tp; - bool scat_buf = false, is_continuation, scat_buf_err = false; __skb_queue_head_init(&msdu_list); for (device_id = 0; device_id < ATH12K_MAX_DEVICES; device_id++) INIT_LIST_HEAD(&rx_desc_used_list[device_id]); - INIT_LIST_HEAD(&rx_desc_scat_list); - srng = &hal->srng_list[dp->reo_dst_ring[ring_id].ring_id]; spin_lock_bh(&srng->lock); +try_again: ath12k_hal_srng_access_begin(ab, srng); - updated_tp = ath12k_hal_srng_dst_get_curr_tp(srng); - - while ((desc = ath12k_hal_srng_dst_ring_get_and_update_tp(srng, &last_tp))) { + while ((desc = ath12k_hal_srng_dst_get_next_entry(ab, srng))) { + struct rx_mpdu_desc *mpdu_info; + struct rx_msdu_desc *msdu_info; enum hal_reo_dest_ring_push_reason push_reason; u32 cookie; @@ -735,9 +707,6 @@ int ath12k_wifi7_dp_rx_process(struct ath12k_dp *dp, int ring_id, if (unlikely(!partner_dp)) { if (desc_info->skb) { dev_kfree_skb_any(desc_info->skb); - if (scat_buf) - scat_buf_err = true; - desc_info->skb = NULL; } @@ -757,92 +726,66 @@ int ath12k_wifi7_dp_rx_process(struct ath12k_dp *dp, int ring_id, if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC) ath12k_warn(ab, "Check HW CC implementation"); + msdu = desc_info->skb; + desc_info->skb = NULL; + + list_add_tail(&desc_info->list, &rx_desc_used_list[device_id]); + + rxcb = ATH12K_SKB_RXCB(msdu); + dma_unmap_single(partner_dp->dev, rxcb->paddr, + msdu->len + skb_tailroom(msdu), + DMA_FROM_DEVICE); + + num_buffs_reaped[device_id]++; + dp->device_stats.reo_rx[ring_id][dp->device_id]++; + push_reason = le32_get_bits(desc->info0, HAL_REO_DEST_RING_INFO0_PUSH_REASON); if (push_reason != HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) { - msdu = desc_info->skb; - rxcb = ATH12K_SKB_RXCB(msdu); - dma_unmap_single(partner_dp->dev, rxcb->paddr, - msdu->len + skb_tailroom(msdu), - DMA_FROM_DEVICE); - dev_kfree_skb_any(desc_info->skb); - if (scat_buf) - scat_buf_err = true; + dev_kfree_skb_any(msdu); dp->device_stats.hal_reo_error[ring_id]++; - list_add_tail(&desc_info->list, &rx_desc_used_list[device_id]); continue; } - desc_info->rx_mpdu_info.info0 = desc->rx_mpdu_info.info0; - desc_info->rx_mpdu_info.peer_meta_data = - desc->rx_mpdu_info.peer_meta_data; - desc_info->rx_msdu_info.info0 = desc->rx_msdu_info.info0; - is_continuation = !!(le32_to_cpu(desc->rx_msdu_info.info0) & - RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); - if (!is_continuation) { - if (unlikely(scat_buf && scat_buf_err)) { - list_for_each_entry_safe(scat_desc_info, tmp, - &rx_desc_scat_list, list) { - msdu = scat_desc_info->skb; - rxcb = ATH12K_SKB_RXCB(msdu); - list_del(&scat_desc_info->list); - list_add_tail(&scat_desc_info->list, - &rx_desc_used_list[device_id]); - dma_unmap_single(partner_dp->dev, rxcb->paddr, - msdu->len + skb_tailroom(msdu), - DMA_FROM_DEVICE); - dev_kfree_skb_any(msdu); - scat_desc_info->skb = NULL; - } - - msdu = desc_info->skb; - rxcb = ATH12K_SKB_RXCB(msdu); - dma_unmap_single(partner_dp->dev, rxcb->paddr, - msdu->len + skb_tailroom(msdu), - DMA_FROM_DEVICE); - dev_kfree_skb_any(msdu); - scat_buf_err = false; - } else { - ctx.dp = dp; - ctx.partner_dp = partner_dp; - ctx.ring_id = ring_id; - ctx.device_id = device_id; - ctx.hw_link_id = hw_link_id; - ctx.msdu_list = &msdu_list; - ctx.num_buffs_reaped = num_buffs_reaped; - ctx.total_msdu_reaped = &total_msdu_reaped; - - if (scat_buf) { - list_for_each_entry_safe(scat_desc_info, tmp, - &rx_desc_scat_list, - list) { - list_del(&scat_desc_info->list); - list_add_tail(&scat_desc_info->list, - &rx_desc_used_list[device_id]); - ath12k_dp_rx_process_desc_info( - scat_desc_info, &ctx); - scat_desc_info->skb = NULL; - } - } - - ath12k_dp_rx_process_desc_info(desc_info, &ctx); - desc_info->skb = NULL; - scat_buf = false; - updated_tp = last_tp; - list_add_tail(&desc_info->list, - &rx_desc_used_list[device_id]); - } + msdu_info = &desc->rx_msdu_info; + mpdu_info = &desc->rx_mpdu_info; + + rxcb->is_first_msdu = !!(le32_to_cpu(msdu_info->info0) & + RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); + rxcb->is_last_msdu = !!(le32_to_cpu(msdu_info->info0) & + RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); + rxcb->is_continuation = !!(le32_to_cpu(msdu_info->info0) & + RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); + rxcb->hw_link_id = hw_link_id; + rxcb->peer_id = ath12k_wifi7_dp_rx_get_peer_id(dp, dp->peer_metadata_ver, + mpdu_info->peer_meta_data); + rxcb->tid = le32_get_bits(mpdu_info->info0, + RX_MPDU_DESC_INFO0_TID); + + __skb_queue_tail(&msdu_list, msdu); + + if (!rxcb->is_continuation) { + total_msdu_reaped++; + done = true; } else { - list_add_tail(&desc_info->list, &rx_desc_scat_list); - scat_buf = true; + done = false; } if (total_msdu_reaped >= budget) break; } - ath12k_hal_srng_update_tp(srng, updated_tp); + /* Hw might have updated the head pointer after we cached it. + * In this case, even though there are entries in the ring we'll + * get rx_desc NULL. Give the read another try with updated cached + * head pointer so that we can reap complete MPDU in the current + * rx processing. + */ + if (!done && ath12k_hal_srng_dst_num_free(ab, srng, true)) { + ath12k_hal_srng_access_end(ab, srng); + goto try_again; + } ath12k_hal_srng_access_end(ab, srng); @@ -1106,8 +1049,10 @@ static int ath12k_wifi7_dp_rx_h_verify_tkip_mic(struct ath12k_pdev_dp *dp_pdev, skb_pull(msdu, hal_rx_desc_sz); if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(dp, msdu, - rx_info))) + rx_info))) { + dev_kfree_skb_any(msdu); return -EINVAL; + } ath12k_dp_rx_h_ppdu(dp_pdev, rx_info); ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, true, diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 58702903c797c..a1063f1c198a0 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include "core.h" #include "debugfs.h" #include "debug.h" @@ -134,6 +136,10 @@ struct wmi_pdev_set_obss_bitmap_arg { const char *label; }; +static DEFINE_MUTEX(ath12k_wmi_mutex); +static refcount_t ath12k_wmi_refcount; +static void __percpu *ath12k_wmi_tb; + static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { [WMI_TAG_ARRAY_BYTE] = { .min_len = 0 }, [WMI_TAG_ARRAY_UINT32] = { .min_len = 0 }, @@ -289,29 +295,19 @@ static int ath12k_wmi_tlv_iter_parse(struct ath12k_base *ab, u16 tag, u16 len, return 0; } -static int ath12k_wmi_tlv_parse(struct ath12k_base *ar, const void **tb, - const void *ptr, size_t len) -{ - return ath12k_wmi_tlv_iter(ar, ptr, len, ath12k_wmi_tlv_iter_parse, - (void *)tb); -} - static const void ** -ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, - struct sk_buff *skb, gfp_t gfp) +ath12k_wmi_tlv_parse(struct ath12k_base *ab, struct sk_buff *skb) { const void **tb; int ret; - tb = kcalloc(WMI_TAG_MAX, sizeof(*tb), gfp); - if (!tb) - return ERR_PTR(-ENOMEM); + tb = this_cpu_ptr(ath12k_wmi_tb); + memset(tb, 0, WMI_TAG_MAX * sizeof(*tb)); - ret = ath12k_wmi_tlv_parse(ab, tb, skb->data, skb->len); - if (ret) { - kfree(tb); + ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len, + ath12k_wmi_tlv_iter_parse, (void *)tb); + if (ret) return ERR_PTR(ret); - } return tb; } @@ -3914,9 +3910,10 @@ ath12k_wmi_obss_color_collision_event(struct ath12k_base *ab, struct sk_buff *sk const struct wmi_obss_color_collision_event *ev; struct ath12k_link_vif *arvif; u32 vdev_id, evt_type; + const void **tb; u64 bitmap; - const void **tb __free(kfree) = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ath12k_warn(ab, "failed to parse OBSS color collision tlv %ld\n", PTR_ERR(tb)); @@ -5725,7 +5722,7 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf const struct wmi_vdev_start_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5735,13 +5732,11 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf ev = tb[WMI_TAG_VDEV_START_RESPONSE_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch vdev start resp ev"); - kfree(tb); return -EPROTO; } *vdev_rsp = *ev; - kfree(tb); return 0; } @@ -5820,7 +5815,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n"); - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5830,7 +5825,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ev = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch reg chan list ext update ev\n"); - kfree(tb); return -EPROTO; } @@ -5860,7 +5854,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, if (num_2g_reg_rules > MAX_REG_RULES || num_5g_reg_rules > MAX_REG_RULES) { ath12k_warn(ab, "Num reg rules for 2G/5G exceeds max limit (num_2g_reg_rules: %d num_5g_reg_rules: %d max_rules: %d)\n", num_2g_reg_rules, num_5g_reg_rules, MAX_REG_RULES); - kfree(tb); return -EINVAL; } @@ -5870,7 +5863,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, if (num_6g_reg_rules_ap[i] > MAX_6GHZ_REG_RULES) { ath12k_warn(ab, "Num 6G reg rules for AP mode(%d) exceeds max limit (num_6g_reg_rules_ap: %d, max_rules: %d)\n", i, num_6g_reg_rules_ap[i], MAX_6GHZ_REG_RULES); - kfree(tb); return -EINVAL; } @@ -5895,14 +5887,12 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, num_6g_reg_rules_cl[WMI_REG_VLP_AP][i] > MAX_6GHZ_REG_RULES) { ath12k_warn(ab, "Num 6g client reg rules exceeds max limit, for client(type: %d)\n", i); - kfree(tb); return -EINVAL; } } if (!total_reg_rules) { ath12k_warn(ab, "No reg rules available\n"); - kfree(tb); return -EINVAL; } @@ -6004,7 +5994,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ext_wmi_reg_rule); if (!reg_info->reg_rules_2g_ptr) { - kfree(tb); ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n"); return -ENOMEM; } @@ -6038,7 +6027,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ext_wmi_reg_rule); if (!reg_info->reg_rules_5g_ptr) { - kfree(tb); ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n"); return -ENOMEM; } @@ -6057,7 +6045,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ext_wmi_reg_rule); if (!reg_info->reg_rules_6g_ap_ptr[i]) { - kfree(tb); ath12k_warn(ab, "Unable to Allocate memory for 6g ap rules\n"); return -ENOMEM; } @@ -6072,7 +6059,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ext_wmi_reg_rule); if (!reg_info->reg_rules_6g_client_ptr[j][i]) { - kfree(tb); ath12k_warn(ab, "Unable to Allocate memory for 6g client rules\n"); return -ENOMEM; } @@ -6107,7 +6093,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n"); - kfree(tb); return 0; } @@ -6118,7 +6103,7 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff * const struct wmi_peer_delete_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6128,7 +6113,6 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff * ev = tb[WMI_TAG_PEER_DELETE_RESP_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch peer delete resp ev"); - kfree(tb); return -EPROTO; } @@ -6138,7 +6122,6 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff * ether_addr_copy(peer_del_resp->peer_macaddr.addr, ev->peer_macaddr.addr); - kfree(tb); return 0; } @@ -6150,7 +6133,7 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab, const struct wmi_vdev_delete_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6160,13 +6143,11 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab, ev = tb[WMI_TAG_VDEV_DELETE_RESP_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch vdev delete resp ev"); - kfree(tb); return -EPROTO; } *vdev_id = le32_to_cpu(ev->vdev_id); - kfree(tb); return 0; } @@ -6178,7 +6159,7 @@ static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, const struct wmi_bcn_tx_status_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6188,14 +6169,12 @@ static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, ev = tb[WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch bcn tx status ev"); - kfree(tb); return -EPROTO; } *vdev_id = le32_to_cpu(ev->vdev_id); *tx_status = le32_to_cpu(ev->tx_status); - kfree(tb); return 0; } @@ -6206,7 +6185,7 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_ const struct wmi_vdev_stopped_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6216,13 +6195,11 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_ ev = tb[WMI_TAG_VDEV_STOPPED_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch vdev stop ev"); - kfree(tb); return -EPROTO; } *vdev_id = le32_to_cpu(ev->vdev_id); - kfree(tb); return 0; } @@ -6361,7 +6338,7 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab, const struct wmi_mgmt_tx_compl_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6371,7 +6348,6 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab, ev = tb[WMI_TAG_MGMT_TX_COMPL_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch mgmt tx compl ev"); - kfree(tb); return -EPROTO; } @@ -6381,7 +6357,6 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab, param->ppdu_id = ev->ppdu_id; param->ack_rssi = ev->ack_rssi; - kfree(tb); return 0; } @@ -6544,7 +6519,7 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_scan_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6554,7 +6529,6 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb, ev = tb[WMI_TAG_SCAN_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch scan ev"); - kfree(tb); return -EPROTO; } @@ -6566,7 +6540,6 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb, scan_evt_param->vdev_id = ev->vdev_id; scan_evt_param->tsf_timestamp = ev->tsf_timestamp; - kfree(tb); return 0; } @@ -6577,7 +6550,7 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf const struct wmi_peer_sta_kickout_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6587,7 +6560,6 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf ev = tb[WMI_TAG_PEER_STA_KICKOUT_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch peer sta kickout ev"); - kfree(tb); return -EPROTO; } @@ -6595,7 +6567,6 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf arg->reason = le32_to_cpu(ev->reason); arg->rssi = le32_to_cpu(ev->rssi); - kfree(tb); return 0; } @@ -6606,7 +6577,7 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_roam_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6616,7 +6587,6 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb, ev = tb[WMI_TAG_ROAM_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch roam ev"); - kfree(tb); return -EPROTO; } @@ -6624,7 +6594,6 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb, roam_ev->reason = ev->reason; roam_ev->rssi = ev->rssi; - kfree(tb); return 0; } @@ -6658,7 +6627,7 @@ static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_chan_info_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6668,7 +6637,6 @@ static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, ev = tb[WMI_TAG_CHAN_INFO_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch chan info ev"); - kfree(tb); return -EPROTO; } @@ -6685,7 +6653,6 @@ static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, ch_info_ev->mac_clk_mhz = ev->mac_clk_mhz; ch_info_ev->vdev_id = ev->vdev_id; - kfree(tb); return 0; } @@ -6697,7 +6664,7 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_pdev_bss_chan_info_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6707,7 +6674,6 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, ev = tb[WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch pdev bss chan info ev"); - kfree(tb); return -EPROTO; } @@ -6725,7 +6691,6 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, bss_ch_info_ev->rx_bss_cycle_count_low = ev->rx_bss_cycle_count_low; bss_ch_info_ev->rx_bss_cycle_count_high = ev->rx_bss_cycle_count_high; - kfree(tb); return 0; } @@ -6737,7 +6702,7 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk const struct wmi_vdev_install_key_compl_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6747,7 +6712,6 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk ev = tb[WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch vdev install key compl ev"); - kfree(tb); return -EPROTO; } @@ -6757,7 +6721,6 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk arg->key_flags = le32_to_cpu(ev->key_flags); arg->status = le32_to_cpu(ev->status); - kfree(tb); return 0; } @@ -6768,7 +6731,7 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff const struct wmi_peer_assoc_conf_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6778,14 +6741,12 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff ev = tb[WMI_TAG_PEER_ASSOC_CONF_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch peer assoc conf ev"); - kfree(tb); return -EPROTO; } peer_assoc_conf->vdev_id = le32_to_cpu(ev->vdev_id); peer_assoc_conf->macaddr = ev->peer_macaddr.addr; - kfree(tb); return 0; } @@ -6803,7 +6764,7 @@ static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *s const void **tb; int ret, i; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6812,7 +6773,6 @@ static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *s ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT]; if (!ev) { - kfree(tb); ath12k_warn(ab, "failed to fetch 11d new cc ev"); return -EPROTO; } @@ -6825,8 +6785,6 @@ static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *s ab->new_alpha2[0], ab->new_alpha2[1]); - kfree(tb); - for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; @@ -8606,7 +8564,7 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab, const struct wmi_pdev_ctl_failsafe_chk_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -8616,7 +8574,6 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab, ev = tb[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch pdev ctl failsafe check ev"); - kfree(tb); return; } @@ -8630,8 +8587,6 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab, if (ev->ctl_failsafe_status != 0) ath12k_warn(ab, "pdev ctl failsafe failure status %d", ev->ctl_failsafe_status); - - kfree(tb); } static void @@ -8703,7 +8658,7 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab, const u32 *vdev_ids; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -8715,7 +8670,6 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab, if (!ev || !vdev_ids) { ath12k_warn(ab, "failed to fetch pdev csa switch count ev"); - kfree(tb); return; } @@ -8725,8 +8679,6 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab, ev->num_vdevs); ath12k_wmi_process_csa_switch_count_event(ab, ev, vdev_ids); - - kfree(tb); } static void @@ -8738,7 +8690,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff struct ath12k *ar; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -8749,7 +8701,6 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff if (!ev) { ath12k_warn(ab, "failed to fetch pdev dfs radar detected ev"); - kfree(tb); return; } @@ -8788,8 +8739,6 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff exit: rcu_read_unlock(); - - kfree(tb); } static void ath12k_tm_wmi_event_segmented(struct ath12k_base *ab, u32 cmd_id, @@ -8800,7 +8749,7 @@ static void ath12k_tm_wmi_event_segmented(struct ath12k_base *ab, u32 cmd_id, int ret; u16 length; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); @@ -8811,14 +8760,11 @@ static void ath12k_tm_wmi_event_segmented(struct ath12k_base *ab, u32 cmd_id, ev = tb[WMI_TAG_ARRAY_BYTE]; if (!ev) { ath12k_warn(ab, "failed to fetch ftm msg\n"); - kfree(tb); return; } length = skb->len - TLV_HDR_SIZE; ath12k_tm_process_event(ab, cmd_id, ev, length); - kfree(tb); - tb = NULL; } static void @@ -8831,7 +8777,7 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab, int temp; u32 pdev_id; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ath12k_warn(ab, "failed to parse tlv: %ld\n", PTR_ERR(tb)); return; @@ -8840,15 +8786,12 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab, ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch pdev temp ev\n"); - kfree(tb); return; } temp = a_sle32_to_cpu(ev->temp); pdev_id = le32_to_cpu(ev->pdev_id); - kfree(tb); - ath12k_dbg(ab, ATH12K_DBG_WMI, "pdev temperature ev temp %d pdev_id %u\n", temp, pdev_id); @@ -8875,7 +8818,7 @@ static void ath12k_fils_discovery_event(struct ath12k_base *ab, const struct wmi_fils_discovery_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, @@ -8887,15 +8830,12 @@ static void ath12k_fils_discovery_event(struct ath12k_base *ab, ev = tb[WMI_TAG_HOST_SWFDA_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch FILS discovery event\n"); - kfree(tb); return; } ath12k_warn(ab, "FILS discovery frame expected from host for vdev_id: %u, transmission scheduled at %u, next TBTT: %u\n", ev->vdev_id, ev->fils_tt, ev->tbtt); - - kfree(tb); } static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, @@ -8905,7 +8845,7 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, const struct wmi_probe_resp_tx_status_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, @@ -8918,7 +8858,6 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, if (!ev) { ath12k_warn(ab, "failed to fetch probe response transmission status event"); - kfree(tb); return; } @@ -8926,8 +8865,6 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, ath12k_warn(ab, "Probe response transmission failed for vdev_id %u, status %u\n", ev->vdev_id, ev->tx_status); - - kfree(tb); } static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab, @@ -8939,7 +8876,7 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab, struct ath12k *ar; int ret, vdev_id; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse P2P NoA TLV: %d\n", ret); @@ -8949,10 +8886,8 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab, ev = tb[WMI_TAG_P2P_NOA_EVENT]; noa = tb[WMI_TAG_P2P_NOA_INFO]; - if (!ev || !noa) { - ret = -EPROTO; - goto out; - } + if (!ev || !noa) + return -EPROTO; vdev_id = __le32_to_cpu(ev->vdev_id); @@ -8975,8 +8910,6 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab, unlock: rcu_read_unlock(); -out: - kfree(tb); return ret; } @@ -8987,7 +8920,7 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, const void **tb; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -8995,10 +8928,8 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, } ev = tb[WMI_TAG_RFKILL_EVENT]; - if (!ev) { - kfree(tb); + if (!ev) return; - } ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi tlv rfkill state change gpio %d type %d radio_state %d\n", @@ -9011,7 +8942,6 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, spin_unlock_bh(&ab->base_lock); queue_work(ab->workqueue, &ab->rfkill_work); - kfree(tb); } static void @@ -9027,7 +8957,7 @@ static void ath12k_wmi_twt_enable_event(struct ath12k_base *ab, const struct wmi_twt_enable_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse wmi twt enable status event tlv: %d\n", @@ -9038,15 +8968,12 @@ static void ath12k_wmi_twt_enable_event(struct ath12k_base *ab, ev = tb[WMI_TAG_TWT_ENABLE_COMPLETE_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch twt enable wmi event\n"); - goto exit; + return; } ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt enable event pdev id %u status %u\n", le32_to_cpu(ev->pdev_id), le32_to_cpu(ev->status)); - -exit: - kfree(tb); } static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab, @@ -9056,7 +8983,7 @@ static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab, const struct wmi_twt_disable_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse wmi twt disable status event tlv: %d\n", @@ -9067,15 +8994,12 @@ static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab, ev = tb[WMI_TAG_TWT_DISABLE_COMPLETE_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch twt disable wmi event\n"); - goto exit; + return; } ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt disable event pdev id %d status %u\n", le32_to_cpu(ev->pdev_id), le32_to_cpu(ev->status)); - -exit: - kfree(tb); } static int ath12k_wmi_wow_wakeup_host_parse(struct ath12k_base *ab, @@ -9148,7 +9072,7 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, const void **tb; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -9158,7 +9082,6 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, ev = tb[WMI_TAG_GTK_OFFLOAD_STATUS_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch gtk offload status ev"); - kfree(tb); return; } @@ -9168,7 +9091,6 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, rcu_read_unlock(); ath12k_warn(ab, "failed to get arvif for vdev_id:%d\n", le32_to_cpu(ev->vdev_id)); - kfree(tb); return; } @@ -9184,8 +9106,6 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, (void *)&replay_ctr_be, GFP_ATOMIC); rcu_read_unlock(); - - kfree(tb); } static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab, @@ -9197,7 +9117,7 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab, const void **tb; int ret, i; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse mlo setup complete event tlv: %d\n", @@ -9208,7 +9128,6 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab, ev = tb[WMI_TAG_MLO_SETUP_COMPLETE_EVENT]; if (!ev) { ath12k_warn(ab, "failed to fetch mlo setup complete event\n"); - kfree(tb); return; } @@ -9227,14 +9146,11 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab, if (!ar) { ath12k_warn(ab, "invalid pdev_id %d status %u in setup complete event\n", ev->pdev_id, ev->status); - goto out; + return; } ar->mlo_setup_status = le32_to_cpu(ev->status); complete(&ar->mlo_setup_done); - -out: - kfree(tb); } static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab, @@ -9244,7 +9160,7 @@ static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab, const void **tb; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse(ab, skb); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse teardown complete event tlv: %d\n", ret); @@ -9252,13 +9168,8 @@ static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab, } ev = tb[WMI_TAG_MLO_TEARDOWN_COMPLETE]; - if (!ev) { + if (!ev) ath12k_warn(ab, "failed to fetch teardown complete event\n"); - kfree(tb); - return; - } - - kfree(tb); } #ifdef CONFIG_ATH12K_DEBUGFS @@ -11362,3 +11273,31 @@ int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab, dev_kfree_skb(skb); return ret; } + +int ath12k_wmi_alloc(void) +{ + guard(mutex)(&ath12k_wmi_mutex); + + if (!ath12k_wmi_tb) { + ath12k_wmi_tb = __alloc_percpu(WMI_TAG_MAX * sizeof(void *), + __alignof__(void *)); + if (!ath12k_wmi_tb) + return -ENOMEM; + + refcount_set(&ath12k_wmi_refcount, 1); + } else { + refcount_inc(&ath12k_wmi_refcount); + } + + return 0; +} + +void ath12k_wmi_free(void) +{ + guard(mutex)(&ath12k_wmi_mutex); + + if (refcount_dec_and_test(&ath12k_wmi_refcount)) { + free_percpu(ath12k_wmi_tb); + ath12k_wmi_tb = NULL; + } +} diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 45cd3d5bff3eb..f27197f912bc7 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -6599,4 +6599,7 @@ int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar, struct ath12k_reg_tpc_power_info *param); int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab, struct wmi_mlo_link_set_active_arg *param); +int ath12k_wmi_alloc(void); +void ath12k_wmi_free(void); + #endif