ath.git patches for v7.2 (PR #1)

For ath9k:
 - improve the GPIO interface.
 
 For ath12k:
 - replace dynamic memory allocation in WMI rx path
 - avoid buffer overread when configuring IRQs
 - code housekeeping
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQ/mtSHzPUi16IfDEksFbugiYzLewUCae9uIQAKCRAsFbugiYzL
 e6j9AQDl8svsSSmRgrw3IYVPlYi6W+XeY1hTFr7RR3AEkDQ8jgD+KbTQ2ogUJA2Q
 DLMnTKtbYczm3NLlza/75lbTDNkDpQs=
 =u5r4
 -----END PGP SIGNATURE-----

Merge tag 'ath-next-20260427' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath

Jeff Johnson says:
==================
ath.git patches for v7.2 (PR #1)

For ath9k:
- improve the GPIO interface.

For ath12k:
- replace dynamic memory allocation in WMI rx path
- avoid buffer overread when configuring IRQs
- code housekeeping
==================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2026-04-28 09:58:20 +02:00
commit 334a70c454
11 changed files with 188 additions and 169 deletions

View File

@ -11,6 +11,7 @@
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/generic.h>
#include <linux/gpio/machine.h> /* For WLAN GPIOs */
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mod_devicetable.h>
@ -214,6 +215,56 @@ static const struct of_device_id ath79_gpio_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
#if IS_ENABLED(CONFIG_ATH9K_AHB)
/*
* This registers all of the ath79k GPIOs as descriptors to be picked
* directly from the ATH79K wifi driver if the two are jitted together
* in the same SoC.
*/
#define ATH79K_WIFI_DESCS 32
static int ath79_gpio_register_wifi_descriptors(struct device *dev,
const char *label)
{
struct gpiod_lookup_table *lookup;
int i;
/* Create a gpiod lookup using gpiochip-local offsets + 1 for NULL */
lookup = devm_kzalloc(dev,
struct_size(lookup, table, ATH79K_WIFI_DESCS + 1),
GFP_KERNEL);
if (!lookup)
return -ENOMEM;
/*
* Ugly system-wide lookup for the NULL device: we know this
* is already NULL but explicitly assign it here for people to
* know what is going on. (Yes this is an ugly legacy hack, live
* with it.)
*/
lookup->dev_id = NULL;
for (i = 0; i < ATH79K_WIFI_DESCS; i++) {
lookup->table[i] =
/*
* Set the HW offset on the chip and the lookup
* index to the same value, so looking up index 0
* will get HW offset 0, index 1 HW offset 1 etc.
*/
GPIO_LOOKUP_IDX(label, i, "ath9k", i, GPIO_ACTIVE_HIGH);
}
gpiod_add_lookup_table(lookup);
return 0;
}
#else
static int ath79_gpio_register_wifi_descriptors(struct device *dev,
const char *label)
{
return 0;
}
#endif
static int ath79_gpio_probe(struct platform_device *pdev)
{
struct gpio_generic_chip_config config;
@ -276,7 +327,11 @@ static int ath79_gpio_probe(struct platform_device *pdev)
girq->handler = handle_simple_irq;
}
return devm_gpiochip_add_data(dev, &ctrl->chip.gc, ctrl);
err = devm_gpiochip_add_data(dev, &ctrl->chip.gc, ctrl);
if (err)
return err;
return ath79_gpio_register_wifi_descriptors(dev, ctrl->chip.gc.label);
}
static struct platform_driver ath79_gpio_driver = {

View File

@ -583,31 +583,36 @@ static int ath12k_ahb_config_ext_irq(struct ath12k_base *ab)
netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi,
ath12k_ahb_ext_grp_napi_poll);
for (j = 0; j < ATH12K_EXT_IRQ_NUM_MAX; j++) {
/* For TX ring, ensure that the ring mask and the
* tcl_to_wbm_rbm_map point to the same ring number.
*/
for (j = 0; j < DP_TCL_NUM_RING_MAX; j++) {
if (ring_mask->tx[i] &
BIT(ab->hal.tcl_to_wbm_rbm_map[j].wbm_ring_num)) {
BIT(ab->hal.tcl_to_wbm_rbm_map[j].wbm_ring_num) &&
num_irq < ATH12K_EXT_IRQ_NUM_MAX) {
irq_grp->irqs[num_irq++] =
wbm2host_tx_completions_ring1 - j;
}
}
if (ring_mask->rx[i] & BIT(j)) {
for (j = 0; j < ATH12K_EXT_IRQ_NUM_MAX; j++) {
if (ring_mask->rx[i] & BIT(j) &&
num_irq < ATH12K_EXT_IRQ_NUM_MAX) {
irq_grp->irqs[num_irq++] =
reo2host_destination_ring1 - j;
}
if (ring_mask->rx_err[i] & BIT(j))
if (ring_mask->rx_err[i] & BIT(j) &&
num_irq < ATH12K_EXT_IRQ_NUM_MAX)
irq_grp->irqs[num_irq++] = reo2host_exception;
if (ring_mask->rx_wbm_rel[i] & BIT(j))
if (ring_mask->rx_wbm_rel[i] & BIT(j) &&
num_irq < ATH12K_EXT_IRQ_NUM_MAX)
irq_grp->irqs[num_irq++] = wbm2host_rx_release;
if (ring_mask->reo_status[i] & BIT(j))
if (ring_mask->reo_status[i] & BIT(j) &&
num_irq < ATH12K_EXT_IRQ_NUM_MAX)
irq_grp->irqs[num_irq++] = reo2host_status;
if (ring_mask->rx_mon_dest[i] & BIT(j))
if (ring_mask->rx_mon_dest[i] & BIT(j) &&
num_irq < ATH12K_EXT_IRQ_NUM_MAX)
irq_grp->irqs[num_irq++] =
rxdma2host_monitor_destination_mac1;
}

View File

@ -2256,6 +2256,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);
@ -2280,6 +2281,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);
@ -2314,6 +2318,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:

View File

@ -146,7 +146,7 @@ static int ath12k_htt_tlv_ppdu_stats_parse(struct ath12k_base *ab,
}
int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len,
int (*iter)(struct ath12k_base *ar, u16 tag, u16 len,
int (*iter)(struct ath12k_base *ab, u16 tag, u16 len,
const void *ptr, void *data),
void *data)
{

View File

@ -1523,7 +1523,7 @@ int ath12k_dp_tx_htt_srng_setup(struct ath12k_base *ab, u32 ring_id,
void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
struct sk_buff *skb);
int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len,
int (*iter)(struct ath12k_base *ar, u16 tag, u16 len,
int (*iter)(struct ath12k_base *ab, u16 tag, u16 len,
const void *ptr, void *data),
void *data);
int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab);

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_HTC_H
@ -301,7 +301,7 @@ struct ath12k_htc {
u8 wmi_ep_count;
};
int ath12k_htc_init(struct ath12k_base *ar);
int ath12k_htc_init(struct ath12k_base *ab);
int ath12k_htc_wait_target(struct ath12k_htc *htc);
int ath12k_htc_start(struct ath12k_htc *htc);
int ath12k_htc_connect_service(struct ath12k_htc *htc,
@ -309,8 +309,8 @@ int ath12k_htc_connect_service(struct ath12k_htc *htc,
struct ath12k_htc_svc_conn_resp *conn_resp);
int ath12k_htc_send(struct ath12k_htc *htc, enum ath12k_htc_ep_id eid,
struct sk_buff *packet);
struct sk_buff *ath12k_htc_alloc_skb(struct ath12k_base *ar, int size);
void ath12k_htc_rx_completion_handler(struct ath12k_base *ar,
struct sk_buff *ath12k_htc_alloc_skb(struct ath12k_base *ab, int size);
void ath12k_htc_rx_completion_handler(struct ath12k_base *ab,
struct sk_buff *skb);
#endif

View File

@ -559,7 +559,6 @@ struct hal_eht_sig_ofdma_cmn_eb1 {
#define HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_4 GENMASK_ULL(35, 27)
#define HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_5 GENMASK_ULL(44, 36)
#define HAL_RX_EHT_SIG_OFDMA_EB2_RU_ALLOC_2_6 GENMASK_ULL(53, 45)
#define HAL_RX_EHT_SIG_OFDMA_EB2_MCS GNEMASK_ULL(57, 54)
struct hal_eht_sig_ofdma_cmn_eb2 {
__le64 info0;

View File

@ -15,6 +15,8 @@
#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"
@ -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 = 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;
}
@ -3911,9 +3907,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));
@ -5714,7 +5711,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);
@ -5724,13 +5721,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;
}
@ -5809,7 +5804,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);
@ -5819,7 +5814,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;
}
@ -5849,7 +5843,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;
}
@ -5859,7 +5852,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;
}
@ -5884,14 +5876,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;
}
@ -5993,7 +5983,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;
}
@ -6027,7 +6016,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;
}
@ -6046,7 +6034,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;
}
@ -6061,7 +6048,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;
}
@ -6096,7 +6082,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;
}
@ -6107,7 +6092,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);
@ -6117,7 +6102,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;
}
@ -6127,7 +6111,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;
}
@ -6139,7 +6122,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);
@ -6149,13 +6132,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;
}
@ -6167,7 +6148,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);
@ -6177,14 +6158,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;
}
@ -6195,7 +6174,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);
@ -6205,13 +6184,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;
}
@ -6350,7 +6327,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);
@ -6360,7 +6337,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;
}
@ -6370,7 +6346,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;
}
@ -6533,7 +6508,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);
@ -6543,7 +6518,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;
}
@ -6555,7 +6529,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;
}
@ -6566,7 +6539,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);
@ -6576,7 +6549,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;
}
@ -6584,7 +6556,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;
}
@ -6595,7 +6566,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);
@ -6605,7 +6576,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;
}
@ -6613,7 +6583,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;
}
@ -6647,7 +6616,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);
@ -6657,7 +6626,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;
}
@ -6674,7 +6642,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;
}
@ -6686,7 +6653,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);
@ -6696,7 +6663,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;
}
@ -6714,7 +6680,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;
}
@ -6726,7 +6691,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);
@ -6736,7 +6701,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;
}
@ -6746,7 +6710,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;
}
@ -6757,7 +6720,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);
@ -6767,14 +6730,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;
}
@ -6792,7 +6753,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);
@ -6801,7 +6762,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;
}
@ -6814,8 +6774,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;
@ -8557,7 +8515,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);
@ -8567,7 +8525,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;
}
@ -8581,8 +8538,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
@ -8654,7 +8609,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);
@ -8666,7 +8621,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;
}
@ -8676,8 +8630,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
@ -8689,7 +8641,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);
@ -8700,7 +8652,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;
}
@ -8739,8 +8690,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,
@ -8751,7 +8700,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);
@ -8762,14 +8711,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
@ -8782,7 +8728,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;
@ -8791,15 +8737,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);
@ -8826,7 +8769,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,
@ -8838,15 +8781,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,
@ -8856,7 +8796,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,
@ -8869,7 +8809,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;
}
@ -8877,8 +8816,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,
@ -8890,7 +8827,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);
@ -8900,10 +8837,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);
@ -8926,8 +8861,6 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
unlock:
rcu_read_unlock();
out:
kfree(tb);
return ret;
}
@ -8938,7 +8871,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);
@ -8946,10 +8879,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",
@ -8962,7 +8893,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
@ -8978,7 +8908,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",
@ -8989,15 +8919,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,
@ -9007,7 +8934,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",
@ -9018,15 +8945,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,
@ -9099,7 +9023,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);
@ -9109,7 +9033,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;
}
@ -9119,7 +9042,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;
}
@ -9135,8 +9057,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,
@ -9148,7 +9068,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",
@ -9159,7 +9079,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;
}
@ -9178,14 +9097,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,
@ -9195,7 +9111,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);
@ -9203,13 +9119,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
@ -11239,3 +11150,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;
}
}

View File

@ -6576,4 +6576,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

View File

@ -21,7 +21,7 @@
#include <linux/time.h>
#include <linux/bitops.h>
#include <linux/etherdevice.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/unaligned.h>
#include "hw.h"
@ -2719,19 +2719,28 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type)
static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out,
const char *label)
{
enum gpiod_flags flags = out ? GPIOD_OUT_LOW : GPIOD_IN;
struct gpio_desc *gpiod;
int err;
if (ah->caps.gpio_requested & BIT(gpio))
if (ah->gpiods[gpio])
return;
err = devm_gpio_request_one(ah->dev, gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label);
/*
* Obtains a system specific GPIO descriptor from another GPIO controller.
* Ideally this should come from the device tree, this is a legacy code
* path.
*/
gpiod = gpiod_get_index(NULL, "ath9k", gpio, flags);
err = PTR_ERR_OR_ZERO(gpiod);
if (err) {
ath_err(ath9k_hw_common(ah), "request GPIO%d failed:%d\n",
gpio, err);
return;
}
ah->caps.gpio_requested |= BIT(gpio);
gpiod_set_consumer_name(gpiod, label);
ah->gpiods[gpio] = gpiod;
}
static void ath9k_hw_gpio_cfg_wmac(struct ath_hw *ah, u32 gpio, bool out,
@ -2791,10 +2800,12 @@ void ath9k_hw_gpio_free(struct ath_hw *ah, u32 gpio)
if (!AR_SREV_SOC(ah))
return;
WARN_ON(gpio >= ah->caps.num_gpio_pins);
if (ah->gpiods[gpio]) {
gpiod_put(ah->gpiods[gpio]);
ah->gpiods[gpio] = NULL;
}
if (ah->caps.gpio_requested & BIT(gpio))
ah->caps.gpio_requested &= ~BIT(gpio);
WARN_ON(gpio >= ah->caps.num_gpio_pins);
}
EXPORT_SYMBOL(ath9k_hw_gpio_free);
@ -2822,8 +2833,8 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
val = REG_READ(ah, AR_GPIO_IN(ah)) & BIT(gpio);
else
val = MS_REG_READ(AR, gpio);
} else if (BIT(gpio) & ah->caps.gpio_requested) {
val = gpio_get_value(gpio) & BIT(gpio);
} else if (ah->gpiods[gpio]) {
val = gpiod_get_value(ah->gpiods[gpio]);
} else {
WARN_ON(1);
}
@ -2846,8 +2857,8 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
AR7010_GPIO_OUT : AR_GPIO_IN_OUT(ah);
REG_RMW(ah, out_addr, val << gpio, BIT(gpio));
} else if (BIT(gpio) & ah->caps.gpio_requested) {
gpio_set_value(gpio, val);
} else if (ah->gpiods[gpio]) {
gpiod_set_value(ah->gpiods[gpio], val);
} else {
WARN_ON(1);
}

View File

@ -19,6 +19,7 @@
#include <linux/if_ether.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/firmware.h>
@ -302,7 +303,6 @@ struct ath9k_hw_capabilities {
u8 max_rxchains;
u8 num_gpio_pins;
u32 gpio_mask;
u32 gpio_requested;
u8 rx_hp_qdepth;
u8 rx_lp_qdepth;
u8 rx_status_len;
@ -783,6 +783,7 @@ struct ath_hw {
struct ath9k_hw_capabilities caps;
struct ath9k_channel channels[ATH9K_NUM_CHANNELS];
struct ath9k_channel *curchan;
struct gpio_desc *gpiods[32];
union {
struct ar5416_eeprom_def def;