mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Lots of fixes:
- mostly driver security/robustness/warning fixes
- ath12k: fix MLO throughput regression
- iwlwifi: add UNII-9 to avoid regression
- brcmfmac:
- fix 802.1X-SHA256
- SDIO fix for some boards
- mac80211:
- fix traffic indication for sleeping STAs
- fix NAN throughput
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmpgjBQACgkQ10qiO8sP
aACNoQ//dgLEKav5m9IfUvhZUV/G++3klPkCTUNU3dQesrHrGRxOk1sRuzoODINz
rC4IfDtoznIX964Lxc+RGLtTE1zUXJ9lR9YDvjXHyF+9kk8CvMbiKJo37IG4GCTc
DsQWL3cSK7X4yDbosd5gCXihjxOKFT65S2e9inFPLUWevi7mbb+Qny/jMd5yqh32
/q/YUKUPSjZqqUFnG1x9nrp4n+0ygBsqUK9o8w6cU9ed7bw2r6fJo+j0BkzxUsPH
Ntde80QKNYgqY73qJ0qEybm7o7XldBMSdHnaO0Iz9qOnlTclpyV7zrfca8ELx2Sx
GQ/1ws1G+/rg3AWsWkXsu8QrUk0e4WuKFel59BBYyfRsvmDjz9Hta9qW9WMioykQ
eGEM0EMJ683BtpYN4RKMmPG20jCxCi8dUBE8OGuRQX/c6exXyVysTNi3rt2oKsls
VMtd74DrdjYrm+MwnxAfnB1CIDlgCbbGMvoZMcQLSQTPmSM5822XKAlGCcNQjkL9
HC0D7KItFXp/LYEoELkXGy+D8ta0BVxJTtHzuf5Msx4DgVu+fmFOwyHud13Hfwei
JfrMMYjym3Aaa+X5y21HgzkqGmPJ9zg7vD5kXRt2vtwax9NiGxWqI/4EPSHD19l1
m6dhiOzYWmHPBsJMtLuvkG9Xmc8V3K40YDK6Dw/1i9yAbUBIpZE=
=BfIb
-----END PGP SIGNATURE-----
Merge tag 'wireless-2026-07-22' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless
Johannes Berg says:
====================
Lots of fixes:
- mostly driver security/robustness/warning fixes
- ath12k: fix MLO throughput regression
- iwlwifi: add UNII-9 to avoid regression
- brcmfmac:
- fix 802.1X-SHA256
- SDIO fix for some boards
- mac80211:
- fix traffic indication for sleeping STAs
- fix NAN throughput
* tag 'wireless-2026-07-22' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless: (80 commits)
wifi: brcmfmac: fix 802.1X-SHA256 call trace warning
wifi: mt76: mt7996: fix possible NULL-pointer deref in mt7996_mcu_sta_bfer_eht()
wifi: mt76: mt7925: fix crash in reset link replay
wifi: mt76: fix airoha_npu dependency tracking
wifi: mt76: restrict NPU/PPE active checks to MMIO devices
wifi: mt76: fix MAC address for non OF pcie cards
wifi: mt76: mt7996: check pointer returned by mt76_connac_get_he_phy_cap()
wifi: mt76: mt7925: fix possible NULL-pointer deref in mt7925_mcu_bss_he_tlv()
wifi: mt76: connac: fix possible NULL-pointer deref in mt76_connac_mcu_uni_bss_he_tlv()
wifi: mt76: mt7915: guard HE capability lookups
wifi: mt76: mt7925: guard link STA in decap offload
wifi: mt76: Disable napi when removing device
wifi: mt76: mt7615: drop TXRX_NOTIFY on non-mmio buses
wifi: mt76: mt7925: drop TXRX_NOTIFY on non-mmio buses
wifi: mt76: mt7921: drop TXRX_NOTIFY on non-mmio buses
wifi: brcmfmac: set F2 blocksize to 256 for BCM43752
wifi: cfg80211: guard optional PMSR nominal time
wifi: mac80211_hwsim: reject undersized HWSIM_ATTR_TX_INFO
wifi: brcmfmac: drain bus_reset work on device removal
wifi: brcmfmac: make release_scratchbuffers idempotent
...
====================
Link: https://patch.msgid.link/20260722092647.119094-3-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
fec15bb3da
|
|
@ -706,6 +706,7 @@ static int ath10k_htt_rx_pop_paddr32_list(struct ath10k_htt *htt,
|
|||
if (!(__le32_to_cpu(rxd_attention->flags) &
|
||||
RX_ATTENTION_FLAGS_MSDU_DONE)) {
|
||||
ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
|
||||
__skb_queue_purge(list);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
|
@ -770,6 +771,7 @@ static int ath10k_htt_rx_pop_paddr64_list(struct ath10k_htt *htt,
|
|||
if (!(__le32_to_cpu(rxd_attention->flags) &
|
||||
RX_ATTENTION_FLAGS_MSDU_DONE)) {
|
||||
ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
|
||||
__skb_queue_purge(list);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -996,6 +996,7 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
|
|||
ret = ath11k_ahb_setup_msa_resources(ab);
|
||||
if (ret) {
|
||||
ath11k_err(ab, "failed to setup msa resources\n");
|
||||
of_node_put(node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4618,6 +4618,9 @@ static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar,
|
|||
msdu_details = &msdu_link->msdu_link[0];
|
||||
|
||||
for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) {
|
||||
if (!i && FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
|
||||
msdu_details[i].buf_addr_info.info0) == 0)
|
||||
break;
|
||||
if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
|
||||
msdu_details[i].buf_addr_info.info0) == 0) {
|
||||
msdu_desc_info = &msdu_details[i - 1].rx_msdu_info;
|
||||
|
|
|
|||
|
|
@ -199,6 +199,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
|
|||
val |= PCIE_SOC_GLOBAL_RESET_V;
|
||||
|
||||
ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
|
||||
/* Flush the posted write to the device */
|
||||
ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
|
||||
|
||||
/* TODO: exact time to sleep is uncertain */
|
||||
delay = 10;
|
||||
|
|
@ -208,6 +210,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
|
|||
val &= ~PCIE_SOC_GLOBAL_RESET_V;
|
||||
|
||||
ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
|
||||
/* Flush the posted write to the device */
|
||||
ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
|
||||
|
||||
mdelay(delay);
|
||||
|
||||
|
|
|
|||
|
|
@ -3294,9 +3294,14 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
|
|||
clear_bit(ATH11K_FLAG_CRASH_FLUSH,
|
||||
&ab->dev_flags);
|
||||
clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
|
||||
ath11k_core_qmi_firmware_ready(ab);
|
||||
set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
|
||||
|
||||
if (!test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
|
||||
ret = ath11k_core_qmi_firmware_ready(ab);
|
||||
if (ret) {
|
||||
set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
|
||||
break;
|
||||
}
|
||||
set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
|
||||
}
|
||||
break;
|
||||
case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -274,11 +274,14 @@ int ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp *dp)
|
|||
|
||||
void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp)
|
||||
{
|
||||
mutex_lock(&dp->link_peer_rhash_tbl_lock);
|
||||
guard(mutex)(&dp->link_peer_rhash_tbl_lock);
|
||||
|
||||
if (!dp->rhead_peer_addr)
|
||||
return;
|
||||
|
||||
rhashtable_destroy(dp->rhead_peer_addr);
|
||||
kfree(dp->rhead_peer_addr);
|
||||
dp->rhead_peer_addr = NULL;
|
||||
mutex_unlock(&dp->link_peer_rhash_tbl_lock);
|
||||
}
|
||||
|
||||
static int ath12k_dp_link_peer_rhash_insert(struct ath12k_dp *dp,
|
||||
|
|
@ -570,6 +573,8 @@ int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
|
|||
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
|
||||
|
||||
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], peer);
|
||||
WRITE_ONCE(dp_peer->link_peers_map,
|
||||
READ_ONCE(dp_peer->link_peers_map) | BIT(peer->link_id));
|
||||
|
||||
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], dp_peer);
|
||||
|
||||
|
|
@ -632,6 +637,8 @@ void ath12k_dp_link_peer_unassign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_
|
|||
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
|
||||
|
||||
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
|
||||
WRITE_ONCE(dp_peer->link_peers_map,
|
||||
READ_ONCE(dp_peer->link_peers_map) & ~BIT(peer->link_id));
|
||||
|
||||
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ struct ath12k_dp_peer {
|
|||
|
||||
/* Info used in MMIC verification of * RX fragments */
|
||||
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
|
||||
unsigned long link_peers_map;
|
||||
struct ath12k_dp_link_peer __rcu *link_peers[ATH12K_NUM_MAX_LINKS];
|
||||
struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1];
|
||||
struct ath12k_dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
|
||||
|
|
|
|||
|
|
@ -1384,10 +1384,9 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc
|
|||
|
||||
pubsta = peer ? peer->sta : NULL;
|
||||
|
||||
if (pubsta && pubsta->valid_links) {
|
||||
status->link_valid = 1;
|
||||
status->link_id = peer->hw_links[rxcb->hw_link_id];
|
||||
}
|
||||
status->link_valid = 0;
|
||||
if (pubsta && pubsta->valid_links)
|
||||
ath12k_hw_set_rx_link_id(dp->hw_params, peer, rxcb, status);
|
||||
|
||||
ath12k_dbg(dp->ab, ATH12K_DBG_DATA,
|
||||
"rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@
|
|||
#include "wmi.h"
|
||||
#include "hal.h"
|
||||
|
||||
struct ath12k_dp_peer;
|
||||
struct ath12k_skb_rxcb;
|
||||
struct ieee80211_rx_status;
|
||||
|
||||
/* Target configuration defines */
|
||||
|
||||
/* Num VDEVS per radio */
|
||||
|
|
@ -243,6 +247,9 @@ struct ath12k_hw_ops {
|
|||
bool (*dp_srng_is_tx_comp_ring)(int ring_num);
|
||||
bool (*is_frame_link_agnostic)(struct ath12k_link_vif *arvif,
|
||||
struct ieee80211_mgmt *mgmt);
|
||||
void (*set_rx_link_id)(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status);
|
||||
};
|
||||
|
||||
static inline
|
||||
|
|
@ -273,6 +280,15 @@ static inline int ath12k_hw_mac_id_to_srng_id(const struct ath12k_hw_params *hw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath12k_hw_set_rx_link_id(const struct ath12k_hw_params *hw,
|
||||
struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
if (hw->hw_ops->set_rx_link_id)
|
||||
hw->hw_ops->set_rx_link_id(dp_peer, rxcb, status);
|
||||
}
|
||||
|
||||
struct ath12k_fw_ie {
|
||||
__le32 id;
|
||||
__le32 len;
|
||||
|
|
|
|||
|
|
@ -1238,9 +1238,13 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar)
|
|||
/* cleanup dp peer */
|
||||
spin_lock_bh(&dp_hw->peer_lock);
|
||||
dp_peer = peer->dp_peer;
|
||||
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
|
||||
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
|
||||
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
|
||||
if (dp_peer) {
|
||||
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
|
||||
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
|
||||
WRITE_ONCE(dp_peer->link_peers_map,
|
||||
READ_ONCE(dp_peer->link_peers_map) & ~BIT(peer->link_id));
|
||||
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
|
||||
}
|
||||
spin_unlock_bh(&dp_hw->peer_lock);
|
||||
|
||||
ath12k_dp_link_peer_rhash_delete(dp, peer);
|
||||
|
|
|
|||
|
|
@ -188,6 +188,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
|
|||
val |= PCIE_SOC_GLOBAL_RESET_V;
|
||||
|
||||
ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
|
||||
/* Flush the posted write to the device */
|
||||
ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
|
||||
|
||||
/* TODO: exact time to sleep is uncertain */
|
||||
delay = 10;
|
||||
|
|
@ -197,6 +199,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
|
|||
val &= ~PCIE_SOC_GLOBAL_RESET_V;
|
||||
|
||||
ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
|
||||
/* Flush the posted write to the device */
|
||||
ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
|
||||
|
||||
mdelay(delay);
|
||||
|
||||
|
|
|
|||
|
|
@ -453,6 +453,9 @@ int ath12k_link_sta_rhash_tbl_init(struct ath12k_base *ab)
|
|||
|
||||
void ath12k_link_sta_rhash_tbl_destroy(struct ath12k_base *ab)
|
||||
{
|
||||
if (!ab->rhead_sta_addr)
|
||||
return;
|
||||
|
||||
rhashtable_destroy(ab->rhead_sta_addr);
|
||||
kfree(ab->rhead_sta_addr);
|
||||
ab->rhead_sta_addr = NULL;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "dp_rx.h"
|
||||
#include "../dp_peer.h"
|
||||
#include "../dp_tx.h"
|
||||
#include "../peer.h"
|
||||
#include "hal_qcn9274.h"
|
||||
|
|
@ -2315,3 +2316,35 @@ ath12k_wifi7_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
|
|||
|
||||
return tlv_tag == HAL_RX_MPDU_START;
|
||||
}
|
||||
|
||||
void
|
||||
ath12k_wifi7_dp_rx_set_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
status->link_valid = 1;
|
||||
status->link_id = dp_peer->hw_links[rxcb->hw_link_id];
|
||||
}
|
||||
|
||||
void
|
||||
ath12k_wifi7_dp_rx_set_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
struct ath12k_dp_link_peer *link_peer;
|
||||
unsigned long links_map;
|
||||
int i;
|
||||
|
||||
RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
|
||||
"ath12k set rx link id called without rcu lock");
|
||||
|
||||
links_map = READ_ONCE(dp_peer->link_peers_map);
|
||||
for_each_set_bit(i, &links_map, ATH12K_NUM_MAX_LINKS) {
|
||||
link_peer = rcu_dereference(dp_peer->link_peers[i]);
|
||||
if (link_peer && link_peer->peer_id == rxcb->peer_id) {
|
||||
status->link_valid = 1;
|
||||
status->link_id = link_peer->link_id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,4 +57,10 @@ ath12k_wifi7_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
|
|||
struct hal_rx_desc *rx_desc);
|
||||
int ath12k_wifi7_dp_rx_tid_delete_handler(struct ath12k_base *ab,
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid);
|
||||
void ath12k_wifi7_dp_rx_set_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status);
|
||||
void ath12k_wifi7_dp_rx_set_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ static const struct ath12k_hw_ops qcn9274_ops = {
|
|||
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_qcn9274,
|
||||
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_qcn9274,
|
||||
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_qcn9274,
|
||||
.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_qcn9274,
|
||||
};
|
||||
|
||||
static const struct ath12k_hw_ops wcn7850_ops = {
|
||||
|
|
@ -168,6 +169,7 @@ static const struct ath12k_hw_ops wcn7850_ops = {
|
|||
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850,
|
||||
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850,
|
||||
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850,
|
||||
.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_wcn7850,
|
||||
};
|
||||
|
||||
static const struct ath12k_hw_ops qcc2072_ops = {
|
||||
|
|
@ -178,6 +180,7 @@ static const struct ath12k_hw_ops qcc2072_ops = {
|
|||
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850,
|
||||
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850,
|
||||
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850,
|
||||
.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_wcn7850,
|
||||
};
|
||||
|
||||
#define ATH12K_TX_RING_MASK_0 0x1
|
||||
|
|
|
|||
|
|
@ -1723,13 +1723,15 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no,
|
|||
|
||||
rxtid = &aggr_conn->rx_tid[tid];
|
||||
|
||||
if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX)
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",
|
||||
__func__, win_sz, tid);
|
||||
|
||||
if (rxtid->aggr)
|
||||
aggr_delete_tid_state(aggr_conn, tid);
|
||||
|
||||
if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) {
|
||||
ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",
|
||||
__func__, win_sz, tid);
|
||||
return;
|
||||
}
|
||||
|
||||
rxtid->seq_next = seq_no;
|
||||
hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q);
|
||||
rxtid->hold_q = kzalloc(hold_q_size, GFP_KERNEL);
|
||||
|
|
@ -1828,7 +1830,7 @@ void aggr_reset_state(struct aggr_info_conn *aggr_conn)
|
|||
return;
|
||||
|
||||
if (aggr_conn->timer_scheduled) {
|
||||
timer_delete(&aggr_conn->timer);
|
||||
timer_delete_sync(&aggr_conn->timer);
|
||||
aggr_conn->timer_scheduled = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -484,6 +484,18 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
|
|||
|
||||
evt = (struct wmi_tx_complete_event *) datap;
|
||||
|
||||
if (len < sizeof(*evt)) {
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d\n",
|
||||
len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (len < sizeof(*evt) + evt->num_msg * sizeof(struct tx_complete_msg_v1)) {
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d for %u msgs\n",
|
||||
len, evt->num_msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
|
||||
evt->num_msg, evt->msg_len, evt->msg_type);
|
||||
|
||||
|
|
@ -862,6 +874,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
|
|||
|
||||
ev = (struct wmi_connect_event *) datap;
|
||||
|
||||
if (len < sizeof(*ev) + ev->beacon_ie_len +
|
||||
ev->assoc_req_len + ev->assoc_resp_len) {
|
||||
ath6kl_dbg(ATH6KL_DBG_WMI,
|
||||
"connect event: IE lengths %u+%u+%u exceed buffer %d\n",
|
||||
ev->beacon_ie_len, ev->assoc_req_len,
|
||||
ev->assoc_resp_len, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (vif->nw_type == AP_NETWORK) {
|
||||
/* AP mode start/STA connected event */
|
||||
struct net_device *dev = vif->ndev;
|
||||
|
|
|
|||
|
|
@ -1215,15 +1215,10 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
|
|||
ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
|
||||
&hif_dev->udev->dev, GFP_KERNEL,
|
||||
hif_dev, ath9k_hif_usb_firmware_cb);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
dev_err(&hif_dev->udev->dev,
|
||||
"ath9k_htc: Async request for firmware %s failed\n",
|
||||
hif_dev->fw_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
|
||||
hif_dev->fw_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,7 +150,8 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
|
|||
spin_lock(&ar->cmd_lock);
|
||||
if (ar->readbuf) {
|
||||
if (len >= 4)
|
||||
memcpy(ar->readbuf, buffer + 4, len - 4);
|
||||
memcpy(ar->readbuf, buffer + 4,
|
||||
min_t(u32, len - 4, ar->readlen));
|
||||
|
||||
ar->readbuf = NULL;
|
||||
}
|
||||
|
|
@ -917,7 +918,9 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
|
|||
}
|
||||
}
|
||||
|
||||
skb_put_data(ar->rx_failover, tbuf, tlen);
|
||||
skb_put_data(ar->rx_failover, tbuf,
|
||||
min_t(unsigned int, tlen,
|
||||
ar->rx_failover_missing));
|
||||
ar->rx_failover_missing -= tlen;
|
||||
|
||||
if (ar->rx_failover_missing <= 0) {
|
||||
|
|
|
|||
|
|
@ -692,7 +692,7 @@ void carl9170_tx_process_status(struct ar9170 *ar,
|
|||
unsigned int i;
|
||||
|
||||
for (i = 0; i < cmd->hdr.ext; i++) {
|
||||
if (WARN_ON(i > ((cmd->hdr.len / 2) + 1))) {
|
||||
if (WARN_ON(i >= (cmd->hdr.len / 2))) {
|
||||
print_hex_dump_bytes("UU:", DUMP_PREFIX_NONE,
|
||||
(void *) cmd, cmd->hdr.len + 4);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1521,13 +1521,16 @@ static inline int at76_guess_freq(struct at76_priv *priv)
|
|||
|
||||
if (ieee80211_is_probe_resp(hdr->frame_control)) {
|
||||
el_off = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
|
||||
el = ((struct ieee80211_mgmt *)hdr)->u.probe_resp.variable;
|
||||
} else if (ieee80211_is_beacon(hdr->frame_control)) {
|
||||
el_off = offsetof(struct ieee80211_mgmt, u.beacon.variable);
|
||||
el = ((struct ieee80211_mgmt *)hdr)->u.beacon.variable;
|
||||
} else {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (len < el_off)
|
||||
goto exit;
|
||||
|
||||
el = priv->rx_skb->data + el_off;
|
||||
len -= el_off;
|
||||
|
||||
el = cfg80211_find_ie(WLAN_EID_DS_PARAMS, el, len);
|
||||
|
|
|
|||
|
|
@ -911,6 +911,7 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
|
|||
return ret;
|
||||
}
|
||||
switch (sdiodev->func2->device) {
|
||||
case SDIO_DEVICE_ID_BROADCOM_43752:
|
||||
case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:
|
||||
f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE;
|
||||
break;
|
||||
|
|
@ -1069,6 +1070,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
|
|||
bus_if = kzalloc_obj(*bus_if);
|
||||
if (!bus_if)
|
||||
return -ENOMEM;
|
||||
mutex_init(&bus_if->bus_reset_lock);
|
||||
sdiodev = kzalloc_obj(*sdiodev);
|
||||
if (!sdiodev) {
|
||||
kfree(bus_if);
|
||||
|
|
@ -1130,6 +1132,14 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
|
|||
if (func->num != 1)
|
||||
return;
|
||||
|
||||
/* Drain bus_reset before the shared brcmf_sdiod_remove()
|
||||
* teardown, which the SDIO reset callback also reaches. The
|
||||
* data worker can arm bus_reset via brcmf_fw_crashed(); cancel
|
||||
* it first.
|
||||
*/
|
||||
brcmf_sdio_cancel_datawork(sdiodev->bus);
|
||||
brcmf_bus_cancel_reset_work(bus_if);
|
||||
|
||||
/* only proceed with rest of cleanup if func 1 */
|
||||
brcmf_sdiod_remove(sdiodev);
|
||||
|
||||
|
|
@ -1204,6 +1214,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
|
|||
} else {
|
||||
/* power will be cut so remove device, probe again in resume */
|
||||
brcmf_sdiod_intr_unregister(sdiodev);
|
||||
brcmf_sdio_cancel_datawork(sdiodev->bus);
|
||||
brcmf_bus_cancel_reset_work(bus_if);
|
||||
ret = brcmf_sdiod_remove(sdiodev);
|
||||
if (ret)
|
||||
brcmf_err("Failed to remove device on suspend\n");
|
||||
|
|
@ -1229,6 +1241,8 @@ static int brcmf_ops_sdio_resume(struct device *dev)
|
|||
ret = brcmf_sdiod_probe(sdiodev);
|
||||
if (ret)
|
||||
brcmf_err("Failed to probe device on resume\n");
|
||||
else
|
||||
brcmf_bus_allow_reset_work(bus_if);
|
||||
} else {
|
||||
if (sdiodev->wowl_enabled && sdiodev->settings->bus.sdio.oob_irq_supported)
|
||||
disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "debug.h"
|
||||
|
||||
/* IDs of the 6 default common rings of msgbuf protocol */
|
||||
|
|
@ -179,6 +180,8 @@ struct brcmf_bus {
|
|||
enum brcmf_fwvendor fwvid;
|
||||
bool always_use_fws_queue;
|
||||
bool wowl_supported;
|
||||
bool removing; /* device removal in progress; quiesce async work */
|
||||
struct mutex bus_reset_lock;
|
||||
|
||||
const struct brcmf_bus_ops *ops;
|
||||
struct brcmf_bus_msgbuf *msgbuf;
|
||||
|
|
@ -186,6 +189,9 @@ struct brcmf_bus {
|
|||
struct list_head list;
|
||||
};
|
||||
|
||||
void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if);
|
||||
void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if);
|
||||
|
||||
/*
|
||||
* callback wrappers
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2146,7 +2146,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
sme->crypto.akm_suites[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
|
||||
} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_1X_SHA256)) {
|
||||
switch (sme->crypto.akm_suites[0]) {
|
||||
case WLAN_AKM_SUITE_8021X:
|
||||
val = WPA2_AUTH_UNSPECIFIED;
|
||||
|
|
|
|||
|
|
@ -1167,6 +1167,35 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize arming from debugfs reset and brcmf_fw_crashed() against
|
||||
* teardown. The remove path sets ->removing and drains the work while
|
||||
* holding bus_reset_lock, so a racing armer is either drained or skips it.
|
||||
*/
|
||||
static void brcmf_bus_schedule_reset(struct brcmf_bus *bus_if)
|
||||
{
|
||||
mutex_lock(&bus_if->bus_reset_lock);
|
||||
if (bus_if->drvr && bus_if->drvr->bus_reset.func && !bus_if->removing)
|
||||
schedule_work(&bus_if->drvr->bus_reset);
|
||||
mutex_unlock(&bus_if->bus_reset_lock);
|
||||
}
|
||||
|
||||
void brcmf_bus_cancel_reset_work(struct brcmf_bus *bus_if)
|
||||
{
|
||||
mutex_lock(&bus_if->bus_reset_lock);
|
||||
bus_if->removing = true;
|
||||
if (bus_if->drvr)
|
||||
cancel_work_sync(&bus_if->drvr->bus_reset);
|
||||
mutex_unlock(&bus_if->bus_reset_lock);
|
||||
}
|
||||
|
||||
void brcmf_bus_allow_reset_work(struct brcmf_bus *bus_if)
|
||||
{
|
||||
mutex_lock(&bus_if->bus_reset_lock);
|
||||
bus_if->removing = false;
|
||||
mutex_unlock(&bus_if->bus_reset_lock);
|
||||
}
|
||||
|
||||
static void brcmf_core_bus_reset(struct work_struct *work)
|
||||
{
|
||||
struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
|
||||
|
|
@ -1187,7 +1216,7 @@ static ssize_t bus_reset_write(struct file *file, const char __user *user_buf,
|
|||
if (value != 1)
|
||||
return -EINVAL;
|
||||
|
||||
schedule_work(&drvr->bus_reset);
|
||||
brcmf_bus_schedule_reset(drvr->bus_if);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
@ -1417,14 +1446,23 @@ void brcmf_dev_coredump(struct device *dev)
|
|||
void brcmf_fw_crashed(struct device *dev)
|
||||
{
|
||||
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
||||
struct brcmf_pub *drvr = bus_if->drvr;
|
||||
struct brcmf_pub *drvr;
|
||||
|
||||
/* May fire before brcmf_attach() wires up drvr, or after removal
|
||||
* has cleared it; guard the derefs below (and the arming gate in
|
||||
* brcmf_bus_schedule_reset() already checks drvr/->removing).
|
||||
*/
|
||||
if (!bus_if)
|
||||
return;
|
||||
drvr = bus_if->drvr;
|
||||
if (!drvr)
|
||||
return;
|
||||
|
||||
bphy_err(drvr, "Firmware has halted or crashed\n");
|
||||
|
||||
brcmf_dev_coredump(dev);
|
||||
|
||||
if (drvr->bus_reset.func)
|
||||
schedule_work(&drvr->bus_reset);
|
||||
brcmf_bus_schedule_reset(bus_if);
|
||||
}
|
||||
|
||||
void brcmf_detach(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -1383,16 +1383,20 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
|
|||
static void
|
||||
brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo)
|
||||
{
|
||||
if (devinfo->shared.scratch)
|
||||
if (devinfo->shared.scratch) {
|
||||
dma_free_coherent(&devinfo->pdev->dev,
|
||||
BRCMF_DMA_D2H_SCRATCH_BUF_LEN,
|
||||
devinfo->shared.scratch,
|
||||
devinfo->shared.scratch_dmahandle);
|
||||
if (devinfo->shared.ringupd)
|
||||
devinfo->shared.scratch = NULL;
|
||||
}
|
||||
if (devinfo->shared.ringupd) {
|
||||
dma_free_coherent(&devinfo->pdev->dev,
|
||||
BRCMF_DMA_D2H_RINGUPD_BUF_LEN,
|
||||
devinfo->shared.ringupd,
|
||||
devinfo->shared.ringupd_dmahandle);
|
||||
devinfo->shared.ringupd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
|
||||
|
|
@ -2499,6 +2503,7 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
mutex_init(&bus->bus_reset_lock);
|
||||
bus->msgbuf = kzalloc_obj(*bus->msgbuf);
|
||||
if (!bus->msgbuf) {
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -2594,6 +2599,11 @@ brcmf_pcie_remove(struct pci_dev *pdev)
|
|||
if (devinfo->ci)
|
||||
brcmf_pcie_intr_disable(devinfo);
|
||||
|
||||
if (devinfo->irq_allocated)
|
||||
synchronize_irq(pdev->irq);
|
||||
|
||||
brcmf_bus_cancel_reset_work(bus);
|
||||
|
||||
brcmf_detach(&pdev->dev);
|
||||
brcmf_free(&pdev->dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -4560,6 +4560,12 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus)
|
||||
{
|
||||
if (bus)
|
||||
cancel_work_sync(&bus->datawork);
|
||||
}
|
||||
|
||||
/* Detach and free everything */
|
||||
void brcmf_sdio_remove(struct brcmf_sdio *bus)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -361,6 +361,7 @@ int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev);
|
|||
int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
|
||||
void brcmf_sdio_remove(struct brcmf_sdio *bus);
|
||||
void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr);
|
||||
void brcmf_sdio_cancel_datawork(struct brcmf_sdio *bus);
|
||||
|
||||
void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, bool active);
|
||||
void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
|
||||
|
|
|
|||
|
|
@ -1260,6 +1260,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
|
|||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
mutex_init(&bus->bus_reset_lock);
|
||||
|
||||
bus->dev = dev;
|
||||
bus_pub->bus = bus;
|
||||
|
|
@ -1329,6 +1330,8 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
|
|||
return;
|
||||
brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
|
||||
|
||||
brcmf_bus_cancel_reset_work(devinfo->bus_pub.bus);
|
||||
|
||||
brcmf_detach(devinfo->dev);
|
||||
brcmf_free(devinfo->dev);
|
||||
kfree(devinfo->bus_pub.bus);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
.non_shared_ant = ANT_B, \
|
||||
.vht_mu_mimo_supported = true, \
|
||||
.uhb_supported = true, \
|
||||
.unii9_supported = true, \
|
||||
.eht_supported = true, \
|
||||
.uhr_supported = true, \
|
||||
.num_rbds = IWL_NUM_RBDS_EHT, \
|
||||
|
|
|
|||
|
|
@ -865,6 +865,11 @@ int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt)
|
|||
min_size, max_size,
|
||||
&tbl_rev);
|
||||
if (!IS_ERR(wifi_pkg)) {
|
||||
if (tbl_rev < 0 ||
|
||||
tbl_rev >= BITS_PER_BYTE *
|
||||
sizeof(rev_data[idx].revisions))
|
||||
continue;
|
||||
|
||||
if (!(BIT(tbl_rev) & rev_data[idx].revisions))
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ struct iwl_nvm_get_info_phy {
|
|||
|
||||
#define IWL_NUM_CHANNELS_V1 51
|
||||
#define IWL_NUM_CHANNELS_V2 110
|
||||
#define IWL_NUM_CHANNELS_V3 115
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_regulatory_v1 - regulatory information
|
||||
|
|
@ -219,12 +220,12 @@ struct iwl_nvm_get_info_regulatory_v1 {
|
|||
} __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_regulatory - regulatory information
|
||||
* struct iwl_nvm_get_info_regulatory_v2 - regulatory information
|
||||
* @lar_enabled: is LAR enabled
|
||||
* @n_channels: number of valid channels in the array
|
||||
* @channel_profile: regulatory data of this channel
|
||||
*/
|
||||
struct iwl_nvm_get_info_regulatory {
|
||||
struct iwl_nvm_get_info_regulatory_v2 {
|
||||
__le32 lar_enabled;
|
||||
__le32 n_channels;
|
||||
__le32 channel_profile[IWL_NUM_CHANNELS_V2];
|
||||
|
|
@ -244,6 +245,32 @@ struct iwl_nvm_get_info_rsp_v3 {
|
|||
struct iwl_nvm_get_info_regulatory_v1 regulatory;
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_3 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_rsp_v4 - response to get NVM data
|
||||
* @general: general NVM data
|
||||
* @mac_sku: data relating to MAC sku
|
||||
* @phy_sku: data relating to PHY sku
|
||||
* @regulatory: regulatory data
|
||||
*/
|
||||
struct iwl_nvm_get_info_rsp_v4 {
|
||||
struct iwl_nvm_get_info_general general;
|
||||
struct iwl_nvm_get_info_sku mac_sku;
|
||||
struct iwl_nvm_get_info_phy phy_sku;
|
||||
struct iwl_nvm_get_info_regulatory_v2 regulatory;
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_4 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_regulatory - regulatory information
|
||||
* @lar_enabled: is LAR enabled
|
||||
* @n_channels: number of valid channels in the array
|
||||
* @channel_profile: regulatory data of this channel
|
||||
*/
|
||||
struct iwl_nvm_get_info_regulatory {
|
||||
__le32 lar_enabled;
|
||||
__le32 n_channels;
|
||||
__le32 channel_profile[IWL_NUM_CHANNELS_V3];
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_3 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_get_info_rsp - response to get NVM data
|
||||
* @general: general NVM data
|
||||
|
|
@ -256,7 +283,7 @@ struct iwl_nvm_get_info_rsp {
|
|||
struct iwl_nvm_get_info_sku mac_sku;
|
||||
struct iwl_nvm_get_info_phy phy_sku;
|
||||
struct iwl_nvm_get_info_regulatory regulatory;
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_4 */
|
||||
} __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_5 */
|
||||
|
||||
/**
|
||||
* struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -1319,7 +1319,7 @@ struct iwl_scan_offload_match_info {
|
|||
u8 resume_while_scanning;
|
||||
u8 self_recovery;
|
||||
__le16 reserved;
|
||||
struct iwl_scan_offload_profile_match matches[];
|
||||
struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES_V2];
|
||||
} __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_3 and
|
||||
* SCAN_OFFLOAD_MATCH_INFO_NOTIFICATION_S_VER_1
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright(c) 2020-2025 Intel Corporation
|
||||
* Copyright(c) 2020-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "iwl-drv.h"
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
#include "fw/api/alive.h"
|
||||
#include "fw/uefi.h"
|
||||
#include "fw/img.h"
|
||||
#include "fw/dbg.h"
|
||||
|
||||
#define IWL_PNVM_REDUCED_CAP_BIT BIT(25)
|
||||
|
||||
|
|
@ -26,6 +27,12 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait,
|
|||
struct iwl_trans *trans = (struct iwl_trans *)data;
|
||||
struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data;
|
||||
|
||||
if (IWL_FW_CHECK(trans,
|
||||
iwl_rx_packet_payload_len(pkt) < sizeof(*pnvm_ntf),
|
||||
"Bad notif len: %d\n",
|
||||
iwl_rx_packet_payload_len(pkt)))
|
||||
return true;
|
||||
|
||||
IWL_DEBUG_FW(trans,
|
||||
"PNVM complete notification received with status 0x%0x\n",
|
||||
le32_to_cpu(pnvm_ntf->status));
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc)
|
|||
if (*size >= IWL_WTAS_BLACK_LIST_MAX)
|
||||
return false;
|
||||
|
||||
list[*size++] = mcc;
|
||||
list[(*size)++] = mcc;
|
||||
return true;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2021, 2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2021, 2025-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -14,9 +14,17 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt,
|
|||
{
|
||||
struct iwl_shared_mem_cfg *mem_cfg = (void *)pkt->data;
|
||||
int i, lmac;
|
||||
int lmac_num = le32_to_cpu(mem_cfg->lmac_num);
|
||||
u8 api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP,
|
||||
SHARED_MEM_CFG_CMD, 0);
|
||||
int lmac_num;
|
||||
u8 api_ver;
|
||||
|
||||
if (IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) <
|
||||
offsetofend(struct iwl_shared_mem_cfg, lmac_smem[1]),
|
||||
"bad shared mem notification size\n"))
|
||||
return;
|
||||
|
||||
lmac_num = le32_to_cpu(mem_cfg->lmac_num);
|
||||
api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP,
|
||||
SHARED_MEM_CFG_CMD, 0);
|
||||
|
||||
/* Note: notification has 3 entries, but we only expect 2 */
|
||||
if (IWL_FW_CHECK(fwrt, lmac_num > ARRAY_SIZE(fwrt->smem_cfg.lmac),
|
||||
|
|
@ -30,7 +38,7 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt,
|
|||
|
||||
if (api_ver >= 4 &&
|
||||
!IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg),
|
||||
"bad shared mem notification size\n")) {
|
||||
"bad shared mem notification size (v4)\n")) {
|
||||
fwrt->smem_cfg.rxfifo2_control_size =
|
||||
le32_to_cpu(mem_cfg->rxfifo2_control_size);
|
||||
}
|
||||
|
|
@ -53,6 +61,11 @@ static void iwl_parse_shared_mem(struct iwl_fw_runtime *fwrt,
|
|||
struct iwl_shared_mem_cfg_v2 *mem_cfg = (void *)pkt->data;
|
||||
int i;
|
||||
|
||||
if (IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) <
|
||||
offsetof(struct iwl_shared_mem_cfg_v2, rxfifo_addr),
|
||||
"bad shared mem notification size\n"))
|
||||
return;
|
||||
|
||||
fwrt->smem_cfg.num_lmacs = 1;
|
||||
|
||||
fwrt->smem_cfg.num_txfifo_entries = ARRAY_SIZE(mem_cfg->txfifo_size);
|
||||
|
|
@ -67,6 +80,11 @@ static void iwl_parse_shared_mem(struct iwl_fw_runtime *fwrt,
|
|||
/* new API has more data, from rxfifo_addr field and on */
|
||||
if (fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
|
||||
if (IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) <
|
||||
sizeof(*mem_cfg),
|
||||
"bad shared mem notification size (extend)\n"))
|
||||
return;
|
||||
|
||||
BUILD_BUG_ON(sizeof(fwrt->smem_cfg.internal_txfifo_size) !=
|
||||
sizeof(mem_cfg->internal_txfifo_size));
|
||||
|
||||
|
|
|
|||
|
|
@ -700,7 +700,7 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
|
|||
return -EINVAL;
|
||||
|
||||
parse_table:
|
||||
if (!(BIT(data->revision) & valid_rev)) {
|
||||
if (data->revision >= 32 || !(BIT(data->revision) & valid_rev)) {
|
||||
ret = -EINVAL;
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"Unsupported UEFI PPAG revision:%d\n",
|
||||
|
|
|
|||
|
|
@ -415,6 +415,7 @@ struct iwl_mac_cfg {
|
|||
* @vht_mu_mimo_supported: VHT MU-MIMO support
|
||||
* @nvm_type: see &enum iwl_nvm_type
|
||||
* @uhb_supported: ultra high band channels supported
|
||||
* @unii9_supported: UNII-9 channels supported
|
||||
* @eht_supported: EHT supported
|
||||
* @uhr_supported: UHR supported
|
||||
* @num_rbds: number of receive buffer descriptors to use
|
||||
|
|
@ -450,6 +451,7 @@ struct iwl_rf_cfg {
|
|||
lp_xtal_workaround:1,
|
||||
vht_mu_mimo_supported:1,
|
||||
uhb_supported:1,
|
||||
unii9_supported:1,
|
||||
eht_supported:1,
|
||||
uhr_supported:1;
|
||||
u8 valid_tx_ant;
|
||||
|
|
|
|||
|
|
@ -475,6 +475,7 @@ static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data,
|
|||
{
|
||||
const struct iwl_ucode_tlv *tlv;
|
||||
u32 tlv_len;
|
||||
size_t aligned_tlv_len;
|
||||
|
||||
while (len >= sizeof(*tlv)) {
|
||||
len -= sizeof(*tlv);
|
||||
|
|
@ -487,8 +488,16 @@ static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data,
|
|||
len, tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
len -= ALIGN(tlv_len, 4);
|
||||
data += sizeof(*tlv) + ALIGN(tlv_len, 4);
|
||||
|
||||
aligned_tlv_len = ALIGN(tlv_len, 4);
|
||||
if (len < aligned_tlv_len) {
|
||||
IWL_ERR(trans, "invalid aligned TLV len: %zd/%zu\n",
|
||||
len, aligned_tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len -= aligned_tlv_len;
|
||||
data += sizeof(*tlv) + aligned_tlv_len;
|
||||
|
||||
iwl_dbg_tlv_alloc(trans, tlv, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
|
|||
* Gets uCode section from tlv.
|
||||
*/
|
||||
static int iwl_store_ucode_sec(struct fw_img_parsing *img,
|
||||
const void *data, int size)
|
||||
const void *data, size_t size)
|
||||
{
|
||||
struct fw_sec *sec;
|
||||
const struct fw_sec_parsing *sec_parse;
|
||||
|
|
@ -501,6 +501,9 @@ static int iwl_store_ucode_sec(struct fw_img_parsing *img,
|
|||
if (WARN_ON(!img || !data))
|
||||
return -EINVAL;
|
||||
|
||||
if (size < sizeof(sec_parse->offset))
|
||||
return -EINVAL;
|
||||
|
||||
sec_parse = (const struct fw_sec_parsing *)data;
|
||||
|
||||
alloc_size = sizeof(*img->sec) * (img->sec_counter + 1);
|
||||
|
|
@ -804,6 +807,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
u32 build, paging_mem_size;
|
||||
int num_of_cpus;
|
||||
bool usniffer_req = false;
|
||||
size_t aligned_tlv_len;
|
||||
|
||||
if (len < sizeof(*ucode)) {
|
||||
IWL_ERR(drv, "uCode has invalid length: %zd\n", len);
|
||||
|
|
@ -852,8 +856,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
len, tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
len -= ALIGN(tlv_len, 4);
|
||||
data += sizeof(*tlv) + ALIGN(tlv_len, 4);
|
||||
|
||||
aligned_tlv_len = ALIGN(tlv_len, 4);
|
||||
if (len < aligned_tlv_len) {
|
||||
IWL_ERR(drv, "invalid aligned TLV len: %zd/%zu\n",
|
||||
len, aligned_tlv_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len -= aligned_tlv_len;
|
||||
data += sizeof(*tlv) + aligned_tlv_len;
|
||||
|
||||
switch (tlv_type) {
|
||||
case IWL_UCODE_TLV_INST:
|
||||
|
|
|
|||
|
|
@ -85,16 +85,7 @@ static const u16 iwl_nvm_channels[] = {
|
|||
149, 153, 157, 161, 165
|
||||
};
|
||||
|
||||
static const u16 iwl_ext_nvm_channels[] = {
|
||||
/* 2.4 GHz */
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/* 5 GHz */
|
||||
36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
|
||||
96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
|
||||
149, 153, 157, 161, 165, 169, 173, 177, 181
|
||||
};
|
||||
|
||||
static const u16 iwl_uhb_nvm_channels[] = {
|
||||
static const u16 iwl_unii9_nvm_channels[] = {
|
||||
/* 2.4 GHz */
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/* 5 GHz */
|
||||
|
|
@ -105,12 +96,16 @@ static const u16 iwl_uhb_nvm_channels[] = {
|
|||
1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69,
|
||||
73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129,
|
||||
133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185,
|
||||
189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233
|
||||
189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233,
|
||||
|
||||
/* UNII-9 */
|
||||
237, 241, 245, 249, 253
|
||||
};
|
||||
|
||||
#define IWL_NVM_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
|
||||
#define IWL_NVM_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels)
|
||||
#define IWL_NVM_NUM_CHANNELS_UHB ARRAY_SIZE(iwl_uhb_nvm_channels)
|
||||
#define IWL_NVM_NUM_CHANNELS_EXT 51
|
||||
#define IWL_NVM_NUM_CHANNELS_UHB 110
|
||||
#define IWL_NVM_NUM_CHANNELS_UNII9 ARRAY_SIZE(iwl_unii9_nvm_channels)
|
||||
#define NUM_2GHZ_CHANNELS 14
|
||||
#define NUM_5GHZ_CHANNELS 37
|
||||
#define FIRST_2GHZ_HT_MINUS 5
|
||||
|
|
@ -351,12 +346,15 @@ static int iwl_init_channel_map(struct iwl_trans *trans,
|
|||
int num_of_ch;
|
||||
const u16 *nvm_chan;
|
||||
|
||||
if (cfg->uhb_supported) {
|
||||
if (cfg->unii9_supported) {
|
||||
num_of_ch = IWL_NVM_NUM_CHANNELS_UNII9;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else if (cfg->uhb_supported) {
|
||||
num_of_ch = IWL_NVM_NUM_CHANNELS_UHB;
|
||||
nvm_chan = iwl_uhb_nvm_channels;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else if (cfg->nvm_type == IWL_NVM_EXT) {
|
||||
num_of_ch = IWL_NVM_NUM_CHANNELS_EXT;
|
||||
nvm_chan = iwl_ext_nvm_channels;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else {
|
||||
num_of_ch = IWL_NVM_NUM_CHANNELS;
|
||||
nvm_chan = iwl_nvm_channels;
|
||||
|
|
@ -1441,7 +1439,9 @@ iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
|
|||
u8 rx_chains = fw->valid_rx_ant;
|
||||
u8 tx_chains = fw->valid_rx_ant;
|
||||
|
||||
if (cfg->uhb_supported)
|
||||
if (cfg->unii9_supported)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_UNII9);
|
||||
else if (cfg->uhb_supported)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_UHB);
|
||||
else
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_EXT);
|
||||
|
|
@ -1506,7 +1506,9 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
|
|||
u16 lar_config;
|
||||
const __le16 *ch_section;
|
||||
|
||||
if (cfg->uhb_supported)
|
||||
if (cfg->unii9_supported)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_UNII9);
|
||||
else if (cfg->uhb_supported)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS_UHB);
|
||||
else if (cfg->nvm_type != IWL_NVM_EXT)
|
||||
data = kzalloc_flex(*data, channels, IWL_NVM_NUM_CHANNELS);
|
||||
|
|
@ -1727,12 +1729,15 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
|
|||
int max_num_ch;
|
||||
struct iwl_reg_capa reg_capa;
|
||||
|
||||
if (cfg->uhb_supported) {
|
||||
if (cfg->unii9_supported) {
|
||||
max_num_ch = IWL_NVM_NUM_CHANNELS_UNII9;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else if (cfg->uhb_supported) {
|
||||
max_num_ch = IWL_NVM_NUM_CHANNELS_UHB;
|
||||
nvm_chan = iwl_uhb_nvm_channels;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else if (cfg->nvm_type == IWL_NVM_EXT) {
|
||||
max_num_ch = IWL_NVM_NUM_CHANNELS_EXT;
|
||||
nvm_chan = iwl_ext_nvm_channels;
|
||||
nvm_chan = iwl_unii9_nvm_channels;
|
||||
} else {
|
||||
max_num_ch = IWL_NVM_NUM_CHANNELS;
|
||||
nvm_chan = iwl_nvm_channels;
|
||||
|
|
@ -2087,13 +2092,26 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
|
|||
struct iwl_nvm_get_info_rsp_v3 *rsp_v3;
|
||||
bool v4 = fw_has_api(&fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_REGULATORY_NVM_INFO);
|
||||
size_t rsp_size = v4 ? sizeof(*rsp) : sizeof(*rsp_v3);
|
||||
size_t rsp_size;
|
||||
void *channel_profile;
|
||||
|
||||
ret = iwl_trans_send_cmd(trans, &hcmd);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
switch (iwl_fw_lookup_notif_ver(fw, REGULATORY_AND_NVM_GROUP,
|
||||
NVM_GET_INFO, 0)) {
|
||||
case 5:
|
||||
rsp_size = sizeof(struct iwl_nvm_get_info_rsp);
|
||||
break;
|
||||
case 4:
|
||||
rsp_size = sizeof(struct iwl_nvm_get_info_rsp_v4);
|
||||
break;
|
||||
default:
|
||||
rsp_size = sizeof(struct iwl_nvm_get_info_rsp_v3);
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != rsp_size,
|
||||
"Invalid payload len in NVM response from FW %d",
|
||||
iwl_rx_packet_payload_len(hcmd.resp_pkt))) {
|
||||
|
|
@ -2107,7 +2125,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
|
|||
if (empty_otp)
|
||||
IWL_INFO(trans, "OTP is empty\n");
|
||||
|
||||
nvm = kzalloc_flex(*nvm, channels, IWL_NUM_CHANNELS_V2);
|
||||
nvm = kzalloc_flex(*nvm, channels, IWL_NUM_CHANNELS_V3);
|
||||
if (!nvm) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
* Copyright (C) 2024-2026 Intel Corporation
|
||||
*/
|
||||
#include "agg.h"
|
||||
#include "sta.h"
|
||||
|
|
@ -222,6 +222,11 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
if (IWL_FW_CHECK(mld, baid >= ARRAY_SIZE(mld->fw_id_to_ba),
|
||||
"Got out-of-range BAID %u in reorder_data=0x%x\n",
|
||||
baid, reorder))
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
/* no sta yet */
|
||||
if (WARN_ONCE(!sta,
|
||||
"Got valid BAID without a valid station assigned\n"))
|
||||
|
|
|
|||
|
|
@ -1708,7 +1708,7 @@ static void iwl_mld_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
|
|||
elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, ies->data,
|
||||
ies->len);
|
||||
|
||||
if (!elem || elem->datalen < 10 ||
|
||||
if (!elem || elem->datalen < 11 ||
|
||||
!(elem->data[10] &
|
||||
WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) {
|
||||
*tolerated = false;
|
||||
|
|
|
|||
|
|
@ -18,9 +18,15 @@ static struct iwl_mcc_update_resp_v8 *
|
|||
iwl_mld_copy_mcc_resp(const struct iwl_rx_packet *pkt)
|
||||
{
|
||||
const struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (const void *)pkt->data;
|
||||
int n_channels = __le32_to_cpu(mcc_resp_v8->n_channels);
|
||||
struct iwl_mcc_update_resp_v8 *resp_cp;
|
||||
int notif_len = struct_size(resp_cp, channels, n_channels);
|
||||
int n_channels;
|
||||
int notif_len;
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) < sizeof(*mcc_resp_v8))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v8->n_channels);
|
||||
notif_len = struct_size(resp_cp, channels, n_channels);
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) != notif_len)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
* Copyright (C) 2024-2026 Intel Corporation
|
||||
*/
|
||||
#ifdef CONFIG_THERMAL
|
||||
#include <linux/sort.h>
|
||||
|
|
@ -272,6 +272,7 @@ static void iwl_mld_thermal_zone_register(struct iwl_mld *mld)
|
|||
if (ret) {
|
||||
IWL_DEBUG_TEMP(mld, "Failed to enable thermal zone\n");
|
||||
thermal_zone_device_unregister(mld->tzone);
|
||||
mld->tzone = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -385,10 +386,8 @@ static void iwl_mld_thermal_zone_unregister(struct iwl_mld *mld)
|
|||
return;
|
||||
|
||||
IWL_DEBUG_TEMP(mld, "Thermal zone device unregister\n");
|
||||
if (mld->tzone) {
|
||||
thermal_zone_device_unregister(mld->tzone);
|
||||
mld->tzone = NULL;
|
||||
}
|
||||
thermal_zone_device_unregister(mld->tzone);
|
||||
mld->tzone = NULL;
|
||||
}
|
||||
|
||||
static void iwl_mld_cooling_device_unregister(struct iwl_mld *mld)
|
||||
|
|
|
|||
|
|
@ -1120,6 +1120,10 @@ void iwl_mld_handle_tx_resp_notif(struct iwl_mld *mld,
|
|||
ssn = le32_to_cpup((__le32 *)agg_status +
|
||||
tx_resp->frame_count) & 0xFFFF;
|
||||
|
||||
if (IWL_FW_CHECK(mld, txq_id >= ARRAY_SIZE(mld->fw_id_to_txq),
|
||||
"Invalid txq id %d\n", txq_id))
|
||||
return;
|
||||
|
||||
__skb_queue_head_init(&skbs);
|
||||
|
||||
/* we can free until ssn % q.n_bd not inclusive */
|
||||
|
|
|
|||
|
|
@ -1509,6 +1509,10 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
if (WARN_ON_ONCE(truncated < 0))
|
||||
truncated = 0;
|
||||
|
||||
/* this would be a firmware bug */
|
||||
if (WARN_ON_ONCE(pktsize < sizeof(*hdr)))
|
||||
return;
|
||||
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
int ivlen = 0, icvlen = 4; /* also FCS */
|
||||
|
|
@ -1517,10 +1521,6 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
if (!pkt)
|
||||
goto report;
|
||||
|
||||
skb_put_data(pkt, pktdata, hdrlen);
|
||||
pktdata += hdrlen;
|
||||
pktsize -= hdrlen;
|
||||
|
||||
if (ieee80211_has_protected(hdr->frame_control)) {
|
||||
/*
|
||||
* This is unlocked and using gtk_i(c)vlen,
|
||||
|
|
@ -1539,13 +1539,24 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
|
||||
/* if truncated, FCS/ICV is (partially) gone */
|
||||
if (truncated >= icvlen) {
|
||||
icvlen = 0;
|
||||
truncated -= icvlen;
|
||||
icvlen = 0;
|
||||
} else {
|
||||
icvlen -= truncated;
|
||||
truncated = 0;
|
||||
}
|
||||
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
pktsize <= hdrlen + ivlen + icvlen,
|
||||
"pktsize is too small %d\n",
|
||||
pktsize)) {
|
||||
kfree_skb(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_put_data(pkt, pktdata, hdrlen);
|
||||
pktdata += hdrlen;
|
||||
pktsize -= hdrlen;
|
||||
pktsize -= ivlen + icvlen;
|
||||
pktdata += ivlen;
|
||||
|
||||
|
|
@ -2123,16 +2134,16 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
|
|||
struct iwl_wowlan_status_data *status,
|
||||
u32 len)
|
||||
{
|
||||
if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys,
|
||||
"MLO is not supported, shouldn't receive MLO keys\n"))
|
||||
return;
|
||||
|
||||
if (len < sizeof(*data)) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
|
||||
status = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys,
|
||||
"MLO is not supported, shouldn't receive MLO keys\n"))
|
||||
return;
|
||||
|
||||
if (mvm->fast_resume)
|
||||
return;
|
||||
|
||||
|
|
@ -2448,13 +2459,15 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm,
|
|||
|
||||
if (fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) {
|
||||
query_len = sizeof(struct iwl_scan_offload_match_info);
|
||||
matches_len = sizeof(struct iwl_scan_offload_profile_match) *
|
||||
max_profiles;
|
||||
query_len = offsetof(struct iwl_scan_offload_match_info,
|
||||
matches) + matches_len;
|
||||
} else {
|
||||
query_len = sizeof(struct iwl_scan_offload_profiles_query_v1);
|
||||
matches_len = sizeof(struct iwl_scan_offload_profile_match_v1) *
|
||||
max_profiles;
|
||||
query_len = sizeof(struct iwl_scan_offload_profiles_query_v1) +
|
||||
matches_len;
|
||||
}
|
||||
|
||||
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
|
||||
|
|
@ -2756,7 +2769,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,
|
|||
struct iwl_wowlan_status_data *status,
|
||||
u32 len)
|
||||
{
|
||||
u32 data_size, packet_len = le32_to_cpu(notif->wake_packet_length);
|
||||
u32 data_size, packet_len;
|
||||
|
||||
if (len < sizeof(*notif)) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN wake packet notification!\n");
|
||||
|
|
@ -2775,6 +2788,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
packet_len = le32_to_cpu(notif->wake_packet_length);
|
||||
data_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif, wake_packet);
|
||||
|
||||
/* data_size got the padding from the notification, remove it. */
|
||||
|
|
@ -2807,7 +2821,8 @@ static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm,
|
|||
if (IS_ERR_OR_NULL(vif))
|
||||
return;
|
||||
|
||||
if (len < sizeof(struct iwl_scan_offload_match_info) + matches_len) {
|
||||
if (len < offsetof(struct iwl_scan_offload_match_info, matches) +
|
||||
matches_len) {
|
||||
IWL_ERR(mvm, "Invalid scan match info notification\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -2942,6 +2957,11 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
|
|||
case WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION): {
|
||||
struct iwl_d3_end_notif *notif = (void *)pkt->data;
|
||||
|
||||
if (len < sizeof(*notif)) {
|
||||
IWL_ERR(mvm, "Invalid D3 end notification size\n");
|
||||
break;
|
||||
}
|
||||
|
||||
d3_data->d3_end_flags = __le32_to_cpu(notif->flags);
|
||||
d3_data->notif_received |= IWL_D3_NOTIF_D3_END_NOTIF;
|
||||
|
||||
|
|
|
|||
|
|
@ -646,7 +646,8 @@ static void iter(struct ieee80211_hw *hw,
|
|||
WARN_ON(*target->cipher == IWL_LOCATION_CIPHER_INVALID);
|
||||
}
|
||||
|
||||
static void
|
||||
/* The tk buffer is assumed to be exactly TK_11AZ_LEN bytes */
|
||||
static int
|
||||
iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
u8 *bssid, u8 *cipher, u8 *hltk, u8 *tk,
|
||||
u8 *rx_pn, u8 *tx_pn, __le32 *flags)
|
||||
|
|
@ -656,12 +657,12 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
if (mvmvif->ftm_unprotected)
|
||||
return;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (!(le32_to_cpu(*flags) & (IWL_INITIATOR_AP_FLAGS_NON_TB |
|
||||
IWL_INITIATOR_AP_FLAGS_TB)))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
|
|
@ -679,14 +680,31 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
if (vif->cfg.assoc &&
|
||||
!memcmp(vif->bss_conf.bssid, bssid, ETH_ALEN)) {
|
||||
struct iwl_mvm_ftm_iter_data target;
|
||||
u32 key_len;
|
||||
|
||||
target.bssid = bssid;
|
||||
target.cipher = cipher;
|
||||
target.tk = NULL;
|
||||
ieee80211_iter_keys(mvm->hw, vif, iter, &target);
|
||||
|
||||
if (!WARN_ON(!target.tk))
|
||||
memcpy(tk, target.tk, TK_11AZ_LEN);
|
||||
if (WARN_ON(!target.tk))
|
||||
return -EINVAL;
|
||||
|
||||
switch (*target.cipher) {
|
||||
case IWL_LOCATION_CIPHER_CCMP_128:
|
||||
case IWL_LOCATION_CIPHER_GCMP_128:
|
||||
key_len = WLAN_KEY_LEN_CCMP;
|
||||
break;
|
||||
case IWL_LOCATION_CIPHER_GCMP_256:
|
||||
key_len = WLAN_KEY_LEN_GCMP_256;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(tk, 0, TK_11AZ_LEN);
|
||||
memcpy(tk, target.tk, key_len);
|
||||
} else {
|
||||
memcpy(tk, entry->tk, sizeof(entry->tk));
|
||||
}
|
||||
|
|
@ -695,8 +713,10 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
memcpy(tx_pn, entry->tx_pn, sizeof(entry->tx_pn));
|
||||
|
||||
FTM_SET_FLAG(SECURED);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -708,12 +728,11 @@ iwl_mvm_ftm_put_target_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid,
|
||||
&target->cipher, target->hltk,
|
||||
target->tk, target->rx_pn,
|
||||
target->tx_pn,
|
||||
&target->initiator_ap_flags);
|
||||
return err;
|
||||
return iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid,
|
||||
&target->cipher, target->hltk,
|
||||
target->tk, target->rx_pn,
|
||||
target->tx_pn,
|
||||
&target->initiator_ap_flags);
|
||||
}
|
||||
|
||||
static int iwl_mvm_ftm_start_v11(struct iwl_mvm *mvm,
|
||||
|
|
@ -881,11 +900,13 @@ iwl_mvm_ftm_put_target_v10(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
iwl_mvm_ftm_set_target_flags(mvm, peer, &target->initiator_ap_flags);
|
||||
iwl_mvm_ftm_set_sta(mvm, vif, peer, &target->sta_id,
|
||||
&target->initiator_ap_flags);
|
||||
iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid,
|
||||
&target->cipher, target->hltk,
|
||||
target->tk, target->rx_pn,
|
||||
target->tx_pn,
|
||||
&target->initiator_ap_flags);
|
||||
ret = iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid,
|
||||
&target->cipher, target->hltk,
|
||||
target->tk, target->rx_pn,
|
||||
target->tx_pn,
|
||||
&target->initiator_ap_flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2r_max_sts = IWL_MVM_FTM_I2R_MAX_STS > 1 ? 1 :
|
||||
IWL_MVM_FTM_I2R_MAX_STS;
|
||||
|
|
|
|||
|
|
@ -964,12 +964,22 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
iwl_rx_packet_payload_len(cmd.resp_pkt) !=
|
||||
sizeof(*resp),
|
||||
"Wrong size for iwl_geo_tx_power_profiles_resp: %d\n",
|
||||
iwl_rx_packet_payload_len(cmd.resp_pkt))) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp = (void *)cmd.resp_pkt->data;
|
||||
ret = le32_to_cpu(resp->profile_idx);
|
||||
|
||||
if (WARN_ON(ret > BIOS_GEO_MAX_PROFILE_NUM))
|
||||
ret = -EIO;
|
||||
|
||||
out:
|
||||
iwl_free_resp(&cmd);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1493,49 +1493,54 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
|
|||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
|
||||
struct iwl_extended_beacon_notif *beacon = (void *)pkt->data;
|
||||
struct iwl_extended_beacon_notif_v5 *beacon_v5 = (void *)pkt->data;
|
||||
struct ieee80211_vif *csa_vif;
|
||||
struct ieee80211_vif *tx_blocked_vif;
|
||||
struct agg_tx_status *agg_status;
|
||||
u32 beacon_gp2;
|
||||
u16 status;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2);
|
||||
|
||||
if (!iwl_mvm_is_short_beacon_notif_supported(mvm)) {
|
||||
struct iwl_extended_beacon_notif_v5 *beacon = (void *)pkt->data;
|
||||
struct iwl_tx_resp *beacon_notify_hdr =
|
||||
&beacon_v5->beacon_notify_hdr;
|
||||
&beacon->beacon_notify_hdr;
|
||||
|
||||
if (unlikely(pkt_len < sizeof(*beacon_v5)))
|
||||
if (unlikely(pkt_len < sizeof(*beacon)))
|
||||
return;
|
||||
|
||||
mvm->ibss_manager = beacon_v5->ibss_mgr_status != 0;
|
||||
beacon_gp2 = le32_to_cpu(beacon->gp2);
|
||||
|
||||
mvm->ibss_manager = beacon->ibss_mgr_status != 0;
|
||||
agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr);
|
||||
status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK;
|
||||
IWL_DEBUG_RX(mvm,
|
||||
"beacon status %#x retries:%d tsf:0x%016llX gp2:0x%X rate:%d\n",
|
||||
status, beacon_notify_hdr->failure_frame,
|
||||
le64_to_cpu(beacon->tsf),
|
||||
mvm->ap_last_beacon_gp2,
|
||||
beacon_gp2,
|
||||
le32_to_cpu(beacon_notify_hdr->initial_rate));
|
||||
} else {
|
||||
const struct iwl_extended_beacon_notif *beacon =
|
||||
(void *)pkt->data;
|
||||
|
||||
if (unlikely(pkt_len < sizeof(*beacon)))
|
||||
return;
|
||||
|
||||
beacon_gp2 = le32_to_cpu(beacon->gp2);
|
||||
|
||||
mvm->ibss_manager = beacon->ibss_mgr_status != 0;
|
||||
status = le32_to_cpu(beacon->status) & TX_STATUS_MSK;
|
||||
IWL_DEBUG_RX(mvm,
|
||||
"beacon status %#x tsf:0x%016llX gp2:0x%X\n",
|
||||
status, le64_to_cpu(beacon->tsf),
|
||||
mvm->ap_last_beacon_gp2);
|
||||
beacon_gp2);
|
||||
}
|
||||
|
||||
csa_vif = rcu_dereference_protected(mvm->csa_vif,
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (unlikely(csa_vif && csa_vif->bss_conf.csa_active))
|
||||
iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2,
|
||||
iwl_mvm_csa_count_down(mvm, csa_vif, beacon_gp2,
|
||||
(status == TX_STATUS_SUCCESS));
|
||||
|
||||
tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif,
|
||||
|
|
|
|||
|
|
@ -625,9 +625,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
hw->wiphy->max_sched_scan_reqs = 1;
|
||||
hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
|
||||
hw->wiphy->max_match_sets = iwl_umac_scan_get_max_profiles(mvm->fw);
|
||||
/* we create the 802.11 header and zero length SSID IE. */
|
||||
hw->wiphy->max_sched_scan_ie_len =
|
||||
SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
|
||||
hw->wiphy->max_sched_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);
|
||||
hw->wiphy->max_sched_scan_plans = IWL_MAX_SCHED_SCAN_PLANS;
|
||||
hw->wiphy->max_sched_scan_plan_interval = U16_MAX;
|
||||
|
||||
|
|
@ -3061,7 +3059,6 @@ void iwl_mvm_stop_ap_ibss_common(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
mvmvif->ap_ibss_active = false;
|
||||
mvm->ap_last_beacon_gp2 = 0;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP && !vif->p2p) {
|
||||
iwl_mvm_vif_set_low_latency(mvmvif, false,
|
||||
|
|
@ -3490,7 +3487,7 @@ static void iwl_mvm_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
|
|||
elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, ies->data,
|
||||
ies->len);
|
||||
|
||||
if (!elem || elem->datalen < 10 ||
|
||||
if (!elem || elem->datalen < 11 ||
|
||||
!(elem->data[10] &
|
||||
WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) {
|
||||
data->tolerated = false;
|
||||
|
|
|
|||
|
|
@ -1168,9 +1168,6 @@ struct iwl_mvm {
|
|||
struct ieee80211_vif __rcu *csa_tx_blocked_vif;
|
||||
u8 csa_tx_block_bcn_timeout;
|
||||
|
||||
/* system time of last beacon (for AP/GO interface) */
|
||||
u32 ap_last_beacon_gp2;
|
||||
|
||||
/* indicates that we transmitted the last beacon */
|
||||
bool ibss_manager;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2019, 2021-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2019, 2021-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -416,6 +416,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
int ret, resp_ver;
|
||||
u32 status;
|
||||
int resp_len, n_channels;
|
||||
unsigned int pkt_len;
|
||||
u16 mcc;
|
||||
|
||||
if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
|
||||
|
|
@ -431,6 +432,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
return ERR_PTR(ret);
|
||||
|
||||
pkt = cmd.resp_pkt;
|
||||
pkt_len = iwl_rx_packet_payload_len(pkt);
|
||||
|
||||
resp_ver = iwl_fw_lookup_notif_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP,
|
||||
MCC_UPDATE_CMD, 0);
|
||||
|
|
@ -439,9 +441,18 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
if (resp_ver >= 8) {
|
||||
struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (void *)pkt->data;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, pkt_len < sizeof(*mcc_resp_v8),
|
||||
"MCC v8 response too short: %u\n", pkt_len)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v8->n_channels);
|
||||
if (iwl_rx_packet_payload_len(pkt) !=
|
||||
struct_size(mcc_resp_v8, channels, n_channels)) {
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
pkt_len !=
|
||||
struct_size(mcc_resp_v8, channels, n_channels),
|
||||
"invalid MCC v8 response size: %u (n_channels=%d)\n",
|
||||
pkt_len, n_channels)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -464,9 +475,18 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) {
|
||||
struct iwl_mcc_update_resp_v4 *mcc_resp_v4 = (void *)pkt->data;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, pkt_len < sizeof(*mcc_resp_v4),
|
||||
"MCC v4 response too short: %u\n", pkt_len)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v4->n_channels);
|
||||
if (iwl_rx_packet_payload_len(pkt) !=
|
||||
struct_size(mcc_resp_v4, channels, n_channels)) {
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
pkt_len !=
|
||||
struct_size(mcc_resp_v4, channels, n_channels),
|
||||
"invalid MCC v4 response size: %u (n_channels=%d)\n",
|
||||
pkt_len, n_channels)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -489,9 +509,18 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
} else {
|
||||
struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, pkt_len < sizeof(*mcc_resp_v3),
|
||||
"MCC v3 response too short: %u\n", pkt_len)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v3->n_channels);
|
||||
if (iwl_rx_packet_payload_len(pkt) !=
|
||||
struct_size(mcc_resp_v3, channels, n_channels)) {
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
pkt_len !=
|
||||
struct_size(mcc_resp_v3, channels, n_channels),
|
||||
"invalid MCC v3 response size: %u (n_channels=%d)\n",
|
||||
pkt_len, n_channels)) {
|
||||
resp_cp = ERR_PTR(-EINVAL);
|
||||
goto exit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2021 - 2023, 2025 Intel Corporation
|
||||
* Copyright (C) 2021 - 2023, 2025-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "mvm.h"
|
||||
|
|
@ -121,6 +121,8 @@ iwl_mvm_get_crosstimestamp_fw(struct iwl_mvm *mvm, u32 *gp2, u64 *sys_time)
|
|||
*sys_time = (u64)le32_to_cpu(resp->platform_timestamp_hi) << 32 |
|
||||
le32_to_cpu(resp->platform_timestamp_lo);
|
||||
|
||||
iwl_free_resp(&cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2018-2026 Intel Corporation
|
||||
*/
|
||||
#include "rs.h"
|
||||
#include "fw-api.h"
|
||||
|
|
@ -423,9 +423,14 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
|
|||
struct iwl_lq_sta_rs_fw *lq_sta;
|
||||
u32 flags;
|
||||
|
||||
notif = (void *)pkt->data;
|
||||
if (IWL_FW_CHECK(mvm, notif->sta_id >= mvm->fw->ucode_capa.num_stations,
|
||||
"Invalid sta id (%d) in TLC notification\n",
|
||||
notif->sta_id))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
notif = (void *)pkt->data;
|
||||
link_sta = rcu_dereference(mvm->fw_id_to_link_sta[notif->sta_id]);
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]);
|
||||
if (IS_ERR_OR_NULL(sta) || !link_sta) {
|
||||
|
|
|
|||
|
|
@ -1227,6 +1227,11 @@ void iwl_mvm_window_status_notif(struct iwl_mvm *mvm,
|
|||
/* get the station */
|
||||
sta_id = (ratid & BA_WINDOW_STATUS_STA_ID_MSK)
|
||||
>> BA_WINDOW_STATUS_STA_ID_POS;
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
sta_id >= mvm->fw->ucode_capa.num_stations,
|
||||
"Invalid sta id (%d) in BA window status notification\n",
|
||||
sta_id))
|
||||
continue;
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
if (IS_ERR_OR_NULL(sta))
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -3144,8 +3144,6 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms);
|
||||
|
||||
/* for 6 GHZ band only PSC channels need to be added */
|
||||
for (i = 0; i < params.n_channels; i++) {
|
||||
struct ieee80211_channel *channel = params.channels[i];
|
||||
|
|
@ -3179,6 +3177,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
|||
goto out;
|
||||
}
|
||||
|
||||
iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms);
|
||||
|
||||
uid = iwl_mvm_build_scan_cmd(mvm, vif, &hcmd, ¶ms, type);
|
||||
if (uid < 0) {
|
||||
ret = uid;
|
||||
|
|
@ -3217,6 +3217,10 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
|
|||
|
||||
mvm->mei_scan_filter.is_mei_limited_scan = false;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, uid >= ARRAY_SIZE(mvm->scan_uid_status),
|
||||
"FW reports out-of-range scan UID %d\n", uid))
|
||||
return;
|
||||
|
||||
IWL_DEBUG_SCAN(mvm,
|
||||
"Scan completed: uid=%u type=%u, status=%s, EBS=%s\n",
|
||||
uid, mvm->scan_uid_status[uid],
|
||||
|
|
|
|||
|
|
@ -951,6 +951,11 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
|
|||
struct ieee80211_vif *vif;
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, id >= ARRAY_SIZE(mvm->vif_id_to_mac),
|
||||
"Invalid mac_link_id (%d) in session protect notif\n",
|
||||
id))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* note we use link ID == MAC ID */
|
||||
|
|
|
|||
|
|
@ -1544,6 +1544,17 @@ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm *mvm,
|
|||
return val & 0xFFF;
|
||||
}
|
||||
|
||||
static inline size_t iwl_mvm_tx_resp_min_len(struct iwl_mvm *mvm,
|
||||
struct iwl_tx_resp *tx_resp)
|
||||
{
|
||||
struct agg_tx_status *agg_status =
|
||||
iwl_mvm_get_agg_status(mvm, tx_resp);
|
||||
|
||||
/* The aggregate response ends with a trailing SCD SSN __le32 word. */
|
||||
return (u8 *)(agg_status + tx_resp->frame_count) - (u8 *)tx_resp +
|
||||
sizeof(__le32);
|
||||
}
|
||||
|
||||
static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
|
|
@ -1847,6 +1858,9 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
|
|||
int queue = SEQ_TO_QUEUE(sequence);
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
if (WARN_ON_ONCE(iwl_mvm_has_new_tx_api(mvm)))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(queue < IWL_MVM_DQA_MIN_DATA_QUEUE &&
|
||||
(queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE)))
|
||||
return;
|
||||
|
|
@ -1881,6 +1895,26 @@ void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
|||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_tx_resp *tx_resp = (void *)pkt->data;
|
||||
size_t min_len;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, !tx_resp->frame_count,
|
||||
"invalid TX_CMD frame_count %u\n",
|
||||
tx_resp->frame_count))
|
||||
return;
|
||||
|
||||
if (IWL_FW_CHECK(mvm,
|
||||
iwl_mvm_has_new_tx_api(mvm) &&
|
||||
tx_resp->frame_count != 1,
|
||||
"invalid TX_CMD frame_count %u for new TX API\n",
|
||||
tx_resp->frame_count))
|
||||
return;
|
||||
|
||||
min_len = iwl_mvm_tx_resp_min_len(mvm, tx_resp);
|
||||
if (IWL_FW_CHECK(mvm, iwl_rx_packet_payload_len(pkt) < min_len,
|
||||
"invalid TX_CMD len %u (frame_count %u, min %zu)\n",
|
||||
iwl_rx_packet_payload_len(pkt), tx_resp->frame_count,
|
||||
min_len))
|
||||
return;
|
||||
|
||||
if (tx_resp->frame_count == 1)
|
||||
iwl_mvm_rx_tx_cmd_single(mvm, pkt);
|
||||
|
|
@ -2100,8 +2134,14 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
|||
if (tid == IWL_MGMT_TID)
|
||||
tid = IWL_MAX_TID_COUNT;
|
||||
|
||||
if (IWL_FW_CHECK(mvm, tid >=
|
||||
ARRAY_SIZE(mvmsta->tid_data),
|
||||
"invalid TID %d in compressed BA\n",
|
||||
tid))
|
||||
continue;
|
||||
|
||||
if (mvmsta)
|
||||
mvmsta->tid_data[i].lq_color = lq_color;
|
||||
mvmsta->tid_data[tid].lq_color = lq_color;
|
||||
|
||||
iwl_mvm_tx_reclaim(mvm, sta_id, tid,
|
||||
(int)(le16_to_cpu(ba_tfd->q_num)),
|
||||
|
|
@ -2121,6 +2161,9 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
|||
ba_notif = (void *)pkt->data;
|
||||
sta_id = ba_notif->sta_id;
|
||||
tid = ba_notif->tid;
|
||||
if (IWL_FW_CHECK(mvm, tid >= ARRAY_SIZE(mvmsta->tid_data),
|
||||
"invalid TID %d in BA notif\n", tid))
|
||||
return;
|
||||
/* "flow" corresponds to Tx queue */
|
||||
txq = le16_to_cpu(ba_notif->scd_flow);
|
||||
/* "ssn" is start of block-ack Tx window, corresponds to index
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2018-2026 Intel Corporation
|
||||
*/
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-fh.h"
|
||||
|
|
@ -99,6 +99,11 @@ int iwl_pcie_init_fw_sec(struct iwl_trans *trans,
|
|||
/* add 2 due to separators */
|
||||
paging_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + umac_cnt + 2);
|
||||
|
||||
if (WARN_ON(lmac_cnt > ARRAY_SIZE(ctxt_dram->lmac_img) ||
|
||||
umac_cnt > ARRAY_SIZE(ctxt_dram->umac_img) ||
|
||||
paging_cnt > ARRAY_SIZE(ctxt_dram->virtual_img)))
|
||||
return -EINVAL;
|
||||
|
||||
dram->fw = kzalloc_objs(*dram->fw, umac_cnt + lmac_cnt);
|
||||
if (!dram->fw)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2003-2014, 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2003-2014, 2018-2024, 2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -1238,11 +1238,16 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
|
|||
}
|
||||
}
|
||||
kfree(trans_pcie->rx_pool);
|
||||
trans_pcie->rx_pool = NULL;
|
||||
kfree(trans_pcie->global_table);
|
||||
trans_pcie->global_table = NULL;
|
||||
kfree(trans_pcie->rxq);
|
||||
trans_pcie->rxq = NULL;
|
||||
|
||||
if (trans_pcie->alloc_page)
|
||||
if (trans_pcie->alloc_page) {
|
||||
__free_pages(trans_pcie->alloc_page, trans_pcie->rx_page_order);
|
||||
trans_pcie->alloc_page = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_pcie_rx_move_to_allocator(struct iwl_rxq *rxq,
|
||||
|
|
|
|||
|
|
@ -823,7 +823,7 @@ struct chan_band_param_set {
|
|||
|
||||
struct mwifiex_ie_types_chan_band_list_param_set {
|
||||
struct mwifiex_ie_types_header header;
|
||||
struct chan_band_param_set chan_band_param[1];
|
||||
struct chan_band_param_set chan_band_param[];
|
||||
} __packed;
|
||||
|
||||
struct mwifiex_ie_types_rates_param_set {
|
||||
|
|
@ -886,7 +886,7 @@ struct mwifiex_ie_types_wildcard_ssid_params {
|
|||
#define TSF_DATA_SIZE 8
|
||||
struct mwifiex_ie_types_tsf_timestamp {
|
||||
struct mwifiex_ie_types_header header;
|
||||
u8 tsf_data[1];
|
||||
u8 tsf_data[];
|
||||
} __packed;
|
||||
|
||||
struct mwifiex_cf_param_set {
|
||||
|
|
@ -903,8 +903,8 @@ struct mwifiex_ibss_param_set {
|
|||
struct mwifiex_ie_types_ss_param_set {
|
||||
struct mwifiex_ie_types_header header;
|
||||
union {
|
||||
struct mwifiex_cf_param_set cf_param_set[1];
|
||||
struct mwifiex_ibss_param_set ibss_param_set[1];
|
||||
DECLARE_FLEX_ARRAY(struct mwifiex_cf_param_set, cf_param_set);
|
||||
DECLARE_FLEX_ARRAY(struct mwifiex_ibss_param_set, ibss_param_set);
|
||||
} cf_ibss;
|
||||
} __packed;
|
||||
|
||||
|
|
@ -922,8 +922,8 @@ struct mwifiex_ds_param_set {
|
|||
struct mwifiex_ie_types_phy_param_set {
|
||||
struct mwifiex_ie_types_header header;
|
||||
union {
|
||||
struct mwifiex_fh_param_set fh_param_set[1];
|
||||
struct mwifiex_ds_param_set ds_param_set[1];
|
||||
DECLARE_FLEX_ARRAY(struct mwifiex_fh_param_set, fh_param_set);
|
||||
DECLARE_FLEX_ARRAY(struct mwifiex_ds_param_set, ds_param_set);
|
||||
} fh_ds;
|
||||
} __packed;
|
||||
|
||||
|
|
@ -1383,7 +1383,7 @@ struct host_cmd_ds_802_11_snmp_mib {
|
|||
__le16 query_type;
|
||||
__le16 oid;
|
||||
__le16 buf_size;
|
||||
u8 value[1];
|
||||
u8 value[];
|
||||
} __packed;
|
||||
|
||||
struct mwifiex_rate_scope {
|
||||
|
|
@ -1551,7 +1551,7 @@ struct mwifiex_scan_cmd_config {
|
|||
* TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set
|
||||
* WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set
|
||||
*/
|
||||
u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored
|
||||
u8 tlv_buf[]; /* SSID TLV(s) and ChanList TLVs are stored
|
||||
here */
|
||||
} __packed;
|
||||
|
||||
|
|
@ -1683,7 +1683,7 @@ struct host_cmd_ds_802_11_bg_scan_query_rsp {
|
|||
struct mwifiex_ietypes_domain_param_set {
|
||||
struct mwifiex_ie_types_header header;
|
||||
u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
|
||||
struct ieee80211_country_ie_triplet triplet[1];
|
||||
struct ieee80211_country_ie_triplet triplet[];
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_ds_802_11d_domain_info {
|
||||
|
|
|
|||
|
|
@ -421,15 +421,15 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
|
|||
|
||||
phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos;
|
||||
phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS);
|
||||
phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set));
|
||||
memcpy(&phy_tlv->fh_ds.ds_param_set,
|
||||
phy_tlv->header.len = cpu_to_le16(sizeof(*phy_tlv->fh_ds.ds_param_set));
|
||||
memcpy(phy_tlv->fh_ds.ds_param_set,
|
||||
&bss_desc->phy_param_set.ds_param_set.current_chan,
|
||||
sizeof(phy_tlv->fh_ds.ds_param_set));
|
||||
sizeof(*phy_tlv->fh_ds.ds_param_set));
|
||||
pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len);
|
||||
|
||||
ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos;
|
||||
ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS);
|
||||
ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set));
|
||||
ss_tlv->header.len = cpu_to_le16(sizeof(*ss_tlv->cf_ibss.cf_param_set));
|
||||
pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len);
|
||||
|
||||
/* Get the common rates supported between the driver and the BSS Desc */
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
|
|||
"cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
|
||||
cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
|
||||
cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
|
||||
- 1 + S_DS_GEN);
|
||||
+ S_DS_GEN);
|
||||
|
||||
snmp_mib->oid = cpu_to_le16((u16)cmd_oid);
|
||||
if (cmd_action == HostCmd_ACT_GEN_GET) {
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ static int mwifiex_request_rgpower_table(struct mwifiex_private *priv)
|
|||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
char rgpower_table_name[30];
|
||||
char country_code[3];
|
||||
int ret;
|
||||
|
||||
strscpy(country_code, domain_info->country_code, sizeof(country_code));
|
||||
|
||||
|
|
@ -214,16 +215,17 @@ static int mwifiex_request_rgpower_table(struct mwifiex_private *priv)
|
|||
adapter->rgpower_data = NULL;
|
||||
}
|
||||
|
||||
if ((request_firmware(&adapter->rgpower_data, rgpower_table_name,
|
||||
adapter->dev))) {
|
||||
ret = request_firmware_direct(&adapter->rgpower_data, rgpower_table_name,
|
||||
adapter->dev);
|
||||
|
||||
if (ret) {
|
||||
mwifiex_dbg(
|
||||
adapter, INFO,
|
||||
"info: %s: failed to request regulatory power table\n",
|
||||
__func__);
|
||||
return -EIO;
|
||||
"info: %s: failed to request regulatory power table: %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mwifiex_dnld_rgpower_table(struct mwifiex_private *priv)
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac,
|
|||
|
||||
/* follow AP's channel bandwidth */
|
||||
if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) &&
|
||||
bss_desc->bcn_ht_cap &&
|
||||
bss_desc->bcn_ht_oper &&
|
||||
ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param))
|
||||
ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param;
|
||||
|
||||
|
|
|
|||
|
|
@ -123,11 +123,31 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
|
|||
len = ETH_ALEN;
|
||||
|
||||
if (len != -1) {
|
||||
u16 evt_len = le16_to_cpu(event->len);
|
||||
|
||||
sinfo->assoc_req_ies = &event->data[len];
|
||||
len = (u8 *)sinfo->assoc_req_ies -
|
||||
(u8 *)&event->frame_control;
|
||||
sinfo->assoc_req_ies_len =
|
||||
le16_to_cpu(event->len) - (u16)len;
|
||||
|
||||
/*
|
||||
* event->len is reported by the device firmware
|
||||
* and is not otherwise validated. Reject a
|
||||
* length that underflows the header, or that
|
||||
* would place the association request IEs
|
||||
* outside the fixed-size event_body[] buffer the
|
||||
* event was copied into; otherwise the IE walk
|
||||
* in mwifiex_set_sta_ht_cap() reads past
|
||||
* event_body and out of the adapter slab object.
|
||||
*/
|
||||
if (evt_len < len ||
|
||||
(u8 *)&event->frame_control + evt_len >
|
||||
adapter->event_body + MAX_EVENT_SIZE) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"invalid STA assoc event length\n");
|
||||
kfree(sinfo);
|
||||
return -1;
|
||||
}
|
||||
sinfo->assoc_req_ies_len = evt_len - (u16)len;
|
||||
}
|
||||
}
|
||||
cfg80211_new_sta(priv->netdev->ieee80211_ptr, event->sta_addr,
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ config MT792x_USB
|
|||
select MT76_USB
|
||||
|
||||
config MT76_NPU
|
||||
bool
|
||||
depends on MT76_CORE
|
||||
tristate
|
||||
depends on NET_AIROHA_NPU=y || MT76_CORE=NET_AIROHA_NPU
|
||||
|
||||
source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
|
||||
source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,11 @@ mt76-y := \
|
|||
mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
|
||||
tx.o agg-rx.o mcu.o wed.o scan.o channel.o
|
||||
|
||||
mt76-$(CONFIG_MT76_NPU) += npu.o
|
||||
ifdef CONFIG_MT76_NPU
|
||||
# CONFIG_MT76_NPU is tristate to simplify dependency tracking,
|
||||
# but it behaves as a bool symbol here.
|
||||
mt76-y += npu.o
|
||||
endif
|
||||
mt76-$(CONFIG_PCI) += pci.o
|
||||
mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
|
||||
|
|
|
|||
|
|
@ -1189,7 +1189,10 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
|
|||
mt76_for_each_q_rx(dev, i) {
|
||||
struct mt76_queue *q = &dev->q_rx[i];
|
||||
|
||||
netif_napi_del(&dev->napi[i]);
|
||||
if (!mt76_queue_is_wed_rro(q)) {
|
||||
napi_disable(&dev->napi[i]);
|
||||
netif_napi_del(&dev->napi[i]);
|
||||
}
|
||||
mt76_dma_rx_cleanup(dev, q);
|
||||
|
||||
page_pool_destroy(q->page_pool);
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ mt76_eeprom_override(struct mt76_phy *phy)
|
|||
if (err == -EPROBE_DEFER)
|
||||
return err;
|
||||
|
||||
if (err) {
|
||||
if (!is_valid_ether_addr(phy->macaddr)) {
|
||||
eth_random_addr(phy->macaddr);
|
||||
dev_info(dev->dev,
|
||||
"Invalid MAC address, using random address %pM\n",
|
||||
|
|
|
|||
|
|
@ -1647,7 +1647,7 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|||
int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state);
|
||||
int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len);
|
||||
|
||||
#ifdef CONFIG_MT76_NPU
|
||||
#if IS_ENABLED(CONFIG_MT76_NPU)
|
||||
void mt76_npu_check_ppe(struct mt76_dev *dev, struct sk_buff *skb,
|
||||
u32 info);
|
||||
int mt76_npu_dma_add_buf(struct mt76_phy *phy, struct mt76_queue *q,
|
||||
|
|
@ -1736,12 +1736,12 @@ static inline int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex,
|
|||
|
||||
static inline bool mt76_npu_device_active(struct mt76_dev *dev)
|
||||
{
|
||||
return !!rcu_access_pointer(dev->mmio.npu);
|
||||
return mt76_is_mmio(dev) && !!rcu_access_pointer(dev->mmio.npu);
|
||||
}
|
||||
|
||||
static inline bool mt76_ppe_device_active(struct mt76_dev *dev)
|
||||
{
|
||||
return !!rcu_access_pointer(dev->mmio.ppe_dev);
|
||||
return mt76_is_mmio(dev) && !!rcu_access_pointer(dev->mmio.ppe_dev);
|
||||
}
|
||||
|
||||
static inline int mt76_npu_send_msg(struct airoha_npu *npu, int ifindex,
|
||||
|
|
|
|||
|
|
@ -1601,6 +1601,8 @@ bool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len)
|
|||
|
||||
switch (type) {
|
||||
case PKT_TYPE_TXRX_NOTIFY:
|
||||
if (!mt76_is_mmio(mdev))
|
||||
return false;
|
||||
mt7615_mac_tx_free(dev, data, len);
|
||||
return false;
|
||||
case PKT_TYPE_TXS:
|
||||
|
|
@ -1634,6 +1636,10 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
|||
dev_kfree_skb(skb);
|
||||
break;
|
||||
case PKT_TYPE_TXRX_NOTIFY:
|
||||
if (!mt76_is_mmio(mdev)) {
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
mt7615_mac_tx_free(dev, skb->data, skb->len);
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1458,6 +1458,8 @@ mt76_connac_mcu_uni_bss_he_tlv(struct mt76_phy *phy, struct ieee80211_vif *vif,
|
|||
struct bss_info_uni_he *he;
|
||||
|
||||
cap = mt76_connac_get_he_phy_cap(phy, vif);
|
||||
if (!cap)
|
||||
return;
|
||||
|
||||
he = (struct bss_info_uni_he *)tlv;
|
||||
he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
|
||||
|
|
|
|||
|
|
@ -595,6 +595,8 @@ mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
|
|||
struct tlv *tlv;
|
||||
|
||||
cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
|
||||
if (!cap)
|
||||
return;
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));
|
||||
|
||||
|
|
@ -1177,13 +1179,12 @@ mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
|
|||
}
|
||||
|
||||
static void
|
||||
mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
|
||||
struct mt7915_phy *phy, struct sta_rec_bf *bf)
|
||||
mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta,
|
||||
const struct ieee80211_sta_he_cap *vc,
|
||||
struct sta_rec_bf *bf)
|
||||
{
|
||||
struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
|
||||
struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
|
||||
const struct ieee80211_sta_he_cap *vc =
|
||||
mt76_connac_get_he_phy_cap(phy->mt76, vif);
|
||||
const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
|
||||
u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
|
||||
u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
|
||||
|
|
@ -1242,6 +1243,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
|
|||
{
|
||||
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
|
||||
struct mt7915_phy *phy = mvif->phy;
|
||||
const struct ieee80211_sta_he_cap *vc = NULL;
|
||||
int tx_ant = hweight8(phy->mt76->chainmask) - 1;
|
||||
struct sta_rec_bf *bf;
|
||||
struct tlv *tlv;
|
||||
|
|
@ -1260,6 +1262,12 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
|
|||
if (!ebf && !dev->ibf)
|
||||
return;
|
||||
|
||||
if (sta->deflink.he_cap.has_he && ebf) {
|
||||
vc = mt76_connac_get_he_phy_cap(phy->mt76, vif);
|
||||
if (!vc)
|
||||
return;
|
||||
}
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
|
||||
bf = (struct sta_rec_bf *)tlv;
|
||||
|
||||
|
|
@ -1268,7 +1276,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
|
|||
* ht: iBF only, since mac80211 lacks of eBF support
|
||||
*/
|
||||
if (sta->deflink.he_cap.has_he && ebf)
|
||||
mt7915_mcu_sta_bfer_he(sta, vif, phy, bf);
|
||||
mt7915_mcu_sta_bfer_he(sta, vc, bf);
|
||||
else if (sta->deflink.vht_cap.vht_supported)
|
||||
mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf);
|
||||
else if (sta->deflink.ht_cap.ht_supported)
|
||||
|
|
|
|||
|
|
@ -570,8 +570,9 @@ bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len)
|
|||
|
||||
switch (type) {
|
||||
case PKT_TYPE_TXRX_NOTIFY:
|
||||
/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */
|
||||
mt7921_mac_tx_free(dev, data, len); /* mmio */
|
||||
if (!mt76_is_mmio(mdev))
|
||||
return false;
|
||||
mt7921_mac_tx_free(dev, data, len);
|
||||
return false;
|
||||
case PKT_TYPE_TXS:
|
||||
for (rxd += 2; rxd + 8 <= end; rxd += 8)
|
||||
|
|
@ -600,7 +601,10 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
|||
|
||||
switch (type) {
|
||||
case PKT_TYPE_TXRX_NOTIFY:
|
||||
/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */
|
||||
if (!mt76_is_mmio(mdev)) {
|
||||
napi_consume_skb(skb, 1);
|
||||
break;
|
||||
}
|
||||
mt7921_mac_tx_free(dev, skb->data, skb->len);
|
||||
napi_consume_skb(skb, 1);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1203,8 +1203,9 @@ bool mt7925_rx_check(struct mt76_dev *mdev, void *data, int len)
|
|||
|
||||
switch (type) {
|
||||
case PKT_TYPE_TXRX_NOTIFY:
|
||||
/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */
|
||||
mt7925_mac_tx_free(dev, data, len); /* mmio */
|
||||
if (!mt76_is_mmio(mdev))
|
||||
return false;
|
||||
mt7925_mac_tx_free(dev, data, len);
|
||||
return false;
|
||||
case PKT_TYPE_TXS:
|
||||
for (rxd += 4; rxd + 12 <= end; rxd += 12)
|
||||
|
|
@ -1240,7 +1241,10 @@ void mt7925_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
|||
|
||||
switch (type) {
|
||||
case PKT_TYPE_TXRX_NOTIFY:
|
||||
/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */
|
||||
if (!mt76_is_mmio(mdev)) {
|
||||
napi_consume_skb(skb, 1);
|
||||
break;
|
||||
}
|
||||
mt7925_mac_tx_free(dev, skb->data, skb->len);
|
||||
napi_consume_skb(skb, 1);
|
||||
break;
|
||||
|
|
@ -1284,6 +1288,9 @@ mt7925_vif_connect_iter(void *priv, u8 *mac,
|
|||
|
||||
for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
bss_conf = mt792x_vif_to_bss_conf(vif, i);
|
||||
if (!bss_conf)
|
||||
continue;
|
||||
|
||||
mconf = mt792x_vif_to_link(mvif, i);
|
||||
|
||||
mt76_connac_mcu_uni_add_dev(&dev->mphy, bss_conf, &mconf->mt76,
|
||||
|
|
|
|||
|
|
@ -1713,6 +1713,9 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw,
|
|||
mconf = mt792x_vif_to_link(mvif, i);
|
||||
mlink = mt792x_sta_to_link(msta, i);
|
||||
|
||||
if (!mlink)
|
||||
continue;
|
||||
|
||||
if (enabled)
|
||||
set_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -2773,6 +2773,8 @@ mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf,
|
|||
struct tlv *tlv;
|
||||
|
||||
cap = mt76_connac_get_he_phy_cap(phy->mt76, link_conf->vif);
|
||||
if (!cap)
|
||||
return;
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he));
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ config MT7996E
|
|||
config MT7996_NPU
|
||||
bool "MT7996 (PCIe) NPU support"
|
||||
depends on MT7996E
|
||||
depends on NET_AIROHA_NPU=y || MT7996E=NET_AIROHA_NPU
|
||||
depends on NET_AIROHA_NPU=y || MT76_CORE=NET_AIROHA_NPU
|
||||
select MT76_NPU
|
||||
default n
|
||||
|
|
|
|||
|
|
@ -935,6 +935,8 @@ mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
|
|||
struct tlv *tlv;
|
||||
|
||||
cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
|
||||
if (!cap)
|
||||
return;
|
||||
|
||||
tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he));
|
||||
|
||||
|
|
@ -1855,17 +1857,18 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_link_sta *link_sta,
|
|||
{
|
||||
struct ieee80211_sta_he_cap *pc = &link_sta->he_cap;
|
||||
struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
|
||||
const struct ieee80211_sta_he_cap *vc =
|
||||
mt76_connac_get_he_phy_cap(phy->mt76, vif);
|
||||
const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
|
||||
u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
|
||||
u8 nss_mcs = mt7996_mcu_get_sta_nss(mcs_map);
|
||||
const struct ieee80211_he_cap_elem *ve;
|
||||
const struct ieee80211_sta_he_cap *vc;
|
||||
u8 snd_dim, sts;
|
||||
|
||||
vc = mt76_connac_get_he_phy_cap(phy->mt76, vif);
|
||||
if (!vc)
|
||||
return;
|
||||
|
||||
bf->tx_mode = MT_PHY_TYPE_HE_SU;
|
||||
ve = &vc->he_cap_elem;
|
||||
|
||||
mt7996_mcu_sta_sounding_rate(bf, phy);
|
||||
|
||||
|
|
@ -1921,14 +1924,18 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_link_sta *link_sta,
|
|||
struct ieee80211_sta_eht_cap *pc = &link_sta->eht_cap;
|
||||
struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
|
||||
struct ieee80211_eht_mcs_nss_supp *eht_nss = &pc->eht_mcs_nss_supp;
|
||||
const struct ieee80211_sta_eht_cap *vc =
|
||||
mt76_connac_get_eht_phy_cap(phy->mt76, vif);
|
||||
const struct ieee80211_eht_cap_elem_fixed *ve = &vc->eht_cap_elem;
|
||||
u8 nss_mcs = u8_get_bits(eht_nss->bw._80.rx_tx_mcs9_max_nss,
|
||||
IEEE80211_EHT_MCS_NSS_RX) - 1;
|
||||
const struct ieee80211_eht_cap_elem_fixed *ve;
|
||||
const struct ieee80211_sta_eht_cap *vc;
|
||||
u8 snd_dim, sts;
|
||||
|
||||
vc = mt76_connac_get_eht_phy_cap(phy->mt76, vif);
|
||||
if (!vc)
|
||||
return;
|
||||
|
||||
bf->tx_mode = MT_PHY_TYPE_EHT_MU;
|
||||
ve = &vc->eht_cap_elem;
|
||||
|
||||
mt7996_mcu_sta_sounding_rate(bf, phy);
|
||||
|
||||
|
|
|
|||
|
|
@ -600,6 +600,11 @@ static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
|
|||
u16 ies_len;
|
||||
struct wilc_assoc_resp *res = (struct wilc_assoc_resp *)buffer;
|
||||
|
||||
if (buffer_len < sizeof(*res)) {
|
||||
ret_conn_info->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret_conn_info->status = le16_to_cpu(res->status_code);
|
||||
if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {
|
||||
ies = &buffer[sizeof(*res)];
|
||||
|
|
|
|||
|
|
@ -870,9 +870,9 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
|
|||
[HWSIM_ATTR_FLAGS] = { .type = NLA_U32 },
|
||||
[HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 },
|
||||
[HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 },
|
||||
[HWSIM_ATTR_TX_INFO] = { .type = NLA_BINARY,
|
||||
.len = IEEE80211_TX_MAX_RATES *
|
||||
sizeof(struct hwsim_tx_rate)},
|
||||
[HWSIM_ATTR_TX_INFO] =
|
||||
NLA_POLICY_EXACT_LEN(IEEE80211_TX_MAX_RATES *
|
||||
sizeof(struct hwsim_tx_rate)),
|
||||
[HWSIM_ATTR_COOKIE] = { .type = NLA_U64 },
|
||||
[HWSIM_ATTR_CHANNELS] = { .type = NLA_U32 },
|
||||
[HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 },
|
||||
|
|
|
|||
|
|
@ -2611,6 +2611,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
|||
memcpy(&sta->deflink.pub->supp_rates,
|
||||
&nmi_sta->deflink.pub->supp_rates,
|
||||
sizeof(sta->deflink.pub->supp_rates));
|
||||
|
||||
sta->deflink.pub->agg = nmi_sta->deflink.pub->agg;
|
||||
__ieee80211_sta_recalc_aggregates(sta, 0);
|
||||
}
|
||||
|
||||
/* set the STA state after all sta info from usermode has been set */
|
||||
|
|
|
|||
|
|
@ -399,6 +399,10 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(sdata->link, old_data, sizeof(old_data));
|
||||
memcpy(sdata->vif.link_conf, old, sizeof(old));
|
||||
ieee80211_set_vif_links_bitmaps(sdata, old_links, dormant_links);
|
||||
for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
ieee80211_link_debugfs_remove(&links[link_id]->data);
|
||||
ieee80211_link_stop(&links[link_id]->data);
|
||||
}
|
||||
/* and free (only) the newly allocated links */
|
||||
memset(to_free, 0, sizeof(links));
|
||||
goto free;
|
||||
|
|
|
|||
|
|
@ -1717,6 +1717,8 @@ static void sta_ps_start(struct sta_info *sta)
|
|||
else
|
||||
clear_bit(tid, &sta->txq_buffered_tids);
|
||||
}
|
||||
|
||||
sta_info_recalc_tim(sta);
|
||||
}
|
||||
|
||||
static void sta_ps_end(struct sta_info *sta)
|
||||
|
|
|
|||
|
|
@ -263,8 +263,9 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
|
|||
"FTM: nominal time is required for PD NTB ranging");
|
||||
return -EINVAL;
|
||||
}
|
||||
out->ftm.nominal_time =
|
||||
nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NOMINAL_TIME]);
|
||||
if (tb[NL80211_PMSR_FTM_REQ_ATTR_NOMINAL_TIME])
|
||||
out->ftm.nominal_time =
|
||||
nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NOMINAL_TIME]);
|
||||
|
||||
if (tb[NL80211_PMSR_FTM_REQ_ATTR_MIN_TIME_BETWEEN_MEASUREMENTS])
|
||||
out->ftm.min_time_between_measurements =
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user