#include <linux/time.h>
#include <linux/of.h>
#include <linux/cleanup.h>
+#include <linux/percpu.h>
+#include <linux/refcount.h>
#include "core.h"
#include "debugfs.h"
#include "debug.h"
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 },
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 = kzalloc_objs(*tb, WMI_TAG_MAX, 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;
}
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));
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);
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;
}
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);
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n");
- kfree(tb);
return 0;
}
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);
ev = tb[WMI_TAG_PEER_DELETE_RESP_EVENT];
if (!ev) {
ath12k_warn(ab, "failed to fetch peer delete resp ev");
- kfree(tb);
return -EPROTO;
}
ether_addr_copy(peer_del_resp->peer_macaddr.addr,
ev->peer_macaddr.addr);
- kfree(tb);
return 0;
}
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);
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;
}
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);
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;
}
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);
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;
}
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);
ev = tb[WMI_TAG_MGMT_TX_COMPL_EVENT];
if (!ev) {
ath12k_warn(ab, "failed to fetch mgmt tx compl ev");
- kfree(tb);
return -EPROTO;
}
param->ppdu_id = ev->ppdu_id;
param->ack_rssi = ev->ack_rssi;
- kfree(tb);
return 0;
}
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);
ev = tb[WMI_TAG_SCAN_EVENT];
if (!ev) {
ath12k_warn(ab, "failed to fetch scan ev");
- kfree(tb);
return -EPROTO;
}
scan_evt_param->vdev_id = ev->vdev_id;
scan_evt_param->tsf_timestamp = ev->tsf_timestamp;
- kfree(tb);
return 0;
}
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);
ev = tb[WMI_TAG_PEER_STA_KICKOUT_EVENT];
if (!ev) {
ath12k_warn(ab, "failed to fetch peer sta kickout ev");
- kfree(tb);
return -EPROTO;
}
arg->reason = le32_to_cpu(ev->reason);
arg->rssi = le32_to_cpu(ev->rssi);
- kfree(tb);
return 0;
}
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);
ev = tb[WMI_TAG_ROAM_EVENT];
if (!ev) {
ath12k_warn(ab, "failed to fetch roam ev");
- kfree(tb);
return -EPROTO;
}
roam_ev->reason = ev->reason;
roam_ev->rssi = ev->rssi;
- kfree(tb);
return 0;
}
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);
ev = tb[WMI_TAG_CHAN_INFO_EVENT];
if (!ev) {
ath12k_warn(ab, "failed to fetch chan info ev");
- kfree(tb);
return -EPROTO;
}
ch_info_ev->mac_clk_mhz = ev->mac_clk_mhz;
ch_info_ev->vdev_id = ev->vdev_id;
- kfree(tb);
return 0;
}
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);
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;
}
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;
}
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);
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;
}
arg->key_flags = le32_to_cpu(ev->key_flags);
arg->status = le32_to_cpu(ev->status);
- kfree(tb);
return 0;
}
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);
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;
}
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);
ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT];
if (!ev) {
- kfree(tb);
ath12k_warn(ab, "failed to fetch 11d new cc ev");
return -EPROTO;
}
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;
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);
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;
}
if (ev->ctl_failsafe_status != 0)
ath12k_warn(ab, "pdev ctl failsafe failure status %d",
ev->ctl_failsafe_status);
-
- kfree(tb);
}
static void
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);
if (!ev || !vdev_ids) {
ath12k_warn(ab, "failed to fetch pdev csa switch count ev");
- kfree(tb);
return;
}
ev->num_vdevs);
ath12k_wmi_process_csa_switch_count_event(ab, ev, vdev_ids);
-
- kfree(tb);
}
static void
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);
if (!ev) {
ath12k_warn(ab, "failed to fetch pdev dfs radar detected ev");
- kfree(tb);
return;
}
exit:
rcu_read_unlock();
-
- kfree(tb);
}
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);
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
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;
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);
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,
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,
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,
if (!ev) {
ath12k_warn(ab,
"failed to fetch probe response transmission status event");
- kfree(tb);
return;
}
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,
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);
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);
unlock:
rcu_read_unlock();
-out:
- kfree(tb);
return ret;
}
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);
}
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",
spin_unlock_bh(&ab->base_lock);
queue_work(ab->workqueue, &ab->rfkill_work);
- kfree(tb);
}
static void
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",
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,
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",
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,
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);
ev = tb[WMI_TAG_GTK_OFFLOAD_STATUS_EVENT];
if (!ev) {
ath12k_warn(ab, "failed to fetch gtk offload status ev");
- kfree(tb);
return;
}
rcu_read_unlock();
ath12k_warn(ab, "failed to get arvif for vdev_id:%d\n",
le32_to_cpu(ev->vdev_id));
- kfree(tb);
return;
}
(void *)&replay_ctr_be, GFP_ATOMIC);
rcu_read_unlock();
-
- kfree(tb);
}
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",
ev = tb[WMI_TAG_MLO_SETUP_COMPLETE_EVENT];
if (!ev) {
ath12k_warn(ab, "failed to fetch mlo setup complete event\n");
- kfree(tb);
return;
}
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,
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);
}
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
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;
+ }
+}