ath.git patches for v6.17

All ath drivers:
 Add "#include <linux/export.h>" to all files that use EXPORT_SYMBOL()
 to fix a newly introduced 'make W=1' check. Note that check has
 subsequently been changed to only test when W=2, but keep the fixes to
 suppress the warning for 'make W=2'.
 
 ath12k:
 Properly handle scan requests on multi-radio wiphy devices.
 Perform the usual set of bug fixes and cleanups.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQ/mtSHzPUi16IfDEksFbugiYzLewUCaFq4qwAKCRAsFbugiYzL
 e9nKAQC0wQ9QR53BFLGVu3TpR2hbaVaJmYlxCtf+DbrEUbOe1gEAgp2Cz0NdjUaQ
 IABFyUquZS/ZAkqytpjXMvoilyDawAg=
 =bBFE
 -----END PGP SIGNATURE-----

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

Jeff Johnson says:
==================
ath.git patches for v6.17

All ath drivers:
Add "#include <linux/export.h>" to all files that use EXPORT_SYMBOL()
to fix a newly introduced 'make W=1' check. Note that check has
subsequently been changed to only test when W=2, but keep the fixes to
suppress the warning for 'make W=2'.

ath12k:
Properly handle scan requests on multi-radio wiphy devices.
Perform the usual set of bug fixes and cleanups.
==================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2025-06-24 17:39:15 +02:00
commit 7322a7d80c
43 changed files with 558 additions and 125 deletions

View File

@ -3,8 +3,10 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include "bmi.h"
#include "hif.h"
#include "debug.h"

View File

@ -4,8 +4,10 @@
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include "hif.h"
#include "ce.h"
#include "debug.h"

View File

@ -4,8 +4,10 @@
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/of.h>

View File

@ -3,11 +3,13 @@
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "coredump.h"
#include <linux/devcoredump.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/utsname.h>

View File

@ -4,10 +4,12 @@
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/export.h>
#include <linux/vmalloc.h>
#include <linux/crc32.h>
#include <linux/firmware.h>

View File

@ -3,8 +3,11 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include "core.h"
#include "hif.h"
#include "debug.h"

View File

@ -4,8 +4,11 @@
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include "core.h"
#include "htc.h"
#include "htt.h"

View File

@ -3,8 +3,10 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include <linux/etherdevice.h>
#include "htt.h"
#include "mac.h"

View File

@ -9,6 +9,7 @@
#include "mac.h"
#include <linux/export.h>
#include <net/cfg80211.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>

View File

@ -1,8 +1,10 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2012 Qualcomm Atheros, Inc.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include <linux/module.h>
#define CREATE_TRACE_POINTS

View File

@ -2,8 +2,10 @@
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include "dp_rx.h"
#include "debug.h"
#include "hif.h"

View File

@ -2,8 +2,10 @@
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/remoteproc.h>

View File

@ -2,8 +2,10 @@
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/devcoredump.h>
#include <linux/export.h>
#include "hif.h"
#include "coredump.h"
#include "debug.h"

View File

@ -2,8 +2,10 @@
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include <linux/vmalloc.h>
#include "core.h"
#include "debug.h"

View File

@ -2,8 +2,10 @@
/*
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include <linux/vmalloc.h>
#include "debugfs.h"

View File

@ -2,9 +2,11 @@
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <crypto/hash.h>
#include <linux/export.h>
#include "core.h"
#include "dp_tx.h"
#include "hal_tx.h"

View File

@ -1,8 +1,10 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include "core.h"
#include "debug.h"

View File

@ -2,8 +2,10 @@
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include "hal_tx.h"
#include "debug.h"
#include "hal_desc.h"

View File

@ -2,8 +2,10 @@
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include "core.h"
#include "pcic.h"
#include "debug.h"

View File

@ -2,9 +2,11 @@
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/elf.h>
#include <linux/export.h>
#include "qmi.h"
#include "core.h"

View File

@ -1,8 +1,10 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include <linux/module.h>
#define CREATE_TRACE_POINTS

View File

@ -2,8 +2,10 @@
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/export.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/remoteproc.h>
@ -1409,6 +1411,7 @@ void ath12k_core_halt(struct ath12k *ar)
ath12k_mac_peer_cleanup_all(ar);
cancel_delayed_work_sync(&ar->scan.timeout);
cancel_work_sync(&ar->regd_update_work);
cancel_work_sync(&ar->regd_channel_update_work);
cancel_work_sync(&ab->rfkill_work);
cancel_work_sync(&ab->update_11d_work);
@ -1472,6 +1475,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
complete(&ar->vdev_setup_done);
complete(&ar->vdev_delete_done);
complete(&ar->bss_survey_done);
complete(&ar->regd_update_completed);
wake_up(&ar->dp.tx_empty_waitq);
idr_for_each(&ar->txmgmt_idr,
@ -1511,6 +1515,9 @@ static void ath12k_update_11d(struct work_struct *work)
ar = pdev->ar;
memcpy(&ar->alpha2, &arg.alpha2, 2);
reinit_completion(&ar->regd_update_completed);
ret = ath12k_wmi_send_set_current_country_cmd(ar, &arg);
if (ret)
ath12k_warn(ar->ab,

View File

@ -345,6 +345,10 @@ struct ath12k_link_vif {
bool is_sta_assoc_link;
struct ath12k_reg_tpc_power_info reg_tpc_info;
bool group_key_valid;
struct wmi_vdev_install_key_arg group_key;
bool pairwise_key_done;
};
struct ath12k_vif {
@ -380,9 +384,7 @@ struct ath12k_vif {
struct ath12k_link_vif __rcu *link[ATH12K_NUM_MAX_LINKS];
struct ath12k_vif_cache *cache[IEEE80211_MLD_MAX_NUM_LINKS];
/* indicates bitmap of link vif created in FW */
u16 links_map;
u8 last_scan_link;
u32 links_map;
/* Must be last - ends in a flexible-array member.
*
* FIXME: Driver should not copy struct ieee80211_chanctx_conf,
@ -719,7 +721,7 @@ struct ath12k {
/* protects the radio specific data like debug stats, ppdu_stats_info stats,
* vdev_stop_status info, scan data, ath12k_sta info, ath12k_link_vif info,
* channel context data, survey info, test mode data.
* channel context data, survey info, test mode data, regd_channel_update_queue.
*/
spinlock_t data_lock;
@ -778,6 +780,8 @@ struct ath12k {
struct completion bss_survey_done;
struct work_struct regd_update_work;
struct work_struct regd_channel_update_work;
struct list_head regd_channel_update_queue;
struct wiphy_work wmi_mgmt_tx_work;
struct sk_buff_head wmi_mgmt_tx_queue;
@ -811,6 +815,7 @@ struct ath12k {
enum ath12k_11d_state state_11d;
u8 alpha2[REG_ALPHA2_LEN];
bool regdom_set_by_user;
struct completion regd_update_completed;
struct completion fw_stats_complete;
struct completion fw_stats_done;

View File

@ -84,6 +84,7 @@ int ath12k_dp_peer_setup(struct ath12k *ar, int vdev_id, const u8 *addr)
ret = ath12k_dp_rx_peer_frag_setup(ar, addr, vdev_id);
if (ret) {
ath12k_warn(ab, "failed to setup rx defrag context\n");
tid--;
goto peer_clean;
}

View File

@ -3761,7 +3761,6 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int *budget,
ath12k_hal_srng_access_begin(ab, srng);
while (likely(*budget)) {
*budget -= 1;
mon_dst_desc = ath12k_hal_srng_dst_peek(ab, srng);
if (unlikely(!mon_dst_desc))
break;

View File

@ -2533,31 +2533,15 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
struct ath12k_dp_rx_info *rx_info)
{
struct ath12k_base *ab = ar->ab;
static const struct ieee80211_radiotap_he known = {
.data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN |
IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN),
.data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN),
};
struct ieee80211_radiotap_he *he;
struct ieee80211_rx_status *rx_status;
struct ieee80211_sta *pubsta;
struct ath12k_peer *peer;
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
struct ieee80211_rx_status *status = rx_info->rx_status;
u8 decap = DP_RX_DECAP_TYPE_RAW;
u8 decap = rx_info->decap_type;
bool is_mcbc = rxcb->is_mcbc;
bool is_eapol = rxcb->is_eapol;
if (status->encoding == RX_ENC_HE && !(status->flag & RX_FLAG_RADIOTAP_HE) &&
!(status->flag & RX_FLAG_SKIP_MONITOR)) {
he = skb_push(msdu, sizeof(known));
memcpy(he, &known, sizeof(known));
status->flag |= RX_FLAG_RADIOTAP_HE;
}
if (!(status->flag & RX_FLAG_ONLY_MONITOR))
decap = rx_info->decap_type;
spin_lock_bh(&ab->base_lock);
peer = ath12k_dp_rx_h_find_peer(ab, msdu, rx_info);

View File

@ -13,10 +13,9 @@
#include "mac.h"
static enum hal_tcl_encap_type
ath12k_dp_tx_get_encap_type(struct ath12k_link_vif *arvif, struct sk_buff *skb)
ath12k_dp_tx_get_encap_type(struct ath12k_base *ab, struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ath12k_base *ab = arvif->ar->ab;
if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
return HAL_TCL_ENCAP_TYPE_RAW;
@ -305,7 +304,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
u32_encode_bits(mcbc_gsn, HTT_TCL_META_DATA_GLOBAL_SEQ_NUM);
}
ti.encap_type = ath12k_dp_tx_get_encap_type(arvif, skb);
ti.encap_type = ath12k_dp_tx_get_encap_type(ab, skb);
ti.addr_search_flags = arvif->hal_addr_search_flags;
ti.search_type = arvif->search_type;
ti.type = HAL_TCL_DESC_TYPE_BUFFER;

View File

@ -1478,7 +1478,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.download_calib = true,
.supports_suspend = false,
.tcl_ring_retry = true,
.reoq_lut_support = false,
.reoq_lut_support = true,
.supports_shadow_regs = false,
.num_tcl_banks = 48,

View File

@ -693,6 +693,9 @@ static void ath12k_get_arvif_iter(void *data, u8 *mac,
if (WARN_ON(!arvif))
continue;
if (!arvif->is_created)
continue;
if (arvif->vdev_id == arvif_iter->vdev_id &&
arvif->ar == arvif_iter->ar) {
arvif_iter->arvif = arvif;
@ -1755,7 +1758,7 @@ static void ath12k_mac_handle_beacon_iter(void *data, u8 *mac,
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ath12k_link_vif *arvif = &ahvif->deflink;
if (vif->type != NL80211_IFTYPE_STATION)
if (vif->type != NL80211_IFTYPE_STATION || !arvif->is_created)
return;
if (!ether_addr_equal(mgmt->bssid, vif->bss_conf.bssid))
@ -1778,16 +1781,16 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
u32 *vdev_id = data;
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ath12k_link_vif *arvif = &ahvif->deflink;
struct ath12k *ar = arvif->ar;
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
struct ieee80211_hw *hw;
if (arvif->vdev_id != *vdev_id)
if (!arvif->is_created || arvif->vdev_id != *vdev_id)
return;
if (!arvif->is_up)
return;
ieee80211_beacon_loss(vif);
hw = ath12k_ar_to_hw(arvif->ar);
/* Firmware doesn't report beacon loss events repeatedly. If AP probe
* (done by mac80211) succeeds but beacons do not resume then it
@ -3496,7 +3499,7 @@ static struct ath12k_link_vif *ath12k_mac_assign_link_vif(struct ath12k_hw *ah,
/* If this is the first link arvif being created for an ML VIF
* use the preallocated deflink memory except for scan arvifs
*/
if (!ahvif->links_map && link_id != ATH12K_DEFAULT_SCAN_LINK) {
if (!ahvif->links_map && link_id < ATH12K_FIRST_SCAN_LINK) {
arvif = &ahvif->deflink;
if (vif->type == NL80211_IFTYPE_STATION)
@ -4149,8 +4152,9 @@ ath12k_mac_select_scan_device(struct ieee80211_hw *hw,
band = NL80211_BAND_6GHZ;
for_each_ar(ah, ar, i) {
/* TODO 5 GHz low high split changes */
if (ar->mac.sbands[band].channels)
if (ar->mac.sbands[band].channels &&
center_freq >= KHZ_TO_MHZ(ar->freq_range.start_freq) &&
center_freq <= KHZ_TO_MHZ(ar->freq_range.end_freq))
return ar;
}
@ -4274,6 +4278,23 @@ static void ath12k_scan_timeout_work(struct work_struct *work)
wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
}
static void ath12k_mac_scan_send_complete(struct ath12k *ar,
struct cfg80211_scan_info *info)
{
struct ath12k_hw *ah = ar->ah;
struct ath12k *partner_ar;
int i;
lockdep_assert_wiphy(ah->hw->wiphy);
for_each_ar(ah, partner_ar, i)
if (partner_ar != ar &&
partner_ar->scan.state == ATH12K_SCAN_RUNNING)
return;
ieee80211_scan_completed(ah->hw, info);
}
static void ath12k_scan_vdev_clean_work(struct wiphy *wiphy, struct wiphy_work *work)
{
struct ath12k *ar = container_of(work, struct ath12k,
@ -4312,7 +4333,7 @@ static void ath12k_scan_vdev_clean_work(struct wiphy *wiphy, struct wiphy_work *
ATH12K_SCAN_STARTING)),
};
ieee80211_scan_completed(ar->ah->hw, &info);
ath12k_mac_scan_send_complete(ar, &info);
}
ar->scan.state = ATH12K_SCAN_IDLE;
@ -4488,11 +4509,12 @@ ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar)
struct ath12k_link_vif *arvif;
struct ath12k_hw *ah = ahvif->ah;
unsigned long links = ahvif->links_map;
unsigned long scan_links_map;
u8 link_id;
lockdep_assert_wiphy(ah->hw->wiphy);
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
for_each_set_bit(link_id, &links, ATH12K_NUM_MAX_LINKS) {
arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]);
if (!arvif || !arvif->is_created)
@ -4502,18 +4524,30 @@ ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar)
return link_id;
}
/* input ar is not assigned to any of the links of ML VIF, use scan
* link (15) for scan vdev creation.
/* input ar is not assigned to any of the links of ML VIF, use next
* available scan link for scan vdev creation. There are cases where
* single scan req needs to be split in driver and initiate separate
* scan requests to firmware based on device.
*/
return ATH12K_DEFAULT_SCAN_LINK;
/* Unset all non-scan links (0-14) of scan_links_map so that ffs() will
* choose an available link among scan links (i.e link id >= 15)
*/
scan_links_map = ~ahvif->links_map & ATH12K_SCAN_LINKS_MASK;
if (scan_links_map)
return __ffs(scan_links_map);
return ATH12K_FIRST_SCAN_LINK;
}
static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req)
static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req,
int n_channels,
struct ieee80211_channel **chan_list,
struct ath12k *ar)
{
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar;
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ath12k_link_vif *arvif;
struct cfg80211_scan_request *req = &hw_req->req;
@ -4527,18 +4561,18 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
arvif = &ahvif->deflink;
/* Since the targeted scan device could depend on the frequency
* requested in the hw_req, select the corresponding radio
*/
ar = ath12k_mac_select_scan_device(hw, vif, hw_req->req.channels[0]->center_freq);
if (!ar)
return -EINVAL;
/* check if any of the links of ML VIF is already started on
* radio(ar) corresponding to given scan frequency and use it,
* if not use scan link (link 15) for scan purpose.
* if not use scan link (link id >= 15) for scan purpose.
*/
link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar);
/* All scan links are occupied. ideally this shouldn't happen as
* mac80211 won't schedule scan for same band until ongoing scan is
* completed, don't try to exceed max links just in case if it happens.
*/
if (link_id >= ATH12K_NUM_MAX_LINKS)
return -EBUSY;
arvif = ath12k_mac_assign_link_vif(ah, vif, link_id);
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac link ID %d selected for scan",
@ -4629,8 +4663,8 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
arg->scan_f_passive = 1;
}
if (req->n_channels) {
arg->num_chan = req->n_channels;
if (n_channels) {
arg->num_chan = n_channels;
arg->chan_list = kcalloc(arg->num_chan, sizeof(*arg->chan_list),
GFP_KERNEL);
if (!arg->chan_list) {
@ -4639,7 +4673,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
}
for (i = 0; i < arg->num_chan; i++)
arg->chan_list[i] = req->channels[i]->center_freq;
arg->chan_list[i] = chan_list[i]->center_freq;
}
ret = ath12k_start_scan(ar, arg);
@ -4658,13 +4692,6 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac scan started");
/* As per cfg80211/mac80211 scan design, it allows only one
* scan at a time. Hence last_scan link id is used for
* tracking the link id on which the scan is been done on
* this vif.
*/
ahvif->last_scan_link = arvif->link_id;
/* Add a margin to account for event/command processing */
ieee80211_queue_delayed_work(ath12k_ar_to_hw(ar), &ar->scan.timeout,
msecs_to_jiffies(arg->max_scan_time +
@ -4685,25 +4712,108 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
return ret;
}
static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req)
{
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ieee80211_channel **chan_list, *chan;
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
unsigned long links_map, link_id;
struct ath12k_link_vif *arvif;
struct ath12k *ar, *scan_ar;
int i, j, ret = 0;
lockdep_assert_wiphy(hw->wiphy);
chan_list = kcalloc(hw_req->req.n_channels, sizeof(*chan_list), GFP_KERNEL);
if (!chan_list)
return -ENOMEM;
/* There could be channels that belong to multiple underlying radio
* in same scan request as mac80211 sees it as single band. In that
* case split the hw_req based on frequency range and schedule scans to
* corresponding radio.
*/
for_each_ar(ah, ar, i) {
int n_chans = 0;
for (j = 0; j < hw_req->req.n_channels; j++) {
chan = hw_req->req.channels[j];
scan_ar = ath12k_mac_select_scan_device(hw, vif,
chan->center_freq);
if (!scan_ar) {
ath12k_hw_warn(ah, "unable to select scan device for freq %d\n",
chan->center_freq);
ret = -EINVAL;
goto abort;
}
if (ar != scan_ar)
continue;
chan_list[n_chans++] = chan;
}
if (n_chans) {
ret = ath12k_mac_initiate_hw_scan(hw, vif, hw_req, n_chans,
chan_list, ar);
if (ret)
goto abort;
}
}
abort:
/* If any of the parallel scans initiated fails, abort all and
* remove the scan interfaces created. Return complete scan
* failure as mac80211 assumes this as single scan request.
*/
if (ret) {
ath12k_hw_warn(ah, "Scan failed %d , cleanup all scan vdevs\n", ret);
links_map = ahvif->links_map;
for_each_set_bit(link_id, &links_map, ATH12K_NUM_MAX_LINKS) {
arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
if (!arvif)
continue;
ar = arvif->ar;
if (ar->scan.arvif == arvif) {
wiphy_work_cancel(hw->wiphy, &ar->scan.vdev_clean_wk);
spin_lock_bh(&ar->data_lock);
ar->scan.arvif = NULL;
ar->scan.state = ATH12K_SCAN_IDLE;
ar->scan_channel = NULL;
ar->scan.roc_freq = 0;
spin_unlock_bh(&ar->data_lock);
}
if (link_id >= ATH12K_FIRST_SCAN_LINK) {
ath12k_mac_remove_link_interface(hw, arvif);
ath12k_mac_unassign_link_vif(arvif);
}
}
}
kfree(chan_list);
return ret;
}
static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
u16 link_id = ahvif->last_scan_link;
unsigned long link_id, links_map = ahvif->links_map;
struct ath12k_link_vif *arvif;
struct ath12k *ar;
lockdep_assert_wiphy(hw->wiphy);
arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
if (!arvif || arvif->is_started)
return;
for_each_set_bit(link_id, &links_map, ATH12K_NUM_MAX_LINKS) {
arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
if (!arvif || arvif->is_started)
continue;
ar = arvif->ar;
ar = arvif->ar;
ath12k_scan_abort(ar);
ath12k_scan_abort(ar);
cancel_delayed_work_sync(&ar->scan.timeout);
cancel_delayed_work_sync(&ar->scan.timeout);
}
}
static int ath12k_install_key(struct ath12k_link_vif *arvif,
@ -4719,14 +4829,13 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif,
.key_len = key->keylen,
.key_data = key->key,
.key_flags = flags,
.ieee80211_key_cipher = key->cipher,
.macaddr = macaddr,
};
struct ath12k_vif *ahvif = arvif->ahvif;
lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
reinit_completion(&ar->install_key_done);
if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags))
return 0;
@ -4735,7 +4844,7 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif,
/* arg.key_cipher = WMI_CIPHER_NONE; */
arg.key_len = 0;
arg.key_data = NULL;
goto install;
goto check_order;
}
switch (key->cipher) {
@ -4763,19 +4872,82 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif,
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV |
IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
install:
ret = ath12k_wmi_vdev_install_key(arvif->ar, &arg);
check_order:
if (ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
arg.key_flags == WMI_KEY_GROUP) {
if (cmd == SET_KEY) {
if (arvif->pairwise_key_done) {
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"vdev %u pairwise key done, go install group key\n",
arg.vdev_id);
goto install;
} else {
/* WCN7850 firmware requires pairwise key to be installed
* before group key. In case group key comes first, cache
* it and return. Will revisit it once pairwise key gets
* installed.
*/
arvif->group_key = arg;
arvif->group_key_valid = true;
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"vdev %u group key before pairwise key, cache and skip\n",
arg.vdev_id);
ret = 0;
goto out;
}
} else {
arvif->group_key_valid = false;
}
}
install:
reinit_completion(&ar->install_key_done);
ret = ath12k_wmi_vdev_install_key(arvif->ar, &arg);
if (ret)
return ret;
if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ))
return -ETIMEDOUT;
if (ether_addr_equal(macaddr, arvif->bssid))
ahvif->key_cipher = key->cipher;
if (ether_addr_equal(arg.macaddr, arvif->bssid))
ahvif->key_cipher = arg.ieee80211_key_cipher;
return ar->install_key_status ? -EINVAL : 0;
if (ar->install_key_status) {
ret = -EINVAL;
goto out;
}
if (ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
arg.key_flags == WMI_KEY_PAIRWISE) {
if (cmd == SET_KEY) {
arvif->pairwise_key_done = true;
if (arvif->group_key_valid) {
/* Install cached GTK */
arvif->group_key_valid = false;
arg = arvif->group_key;
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"vdev %u pairwise key done, group key ready, go install\n",
arg.vdev_id);
goto install;
}
} else {
arvif->pairwise_key_done = false;
}
}
out:
if (ret) {
/* In case of failure userspace may not do DISABLE_KEY
* but triggers re-connection directly, so manually reset
* status here.
*/
arvif->group_key_valid = false;
arvif->pairwise_key_done = false;
}
return ret;
}
static int ath12k_clear_peer_keys(struct ath12k_link_vif *arvif,
@ -4869,9 +5041,9 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
}
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
flags |= WMI_KEY_PAIRWISE;
flags = WMI_KEY_PAIRWISE;
else
flags |= WMI_KEY_GROUP;
flags = WMI_KEY_GROUP;
ret = ath12k_install_key(arvif, key, cmd, peer_addr, flags);
if (ret) {
@ -8114,7 +8286,17 @@ static int ath12k_mac_start(struct ath12k *ar)
/* TODO: Do we need to enable ANI? */
ath12k_reg_update_chan_list(ar, false);
ret = ath12k_reg_update_chan_list(ar, false);
/* The ar state alone can be turned off for non supported country
* without returning the error value. As we need to update the channel
* for the next ar.
*/
if (ret) {
if (ret == -EINVAL)
ret = 0;
goto err;
}
ar->num_started_vdevs = 0;
ar->num_created_vdevs = 0;
@ -8286,6 +8468,7 @@ static void ath12k_mac_stop(struct ath12k *ar)
{
struct ath12k_hw *ah = ar->ah;
struct htt_ppdu_stats_info *ppdu_stats, *tmp;
struct ath12k_wmi_scan_chan_list_arg *arg;
int ret;
lockdep_assert_held(&ah->hw_mutex);
@ -8300,6 +8483,7 @@ static void ath12k_mac_stop(struct ath12k *ar)
cancel_delayed_work_sync(&ar->scan.timeout);
wiphy_work_cancel(ath12k_ar_to_hw(ar)->wiphy, &ar->scan.vdev_clean_wk);
cancel_work_sync(&ar->regd_channel_update_work);
cancel_work_sync(&ar->regd_update_work);
cancel_work_sync(&ar->ab->rfkill_work);
cancel_work_sync(&ar->ab->update_11d_work);
@ -8307,10 +8491,18 @@ static void ath12k_mac_stop(struct ath12k *ar)
complete(&ar->completed_11d_scan);
spin_lock_bh(&ar->data_lock);
list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
list_del(&ppdu_stats->list);
kfree(ppdu_stats);
}
while ((arg = list_first_entry_or_null(&ar->regd_channel_update_queue,
struct ath12k_wmi_scan_chan_list_arg,
list))) {
list_del(&arg->list);
kfree(arg);
}
spin_unlock_bh(&ar->data_lock);
rcu_assign_pointer(ar->ab->pdevs_active[ar->pdev_idx], NULL);
@ -9055,7 +9247,8 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
struct ath12k_hw *ah = hw->priv;
struct ath12k *ar;
struct ath12k_base *ab;
u8 link_id = arvif->link_id;
u8 link_id = arvif->link_id, scan_link_id;
unsigned long scan_link_map;
int ret;
lockdep_assert_wiphy(hw->wiphy);
@ -9074,12 +9267,16 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
* and now we want to create for actual usage.
*/
if (ieee80211_vif_is_mld(vif)) {
scan_arvif = wiphy_dereference(hw->wiphy,
ahvif->link[ATH12K_DEFAULT_SCAN_LINK]);
if (scan_arvif && scan_arvif->ar == ar) {
ar->scan.arvif = NULL;
ath12k_mac_remove_link_interface(hw, scan_arvif);
ath12k_mac_unassign_link_vif(scan_arvif);
scan_link_map = ahvif->links_map & ATH12K_SCAN_LINKS_MASK;
for_each_set_bit(scan_link_id, &scan_link_map, ATH12K_NUM_MAX_LINKS) {
scan_arvif = wiphy_dereference(hw->wiphy,
ahvif->link[scan_link_id]);
if (scan_arvif && scan_arvif->ar == ar) {
ar->scan.arvif = NULL;
ath12k_mac_remove_link_interface(hw, scan_arvif);
ath12k_mac_unassign_link_vif(scan_arvif);
break;
}
}
}
@ -9314,7 +9511,7 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
.aborted = true,
};
ieee80211_scan_completed(ar->ah->hw, &info);
ath12k_mac_scan_send_complete(ar, &info);
}
ar->scan.state = ATH12K_SCAN_IDLE;
@ -9820,7 +10017,7 @@ ath12k_mac_change_chanctx_cnt_iter(void *data, u8 *mac,
if (WARN_ON(!arvif))
continue;
if (arvif->ar != arg->ar)
if (!arvif->is_created || arvif->ar != arg->ar)
continue;
link_conf = wiphy_dereference(ahvif->ah->hw->wiphy,
@ -9855,7 +10052,7 @@ ath12k_mac_change_chanctx_fill_iter(void *data, u8 *mac,
if (WARN_ON(!arvif))
continue;
if (arvif->ar != arg->ar)
if (!arvif->is_created || arvif->ar != arg->ar)
continue;
link_conf = wiphy_dereference(ahvif->ah->hw->wiphy,
@ -11250,6 +11447,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
struct wmi_set_current_country_arg arg = {};
memcpy(&arg.alpha2, ar->alpha2, 2);
reinit_completion(&ar->regd_update_completed);
ath12k_wmi_send_set_current_country_cmd(ar, &arg);
}
@ -11761,6 +11959,32 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band)
return 0;
}
static int ath12k_mac_update_band(struct ath12k *ar,
struct ieee80211_supported_band *orig_band,
struct ieee80211_supported_band *new_band)
{
int i;
if (!orig_band || !new_band)
return -EINVAL;
if (orig_band->band != new_band->band)
return -EINVAL;
for (i = 0; i < new_band->n_channels; i++) {
if (new_band->channels[i].flags & IEEE80211_CHAN_DISABLED)
continue;
/* An enabled channel in new_band should not be already enabled
* in the orig_band
*/
if (WARN_ON(!(orig_band->channels[i].flags &
IEEE80211_CHAN_DISABLED)))
return -EINVAL;
orig_band->channels[i].flags &= ~IEEE80211_CHAN_DISABLED;
}
return 0;
}
static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
u32 supported_bands,
struct ieee80211_supported_band *bands[])
@ -11771,6 +11995,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
u32 phy_id, freq_low, freq_high;
struct ath12k_hw *ah = ar->ah;
void *channels;
int ret;
BUILD_BUG_ON((ARRAY_SIZE(ath12k_2ghz_channels) +
ARRAY_SIZE(ath12k_5ghz_channels) +
@ -11792,7 +12017,6 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
band->channels = channels;
band->n_bitrates = ath12k_g_rates_size;
band->bitrates = ath12k_g_rates;
bands[NL80211_BAND_2GHZ] = band;
if (ab->hw_params->single_pdev_only) {
phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2GHZ_CAP);
@ -11809,6 +12033,22 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
reg_cap->high_2ghz_chan);
ath12k_mac_update_freq_range(ar, freq_low, freq_high);
if (!bands[NL80211_BAND_2GHZ]) {
bands[NL80211_BAND_2GHZ] = band;
} else {
/* Split mac in same band under same wiphy */
ret = ath12k_mac_update_band(ar, bands[NL80211_BAND_2GHZ], band);
if (ret) {
kfree(channels);
band->channels = NULL;
return ret;
}
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac pdev %u identified as 2 GHz split mac with start freq %d end freq %d",
ar->pdev->pdev_id,
KHZ_TO_MHZ(ar->freq_range.start_freq),
KHZ_TO_MHZ(ar->freq_range.end_freq));
}
}
if (supported_bands & WMI_HOST_WLAN_5GHZ_CAP) {
@ -11827,7 +12067,6 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
band->channels = channels;
band->n_bitrates = ath12k_a_rates_size;
band->bitrates = ath12k_a_rates;
bands[NL80211_BAND_6GHZ] = band;
freq_low = max(reg_cap->low_5ghz_chan,
ab->reg_freq_6ghz.start_freq);
@ -11840,6 +12079,26 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
ath12k_mac_update_freq_range(ar, freq_low, freq_high);
ah->use_6ghz_regd = true;
if (!bands[NL80211_BAND_6GHZ]) {
bands[NL80211_BAND_6GHZ] = band;
} else {
/* Split mac in same band under same wiphy */
ret = ath12k_mac_update_band(ar,
bands[NL80211_BAND_6GHZ],
band);
if (ret) {
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
kfree(channels);
band->channels = NULL;
return ret;
}
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac pdev %u identified as 6 GHz split mac with start freq %d end freq %d",
ar->pdev->pdev_id,
KHZ_TO_MHZ(ar->freq_range.start_freq),
KHZ_TO_MHZ(ar->freq_range.end_freq));
}
}
if (reg_cap->low_5ghz_chan < ATH12K_MIN_6GHZ_FREQ) {
@ -11858,7 +12117,6 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
band->channels = channels;
band->n_bitrates = ath12k_a_rates_size;
band->bitrates = ath12k_a_rates;
bands[NL80211_BAND_5GHZ] = band;
if (ab->hw_params->single_pdev_only) {
phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5GHZ_CAP);
@ -11875,6 +12133,28 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
reg_cap->high_5ghz_chan);
ath12k_mac_update_freq_range(ar, freq_low, freq_high);
if (!bands[NL80211_BAND_5GHZ]) {
bands[NL80211_BAND_5GHZ] = band;
} else {
/* Split mac in same band under same wiphy */
ret = ath12k_mac_update_band(ar,
bands[NL80211_BAND_5GHZ],
band);
if (ret) {
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
kfree(channels);
band->channels = NULL;
return ret;
}
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac pdev %u identified as 5 GHz split mac with start freq %d end freq %d",
ar->pdev->pdev_id,
KHZ_TO_MHZ(ar->freq_range.start_freq),
KHZ_TO_MHZ(ar->freq_range.end_freq));
}
}
}
@ -12208,6 +12488,7 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah)
int i;
for_each_ar(ah, ar, i) {
cancel_work_sync(&ar->regd_channel_update_work);
cancel_work_sync(&ar->regd_update_work);
ath12k_debugfs_unregister(ar);
ath12k_fw_stats_reset(ar);
@ -12466,6 +12747,16 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
goto err_cleanup_if_combs;
}
/* Boot-time regulatory updates have already been processed.
* Mark them as complete now, because after registration,
* cfg80211 will notify us again if there are any pending hints.
* We need to wait for those hints to be processed, so it's
* important to mark the boot-time updates as complete before
* proceeding with registration.
*/
for_each_ar(ah, ar, i)
complete(&ar->regd_update_completed);
ret = ieee80211_register_hw(hw);
if (ret) {
ath12k_err(ab, "ieee80211 registration failed: %d\n", ret);
@ -12493,6 +12784,9 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
memcpy(&current_cc.alpha2, ab->new_alpha2, 2);
memcpy(&ar->alpha2, ab->new_alpha2, 2);
reinit_completion(&ar->regd_update_completed);
ret = ath12k_wmi_send_set_current_country_cmd(ar, &current_cc);
if (ret)
ath12k_warn(ar->ab,
@ -12565,9 +12859,12 @@ static void ath12k_mac_setup(struct ath12k *ar)
init_completion(&ar->scan.on_channel);
init_completion(&ar->mlo_setup_done);
init_completion(&ar->completed_11d_scan);
init_completion(&ar->regd_update_completed);
INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work);
wiphy_work_init(&ar->scan.vdev_clean_wk, ath12k_scan_vdev_clean_work);
INIT_WORK(&ar->regd_channel_update_work, ath12k_regd_update_chan_list_work);
INIT_LIST_HEAD(&ar->regd_channel_update_queue);
INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work);
wiphy_work_init(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work);

View File

@ -51,8 +51,11 @@ struct ath12k_generic_iter {
/* Default link after the IEEE802.11 defined Max link id limit
* for driver usage purpose.
*/
#define ATH12K_DEFAULT_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS
#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + 1)
#define ATH12K_FIRST_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS
#define ATH12K_SCAN_MAX_LINKS ATH12K_GROUP_MAX_RADIO
/* Define 1 scan link for each radio for parallel scan purposes */
#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + ATH12K_SCAN_MAX_LINKS)
#define ATH12K_SCAN_LINKS_MASK GENMASK(ATH12K_NUM_MAX_LINKS, IEEE80211_MLD_MAX_NUM_LINKS)
#define ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE 2

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <net/mac80211.h>
@ -124,7 +125,7 @@ static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
WARN_ON(!rcu_read_lock_any_held());
arvif = &ahvif->deflink;
if (arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id)
if (!arvif->is_created || arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id)
return;
ath12k_p2p_noa_update(arvif, arg->noa);

View File

@ -65,7 +65,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
for_each_ar(ah, ar, i) {
ret = ath12k_reg_update_chan_list(ar, true);
if (ret) {
if (ret && ret != -EINVAL) {
ath12k_warn(ar->ab,
"failed to update chan list for pdev %u, ret %d\n",
i, ret);
@ -102,6 +102,8 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
/* Send the reg change request to all the radios */
for_each_ar(ah, ar, i) {
reinit_completion(&ar->regd_update_completed);
if (ar->ab->hw_params->current_cc_support) {
memcpy(&current_arg.alpha2, request->alpha2, 2);
memcpy(&ar->alpha2, &current_arg.alpha2, 2);
@ -137,32 +139,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
struct ath12k_wmi_channel_arg *ch;
enum nl80211_band band;
int num_channels = 0;
int i, ret, left;
if (wait && ar->state_11d == ATH12K_11D_RUNNING) {
left = wait_for_completion_timeout(&ar->completed_11d_scan,
ATH12K_SCAN_TIMEOUT_HZ);
if (!left) {
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"failed to receive 11d scan complete: timed out\n");
ar->state_11d = ATH12K_11D_IDLE;
}
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"reg 11d scan wait left time %d\n", left);
}
if (wait &&
(ar->scan.state == ATH12K_SCAN_STARTING ||
ar->scan.state == ATH12K_SCAN_RUNNING)) {
left = wait_for_completion_timeout(&ar->scan.completed,
ATH12K_SCAN_TIMEOUT_HZ);
if (!left)
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"failed to receive hw scan complete: timed out\n");
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"reg hw scan wait left time %d\n", left);
}
int i, ret = 0;
if (ar->ah->state == ATH12K_HW_STATE_RESTARTING)
return 0;
@ -176,13 +153,22 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
if (bands[band]->channels[i].flags &
IEEE80211_CHAN_DISABLED)
continue;
/* Skip Channels that are not in current radio's range */
if (bands[band]->channels[i].center_freq <
KHZ_TO_MHZ(ar->freq_range.start_freq) ||
bands[band]->channels[i].center_freq >
KHZ_TO_MHZ(ar->freq_range.end_freq))
continue;
num_channels++;
}
}
if (WARN_ON(!num_channels))
if (!num_channels) {
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"pdev is not supported for this country\n");
return -EINVAL;
}
arg = kzalloc(struct_size(arg, channel, num_channels), GFP_KERNEL);
@ -204,6 +190,13 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
if (channel->flags & IEEE80211_CHAN_DISABLED)
continue;
/* Skip Channels that are not in current radio's range */
if (bands[band]->channels[i].center_freq <
KHZ_TO_MHZ(ar->freq_range.start_freq) ||
bands[band]->channels[i].center_freq >
KHZ_TO_MHZ(ar->freq_range.end_freq))
continue;
/* TODO: Set to true/false based on some condition? */
ch->allow_ht = true;
ch->allow_vht = true;
@ -244,6 +237,16 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
}
}
if (wait) {
spin_lock_bh(&ar->data_lock);
list_add_tail(&arg->list, &ar->regd_channel_update_queue);
spin_unlock_bh(&ar->data_lock);
queue_work(ar->ab->workqueue, &ar->regd_channel_update_work);
return 0;
}
ret = ath12k_wmi_send_scan_chan_list_cmd(ar, arg);
kfree(arg);
@ -272,9 +275,19 @@ int ath12k_regd_update(struct ath12k *ar, bool init)
struct ieee80211_regdomain *regd, *regd_copy = NULL;
int ret, regd_len, pdev_id;
struct ath12k_base *ab;
long time_left;
ab = ar->ab;
time_left = wait_for_completion_timeout(&ar->regd_update_completed,
ATH12K_REG_UPDATE_TIMEOUT_HZ);
if (time_left == 0) {
ath12k_warn(ab, "Timeout while waiting for regulatory update");
/* Even though timeout has occurred, still continue since at least boot
* time data would be there to process
*/
}
supported_bands = ar->pdev->cap.supported_bands;
reg_cap = &ab->hal_reg_cap[ar->pdev_idx];
@ -764,6 +777,54 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
return new_regd;
}
void ath12k_regd_update_chan_list_work(struct work_struct *work)
{
struct ath12k *ar = container_of(work, struct ath12k,
regd_channel_update_work);
struct ath12k_wmi_scan_chan_list_arg *arg;
struct list_head local_update_list;
int left;
INIT_LIST_HEAD(&local_update_list);
spin_lock_bh(&ar->data_lock);
list_splice_tail_init(&ar->regd_channel_update_queue, &local_update_list);
spin_unlock_bh(&ar->data_lock);
while ((arg = list_first_entry_or_null(&local_update_list,
struct ath12k_wmi_scan_chan_list_arg,
list))) {
if (ar->state_11d != ATH12K_11D_IDLE) {
left = wait_for_completion_timeout(&ar->completed_11d_scan,
ATH12K_SCAN_TIMEOUT_HZ);
if (!left) {
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"failed to receive 11d scan complete: timed out\n");
ar->state_11d = ATH12K_11D_IDLE;
}
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"reg 11d scan wait left time %d\n", left);
}
if ((ar->scan.state == ATH12K_SCAN_STARTING ||
ar->scan.state == ATH12K_SCAN_RUNNING)) {
left = wait_for_completion_timeout(&ar->scan.completed,
ATH12K_SCAN_TIMEOUT_HZ);
if (!left)
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"failed to receive hw scan complete: timed out\n");
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"reg hw scan wait left time %d\n", left);
}
ath12k_wmi_send_scan_chan_list_cmd(ar, arg);
list_del(&arg->list);
kfree(arg);
}
}
void ath12k_regd_update_work(struct work_struct *work)
{
struct ath12k *ar = container_of(work, struct ath12k,

View File

@ -13,6 +13,8 @@
struct ath12k_base;
struct ath12k;
#define ATH12K_REG_UPDATE_TIMEOUT_HZ (3 * HZ)
#define ATH12K_2GHZ_MAX_FREQUENCY 2495
#define ATH12K_5GHZ_MAX_FREQUENCY 5920
@ -113,6 +115,7 @@ int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
struct ath12k_reg_info *reg_info,
enum wmi_vdev_type vdev_type,
enum ieee80211_ap_reg_power power_type);
void ath12k_regd_update_chan_list_work(struct work_struct *work);
enum wmi_reg_6g_ap_type
ath12k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type);
enum ath12k_reg_status ath12k_reg_validate_reg_info(struct ath12k_base *ab,

View File

@ -6445,9 +6445,16 @@ static int freq_to_idx(struct ath12k *ar, int freq)
if (!sband)
continue;
for (ch = 0; ch < sband->n_channels; ch++, idx++)
for (ch = 0; ch < sband->n_channels; ch++, idx++) {
if (sband->channels[ch].center_freq <
KHZ_TO_MHZ(ar->freq_range.start_freq) ||
sband->channels[ch].center_freq >
KHZ_TO_MHZ(ar->freq_range.end_freq))
continue;
if (sband->channels[ch].center_freq == freq)
goto exit;
}
}
exit:
@ -6677,7 +6684,8 @@ static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab,
static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
{
struct ath12k_reg_info *reg_info;
u8 pdev_idx;
struct ath12k *ar = NULL;
u8 pdev_idx = 255;
int ret;
reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
@ -6732,7 +6740,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
kfree(reg_info);
if (ret == ATH12K_REG_STATUS_VALID)
return ret;
goto out;
fallback:
/* Fallback to older reg (by sending previous country setting
@ -6746,6 +6754,18 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
WARN_ON(1);
out:
/* In some error cases, even a valid pdev_idx might not be available */
if (pdev_idx != 255)
ar = ab->pdevs[pdev_idx].ar;
/* During the boot-time update, 'ar' might not be allocated,
* so the completion cannot be marked at that point.
* This boot-time update is handled in ath12k_mac_hw_register()
* before registering the hardware.
*/
if (ar)
complete(&ar->regd_update_completed);
return ret;
}

View File

@ -3760,6 +3760,7 @@ struct wmi_vdev_install_key_arg {
u32 key_idx;
u32 key_flags;
u32 key_cipher;
u32 ieee80211_key_cipher;
u32 key_len;
u32 key_txmic_len;
u32 key_rxmic_len;
@ -3948,6 +3949,7 @@ struct wmi_stop_scan_cmd {
} __packed;
struct ath12k_wmi_scan_chan_list_arg {
struct list_head list;
u32 pdev_id;
u16 nallchans;
struct ath12k_wmi_channel_arg channel[];

View File

@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/export.h>
#include "common.h"
#define FUDGE 2

View File

@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/export.h>
#include "common.h"
static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf,

View File

@ -16,6 +16,7 @@
/* We use the hw_value as an index into our private channel structure */
#include <linux/export.h>
#include "common.h"
#define CHAN2G(_freq, _idx) { \

View File

@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/export.h>
#include <linux/relay.h>
#include <linux/random.h>
#include "ath9k.h"

View File

@ -18,6 +18,7 @@
* Module for common driver code between ath9k and ath9k_htc
*/
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/module.h>

View File

@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/export.h>
#include "ath9k.h"
#include "hw.h"
#include "dynack.h"

View File

@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/export.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/module.h>

View File

@ -16,6 +16,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/module.h>