iwlwifi features, notably:

- PNVM integrated in the ucode image
 - more cleanups in the transport layer
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQM3A3Pv7vbm9vtjWbacY7uyt+OfQUCaG4v0AAKCRDacY7uyt+O
 fTaDAQCOJRC01eAL57AzxOf/YvT9zrN2dDR0NoBPqcfHmgJfWAEA4qEaqz9T5SPC
 ELoOuCYk3YibwIgZFeqQmy4VQaIl2g4=
 =/7vB
 -----END PGP SIGNATURE-----

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

Miri Korenblit says:
====================
iwlwifi features, notably:

- PNVM integrated in the ucode image
- more cleanups in the transport layer
====================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2025-07-09 11:39:23 +02:00
commit c8c5e97da9
26 changed files with 564 additions and 693 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),