summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2026-10-13 14:03:34 +0200
committerJohannes Berg <johannes.berg@intel.com>2026-10-13 14:03:49 +0200
commitcd026e68fdbf88b9cc522b76c7a9d92c9a41f709 (patch)
tree7eb9db63064208af1adb960edc48167340e16bbe
parentfbcdcc450c47b2dbc0e3c790a40071e7485bb68c (diff)
parent4aa45334eb23d40bf31c43405daea9b73469f2a6 (diff)
Merge tag 'ath-next-20261012' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath
Jeff Johnson says: ================== ath.git patches for v7.4 (PR #3) Nothing special here, just a bunch of assorted cleanups and bug fixes spread across the ath family of Wi-Fi drivers. ================== Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c12
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/core.c21
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c33
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/ahb.c41
-rw-r--r--drivers/net/wireless/ath/ath12k/core.c37
-rw-r--r--drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/dp.h8
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/hw.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c87
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h26
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hw.c6
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c17
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/channel.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c9
19 files changed, 217 insertions, 94 deletions
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index e46f579d745d..efaea150025b 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -505,9 +505,8 @@ free_idr_pending_tx:
return ret;
}
-static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
+static void ath10k_htt_tx_clean_up_pending(int msdu_id, struct ath10k *ar)
{
- struct ath10k *ar = ctx;
struct ath10k_htt *htt = &ar->htt;
struct htt_tx_done tx_done = {};
@@ -517,8 +516,6 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
tx_done.status = HTT_TX_COMPL_STATE_DISCARD;
ath10k_txrx_tx_unref(htt, &tx_done);
-
- return 0;
}
void ath10k_htt_tx_destroy(struct ath10k_htt *htt)
@@ -535,8 +532,13 @@ void ath10k_htt_tx_destroy(struct ath10k_htt *htt)
static void ath10k_htt_flush_tx_queue(struct ath10k_htt *htt)
{
+ struct sk_buff *msdu;
+ int msdu_id;
+
ath10k_htc_stop_hl(htt->ar);
- idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
+
+ idr_for_each_entry(&htt->pending_tx, msdu, msdu_id)
+ ath10k_htt_tx_clean_up_pending(msdu_id, htt->ar);
}
void ath10k_htt_tx_stop(struct ath10k_htt *htt)
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index 0d74548a5f34..08a64f737fb4 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -1128,6 +1128,7 @@ err_release_qmi_handle:
err:
kfree(qmi);
+ ar_snoc->qmi = NULL;
return ret;
}
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index d2ed6a0ea7e3..766ae27306f4 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1275,9 +1275,6 @@ int ath11k_core_suspend_late(struct ath11k_base *ab)
if (ab->actual_pm_policy == ATH11K_PM_WOW)
return 0;
- ath11k_hif_irq_disable(ab);
- ath11k_hif_ce_irq_disable(ab);
-
ath11k_hif_power_down(ab, true);
return 0;
@@ -2333,17 +2330,9 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
int ret;
mutex_lock(&ab->core_lock);
+ ath11k_hif_irq_disable(ab);
+ ath11k_hif_ce_irq_disable(ab);
ath11k_thermal_unregister(ab);
-
- /*
- * ath11k_core_reset() already disabled the interrupts on the reset
- * path; only the firmware crash path reaches here with them live.
- */
- if (!ab->is_reset) {
- ath11k_hif_irq_disable(ab);
- ath11k_hif_ce_irq_disable(ab);
- }
-
ath11k_dp_pdev_free(ab);
ath11k_cfr_deinit(ab);
ath11k_spectral_deinit(ab);
@@ -2459,8 +2448,7 @@ void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab)
complete(&ar->thermal.wmi_sync);
wake_up(&ar->dp.tx_empty_waitq);
- idr_for_each(&ar->txmgmt_idr,
- ath11k_mac_tx_mgmt_pending_free, ar);
+ ath11k_mac_tx_mgmt_pending_free(ar);
idr_destroy(&ar->txmgmt_idr);
wake_up(&ar->txmgmt_empty_waitq);
@@ -2605,9 +2593,6 @@ static void ath11k_core_reset(struct work_struct *work)
time_left = wait_for_completion_timeout(&ab->recovery_start,
ATH11K_RECOVER_START_TIMEOUT_HZ);
- ath11k_hif_irq_disable(ab);
- ath11k_hif_ce_irq_disable(ab);
-
ath11k_hif_power_down(ab, false);
ath11k_hif_power_up(ab);
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index c1fa42edd363..1a237adaa37d 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -6167,25 +6167,27 @@ static void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id)
ath11k_mgmt_over_wmi_tx_drop(ar, msdu);
}
-int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
+void ath11k_mac_tx_mgmt_pending_free(struct ath11k *ar)
{
- struct ath11k *ar = ctx;
-
- ath11k_mac_tx_mgmt_free(ar, buf_id);
+ struct sk_buff *msdu;
+ int buf_id;
- return 0;
+ idr_for_each_entry(&ar->txmgmt_idr, msdu, buf_id)
+ ath11k_mac_tx_mgmt_free(ar, buf_id);
}
-static int ath11k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
+static void ath11k_mac_vif_txmgmt_cleanup(struct ath11k *ar,
+ struct ieee80211_vif *vif)
{
- struct ieee80211_vif *vif = ctx;
- struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
- struct ath11k *ar = skb_cb->ar;
-
- if (skb_cb->vif == vif)
- ath11k_mac_tx_mgmt_free(ar, buf_id);
+ struct ath11k_skb_cb *skb_cb;
+ struct sk_buff *skb;
+ int buf_id;
- return 0;
+ idr_for_each_entry(&ar->txmgmt_idr, skb, buf_id) {
+ skb_cb = ATH11K_SKB_CB(skb);
+ if (skb_cb->vif == vif)
+ ath11k_mac_tx_mgmt_free(ar, buf_id);
+ }
}
static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
@@ -7417,8 +7419,7 @@ err_vdev_del:
ath11k_peer_cleanup(ar, arvif->vdev_id);
- idr_for_each(&ar->txmgmt_idr,
- ath11k_mac_vif_txmgmt_idr_remove, vif);
+ ath11k_mac_vif_txmgmt_cleanup(ar, vif);
for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) {
spin_lock_bh(&ab->dp.tx_ring[i].tx_idr_lock);
@@ -10418,7 +10419,7 @@ static void __ath11k_mac_unregister(struct ath11k *ar)
ieee80211_unregister_hw(ar->hw);
- idr_for_each(&ar->txmgmt_idr, ath11k_mac_tx_mgmt_pending_free, ar);
+ ath11k_mac_tx_mgmt_pending_free(ar);
idr_destroy(&ar->txmgmt_idr);
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h
index 59f83c7175fd..127cb476b44b 100644
--- a/drivers/net/wireless/ath/ath11k/mac.h
+++ b/drivers/net/wireless/ath/ath11k/mac.h
@@ -162,7 +162,7 @@ struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id)
void ath11k_mac_drain_tx(struct ath11k *ar);
void ath11k_mac_peer_cleanup_all(struct ath11k *ar);
-int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
+void ath11k_mac_tx_mgmt_pending_free(struct ath11k *ar);
u8 ath11k_mac_bw_to_mac80211_bw(u8 bw);
enum nl80211_he_gi ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi);
enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy);
diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c
index 85360365aa4b..2c55aae06dd0 100644
--- a/drivers/net/wireless/ath/ath12k/ahb.c
+++ b/drivers/net/wireless/ath/ath12k/ahb.c
@@ -191,6 +191,26 @@ static void __ath12k_ahb_ext_irq_disable(struct ath12k_base *ab)
}
}
+static void ath12k_ahb_free_napi_for_group(struct ath12k_ext_irq_grp *irq_grp)
+{
+ netif_napi_del(&irq_grp->napi);
+ free_netdev(irq_grp->napi_ndev);
+ irq_grp->napi_ndev = NULL;
+}
+
+static void ath12k_ahb_free_napi(struct ath12k_base *ab, int num_ext_irq_grp)
+{
+ int i;
+
+ for (i = 0; i < num_ext_irq_grp; i++)
+ ath12k_ahb_free_napi_for_group(&ab->ext_irq_grp[i]);
+}
+
+static void ath12k_ahb_free_ext_napi(struct ath12k_base *ab)
+{
+ ath12k_ahb_free_napi(ab, ATH12K_EXT_IRQ_GRP_NUM_MAX);
+}
+
static void ath12k_ahb_ext_grp_enable(struct ath12k_ext_irq_grp *irq_grp)
{
int i;
@@ -622,8 +642,10 @@ static int ath12k_ahb_config_ext_irq(struct ath12k_base *ab)
irq_grp->grp_id = i;
irq_grp->napi_ndev = alloc_netdev_dummy(0);
- if (!irq_grp->napi_ndev)
- return -ENOMEM;
+ if (!irq_grp->napi_ndev) {
+ ret = -ENOMEM;
+ goto free_napi_ndev;
+ }
netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi,
ath12k_ahb_ext_grp_napi_poll);
@@ -675,12 +697,19 @@ static int ath12k_ahb_config_ext_irq(struct ath12k_base *ab)
ath12k_ahb_ext_interrupt_handler,
IRQF_TRIGGER_RISING,
irq_name[irq_idx], irq_grp);
- if (ret)
+ if (ret) {
ath12k_warn(ab, "failed request_irq for %d\n", irq);
+ ath12k_ahb_free_napi_for_group(irq_grp);
+ goto free_napi_ndev;
+ }
}
}
return 0;
+
+free_napi_ndev:
+ ath12k_ahb_free_napi(ab, i);
+ return ret;
}
static int ath12k_ahb_config_irq(struct ath12k_base *ab)
@@ -1353,7 +1382,7 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
ret = ab_ahb->device_family_ops->arch_init(ab);
if (ret) {
ath12k_err(ab, "AHB arch_init failed %d\n", ret);
- goto err_rproc_deconfigure;
+ goto err_free_ext_napi;
}
ret = ath12k_core_init(ab);
@@ -1367,6 +1396,9 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
err_deinit_arch:
ab_ahb->device_family_ops->arch_deinit(ab);
+err_free_ext_napi:
+ ath12k_ahb_free_ext_napi(ab);
+
err_rproc_deconfigure:
mutex_lock(&ath12k_rproc_info_lock);
ath12k_ahb_deconfigure_rproc(ab);
@@ -1409,6 +1441,7 @@ static void ath12k_ahb_free_resources(struct ath12k_base *ab)
struct platform_device *pdev = ab->pdev;
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
+ ath12k_ahb_free_ext_napi(ab);
ath12k_hal_srng_deinit(ab);
ath12k_ce_free_pipes(ab);
ath12k_ahb_resource_deinit(ab);
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index e527b59ecba5..25987bc58556 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -54,6 +54,7 @@ ath12k_mem_profile_based_param ath12k_mem_profile_based_param[] = {
.num_pool_tx_desc = 32768,
.rx_desc_count = 12288,
.rx_release_ring_size = 16384,
+ .rxdma_buf_ring_size = 8192,
},
},
[ATH12K_QMI_MEMORY_MODE_LOW_512_M] = {
@@ -68,10 +69,40 @@ ath12k_mem_profile_based_param ath12k_mem_profile_based_param[] = {
.num_pool_tx_desc = 16384,
.rx_desc_count = 6144,
.rx_release_ring_size = 8192,
+ .rxdma_buf_ring_size = 4096,
},
},
};
+/*
+ * On these machines the OS cannot control the WCN7850 hardware rfkill
+ * input, which reads as "radio off", so hardware rfkill must stay
+ * disabled. Ideally this would come from the connector node of the board
+ * DT, but that binding does not exist yet.
+ */
+static const struct ath12k_core_broken_rfkill_table {
+ enum ath12k_hw_rev hw_rev;
+ const char *compatible;
+} ath12k_core_broken_rfkill_table[] = {
+ { ATH12K_HW_WCN7850_HW20, "microsoft,denali" },
+ { ATH12K_HW_WCN7850_HW20, "microsoft,romulus13" },
+ { ATH12K_HW_WCN7850_HW20, "microsoft,romulus15" },
+ { /* Sentinel */ }
+};
+
+static bool ath12k_core_rfkill_is_broken(struct ath12k_base *ab)
+{
+ const struct ath12k_core_broken_rfkill_table *entry;
+
+ for (entry = ath12k_core_broken_rfkill_table; entry->compatible; entry++) {
+ if (ab->hw_rev == entry->hw_rev &&
+ of_machine_is_compatible(entry->compatible))
+ return true;
+ }
+
+ return false;
+}
+
static int ath12k_core_rfkill_config(struct ath12k_base *ab)
{
struct ath12k *ar;
@@ -83,6 +114,9 @@ static int ath12k_core_rfkill_config(struct ath12k_base *ab)
if (ath12k_acpi_get_disable_rfkill(ab))
return 0;
+ if (ath12k_core_rfkill_is_broken(ab))
+ return 0;
+
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
@@ -1537,8 +1571,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
complete_all(&ar->thermal.wmi_sync);
wake_up(&ar->dp.tx_empty_waitq);
- idr_for_each(&ar->txmgmt_idr,
- ath12k_mac_tx_mgmt_pending_free, ar);
+ ath12k_mac_tx_mgmt_pending_free(ar);
idr_destroy(&ar->txmgmt_idr);
wake_up(&ar->txmgmt_empty_waitq);
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
index b772181a496e..f84f1828275a 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
@@ -6190,7 +6190,7 @@ static ssize_t ath12k_write_htt_stats_type(struct file *file,
const int size = 32;
int num_args;
- if (count > size)
+ if (count >= size)
return -EINVAL;
char *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index c53eac20b989..108e27dd5797 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -31,6 +31,7 @@ struct ath12k_dp_profile_params {
u32 num_pool_tx_desc;
u32 rx_desc_count;
u32 rx_release_ring_size;
+ u32 rxdma_buf_ring_size;
};
#define DP_MON_PURGE_TIMEOUT_MS 100
@@ -210,7 +211,6 @@ struct ath12k_pdev_dp {
#define DP_REO_EXCEPTION_RING_SIZE 128
#define DP_REO_CMD_RING_SIZE 256
#define DP_REO_STATUS_RING_SIZE 2048
-#define DP_RXDMA_BUF_RING_SIZE 4096
#define DP_RX_MAC_BUF_RING_SIZE 4096
#define DP_RXDMA_REFILL_RING_SIZE 2048
#define DP_RXDMA_ERR_DST_RING_SIZE 1024
@@ -730,6 +730,12 @@ ath12k_dp_rx_release_ring_size(const struct ath12k_dp_profile_params *p)
return p->rx_release_ring_size;
}
+static inline u32
+ath12k_dp_rxdma_buf_ring_size(const struct ath12k_dp_profile_params *p)
+{
+ return p->rxdma_buf_ring_size;
+}
+
void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif);
void ath12k_dp_partner_cc_init(struct ath12k_base *ab);
int ath12k_dp_pdev_alloc(struct ath12k_base *ab);
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index cfaf26ae2720..36be543b7c50 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -1699,7 +1699,7 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab)
ret = ath12k_dp_srng_setup(ab,
&dp->rx_refill_buf_ring.refill_buf_ring,
HAL_RXDMA_BUF, 0, 0,
- DP_RXDMA_BUF_RING_SIZE);
+ ath12k_dp_rxdma_buf_ring_size(dp_params));
if (ret) {
ath12k_warn(ab, "failed to setup rx_refill_buf_ring\n");
return ret;
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index 1e652dc0d247..52558dd126a0 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -239,6 +239,7 @@ struct ath12k_hw_params {
} client;
bool host_alloc_ml_id;
+ bool advertise_iface_mac_pool;
};
struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 196b807210de..01f8c6572f65 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -9194,25 +9194,27 @@ static void ath12k_mac_tx_mgmt_free(struct ath12k *ar, int buf_id)
ath12k_mgmt_over_wmi_tx_drop(ar, msdu);
}
-int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
+void ath12k_mac_tx_mgmt_pending_free(struct ath12k *ar)
{
- struct ath12k *ar = ctx;
-
- ath12k_mac_tx_mgmt_free(ar, buf_id);
+ struct sk_buff *msdu;
+ int buf_id;
- return 0;
+ idr_for_each_entry(&ar->txmgmt_idr, msdu, buf_id)
+ ath12k_mac_tx_mgmt_free(ar, buf_id);
}
-static int ath12k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
+static void ath12k_mac_vif_txmgmt_cleanup(struct ath12k *ar,
+ struct ieee80211_vif *vif)
{
- struct ieee80211_vif *vif = ctx;
- struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
- struct ath12k *ar = skb_cb->ar;
-
- if (skb_cb->vif == vif)
- ath12k_mac_tx_mgmt_free(ar, buf_id);
+ struct ath12k_skb_cb *skb_cb;
+ struct sk_buff *skb;
+ int buf_id;
- return 0;
+ idr_for_each_entry(&ar->txmgmt_idr, skb, buf_id) {
+ skb_cb = ATH12K_SKB_CB(skb);
+ if (skb_cb->vif == vif)
+ ath12k_mac_tx_mgmt_free(ar, buf_id);
+ }
}
static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_link_vif *arvif,
@@ -10977,8 +10979,7 @@ err_vdev_del:
ath12k_peer_cleanup(ar, arvif->vdev_id);
ath12k_ahvif_put_link_cache(ahvif, arvif->link_id);
- idr_for_each(&ar->txmgmt_idr,
- ath12k_mac_vif_txmgmt_idr_remove, vif);
+ ath12k_mac_vif_txmgmt_cleanup(ar, vif);
ath12k_mac_vif_unref(ath12k_ab_to_dp(ab), vif);
@@ -14738,7 +14739,7 @@ static struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = {
static void ath12k_mac_cleanup_unregister(struct ath12k *ar)
{
- idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar);
+ ath12k_mac_tx_mgmt_pending_free(ar);
idr_destroy(&ar->txmgmt_idr);
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
@@ -14746,6 +14747,56 @@ static void ath12k_mac_cleanup_unregister(struct ath12k *ar)
kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
}
+static void ath12k_mac_cleanup_mac_address_list(struct ath12k_hw *ah)
+{
+ kfree(ah->hw->wiphy->addresses);
+ ah->hw->wiphy->addresses = NULL;
+ ah->hw->wiphy->n_addresses = 0;
+}
+
+static void ath12k_mac_setup_mac_address_list(struct ath12k_hw *ah,
+ const u8 *mac_addr)
+{
+ struct mac_address *addresses;
+ struct ath12k *ar;
+ u16 n_addresses;
+ int i;
+
+ /*
+ * wiphy->addresses is per wiphy, so the generated interface MAC
+ * pool is advertised for the whole ath12k_hw. The hw_params flag is
+ * expected to be consistent across all radios in an ath12k_hw, so
+ * use the first radio as the source.
+ */
+ ar = ath12k_ah_to_ar(ah, 0);
+ if (!ar->ab->hw_params->advertise_iface_mac_pool)
+ return;
+
+ /*
+ * Only the upper nibble of the first octet is varied, so at most 16
+ * addresses can be derived from one base.
+ */
+ n_addresses = min_t(u16, TARGET_NUM_VDEVS(ar->ab), 16);
+ if (n_addresses <= 1)
+ return;
+
+ addresses = kzalloc_objs(*addresses, n_addresses);
+ if (!addresses)
+ return;
+
+ ether_addr_copy(addresses[0].addr, mac_addr);
+ for (i = 1; i < n_addresses; i++) {
+ ether_addr_copy(addresses[i].addr, mac_addr);
+ /* set Local Administered Address bit */
+ addresses[i].addr[0] |= 0x2;
+
+ addresses[i].addr[0] += i << 4;
+ }
+
+ ah->hw->wiphy->addresses = addresses;
+ ah->hw->wiphy->n_addresses = n_addresses;
+}
+
static void ath12k_mac_hw_unregister(struct ath12k_hw *ah)
{
struct ieee80211_hw *hw = ah->hw;
@@ -14765,6 +14816,7 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah)
ath12k_mac_cleanup_unregister(ar);
ath12k_mac_cleanup_iface_combinations(ah);
+ ath12k_mac_cleanup_mac_address_list(ah);
SET_IEEE80211_DEV(hw, NULL);
}
@@ -14881,6 +14933,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
wiphy->available_antennas_tx = antennas_tx;
SET_IEEE80211_PERM_ADDR(hw, mac_addr);
+ ath12k_mac_setup_mac_address_list(ah, mac_addr);
SET_IEEE80211_DEV(hw, ab->dev);
ret = ath12k_mac_setup_iface_combinations(ah);
@@ -15123,6 +15176,8 @@ err_cleanup_unregister:
ath12k_mac_cleanup_unregister(ar);
}
+ ath12k_mac_cleanup_mac_address_list(ah);
+
SET_IEEE80211_DEV(hw, NULL);
return ret;
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index aba98afd4365..ae44ebfd9bd9 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -173,7 +173,7 @@ struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id)
void ath12k_mac_drain_tx(struct ath12k *ar);
void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
void ath12k_mac_dp_peer_cleanup(struct ath12k_hw *ah);
-int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
+void ath12k_mac_tx_mgmt_pending_free(struct ath12k *ar);
enum rate_info_bw ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw);
enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw bw);
enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher);
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h
index e1ab47b44433..822de3a4abc8 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h
@@ -2100,41 +2100,15 @@ enum hal_rx_reo_queue_pn_size {
#define HAL_RX_REO_QUEUE_INFO0_VLD BIT(0)
#define HAL_RX_REO_QUEUE_INFO0_ASSOC_LNK_DESC_COUNTER GENMASK(2, 1)
-#define HAL_RX_REO_QUEUE_INFO0_DIS_DUP_DETECTION BIT(3)
-#define HAL_RX_REO_QUEUE_INFO0_SOFT_REORDER_EN BIT(4)
#define HAL_RX_REO_QUEUE_INFO0_AC GENMASK(6, 5)
-#define HAL_RX_REO_QUEUE_INFO0_BAR BIT(7)
#define HAL_RX_REO_QUEUE_INFO0_RETRY BIT(8)
-#define HAL_RX_REO_QUEUE_INFO0_CHECK_2K_MODE BIT(9)
-#define HAL_RX_REO_QUEUE_INFO0_OOR_MODE BIT(10)
#define HAL_RX_REO_QUEUE_INFO0_BA_WINDOW_SIZE GENMASK(20, 11)
#define HAL_RX_REO_QUEUE_INFO0_PN_CHECK BIT(21)
-#define HAL_RX_REO_QUEUE_INFO0_EVEN_PN BIT(22)
-#define HAL_RX_REO_QUEUE_INFO0_UNEVEN_PN BIT(23)
-#define HAL_RX_REO_QUEUE_INFO0_PN_HANDLE_ENABLE BIT(24)
#define HAL_RX_REO_QUEUE_INFO0_PN_SIZE GENMASK(26, 25)
#define HAL_RX_REO_QUEUE_INFO0_IGNORE_AMPDU_FLG BIT(27)
#define HAL_RX_REO_QUEUE_INFO1_SVLD BIT(0)
#define HAL_RX_REO_QUEUE_INFO1_SSN GENMASK(12, 1)
-#define HAL_RX_REO_QUEUE_INFO1_CURRENT_IDX GENMASK(22, 13)
-#define HAL_RX_REO_QUEUE_INFO1_SEQ_2K_ERR BIT(23)
-#define HAL_RX_REO_QUEUE_INFO1_PN_ERR BIT(24)
-#define HAL_RX_REO_QUEUE_INFO1_PN_VALID BIT(31)
-
-#define HAL_RX_REO_QUEUE_INFO2_MPDU_COUNT GENMASK(6, 0)
-#define HAL_RX_REO_QUEUE_INFO2_MSDU_COUNT (31, 7)
-
-#define HAL_RX_REO_QUEUE_INFO3_TIMEOUT_COUNT GENMASK(9, 4)
-#define HAL_RX_REO_QUEUE_INFO3_FWD_DUE_TO_BAR_CNT GENMASK(15, 10)
-#define HAL_RX_REO_QUEUE_INFO3_DUPLICATE_COUNT GENMASK(31, 16)
-
-#define HAL_RX_REO_QUEUE_INFO4_FRAME_IN_ORD_COUNT GENMASK(23, 0)
-#define HAL_RX_REO_QUEUE_INFO4_BAR_RECVD_COUNT GENMASK(31, 24)
-
-#define HAL_RX_REO_QUEUE_INFO5_LATE_RX_MPDU_COUNT GENMASK(11, 0)
-#define HAL_RX_REO_QUEUE_INFO5_WINDOW_JUMP_2K GENMASK(15, 12)
-#define HAL_RX_REO_QUEUE_INFO5_HOLE_COUNT GENMASK(31, 16)
struct hal_rx_reo_queue {
struct hal_desc_header desc_hdr;
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
index aec7c652808c..b1c17cc197df 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
@@ -447,6 +447,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
},
.host_alloc_ml_id = true,
+ .advertise_iface_mac_pool = false,
},
{
.name = "wcn7850 hw2.0",
@@ -542,6 +543,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
},
.host_alloc_ml_id = false,
+ .advertise_iface_mac_pool = true,
},
{
.name = "qcn9274 hw2.0",
@@ -633,6 +635,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
},
.host_alloc_ml_id = true,
+ .advertise_iface_mac_pool = false,
},
{
.name = "ipq5332 hw1.0",
@@ -718,6 +721,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
},
.host_alloc_ml_id = true,
+ .advertise_iface_mac_pool = false,
},
{
.name = "qcc2072 hw1.0",
@@ -814,6 +818,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
},
.host_alloc_ml_id = false,
+ .advertise_iface_mac_pool = true,
},
{
.name = "ipq5424 hw1.0",
@@ -902,6 +907,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
},
.host_alloc_ml_id = true,
+ .advertise_iface_mac_pool = false,
},
};
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 3149b6376c94..75b259990c79 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5050,6 +5050,7 @@ static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab,
u16 tag, u16 len,
const void *ptr, void *data)
{
+ struct ath12k_svc_ext_info *svc_ext_info = &ab->wmi_ab.svc_ext_info;
struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0];
struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;
int ret;
@@ -5094,6 +5095,22 @@ static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab,
return ret;
}
+ if (svc_rdy_ext->tot_phy_id >
+ ARRAY_SIZE(svc_ext_info->mac_phy_info)) {
+ ath12k_warn(ab, "too many PHY entries %u (max %zu)\n",
+ svc_rdy_ext->tot_phy_id,
+ ARRAY_SIZE(svc_ext_info->mac_phy_info));
+ return -EINVAL;
+ }
+
+ if (svc_rdy_ext->n_mac_phy_caps < svc_rdy_ext->tot_phy_id) {
+ ath12k_warn(ab,
+ "not enough MAC/PHY caps %u, expected %u\n",
+ svc_rdy_ext->n_mac_phy_caps,
+ svc_rdy_ext->tot_phy_id);
+ return -EINVAL;
+ }
+
ath12k_wmi_save_all_mac_phy_info(ab, svc_rdy_ext);
svc_rdy_ext->mac_phy_done = true;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index a9a35476fecd..65b7c68a9297 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1560,9 +1560,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
- rtnl_lock();
ath6kl_cfg80211_vif_cleanup(vif);
- rtnl_unlock();
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 8b27d8cc086a..cfb1c90eb4b6 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1363,6 +1363,8 @@ void ath9k_init_channel_context(struct ath_softc *sc)
void ath9k_deinit_channel_context(struct ath_softc *sc)
{
+ timer_shutdown_sync(&sc->sched.timer);
+ timer_shutdown_sync(&sc->offchannel.timer);
cancel_work_sync(&sc->chanctx_work);
}
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index ca01a07f6630..beedabee7d47 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -805,6 +805,15 @@ static ssize_t write_file_spec_scan_ctl(struct file *file,
buf[len] = '\0';
+ /*
+ * Every command below drives PHY register writes. Refuse them while
+ * the hardware is disabled (the interface is down): on the AR9271
+ * that traffic hangs the firmware until the device is re-enumerated.
+ * The reset control refuses on the same flag.
+ */
+ if (test_bit(ATH_OP_INVALID, &common->op_flags))
+ return -EBUSY;
+
if (strncmp("trigger", buf, 7) == 0) {
ath9k_cmn_spectral_scan_trigger(common, spec_priv);
} else if (strncmp("background", buf, 10) == 0) {