Quite a bit more work, notably:

- mt76: firmware recovery improvements, MLO work
  - iwlwifi: use embedded PNVM in (to be released) FW images
             to fix compatibility issues
  - cfg80211/mac80211: extended regulatory info support (6 GHz)
  - cfg80211: use "faux device" for regulatory
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmhvskoACgkQ10qiO8sP
 aACdthAAiN1wzi9Hrpm2ULqDecEL553ecvfOPAzlYibF4wiulVEdKJd7nFn03udA
 n2ylEgiANbTb+yEgDjj6IwQ9w5XmYvlLSGO/wIag3UUSWUYuCC5if/JEq56lom+B
 IZFMOFXpvO35jSe1h1v0HuuJvbeZv7KDWMJlA4aSXbLx4Y1juAuQid4/YllUkuXt
 QgAziAhF7laNk+8nfQLQ3N1DQytftiDK32vCJ6kJ7ciEhh8qxwT5aVkmE0Q/iOLg
 na4TdrcRRMQ7kkgODqksGz1nVrr/0AHyMVi/rQ/YaL1uY8fBxvbs0nmjU8G78LkO
 gM/401kySEzgLl6x/xrnaVUupbAtsyYrHYH+4q6Z07UPg1OgYY4G71rJIMp/Hq52
 /iQVMOFmbhoIqFLqlvmh92QqZRH+rMf/KnO9Pnh/wVdxGH74ZP0bFYB02bqdaRie
 uxtO9lHfnuMedET85D747rmgAqrBJ2t3BqAD++LNdqF530eOaWiBkAPeAbTRSgis
 d1BJoDtWL3l0tjAA1ivdUw/fPjqWxffpdDTtzSwRjuFUNE5YPpz3VuKNSurSgvMZ
 DCSvxTHf5DLVrg6b4W/YXickD2kArJLpaCwkxzkpyBzh6wyRvxs+b/oZSQRVeKvL
 C36I3WNDqARfC29ilYUiz/G8kJry8IQaSuLaMP6X92Fa6Hdl7Kg=
 =qkYl
 -----END PGP SIGNATURE-----

Merge tag 'wireless-next-2025-07-10' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next

Johannes Berg says:

====================
Quite a bit more work, notably:
 - mt76: firmware recovery improvements, MLO work
 - iwlwifi: use embedded PNVM in (to be released) FW images
            to fix compatibility issues
 - cfg80211/mac80211: extended regulatory info support (6 GHz)
 - cfg80211: use "faux device" for regulatory

* tag 'wireless-next-2025-07-10' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (48 commits)
  wifi: mac80211: don't complete management TX on SAE commit
  wifi: cfg80211/mac80211: implement dot11ExtendedRegInfoSupport
  wifi: mac80211: send extended MLD capa/ops if AP has it
  wifi: mac80211: copy first_part into HW scan
  wifi: cfg80211: add a flag for the first part of a scan
  wifi: mac80211: remove DISALLOW_PUNCTURING_5GHZ code
  wifi: cfg80211: only verify part of Extended MLD Capabilities
  wifi: nl80211: make nl80211_check_scan_flags() type safe
  wifi: cfg80211: hide scan internals
  wifi: mac80211: fix deactivated link CSA
  wifi: mac80211: add mandatory bitrate support for 6 GHz
  wifi: mac80211: remove spurious blank line
  wifi: mac80211: verify state before connection
  wifi: mac80211: avoid weird state in error path
  wifi: iwlwifi: mvm: remove support for iwl_wowlan_info_notif_v4
  wifi: iwlwifi: bump minimum API version in BZ
  wifi: iwlwifi: mvm: remove unneeded argument
  wifi: iwlwifi: mvm: remove MLO GTK rekey code
  wifi: iwlwifi: pcie: rename iwl_pci_gen1_2_probe() argument
  wifi: iwlwifi: match discrete/integrated to fix some names
  ...
====================

Link: https://patch.msgid.link/20250710123113.24878-3-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2025-07-10 17:24:21 -07:00
commit 809f683324
61 changed files with 1221 additions and 1056 deletions

View File

@ -10,10 +10,10 @@
#include "fw/api/txq.h"
/* Highest firmware API version supported */
#define IWL_BZ_UCODE_API_MAX 99
#define IWL_BZ_UCODE_API_MAX 102
/* Lowest firmware API version supported */
#define IWL_BZ_UCODE_API_MIN 94
#define IWL_BZ_UCODE_API_MIN 98
/* Memory offsets and lengths */
#define IWL_BZ_SMEM_OFFSET 0x400000

View File

@ -9,7 +9,7 @@
#include "fw/api/txq.h"
/* Highest firmware API version supported */
#define IWL_DR_UCODE_API_MAX 99
#define IWL_DR_UCODE_API_MAX 102
/* Lowest firmware API version supported */
#define IWL_DR_UCODE_API_MIN 98

View File

@ -10,7 +10,7 @@
#include "fw/api/txq.h"
/* Highest firmware API version supported */
#define IWL_SC_UCODE_API_MAX 99
#define IWL_SC_UCODE_API_MAX 102
/* Lowest firmware API version supported */
#define IWL_SC_UCODE_API_MIN 98

View File

@ -676,10 +676,9 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans)
CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM);
/* See if we got it */
ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM,
CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM,
IWL_EEPROM_SEM_TIMEOUT);
ret = iwl_poll_bits(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM,
IWL_EEPROM_SEM_TIMEOUT);
if (ret >= 0) {
IWL_DEBUG_EEPROM(trans->dev,
"Acquired semaphore after %d tries.\n",
@ -797,10 +796,9 @@ static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr,
iwl_write32(trans, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
ret = iwl_poll_bits(trans, CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
IWL_ERR(trans, "Time out reading OTP[%d]\n", addr);
return ret;
@ -993,10 +991,9 @@ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size)
iwl_write32(trans, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
ret = iwl_poll_bit(trans, CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
ret = iwl_poll_bits(trans, CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
IWL_ERR(trans,
"Time out reading EEPROM[%d]\n", addr);

View File

@ -1467,7 +1467,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
/********************
* 6. Setup services
********************/
if (iwl_setup_deferred_work(priv))
err = iwl_setup_deferred_work(priv);
if (err)
goto out_uninit_drv;
iwl_setup_rx_handlers(priv);

View File

@ -912,7 +912,7 @@ struct iwl_wowlan_mlo_gtk {
} __packed; /* WOWLAN_MLO_GTK_KEY_API_S_VER_1 */
/**
* struct iwl_wowlan_info_notif_v4 - WoWLAN information notification
* struct iwl_wowlan_info_notif_v3 - WoWLAN information notification
* @gtk: GTK data
* @igtk: IGTK data
* @bigtk: BIGTK data
@ -927,12 +927,9 @@ struct iwl_wowlan_mlo_gtk {
* @tid_tear_down: bit mask of tids whose BA sessions were closed
* in suspend state
* @station_id: station id
* @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs
* following this notif, or reserved in version < 4
* @reserved2: reserved
* @mlo_gtks: array of GTKs of size num_mlo_link_keys for version >= 4
*/
struct iwl_wowlan_info_notif_v4 {
struct iwl_wowlan_info_notif_v3 {
struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM];
@ -946,10 +943,8 @@ struct iwl_wowlan_info_notif_v4 {
__le32 received_beacons;
u8 tid_tear_down;
u8 station_id;
u8 num_mlo_link_keys;
u8 reserved2;
struct iwl_wowlan_mlo_gtk mlo_gtks[];
} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3, _VER_4 */
u8 reserved2[2];
} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3 */
/**
* struct iwl_wowlan_info_notif - WoWLAN information notification

View File

@ -104,6 +104,9 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_CURRENT_PC = 68,
IWL_UCODE_TLV_FSEQ_BIN_VERSION = 72,
/* contains sub-sections like PNVM file does (did) */
IWL_UCODE_TLV_PNVM_DATA = 74,
IWL_UCODE_TLV_FW_NUM_STATIONS = IWL_UCODE_TLV_CONST_BASE + 0,
IWL_UCODE_TLV_FW_NUM_LINKS = IWL_UCODE_TLV_CONST_BASE + 1,
IWL_UCODE_TLV_FW_NUM_BEACONS = IWL_UCODE_TLV_CONST_BASE + 2,

View File

@ -195,6 +195,8 @@ struct iwl_dump_exclude {
* @phy_integration_ver_len: length of @phy_integration_ver
* @dump_excl: image dump exclusion areas for RT image
* @dump_excl_wowlan: image dump exclusion areas for WoWLAN image
* @pnvm_data: PNVM data embedded in the .ucode file, if any
* @pnvm_size: size of the embedded PNVM data
*/
struct iwl_fw {
u32 ucode_ver;
@ -227,6 +229,9 @@ struct iwl_fw {
u32 phy_integration_ver_len;
struct iwl_dump_exclude dump_excl[2], dump_excl_wowlan[2];
const void *pnvm_data;
u32 pnvm_size;
};
static inline const char *get_fw_dbg_mode_string(int mode)

View File

@ -11,6 +11,7 @@
#include "fw/api/nvm-reg.h"
#include "fw/api/alive.h"
#include "fw/uefi.h"
#include "fw/img.h"
#define IWL_PNVM_REDUCED_CAP_BIT BIT(25)
@ -264,8 +265,8 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len)
return 0;
}
static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
__le32 sku_id[3])
static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
__le32 sku_id[3], const struct iwl_fw *fw)
{
struct pnvm_sku_package *package;
u8 *image = NULL;
@ -290,6 +291,12 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
}
}
if (fw->pnvm_data) {
*len = fw->pnvm_size;
return fw->pnvm_data;
}
/* If it's not available, or for Intel SKU, try from the filesystem */
if (iwl_pnvm_get_from_fs(trans_p, &image, len))
return NULL;
@ -298,11 +305,11 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
static void
iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa,
const struct iwl_fw *fw,
__le32 sku_id[3])
{
struct iwl_pnvm_image *pnvm_data = NULL;
u8 *data = NULL;
const u8 *data = NULL;
size_t length;
int ret;
@ -313,7 +320,7 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
if (trans->pnvm_loaded)
goto set;
data = iwl_get_pnvm_image(trans, &length, sku_id);
data = iwl_get_pnvm_image(trans, &length, sku_id, fw);
if (!data) {
trans->fail_to_parse_pnvm_image = true;
return;
@ -329,15 +336,17 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
goto free;
}
ret = iwl_trans_load_pnvm(trans, pnvm_data, capa);
ret = iwl_trans_load_pnvm(trans, pnvm_data, &fw->ucode_capa);
if (ret)
goto free;
IWL_DEBUG_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version);
set:
iwl_trans_set_pnvm(trans, capa);
iwl_trans_set_pnvm(trans, &fw->ucode_capa);
free:
kvfree(data);
/* free only if it was allocated, i.e. not just embedded PNVM data */
if (data != fw->pnvm_data)
kvfree(data);
kfree(pnvm_data);
}
@ -392,8 +401,7 @@ iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans,
int iwl_pnvm_load(struct iwl_trans *trans,
struct iwl_notif_wait_data *notif_wait,
const struct iwl_ucode_capabilities *capa,
__le32 sku_id[3])
const struct iwl_fw *fw, __le32 sku_id[3])
{
struct iwl_notification_wait pnvm_wait;
static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP,
@ -403,8 +411,8 @@ int iwl_pnvm_load(struct iwl_trans *trans,
if (!sku_id[0] && !sku_id[1] && !sku_id[2])
return 0;
iwl_pnvm_load_pnvm_to_trans(trans, capa, sku_id);
iwl_pnvm_load_reduce_power_to_trans(trans, capa, sku_id);
iwl_pnvm_load_pnvm_to_trans(trans, fw, sku_id);
iwl_pnvm_load_reduce_power_to_trans(trans, &fw->ucode_capa, sku_id);
iwl_init_notification_wait(notif_wait, &pnvm_wait,
ntf_cmds, ARRAY_SIZE(ntf_cmds),

View File

@ -7,6 +7,7 @@
#include "iwl-drv.h"
#include "fw/notif-wait.h"
#include "fw/img.h"
#define MVM_UCODE_PNVM_TIMEOUT (HZ / 4)
@ -14,8 +15,7 @@
int iwl_pnvm_load(struct iwl_trans *trans,
struct iwl_notif_wait_data *notif_wait,
const struct iwl_ucode_capabilities *capa,
__le32 sku_id[3]);
const struct iwl_fw *fw, __le32 sku_id[3]);
static inline
void iwl_pnvm_get_fs_name(struct iwl_trans *trans,

View File

@ -488,8 +488,8 @@ struct iwl_dev_info {
rf_type:9,
match_bw_limit:1,
bw_limit:1,
match_rf_step:1,
rf_step:4,
match_discrete:1,
discrete:1,
match_rf_id:1,
rf_id:4,
match_cdb:1,
@ -499,12 +499,13 @@ struct iwl_dev_info {
#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
extern const struct iwl_dev_info iwl_dev_info_table[];
extern const unsigned int iwl_dev_info_table_size;
const struct iwl_dev_info *
iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb,
u8 rf_id, u8 bw_limit, u8 rf_step);
extern const struct pci_device_id iwl_hw_card_ids[];
#endif
const struct iwl_dev_info *
iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb,
u8 rf_id, u8 bw_limit, bool discrete);
/*
* This list declares the config structures for all devices.
*/

View File

@ -136,6 +136,9 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
kfree(drv->fw.phy_integration_ver);
kfree(drv->trans->dbg.pc_data);
drv->trans->dbg.pc_data = NULL;
kvfree(drv->fw.pnvm_data);
drv->fw.pnvm_data = NULL;
drv->fw.pnvm_size = 0;
for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
iwl_free_fw_img(drv, drv->fw.img + i);
@ -1400,6 +1403,15 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
drv->trans->dbg.num_pc =
tlv_len / sizeof(struct iwl_pc_data);
break;
case IWL_UCODE_TLV_PNVM_DATA:
if (drv->fw.pnvm_data)
break;
drv->fw.pnvm_data =
kvmemdup(tlv_data, tlv_len, GFP_KERNEL);
if (!drv->fw.pnvm_data)
return -ENOMEM;
drv->fw.pnvm_size = tlv_len;
break;
default:
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
break;
@ -2037,8 +2049,6 @@ static int __init iwl_drv_init(void)
for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++)
INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv);
pr_info(DRV_DESCRIPTION "\n");
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* Create the root of iwlwifi debugfs subsystem. */
iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL);

View File

@ -47,8 +47,8 @@ IWL_EXPORT_SYMBOL(iwl_read32);
#define IWL_POLL_INTERVAL 10 /* microseconds */
int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
u32 bits, u32 mask, int timeout)
int iwl_poll_bits_mask(struct iwl_trans *trans, u32 addr,
u32 bits, u32 mask, int timeout)
{
int t = 0;
@ -61,7 +61,7 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
return -ETIMEDOUT;
}
IWL_EXPORT_SYMBOL(iwl_poll_bit);
IWL_EXPORT_SYMBOL(iwl_poll_bits_mask);
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
{
@ -477,7 +477,7 @@ int iwl_finish_nic_init(struct iwl_trans *trans)
* device-internal resources is supported, e.g. iwl_write_prph()
* and accesses to uCode SRAM.
*/
err = iwl_poll_bit(trans, CSR_GP_CNTRL, poll_ready, poll_ready, 25000);
err = iwl_poll_bits(trans, CSR_GP_CNTRL, poll_ready, 25000);
if (err < 0) {
IWL_DEBUG_INFO(trans, "Failed to wake NIC\n");

View File

@ -23,8 +23,13 @@ static inline void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask)
iwl_trans_set_bits_mask(trans, reg, mask, 0);
}
int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
u32 bits, u32 mask, int timeout);
int iwl_poll_bits_mask(struct iwl_trans *trans, u32 addr,
u32 bits, u32 mask, int timeout);
static inline int iwl_poll_bits(struct iwl_trans *trans, u32 addr, u32 bits,
int timeout)
{
return iwl_poll_bits_mask(trans, addr, bits, bits, timeout);
}
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
int timeout);

View File

@ -268,7 +268,9 @@ static void iwl_trans_restart_wk(struct work_struct *wk)
struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
struct device *dev,
const struct iwl_mac_cfg *mac_cfg)
const struct iwl_mac_cfg *mac_cfg,
unsigned int txcmd_size,
unsigned int txcmd_align)
{
struct iwl_trans *trans;
#ifdef CONFIG_LOCKDEP
@ -290,35 +292,6 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
INIT_DELAYED_WORK(&trans->restart.wk, iwl_trans_restart_wk);
return trans;
}
int iwl_trans_init(struct iwl_trans *trans)
{
int txcmd_size, txcmd_align;
/* check if name/num_rx_queues were set as a proxy for info being set */
if (WARN_ON(!trans->info.name || !trans->info.num_rxqs))
return -EINVAL;
if (!trans->mac_cfg->gen2) {
txcmd_size = sizeof(struct iwl_tx_cmd_v6);
txcmd_align = sizeof(void *);
} else if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
txcmd_size = sizeof(struct iwl_tx_cmd_v9);
txcmd_align = 64;
} else {
txcmd_size = sizeof(struct iwl_tx_cmd);
txcmd_align = 128;
}
txcmd_size += sizeof(struct iwl_cmd_header);
txcmd_size += 36; /* biggest possible 802.11 header */
/* Ensure device TX cmd cannot reach/cross a page boundary in gen2 */
if (WARN_ON(trans->mac_cfg->gen2 && txcmd_size >= txcmd_align))
return -EINVAL;
snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
"iwl_cmd_pool:%s", dev_name(trans->dev));
trans->dev_cmd_pool =
@ -326,9 +299,9 @@ int iwl_trans_init(struct iwl_trans *trans)
txcmd_size, txcmd_align,
SLAB_HWCACHE_ALIGN, NULL);
if (!trans->dev_cmd_pool)
return -ENOMEM;
return NULL;
return 0;
return trans;
}
void iwl_trans_free(struct iwl_trans *trans)

View File

@ -1204,9 +1204,10 @@ static inline void iwl_trans_finish_sw_reset(struct iwl_trans *trans)
* transport helper functions
*****************************************************/
struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
struct device *dev,
const struct iwl_mac_cfg *cfg_trans);
int iwl_trans_init(struct iwl_trans *trans);
struct device *dev,
const struct iwl_mac_cfg *mac_cfg,
unsigned int txcmd_size,
unsigned int txcmd_align);
void iwl_trans_free(struct iwl_trans *trans);
static inline bool iwl_trans_is_hw_error_value(u32 val)

View File

@ -294,7 +294,7 @@ static int iwl_mld_run_fw_init_sequence(struct iwl_mld *mld)
return ret;
ret = iwl_pnvm_load(mld->trans, &mld->notif_wait,
&mld->fw->ucode_capa, alive_data.sku_id);
mld->fw, alive_data.sku_id);
if (ret) {
IWL_ERR(mld, "Timeout waiting for PNVM load %d\n", ret);
return ret;

View File

@ -299,18 +299,18 @@ void iwl_mld_ptp_init(struct iwl_mld *mld)
PTR_ERR(mld->ptp_data.ptp_clock));
mld->ptp_data.ptp_clock = NULL;
} else {
IWL_INFO(mld, "Registered PHC clock: %s, with index: %d\n",
mld->ptp_data.ptp_clock_info.name,
ptp_clock_index(mld->ptp_data.ptp_clock));
IWL_DEBUG_INFO(mld, "Registered PHC clock: %s, with index: %d\n",
mld->ptp_data.ptp_clock_info.name,
ptp_clock_index(mld->ptp_data.ptp_clock));
}
}
void iwl_mld_ptp_remove(struct iwl_mld *mld)
{
if (mld->ptp_data.ptp_clock) {
IWL_INFO(mld, "Unregistering PHC clock: %s, with index: %d\n",
mld->ptp_data.ptp_clock_info.name,
ptp_clock_index(mld->ptp_data.ptp_clock));
IWL_DEBUG_INFO(mld, "Unregistering PHC clock: %s, with index: %d\n",
mld->ptp_data.ptp_clock_info.name,
ptp_clock_index(mld->ptp_data.ptp_clock));
ptp_clock_unregister(mld->ptp_data.ptp_clock);
mld->ptp_data.ptp_clock = NULL;

View File

@ -1474,9 +1474,6 @@ struct iwl_wowlan_status_data {
struct iwl_multicast_key_data igtk;
struct iwl_multicast_key_data bigtk[WOWLAN_BIGTK_KEYS_NUM];
int num_mlo_keys;
struct iwl_wowlan_mlo_gtk mlo_keys[WOWLAN_MAX_MLO_KEYS];
u8 *wake_packet;
};
@ -1790,8 +1787,7 @@ static void iwl_mvm_set_key_rx_seq_idx(struct ieee80211_key_conf *key,
}
static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
struct iwl_wowlan_status_data *status,
bool installed)
struct iwl_wowlan_status_data *status)
{
int i;
@ -1815,7 +1811,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
/* handle the case where we didn't, last key only */
if (status->gtk_seq[i].key_id == -1 &&
(!status->num_of_gtk_rekeys || installed))
(!status->num_of_gtk_rekeys))
iwl_mvm_set_key_rx_seq_idx(key, status, i);
}
}
@ -1966,7 +1962,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
(status->gtk[1].len && keyidx == status->gtk[1].id))) {
ieee80211_remove_key(key);
} else {
iwl_mvm_set_key_rx_seq(key, data->status, false);
iwl_mvm_set_key_rx_seq(key, data->status);
}
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
@ -1986,167 +1982,6 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
}
}
struct iwl_mvm_d3_mlo_old_keys {
u32 cipher[IEEE80211_MLD_MAX_NUM_LINKS][WOWLAN_MLO_GTK_KEY_NUM_TYPES];
struct ieee80211_key_conf *key[IEEE80211_MLD_MAX_NUM_LINKS][8];
};
static void iwl_mvm_mlo_key_ciphers(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key,
void *data)
{
struct iwl_mvm_d3_mlo_old_keys *old_keys = data;
enum iwl_wowlan_mlo_gtk_type key_type;
if (key->link_id < 0)
return;
if (WARN_ON(key->link_id >= IEEE80211_MLD_MAX_NUM_LINKS ||
key->keyidx >= 8))
return;
if (WARN_ON(old_keys->key[key->link_id][key->keyidx]))
return;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
key_type = WOWLAN_MLO_GTK_KEY_TYPE_GTK;
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
case WLAN_CIPHER_SUITE_AES_CMAC:
if (key->keyidx == 4 || key->keyidx == 5) {
key_type = WOWLAN_MLO_GTK_KEY_TYPE_IGTK;
break;
} else if (key->keyidx == 6 || key->keyidx == 7) {
key_type = WOWLAN_MLO_GTK_KEY_TYPE_BIGTK;
break;
}
return;
default:
/* ignore WEP/TKIP or unknown ciphers */
return;
}
old_keys->cipher[key->link_id][key_type] = key->cipher;
old_keys->key[key->link_id][key->keyidx] = key;
}
static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status,
struct ieee80211_vif *vif,
struct iwl_mvm *mvm)
{
int i;
struct iwl_mvm_d3_mlo_old_keys *old_keys;
bool ret = true;
IWL_DEBUG_WOWLAN(mvm, "Num of MLO Keys: %d\n", status->num_mlo_keys);
if (!status->num_mlo_keys)
return true;
old_keys = kzalloc(sizeof(*old_keys), GFP_KERNEL);
if (!old_keys)
return false;
/* find the cipher for each mlo key */
ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mlo_key_ciphers, old_keys);
for (i = 0; i < status->num_mlo_keys; i++) {
struct iwl_wowlan_mlo_gtk *mlo_key = &status->mlo_keys[i];
struct ieee80211_key_conf *key, *old_key;
struct ieee80211_key_seq seq;
DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key,
WOWLAN_KEY_MAX_SIZE);
u16 flags = le16_to_cpu(mlo_key->flags);
int j, link_id, key_id, key_type;
link_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK);
key_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK);
key_type = u16_get_bits(flags,
WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK);
if (!(vif->valid_links & BIT(link_id)))
continue;
if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS ||
key_id >= 8 ||
key_type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES))
continue;
conf->cipher = old_keys->cipher[link_id][key_type];
/* WARN_ON? */
if (!conf->cipher)
continue;
conf->keylen = 0;
switch (conf->cipher) {
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
conf->keylen = WLAN_KEY_LEN_CCMP;
break;
case WLAN_CIPHER_SUITE_GCMP_256:
conf->keylen = WLAN_KEY_LEN_GCMP_256;
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
conf->keylen = WLAN_KEY_LEN_BIP_GMAC_128;
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
conf->keylen = WLAN_KEY_LEN_BIP_GMAC_256;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
conf->keylen = WLAN_KEY_LEN_AES_CMAC;
break;
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
conf->keylen = WLAN_KEY_LEN_BIP_CMAC_256;
break;
}
if (WARN_ON(!conf->keylen ||
conf->keylen > WOWLAN_KEY_MAX_SIZE))
continue;
memcpy(conf->key, mlo_key->key, conf->keylen);
conf->keyidx = key_id;
old_key = old_keys->key[link_id][key_id];
if (old_key) {
IWL_DEBUG_WOWLAN(mvm,
"Remove MLO key id %d, link id %d\n",
key_id, link_id);
ieee80211_remove_key(old_key);
}
IWL_DEBUG_WOWLAN(mvm, "Add MLO key id %d, link id %d\n",
key_id, link_id);
key = ieee80211_gtk_rekey_add(vif, conf, link_id);
if (WARN_ON(IS_ERR(key))) {
ret = false;
goto out;
}
/*
* mac80211 expects the pn in big-endian
* also note that seq is a union of all cipher types
* (ccmp, gcmp, cmac, gmac), and they all have the same
* pn field (of length 6) so just copy it to ccmp.pn.
*/
for (j = 5; j >= 0; j--)
seq.ccmp.pn[5 - j] = mlo_key->pn[j];
/* group keys are non-QoS and use TID 0 */
ieee80211_set_key_rx_seq(key, 0, &seq);
}
out:
kfree(old_keys);
return ret;
}
static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
struct ieee80211_vif *vif,
struct iwl_mvm *mvm, u32 gtk_cipher)
@ -2346,9 +2181,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
return false;
}
if (!iwl_mvm_mlo_gtk_rekey(status, vif, mvm))
return false;
ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
(void *)&replay_ctr, GFP_KERNEL);
}
@ -2479,10 +2311,11 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
struct iwl_wowlan_status_data *status,
u32 len)
{
u32 expected_len = sizeof(*data) +
data->num_mlo_link_keys * sizeof(status->mlo_keys[0]);
if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys,
"MLO is not supported, shouldn't receive MLO keys\n"))
return;
if (len < expected_len) {
if (len < sizeof(*data)) {
IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
status = NULL;
return;
@ -2511,33 +2344,17 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
le32_to_cpu(data->num_of_gtk_rekeys);
status->received_beacons = le32_to_cpu(data->received_beacons);
status->tid_tear_down = data->tid_tear_down;
if (data->num_mlo_link_keys) {
status->num_mlo_keys = data->num_mlo_link_keys;
if (IWL_FW_CHECK(mvm,
status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS,
"Too many mlo keys: %d, max %d\n",
status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS))
status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS;
memcpy(status->mlo_keys, data->mlo_gtks,
status->num_mlo_keys * sizeof(status->mlo_keys[0]));
}
}
static void
iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm,
struct iwl_wowlan_info_notif_v4 *data,
iwl_mvm_parse_wowlan_info_notif_v3(struct iwl_mvm *mvm,
struct iwl_wowlan_info_notif_v3 *data,
struct iwl_wowlan_status_data *status,
u32 len, bool has_mlo_keys)
u32 len)
{
u32 i;
u32 expected_len = sizeof(*data);
if (has_mlo_keys)
expected_len += (data->num_mlo_link_keys *
sizeof(status->mlo_keys[0]));
if (len < expected_len) {
if (len < sizeof(*data)) {
IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
status = NULL;
return;
@ -2560,17 +2377,6 @@ iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm,
le32_to_cpu(data->num_of_gtk_rekeys);
status->received_beacons = le32_to_cpu(data->received_beacons);
status->tid_tear_down = data->tid_tear_down;
if (has_mlo_keys && data->num_mlo_link_keys) {
status->num_mlo_keys = data->num_mlo_link_keys;
if (IWL_FW_CHECK(mvm,
status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS,
"Too many mlo keys: %d, max %d\n",
status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS))
status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS;
memcpy(status->mlo_keys, data->mlo_gtks,
status->num_mlo_keys * sizeof(status->mlo_keys[0]));
}
}
static void
@ -3316,19 +3122,23 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2,
d3_data->status,
len);
} else if (wowlan_info_ver < 5) {
struct iwl_wowlan_info_notif_v4 *notif =
} else if (wowlan_info_ver == 3) {
struct iwl_wowlan_info_notif_v3 *notif =
(void *)pkt->data;
iwl_mvm_parse_wowlan_info_notif_v4(mvm, notif,
d3_data->status, len,
wowlan_info_ver > 3);
} else {
iwl_mvm_parse_wowlan_info_notif_v3(mvm, notif,
d3_data->status, len);
} else if (wowlan_info_ver == 5) {
struct iwl_wowlan_info_notif *notif =
(void *)pkt->data;
iwl_mvm_parse_wowlan_info_notif(mvm, notif,
d3_data->status, len);
} else {
IWL_FW_CHECK(mvm, 1,
"Firmware advertises unknown WoWLAN info notification %d!\n",
wowlan_info_ver);
return false;
}
d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO;

View File

@ -432,7 +432,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
iwl_trans_fw_alive(mvm->trans);
ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait,
&mvm->fw->ucode_capa, alive_data.sku_id);
mvm->fw, alive_data.sku_id);
if (ret) {
IWL_ERR(mvm, "Timeout waiting for PNVM load!\n");
iwl_fw_set_current_image(&mvm->fwrt, old_type);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2021 - 2023 Intel Corporation
* Copyright (C) 2021 - 2023, 2025 Intel Corporation
*/
#include "mvm.h"
@ -298,9 +298,9 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm)
PTR_ERR(mvm->ptp_data.ptp_clock));
mvm->ptp_data.ptp_clock = NULL;
} else if (mvm->ptp_data.ptp_clock) {
IWL_INFO(mvm, "Registered PHC clock: %s, with index: %d\n",
mvm->ptp_data.ptp_clock_info.name,
ptp_clock_index(mvm->ptp_data.ptp_clock));
IWL_DEBUG_INFO(mvm, "Registered PHC clock: %s, with index: %d\n",
mvm->ptp_data.ptp_clock_info.name,
ptp_clock_index(mvm->ptp_data.ptp_clock));
}
}
@ -312,9 +312,9 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm)
void iwl_mvm_ptp_remove(struct iwl_mvm *mvm)
{
if (mvm->ptp_data.ptp_clock) {
IWL_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n",
mvm->ptp_data.ptp_clock_info.name,
ptp_clock_index(mvm->ptp_data.ptp_clock));
IWL_DEBUG_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n",
mvm->ptp_data.ptp_clock_info.name,
ptp_clock_index(mvm->ptp_data.ptp_clock));
ptp_clock_unregister(mvm->ptp_data.ptp_clock);
mvm->ptp_data.ptp_clock = NULL;

View File

@ -577,8 +577,10 @@ EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_hw_card_ids);
.subdevice_m_h = _HIGHEST_BIT(m)
#define RF_TYPE(n) .match_rf_type = 1, \
.rf_type = IWL_CFG_RF_TYPE_##n
#define RF_STEP(n) .match_rf_step = 1, \
.rf_step = SILICON_##n##_STEP
#define DISCRETE .match_discrete = 1, \
.discrete = 1
#define INTEGRATED .match_discrete = 1, \
.discrete = 0
#define RF_ID(n) .match_rf_id = 1, \
.rf_id = IWL_CFG_RF_ID_##n
#define NO_CDB .match_cdb = 1, .cdb = 0
@ -1032,9 +1034,8 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = {
/* FM RF */
IWL_DEV_INFO(iwl_rf_fm, iwl_be201_name, RF_TYPE(FM)),
IWL_DEV_INFO(iwl_rf_fm, iwl_be401_name, RF_TYPE(FM), CDB),
/* the discrete NICs got the RF B0, it's only for the name anyway */
IWL_DEV_INFO(iwl_rf_fm, iwl_be200_name, RF_TYPE(FM),
DEVICE(0x272B), RF_STEP(B)),
DEVICE(0x272B), DISCRETE),
IWL_DEV_INFO(iwl_rf_fm_160mhz, iwl_be202_name,
RF_TYPE(FM), BW_LIMITED),
@ -1074,149 +1075,12 @@ const unsigned int iwl_dev_info_table_size = ARRAY_SIZE(iwl_dev_info_table);
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_dev_info_table_size);
#endif
/*
* Read rf id and cdb info from prph register and store it
*/
static void get_crf_id(struct iwl_trans *iwl_trans,
struct iwl_trans_info *info)
{
u32 sd_reg_ver_addr;
u32 hw_wfpm_id;
u32 val = 0;
u8 step;
if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
sd_reg_ver_addr = SD_REG_VER_GEN2;
else
sd_reg_ver_addr = SD_REG_VER;
/* Enable access to peripheral registers */
val = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG);
val |= WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK;
iwl_write_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG, val);
/* Read crf info */
info->hw_crf_id = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr);
/* Read cnv info */
info->hw_cnv_id = iwl_read_prph_no_grab(iwl_trans, CNVI_AUX_MISC_CHIP);
/* For BZ-W, take B step also when A step is indicated */
if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W)
step = SILICON_B_STEP;
/* In BZ, the MAC step must be read from the CNVI aux register */
if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ) {
step = CNVI_AUX_MISC_CHIP_MAC_STEP(info->hw_cnv_id);
/* For BZ-U, take B step also when A step is indicated */
if ((CNVI_AUX_MISC_CHIP_PROD_TYPE(info->hw_cnv_id) ==
CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_U) &&
step == SILICON_A_STEP)
step = SILICON_B_STEP;
}
if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ ||
CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W) {
info->hw_rev_step = step;
info->hw_rev |= step;
}
/* Read cdb info (also contains the jacket info if needed in the future */
hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR);
IWL_INFO(iwl_trans, "Detected crf-id 0x%x, cnv-id 0x%x wfpm id 0x%x\n",
info->hw_crf_id, info->hw_cnv_id, hw_wfpm_id);
}
/*
* In case that there is no OTP on the NIC, map the rf id and cdb info
* from the prph registers.
*/
static int map_crf_id(struct iwl_trans *iwl_trans,
struct iwl_trans_info *info)
{
int ret = 0;
u32 val = info->hw_crf_id;
u32 step_id = REG_CRF_ID_STEP(val);
u32 slave_id = REG_CRF_ID_SLAVE(val);
u32 jacket_id_cnv = REG_CRF_ID_SLAVE(info->hw_cnv_id);
u32 hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans,
WFPM_OTP_CFG1_ADDR);
u32 jacket_id_wfpm = WFPM_OTP_CFG1_IS_JACKET(hw_wfpm_id);
u32 cdb_id_wfpm = WFPM_OTP_CFG1_IS_CDB(hw_wfpm_id);
/* Map between crf id to rf id */
switch (REG_CRF_ID_TYPE(val)) {
case REG_CRF_ID_TYPE_JF_1:
info->hw_rf_id = (IWL_CFG_RF_TYPE_JF1 << 12);
break;
case REG_CRF_ID_TYPE_JF_2:
info->hw_rf_id = (IWL_CFG_RF_TYPE_JF2 << 12);
break;
case REG_CRF_ID_TYPE_HR_NONE_CDB_1X1:
info->hw_rf_id = (IWL_CFG_RF_TYPE_HR1 << 12);
break;
case REG_CRF_ID_TYPE_HR_NONE_CDB:
info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12);
break;
case REG_CRF_ID_TYPE_HR_CDB:
info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12);
break;
case REG_CRF_ID_TYPE_GF:
info->hw_rf_id = (IWL_CFG_RF_TYPE_GF << 12);
break;
case REG_CRF_ID_TYPE_FM:
info->hw_rf_id = (IWL_CFG_RF_TYPE_FM << 12);
break;
case REG_CRF_ID_TYPE_WHP:
info->hw_rf_id = (IWL_CFG_RF_TYPE_WH << 12);
break;
case REG_CRF_ID_TYPE_PE:
info->hw_rf_id = (IWL_CFG_RF_TYPE_PE << 12);
break;
default:
ret = -EIO;
IWL_ERR(iwl_trans,
"Can't find a correct rfid for crf id 0x%x\n",
REG_CRF_ID_TYPE(val));
goto out;
}
/* Set Step-id */
info->hw_rf_id |= (step_id << 8);
/* Set CDB capabilities */
if (cdb_id_wfpm || slave_id) {
info->hw_rf_id += BIT(28);
IWL_INFO(iwl_trans, "Adding cdb to rf id\n");
}
/* Set Jacket capabilities */
if (jacket_id_wfpm || jacket_id_cnv) {
info->hw_rf_id += BIT(29);
IWL_INFO(iwl_trans, "Adding jacket to rf id\n");
}
IWL_INFO(iwl_trans,
"Detected rf-type 0x%x step-id 0x%x slave-id 0x%x from crf id 0x%x\n",
REG_CRF_ID_TYPE(val), step_id, slave_id, info->hw_rf_id);
IWL_INFO(iwl_trans,
"Detected cdb-id 0x%x jacket-id 0x%x from wfpm id 0x%x\n",
cdb_id_wfpm, jacket_id_wfpm, hw_wfpm_id);
IWL_INFO(iwl_trans, "Detected jacket-id 0x%x from cnvi id 0x%x\n",
jacket_id_cnv, info->hw_cnv_id);
out:
return ret;
}
/* PCI registers */
#define PCI_CFG_RETRY_TIMEOUT 0x041
VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info *
const struct iwl_dev_info *
iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb,
u8 rf_id, u8 bw_limit, u8 rf_step)
u8 rf_id, u8 bw_limit, bool discrete)
{
int num_devices = ARRAY_SIZE(iwl_dev_info_table);
int i;
@ -1251,7 +1115,7 @@ iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb,
if (dev_info->match_bw_limit && dev_info->bw_limit != bw_limit)
continue;
if (dev_info->match_rf_step && dev_info->rf_step != rf_step)
if (dev_info->match_discrete && dev_info->discrete != discrete)
continue;
return dev_info;
@ -1261,193 +1125,47 @@ iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb,
}
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_pci_find_dev_info);
static void iwl_pcie_recheck_me_status(struct work_struct *wk)
{
struct iwl_trans_pcie *trans_pcie = container_of(wk,
typeof(*trans_pcie),
me_recheck_wk.work);
u32 val;
val = iwl_read32(trans_pcie->trans, CSR_HW_IF_CONFIG_REG);
trans_pcie->me_present = !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP);
}
static void iwl_pcie_check_me_status(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 val;
trans_pcie->me_present = -1;
INIT_DELAYED_WORK(&trans_pcie->me_recheck_wk,
iwl_pcie_recheck_me_status);
/* we don't have a good way of determining this until BZ */
if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ)
return;
val = iwl_read_prph(trans, CNVI_SCU_REG_FOR_ECO_1);
if (val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN) {
trans_pcie->me_present =
!!(val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT);
return;
}
val = iwl_read32(trans, CSR_HW_IF_CONFIG_REG);
if (val & (CSR_HW_IF_CONFIG_REG_ME_OWN |
CSR_HW_IF_CONFIG_REG_IAMT_UP)) {
trans_pcie->me_present = 1;
return;
}
/* recheck again later, ME might still be initializing */
schedule_delayed_work(&trans_pcie->me_recheck_wk, HZ);
}
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct iwl_mac_cfg *trans;
const struct iwl_dev_info *dev_info;
struct iwl_trans_info info = {
.hw_id = (pdev->device << 16) + pdev->subsystem_device,
};
struct iwl_trans *iwl_trans;
struct iwl_trans_pcie *trans_pcie;
const struct iwl_mac_cfg *mac_cfg = (void *)ent->driver_data;
u8 __iomem *hw_base;
u32 bar0, hw_rev;
int ret;
trans = (void *)ent->driver_data;
iwl_trans = iwl_trans_pcie_alloc(pdev, trans, &info);
if (IS_ERR(iwl_trans))
return PTR_ERR(iwl_trans);
trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
iwl_trans_pcie_check_product_reset_status(pdev);
iwl_trans_pcie_check_product_reset_mode(pdev);
/* set the things we know so far for the grab NIC access */
iwl_trans_set_info(iwl_trans, &info);
/*
* Let's try to grab NIC access early here. Sometimes, NICs may
* fail to initialize, and if that happens it's better if we see
* issues early on (and can reprobe, per the logic inside), than
* first trying to load the firmware etc. and potentially only
* detecting any problems when the first interface is brought up.
*/
ret = iwl_pcie_prepare_card_hw(iwl_trans);
if (!ret) {
ret = iwl_finish_nic_init(iwl_trans);
/* reassign our BAR 0 if invalid due to possible runtime PM races */
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0);
if (bar0 == PCI_BASE_ADDRESS_MEM_TYPE_64) {
ret = pci_assign_resource(pdev, 0);
if (ret)
goto out_free_trans;
if (iwl_trans_grab_nic_access(iwl_trans)) {
get_crf_id(iwl_trans, &info);
/* all good */
iwl_trans_release_nic_access(iwl_trans);
} else {
ret = -EIO;
goto out_free_trans;
}
return ret;
}
info.hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID);
/*
* The RF_ID is set to zero in blank OTP so read version to
* extract the RF_ID.
* This is relevant only for family 9000 and up.
*/
if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000 &&
!CSR_HW_RFID_TYPE(info.hw_rf_id) && map_crf_id(iwl_trans, &info)) {
ret = -EINVAL;
goto out_free_trans;
}
IWL_INFO(iwl_trans, "PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n",
pdev->device, pdev->subsystem_device,
info.hw_rev, info.hw_rf_id);
dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device,
CSR_HW_RFID_TYPE(info.hw_rf_id),
CSR_HW_RFID_IS_CDB(info.hw_rf_id),
IWL_SUBDEVICE_RF_ID(pdev->subsystem_device),
IWL_SUBDEVICE_BW_LIM(pdev->subsystem_device),
CSR_HW_RFID_STEP(info.hw_rf_id));
if (dev_info) {
iwl_trans->cfg = dev_info->cfg;
info.name = dev_info->name;
}
#if IS_ENABLED(CONFIG_IWLMVM)
/*
* special-case 7265D, it has the same PCI IDs.
*
* Note that because we already pass the cfg to the transport above,
* all the parameters that the transport uses must, until that is
* changed, be identical to the ones in the 7265D configuration.
*/
if (iwl_trans->cfg == &iwl7265_cfg &&
(info.hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D)
iwl_trans->cfg = &iwl7265d_cfg;
#endif
if (!iwl_trans->cfg) {
pr_err("No config found for PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n",
pdev->device, pdev->subsystem_device,
info.hw_rev, info.hw_rf_id);
ret = -EINVAL;
goto out_free_trans;
}
IWL_INFO(iwl_trans, "Detected %s\n", info.name);
if (iwl_trans->mac_cfg->mq_rx_supported) {
if (WARN_ON(!iwl_trans->cfg->num_rbds)) {
ret = -EINVAL;
goto out_free_trans;
}
trans_pcie->num_rx_bufs = iwl_trans_get_num_rbds(iwl_trans);
} else {
trans_pcie->num_rx_bufs = RX_QUEUE_SIZE;
}
if (!iwl_trans->mac_cfg->integrated) {
u16 link_status;
pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &link_status);
info.pcie_link_speed =
u16_get_bits(link_status, PCI_EXP_LNKSTA_CLS);
}
iwl_trans_set_info(iwl_trans, &info);
ret = iwl_trans_init(iwl_trans);
ret = pcim_enable_device(pdev);
if (ret)
goto out_free_trans;
return ret;
pci_set_drvdata(pdev, iwl_trans);
pci_set_master(pdev);
iwl_pcie_check_me_status(iwl_trans);
/* try to get ownership so that we'll know if we don't own it */
iwl_pcie_prepare_card_hw(iwl_trans);
iwl_trans->drv = iwl_drv_start(iwl_trans);
if (IS_ERR(iwl_trans->drv)) {
ret = PTR_ERR(iwl_trans->drv);
goto out_free_trans;
ret = pcim_request_all_regions(pdev, DRV_NAME);
if (ret) {
dev_err(&pdev->dev, "Requesting all PCI BARs failed.\n");
return ret;
}
/* register transport layer debugfs here */
iwl_trans_pcie_dbgfs_register(iwl_trans);
hw_base = pcim_iomap(pdev, 0, 0);
if (!hw_base) {
dev_err(&pdev->dev, "Failed to map BAR 0.\n");
return -ENOMEM;
}
return 0;
/* We can't use iwl_read32 because trans wasn't allocated */
hw_rev = readl(hw_base + CSR_HW_REV);
if (hw_rev == 0xffffffff) {
dev_err(&pdev->dev, "HW_REV=0xFFFFFFFF, PCI issues?\n");
return -EIO;
}
out_free_trans:
iwl_trans_pcie_free(iwl_trans);
return ret;
return iwl_pci_gen1_2_probe(pdev, ent, mac_cfg, hw_base, hw_rev);
}
static void iwl_pci_remove(struct pci_dev *pdev)

View File

@ -538,10 +538,6 @@ iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie)
* Convention: trans API functions: iwl_trans_pcie_XXX
* Other functions: iwl_pcie_XXX
*/
struct iwl_trans
*iwl_trans_pcie_alloc(struct pci_dev *pdev,
const struct iwl_mac_cfg *mac_cfg,
struct iwl_trans_info *info);
void iwl_trans_pcie_free(struct iwl_trans *trans);
void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions,
struct device *dev);
@ -1081,6 +1077,10 @@ bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans);
void __releases(nic_access_nobh)
iwl_trans_pcie_release_nic_access(struct iwl_trans *trans);
void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power);
int iwl_pci_gen1_2_probe(struct pci_dev *pdev,
const struct pci_device_id *ent,
const struct iwl_mac_cfg *mac_cfg,
u8 __iomem *hw_base, u32 hw_rev);
/* transport gen 1 exported functions */
void iwl_trans_pcie_fw_alive(struct iwl_trans *trans);

View File

@ -25,6 +25,7 @@
#include "fw/dbg.h"
#include "fw/api/tx.h"
#include "fw/acpi.h"
#include "fw/api/tx.h"
#include "mei/iwl-mei.h"
#include "internal.h"
#include "iwl-fh.h"
@ -380,17 +381,15 @@ void iwl_pcie_apm_stop_master(struct iwl_trans *trans)
iwl_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ);
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS,
CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS,
100);
ret = iwl_poll_bits(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS,
100);
usleep_range(10000, 20000);
} else {
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
ret = iwl_poll_bit(trans, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
ret = iwl_poll_bits(trans, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
}
if (ret < 0)
@ -492,10 +491,9 @@ static int iwl_pcie_set_hw_ready(struct iwl_trans *trans)
CSR_HW_IF_CONFIG_REG_PCI_OWN_SET);
/* See if we got it */
ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PCI_OWN_SET,
CSR_HW_IF_CONFIG_REG_PCI_OWN_SET,
HW_READY_TIMEOUT);
ret = iwl_poll_bits(trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PCI_OWN_SET,
HW_READY_TIMEOUT);
if (ret >= 0)
iwl_set_bit(trans, CSR_MBOX_SET_REG, CSR_MBOX_SET_REG_OS_ALIVE);
@ -2354,7 +2352,7 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent)
* 5000 series and later (including 1000 series) have non-volatile SRAM,
* and do not save/restore SRAM when power cycling.
*/
ret = iwl_poll_bit(trans, CSR_GP_CNTRL, poll, mask, 15000);
ret = iwl_poll_bits_mask(trans, CSR_GP_CNTRL, poll, mask, 15000);
if (unlikely(ret < 0)) {
u32 cntrl = iwl_read32(trans, CSR_GP_CNTRL);
@ -3686,36 +3684,56 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans)
iwl_trans_sync_nmi_with_addr(trans, inta_addr, sw_err_bit);
}
struct iwl_trans *
static int iwl_trans_pcie_set_txcmd_info(const struct iwl_mac_cfg *mac_cfg,
unsigned int *txcmd_size,
unsigned int *txcmd_align)
{
if (!mac_cfg->gen2) {
*txcmd_size = sizeof(struct iwl_tx_cmd_v6);
*txcmd_align = sizeof(void *);
} else if (mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
*txcmd_size = sizeof(struct iwl_tx_cmd_v9);
*txcmd_align = 64;
} else {
*txcmd_size = sizeof(struct iwl_tx_cmd);
*txcmd_align = 128;
}
*txcmd_size += sizeof(struct iwl_cmd_header);
*txcmd_size += 36; /* biggest possible 802.11 header */
/* Ensure device TX cmd cannot reach/cross a page boundary in gen2 */
if (WARN_ON((mac_cfg->gen2 && *txcmd_size >= *txcmd_align)))
return -EINVAL;
return 0;
}
static struct iwl_trans *
iwl_trans_pcie_alloc(struct pci_dev *pdev,
const struct iwl_mac_cfg *mac_cfg,
struct iwl_trans_info *info)
struct iwl_trans_info *info, u8 __iomem *hw_base)
{
struct iwl_trans_pcie *trans_pcie, **priv;
unsigned int txcmd_size, txcmd_align;
struct iwl_trans *trans;
unsigned int bc_tbl_n_entries;
int ret, addr_size;
u32 bar0;
/* reassign our BAR 0 if invalid due to possible runtime PM races */
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0);
if (bar0 == PCI_BASE_ADDRESS_MEM_TYPE_64) {
ret = pci_assign_resource(pdev, 0);
if (ret)
return ERR_PTR(ret);
}
ret = pcim_enable_device(pdev);
ret = iwl_trans_pcie_set_txcmd_info(mac_cfg, &txcmd_size,
&txcmd_align);
if (ret)
return ERR_PTR(ret);
trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), &pdev->dev,
mac_cfg);
mac_cfg, txcmd_size, txcmd_align);
if (!trans)
return ERR_PTR(-ENOMEM);
trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
trans_pcie->hw_base = hw_base;
/* Initialize the wait queue for commands */
init_waitqueue_head(&trans_pcie->wait_command_queue);
@ -3813,8 +3831,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev,
PCIE_LINK_STATE_CLKPM);
}
pci_set_master(pdev);
addr_size = trans_pcie->txqs.tfd.addr_size;
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_size));
if (ret) {
@ -3826,19 +3842,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev,
}
}
ret = pcim_request_all_regions(pdev, DRV_NAME);
if (ret) {
dev_err(&pdev->dev, "Requesting all PCI BARs failed.\n");
goto out_no_pci;
}
trans_pcie->hw_base = pcim_iomap(pdev, 0, 0);
if (!trans_pcie->hw_base) {
dev_err(&pdev->dev, "Could not ioremap PCI BAR 0.\n");
ret = -ENODEV;
goto out_no_pci;
}
/* We disable the RETRY_TIMEOUT register (0x41) to keep
* PCI Tx retries from interfering with C3 CPU state */
pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
@ -3846,13 +3849,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev,
trans_pcie->pci_dev = pdev;
iwl_disable_interrupts(trans);
info->hw_rev = iwl_read32(trans, CSR_HW_REV);
if (info->hw_rev == 0xffffffff) {
dev_err(&pdev->dev, "HW_REV=0xFFFFFFFF, PCI issues?\n");
ret = -EIO;
goto out_no_pci;
}
/*
* In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have
* changed, and now the revision step also includes bit 0-1 (no more
@ -3952,3 +3948,326 @@ int iwl_trans_pcie_copy_imr(struct iwl_trans *trans,
trans_pcie->imr_status = IMR_D2S_IDLE;
return 0;
}
/*
* Read rf id and cdb info from prph register and store it
*/
static void get_crf_id(struct iwl_trans *iwl_trans,
struct iwl_trans_info *info)
{
u32 sd_reg_ver_addr;
u32 hw_wfpm_id;
u32 val = 0;
u8 step;
if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
sd_reg_ver_addr = SD_REG_VER_GEN2;
else
sd_reg_ver_addr = SD_REG_VER;
/* Enable access to peripheral registers */
val = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG);
val |= WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK;
iwl_write_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG, val);
/* Read crf info */
info->hw_crf_id = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr);
/* Read cnv info */
info->hw_cnv_id = iwl_read_prph_no_grab(iwl_trans, CNVI_AUX_MISC_CHIP);
/* For BZ-W, take B step also when A step is indicated */
if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W)
step = SILICON_B_STEP;
/* In BZ, the MAC step must be read from the CNVI aux register */
if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ) {
step = CNVI_AUX_MISC_CHIP_MAC_STEP(info->hw_cnv_id);
/* For BZ-U, take B step also when A step is indicated */
if ((CNVI_AUX_MISC_CHIP_PROD_TYPE(info->hw_cnv_id) ==
CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_U) &&
step == SILICON_A_STEP)
step = SILICON_B_STEP;
}
if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ ||
CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W) {
info->hw_rev_step = step;
info->hw_rev |= step;
}
/* Read cdb info (also contains the jacket info if needed in the future */
hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR);
IWL_INFO(iwl_trans, "Detected crf-id 0x%x, cnv-id 0x%x wfpm id 0x%x\n",
info->hw_crf_id, info->hw_cnv_id, hw_wfpm_id);
}
/*
* In case that there is no OTP on the NIC, map the rf id and cdb info
* from the prph registers.
*/
static int map_crf_id(struct iwl_trans *iwl_trans,
struct iwl_trans_info *info)
{
int ret = 0;
u32 val = info->hw_crf_id;
u32 step_id = REG_CRF_ID_STEP(val);
u32 slave_id = REG_CRF_ID_SLAVE(val);
u32 jacket_id_cnv = REG_CRF_ID_SLAVE(info->hw_cnv_id);
u32 hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans,
WFPM_OTP_CFG1_ADDR);
u32 jacket_id_wfpm = WFPM_OTP_CFG1_IS_JACKET(hw_wfpm_id);
u32 cdb_id_wfpm = WFPM_OTP_CFG1_IS_CDB(hw_wfpm_id);
/* Map between crf id to rf id */
switch (REG_CRF_ID_TYPE(val)) {
case REG_CRF_ID_TYPE_JF_1:
info->hw_rf_id = (IWL_CFG_RF_TYPE_JF1 << 12);
break;
case REG_CRF_ID_TYPE_JF_2:
info->hw_rf_id = (IWL_CFG_RF_TYPE_JF2 << 12);
break;
case REG_CRF_ID_TYPE_HR_NONE_CDB_1X1:
info->hw_rf_id = (IWL_CFG_RF_TYPE_HR1 << 12);
break;
case REG_CRF_ID_TYPE_HR_NONE_CDB:
info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12);
break;
case REG_CRF_ID_TYPE_HR_CDB:
info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12);
break;
case REG_CRF_ID_TYPE_GF:
info->hw_rf_id = (IWL_CFG_RF_TYPE_GF << 12);
break;
case REG_CRF_ID_TYPE_FM:
info->hw_rf_id = (IWL_CFG_RF_TYPE_FM << 12);
break;
case REG_CRF_ID_TYPE_WHP:
info->hw_rf_id = (IWL_CFG_RF_TYPE_WH << 12);
break;
case REG_CRF_ID_TYPE_PE:
info->hw_rf_id = (IWL_CFG_RF_TYPE_PE << 12);
break;
default:
ret = -EIO;
IWL_ERR(iwl_trans,
"Can't find a correct rfid for crf id 0x%x\n",
REG_CRF_ID_TYPE(val));
goto out;
}
/* Set Step-id */
info->hw_rf_id |= (step_id << 8);
/* Set CDB capabilities */
if (cdb_id_wfpm || slave_id) {
info->hw_rf_id += BIT(28);
IWL_INFO(iwl_trans, "Adding cdb to rf id\n");
}
/* Set Jacket capabilities */
if (jacket_id_wfpm || jacket_id_cnv) {
info->hw_rf_id += BIT(29);
IWL_INFO(iwl_trans, "Adding jacket to rf id\n");
}
IWL_INFO(iwl_trans,
"Detected rf-type 0x%x step-id 0x%x slave-id 0x%x from crf id 0x%x\n",
REG_CRF_ID_TYPE(val), step_id, slave_id, info->hw_rf_id);
IWL_INFO(iwl_trans,
"Detected cdb-id 0x%x jacket-id 0x%x from wfpm id 0x%x\n",
cdb_id_wfpm, jacket_id_wfpm, hw_wfpm_id);
IWL_INFO(iwl_trans, "Detected jacket-id 0x%x from cnvi id 0x%x\n",
jacket_id_cnv, info->hw_cnv_id);
out:
return ret;
}
static void iwl_pcie_recheck_me_status(struct work_struct *wk)
{
struct iwl_trans_pcie *trans_pcie = container_of(wk,
typeof(*trans_pcie),
me_recheck_wk.work);
u32 val;
val = iwl_read32(trans_pcie->trans, CSR_HW_IF_CONFIG_REG);
trans_pcie->me_present = !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP);
}
static void iwl_pcie_check_me_status(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 val;
trans_pcie->me_present = -1;
INIT_DELAYED_WORK(&trans_pcie->me_recheck_wk,
iwl_pcie_recheck_me_status);
/* we don't have a good way of determining this until BZ */
if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ)
return;
val = iwl_read_prph(trans, CNVI_SCU_REG_FOR_ECO_1);
if (val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN) {
trans_pcie->me_present =
!!(val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT);
return;
}
val = iwl_read32(trans, CSR_HW_IF_CONFIG_REG);
if (val & (CSR_HW_IF_CONFIG_REG_ME_OWN |
CSR_HW_IF_CONFIG_REG_IAMT_UP)) {
trans_pcie->me_present = 1;
return;
}
/* recheck again later, ME might still be initializing */
schedule_delayed_work(&trans_pcie->me_recheck_wk, HZ);
}
int iwl_pci_gen1_2_probe(struct pci_dev *pdev,
const struct pci_device_id *ent,
const struct iwl_mac_cfg *mac_cfg,
u8 __iomem *hw_base, u32 hw_rev)
{
const struct iwl_dev_info *dev_info;
struct iwl_trans_info info = {
.hw_id = (pdev->device << 16) + pdev->subsystem_device,
.hw_rev = hw_rev,
};
struct iwl_trans *iwl_trans;
struct iwl_trans_pcie *trans_pcie;
int ret;
iwl_trans = iwl_trans_pcie_alloc(pdev, mac_cfg, &info, hw_base);
if (IS_ERR(iwl_trans))
return PTR_ERR(iwl_trans);
trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
iwl_trans_pcie_check_product_reset_status(pdev);
iwl_trans_pcie_check_product_reset_mode(pdev);
/* set the things we know so far for the grab NIC access */
iwl_trans_set_info(iwl_trans, &info);
/*
* Let's try to grab NIC access early here. Sometimes, NICs may
* fail to initialize, and if that happens it's better if we see
* issues early on (and can reprobe, per the logic inside), than
* first trying to load the firmware etc. and potentially only
* detecting any problems when the first interface is brought up.
*/
ret = iwl_pcie_prepare_card_hw(iwl_trans);
if (!ret) {
ret = iwl_finish_nic_init(iwl_trans);
if (ret)
goto out_free_trans;
if (iwl_trans_grab_nic_access(iwl_trans)) {
get_crf_id(iwl_trans, &info);
/* all good */
iwl_trans_release_nic_access(iwl_trans);
} else {
ret = -EIO;
goto out_free_trans;
}
}
info.hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID);
/*
* The RF_ID is set to zero in blank OTP so read version to
* extract the RF_ID.
* This is relevant only for family 9000 and up.
*/
if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000 &&
!CSR_HW_RFID_TYPE(info.hw_rf_id) && map_crf_id(iwl_trans, &info)) {
ret = -EINVAL;
goto out_free_trans;
}
IWL_INFO(iwl_trans, "PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n",
pdev->device, pdev->subsystem_device,
info.hw_rev, info.hw_rf_id);
dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device,
CSR_HW_RFID_TYPE(info.hw_rf_id),
CSR_HW_RFID_IS_CDB(info.hw_rf_id),
IWL_SUBDEVICE_RF_ID(pdev->subsystem_device),
IWL_SUBDEVICE_BW_LIM(pdev->subsystem_device),
!iwl_trans->mac_cfg->integrated);
if (dev_info) {
iwl_trans->cfg = dev_info->cfg;
info.name = dev_info->name;
}
#if IS_ENABLED(CONFIG_IWLMVM)
/*
* special-case 7265D, it has the same PCI IDs.
*
* Note that because we already pass the cfg to the transport above,
* all the parameters that the transport uses must, until that is
* changed, be identical to the ones in the 7265D configuration.
*/
if (iwl_trans->cfg == &iwl7265_cfg &&
(info.hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D)
iwl_trans->cfg = &iwl7265d_cfg;
#endif
if (!iwl_trans->cfg) {
pr_err("No config found for PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n",
pdev->device, pdev->subsystem_device,
info.hw_rev, info.hw_rf_id);
ret = -EINVAL;
goto out_free_trans;
}
IWL_INFO(iwl_trans, "Detected %s\n", info.name);
if (iwl_trans->mac_cfg->mq_rx_supported) {
if (WARN_ON(!iwl_trans->cfg->num_rbds)) {
ret = -EINVAL;
goto out_free_trans;
}
trans_pcie->num_rx_bufs = iwl_trans_get_num_rbds(iwl_trans);
} else {
trans_pcie->num_rx_bufs = RX_QUEUE_SIZE;
}
if (!iwl_trans->mac_cfg->integrated) {
u16 link_status;
pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &link_status);
info.pcie_link_speed =
u16_get_bits(link_status, PCI_EXP_LNKSTA_CLS);
}
iwl_trans_set_info(iwl_trans, &info);
pci_set_drvdata(pdev, iwl_trans);
iwl_pcie_check_me_status(iwl_trans);
/* try to get ownership so that we'll know if we don't own it */
iwl_pcie_prepare_card_hw(iwl_trans);
iwl_trans->drv = iwl_drv_start(iwl_trans);
if (IS_ERR(iwl_trans->drv)) {
ret = PTR_ERR(iwl_trans->drv);
goto out_free_trans;
}
/* register transport layer debugfs here */
iwl_trans_pcie_dbgfs_register(iwl_trans);
return 0;
out_free_trans:
iwl_trans_pcie_free(iwl_trans);
return ret;
}

View File

@ -590,7 +590,7 @@ static void iwl_pcie_tx_stop_fh(struct iwl_trans *trans)
}
/* Wait for DMA channels to be idle */
ret = iwl_poll_bit(trans, FH_TSSR_TX_STATUS_REG, mask, mask, 5000);
ret = iwl_poll_bits(trans, FH_TSSR_TX_STATUS_REG, mask, 5000);
if (ret < 0)
IWL_ERR(trans,
"Failing on timeout while stopping DMA channel %d [0x%08x]\n",

View File

@ -31,15 +31,6 @@ static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *d
pos += scnprintf(buf + pos, sizeof(buf) - pos,
" bw_limit=*");
if (di->match_rf_step)
pos += scnprintf(buf + pos, sizeof(buf) - pos,
" rf_step=%c",
di->rf_step == SILICON_Z_STEP ? 'Z' :
'A' + di->rf_step);
else
pos += scnprintf(buf + pos, sizeof(buf) - pos,
" rf_step=*");
if (di->match_rf_id)
pos += scnprintf(buf + pos, sizeof(buf) - pos,
" rf_id=0x%x", di->rf_id);
@ -54,6 +45,13 @@ static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *d
pos += scnprintf(buf + pos, sizeof(buf) - pos,
" cdb=*");
if (di->match_discrete)
pos += scnprintf(buf + pos, sizeof(buf) - pos,
" discrete=%d",
di->discrete);
else
pos += scnprintf(buf + pos, sizeof(buf) - pos,
" discrete=*");
printk(KERN_DEBUG "%sdev=%04x subdev=%04x/%04x%s\n",
pfx, di->device, di->subdevice, subdevice_mask, buf);
@ -70,7 +68,7 @@ static void devinfo_table_order(struct kunit *test)
ret = iwl_pci_find_dev_info(di->device, di->subdevice,
di->rf_type, di->cdb,
di->rf_id, di->bw_limit,
di->rf_step);
di->discrete);
if (!ret) {
iwl_pci_print_dev_info("No entry found for: ", di);
KUNIT_FAIL(test,
@ -85,6 +83,32 @@ static void devinfo_table_order(struct kunit *test)
}
}
static void devinfo_discrete_match(struct kunit *test)
{
/*
* Validate that any entries with discrete/integrated match have
* the same config with the value inverted (if they match at all.)
*/
for (int idx = 0; idx < iwl_dev_info_table_size; idx++) {
const struct iwl_dev_info *di = &iwl_dev_info_table[idx];
const struct iwl_dev_info *ret;
if (!di->match_discrete)
continue;
ret = iwl_pci_find_dev_info(di->device, di->subdevice,
di->rf_type, di->cdb,
di->rf_id, di->bw_limit,
!di->discrete);
if (!ret)
continue;
KUNIT_EXPECT_PTR_EQ(test, di->cfg, ret->cfg);
/* and check the name is different, that'd be the point of it */
KUNIT_EXPECT_NE(test, strcmp(di->name, ret->name), 0);
}
}
static void devinfo_names(struct kunit *test)
{
int idx;
@ -216,6 +240,7 @@ static void devinfo_no_mac_cfg_dups(struct kunit *test)
static struct kunit_case devinfo_test_cases[] = {
KUNIT_CASE(devinfo_table_order),
KUNIT_CASE(devinfo_discrete_match),
KUNIT_CASE(devinfo_names),
KUNIT_CASE(devinfo_no_cfg_dups),
KUNIT_CASE(devinfo_no_name_dups),

View File

@ -173,13 +173,13 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw,
if (!mlink)
goto out;
if (link_conf != &vif->bss_conf)
if (mlink != (struct mt76_vif_link *)vif->drv_priv)
rcu_assign_pointer(mvif->link[link_id], NULL);
dev->drv->vif_link_remove(phy, vif, link_conf, mlink);
mlink->ctx = NULL;
if (link_conf != &vif->bss_conf)
if (mlink != (struct mt76_vif_link *)vif->drv_priv)
kfree_rcu(mlink, rcu_head);
out:

View File

@ -643,10 +643,8 @@ mt76_dma_rx_fill_buf(struct mt76_dev *dev, struct mt76_queue *q,
while (q->queued < q->ndesc - 1) {
struct mt76_queue_buf qbuf = {};
enum dma_data_direction dir;
dma_addr_t addr;
int offset;
void *buf = NULL;
int offset;
if (mt76_queue_is_wed_rro_ind(q))
goto done;
@ -655,11 +653,8 @@ mt76_dma_rx_fill_buf(struct mt76_dev *dev, struct mt76_queue *q,
if (!buf)
break;
addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset;
dir = page_pool_get_dma_dir(q->page_pool);
dma_sync_single_for_device(dev->dma_dev, addr, len, dir);
qbuf.addr = addr + q->buf_offset;
qbuf.addr = page_pool_get_dma_addr(virt_to_head_page(buf)) +
offset + q->buf_offset;
done:
qbuf.len = len - q->buf_offset;
qbuf.skip_unmap = false;

View File

@ -78,6 +78,10 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
unsigned long expires;
int ret, seq;
if (mt76_is_sdio(dev))
if (test_bit(MT76_RESET, &dev->phy.state) && atomic_read(&dev->bus_hung))
return -EIO;
if (ret_skb)
*ret_skb = NULL;

View File

@ -983,6 +983,8 @@ struct mt76_dev {
struct mt76_usb usb;
struct mt76_sdio sdio;
};
atomic_t bus_hung;
};
/* per-phy stats. */
@ -1865,6 +1867,9 @@ mt76_vif_link(struct mt76_dev *dev, struct ieee80211_vif *vif, int link_id)
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
struct mt76_vif_data *mvif = mlink->mvif;
if (!link_id)
return mlink;
return mt76_dereference(mvif->link[link_id], dev);
}
@ -1875,7 +1880,7 @@ mt76_vif_conf_link(struct mt76_dev *dev, struct ieee80211_vif *vif,
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
struct mt76_vif_data *mvif = mlink->mvif;
if (link_conf == &vif->bss_conf)
if (link_conf == &vif->bss_conf || !link_conf->link_id)
return mlink;
return mt76_dereference(mvif->link[link_conf->link_id], dev);

View File

@ -197,6 +197,8 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
static void
mt7915_mcu_set_timeout(struct mt76_dev *mdev, int cmd)
{
mdev->mcu.timeout = 5 * HZ;
if ((cmd & __MCU_CMD_FIELD_ID) != MCU_CMD_EXT_CID)
return;
@ -208,6 +210,9 @@ mt7915_mcu_set_timeout(struct mt76_dev *mdev, int cmd)
case MCU_EXT_CMD_BSS_INFO_UPDATE:
mdev->mcu.timeout = 2 * HZ;
return;
case MCU_EXT_CMD_EFUSE_BUFFER_MODE:
mdev->mcu.timeout = 10 * HZ;
return;
default:
break;
}
@ -2110,16 +2115,21 @@ static int mt7915_load_firmware(struct mt7915_dev *dev)
{
int ret;
/* make sure fw is download state */
if (mt7915_firmware_state(dev, false)) {
/* restart firmware once */
mt76_connac_mcu_restart(&dev->mt76);
ret = mt7915_firmware_state(dev, false);
if (ret) {
dev_err(dev->mt76.dev,
"Firmware is not ready for download\n");
return ret;
}
/* Release Semaphore if taken by previous failed attempt */
ret = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false);
if (ret != PATCH_REL_SEM_SUCCESS) {
dev_err(dev->mt76.dev, "Could not release semaphore\n");
/* Continue anyways */
}
/* Always restart MCU firmware */
mt76_connac_mcu_restart(&dev->mt76);
/* Check if MCU is ready */
ret = mt7915_firmware_state(dev, false);
if (ret) {
dev_err(dev->mt76.dev, "Firmware did not enter download state\n");
return ret;
}
ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH));

View File

@ -675,6 +675,8 @@ void mt7921_mac_reset_work(struct work_struct *work)
if (!ret)
break;
}
if (mt76_is_sdio(&dev->mt76) && atomic_read(&dev->mt76.bus_hung))
return;
if (i == 10)
dev_err(dev->mt76.dev, "chip reset failed\n");

View File

@ -150,6 +150,8 @@ static int mt7921s_probe(struct sdio_func *func,
if (ret)
goto error;
atomic_set(&mdev->bus_hung, false);
mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
(mt76_rr(dev, MT_HW_REV) & 0xff);
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);

View File

@ -6,6 +6,8 @@
#include "mt7921.h"
#include "../mt76_connac2_mac.h"
#include "../sdio.h"
#include <linux/mmc/host.h>
#include <linux/kallsyms.h>
static void mt7921s_enable_irq(struct mt76_dev *dev)
{
@ -35,6 +37,9 @@ int mt7921s_wfsys_reset(struct mt792x_dev *dev)
struct mt76_sdio *sdio = &dev->mt76.sdio;
u32 val, status;
if (atomic_read(&dev->mt76.bus_hung))
return 0;
mt7921s_mcu_drv_pmctrl(dev);
sdio_claim_host(sdio->func);
@ -91,11 +96,64 @@ int mt7921s_init_reset(struct mt792x_dev *dev)
return 0;
}
static struct mt76_sdio *msdio;
static void mt7921s_card_reset(struct work_struct *work)
{
struct mmc_host *sdio_host = msdio->func->card->host;
sdio_claim_host(msdio->func);
sdio_release_irq(msdio->func);
sdio_release_host(msdio->func);
mmc_remove_host(sdio_host);
msleep(50);
mmc_add_host(sdio_host);
}
static DECLARE_WORK(sdio_reset_work, mt7921s_card_reset);
static int mt7921s_check_bus(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
int err;
sdio_claim_host(sdio->func);
sdio_readl(dev->sdio.func, MCR_WHCR, &err);
sdio_release_host(sdio->func);
return err;
}
static int mt7921s_host_reset(struct mt792x_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
int err = -1;
if (!atomic_read(&mdev->bus_hung))
err = mt7921s_check_bus(&dev->mt76);
if (err) {
atomic_set(&mdev->bus_hung, true);
msdio = &dev->mt76.sdio;
dev_err(mdev->dev, "SDIO bus problem detected(%d), resetting card!!\n", err);
schedule_work(&sdio_reset_work);
return err;
}
atomic_set(&mdev->bus_hung, false);
return 0;
}
int mt7921s_mac_reset(struct mt792x_dev *dev)
{
int err;
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
mt7921s_host_reset(dev);
if (atomic_read(&dev->mt76.bus_hung))
return 0;
mt76_txq_schedule_all(&dev->mphy);
mt76_worker_disable(&dev->mt76.tx_worker);
set_bit(MT76_MCU_RESET, &dev->mphy.state);

View File

@ -2866,7 +2866,7 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
for (i = 0; i < sreq->n_ssids; i++) {
if (!sreq->ssids[i].ssid_len)
continue;
if (i > MT7925_RNR_SCAN_MAX_BSSIDS)
if (i >= MT7925_RNR_SCAN_MAX_BSSIDS)
break;
ssid->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len);
@ -2883,7 +2883,7 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
mt76_connac_mcu_build_rnr_scan_param(mdev, sreq);
for (j = 0; j < mdev->rnr.bssid_num; j++) {
if (j > MT7925_RNR_SCAN_MAX_BSSIDS)
if (j >= MT7925_RNR_SCAN_MAX_BSSIDS)
break;
tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID,

View File

@ -666,6 +666,7 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw)
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
ieee80211_hw_set(hw, CONNECTION_MONITOR);
ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR);
if (is_mt7921(&dev->mt76))
ieee80211_hw_set(hw, CHANCTX_STA_CSA);

View File

@ -1087,9 +1087,9 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (wcid->offchannel)
mlink = rcu_dereference(mvif->mt76.offchannel_link);
if (!mlink)
mlink = &mvif->deflink.mt76;
mlink = rcu_dereference(mvif->mt76.link[wcid->link_id]);
txp->fw.bss_idx = mlink->idx;
txp->fw.bss_idx = mlink ? mlink->idx : mvif->deflink.mt76.idx;
}
txp->fw.token = cpu_to_le16(id);
@ -1129,15 +1129,14 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
}
static void
mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta,
struct mt76_wcid *wcid, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
struct mt7996_sta_link *msta_link;
struct mt7996_sta *msta;
u16 fc, tid;
if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))
return;
tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
@ -1146,7 +1145,8 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
if (is_8023) {
fc = IEEE80211_FTYPE_DATA |
(sta->wme ? IEEE80211_STYPE_QOS_DATA : IEEE80211_STYPE_DATA);
(link_sta->sta->wme ? IEEE80211_STYPE_QOS_DATA
: IEEE80211_STYPE_DATA);
} else {
/* No need to get precise TID for Action/Management Frame,
* since it will not meet the following Frame Control
@ -1162,19 +1162,16 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
return;
msta = (struct mt7996_sta *)sta->drv_priv;
msta_link = &msta->deflink;
if (!test_and_set_bit(tid, &msta_link->wcid.ampdu_state))
ieee80211_start_tx_ba_session(sta, tid, 0);
if (!test_and_set_bit(tid, &wcid->ampdu_state))
ieee80211_start_tx_ba_session(link_sta->sta, tid, 0);
}
static void
mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
struct ieee80211_sta *sta, struct list_head *free_list)
struct ieee80211_link_sta *link_sta,
struct mt76_wcid *wcid, struct list_head *free_list)
{
struct mt76_dev *mdev = &dev->mt76;
struct mt76_wcid *wcid;
__le32 *txwi;
u16 wcid_idx;
@ -1183,12 +1180,10 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
goto out;
txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
if (sta) {
wcid = (struct mt76_wcid *)sta->drv_priv;
if (link_sta) {
wcid_idx = wcid->idx;
if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
mt7996_tx_check_aggr(sta, t->skb);
mt7996_tx_check_aggr(link_sta, wcid, t->skb);
} else {
wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX);
}
@ -1207,8 +1202,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
struct mt76_dev *mdev = &dev->mt76;
struct mt76_phy *phy2 = mdev->phys[MT_BAND1];
struct mt76_phy *phy3 = mdev->phys[MT_BAND2];
struct ieee80211_link_sta *link_sta = NULL;
struct mt76_txwi_cache *txwi;
struct ieee80211_sta *sta = NULL;
struct mt76_wcid *wcid = NULL;
LIST_HEAD(free_list);
struct sk_buff *skb, *tmp;
@ -1245,7 +1240,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
*/
info = le32_to_cpu(*cur_info);
if (info & MT_TXFREE_INFO_PAIR) {
struct mt7996_sta_link *msta_link;
struct ieee80211_sta *sta;
u16 idx;
idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
@ -1254,9 +1249,11 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
if (!sta)
goto next;
msta_link = container_of(wcid, struct mt7996_sta_link,
wcid);
mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid);
link_sta = rcu_dereference(sta->link[wcid->link_id]);
if (!link_sta)
goto next;
mt76_wcid_add_poll(&dev->mt76, wcid);
next:
/* ver 7 has a new DW with pair = 1, skip it */
if (ver == 7 && ((void *)(cur_info + 1) < end) &&
@ -1289,7 +1286,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
if (!txwi)
continue;
mt7996_txwi_free(dev, txwi, sta, &free_list);
mt7996_txwi_free(dev, txwi, link_sta, wcid,
&free_list);
}
}
@ -1748,7 +1746,7 @@ void mt7996_tx_token_put(struct mt7996_dev *dev)
spin_lock_bh(&dev->mt76.token_lock);
idr_for_each_entry(&dev->mt76.token, txwi, id) {
mt7996_txwi_free(dev, txwi, NULL, NULL);
mt7996_txwi_free(dev, txwi, NULL, NULL, NULL);
dev->mt76.token_count--;
}
spin_unlock_bh(&dev->mt76.token_lock);

View File

@ -960,8 +960,8 @@ mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
}
static void
mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_sta *sta,
unsigned long links)
mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, unsigned long links)
{
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct mt76_dev *mdev = &dev->mt76;
@ -969,6 +969,8 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_sta *sta,
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt7996_sta_link *msta_link = NULL;
struct mt7996_vif_link *link;
struct mt76_phy *mphy;
msta_link = rcu_replace_pointer(msta->link[link_id], msta_link,
lockdep_is_held(&mdev->mutex));
@ -976,6 +978,15 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_sta *sta,
continue;
mt7996_mac_sta_deinit_link(dev, msta_link);
link = mt7996_vif_link(dev, vif, link_id);
if (!link)
continue;
mphy = mt76_vif_link_phy(&link->mt76);
if (!mphy)
continue;
mphy->num_sta--;
if (msta->deflink_id == link_id) {
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
continue;
@ -997,6 +1008,7 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf;
struct ieee80211_link_sta *link_sta;
struct mt7996_vif_link *link;
struct mt76_phy *mphy;
if (rcu_access_pointer(msta->link[link_id]))
continue;
@ -1023,12 +1035,19 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
link_id);
if (err)
goto error_unlink;
mphy = mt76_vif_link_phy(&link->mt76);
if (!mphy) {
err = -EINVAL;
goto error_unlink;
}
mphy->num_sta++;
}
return 0;
error_unlink:
mt7996_mac_sta_remove_links(dev, sta, new_links);
mt7996_mac_sta_remove_links(dev, vif, sta, new_links);
return err;
}
@ -1045,7 +1064,7 @@ mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_lock(&dev->mt76.mutex);
mt7996_mac_sta_remove_links(dev, sta, rem);
mt7996_mac_sta_remove_links(dev, vif, sta, rem);
ret = mt7996_mac_sta_add_links(dev, vif, sta, add);
mutex_unlock(&dev->mt76.mutex);
@ -1054,25 +1073,21 @@ mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
static int
mt7996_mac_sta_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
mt7996_mac_sta_add(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76_dev *mdev = mphy->dev;
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
unsigned long links = sta->mlo ? sta->valid_links : BIT(0);
unsigned long links = sta->valid_links ? sta->valid_links : BIT(0);
int err;
mutex_lock(&mdev->mutex);
mutex_lock(&dev->mt76.mutex);
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
msta->vif = mvif;
err = mt7996_mac_sta_add_links(dev, vif, sta, links);
if (!err)
mphy->num_sta++;
mutex_unlock(&mdev->mutex);
mutex_unlock(&dev->mt76.mutex);
return err;
}
@ -1119,7 +1134,6 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif,
return err;
msta_link->wcid.tx_info |= MT_WCID_TX_INFO_SET;
msta_link->wcid.sta = 1;
break;
case MT76_STA_EVENT_AUTHORIZE:
err = mt7996_mcu_add_sta(dev, link_conf, link_sta,
@ -1151,19 +1165,14 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif,
}
static void
mt7996_mac_sta_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif,
mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76_dev *mdev = mphy->dev;
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
unsigned long links = sta->mlo ? sta->valid_links : BIT(0);
unsigned long links = sta->valid_links ? sta->valid_links : BIT(0);
mutex_lock(&mdev->mutex);
mt7996_mac_sta_remove_links(dev, sta, links);
mphy->num_sta--;
mutex_unlock(&mdev->mutex);
mutex_lock(&dev->mt76.mutex);
mt7996_mac_sta_remove_links(dev, vif, sta, links);
mutex_unlock(&dev->mt76.mutex);
}
static int
@ -1171,20 +1180,16 @@ mt7996_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state)
{
struct mt76_phy *mphy = mt76_vif_phy(hw, vif);
struct mt7996_dev *dev = mt7996_hw_dev(hw);
enum mt76_sta_event ev;
if (!mphy)
return -EINVAL;
if (old_state == IEEE80211_STA_NOTEXIST &&
new_state == IEEE80211_STA_NONE)
return mt7996_mac_sta_add(mphy, vif, sta);
return mt7996_mac_sta_add(dev, vif, sta);
if (old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)
mt7996_mac_sta_remove(mphy, vif, sta);
mt7996_mac_sta_remove(dev, vif, sta);
if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC)
@ -1217,10 +1222,17 @@ static void mt7996_tx(struct ieee80211_hw *hw,
if (vif) {
struct mt7996_vif *mvif = (void *)vif->drv_priv;
struct mt76_vif_link *mlink;
struct mt76_vif_link *mlink = &mvif->deflink.mt76;
mlink = rcu_dereference(mvif->mt76.link[link_id]);
if (mlink && mlink->wcid)
if (link_id < IEEE80211_LINK_UNSPECIFIED)
mlink = rcu_dereference(mvif->mt76.link[link_id]);
if (!mlink) {
ieee80211_free_txskb(hw, skb);
goto unlock;
}
if (mlink->wcid)
wcid = mlink->wcid;
if (mvif->mt76.roc_phy &&
@ -1229,7 +1241,7 @@ static void mt7996_tx(struct ieee80211_hw *hw,
if (mphy->roc_link)
wcid = mphy->roc_link->wcid;
} else {
mphy = mt76_vif_link_phy(&mvif->deflink.mt76);
mphy = mt76_vif_link_phy(mlink);
}
}
@ -1238,7 +1250,7 @@ static void mt7996_tx(struct ieee80211_hw *hw,
goto unlock;
}
if (control->sta) {
if (control->sta && link_id < IEEE80211_LINK_UNSPECIFIED) {
struct mt7996_sta *msta = (void *)control->sta->drv_priv;
struct mt7996_sta_link *msta_link;

View File

@ -2216,15 +2216,15 @@ mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif,
static void
mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
unsigned long links = sta->valid_links;
unsigned int nlinks = hweight16(links);
unsigned int nlinks = hweight16(sta->valid_links);
struct mld_setup_link *mld_setup_link;
struct ieee80211_link_sta *link_sta;
struct sta_rec_mld_setup *mld_setup;
struct mt7996_sta_link *msta_link;
struct ieee80211_vif *vif;
unsigned int link_id;
struct tlv *tlv;
@ -2242,18 +2242,16 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx);
if (nlinks > 1) {
link_id = __ffs(links & ~BIT(msta->deflink_id));
msta_link = mt76_dereference(msta->link[msta->deflink_id],
&dev->mt76);
link_id = __ffs(sta->valid_links & ~BIT(msta->deflink_id));
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
if (!msta_link)
return;
}
mld_setup->seconed_id = cpu_to_le16(msta_link->wcid.idx);
mld_setup->link_num = nlinks;
vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
mld_setup_link = (struct mld_setup_link *)mld_setup->link_info;
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
for_each_sta_active_link(vif, sta, link_sta, link_id) {
struct mt7996_vif_link *link;
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
@ -2345,7 +2343,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev,
mt7996_mcu_sta_muru_tlv(dev, skb, link_conf, link_sta);
if (sta->mlo) {
mt7996_mcu_sta_mld_setup_tlv(dev, skb, sta);
mt7996_mcu_sta_mld_setup_tlv(dev, skb, link_conf->vif,
sta);
mt7996_mcu_sta_eht_mld_tlv(dev, skb, sta);
}
}

View File

@ -112,6 +112,7 @@ mt76s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
if (err < 0) {
dev_err(dev->dev, "sdio read data failed:%d\n", err);
atomic_set(&dev->bus_hung, true);
put_page(page);
return err;
}
@ -234,9 +235,10 @@ static int __mt76s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
sdio_release_host(sdio->func);
if (err)
if (err) {
dev_err(dev->dev, "sdio write failed: %d\n", err);
atomic_set(&dev->bus_hung, true);
}
return err;
}

View File

@ -34,11 +34,10 @@ u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc;
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
int i, len = SKB_WITH_OVERHEAD(q->buf_size);
struct mt76_txwi_cache *t = NULL;
int i;
for (i = 0; i < size; i++) {
enum dma_data_direction dir;
dma_addr_t addr;
u32 offset;
int token;
@ -53,9 +52,6 @@ u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
goto unmap;
addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset;
dir = page_pool_get_dma_dir(q->page_pool);
dma_sync_single_for_device(dev->dma_dev, addr, len, dir);
desc->buf0 = cpu_to_le32(addr);
token = mt76_rx_token_consume(dev, buf, t, addr);
if (token < 0) {

View File

@ -9,7 +9,7 @@
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (c) 2018 - 2024 Intel Corporation
* Copyright (c) 2018 - 2025 Intel Corporation
*/
#ifndef LINUX_IEEE80211_H
@ -2837,11 +2837,12 @@ static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len)
#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000
#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x80000000
#define IEEE80211_6GHZ_CTRL_REG_LPI_AP 0
#define IEEE80211_6GHZ_CTRL_REG_SP_AP 1
#define IEEE80211_6GHZ_CTRL_REG_VLP_AP 2
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP 3
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP 4
#define IEEE80211_6GHZ_CTRL_REG_LPI_AP 0
#define IEEE80211_6GHZ_CTRL_REG_SP_AP 1
#define IEEE80211_6GHZ_CTRL_REG_VLP_AP 2
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP 3
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD 4
#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP 8
/**
* struct ieee80211_he_6ghz_oper - HE 6 GHz operation Information field
@ -2859,13 +2860,31 @@ struct ieee80211_he_6ghz_oper {
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ 2
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ 3
#define IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON 0x4
#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO 0x38
#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO 0x78
u8 control;
u8 ccfs0;
u8 ccfs1;
u8 minrate;
} __packed;
/**
* enum ieee80211_reg_conn_bits - represents Regulatory connectivity field bits.
*
* This enumeration defines bit flags used to represent regulatory connectivity
* field bits.
*
* @IEEE80211_REG_CONN_LPI_VALID: Indicates whether the LPI bit is valid.
* @IEEE80211_REG_CONN_LPI_VALUE: Represents the value of the LPI bit.
* @IEEE80211_REG_CONN_SP_VALID: Indicates whether the SP bit is valid.
* @IEEE80211_REG_CONN_SP_VALUE: Represents the value of the SP bit.
*/
enum ieee80211_reg_conn_bits {
IEEE80211_REG_CONN_LPI_VALID = BIT(0),
IEEE80211_REG_CONN_LPI_VALUE = BIT(1),
IEEE80211_REG_CONN_SP_VALID = BIT(2),
IEEE80211_REG_CONN_SP_VALUE = BIT(3),
};
/* transmit power interpretation type of transmit power envelope element */
enum ieee80211_tx_power_intrpt_type {
IEEE80211_TPE_LOCAL_EIRP,
@ -3847,6 +3866,7 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_FILS_PUBLIC_KEY = 12,
WLAN_EID_EXT_FILS_NONCE = 13,
WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE = 14,
WLAN_EID_EXT_DH_PARAMETER = 32,
WLAN_EID_EXT_HE_CAPABILITY = 35,
WLAN_EID_EXT_HE_OPERATION = 36,
WLAN_EID_EXT_UORA = 37,
@ -3870,6 +3890,8 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_EHT_CAPABILITY = 108,
WLAN_EID_EXT_TID_TO_LINK_MAPPING = 109,
WLAN_EID_EXT_BANDWIDTH_INDICATION = 135,
WLAN_EID_EXT_KNOWN_STA_IDENTIFCATION = 136,
WLAN_EID_EXT_NON_AP_STA_REG_CON = 137,
};
/* Action category code */
@ -5333,6 +5355,13 @@ static inline u16 ieee80211_mle_get_mld_capa_op(const u8 *data)
return get_unaligned_le16(common);
}
/* Defined in Figure 9-1074t in P802.11be_D7.0 */
#define IEEE80211_EHT_ML_EXT_MLD_CAPA_OP_PARAM_UPDATE 0x0001
#define IEEE80211_EHT_ML_EXT_MLD_CAPA_OP_RECO_MAX_LINKS_MASK 0x001e
#define IEEE80211_EHT_ML_EXT_MLD_CAPA_NSTR_UPDATE 0x0020
#define IEEE80211_EHT_ML_EXT_MLD_CAPA_EMLSR_ENA_ON_ONE_LINK 0x0040
#define IEEE80211_EHT_ML_EXT_MLD_CAPA_BTM_MLD_RECO_MULTI_AP 0x0080
/**
* ieee80211_mle_get_ext_mld_capa_op - returns the extended MLD capabilities
* and operations.

View File

@ -2748,15 +2748,16 @@ struct cfg80211_scan_6ghz_params {
* @wiphy: the wiphy this was for
* @scan_start: time (in jiffies) when the scan started
* @wdev: the wireless device to scan for
* @info: (internal) information about completed scan
* @notified: (internal) scan request was notified as done or aborted
* @no_cck: used to send probe requests at non CCK rate in 2GHz band
* @mac_addr: MAC address used with randomisation
* @mac_addr_mask: MAC address mask used with randomisation, bits that
* are 0 in the mask should be randomised, bits that are 1 should
* be taken from the @mac_addr
* @scan_6ghz: relevant for split scan request only,
* true if this is the second scan request
* true if this is a 6 GHz scan request
* @first_part: %true if this is the first part of a split scan request or a
* scan that was not split. May be %true for a @scan_6ghz scan if no other
* channels were requested
* @n_6ghz_params: number of 6 GHz params
* @scan_6ghz_params: 6 GHz params
* @bssid: BSSID to scan for (most commonly, the wildcard BSSID)
@ -2780,14 +2781,11 @@ struct cfg80211_scan_request {
u8 mac_addr[ETH_ALEN] __aligned(2);
u8 mac_addr_mask[ETH_ALEN] __aligned(2);
u8 bssid[ETH_ALEN] __aligned(2);
/* internal */
struct wiphy *wiphy;
unsigned long scan_start;
struct cfg80211_scan_info info;
bool notified;
bool no_cck;
bool scan_6ghz;
bool first_part;
u32 n_6ghz_params;
struct cfg80211_scan_6ghz_params *scan_6ghz_params;
s8 tsf_report_link_id;

View File

@ -2852,8 +2852,6 @@ struct ieee80211_txq {
*
* @IEEE80211_HW_DISALLOW_PUNCTURING: HW requires disabling puncturing in EHT
* and connecting with a lower bandwidth instead
* @IEEE80211_HW_DISALLOW_PUNCTURING_5GHZ: HW requires disabling puncturing in
* EHT in 5 GHz and connecting with a lower bandwidth instead
*
* @IEEE80211_HW_HANDLES_QUIET_CSA: HW/driver handles quieting for CSA, so
* no need to stop queues. This really should be set by a driver that
@ -2923,7 +2921,6 @@ enum ieee80211_hw_flags {
IEEE80211_HW_DETECTS_COLOR_COLLISION,
IEEE80211_HW_MLO_MCAST_MULTI_LINK_TX,
IEEE80211_HW_DISALLOW_PUNCTURING,
IEEE80211_HW_DISALLOW_PUNCTURING_5GHZ,
IEEE80211_HW_HANDLES_QUIET_CSA,
IEEE80211_HW_STRICT,
@ -4313,6 +4310,8 @@ struct ieee80211_prep_tx_info {
* @mgd_complete_tx: Notify the driver that the response frame for a previously
* transmitted frame announced with @mgd_prepare_tx was received, the data
* is filled similarly to @mgd_prepare_tx though the duration is not used.
* Note that this isn't always called for each mgd_prepare_tx() call, for
* example for SAE the 'confirm' messages can be on the air in any order.
*
* @mgd_protect_tdls_discover: Protect a TDLS discovery session. After sending
* a TDLS discovery-request, we expect a reply to arrive on the AP's
@ -4477,6 +4476,8 @@ struct ieee80211_prep_tx_info {
* new links bitmaps may be 0 if going from/to a non-MLO situation.
* The @old array contains pointers to the old bss_conf structures
* that were already removed, in case they're needed.
* Note that removal of link should always succeed, so the return value
* will be ignored in a removal only case.
* This callback can sleep.
* @change_sta_links: Change the valid links of a station, similar to
* @change_vif_links. This callback can sleep.

View File

@ -4,7 +4,7 @@
*
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2018 - 2019, 2021-2024 Intel Corporation
* Copyright (C) 2018 - 2019, 2021-2025 Intel Corporation
*/
#include <linux/debugfs.h>
@ -490,7 +490,6 @@ static const char *hw_flag_names[] = {
FLAG(DETECTS_COLOR_COLLISION),
FLAG(MLO_MCAST_MULTI_LINK_TX),
FLAG(DISALLOW_PUNCTURING),
FLAG(DISALLOW_PUNCTURING_5GHZ),
FLAG(HANDLES_QUIET_CSA),
FLAG(STRICT),
#undef FLAG

View File

@ -2642,6 +2642,8 @@ int ieee80211_put_eht_cap(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata,
const struct ieee80211_supported_band *sband,
const struct ieee80211_conn_settings *conn);
int ieee80211_put_reg_conn(struct sk_buff *skb,
enum ieee80211_channel_flags flags);
/* channel management */
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,

View File

@ -2,7 +2,7 @@
/*
* MLO link handling
*
* Copyright (C) 2022-2024 Intel Corporation
* Copyright (C) 2022-2025 Intel Corporation
*/
#include <linux/slab.h>
#include <linux/kernel.h>
@ -368,6 +368,13 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
ieee80211_update_apvlan_links(sdata);
}
/*
* Ignore errors if we are only removing links as removal should
* always succeed
*/
if (!new_links)
ret = 0;
if (ret) {
/* restore config */
memcpy(sdata->link, old_data, sizeof(old_data));

View File

@ -776,10 +776,6 @@ static bool ieee80211_chandef_usable(struct ieee80211_sub_if_data *sdata,
ieee80211_hw_check(&sdata->local->hw, DISALLOW_PUNCTURING))
return false;
if (chandef->punctured && chandef->chan->band == NL80211_BAND_5GHZ &&
ieee80211_hw_check(&sdata->local->hw, DISALLOW_PUNCTURING_5GHZ))
return false;
return true;
}
@ -1645,6 +1641,30 @@ static size_t ieee80211_add_before_he_elems(struct sk_buff *skb,
return noffset;
}
static size_t ieee80211_add_before_reg_conn(struct sk_buff *skb,
const u8 *elems, size_t elems_len,
size_t offset)
{
static const u8 before_reg_conn[] = {
/*
* no need to list the ones split off before HE
* or generated here
*/
WLAN_EID_EXTENSION, WLAN_EID_EXT_DH_PARAMETER,
WLAN_EID_EXTENSION, WLAN_EID_EXT_KNOWN_STA_IDENTIFCATION,
};
size_t noffset;
if (!elems_len)
return offset;
noffset = ieee80211_ie_split(elems, elems_len, before_reg_conn,
ARRAY_SIZE(before_reg_conn), offset);
skb_put_data(skb, elems + offset, noffset - offset);
return noffset;
}
#define PRESENT_ELEMS_MAX 8
#define PRESENT_ELEM_EXT_OFFS 0x100
@ -1805,6 +1825,22 @@ ieee80211_add_link_elems(struct ieee80211_sub_if_data *sdata,
ieee80211_put_he_6ghz_cap(skb, sdata, smps_mode);
}
/*
* if present, add any custom IEs that go before regulatory
* connectivity element
*/
offset = ieee80211_add_before_reg_conn(skb, extra_elems,
extra_elems_len, offset);
if (sband->band == NL80211_BAND_6GHZ) {
/*
* as per Section E.2.7 of IEEE 802.11 REVme D7.0, non-AP STA
* capable of operating on the 6 GHz band shall transmit
* regulatory connectivity element.
*/
ieee80211_put_reg_conn(skb, chan->flags);
}
/*
* careful - need to know about all the present elems before
* calling ieee80211_assoc_add_ml_elem(), so add this one if
@ -1943,14 +1979,7 @@ ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata,
}
skb_put_data(skb, &mld_capa_ops, sizeof(mld_capa_ops));
/* Many APs have broken parsing of the extended MLD capa/ops field,
* dropping (re-)association request frames or replying with association
* response with a failure status if it's present. Without a clear
* indication as to whether the AP supports parsing this field or not do
* not include it in the common information unless strict mode is set.
*/
if (ieee80211_hw_check(&local->hw, STRICT) &&
assoc_data->ext_mld_capa_ops) {
if (assoc_data->ext_mld_capa_ops) {
ml_elem->control |=
cpu_to_le16(IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP);
common->len += 2;
@ -2381,9 +2410,26 @@ static void ieee80211_csa_switch_work(struct wiphy *wiphy,
* update cfg80211 directly.
*/
if (!ieee80211_vif_link_active(&sdata->vif, link->link_id)) {
struct link_sta_info *link_sta;
struct sta_info *ap_sta;
link->conf->chanreq = link->csa.chanreq;
cfg80211_ch_switch_notify(sdata->dev, &link->csa.chanreq.oper,
link->link_id);
link->conf->csa_active = false;
ap_sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
if (WARN_ON(!ap_sta))
return;
link_sta = wiphy_dereference(wiphy,
ap_sta->link[link->link_id]);
if (WARN_ON(!link_sta))
return;
link_sta->pub->bandwidth =
_ieee80211_sta_cur_vht_bw(link_sta,
&link->csa.chanreq.oper);
return;
}
@ -4734,6 +4780,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_prep_tx_info info = {
.subtype = IEEE80211_STYPE_AUTH,
};
bool sae_need_confirm = false;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
@ -4779,6 +4826,8 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
jiffies + IEEE80211_AUTH_WAIT_SAE_RETRY;
ifmgd->auth_data->timeout_started = true;
run_again(sdata, ifmgd->auth_data->timeout);
if (auth_transaction == 1)
sae_need_confirm = true;
goto notify_driver;
}
@ -4821,6 +4870,9 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
ifmgd->auth_data->expected_transaction == 2)) {
if (!ieee80211_mark_sta_auth(sdata))
return; /* ignore frame -- wait for timeout */
} else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
auth_transaction == 1) {
sae_need_confirm = true;
} else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
auth_transaction == 2) {
sdata_info(sdata, "SAE peer confirmed\n");
@ -4829,7 +4881,8 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
notify_driver:
drv_mgd_complete_tx(sdata->local, sdata, &info);
if (!sae_need_confirm)
drv_mgd_complete_tx(sdata->local, sdata, &info);
}
#define case_WLAN(type) \
@ -5925,6 +5978,7 @@ ieee80211_ap_power_type(u8 control)
return IEEE80211_REG_LPI_AP;
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD:
return IEEE80211_REG_SP_AP;
case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
return IEEE80211_REG_VLP_AP;
@ -8698,21 +8752,33 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
bool have_sta = false;
bool mlo;
int err;
u16 new_links;
if (link_id >= 0) {
mlo = true;
if (WARN_ON(!ap_mld_addr))
return -EINVAL;
err = ieee80211_vif_set_links(sdata, BIT(link_id), 0);
new_links = BIT(link_id);
} else {
if (WARN_ON(ap_mld_addr))
return -EINVAL;
ap_mld_addr = cbss->bssid;
err = ieee80211_vif_set_links(sdata, 0, 0);
new_links = 0;
link_id = 0;
mlo = false;
}
if (assoc) {
rcu_read_lock();
have_sta = sta_info_get(sdata, ap_mld_addr);
rcu_read_unlock();
}
if (mlo && !have_sta &&
WARN_ON(sdata->vif.valid_links || sdata->vif.active_links))
return -EINVAL;
err = ieee80211_vif_set_links(sdata, new_links, 0);
if (err)
return err;
@ -8733,12 +8799,6 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
goto out_err;
}
if (assoc) {
rcu_read_lock();
have_sta = sta_info_get(sdata, ap_mld_addr);
rcu_read_unlock();
}
if (!have_sta) {
if (mlo)
new_sta = sta_info_alloc_with_link(sdata, ap_mld_addr,
@ -9338,6 +9398,39 @@ ieee80211_mgd_get_ap_ht_vht_capa(struct ieee80211_sub_if_data *sdata,
return err;
}
static bool
ieee80211_mgd_assoc_bss_has_mld_ext_capa_ops(struct cfg80211_assoc_request *req)
{
const struct cfg80211_bss_ies *ies;
struct cfg80211_bss *bss;
const struct element *ml;
/* not an MLO connection if link_id < 0, so irrelevant */
if (req->link_id < 0)
return false;
bss = req->links[req->link_id].bss;
guard(rcu)();
ies = rcu_dereference(bss->ies);
for_each_element_extid(ml, WLAN_EID_EXT_EHT_MULTI_LINK,
ies->data, ies->len) {
const struct ieee80211_multi_link_elem *mle;
if (!ieee80211_mle_type_ok(ml->data + 1,
IEEE80211_ML_CONTROL_TYPE_BASIC,
ml->datalen - 1))
continue;
mle = (void *)(ml->data + 1);
if (mle->control & cpu_to_le16(IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP))
return true;
}
return false;
}
int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
struct cfg80211_assoc_request *req)
{
@ -9390,7 +9483,17 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
else
memcpy(assoc_data->ap_addr, cbss->bssid, ETH_ALEN);
assoc_data->ext_mld_capa_ops = cpu_to_le16(req->ext_mld_capa_ops);
/*
* Many APs have broken parsing of the extended MLD capa/ops field,
* dropping (re-)association request frames or replying with association
* response with a failure status if it's present.
* Set our value from the userspace request only in strict mode or if
* the AP also had that field present.
*/
if (ieee80211_hw_check(&local->hw, STRICT) ||
ieee80211_mgd_assoc_bss_has_mld_ext_capa_ops(req))
assoc_data->ext_mld_capa_ops =
cpu_to_le16(req->ext_mld_capa_ops);
if (ifmgd->associated) {
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
@ -10033,7 +10136,6 @@ void ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata,
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
if (!add_links_data->link[link_id].bss ||
!(sdata->u.mgd.reconf.added_links & BIT(link_id)))
continue;
valid_links |= BIT(link_id);

View File

@ -4245,10 +4245,16 @@ static bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx,
rx->link_sta = NULL;
}
if (link_id < 0)
rx->link = &rx->sdata->deflink;
else if (!ieee80211_rx_data_set_link(rx, link_id))
if (link_id < 0) {
if (ieee80211_vif_is_mld(&rx->sdata->vif) &&
sta && !sta->sta.valid_links)
rx->link =
rcu_dereference(rx->sdata->link[sta->deflink.link_id]);
else
rx->link = &rx->sdata->deflink;
} else if (!ieee80211_rx_data_set_link(rx, link_id)) {
return false;
}
return true;
}

View File

@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2013-2015 Intel Mobile Communications GmbH
* Copyright 2016-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2024 Intel Corporation
* Copyright (C) 2018-2025 Intel Corporation
*/
#include <linux/if_arp.h>
@ -800,6 +800,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
local->hw_scan_req->req.scan_6ghz_params =
req->scan_6ghz_params;
local->hw_scan_req->req.scan_6ghz = req->scan_6ghz;
local->hw_scan_req->req.first_part = req->first_part;
/*
* After allocating local->hw_scan_req, we must

View File

@ -4,7 +4,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015 - 2017 Intel Deutschland GmbH
* Copyright (C) 2018-2024 Intel Corporation
* Copyright (C) 2018-2025 Intel Corporation
*/
#include <linux/module.h>
@ -729,6 +729,7 @@ __sta_info_alloc(struct ieee80211_sub_if_data *sdata,
IEEE80211_RATE_MANDATORY_G;
break;
case NL80211_BAND_5GHZ:
case NL80211_BAND_6GHZ:
mandatory = IEEE80211_RATE_MANDATORY_A;
break;
case NL80211_BAND_60GHZ:

View File

@ -2556,6 +2556,23 @@ int ieee80211_put_he_cap(struct sk_buff *skb,
return 0;
}
int ieee80211_put_reg_conn(struct sk_buff *skb,
enum ieee80211_channel_flags flags)
{
u8 reg_conn = IEEE80211_REG_CONN_LPI_VALID |
IEEE80211_REG_CONN_LPI_VALUE |
IEEE80211_REG_CONN_SP_VALID;
if (!(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT))
reg_conn |= IEEE80211_REG_CONN_SP_VALUE;
skb_put_u8(skb, WLAN_EID_EXTENSION);
skb_put_u8(skb, 1 + sizeof(reg_conn));
skb_put_u8(skb, WLAN_EID_EXT_NON_AP_STA_REG_CON);
skb_put_u8(skb, reg_conn);
return 0;
}
int ieee80211_put_he_6ghz_cap(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode)

View File

@ -239,7 +239,7 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
rdev->opencount--;
if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
if (rdev->scan_req && rdev->scan_req->req.wdev == wdev) {
if (WARN_ON(!rdev->scan_req->notified &&
(!rdev->int_scan_req ||
!rdev->int_scan_req->notified)))
@ -1574,7 +1574,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
case NETDEV_DOWN:
wiphy_lock(&rdev->wiphy);
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
if (rdev->scan_req && rdev->scan_req->req.wdev == wdev) {
if (WARN_ON(!rdev->scan_req->notified &&
(!rdev->int_scan_req ||
!rdev->int_scan_req->notified)))

View File

@ -21,6 +21,13 @@
#define WIPHY_IDX_INVALID -1
struct cfg80211_scan_request_int {
struct cfg80211_scan_info info;
bool notified;
/* must be last - variable members */
struct cfg80211_scan_request req;
};
struct cfg80211_registered_device {
const struct cfg80211_ops *ops;
struct list_head list;
@ -70,8 +77,8 @@ struct cfg80211_registered_device {
struct rb_root bss_tree;
u32 bss_generation;
u32 bss_entries;
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
struct cfg80211_scan_request *int_scan_req;
struct cfg80211_scan_request_int *scan_req; /* protected by RTNL */
struct cfg80211_scan_request_int *int_scan_req;
struct sk_buff *scan_msg;
struct list_head sched_scan_req_list;
time64_t suspend_at;

View File

@ -352,8 +352,25 @@ cfg80211_mlme_check_mlo_compat(const struct ieee80211_multi_link_elem *mle_a,
return -EINVAL;
}
if (ieee80211_mle_get_ext_mld_capa_op((const u8 *)mle_a) !=
ieee80211_mle_get_ext_mld_capa_op((const u8 *)mle_b)) {
/*
* Only verify the values in Extended MLD Capabilities that are
* not reserved when transmitted by an AP (and expected to remain the
* same over time).
* The Recommended Max Simultaneous Links subfield in particular is
* reserved when included in a unicast Probe Response frame and may
* also change when the AP adds/removes links. The BTM MLD
* Recommendation For Multiple APs Support subfield is reserved when
* transmitted by an AP. All other bits are currently reserved.
* See IEEE P802.11be/D7.0, Table 9-417o.
*/
if ((ieee80211_mle_get_ext_mld_capa_op((const u8 *)mle_a) &
(IEEE80211_EHT_ML_EXT_MLD_CAPA_OP_PARAM_UPDATE |
IEEE80211_EHT_ML_EXT_MLD_CAPA_NSTR_UPDATE |
IEEE80211_EHT_ML_EXT_MLD_CAPA_EMLSR_ENA_ON_ONE_LINK)) !=
(ieee80211_mle_get_ext_mld_capa_op((const u8 *)mle_b) &
(IEEE80211_EHT_ML_EXT_MLD_CAPA_OP_PARAM_UPDATE |
IEEE80211_EHT_ML_EXT_MLD_CAPA_NSTR_UPDATE |
IEEE80211_EHT_ML_EXT_MLD_CAPA_EMLSR_ENA_ON_ONE_LINK))) {
NL_SET_ERR_MSG(extack,
"extended link MLD capabilities/ops mismatch");
return -EINVAL;

View File

@ -9811,34 +9811,12 @@ static bool nl80211_check_scan_feat(struct wiphy *wiphy, u32 flags, u32 flag,
static int
nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
void *request, struct nlattr **attrs,
bool is_sched_scan)
struct nlattr **attrs, u8 *mac_addr, u8 *mac_addr_mask,
u32 *flags, enum nl80211_feature_flags randomness_flag)
{
u8 *mac_addr, *mac_addr_mask;
u32 *flags;
enum nl80211_feature_flags randomness_flag;
if (!attrs[NL80211_ATTR_SCAN_FLAGS])
return 0;
if (is_sched_scan) {
struct cfg80211_sched_scan_request *req = request;
randomness_flag = wdev ?
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR :
NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
flags = &req->flags;
mac_addr = req->mac_addr;
mac_addr_mask = req->mac_addr_mask;
} else {
struct cfg80211_scan_request *req = request;
randomness_flag = NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
flags = &req->flags;
mac_addr = req->mac_addr;
mac_addr_mask = req->mac_addr_mask;
}
*flags = nla_get_u32(attrs[NL80211_ATTR_SCAN_FLAGS]);
if (((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
@ -9887,11 +9865,35 @@ nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
return 0;
}
static int
nl80211_check_scan_flags_sched(struct wiphy *wiphy, struct wireless_dev *wdev,
struct nlattr **attrs,
struct cfg80211_sched_scan_request *req)
{
return nl80211_check_scan_flags(wiphy, wdev, attrs,
req->mac_addr, req->mac_addr_mask,
&req->flags,
wdev ? NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR :
NL80211_FEATURE_ND_RANDOM_MAC_ADDR);
}
static int
nl80211_check_scan_flags_reg(struct wiphy *wiphy, struct wireless_dev *wdev,
struct nlattr **attrs,
struct cfg80211_scan_request_int *req)
{
return nl80211_check_scan_flags(wiphy, wdev, attrs,
req->req.mac_addr,
req->req.mac_addr_mask,
&req->req.flags,
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR);
}
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev = info->user_ptr[1];
struct cfg80211_scan_request *request;
struct cfg80211_scan_request_int *request;
struct nlattr *scan_freqs = NULL;
bool scan_freqs_khz = false;
struct nlattr *attr;
@ -9943,21 +9945,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (ie_len > wiphy->max_scan_ie_len)
return -EINVAL;
size = struct_size(request, channels, n_channels);
size = struct_size(request, req.channels, n_channels);
ssids_offset = size;
size = size_add(size, array_size(sizeof(*request->ssids), n_ssids));
size = size_add(size, array_size(sizeof(*request->req.ssids), n_ssids));
ie_offset = size;
size = size_add(size, ie_len);
request = kzalloc(size, GFP_KERNEL);
if (!request)
return -ENOMEM;
request->n_channels = n_channels;
request->req.n_channels = n_channels;
if (n_ssids)
request->ssids = (void *)request + ssids_offset;
request->n_ssids = n_ssids;
request->req.ssids = (void *)request + ssids_offset;
request->req.n_ssids = n_ssids;
if (ie_len)
request->ie = (void *)request + ie_offset;
request->req.ie = (void *)request + ie_offset;
i = 0;
if (scan_freqs) {
@ -9980,7 +9982,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
!cfg80211_wdev_channel_allowed(wdev, chan))
continue;
request->channels[i] = chan;
request->req.channels[i] = chan;
i++;
}
} else {
@ -10001,7 +10003,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
!cfg80211_wdev_channel_allowed(wdev, chan))
continue;
request->channels[i] = chan;
request->req.channels[i] = chan;
i++;
}
}
@ -10012,10 +10014,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
goto out_free;
}
request->n_channels = i;
request->req.n_channels = i;
for (i = 0; i < request->n_channels; i++) {
struct ieee80211_channel *chan = request->channels[i];
for (i = 0; i < request->req.n_channels; i++) {
struct ieee80211_channel *chan = request->req.channels[i];
/* if we can go off-channel to the target channel we're good */
if (cfg80211_off_channel_oper_allowed(wdev, chan))
@ -10034,22 +10036,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
err = -EINVAL;
goto out_free;
}
request->ssids[i].ssid_len = nla_len(attr);
memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
request->req.ssids[i].ssid_len = nla_len(attr);
memcpy(request->req.ssids[i].ssid,
nla_data(attr), nla_len(attr));
i++;
}
}
if (info->attrs[NL80211_ATTR_IE]) {
request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
memcpy((void *)request->ie,
request->req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
memcpy((void *)request->req.ie,
nla_data(info->attrs[NL80211_ATTR_IE]),
request->ie_len);
request->req.ie_len);
}
for (i = 0; i < NUM_NL80211_BANDS; i++)
if (wiphy->bands[i])
request->rates[i] =
request->req.rates[i] =
(1 << wiphy->bands[i]->n_bitrates) - 1;
if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
@ -10069,25 +10072,24 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
err = ieee80211_get_ratemask(wiphy->bands[band],
nla_data(attr),
nla_len(attr),
&request->rates[band]);
&request->req.rates[band]);
if (err)
goto out_free;
}
}
if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
request->duration =
request->req.duration =
nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
request->duration_mandatory =
request->req.duration_mandatory =
nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
}
err = nl80211_check_scan_flags(wiphy, wdev, request, info->attrs,
false);
err = nl80211_check_scan_flags_reg(wiphy, wdev, info->attrs, request);
if (err)
goto out_free;
request->no_cck =
request->req.no_cck =
nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
/* Initial implementation used NL80211_ATTR_MAC to set the specific
@ -10100,19 +10102,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
* (NL80211_ATTR_SCAN_FLAGS is used to enable random MAC address use).
*/
if (info->attrs[NL80211_ATTR_BSSID])
memcpy(request->bssid,
memcpy(request->req.bssid,
nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN);
else if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
else if (!(request->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR) &&
info->attrs[NL80211_ATTR_MAC])
memcpy(request->bssid, nla_data(info->attrs[NL80211_ATTR_MAC]),
memcpy(request->req.bssid,
nla_data(info->attrs[NL80211_ATTR_MAC]),
ETH_ALEN);
else
eth_broadcast_addr(request->bssid);
eth_broadcast_addr(request->req.bssid);
request->tsf_report_link_id = nl80211_link_id_or_invalid(info->attrs);
request->wdev = wdev;
request->wiphy = &rdev->wiphy;
request->scan_start = jiffies;
request->req.tsf_report_link_id =
nl80211_link_id_or_invalid(info->attrs);
request->req.wdev = wdev;
request->req.wiphy = &rdev->wiphy;
request->req.scan_start = jiffies;
rdev->scan_req = request;
err = cfg80211_scan(rdev);
@ -10534,7 +10538,7 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
request->ie_len);
}
err = nl80211_check_scan_flags(wiphy, wdev, request, attrs, true);
err = nl80211_check_scan_flags_sched(wiphy, wdev, attrs, request);
if (err)
goto out_free;
@ -18414,7 +18418,7 @@ void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
static int nl80211_add_scan_req(struct sk_buff *msg,
struct cfg80211_registered_device *rdev)
{
struct cfg80211_scan_request *req = rdev->scan_req;
struct cfg80211_scan_request_int *req = rdev->scan_req;
struct nlattr *nest;
int i;
struct cfg80211_scan_info *info;
@ -18425,19 +18429,20 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
nest = nla_nest_start_noflag(msg, NL80211_ATTR_SCAN_SSIDS);
if (!nest)
goto nla_put_failure;
for (i = 0; i < req->n_ssids; i++) {
if (nla_put(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid))
for (i = 0; i < req->req.n_ssids; i++) {
if (nla_put(msg, i, req->req.ssids[i].ssid_len,
req->req.ssids[i].ssid))
goto nla_put_failure;
}
nla_nest_end(msg, nest);
if (req->flags & NL80211_SCAN_FLAG_FREQ_KHZ) {
if (req->req.flags & NL80211_SCAN_FLAG_FREQ_KHZ) {
nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQ_KHZ);
if (!nest)
goto nla_put_failure;
for (i = 0; i < req->n_channels; i++) {
for (i = 0; i < req->req.n_channels; i++) {
if (nla_put_u32(msg, i,
ieee80211_channel_to_khz(req->channels[i])))
ieee80211_channel_to_khz(req->req.channels[i])))
goto nla_put_failure;
}
nla_nest_end(msg, nest);
@ -18446,19 +18451,20 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
NL80211_ATTR_SCAN_FREQUENCIES);
if (!nest)
goto nla_put_failure;
for (i = 0; i < req->n_channels; i++) {
if (nla_put_u32(msg, i, req->channels[i]->center_freq))
for (i = 0; i < req->req.n_channels; i++) {
if (nla_put_u32(msg, i,
req->req.channels[i]->center_freq))
goto nla_put_failure;
}
nla_nest_end(msg, nest);
}
if (req->ie &&
nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
if (req->req.ie &&
nla_put(msg, NL80211_ATTR_IE, req->req.ie_len, req->req.ie))
goto nla_put_failure;
if (req->flags &&
nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
if (req->req.flags &&
nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->req.flags))
goto nla_put_failure;
info = rdev->int_scan_req ? &rdev->int_scan_req->info :

View File

@ -456,15 +456,15 @@ rdev_set_monitor_channel(struct cfg80211_registered_device *rdev,
}
static inline int rdev_scan(struct cfg80211_registered_device *rdev,
struct cfg80211_scan_request *request)
struct cfg80211_scan_request_int *request)
{
int ret;
if (WARN_ON_ONCE(!request->n_ssids && request->ssids))
if (WARN_ON_ONCE(!request->req.n_ssids && request->req.ssids))
return -EINVAL;
trace_rdev_scan(&rdev->wiphy, request);
ret = rdev->ops->scan(&rdev->wiphy, request);
ret = rdev->ops->scan(&rdev->wiphy, &request->req);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}

View File

@ -53,7 +53,7 @@
#include <linux/list.h>
#include <linux/ctype.h>
#include <linux/nl80211.h>
#include <linux/platform_device.h>
#include <linux/device/faux.h>
#include <linux/verification.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
@ -105,7 +105,7 @@ static struct regulatory_request __rcu *last_request =
(void __force __rcu *)&core_request_world;
/* To trigger userspace events and load firmware */
static struct platform_device *reg_pdev;
static struct faux_device *reg_fdev;
/*
* Central wireless core regulatory domains, we only need two,
@ -583,7 +583,7 @@ static int call_crda(const char *alpha2)
else
pr_debug("Calling CRDA to update world regulatory domain\n");
ret = kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
ret = kobject_uevent_env(&reg_fdev->dev.kobj, KOBJ_CHANGE, env);
if (ret)
return ret;
@ -779,7 +779,7 @@ static bool regdb_has_valid_signature(const u8 *data, unsigned int size)
const struct firmware *sig;
bool result;
if (request_firmware(&sig, "regulatory.db.p7s", &reg_pdev->dev))
if (request_firmware(&sig, "regulatory.db.p7s", &reg_fdev->dev))
return false;
result = verify_pkcs7_signature(data, size, sig->data, sig->size,
@ -1061,7 +1061,7 @@ static int query_regdb_file(const char *alpha2)
return -ENOMEM;
err = request_firmware_nowait(THIS_MODULE, true, "regulatory.db",
&reg_pdev->dev, GFP_KERNEL,
&reg_fdev->dev, GFP_KERNEL,
(void *)alpha2, regdb_fw_cb);
if (err)
kfree(alpha2);
@ -1077,7 +1077,7 @@ int reg_reload_regdb(void)
const struct ieee80211_regdomain *current_regdomain;
struct regulatory_request *request;
err = request_firmware(&fw, "regulatory.db", &reg_pdev->dev);
err = request_firmware(&fw, "regulatory.db", &reg_fdev->dev);
if (err)
return err;
@ -4300,12 +4300,12 @@ static int __init regulatory_init_db(void)
* in that case, don't try to do any further work here as
* it's doomed to lead to crashes.
*/
if (IS_ERR_OR_NULL(reg_pdev))
if (!reg_fdev)
return -EINVAL;
err = load_builtin_regdb_keys();
if (err) {
platform_device_unregister(reg_pdev);
faux_device_destroy(reg_fdev);
return err;
}
@ -4313,7 +4313,7 @@ static int __init regulatory_init_db(void)
err = regulatory_hint_core(cfg80211_world_regdom->alpha2);
if (err) {
if (err == -ENOMEM) {
platform_device_unregister(reg_pdev);
faux_device_destroy(reg_fdev);
return err;
}
/*
@ -4342,9 +4342,9 @@ late_initcall(regulatory_init_db);
int __init regulatory_init(void)
{
reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
if (IS_ERR(reg_pdev))
return PTR_ERR(reg_pdev);
reg_fdev = faux_device_create("regulatory", NULL, NULL);
if (!reg_fdev)
return -ENODEV;
rcu_assign_pointer(cfg80211_regdomain, cfg80211_world_regdom);
@ -4372,9 +4372,9 @@ void regulatory_exit(void)
reset_regdomains(true, NULL);
rtnl_unlock();
dev_set_uevent_suppress(&reg_pdev->dev, true);
dev_set_uevent_suppress(&reg_fdev->dev, true);
platform_device_unregister(reg_pdev);
faux_device_destroy(reg_fdev);
list_for_each_entry_safe(reg_beacon, btmp, &reg_pending_beacons, list) {
list_del(&reg_beacon->list);

View File

@ -782,9 +782,9 @@ cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies,
}
EXPORT_SYMBOL_IF_CFG80211_KUNIT(cfg80211_parse_colocated_ap);
static void cfg80211_scan_req_add_chan(struct cfg80211_scan_request *request,
struct ieee80211_channel *chan,
bool add_to_6ghz)
static void cfg80211_scan_req_add_chan(struct cfg80211_scan_request *request,
struct ieee80211_channel *chan,
bool add_to_6ghz)
{
int i;
u32 n_channels = request->n_channels;
@ -838,30 +838,32 @@ static bool cfg80211_find_ssid_match(struct cfg80211_colocated_ap *ap,
return false;
}
static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev,
bool first_part)
{
u8 i;
struct cfg80211_colocated_ap *ap;
int n_channels, count = 0, err;
struct cfg80211_scan_request *request, *rdev_req = rdev->scan_req;
struct cfg80211_scan_request_int *request, *rdev_req = rdev->scan_req;
LIST_HEAD(coloc_ap_list);
bool need_scan_psc = true;
const struct ieee80211_sband_iftype_data *iftd;
size_t size, offs_ssids, offs_6ghz_params, offs_ies;
rdev_req->scan_6ghz = true;
rdev_req->req.scan_6ghz = true;
rdev_req->req.first_part = first_part;
if (!rdev->wiphy.bands[NL80211_BAND_6GHZ])
return -EOPNOTSUPP;
iftd = ieee80211_get_sband_iftype_data(rdev->wiphy.bands[NL80211_BAND_6GHZ],
rdev_req->wdev->iftype);
rdev_req->req.wdev->iftype);
if (!iftd || !iftd->he_cap.has_he)
return -EOPNOTSUPP;
n_channels = rdev->wiphy.bands[NL80211_BAND_6GHZ]->n_channels;
if (rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ) {
if (rdev_req->req.flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ) {
struct cfg80211_internal_bss *intbss;
spin_lock_bh(&rdev->bss_lock);
@ -883,8 +885,8 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
* This is relevant for ML probe requests when the lower
* band APs have not been discovered.
*/
if (is_broadcast_ether_addr(rdev_req->bssid) ||
!ether_addr_equal(rdev_req->bssid, res->bssid) ||
if (is_broadcast_ether_addr(rdev_req->req.bssid) ||
!ether_addr_equal(rdev_req->req.bssid, res->bssid) ||
res->channel->band != NL80211_BAND_6GHZ)
continue;
@ -911,13 +913,13 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
spin_unlock_bh(&rdev->bss_lock);
}
size = struct_size(request, channels, n_channels);
size = struct_size(request, req.channels, n_channels);
offs_ssids = size;
size += sizeof(*request->ssids) * rdev_req->n_ssids;
size += sizeof(*request->req.ssids) * rdev_req->req.n_ssids;
offs_6ghz_params = size;
size += sizeof(*request->scan_6ghz_params) * count;
size += sizeof(*request->req.scan_6ghz_params) * count;
offs_ies = size;
size += rdev_req->ie_len;
size += rdev_req->req.ie_len;
request = kzalloc(size, GFP_KERNEL);
if (!request) {
@ -926,26 +928,26 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
}
*request = *rdev_req;
request->n_channels = 0;
request->n_6ghz_params = 0;
if (rdev_req->n_ssids) {
request->req.n_channels = 0;
request->req.n_6ghz_params = 0;
if (rdev_req->req.n_ssids) {
/*
* Add the ssids from the parent scan request to the new
* scan request, so the driver would be able to use them
* in its probe requests to discover hidden APs on PSC
* channels.
*/
request->ssids = (void *)request + offs_ssids;
memcpy(request->ssids, rdev_req->ssids,
sizeof(*request->ssids) * request->n_ssids);
request->req.ssids = (void *)request + offs_ssids;
memcpy(request->req.ssids, rdev_req->req.ssids,
sizeof(*request->req.ssids) * request->req.n_ssids);
}
request->scan_6ghz_params = (void *)request + offs_6ghz_params;
request->req.scan_6ghz_params = (void *)request + offs_6ghz_params;
if (rdev_req->ie_len) {
if (rdev_req->req.ie_len) {
void *ie = (void *)request + offs_ies;
memcpy(ie, rdev_req->ie, rdev_req->ie_len);
request->ie = ie;
memcpy(ie, rdev_req->req.ie, rdev_req->req.ie_len);
request->req.ie = ie;
}
/*
@ -953,10 +955,12 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
* and at least one of the reported co-located APs with same SSID
* indicating that all APs in the same ESS are co-located
*/
if (count && request->n_ssids == 1 && request->ssids[0].ssid_len) {
if (count &&
request->req.n_ssids == 1 &&
request->req.ssids[0].ssid_len) {
list_for_each_entry(ap, &coloc_ap_list, list) {
if (ap->colocated_ess &&
cfg80211_find_ssid_match(ap, request)) {
cfg80211_find_ssid_match(ap, &request->req)) {
need_scan_psc = false;
break;
}
@ -968,51 +972,52 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
* regardless of the collocated APs (PSC channels or all channels
* in case that NL80211_SCAN_FLAG_COLOCATED_6GHZ is not set)
*/
for (i = 0; i < rdev_req->n_channels; i++) {
if (rdev_req->channels[i]->band == NL80211_BAND_6GHZ &&
for (i = 0; i < rdev_req->req.n_channels; i++) {
if (rdev_req->req.channels[i]->band == NL80211_BAND_6GHZ &&
((need_scan_psc &&
cfg80211_channel_is_psc(rdev_req->channels[i])) ||
!(rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))) {
cfg80211_scan_req_add_chan(request,
rdev_req->channels[i],
cfg80211_channel_is_psc(rdev_req->req.channels[i])) ||
!(rdev_req->req.flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))) {
cfg80211_scan_req_add_chan(&request->req,
rdev_req->req.channels[i],
false);
}
}
if (!(rdev_req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))
if (!(rdev_req->req.flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ))
goto skip;
list_for_each_entry(ap, &coloc_ap_list, list) {
bool found = false;
struct cfg80211_scan_6ghz_params *scan_6ghz_params =
&request->scan_6ghz_params[request->n_6ghz_params];
&request->req.scan_6ghz_params[request->req.n_6ghz_params];
struct ieee80211_channel *chan =
ieee80211_get_channel(&rdev->wiphy, ap->center_freq);
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED ||
!cfg80211_wdev_channel_allowed(rdev_req->wdev, chan))
!cfg80211_wdev_channel_allowed(rdev_req->req.wdev, chan))
continue;
for (i = 0; i < rdev_req->n_channels; i++) {
if (rdev_req->channels[i] == chan)
for (i = 0; i < rdev_req->req.n_channels; i++) {
if (rdev_req->req.channels[i] == chan)
found = true;
}
if (!found)
continue;
if (request->n_ssids > 0 &&
!cfg80211_find_ssid_match(ap, request))
if (request->req.n_ssids > 0 &&
!cfg80211_find_ssid_match(ap, &request->req))
continue;
if (!is_broadcast_ether_addr(request->bssid) &&
!ether_addr_equal(request->bssid, ap->bssid))
if (!is_broadcast_ether_addr(request->req.bssid) &&
!ether_addr_equal(request->req.bssid, ap->bssid))
continue;
if (!request->n_ssids && ap->multi_bss && !ap->transmitted_bssid)
if (!request->req.n_ssids && ap->multi_bss &&
!ap->transmitted_bssid)
continue;
cfg80211_scan_req_add_chan(request, chan, true);
cfg80211_scan_req_add_chan(&request->req, chan, true);
memcpy(scan_6ghz_params->bssid, ap->bssid, ETH_ALEN);
scan_6ghz_params->short_ssid = ap->short_ssid;
scan_6ghz_params->short_ssid_valid = ap->short_ssid_valid;
@ -1028,14 +1033,14 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
if (cfg80211_channel_is_psc(chan) && !need_scan_psc)
scan_6ghz_params->psc_no_listen = true;
request->n_6ghz_params++;
request->req.n_6ghz_params++;
}
skip:
cfg80211_free_coloc_ap_list(&coloc_ap_list);
if (request->n_channels) {
struct cfg80211_scan_request *old = rdev->int_scan_req;
if (request->req.n_channels) {
struct cfg80211_scan_request_int *old = rdev->int_scan_req;
rdev->int_scan_req = request;
@ -1043,7 +1048,7 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
* If this scan follows a previous scan, save the scan start
* info from the first part of the scan
*/
if (old)
if (!first_part && !WARN_ON(!old))
rdev->int_scan_req->info = old->info;
err = rdev_scan(rdev, request);
@ -1063,35 +1068,39 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
int cfg80211_scan(struct cfg80211_registered_device *rdev)
{
struct cfg80211_scan_request *request;
struct cfg80211_scan_request *rdev_req = rdev->scan_req;
struct cfg80211_scan_request_int *request;
struct cfg80211_scan_request_int *rdev_req = rdev->scan_req;
u32 n_channels = 0, idx, i;
if (!(rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ))
if (!(rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ)) {
rdev_req->req.first_part = true;
return rdev_scan(rdev, rdev_req);
}
for (i = 0; i < rdev_req->n_channels; i++) {
if (rdev_req->channels[i]->band != NL80211_BAND_6GHZ)
for (i = 0; i < rdev_req->req.n_channels; i++) {
if (rdev_req->req.channels[i]->band != NL80211_BAND_6GHZ)
n_channels++;
}
if (!n_channels)
return cfg80211_scan_6ghz(rdev);
return cfg80211_scan_6ghz(rdev, true);
request = kzalloc(struct_size(request, channels, n_channels),
request = kzalloc(struct_size(request, req.channels, n_channels),
GFP_KERNEL);
if (!request)
return -ENOMEM;
*request = *rdev_req;
request->n_channels = n_channels;
request->req.n_channels = n_channels;
for (i = idx = 0; i < rdev_req->n_channels; i++) {
if (rdev_req->channels[i]->band != NL80211_BAND_6GHZ)
request->channels[idx++] = rdev_req->channels[i];
for (i = idx = 0; i < rdev_req->req.n_channels; i++) {
if (rdev_req->req.channels[i]->band != NL80211_BAND_6GHZ)
request->req.channels[idx++] =
rdev_req->req.channels[i];
}
rdev_req->scan_6ghz = false;
rdev_req->req.scan_6ghz = false;
rdev_req->req.first_part = true;
rdev->int_scan_req = request;
return rdev_scan(rdev, request);
}
@ -1099,7 +1108,7 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev)
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
bool send_message)
{
struct cfg80211_scan_request *request, *rdev_req;
struct cfg80211_scan_request_int *request, *rdev_req;
struct wireless_dev *wdev;
struct sk_buff *msg;
#ifdef CONFIG_CFG80211_WEXT
@ -1118,13 +1127,13 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
if (!rdev_req)
return;
wdev = rdev_req->wdev;
wdev = rdev_req->req.wdev;
request = rdev->int_scan_req ? rdev->int_scan_req : rdev_req;
if (wdev_running(wdev) &&
(rdev->wiphy.flags & WIPHY_FLAG_SPLIT_SCAN_6GHZ) &&
!rdev_req->scan_6ghz && !request->info.aborted &&
!cfg80211_scan_6ghz(rdev))
!rdev_req->req.scan_6ghz && !request->info.aborted &&
!cfg80211_scan_6ghz(rdev, false))
return;
/*
@ -1136,10 +1145,10 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
cfg80211_sme_scan_done(wdev->netdev);
if (!request->info.aborted &&
request->flags & NL80211_SCAN_FLAG_FLUSH) {
request->req.flags & NL80211_SCAN_FLAG_FLUSH) {
/* flush entries from previous scans */
spin_lock_bh(&rdev->bss_lock);
__cfg80211_bss_expire(rdev, request->scan_start);
__cfg80211_bss_expire(rdev, request->req.scan_start);
spin_unlock_bh(&rdev->bss_lock);
}
@ -1175,13 +1184,16 @@ void __cfg80211_scan_done(struct wiphy *wiphy, struct wiphy_work *wk)
void cfg80211_scan_done(struct cfg80211_scan_request *request,
struct cfg80211_scan_info *info)
{
struct cfg80211_scan_info old_info = request->info;
struct cfg80211_scan_request_int *intreq =
container_of(request, struct cfg80211_scan_request_int, req);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(request->wiphy);
struct cfg80211_scan_info old_info = intreq->info;
trace_cfg80211_scan_done(request, info);
WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req &&
request != wiphy_to_rdev(request->wiphy)->int_scan_req);
trace_cfg80211_scan_done(intreq, info);
WARN_ON(intreq != rdev->scan_req &&
intreq != rdev->int_scan_req);
request->info = *info;
intreq->info = *info;
/*
* In case the scan is split, the scan_start_tsf and tsf_bssid should
@ -1189,14 +1201,13 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request,
* be non zero.
*/
if (request->scan_6ghz && old_info.scan_start_tsf) {
request->info.scan_start_tsf = old_info.scan_start_tsf;
memcpy(request->info.tsf_bssid, old_info.tsf_bssid,
sizeof(request->info.tsf_bssid));
intreq->info.scan_start_tsf = old_info.scan_start_tsf;
memcpy(intreq->info.tsf_bssid, old_info.tsf_bssid,
sizeof(intreq->info.tsf_bssid));
}
request->notified = true;
wiphy_work_queue(request->wiphy,
&wiphy_to_rdev(request->wiphy)->scan_done_wk);
intreq->notified = true;
wiphy_work_queue(request->wiphy, &rdev->scan_done_wk);
}
EXPORT_SYMBOL(cfg80211_scan_done);
@ -2220,6 +2231,7 @@ cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len)
return IEEE80211_REG_LPI_AP;
case IEEE80211_6GHZ_CTRL_REG_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP:
case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD:
return IEEE80211_REG_SP_AP;
case IEEE80211_6GHZ_CTRL_REG_VLP_AP:
return IEEE80211_REG_VLP_AP;
@ -3496,7 +3508,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
struct cfg80211_registered_device *rdev;
struct wiphy *wiphy;
struct iw_scan_req *wreq = NULL;
struct cfg80211_scan_request *creq;
struct cfg80211_scan_request_int *creq;
int i, err, n_channels = 0;
enum nl80211_band band;
@ -3526,19 +3538,20 @@ int cfg80211_wext_siwscan(struct net_device *dev,
n_channels = ieee80211_get_num_supported_channels(wiphy);
}
creq = kzalloc(struct_size(creq, channels, n_channels) +
creq = kzalloc(struct_size(creq, req.channels, n_channels) +
sizeof(struct cfg80211_ssid),
GFP_ATOMIC);
if (!creq)
return -ENOMEM;
creq->wiphy = wiphy;
creq->wdev = dev->ieee80211_ptr;
creq->req.wiphy = wiphy;
creq->req.wdev = dev->ieee80211_ptr;
/* SSIDs come after channels */
creq->ssids = (void *)creq + struct_size(creq, channels, n_channels);
creq->n_channels = n_channels;
creq->n_ssids = 1;
creq->scan_start = jiffies;
creq->req.ssids = (void *)creq +
struct_size(creq, req.channels, n_channels);
creq->req.n_channels = n_channels;
creq->req.n_ssids = 1;
creq->req.scan_start = jiffies;
/* translate "Scan on frequencies" request */
i = 0;
@ -3554,7 +3567,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
/* ignore disabled channels */
chan = &wiphy->bands[band]->channels[j];
if (chan->flags & IEEE80211_CHAN_DISABLED ||
!cfg80211_wdev_channel_allowed(creq->wdev, chan))
!cfg80211_wdev_channel_allowed(creq->req.wdev, chan))
continue;
/* If we have a wireless request structure and the
@ -3577,7 +3590,8 @@ int cfg80211_wext_siwscan(struct net_device *dev,
}
wext_freq_found:
creq->channels[i] = &wiphy->bands[band]->channels[j];
creq->req.channels[i] =
&wiphy->bands[band]->channels[j];
i++;
wext_freq_not_found: ;
}
@ -3588,28 +3602,30 @@ int cfg80211_wext_siwscan(struct net_device *dev,
goto out;
}
/* Set real number of channels specified in creq->channels[] */
creq->n_channels = i;
/* Set real number of channels specified in creq->req.channels[] */
creq->req.n_channels = i;
/* translate "Scan for SSID" request */
if (wreq) {
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
return -EINVAL;
memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
creq->ssids[0].ssid_len = wreq->essid_len;
memcpy(creq->req.ssids[0].ssid, wreq->essid,
wreq->essid_len);
creq->req.ssids[0].ssid_len = wreq->essid_len;
}
if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE) {
creq->ssids = NULL;
creq->n_ssids = 0;
creq->req.ssids = NULL;
creq->req.n_ssids = 0;
}
}
for (i = 0; i < NUM_NL80211_BANDS; i++)
if (wiphy->bands[i])
creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
creq->req.rates[i] =
(1 << wiphy->bands[i]->n_bitrates) - 1;
eth_broadcast_addr(creq->bssid);
eth_broadcast_addr(creq->req.bssid);
scoped_guard(wiphy, &rdev->wiphy) {
rdev->scan_req = creq;

View File

@ -5,7 +5,7 @@
* (for nl80211's connect() and wext)
*
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2009, 2020, 2022-2024 Intel Corporation. All rights reserved.
* Copyright (C) 2009, 2020, 2022-2025 Intel Corporation. All rights reserved.
* Copyright 2017 Intel Deutschland GmbH
*/
@ -64,7 +64,7 @@ static void cfg80211_sme_free(struct wireless_dev *wdev)
static int cfg80211_conn_scan(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_scan_request *request;
struct cfg80211_scan_request_int *request;
int n_channels, err;
lockdep_assert_wiphy(wdev->wiphy);
@ -77,13 +77,13 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
else
n_channels = ieee80211_get_num_supported_channels(wdev->wiphy);
request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
sizeof(request->channels[0]) * n_channels,
request = kzalloc(sizeof(*request) + sizeof(request->req.ssids[0]) +
sizeof(request->req.channels[0]) * n_channels,
GFP_KERNEL);
if (!request)
return -ENOMEM;
request->n_channels = n_channels;
request->req.n_channels = n_channels;
if (wdev->conn->params.channel) {
enum nl80211_band band = wdev->conn->params.channel->band;
struct ieee80211_supported_band *sband =
@ -93,8 +93,8 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
kfree(request);
return -EINVAL;
}
request->channels[0] = wdev->conn->params.channel;
request->rates[band] = (1 << sband->n_bitrates) - 1;
request->req.channels[0] = wdev->conn->params.channel;
request->req.rates[band] = (1 << sband->n_bitrates) - 1;
} else {
int i = 0, j;
enum nl80211_band band;
@ -109,26 +109,26 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
channel = &bands->channels[j];
if (channel->flags & IEEE80211_CHAN_DISABLED)
continue;
request->channels[i++] = channel;
request->req.channels[i++] = channel;
}
request->rates[band] = (1 << bands->n_bitrates) - 1;
request->req.rates[band] = (1 << bands->n_bitrates) - 1;
}
n_channels = i;
}
request->n_channels = n_channels;
request->ssids = (void *)request +
struct_size(request, channels, n_channels);
request->n_ssids = 1;
request->req.n_channels = n_channels;
request->req.ssids = (void *)request +
struct_size(request, req.channels, n_channels);
request->req.n_ssids = 1;
memcpy(request->ssids[0].ssid, wdev->conn->params.ssid,
wdev->conn->params.ssid_len);
request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
memcpy(request->req.ssids[0].ssid, wdev->conn->params.ssid,
wdev->conn->params.ssid_len);
request->req.ssids[0].ssid_len = wdev->conn->params.ssid_len;
eth_broadcast_addr(request->bssid);
eth_broadcast_addr(request->req.bssid);
request->wdev = wdev;
request->wiphy = &rdev->wiphy;
request->scan_start = jiffies;
request->req.wdev = wdev;
request->req.wiphy = &rdev->wiphy;
request->req.scan_start = jiffies;
rdev->scan_req = request;

View File

@ -373,7 +373,8 @@ TRACE_EVENT(rdev_return_int,
);
TRACE_EVENT(rdev_scan,
TP_PROTO(struct wiphy *wiphy, struct cfg80211_scan_request *request),
TP_PROTO(struct wiphy *wiphy,
struct cfg80211_scan_request_int *request),
TP_ARGS(wiphy, request),
TP_STRUCT__entry(
WIPHY_ENTRY
@ -3716,12 +3717,12 @@ TRACE_EVENT(cfg80211_tdls_oper_request,
);
TRACE_EVENT(cfg80211_scan_done,
TP_PROTO(struct cfg80211_scan_request *request,
TP_PROTO(struct cfg80211_scan_request_int *request,
struct cfg80211_scan_info *info),
TP_ARGS(request, info),
TP_STRUCT__entry(
__field(u32, n_channels)
__dynamic_array(u8, ie, request ? request->ie_len : 0)
__dynamic_array(u8, ie, request ? request->req.ie_len : 0)
__array(u32, rates, NUM_NL80211_BANDS)
__field(u32, wdev_id)
MAC_ENTRY(wiphy_mac)
@ -3732,16 +3733,16 @@ TRACE_EVENT(cfg80211_scan_done,
),
TP_fast_assign(
if (request) {
memcpy(__get_dynamic_array(ie), request->ie,
request->ie_len);
memcpy(__entry->rates, request->rates,
memcpy(__get_dynamic_array(ie), request->req.ie,
request->req.ie_len);
memcpy(__entry->rates, request->req.rates,
NUM_NL80211_BANDS);
__entry->wdev_id = request->wdev ?
request->wdev->identifier : 0;
if (request->wiphy)
__entry->wdev_id = request->req.wdev ?
request->req.wdev->identifier : 0;
if (request->req.wiphy)
MAC_ASSIGN(wiphy_mac,
request->wiphy->perm_addr);
__entry->no_cck = request->no_cck;
request->req.wiphy->perm_addr);
__entry->no_cck = request->req.no_cck;
}
if (info) {
__entry->aborted = info->aborted;