* [PATCH ath-next v7] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Nicolas Escande @ 2026-04-07 9:54 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless
On each WMI message received from the hardware, we alloc a temporary array
of WMI_TAG_MAX entries of type void *. This array is then populated with
pointers of parsed structs depending on the WMI type, and then freed. This
alloc can fail when memory pressure in the system is high enough.
Given the fact that it is scheduled in softirq with the system_bh_wq, we
should not be able to parse more than one WMI message per CPU at any time.
So instead lets move to a per cpu allocated array, that is reused across
calls. This memory is allocated as needed and refcounted to exist only
as long as one struct ath12k_base lives.
ath12k_wmi_tlv_parse_alloc() and ath12k_wmi_tlv_parse() are merged
together as it no longer allocs mem but returns the existing per-cpu one.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00218-QCAHKSWPL_SILICONZ-1
Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
---
changes from v6:
- fix useless ath12k_wmi_tb NULL init
- do not use refcount_inc when refount is at 0, it can warn
changes from v5:
- use of the refount_t kernel api
changes from v4:
- moved to a single instance, refcounted per cpu memory alloc
changes from v3:
- simplified ath12k_core_init() with a single statement
- move perpcu.h include directly to wmi.c
changes from v2:
- removed now superfluous return in ath12k_wmi_event_teardown_complete()
- moved ath12k_wmi_tb declaration to wmi.c & added two functions to
alloc / free it
- removed useless error message on memory allocation failure
changes from v1:
- rebased on ath-next 27401c9b1432
- changed wording according to Jeff's comment
- moved alloc/cleanup to new module_init/exit functions in the
ath12k module as per Baochen's comment
changes from RFC:
- rebased on ath-next 8e0ab5b9adb7
- converted missing call sites ath12k_wmi_obss_color_collision_event()
& ath12k_wmi_pdev_temperature_event()
- changed alloc order & cleanup path in ath12k_core_alloc() as it seems
it confused people
- used sizeof(*tb) in ath12k_wmi_tlv_parse()
---
drivers/net/wireless/ath/ath12k/core.c | 6 +
drivers/net/wireless/ath/ath12k/wmi.c | 217 +++++++++----------------
drivers/net/wireless/ath/ath12k/wmi.h | 3 +
3 files changed, 87 insertions(+), 139 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index c31c47fb5a73..6f0f4bfbf699 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -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:
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 65a05a9520ff..484fdd3b1b7f 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -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;
+ }
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 5ba9b7d3a888..4a34b2ca99ea 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -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
--
2.53.0
^ permalink raw reply related
* Re: [PATCH 1/1] wifi: cfg80211: wext: prevent encoding_size overflow in giwrange
From: Johannes Berg @ 2026-04-07 10:42 UTC (permalink / raw)
To: Ren Wei, linux-wireless
Cc: linville, kilroyd, yifanwucs, tomapufckgml, yuantan098, bird,
enjou1224z, xuyuqiabc
In-Reply-To: <20260402121007.339835-2-n05ec@lzu.edu.cn>
On Thu, 2026-04-02 at 20:10 +0800, Ren Wei wrote:
> From: Yuqi Xu <xuyuqiabc@gmail.com>
>
> cfg80211_wext_giwrange() appends one encoding_size entry for each
> WLAN_CIPHER_SUITE_WEP40 and WLAN_CIPHER_SUITE_WEP104 value advertised by
> the wiphy. struct iw_range only provides IW_MAX_ENCODING_SIZES slots in
> encoding_size[], so duplicated WEP entries can advance num_encoding_sizes
> past the end of the array and corrupt the iw_range buffer returned by
> SIOCGIWRANGE.
>
> This can happen when the wiphy cipher list contains duplicated WEP entries.
That's pretty ridiculous though, even if it can (right now) be reached
through hwsim.
Probably better to just make cfg80211 reject duplicate entries though
than specifically hacking wext...
johannes
^ permalink raw reply
* [PATCH wireless v3] wifi: mt76: mt7996: replace direct WTBL access with MCU for station statistics
From: Joshua Klinesmith @ 2026-04-07 10:45 UTC (permalink / raw)
To: linux-wireless
Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang,
Joshua Klinesmith
Direct MMIO access to WTBL entries for airtime and RSSI statistics in
mt7996_mac_sta_poll() races with firmware, causing warnings at
mt7996_mac_wtbl_lmac_addr, MCU message timeouts, and firmware
communication breakdown. The function was called from
mt7996_mac_tx_free() on every TX-Free-Done event, compounding the
issue with heavy CPU overhead.
Replace the direct WTBL polling with firmware MCU queries:
- Airtime: UNI_ALL_STA_TXRX_AIR_TIME via the existing all_sta_info
MCU command, with a new handler in mt7996_mcu_rx_all_sta_info_event()
- RSSI: UNI_PER_STA_RSSI via new mt7996_mcu_get_per_sta_info() using
MCU_WM_UNI_CMD(PER_STA_INFO)
Both queries run from mt7996_mac_work() every 5th tick under dev mutex,
matching the pattern already used for TX rate, admission stats, and
MSDU count reporting.
Remove mt7996_mac_sta_poll() and its airtime_ac tracking array entirely,
along with the now-orphaned mt76_wcid_add_poll() producers in the RX
status, TX free, and TX status paths that fed the removed consumer.
The per-sta-info response handler validates the firmware-returned entry
count against what was requested and against the skb payload length
before walking the response array, and uses bounds-checked
mt76_wcid_ptr() for WLAN ID lookup. RSSI polling is batched in groups
of PER_STA_INFO_MAX_NUM to cover the full WTBL capacity.
Vendor driver analysis (mt_wifi.ko from Xiaomi AX3000T MT7981 firmware)
confirms the RCPI-to-RSSI conversion formula (rcpi - 220) / 2 and that
the vendor never performs direct WTBL reads for statistics.
Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Link: https://github.com/openwrt/openwrt/issues/21177
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
.../wireless/mediatek/mt76/mt76_connac_mcu.h | 7 +
.../net/wireless/mediatek/mt76/mt7996/mac.c | 144 +-----------------
.../net/wireless/mediatek/mt76/mt7996/mcu.c | 133 ++++++++++++++++
.../net/wireless/mediatek/mt76/mt7996/mcu.h | 25 +++
.../wireless/mediatek/mt76/mt7996/mt7996.h | 2 +-
5 files changed, 168 insertions(+), 143 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index 8d59cf43f0e2..14d3ee7defa1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1392,6 +1392,13 @@ enum {
UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT,
};
+#define PER_STA_INFO_MAX_NUM 90
+
+enum UNI_PER_STA_INFO_TAG {
+ UNI_PER_STA_RSSI,
+ UNI_PER_STA_MAX_NUM
+};
+
enum UNI_ALL_STA_INFO_TAG {
UNI_ALL_STA_TXRX_RATE,
UNI_ALL_STA_TX_STAT,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index d4f3ee943b47..ad8377375265 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -111,119 +111,6 @@ u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw)
return MT_WTBL_LMAC_OFFS(wcid, dw);
}
-static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
-{
- static const u8 ac_to_tid[] = {
- [IEEE80211_AC_BE] = 0,
- [IEEE80211_AC_BK] = 1,
- [IEEE80211_AC_VI] = 4,
- [IEEE80211_AC_VO] = 6
- };
- struct mt7996_sta_link *msta_link;
- struct mt76_vif_link *mlink;
- struct ieee80211_sta *sta;
- struct mt7996_sta *msta;
- u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
- LIST_HEAD(sta_poll_list);
- struct mt76_wcid *wcid;
- int i;
-
- spin_lock_bh(&dev->mt76.sta_poll_lock);
- list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
- spin_unlock_bh(&dev->mt76.sta_poll_lock);
-
- rcu_read_lock();
-
- while (true) {
- bool clear = false;
- u32 addr, val;
- u16 idx;
- s8 rssi[4];
-
- spin_lock_bh(&dev->mt76.sta_poll_lock);
- if (list_empty(&sta_poll_list)) {
- spin_unlock_bh(&dev->mt76.sta_poll_lock);
- break;
- }
- msta_link = list_first_entry(&sta_poll_list,
- struct mt7996_sta_link,
- wcid.poll_list);
- msta = msta_link->sta;
- wcid = &msta_link->wcid;
- list_del_init(&wcid->poll_list);
- spin_unlock_bh(&dev->mt76.sta_poll_lock);
-
- idx = wcid->idx;
-
- /* refresh peer's airtime reporting */
- addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20);
-
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- u32 tx_last = msta_link->airtime_ac[i];
- u32 rx_last = msta_link->airtime_ac[i + 4];
-
- msta_link->airtime_ac[i] = mt76_rr(dev, addr);
- msta_link->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
-
- tx_time[i] = msta_link->airtime_ac[i] - tx_last;
- rx_time[i] = msta_link->airtime_ac[i + 4] - rx_last;
-
- if ((tx_last | rx_last) & BIT(30))
- clear = true;
-
- addr += 8;
- }
-
- if (clear) {
- mt7996_mac_wtbl_update(dev, idx,
- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
- memset(msta_link->airtime_ac, 0,
- sizeof(msta_link->airtime_ac));
- }
-
- if (!wcid->sta)
- continue;
-
- sta = container_of((void *)msta, struct ieee80211_sta,
- drv_priv);
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- u8 q = mt76_connac_lmac_mapping(i);
- u32 tx_cur = tx_time[q];
- u32 rx_cur = rx_time[q];
- u8 tid = ac_to_tid[i];
-
- if (!tx_cur && !rx_cur)
- continue;
-
- ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur);
- }
-
- /* get signal strength of resp frames (CTS/BA/ACK) */
- addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34);
- val = mt76_rr(dev, addr);
-
- rssi[0] = to_rssi(GENMASK(7, 0), val);
- rssi[1] = to_rssi(GENMASK(15, 8), val);
- rssi[2] = to_rssi(GENMASK(23, 16), val);
- rssi[3] = to_rssi(GENMASK(31, 14), val);
-
- mlink = rcu_dereference(msta->vif->mt76.link[wcid->link_id]);
- if (mlink) {
- struct mt76_phy *mphy = mt76_vif_link_phy(mlink);
-
- if (mphy)
- msta_link->ack_signal =
- mt76_rx_signal(mphy->antenna_mask,
- rssi);
- }
-
- ewma_avg_signal_add(&msta_link->avg_ack_signal,
- -msta_link->ack_signal);
- }
-
- rcu_read_unlock();
-}
-
/* The HW does not translate the mac header to 802.3 for mesh point */
static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
{
@@ -508,7 +395,6 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
msta_link = container_of(status->wcid, struct mt7996_sta_link,
wcid);
msta = msta_link->sta;
- mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid);
}
status->freq = mphy->chandef.chan->center_freq;
@@ -1355,9 +1241,6 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
info = le32_to_cpu(*cur_info);
if (info & MT_TXFREE_INFO_PAIR) {
struct ieee80211_sta *sta;
- unsigned long valid_links;
- struct mt7996_sta *msta;
- unsigned int id;
u16 idx;
idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
@@ -1371,22 +1254,6 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
link_sta = rcu_dereference(sta->link[wcid->link_id]);
if (!link_sta)
goto next;
-
- msta = (struct mt7996_sta *)sta->drv_priv;
- valid_links = sta->valid_links ?: BIT(0);
-
- /* For MLD STA, add all link's wcid to sta_poll_list */
- for_each_set_bit(id, &valid_links,
- IEEE80211_MLD_MAX_NUM_LINKS) {
- struct mt7996_sta_link *msta_link;
-
- msta_link = rcu_dereference(msta->link[id]);
- if (!msta_link)
- continue;
-
- mt76_wcid_add_poll(&dev->mt76,
- &msta_link->wcid);
- }
next:
/* ver 7 has a new DW with pair = 1, skip it */
if (ver == 7 && ((void *)(cur_info + 1) < end) &&
@@ -1424,8 +1291,6 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
}
}
- mt7996_mac_sta_poll(dev);
-
if (wake)
mt76_set_tx_blocked(&dev->mt76, false);
@@ -1590,7 +1455,6 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
{
- struct mt7996_sta_link *msta_link;
struct mt76_wcid *wcid;
__le32 *txs_data = data;
u16 wcidx;
@@ -1610,12 +1474,6 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data);
- if (!wcid->sta)
- goto out;
-
- msta_link = container_of(wcid, struct mt7996_sta_link, wcid);
- mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid);
-
out:
rcu_read_unlock();
}
@@ -2947,6 +2805,8 @@ void mt7996_mac_work(struct work_struct *work)
mt7996_mac_update_stats(phy);
mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_RATE);
+ mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_AIR_TIME);
+ mt7996_mcu_get_per_sta_info(phy, UNI_PER_STA_RSSI);
if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) {
mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_ADM_STAT);
mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_MSDU_COUNT);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index c0c042de477b..ffe30c914678 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -616,6 +616,33 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
wcid->stats.rx_packets +=
le32_to_cpu(res->msdu_cnt[i].rx_msdu_cnt);
break;
+ case UNI_ALL_STA_TXRX_AIR_TIME: {
+ static const u8 ac_to_tid[] = {
+ [IEEE80211_AC_BE] = 0,
+ [IEEE80211_AC_BK] = 1,
+ [IEEE80211_AC_VI] = 4,
+ [IEEE80211_AC_VO] = 6
+ };
+ struct ieee80211_sta *sta;
+
+ wlan_idx = le16_to_cpu(res->airtime[i].wlan_idx);
+ wcid = mt76_wcid_ptr(dev, wlan_idx);
+ sta = wcid_to_sta(wcid);
+ if (!sta)
+ break;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ u8 lmac_ac = mt76_connac_lmac_mapping(ac);
+ u32 tx_cur = le32_to_cpu(res->airtime[i].tx[lmac_ac]);
+ u32 rx_cur = le32_to_cpu(res->airtime[i].rx[lmac_ac]);
+
+ if (!tx_cur && !rx_cur)
+ continue;
+
+ ieee80211_sta_register_airtime(sta, ac_to_tid[ac], tx_cur, rx_cur);
+ }
+ break;
+ }
default:
break;
}
@@ -4755,6 +4782,112 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag)
&req, sizeof(req), false);
}
+int mt7996_mcu_get_per_sta_info(struct mt7996_phy *phy, u16 tag)
+{
+ struct mt7996_dev *dev = phy->dev;
+ struct mt7996_mcu_per_sta_info_event *res;
+ struct mt76_wcid *wcid;
+ struct sk_buff *skb;
+ int i, ret, sta_num, resp_sta_num;
+ int wcid_idx = 0;
+ struct {
+ u8 _rsv1;
+ u8 unsolicit;
+ u8 _rsv2[2];
+
+ __le16 tag;
+ __le16 len;
+ __le16 sta_num;
+ u8 _rsv3[2];
+ __le16 wlan_idx[PER_STA_INFO_MAX_NUM];
+ } __packed req = {
+ .tag = cpu_to_le16(tag),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ };
+
+ while (wcid_idx < mt7996_wtbl_size(dev)) {
+ sta_num = 0;
+
+ rcu_read_lock();
+ for (i = wcid_idx;
+ i < mt7996_wtbl_size(dev) && sta_num < PER_STA_INFO_MAX_NUM;
+ i++) {
+ wcid = rcu_dereference(dev->mt76.wcid[i]);
+ if (!wcid || !wcid->sta)
+ continue;
+ req.wlan_idx[sta_num++] = cpu_to_le16(i);
+ }
+ rcu_read_unlock();
+ wcid_idx = i;
+
+ if (!sta_num)
+ continue;
+
+ req.sta_num = cpu_to_le16(sta_num);
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
+ MCU_WM_UNI_CMD(PER_STA_INFO),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ res = (struct mt7996_mcu_per_sta_info_event *)skb->data;
+
+ resp_sta_num = le16_to_cpu(res->sta_num);
+ if (resp_sta_num > sta_num ||
+ skb->len < struct_size(res, rssi, resp_sta_num)) {
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ rcu_read_lock();
+ for (i = 0; i < resp_sta_num; i++) {
+ struct mt7996_sta_link *msta_link;
+ struct mt76_vif_data *mvif;
+ struct mt76_vif_link *mlink;
+ struct mt76_phy *mphy;
+ u16 wlan_idx;
+ s8 rssi[4];
+
+ switch (tag) {
+ case UNI_PER_STA_RSSI:
+ wlan_idx = le16_to_cpu(res->rssi[i].wlan_idx);
+ wcid = mt76_wcid_ptr(dev, wlan_idx);
+ if (!wcid || !wcid->sta)
+ break;
+
+ msta_link = container_of(wcid,
+ struct mt7996_sta_link,
+ wcid);
+
+ rssi[0] = (res->rssi[i].rcpi[0] - 220) / 2;
+ rssi[1] = (res->rssi[i].rcpi[1] - 220) / 2;
+ rssi[2] = (res->rssi[i].rcpi[2] - 220) / 2;
+ rssi[3] = (res->rssi[i].rcpi[3] - 220) / 2;
+
+ mvif = &msta_link->sta->vif->mt76;
+ mlink = rcu_dereference(mvif->link[wcid->link_id]);
+ if (mlink) {
+ mphy = mt76_vif_link_phy(mlink);
+ if (mphy)
+ msta_link->ack_signal =
+ mt76_rx_signal(mphy->antenna_mask,
+ rssi);
+ }
+
+ ewma_avg_signal_add(&msta_link->avg_ack_signal,
+ -msta_link->ack_signal);
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ dev_kfree_skb(skb);
+ }
+
+ return 0;
+}
+
int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id)
{
struct {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
index e0b83ac9f5e2..b5bad9a76c49 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
@@ -220,6 +220,31 @@ struct mt7996_mcu_all_sta_info_event {
__le32 tx_msdu_cnt;
__le32 rx_msdu_cnt;
} __packed, msdu_cnt);
+
+ DECLARE_FLEX_ARRAY(struct {
+ __le16 wlan_idx;
+ u8 rsv[2];
+ __le32 tx[IEEE80211_NUM_ACS];
+ __le32 rx[IEEE80211_NUM_ACS];
+ } __packed, airtime);
+ } __packed;
+} __packed;
+
+struct mt7996_mcu_per_sta_info_event {
+ u8 rsv[4];
+ __le16 tag;
+ __le16 len;
+ u8 more;
+ u8 rsv2;
+ __le16 sta_num;
+ u8 rsv3[4];
+
+ union {
+ DECLARE_FLEX_ARRAY(struct {
+ __le16 wlan_idx;
+ u8 rsv[2];
+ u8 rcpi[4];
+ } __packed, rssi);
} __packed;
} __packed;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 7a884311800e..b523e971f78c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -222,7 +222,6 @@ struct mt7996_sta_link {
struct mt7996_sta *sta;
struct list_head rc_list;
- u32 airtime_ac[8];
int ack_signal;
struct ewma_avg_signal avg_ack_signal;
@@ -741,6 +740,7 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev);
void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
void mt7996_mcu_exit(struct mt7996_dev *dev);
int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
+int mt7996_mcu_get_per_sta_info(struct mt7996_phy *phy, u16 tag);
int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2] iwlwifi: dvm: add missing cleaup for on error path
From: Johannes Berg @ 2026-04-07 10:50 UTC (permalink / raw)
To: Markus Elfring, Haoxiang Li, linux-wireless, Miri Korenblit; +Cc: LKML
In-Reply-To: <604fd5a1-135b-4a47-b752-52cb21d8863e@web.de>
On Thu, 2026-04-02 at 08:10 +0200, Markus Elfring wrote:
>
>
> 3. Would you like to avoid a typo in the summary phrase?
>
See also
https://lore.kernel.org/linux-wireless/3a7022fcd18fdaf98044f8a3a21b09a2f7cba914.camel@sipsolutions.net/
johannes
^ permalink raw reply
* Re: [PATCH] carl9170: main: track sw_scan state and suppress transient channel-change errors
From: Johannes Berg @ 2026-04-07 10:52 UTC (permalink / raw)
To: Masi Osmani, Christian Lamparter; +Cc: linux-wireless, ath9k-devel
In-Reply-To: <GVYP280MB15183AA20A65C0C5C03D09699453A@GVYP280MB1518.SWEP280.PROD.OUTLOOK.COM>
FWIW, all wifi patches should have "wifi: " prefix.
(but I think you're not going to get my email, hotmail doesn't like me)
johannes
^ permalink raw reply
* Re: [PATCH] mac80211: stop hardware before clearing driver state on reconfig failure
From: Johannes Berg @ 2026-04-07 10:53 UTC (permalink / raw)
To: Masi Osmani; +Cc: linux-wireless, Christian Lamparter
In-Reply-To: <GVYP280MB151883A5BB2910EE6439DE2F9453A@GVYP280MB1518.SWEP280.PROD.OUTLOOK.COM>
On Tue, 2026-03-31 at 12:00 +0200, Masi Osmani wrote:
> This patch fixes a hard system freeze (requires power cycle) observed
> when unplugging an AR9170 USB WiFi adapter while under traffic, or when
> any driver that uses ieee80211_reconfig() encounters a firmware deadlock.
>
> The race: ieee80211_handle_reconfig_failure() tears down station tables
> while USB RX tasklets can still deliver frames that reference them
> (use-after-free). Calling drv_stop() before clearing IN_DRIVER state
> closes the race at the root cause.
You can really stop resending this patch, I'm not taking it.
https://lore.kernel.org/linux-wireless/e7f3ba3acca1308bc0871a3892da9e15525d5038.camel@sipsolutions.net/
johannes
^ permalink raw reply
* [PATCH v2] rtlwifi: rtl8821ae: Remove dead code in rtl8821ae_update_hal_rate_table()
From: Chelsy Ratnawat @ 2026-04-07 12:34 UTC (permalink / raw)
To: pkshih
Cc: colin.i.king, johannes.berg, bhelgaas, arnd, linux-wireless,
Chelsy Ratnawat
The variable 'mimo_ps' is initialized to IEEE80211_SMPS_OFF and never
modified throughout the function. This makes the condition checking for
IEEE80211_SMPS_STATIC always evaluate to false, rendering the entire
if-branch unreachable dead code.
The error was reported by Coverity Scan.
Signed-off-by: Chelsy Ratnawat <chelsyratnawat2001@gmail.com>
---
Changes in v2:
- Declared local variable u32 ratr_mask at top of function.
.../wireless/realtek/rtlwifi/rtl8821ae/hw.c | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
index 3a4a33476205..c4dcae2d375e 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
@@ -3257,9 +3257,9 @@ static void rtl8821ae_update_hal_rate_table(struct ieee80211_hw *hw,
u32 ratr_value;
u8 ratr_index = 0;
u8 b_nmode = mac->ht_enable;
- u8 mimo_ps = IEEE80211_SMPS_OFF;
u16 shortgi_rate;
u32 tmp_ratr_value;
+ u32 ratr_mask;
u8 curtxbw_40mhz = mac->bw_40;
u8 b_curshortgi_40mhz = (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
1 : 0;
@@ -3288,19 +3288,14 @@ static void rtl8821ae_update_hal_rate_table(struct ieee80211_hw *hw,
case WIRELESS_MODE_N_24G:
case WIRELESS_MODE_N_5G:
b_nmode = 1;
- if (mimo_ps == IEEE80211_SMPS_STATIC) {
- ratr_value &= 0x0007F005;
- } else {
- u32 ratr_mask;
- if (get_rf_type(rtlphy) == RF_1T2R ||
- get_rf_type(rtlphy) == RF_1T1R)
- ratr_mask = 0x000ff005;
- else
- ratr_mask = 0x0f0ff005;
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_1T1R)
+ ratr_mask = 0x000ff005;
+ else
+ ratr_mask = 0x0f0ff005;
- ratr_value &= ratr_mask;
- }
+ ratr_value &= ratr_mask;
break;
default:
if (rtlphy->rf_type == RF_1T2R)
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2 4/7] arm64: dts: qcom: milos: Split up uart11 pinctrl
From: Konrad Dybcio @ 2026-04-07 13:07 UTC (permalink / raw)
To: Luca Weiss, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Alexander Koskovich,
Liam Girdwood, Mark Brown, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
Johannes Berg, Jeff Johnson
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, devicetree, linux-bluetooth, linux-wireless, ath11k
In-Reply-To: <20260403-milos-fp6-bt-wifi-v2-4-393322b27c5f@fairphone.com>
On 4/3/26 3:52 PM, Luca Weiss wrote:
> In order to set the pinctrl for the individual CTS, RTS, TX and RX pins,
> split up the pinctrl configuration into 4 nodes so that boards can set
> some properties separately.
>
> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH v2 6/7] arm64: dts: qcom: milos-fairphone-fp6: Enable Bluetooth
From: Konrad Dybcio @ 2026-04-07 13:10 UTC (permalink / raw)
To: Luca Weiss, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Alexander Koskovich,
Liam Girdwood, Mark Brown, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
Johannes Berg, Jeff Johnson
Cc: ~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, devicetree, linux-bluetooth, linux-wireless, ath11k
In-Reply-To: <20260403-milos-fp6-bt-wifi-v2-6-393322b27c5f@fairphone.com>
On 4/3/26 3:52 PM, Luca Weiss wrote:
> Add the nodes to describe the WCN6755 chip with its PMU and Bluetooth
> parts.
>
> Thanks to Alexander Koskovich for helping with the bringup, adding
> 'clocks' to the PMU node to make Bluetooth work.
>
> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
> ---
[...]
> + wcn6750-pmu {
> + compatible = "qcom,wcn6755-pmu", "qcom,wcn6750-pmu";
> +
> + vddaon-supply = <&vreg_s3b>;
> + vddasd-supply = <&vreg_l7b>;
> + vddpmu-supply = <&vreg_s3b>;
> + vddrfa0p8-supply = <&vreg_s3b>;
> + vddrfa1p2-supply = <&vreg_s2b>;
> + vddrfa1p7-supply = <&vreg_s1b>;
> + vddrfa2p2-supply = <&vreg_s1j>;
> +
> + bt-enable-gpios = <&tlmm 53 GPIO_ACTIVE_HIGH>;
> +
> + clocks = <&rpmhcc RPMH_RF_CLK1>;
nit: I should have caught this.. intriguing order of properties where
supplies are topmost during r3g2 review, which is presumably where
this originated from.. not a big deal though..
[...]
> + bluetooth_enable_default: bluetooth-enable-default-state {
> + pins = "gpio53";
> + function = "gpio";
> + output-low;
> + bias-disable;
nit: you shouldn't need to initially actively drive the pin, a
pull-down should be sufficient
(if insist you do, output-foo is usually below bias properties)
with or without changes:
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH v2 7/7] arm64: dts: qcom: milos-fairphone-fp6: Enable WiFi
From: Konrad Dybcio @ 2026-04-07 13:16 UTC (permalink / raw)
To: Dmitry Baryshkov, Luca Weiss, Jeff Johnson, Baochen Qiang
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Alexander Koskovich, Liam Girdwood, Mark Brown,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, Johannes Berg, Jeff Johnson,
~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, devicetree, linux-bluetooth, linux-wireless, ath11k
In-Reply-To: <4fbs4arx6sez6fffy75ctmzecfvitr6aocau3cczlr2ps2ptld@v7wpa2irsihl>
On 4/3/26 9:35 PM, Dmitry Baryshkov wrote:
> On Fri, Apr 03, 2026 at 03:52:53PM +0200, Luca Weiss wrote:
>> Configure and enable the WiFi node, and add the required pinctrl to
>> provide the sleep clock from the PMK8550 (PMK7635) to WCN6755.
>>
>> Thanks to Alexander Koskovich for helping with the bringup, adding
>> the missing pinctrl to make the WPSS stop crashing.
>>
>> Link: https://lore.kernel.org/linux-arm-msm/DBF7OWAWQ94M.FSCP4DPF8ZJY@fairphone.com/
>> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
>> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
>> ---
>> arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 19 ++++++++++++++++++-
>> 1 file changed, 18 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
>> index db72418b7195..d8ac495ca7c8 100644
>> --- a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
>> +++ b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
>> @@ -242,7 +242,7 @@ wcn6750-pmu {
>>
>> clocks = <&rpmhcc RPMH_RF_CLK1>;
>>
>> - pinctrl-0 = <&bluetooth_enable_default>;
>> + pinctrl-0 = <&bluetooth_enable_default>, <&pmk8550_sleep_clk_default>;
>> pinctrl-names = "default";
>>
>> regulators {
>> @@ -766,6 +766,17 @@ &pmiv0104_eusb2_repeater {
>> qcom,tune-usb2-preem = /bits/ 8 <0x6>;
>> };
>>
>> +&pmk8550_gpios {
>> + pmk8550_sleep_clk_default: sleep-clk-default-state {
>> + pins = "gpio5";
>> + function = "func1";
>> + input-disable;
>> + output-enable;
>
> Hmm, if it's a sleep_clk, should it not be handled via the power
> sequencer?
If you mean that it may be needed to toggle it with specific timings,
possibly.. seems that WCN6855 has a "xo-clk" GPIO defined. I requested
access to some docs that I think should have the answer, hopefully should
get it soon.
Or maybe +Jeff/Baochen could answer faster?
Konrad
^ permalink raw reply
* Re: [PATCH] mac80211_hwsim: change hwsim_class to a const struct
From: Johannes Berg @ 2026-04-07 13:46 UTC (permalink / raw)
To: Jori Koolstra; +Cc: Greg Kroah-Hartman, open list:MAC80211, open list
In-Reply-To: <20260401165938.3843784-1-jkoolstra@xs4all.nl>
Hi,
The subject should have a "wifi: " prefix. Maybe we need a MAINTAINERS
thing for that ...
Also, this patch doesn't apply on wireless-next, please respin.
johannes
^ permalink raw reply
* Re: [PATCH 3/3] wifi: Transition/Padding delay subfields are for both EMLSR and EMLMR
From: Johannes Berg @ 2026-04-07 14:00 UTC (permalink / raw)
To: Pablo Martin-Gomez; +Cc: linux-wireless
In-Reply-To: <20260327201135.905852-4-pmartin-gomez@freebox.fr>
On Fri, 2026-03-27 at 21:11 +0100, Pablo Martin-Gomez wrote:
> -#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY 0x0070
> +#define IEEE80211_EML_CAP_EMLSR_EMLMR_TRANSITION_DELAY 0x0070
> #define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_0US 0
> #define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_16US 1
> #define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_32US 2
I think this is confusing. You have the "EMLSR_EMLMR_" prefix in the
definition for the mask, but not in the values, but also the prefix
itself gets very long, not sure what to do about that. Maybe just
..._EML_TRANSITION_DELAY even if it doesn't match the spec completely.
And then another thing - I was going to apply the other two patches, but
really then looked at my git log and saw that no, really, the subjects
are stating a spec thing rather than describing a change, so please fix
that too.
johannes
^ permalink raw reply
* Re: [PATCH 0/3] wifi: refactor USB endpoint lookups
From: Johannes Berg @ 2026-04-07 14:01 UTC (permalink / raw)
To: Johan Hovold, linux-wireless; +Cc: libertas-dev, linux-kernel
In-Reply-To: <20260330103207.1671926-1-johan@kernel.org>
On Mon, 2026-03-30 at 12:32 +0200, Johan Hovold wrote:
> Use the common USB helper for looking up bulk and interrupt endpoints
> instead of open coding.
>
> Johan
>
>
> Johan Hovold (3):
> wifi: at76c50x: refactor endpoint lookup
> wifi: libertas: refactor endpoint lookup
> wifi: libertas_tf: refactor endpoint lookup
These didn't apply on wireless-next, please fix and resend.
johannes
^ permalink raw reply
* Re: [PATCH wireless v2] wifi: mt76: mt7996: replace direct WTBL access with MCU for station statistics
From: kernel test robot @ 2026-04-07 14:56 UTC (permalink / raw)
To: Joshua Klinesmith, linux-wireless
Cc: llvm, oe-kbuild-all, nbd, lorenzo, ryder.lee, shayne.chen,
sean.wang, Joshua Klinesmith
In-Reply-To: <20260407053855.75828-1-joshuaklinesmith@gmail.com>
Hi Joshua,
kernel test robot noticed the following build errors:
[auto build test ERROR on wireless/main]
[also build test ERROR on linus/master v7.0-rc7 next-20260406]
[cannot apply to wireless-next/main]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Joshua-Klinesmith/wifi-mt76-mt7996-replace-direct-WTBL-access-with-MCU-for-station-statistics/20260407-151612
base: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git main
patch link: https://lore.kernel.org/r/20260407053855.75828-1-joshuaklinesmith%40gmail.com
patch subject: [PATCH wireless v2] wifi: mt76: mt7996: replace direct WTBL access with MCU for station statistics
config: riscv-allmodconfig (https://download.01.org/0day-ci/archive/20260407/202604072310.QZ9n9tFj-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project c80443cd37b2e2788cba67ffa180a6331e5f0791)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260407/202604072310.QZ9n9tFj-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604072310.QZ9n9tFj-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4870:10: error: incompatible pointer types assigning to 'struct mt76_vif_link *' from 'struct mt76_vif_data *' [-Wincompatible-pointer-types]
4870 | mvif = &msta_link->sta->vif->mt76;
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
11 errors generated.
vim +4870 drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
4786
4787 int mt7996_mcu_get_per_sta_info(struct mt7996_phy *phy, u16 tag)
4788 {
4789 struct mt7996_dev *dev = phy->dev;
4790 struct mt7996_mcu_per_sta_info_event *res;
4791 struct mt76_wcid *wcid;
4792 struct sk_buff *skb;
4793 int i, ret, sta_num, resp_sta_num;
4794 int wcid_idx = 0;
4795 struct {
4796 u8 _rsv1;
4797 u8 unsolicit;
4798 u8 _rsv2[2];
4799
4800 __le16 tag;
4801 __le16 len;
4802 __le16 sta_num;
4803 u8 _rsv3[2];
4804 __le16 wlan_idx[PER_STA_INFO_MAX_NUM];
4805 } __packed req = {
4806 .tag = cpu_to_le16(tag),
4807 .len = cpu_to_le16(sizeof(req) - 4),
4808 };
4809
4810 while (wcid_idx < mt7996_wtbl_size(dev)) {
4811 sta_num = 0;
4812
4813 rcu_read_lock();
4814 for (i = wcid_idx;
4815 i < mt7996_wtbl_size(dev) && sta_num < PER_STA_INFO_MAX_NUM;
4816 i++) {
4817 wcid = rcu_dereference(dev->mt76.wcid[i]);
4818 if (!wcid || !wcid->sta)
4819 continue;
4820 req.wlan_idx[sta_num++] = cpu_to_le16(i);
4821 }
4822 rcu_read_unlock();
4823 wcid_idx = i;
4824
4825 if (!sta_num)
4826 continue;
4827
4828 req.sta_num = cpu_to_le16(sta_num);
4829
4830 ret = mt76_mcu_send_and_get_msg(&dev->mt76,
4831 MCU_WM_UNI_CMD(PER_STA_INFO),
4832 &req, sizeof(req), true, &skb);
4833 if (ret)
4834 return ret;
4835
4836 res = (struct mt7996_mcu_per_sta_info_event *)skb->data;
4837
4838 resp_sta_num = le16_to_cpu(res->sta_num);
4839 if (resp_sta_num > sta_num ||
4840 skb->len < struct_size(res, rssi, resp_sta_num)) {
4841 dev_kfree_skb(skb);
4842 return -EINVAL;
4843 }
4844
4845 rcu_read_lock();
4846 for (i = 0; i < resp_sta_num; i++) {
4847 struct mt7996_sta_link *msta_link;
4848 struct mt76_vif_link *mvif;
4849 struct mt76_vif_link *mlink;
4850 struct mt76_phy *mphy;
4851 u16 wlan_idx;
4852 s8 rssi[4];
4853
4854 switch (tag) {
4855 case UNI_PER_STA_RSSI:
4856 wlan_idx = le16_to_cpu(res->rssi[i].wlan_idx);
4857 wcid = mt76_wcid_ptr(dev, wlan_idx);
4858 if (!wcid || !wcid->sta)
4859 break;
4860
4861 msta_link = container_of(wcid,
4862 struct mt7996_sta_link,
4863 wcid);
4864
4865 rssi[0] = (res->rssi[i].rcpi[0] - 220) / 2;
4866 rssi[1] = (res->rssi[i].rcpi[1] - 220) / 2;
4867 rssi[2] = (res->rssi[i].rcpi[2] - 220) / 2;
4868 rssi[3] = (res->rssi[i].rcpi[3] - 220) / 2;
4869
> 4870 mvif = &msta_link->sta->vif->mt76;
4871 mlink = rcu_dereference(mvif->link[wcid->link_id]);
4872 if (mlink) {
4873 mphy = mt76_vif_link_phy(mlink);
4874 if (mphy)
4875 msta_link->ack_signal =
4876 mt76_rx_signal(mphy->antenna_mask,
4877 rssi);
4878 }
4879
4880 ewma_avg_signal_add(&msta_link->avg_ack_signal,
4881 -msta_link->ack_signal);
4882 break;
4883 }
4884 }
4885 rcu_read_unlock();
4886
4887 dev_kfree_skb(skb);
4888 }
4889
4890 return 0;
4891 }
4892
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH wireless v2] wifi: mt76: mt7996: replace direct WTBL access with MCU for station statistics
From: kernel test robot @ 2026-04-07 14:56 UTC (permalink / raw)
To: Joshua Klinesmith, linux-wireless
Cc: llvm, oe-kbuild-all, nbd, lorenzo, ryder.lee, shayne.chen,
sean.wang, Joshua Klinesmith
In-Reply-To: <20260407053855.75828-1-joshuaklinesmith@gmail.com>
Hi Joshua,
kernel test robot noticed the following build errors:
[auto build test ERROR on wireless/main]
[also build test ERROR on linus/master v7.0-rc7 next-20260406]
[cannot apply to wireless-next/main]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Joshua-Klinesmith/wifi-mt76-mt7996-replace-direct-WTBL-access-with-MCU-for-station-statistics/20260407-151612
base: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git main
patch link: https://lore.kernel.org/r/20260407053855.75828-1-joshuaklinesmith%40gmail.com
patch subject: [PATCH wireless v2] wifi: mt76: mt7996: replace direct WTBL access with MCU for station statistics
config: loongarch-allmodconfig (https://download.01.org/0day-ci/archive/20260407/202604072218.tGCSoRNR-lkp@intel.com/config)
compiler: clang version 19.1.7 (https://github.com/llvm/llvm-project cd708029e0b2869e80abe31ddb175f7c35361f90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260407/202604072218.tGCSoRNR-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202604072218.tGCSoRNR-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4870:10: error: incompatible pointer types assigning to 'struct mt76_vif_link *' from 'struct mt76_vif_data *' [-Werror,-Wincompatible-pointer-types]
4870 | mvif = &msta_link->sta->vif->mt76;
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:514:10: note: expanded from macro '__rcu_dereference_check'
514 | typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
| ^
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:514:31: note: expanded from macro '__rcu_dereference_check'
514 | typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
| ^
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:514:53: note: expanded from macro '__rcu_dereference_check'
514 | typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
| ^
note: (skipping 3 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
include/linux/compiler_types.h:706:22: note: expanded from macro 'compiletime_assert'
706 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~
include/linux/compiler_types.h:694:23: note: expanded from macro '_compiletime_assert'
694 | __compiletime_assert(condition, msg, prefix, suffix)
| ^~~~~~~~~
include/linux/compiler_types.h:686:9: note: expanded from macro '__compiletime_assert'
686 | if (!(condition)) \
| ^~~~~~~~~
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:514:53: note: expanded from macro '__rcu_dereference_check'
514 | typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
| ^
note: (skipping 3 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
include/linux/compiler_types.h:706:22: note: expanded from macro 'compiletime_assert'
706 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~
include/linux/compiler_types.h:694:23: note: expanded from macro '_compiletime_assert'
694 | __compiletime_assert(condition, msg, prefix, suffix)
| ^~~~~~~~~
include/linux/compiler_types.h:686:9: note: expanded from macro '__compiletime_assert'
686 | if (!(condition)) \
| ^~~~~~~~~
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:514:53: note: expanded from macro '__rcu_dereference_check'
514 | typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
| ^
note: (skipping 3 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
include/linux/compiler_types.h:706:22: note: expanded from macro 'compiletime_assert'
706 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~
include/linux/compiler_types.h:694:23: note: expanded from macro '_compiletime_assert'
694 | __compiletime_assert(condition, msg, prefix, suffix)
| ^~~~~~~~~
include/linux/compiler_types.h:686:9: note: expanded from macro '__compiletime_assert'
686 | if (!(condition)) \
| ^~~~~~~~~
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:514:53: note: expanded from macro '__rcu_dereference_check'
514 | typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
| ^
note: (skipping 3 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
include/linux/compiler_types.h:706:22: note: expanded from macro 'compiletime_assert'
706 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~
include/linux/compiler_types.h:694:23: note: expanded from macro '_compiletime_assert'
694 | __compiletime_assert(condition, msg, prefix, suffix)
| ^~~~~~~~~
include/linux/compiler_types.h:686:9: note: expanded from macro '__compiletime_assert'
686 | if (!(condition)) \
| ^~~~~~~~~
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:514:53: note: expanded from macro '__rcu_dereference_check'
514 | typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
| ^
note: (skipping 2 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
include/linux/compiler_types.h:706:22: note: expanded from macro 'compiletime_assert'
706 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~
include/linux/compiler_types.h:694:23: note: expanded from macro '_compiletime_assert'
694 | __compiletime_assert(condition, msg, prefix, suffix)
| ^~~~~~~~~
include/linux/compiler_types.h:686:9: note: expanded from macro '__compiletime_assert'
686 | if (!(condition)) \
| ^~~~~~~~~
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:514:53: note: expanded from macro '__rcu_dereference_check'
514 | typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
| ^
include/asm-generic/rwonce.h:50:14: note: expanded from macro 'READ_ONCE'
50 | __READ_ONCE(x); \
| ^
include/asm-generic/rwonce.h:44:65: note: expanded from macro '__READ_ONCE'
44 | #define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
| ^
include/linux/compiler_types.h:642:53: note: expanded from macro '__unqual_scalar_typeof'
642 | #define __unqual_scalar_typeof(x) __typeof_unqual__(x)
| ^
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:514:53: note: expanded from macro '__rcu_dereference_check'
514 | typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \
| ^
include/asm-generic/rwonce.h:50:14: note: expanded from macro 'READ_ONCE'
50 | __READ_ONCE(x); \
| ^
include/asm-generic/rwonce.h:44:72: note: expanded from macro '__READ_ONCE'
44 | #define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
| ^
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:35: error: no member named 'link' in 'struct mt76_vif_link'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ~~~~ ^
include/linux/rcupdate.h:752:50: note: expanded from macro 'rcu_dereference'
752 | #define rcu_dereference(p) rcu_dereference_check(p, 0)
| ^
include/linux/rcupdate.h:662:27: note: expanded from macro 'rcu_dereference_check'
662 | __rcu_dereference_check((p), __UNIQUE_ID(rcu), \
| ^
include/linux/rcupdate.h:517:12: note: expanded from macro '__rcu_dereference_check'
517 | ((typeof(*p) __force __kernel *)(local)); \
| ^
>> drivers/net/wireless/mediatek/mt76/mt7996/mcu.c:4871:11: error: assigning to 'struct mt76_vif_link *' from incompatible type 'void'
4871 | mlink = rcu_dereference(mvif->link[wcid->link_id]);
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 errors generated.
vim +4870 drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
4786
4787 int mt7996_mcu_get_per_sta_info(struct mt7996_phy *phy, u16 tag)
4788 {
4789 struct mt7996_dev *dev = phy->dev;
4790 struct mt7996_mcu_per_sta_info_event *res;
4791 struct mt76_wcid *wcid;
4792 struct sk_buff *skb;
4793 int i, ret, sta_num, resp_sta_num;
4794 int wcid_idx = 0;
4795 struct {
4796 u8 _rsv1;
4797 u8 unsolicit;
4798 u8 _rsv2[2];
4799
4800 __le16 tag;
4801 __le16 len;
4802 __le16 sta_num;
4803 u8 _rsv3[2];
4804 __le16 wlan_idx[PER_STA_INFO_MAX_NUM];
4805 } __packed req = {
4806 .tag = cpu_to_le16(tag),
4807 .len = cpu_to_le16(sizeof(req) - 4),
4808 };
4809
4810 while (wcid_idx < mt7996_wtbl_size(dev)) {
4811 sta_num = 0;
4812
4813 rcu_read_lock();
4814 for (i = wcid_idx;
4815 i < mt7996_wtbl_size(dev) && sta_num < PER_STA_INFO_MAX_NUM;
4816 i++) {
4817 wcid = rcu_dereference(dev->mt76.wcid[i]);
4818 if (!wcid || !wcid->sta)
4819 continue;
4820 req.wlan_idx[sta_num++] = cpu_to_le16(i);
4821 }
4822 rcu_read_unlock();
4823 wcid_idx = i;
4824
4825 if (!sta_num)
4826 continue;
4827
4828 req.sta_num = cpu_to_le16(sta_num);
4829
4830 ret = mt76_mcu_send_and_get_msg(&dev->mt76,
4831 MCU_WM_UNI_CMD(PER_STA_INFO),
4832 &req, sizeof(req), true, &skb);
4833 if (ret)
4834 return ret;
4835
4836 res = (struct mt7996_mcu_per_sta_info_event *)skb->data;
4837
4838 resp_sta_num = le16_to_cpu(res->sta_num);
4839 if (resp_sta_num > sta_num ||
4840 skb->len < struct_size(res, rssi, resp_sta_num)) {
4841 dev_kfree_skb(skb);
4842 return -EINVAL;
4843 }
4844
4845 rcu_read_lock();
4846 for (i = 0; i < resp_sta_num; i++) {
4847 struct mt7996_sta_link *msta_link;
4848 struct mt76_vif_link *mvif;
4849 struct mt76_vif_link *mlink;
4850 struct mt76_phy *mphy;
4851 u16 wlan_idx;
4852 s8 rssi[4];
4853
4854 switch (tag) {
4855 case UNI_PER_STA_RSSI:
4856 wlan_idx = le16_to_cpu(res->rssi[i].wlan_idx);
4857 wcid = mt76_wcid_ptr(dev, wlan_idx);
4858 if (!wcid || !wcid->sta)
4859 break;
4860
4861 msta_link = container_of(wcid,
4862 struct mt7996_sta_link,
4863 wcid);
4864
4865 rssi[0] = (res->rssi[i].rcpi[0] - 220) / 2;
4866 rssi[1] = (res->rssi[i].rcpi[1] - 220) / 2;
4867 rssi[2] = (res->rssi[i].rcpi[2] - 220) / 2;
4868 rssi[3] = (res->rssi[i].rcpi[3] - 220) / 2;
4869
> 4870 mvif = &msta_link->sta->vif->mt76;
> 4871 mlink = rcu_dereference(mvif->link[wcid->link_id]);
4872 if (mlink) {
4873 mphy = mt76_vif_link_phy(mlink);
4874 if (mphy)
4875 msta_link->ack_signal =
4876 mt76_rx_signal(mphy->antenna_mask,
4877 rssi);
4878 }
4879
4880 ewma_avg_signal_add(&msta_link->avg_ack_signal,
4881 -msta_link->ack_signal);
4882 break;
4883 }
4884 }
4885 rcu_read_unlock();
4886
4887 dev_kfree_skb(skb);
4888 }
4889
4890 return 0;
4891 }
4892
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH v4 net-next] net: use get_random_u{16,32,64}() where appropriate
From: David Carlier @ 2026-04-07 15:07 UTC (permalink / raw)
To: Jakub Kicinski, David S . Miller, Eric Dumazet, Paolo Abeni
Cc: Andrew Lunn, Simon Horman, Ilya Dryomov, Johannes Berg,
Matthieu Baerts, Mat Martineau, Geliang Tang, Aaron Conole,
Ilya Maximets, Marcelo Ricardo Leitner, Xin Long, Jon Maloy,
netdev, linux-wireless, mptcp, dev, linux-sctp, tipc-discussion,
linux-kernel, David Carlier
Use the typed random integer helpers instead of
get_random_bytes() when filling a single integer variable.
The helpers return the value directly, require no pointer
or size argument, and better express intent.
Skipped sites writing into __be16 (netdevsim) and __le64
(ceph) fields where a direct assignment would trigger
sparse endianness warnings.
Signed-off-by: David Carlier <devnexen@gmail.com>
Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
---
Notes:
Changes v3 -> v4:
- Dropped net/ceph/auth_x.c site: client_challenge is __le64,
direct assignment triggers sparse endianness warning
(Matthieu Baerts)
- Added Reviewed-by from Matthieu Baerts for net/mptcp changes
v3: https://lore.kernel.org/netdev/20260405154816.4774-1-devnexen@gmail.com/
v2: https://lore.kernel.org/netdev/Z/BfE0zn+DJxhBH7@debian/
drivers/net/netdevsim/psample.c | 4 ++--
net/core/net_namespace.c | 2 +-
net/mac80211/mesh_plink.c | 2 +-
net/mptcp/subflow.c | 4 ++--
net/openvswitch/flow_table.c | 2 +-
net/sctp/sm_make_chunk.c | 4 ++--
net/tipc/node.c | 2 +-
7 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/net/netdevsim/psample.c b/drivers/net/netdevsim/psample.c
index 47d24bc64ee4..717d157c3ae2 100644
--- a/drivers/net/netdevsim/psample.c
+++ b/drivers/net/netdevsim/psample.c
@@ -94,7 +94,7 @@ static void nsim_dev_psample_md_prepare(const struct nsim_dev_psample *psample,
if (psample->out_tc_occ_max) {
u64 out_tc_occ;
- get_random_bytes(&out_tc_occ, sizeof(u64));
+ out_tc_occ = get_random_u64();
md->out_tc_occ = out_tc_occ & (psample->out_tc_occ_max - 1);
md->out_tc_occ_valid = 1;
}
@@ -102,7 +102,7 @@ static void nsim_dev_psample_md_prepare(const struct nsim_dev_psample *psample,
if (psample->latency_max) {
u64 latency;
- get_random_bytes(&latency, sizeof(u64));
+ latency = get_random_u64();
md->latency = latency & (psample->latency_max - 1);
md->latency_valid = 1;
}
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 1057d16d5dd2..deb8b2ec5674 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -411,7 +411,7 @@ static __net_init int preinit_net(struct net *net, struct user_namespace *user_n
ref_tracker_dir_init(&net->refcnt_tracker, 128, "net_refcnt");
ref_tracker_dir_init(&net->notrefcnt_tracker, 128, "net_notrefcnt");
- get_random_bytes(&net->hash_mix, sizeof(u32));
+ net->hash_mix = get_random_u32();
net->dev_base_seq = 1;
net->user_ns = user_ns;
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 803106fc3134..7cbab90c8784 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -712,7 +712,7 @@ void mesh_plink_timer(struct timer_list *t)
"Mesh plink for %pM (retry, timeout): %d %d\n",
sta->sta.addr, sta->mesh->plink_retries,
sta->mesh->plink_timeout);
- get_random_bytes(&rand, sizeof(u32));
+ rand = get_random_u32();
sta->mesh->plink_timeout = sta->mesh->plink_timeout +
rand % sta->mesh->plink_timeout;
++sta->mesh->plink_retries;
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 5cfe19990f31..1a7736145dbc 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -72,7 +72,7 @@ static void subflow_req_create_thmac(struct mptcp_subflow_request_sock *subflow_
struct mptcp_sock *msk = subflow_req->msk;
u8 hmac[SHA256_DIGEST_SIZE];
- get_random_bytes(&subflow_req->local_nonce, sizeof(u32));
+ subflow_req->local_nonce = get_random_u32();
subflow_generate_hmac(READ_ONCE(msk->local_key),
READ_ONCE(msk->remote_key),
@@ -1639,7 +1639,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_pm_local *local,
ssk = sf->sk;
subflow = mptcp_subflow_ctx(ssk);
do {
- get_random_bytes(&subflow->local_nonce, sizeof(u32));
+ subflow->local_nonce = get_random_u32();
} while (!subflow->local_nonce);
/* if 'IPADDRANY', the ID will be set later, after the routing */
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
index 61c6a5f77c2e..67d5b8c0fe79 100644
--- a/net/openvswitch/flow_table.c
+++ b/net/openvswitch/flow_table.c
@@ -167,7 +167,7 @@ static struct table_instance *table_instance_alloc(int new_size)
ti->n_buckets = new_size;
ti->node_ver = 0;
- get_random_bytes(&ti->hash_seed, sizeof(u32));
+ ti->hash_seed = get_random_u32();
return ti;
}
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 2c0017d058d4..de86ac088289 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -2727,7 +2727,7 @@ __u32 sctp_generate_tag(const struct sctp_endpoint *ep)
__u32 x;
do {
- get_random_bytes(&x, sizeof(__u32));
+ x = get_random_u32();
} while (x == 0);
return x;
@@ -2738,7 +2738,7 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
{
__u32 retval;
- get_random_bytes(&retval, sizeof(__u32));
+ retval = get_random_u32();
return retval;
}
diff --git a/net/tipc/node.c b/net/tipc/node.c
index af442a5ef8f3..97aa970a0d83 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1275,7 +1275,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
goto exit;
if_name = strchr(b->name, ':') + 1;
- get_random_bytes(&session, sizeof(u16));
+ session = get_random_u16();
if (!tipc_link_create(net, if_name, b->identity, b->tolerance,
b->net_plane, b->mtu, b->priority,
b->min_win, b->max_win, session,
--
2.53.0
^ permalink raw reply related
* [PATCH v2 1/3] wifi: at76c50x: refactor endpoint lookup
From: Johan Hovold @ 2026-04-07 15:11 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, libertas-dev, linux-kernel, Johan Hovold
In-Reply-To: <20260407151111.3187826-1-johan@kernel.org>
Use the common USB helper for looking up bulk and interrupt endpoints
instead of open coding.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/net/wireless/atmel/at76c50x-usb.c | 22 ++++------------------
1 file changed, 4 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c
index 44b04ea3cc8b..32e3e09e7680 100644
--- a/drivers/net/wireless/atmel/at76c50x-usb.c
+++ b/drivers/net/wireless/atmel/at76c50x-usb.c
@@ -2226,34 +2226,20 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
static int at76_alloc_urbs(struct at76_priv *priv,
struct usb_interface *interface)
{
- struct usb_endpoint_descriptor *endpoint, *ep_in, *ep_out;
- int i;
+ struct usb_endpoint_descriptor *ep_in, *ep_out;
int buffer_size;
struct usb_host_interface *iface_desc;
+ int ret;
at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);
at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __func__,
interface->cur_altsetting->desc.bNumEndpoints);
- ep_in = NULL;
- ep_out = NULL;
iface_desc = interface->cur_altsetting;
- for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
- endpoint = &iface_desc->endpoint[i].desc;
-
- at76_dbg(DBG_URB, "%s: %d. endpoint: addr 0x%x attr 0x%x",
- __func__, i, endpoint->bEndpointAddress,
- endpoint->bmAttributes);
-
- if (!ep_in && usb_endpoint_is_bulk_in(endpoint))
- ep_in = endpoint;
- if (!ep_out && usb_endpoint_is_bulk_out(endpoint))
- ep_out = endpoint;
- }
-
- if (!ep_in || !ep_out) {
+ ret = usb_find_common_endpoints(iface_desc, &ep_in, &ep_out, NULL, NULL);
+ if (ret) {
dev_err(&interface->dev, "bulk endpoints missing\n");
return -ENXIO;
}
--
2.52.0
^ permalink raw reply related
* [PATCH v2 0/3] wifi: refactor USB endpoint lookups
From: Johan Hovold @ 2026-04-07 15:11 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, libertas-dev, linux-kernel, Johan Hovold
Use the common USB helper for looking up bulk and interrupt endpoints
instead of open coding.
Johan
Changes in v2:
- rebase on wireless-next
Johan Hovold (3):
wifi: at76c50x: refactor endpoint lookup
wifi: libertas: refactor endpoint lookup
wifi: libertas_tf: refactor endpoint lookup
drivers/net/wireless/atmel/at76c50x-usb.c | 22 ++-------
.../net/wireless/marvell/libertas/if_usb.c | 33 +++++++------
.../net/wireless/marvell/libertas_tf/if_usb.c | 46 +++++++++----------
3 files changed, 41 insertions(+), 60 deletions(-)
--
2.52.0
^ permalink raw reply
* [PATCH v2 2/3] wifi: libertas: refactor endpoint lookup
From: Johan Hovold @ 2026-04-07 15:11 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, libertas-dev, linux-kernel, Johan Hovold
In-Reply-To: <20260407151111.3187826-1-johan@kernel.org>
Use the common USB helpers for looking up bulk and interrupt endpoints
(and determining max packet size) instead of open coding.
Note that the driver has an implicit max packet size check which is
kept.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
.../net/wireless/marvell/libertas/if_usb.c | 33 +++++++++----------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
index 176f2106bab6..4fae0e335136 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
@@ -193,13 +193,12 @@ static void if_usb_reset_olpc_card(struct lbs_private *priv)
static int if_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct usb_endpoint_descriptor *ep_in, *ep_out;
struct usb_device *udev;
struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
struct lbs_private *priv;
struct if_usb_card *cardp;
int r = -ENOMEM;
- int i;
udev = interface_to_usbdev(intf);
@@ -224,25 +223,25 @@ static int if_usb_probe(struct usb_interface *intf,
init_usb_anchor(&cardp->rx_submitted);
init_usb_anchor(&cardp->tx_submitted);
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- if (usb_endpoint_is_bulk_in(endpoint)) {
- cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_in = usb_endpoint_num(endpoint);
+ if (usb_find_common_endpoints_reverse(iface_desc, &ep_in, &ep_out, NULL, NULL)) {
+ lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
+ goto dealloc;
+ }
- lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
- lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
+ cardp->ep_in_size = usb_endpoint_maxp(ep_in);
+ cardp->ep_in = usb_endpoint_num(ep_in);
- } else if (usb_endpoint_is_bulk_out(endpoint)) {
- cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_out = usb_endpoint_num(endpoint);
+ lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
+ lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
+
+ cardp->ep_out_size = usb_endpoint_maxp(ep_out);
+ cardp->ep_out = usb_endpoint_num(ep_out);
+
+ lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+ lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
- lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
- lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
- }
- }
if (!cardp->ep_out_size || !cardp->ep_in_size) {
- lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
+ lbs_deb_usbd(&udev->dev, "Endpoints not valid\n");
goto dealloc;
}
if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
--
2.52.0
^ permalink raw reply related
* [PATCH v2 3/3] wifi: libertas_tf: refactor endpoint lookup
From: Johan Hovold @ 2026-04-07 15:11 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, libertas-dev, linux-kernel, Johan Hovold
In-Reply-To: <20260407151111.3187826-1-johan@kernel.org>
Use the common USB helpers for looking up bulk and interrupt endpoints
(and determining max packet size) instead of open coding.
Note that the driver has an implicit max packet size check which is
kept.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
.../net/wireless/marvell/libertas_tf/if_usb.c | 46 +++++++++----------
1 file changed, 21 insertions(+), 25 deletions(-)
diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
index 07b38f2b8f58..b85c6d783bf7 100644
--- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
@@ -144,12 +144,12 @@ static const struct lbtf_ops if_usb_ops = {
static int if_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct usb_endpoint_descriptor *ep_in, *ep_out;
struct usb_device *udev;
struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
struct lbtf_private *priv;
struct if_usb_card *cardp;
- int i;
+ int ret;
lbtf_deb_enter(LBTF_DEB_USB);
udev = interface_to_usbdev(intf);
@@ -171,31 +171,27 @@ static int if_usb_probe(struct usb_interface *intf,
udev->descriptor.bDeviceSubClass,
udev->descriptor.bDeviceProtocol);
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- if (usb_endpoint_is_bulk_in(endpoint)) {
- cardp->ep_in_size =
- le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_in = usb_endpoint_num(endpoint);
-
- lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n",
- cardp->ep_in);
- lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n",
- cardp->ep_in_size);
- } else if (usb_endpoint_is_bulk_out(endpoint)) {
- cardp->ep_out_size =
- le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_out = usb_endpoint_num(endpoint);
-
- lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n",
- cardp->ep_out);
- lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n",
- cardp->ep_out_size);
- }
+ ret = usb_find_common_endpoints_reverse(iface_desc, &ep_in, &ep_out,
+ NULL, NULL);
+ if (ret) {
+ lbtf_deb_usbd(&udev->dev, "Endpoints not found\n");
+ goto dealloc;
}
+
+ cardp->ep_in_size = usb_endpoint_maxp(ep_in);
+ cardp->ep_in = usb_endpoint_num(ep_in);
+
+ lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
+ lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
+
+ cardp->ep_out_size = usb_endpoint_maxp(ep_out);
+ cardp->ep_out = usb_endpoint_num(ep_out);
+
+ lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+ lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
+
if (!cardp->ep_out_size || !cardp->ep_in_size) {
- lbtf_deb_usbd(&udev->dev, "Endpoints not found\n");
- /* Endpoints not found */
+ lbtf_deb_usbd(&udev->dev, "Endpoints not valid\n");
goto dealloc;
}
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v6] wifi: ath9k: Obtain system GPIOS from descriptors
From: Michał Kępień @ 2026-04-07 15:13 UTC (permalink / raw)
To: Linus Walleij
Cc: Jeff Johnson, Andy Shevchenko, Arnd Bergmann, Alban Bedel,
Bartosz Golaszewski, Toke Høiland-Jørgensen,
linux-wireless, brcm80211-dev-list.pdl, linux-gpio,
Bartosz Golaszewski
In-Reply-To: <20260317-descriptors-wireless-v6-1-b19ecff9cd2b@kernel.org>
Linus,
> The ath9k has an odd use of system-wide GPIOs: if the chip
> does not have internal GPIO capability, it will try to obtain a
> GPIO line from the system GPIO controller:
>
> if (BIT(gpio) & ah->caps.gpio_mask)
> ath9k_hw_gpio_cfg_wmac(...);
> else if (AR_SREV_SOC(ah))
> ath9k_hw_gpio_cfg_soc(ah, gpio, out, label);
>
> Where ath9k_hw_gpio_cfg_soc() will attempt to issue
> gpio_request_one() passing the local GPIO number of the controller
> (0..31) to gpio_request_one().
>
> This is somewhat peculiar and possibly even dangerous: there is
> nowadays no guarantee of the numbering of these system-wide
> GPIOs, and assuming that GPIO 0..31 as used by ath9k would
> correspond to GPIOs 0..31 on the system as a whole seems a bit
> wild.
>
> Register all 32 GPIOs at index 0..31 directly in the ATH79K
> GPIO driver and associate with the NULL device (making them
> widely available) if and only if we are probing ATH79K wifi
> from the AHB bus (used for SoCs). We obtain these offsets from
> the NULL device if necessary.
>
> These GPIOs should ideally be defined in the device tree
> instead, but we have no control over that for the legacy
> code path.
>
> Testcompiled with the ath79 defconfig.
I could only test a 6.12 backport of v6 on real hardware as that is the
kernel version that OpenWRT's current main branch uses for my router.
That being said, the only conflict I had to resolve was the one caused
by commit 551a097118391018ddc4079cbcec6fe4e7d64bc5 ("gpio: ath79: use
new generic GPIO chip API") in ath79_gpio_probe(), i.e. no functional
changes were necessary.
After replacing the "tweaked" version of v2 with a 6.12 backport of v6
in OpenWRT's source tree, the WiFi LED still works fine on my router.
For the above:
Tested-by: Michał Kępień <kernel@kempniu.pl>
--
Best regards,
Michał Kępień
^ permalink raw reply
* Re: [PATCH v4 net-next] net: use get_random_u{16,32,64}() where appropriate
From: Eric Dumazet @ 2026-04-07 15:14 UTC (permalink / raw)
To: David Carlier
Cc: Jakub Kicinski, David S . Miller, Paolo Abeni, Andrew Lunn,
Simon Horman, Ilya Dryomov, Johannes Berg, Matthieu Baerts,
Mat Martineau, Geliang Tang, Aaron Conole, Ilya Maximets,
Marcelo Ricardo Leitner, Xin Long, Jon Maloy, netdev,
linux-wireless, mptcp, dev, linux-sctp, tipc-discussion,
linux-kernel
In-Reply-To: <20260407150758.5889-1-devnexen@gmail.com>
On Tue, Apr 7, 2026 at 8:08 AM David Carlier <devnexen@gmail.com> wrote:
>
> Use the typed random integer helpers instead of
> get_random_bytes() when filling a single integer variable.
> The helpers return the value directly, require no pointer
> or size argument, and better express intent.
>
> Skipped sites writing into __be16 (netdevsim) and __le64
> (ceph) fields where a direct assignment would trigger
> sparse endianness warnings.
>
> Signed-off-by: David Carlier <devnexen@gmail.com>
> Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* Re: [PATCH ath-next] wifi: ath12k: Support channel change stats
From: Jeff Johnson @ 2026-04-07 15:22 UTC (permalink / raw)
To: Baochen Qiang, Roopni Devanathan, ath12k
Cc: linux-wireless, Harish Rachakonda
In-Reply-To: <63acfa83-753c-4b45-8f11-8e18e760cbf2@oss.qualcomm.com>
On 4/6/2026 8:23 PM, Baochen Qiang wrote:
> On 3/26/2026 1:06 PM, Roopni Devanathan wrote:
>> Note: WCN7850 firmware does not support HTT stats type 76.
>
> this note also applies to QCC2072.
I've updated this in 'pending'
https://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git/commit/?h=pending&id=a9adb8f605d5660f1db49f8cbec51ff73b4b7be8
^ permalink raw reply
* Re: [PATCH wireless 4/4] wifi: mt76: mt7925: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Ben Greear @ 2026-04-07 15:25 UTC (permalink / raw)
To: Joshua Klinesmith, linux-wireless
Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
stable
In-Reply-To: <20260406234739.29926-5-joshuaklinesmith@gmail.com>
On 4/6/26 16:47, Joshua Klinesmith wrote:
> The fourth receive chain RCPI uses GENMASK(31, 14), an 18-bit mask
> spanning bits 14-31. It should be GENMASK(31, 24), an 8-bit mask
> for the fourth byte, consistent with the other three chains and
> with the RCPI3 definitions used elsewhere in the driver
> (MT_PRXV_RCPI3 and MT_TXS7_F0_RCPI_3 both use GENMASK(31, 24)).
Hello Joshua,
How much of this is AI driven? As far as I know, mt7925 is a 2x2 chipset
at max. So while the patch may be correct, it may also not matter in practice
and at least may not need to be backported into stable. If it is a minor
cleanup that doesn't actually matter, that should be described more clearly
in the commit message?
Some of your patches are touching tricky parts of the code and making
subtle comparisons against how the vendor's driver is written. How well has
this been tested and reviewed by a knowledgeable human in general?
Thanks,
Ben
>
> On devices with fewer than 4 antenna chains, the corrupted value
> is masked out by antenna_mask in mt76_rx_signal(). On 4-chain
> devices, this produces incorrect ACK signal strength readings.
>
> Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
> Cc: stable@vger.kernel.org
> Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
> ---
> drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
> index 6334019249..85e91ca84f 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
> @@ -144,7 +144,7 @@ static void mt7925_mac_sta_poll(struct mt792x_dev *dev)
> rssi[0] = to_rssi(GENMASK(7, 0), val);
> rssi[1] = to_rssi(GENMASK(15, 8), val);
> rssi[2] = to_rssi(GENMASK(23, 16), val);
> - rssi[3] = to_rssi(GENMASK(31, 14), val);
> + rssi[3] = to_rssi(GENMASK(31, 24), val);
>
> mlink->ack_signal =
> mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH mt76] wifi: mt76: mt76x2u: Add support for ELECOM WDC-867SU3S
From: Zenm Chen @ 2026-04-07 15:44 UTC (permalink / raw)
To: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, matthias.bgg,
angelogioacchino.delregno, linux-wireless, linux-kernel,
linux-arm-kernel, linux-mediatek
Cc: zenmchen, stable
Add the ID 056e:400a to the table to support an additional MT7612U
adapter: ELECOM WDC-867SU3S.
Compile tested only.
Cc: stable@vger.kernel.org # 5.10.x
Signed-off-by: Zenm Chen <zenmchen@gmail.com>
---
This ID was found from [1] and adding it to the device table should be
enough to make it work. Hardware probes at [2] can prove its existence.
[1] https://bushowhige.blogspot.com/2019/08/ubuntu-1804-mediatek-usb-wi-fi.html
[2] https://linux-hardware.org/?id=usb:056e-400a
---
drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
index 01cb3b283..459c4044f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
@@ -16,6 +16,7 @@ static const struct usb_device_id mt76x2u_device_table[] = {
{ USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USBAC1200 - Alfa AWUS036ACM */
{ USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */
{ USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */
+ { USB_DEVICE(0x056e, 0x400a) }, /* ELECOM WDC-867SU3S */
{ USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */
{ USB_DEVICE(0x0471, 0x2126) }, /* LiteOn WN4516R module, nonstandard USB connector */
{ USB_DEVICE(0x0471, 0x7600) }, /* LiteOn WN4519R module, nonstandard USB connector */
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox