iwlwifi patches intended for v6.2

* iwlmei fixes
 * Debug mechanism update for new devices (BZ)
 * Checksum offload fix for the new devices (BZ)
 * A few rate scale fixes and cleanups
 * A fix for iwlwifi debug mechanism
 * Start of MLO preparations - supporting new key API
 -----BEGIN PGP SIGNATURE-----
 
 iQJPBAABCAA5FiEE9cg2NujikJ5EMZusCDCCYA5zdzwFAmNs5fsbHGdyZWdvcnku
 Z3JlZW5tYW5AaW50ZWwuY29tAAoJEAgwgmAOc3c8HycP/29xLeQi5PDCuU4Y1oDq
 vp6ddZUwvfgNaeGn+hv4nbob/gpXzaWgXxum3QrE2AwB95U6UNjNLjCAKh+2HS3V
 tzClp5kNU6TWIwgUnfWfuGWQjqC5X9YOG+LLjKpDXZgm4StfMn5vg7U3temxIpye
 OA1Mdk992eJ+vp38zJmYIofh5GiZ/TXgxDoGMm5B2CeHyRt6WlUZh+9lFLXZ5maw
 JLfLqoAhQHs0WGGDSNjCCImmspCDiueiX07O3W9EO9A9Hmv6iSb1PDsxOcvcuxml
 YoeqgALtz3i6LIjeEtMi50dinlSr3THbxdBWQZF5QTpWZqvXvH5Zq9zq6ymU7f0Q
 tN35uIDgbY5W0ByXf021rTmifhHMwhiSp0WHdEgo/tKt9g1Zkr4FtoRL+JUbmRd9
 CCGErUb/7nCAtSi/FKqvF1xUouFws38i4xbvBI1Vg9lfAwqx6MEfkxwrREW78jur
 byl5HYtBfASAPt0oWaSUMBCNQwPGdj0rmgQNAkR/bMgS+9YZdicG4uuSVJQp77/P
 unE0eOyBCIcZBQji9l3V8kuZuvm7mZrAJp5POlRyvhtd4szCboq/OF7ke7LKYJqo
 tsuO/ouvkFjIJXtYUtNOxU51lBWoACPYJBTXe/4qc3O2cSl3KDXMQ7HKU8eGK42V
 sE3yKbbwuIZAm+VYTgnY0Uy4
 =ggBO
 -----END PGP SIGNATURE-----

Merge tag 'iwlwifi-next-for-kalle-2022-11-06-v2' of http://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

iwlwifi patches intended for v6.2

* iwlmei fixes
* Debug mechanism update for new devices (BZ)
* Checksum offload fix for the new devices (BZ)
* A few rate scale fixes and cleanups
* A fix for iwlwifi debug mechanism
* Start of MLO preparations - supporting new key API
This commit is contained in:
Kalle Valo 2022-11-17 14:53:45 +02:00
commit e7e40cc655
19 changed files with 781 additions and 129 deletions

View file

@ -172,6 +172,13 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
BIT(NL80211_BAND_6GHZ),
};
static const struct iwl_ht_params iwl_gl_a_ht_params = {
.stbc = false, /* we explicitly disable STBC for GL step A */
.ldpc = true,
.ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) |
BIT(NL80211_BAND_6GHZ),
};
#define IWL_DEVICE_22000_COMMON \
.ucode_api_max = IWL_22000_UCODE_API_MAX, \
.ucode_api_min = IWL_22000_UCODE_API_MIN, \
@ -249,7 +256,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
}, \
}
#define IWL_DEVICE_BZ \
#define IWL_DEVICE_BZ_COMMON \
.ucode_api_max = IWL_22000_UCODE_API_MAX, \
.ucode_api_min = IWL_22000_UCODE_API_MIN, \
.led_mode = IWL_LED_RF_STATE, \
@ -261,12 +268,10 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
.dccm2_len = IWL_22000_DCCM2_LEN, \
.smem_offset = IWL_22000_SMEM_OFFSET, \
.smem_len = IWL_22000_SMEM_LEN, \
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, \
.apmg_not_supported = true, \
.trans.mq_rx_supported = true, \
.vht_mu_mimo_supported = true, \
.mac_addr_from_csr = 0x30, \
.ht_params = &iwl_22000_ht_params, \
.nvm_ver = IWL_22000_NVM_VERSION, \
.trans.use_tfh = true, \
.trans.rf_id = true, \
@ -313,6 +318,14 @@ static const struct iwl_ht_params iwl_22000_ht_params = {
}, \
}
#define IWL_DEVICE_BZ \
IWL_DEVICE_BZ_COMMON, \
.ht_params = &iwl_22000_ht_params
#define IWL_DEVICE_GL_A \
IWL_DEVICE_BZ_COMMON, \
.ht_params = &iwl_gl_a_ht_params
const struct iwl_cfg_trans_params iwl_qnj_trans_cfg = {
.mq_rx_supported = true,
.use_tfh = true,
@ -901,6 +914,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_hr_b0 = {
.fw_name_pre = IWL_BZ_A_HR_B_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -908,6 +922,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_gf_a0 = {
.fw_name_pre = IWL_BZ_A_GF_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -915,6 +930,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0 = {
.fw_name_pre = IWL_BZ_A_GF4_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -922,6 +938,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_mr_a0 = {
.fw_name_pre = IWL_BZ_A_MR_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -929,6 +946,7 @@ const struct iwl_cfg iwl_cfg_bz_a0_fm_a0 = {
.fw_name_pre = IWL_BZ_A_FM_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -936,13 +954,15 @@ const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0 = {
.fw_name_pre = IWL_BZ_A_FM4_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = {
.fw_name_pre = IWL_GL_A_FM_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
IWL_DEVICE_GL_A,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -950,6 +970,7 @@ const struct iwl_cfg iwl_cfg_gl_b0_fm_b0 = {
.fw_name_pre = IWL_GL_B_FM_B_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -957,6 +978,7 @@ const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = {
.fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -964,6 +986,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0 = {
.fw_name_pre = IWL_BNJ_A_FM_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -971,6 +994,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0 = {
.fw_name_pre = IWL_BNJ_A_FM4_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -978,6 +1002,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0 = {
.fw_name_pre = IWL_BNJ_A_GF_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -985,6 +1010,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0 = {
.fw_name_pre = IWL_BNJ_A_GF4_A_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -992,6 +1018,7 @@ const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0 = {
.fw_name_pre = IWL_BNJ_A_HR_B_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
@ -999,6 +1026,7 @@ const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = {
.fw_name_pre = IWL_BNJ_B_FM_B_FW_PRE,
.uhb_supported = true,
IWL_DEVICE_BZ,
.features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM,
.num_rbds = IWL_NUM_RBDS_AX210_HE,
};
MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));

View file

@ -71,6 +71,11 @@ enum iwl_data_path_subcmd_ids {
*/
SCD_QUEUE_CONFIG_CMD = 0x17,
/**
* @SEC_KEY_CMD: security key command, uses &struct iwl_sec_key_cmd
*/
SEC_KEY_CMD = 0x18,
/**
* @MONITOR_NOTIF: Datapath monitoring notification, using
* &struct iwl_datapath_monitor_notif
@ -403,4 +408,78 @@ struct iwl_scd_queue_cfg_cmd {
} __packed u; /* TX_QUEUE_CFG_CMD_OPERATION_API_U_VER_1 */
} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_3 */
/**
* enum iwl_sec_key_flags - security key command key flags
* @IWL_SEC_KEY_FLAG_CIPHER_MASK: cipher mask
* @IWL_SEC_KEY_FLAG_CIPHER_WEP: WEP cipher
* @IWL_SEC_KEY_FLAG_CIPHER_CCMP: CCMP/CMAC cipher
* @IWL_SEC_KEY_FLAG_CIPHER_TKIP: TKIP cipher
* @IWL_SEC_KEY_FLAG_CIPHER_GCMP: GCMP/GMAC cipher
* @IWL_SEC_KEY_FLAG_NO_TX: don't install for TX
* @IWL_SEC_KEY_FLAG_KEY_SIZE: large key size (WEP-104, GCMP-256, GMAC-256)
* @IWL_SEC_KEY_FLAG_MFP: MFP is in used for this key
* @IWL_SEC_KEY_FLAG_MCAST_KEY: this is a multicast key
* @IWL_SEC_KEY_FLAG_SPP_AMSDU: SPP A-MSDU should be used
*/
enum iwl_sec_key_flags {
IWL_SEC_KEY_FLAG_CIPHER_MASK = 0x07,
IWL_SEC_KEY_FLAG_CIPHER_WEP = 0x01,
IWL_SEC_KEY_FLAG_CIPHER_CCMP = 0x02,
IWL_SEC_KEY_FLAG_CIPHER_TKIP = 0x03,
IWL_SEC_KEY_FLAG_CIPHER_GCMP = 0x05,
IWL_SEC_KEY_FLAG_NO_TX = 0x08,
IWL_SEC_KEY_FLAG_KEY_SIZE = 0x10,
IWL_SEC_KEY_FLAG_MFP = 0x20,
IWL_SEC_KEY_FLAG_MCAST_KEY = 0x40,
IWL_SEC_KEY_FLAG_SPP_AMSDU = 0x80,
};
#define IWL_SEC_WEP_KEY_OFFSET 3
/**
* struct iwl_sec_key_cmd - security key command
* @action: action from &enum iwl_ctxt_action
* @u.add.sta_mask: station mask for the new key
* @u.add.key_id: key ID (0-7) for the new key
* @u.add.key_flags: key flags per &enum iwl_sec_key_flags
* @u.add.key: key material. WEP keys should start from &IWL_SEC_WEP_KEY_OFFSET.
* @u.add.tkip_mic_rx_key: TKIP MIC RX key
* @u.add.tkip_mic_tx_key: TKIP MIC TX key
* @u.add.rx_seq: RX sequence counter value
* @u.add.tx_seq: TX sequence counter value
* @u.modify.old_sta_mask: old station mask
* @u.modify.new_sta_mask: new station mask
* @u.modify.key_id: key ID
* @u.modify.key_flags: new key flags
* @u.remove.sta_mask: station mask
* @u.remove.key_id: key ID
* @u.remove.key_flags: key flags
*/
struct iwl_sec_key_cmd {
__le32 action;
union {
struct {
__le32 sta_mask;
__le32 key_id;
__le32 key_flags;
u8 key[32];
u8 tkip_mic_rx_key[8];
u8 tkip_mic_tx_key[8];
__le64 rx_seq;
__le64 tx_seq;
} __packed add; /* SEC_KEY_ADD_CMD_API_S_VER_1 */
struct {
__le32 old_sta_mask;
__le32 new_sta_mask;
__le32 key_id;
__le32 key_flags;
} __packed modify; /* SEC_KEY_MODIFY_CMD_API_S_VER_1 */
struct {
__le32 sta_mask;
__le32 key_id;
__le32 key_flags;
} __packed remove; /* SEC_KEY_REMOVE_CMD_API_S_VER_1 */
} __packed u; /* SEC_KEY_OPERATION_API_U_VER_1 */
} __packed; /* SEC_KEY_CMD_API_S_VER_1 */
#endif /* __iwl_fw_api_datapath_h__ */

View file

@ -590,6 +590,9 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt,
if (alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1)
return -EIO;
num_frags = 1;
} else if (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ &&
alloc_id > IWL_FW_INI_ALLOCATION_ID_DBGC3) {
return -EIO;
}
remain_pages = DIV_ROUND_UP(le32_to_cpu(fw_mon_cfg->req_size),
@ -789,7 +792,7 @@ static void iwl_dbg_tlv_update_drams(struct iwl_fw_runtime *fwrt)
dram_info->second_word = cpu_to_le32(DRAM_INFO_SECOND_MAGIC_WORD);
for (i = IWL_FW_INI_ALLOCATION_ID_DBGC1;
i <= IWL_FW_INI_ALLOCATION_ID_DBGC3; i++) {
i < IWL_FW_INI_ALLOCATION_NUM; i++) {
ret = iwl_dbg_tlv_update_dram(fwrt, i, dram_info);
if (!ret)
dram_alloc = true;
@ -1324,7 +1327,7 @@ static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt)
"WRT: removing allocation id %d from region id %d\n",
le32_to_cpu(reg->dram_alloc_id), i);
failed_alloc &= ~le32_to_cpu(reg->dram_alloc_id);
failed_alloc &= ~BIT(le32_to_cpu(reg->dram_alloc_id));
fwrt->trans->dbg.unsupported_region_msk |= BIT(i);
kfree(*active_reg);

View file

@ -377,6 +377,7 @@ enum {
#define PREG_PRPH_WPROT_22000 0xA04D00
#define SB_MODIFY_CFG_FLAG 0xA03088
#define SB_CFG_RESIDES_IN_OTP_MASK 0x10
#define SB_CPU_1_STATUS 0xA01E30
#define SB_CPU_2_STATUS 0xA01E34
#define UMAG_SB_CPU_1_STATUS 0xA038C0
@ -500,4 +501,7 @@ enum {
#define REG_OTP_MINOR 0xA0333C
#define WFPM_LMAC2_PD_NOTIFICATION 0xA033CC
#define WFPM_LMAC2_PD_RE_READ BIT(31)
#endif /* __iwl_prph_h__ */

View file

@ -220,6 +220,7 @@ struct iwl_mei_nvm {
/**
* enum iwl_mei_pairwise_cipher - cipher for UCAST key
* @IWL_MEI_CIPHER_NONE: none
* @IWL_MEI_CIPHER_TKIP: tkip
* @IWL_MEI_CIPHER_CCMP: ccmp
* @IWL_MEI_CIPHER_GCMP: gcmp
* @IWL_MEI_CIPHER_GCMP_256: gcmp 256
@ -228,6 +229,7 @@ struct iwl_mei_nvm {
*/
enum iwl_mei_pairwise_cipher {
IWL_MEI_CIPHER_NONE = 0,
IWL_MEI_CIPHER_TKIP = 2,
IWL_MEI_CIPHER_CCMP = 4,
IWL_MEI_CIPHER_GCMP = 8,
IWL_MEI_CIPHER_GCMP_256 = 9,
@ -446,9 +448,25 @@ void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,
void iwl_mei_host_disassociated(void);
/**
* iwl_mei_device_down() - must be called when the device is down
* iwl_mei_device_state() - must be called when the device changes up/down state
* @up: true if the device is up, false otherwise.
*/
void iwl_mei_device_down(void);
void iwl_mei_device_state(bool up);
/**
* iwl_mei_pldr_req() - must be called before loading the fw
*
* Return: 0 if the PLDR flow was successful and the fw can be loaded, negative
* value otherwise.
*/
int iwl_mei_pldr_req(void);
/**
* iwl_mei_alive_notif() - must be called when alive notificaiton is received
* @success: true if received alive notification, false if waiting for the
* notificaiton timed out.
*/
void iwl_mei_alive_notif(bool success);
#else
@ -497,7 +515,13 @@ static inline void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_
static inline void iwl_mei_host_disassociated(void)
{}
static inline void iwl_mei_device_down(void)
static inline void iwl_mei_device_state(bool up)
{}
static inline int iwl_mei_pldr_req(void)
{ return 0; }
static inline void iwl_mei_alive_notif(bool success)
{}
#endif /* CONFIG_IWLMEI */

View file

@ -147,9 +147,15 @@ struct iwl_mei_filters {
* to send CSME_OWNERSHIP_CONFIRMED when the driver completes its down
* flow.
* @link_prot_state: true when we are in link protection PASSIVE
* @device_down: true if the device is down. Used to remember to send
* CSME_OWNERSHIP_CONFIRMED when the driver is already down.
* @csa_throttle_end_wk: used when &csa_throttled is true
* @pldr_wq: the wait queue for PLDR flow
* @pldr_active: PLDR flow is in progress
* @data_q_lock: protects the access to the data queues which are
* accessed without the mutex.
* @netdev_work: used to defer registering and unregistering of the netdev to
* avoid taking the rtnl lock in the SAP messages handlers.
* @sap_seq_no: the sequence number for the SAP messages
* @seq_no: the sequence number for the SAP messages
* @dbgfs_dir: the debugfs dir entry
@ -167,8 +173,12 @@ struct iwl_mei {
bool csa_throttled;
bool csme_taking_ownership;
bool link_prot_state;
bool device_down;
struct delayed_work csa_throttle_end_wk;
wait_queue_head_t pldr_wq;
bool pldr_active;
spinlock_t data_q_lock;
struct work_struct netdev_work;
atomic_t sap_seq_no;
atomic_t seq_no;
@ -588,13 +598,38 @@ static rx_handler_result_t iwl_mei_rx_handler(struct sk_buff **pskb)
return res;
}
static void iwl_mei_netdev_work(struct work_struct *wk)
{
struct iwl_mei *mei =
container_of(wk, struct iwl_mei, netdev_work);
struct net_device *netdev;
/*
* First take rtnl and only then the mutex to avoid an ABBA
* with iwl_mei_set_netdev()
*/
rtnl_lock();
mutex_lock(&iwl_mei_mutex);
netdev = rcu_dereference_protected(iwl_mei_cache.netdev,
lockdep_is_held(&iwl_mei_mutex));
if (netdev) {
if (mei->amt_enabled)
netdev_rx_handler_register(netdev, iwl_mei_rx_handler,
mei);
else
netdev_rx_handler_unregister(netdev);
}
mutex_unlock(&iwl_mei_mutex);
rtnl_unlock();
}
static void
iwl_mei_handle_rx_start_ok(struct mei_cl_device *cldev,
const struct iwl_sap_me_msg_start_ok *rsp,
ssize_t len)
{
struct iwl_mei *mei = mei_cldev_get_drvdata(cldev);
if (len != sizeof(*rsp)) {
dev_err(&cldev->dev,
"got invalid SAP_ME_MSG_START_OK from CSME firmware\n");
@ -613,13 +648,10 @@ iwl_mei_handle_rx_start_ok(struct mei_cl_device *cldev,
mutex_lock(&iwl_mei_mutex);
set_bit(IWL_MEI_STATUS_SAP_CONNECTED, &iwl_mei_status);
/* wifi driver has registered already */
if (iwl_mei_cache.ops) {
iwl_mei_send_sap_msg(mei->cldev,
SAP_MSG_NOTIF_WIFIDR_UP);
iwl_mei_cache.ops->sap_connected(iwl_mei_cache.priv);
}
/*
* We'll receive AMT_STATE SAP message in a bit and
* that will continue the flow
*/
mutex_unlock(&iwl_mei_mutex);
}
@ -712,6 +744,13 @@ static void iwl_mei_set_init_conf(struct iwl_mei *mei)
.val = cpu_to_le32(iwl_mei_cache.rf_kill),
};
/* wifi driver has registered already */
if (iwl_mei_cache.ops) {
iwl_mei_send_sap_msg(mei->cldev,
SAP_MSG_NOTIF_WIFIDR_UP);
iwl_mei_cache.ops->sap_connected(iwl_mei_cache.priv);
}
iwl_mei_send_sap_msg(mei->cldev, SAP_MSG_NOTIF_WHO_OWNS_NIC);
if (iwl_mei_cache.conn_info) {
@ -738,38 +777,23 @@ static void iwl_mei_handle_amt_state(struct mei_cl_device *cldev,
const struct iwl_sap_msg_dw *dw)
{
struct iwl_mei *mei = mei_cldev_get_drvdata(cldev);
struct net_device *netdev;
/*
* First take rtnl and only then the mutex to avoid an ABBA
* with iwl_mei_set_netdev()
*/
rtnl_lock();
mutex_lock(&iwl_mei_mutex);
netdev = rcu_dereference_protected(iwl_mei_cache.netdev,
lockdep_is_held(&iwl_mei_mutex));
if (mei->amt_enabled == !!le32_to_cpu(dw->val))
goto out;
mei->amt_enabled = dw->val;
if (mei->amt_enabled) {
if (netdev)
netdev_rx_handler_register(netdev, iwl_mei_rx_handler, mei);
if (mei->amt_enabled)
iwl_mei_set_init_conf(mei);
} else {
if (iwl_mei_cache.ops)
iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false);
if (netdev)
netdev_rx_handler_unregister(netdev);
}
else if (iwl_mei_cache.ops)
iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false, false);
schedule_work(&mei->netdev_work);
out:
mutex_unlock(&iwl_mei_mutex);
rtnl_unlock();
}
static void iwl_mei_handle_nic_owner(struct mei_cl_device *cldev,
@ -798,14 +822,18 @@ static void iwl_mei_handle_csme_taking_ownership(struct mei_cl_device *cldev,
mei->got_ownership = false;
/*
* Remember to send CSME_OWNERSHIP_CONFIRMED when the wifi driver
* is finished taking the device down.
*/
mei->csme_taking_ownership = true;
if (iwl_mei_cache.ops && !mei->device_down) {
/*
* Remember to send CSME_OWNERSHIP_CONFIRMED when the wifi
* driver is finished taking the device down.
*/
mei->csme_taking_ownership = true;
if (iwl_mei_cache.ops)
iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, true);
iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, true, true);
} else {
iwl_mei_send_sap_msg(cldev,
SAP_MSG_NOTIF_CSME_OWNERSHIP_CONFIRMED);
}
}
static void iwl_mei_handle_nvm(struct mei_cl_device *cldev,
@ -857,6 +885,15 @@ static void iwl_mei_handle_rx_host_own_req(struct mei_cl_device *cldev,
iwl_mei_cache.ops->rfkill(iwl_mei_cache.priv, false);
}
static void iwl_mei_handle_pldr_ack(struct mei_cl_device *cldev,
const struct iwl_sap_pldr_ack_data *ack)
{
struct iwl_mei *mei = mei_cldev_get_drvdata(cldev);
mei->pldr_active = le32_to_cpu(ack->status) == SAP_PLDR_STATUS_SUCCESS;
wake_up_all(&mei->pldr_wq);
}
static void iwl_mei_handle_ping(struct mei_cl_device *cldev,
const struct iwl_sap_hdr *hdr)
{
@ -937,6 +974,8 @@ static void iwl_mei_handle_sap_msg(struct mei_cl_device *cldev,
iwl_mei_handle_can_release_ownership, 0);
SAP_MSG_HANDLER(CSME_TAKING_OWNERSHIP,
iwl_mei_handle_csme_taking_ownership, 0);
SAP_MSG_HANDLER(PLDR_ACK, iwl_mei_handle_pldr_ack,
sizeof(struct iwl_sap_pldr_ack_data));
default:
/*
* This is not really an error, there are message that we decided
@ -1313,6 +1352,62 @@ struct iwl_mei_nvm *iwl_mei_get_nvm(void)
}
EXPORT_SYMBOL_GPL(iwl_mei_get_nvm);
#define IWL_MEI_PLDR_NUM_RETRIES 3
int iwl_mei_pldr_req(void)
{
struct iwl_mei *mei;
int ret;
struct iwl_sap_pldr_data msg = {
.hdr.type = cpu_to_le16(SAP_MSG_NOTIF_PLDR),
.hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)),
};
int i;
mutex_lock(&iwl_mei_mutex);
/* In case we didn't have a bind */
if (!iwl_mei_is_connected()) {
ret = 0;
goto out;
}
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
if (!mei) {
ret = -ENODEV;
goto out;
}
if (!mei->amt_enabled) {
ret = 0;
goto out;
}
for (i = 0; i < IWL_MEI_PLDR_NUM_RETRIES; i++) {
ret = iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
mutex_unlock(&iwl_mei_mutex);
if (ret)
return ret;
ret = wait_event_timeout(mei->pldr_wq, mei->pldr_active, HZ / 2);
if (ret)
break;
/* Take the mutex for the next iteration */
mutex_lock(&iwl_mei_mutex);
}
if (ret)
return 0;
ret = -ETIMEDOUT;
out:
mutex_unlock(&iwl_mei_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(iwl_mei_pldr_req);
int iwl_mei_get_ownership(void)
{
struct iwl_mei *mei;
@ -1352,32 +1447,40 @@ int iwl_mei_get_ownership(void)
ret = wait_event_timeout(mei->get_ownership_wq,
mei->got_ownership, HZ / 2);
if (!ret)
return -ETIMEDOUT;
mutex_lock(&iwl_mei_mutex);
/* In case we didn't have a bind */
if (!iwl_mei_is_connected()) {
ret = 0;
goto out;
}
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
if (!mei) {
ret = -ENODEV;
goto out;
}
ret = !mei->got_ownership;
return (!ret) ? -ETIMEDOUT : 0;
out:
mutex_unlock(&iwl_mei_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(iwl_mei_get_ownership);
void iwl_mei_alive_notif(bool success)
{
struct iwl_mei *mei;
struct iwl_sap_pldr_end_data msg = {
.hdr.type = cpu_to_le16(SAP_MSG_NOTIF_PLDR_END),
.hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)),
.status = success ? cpu_to_le32(SAP_PLDR_STATUS_SUCCESS) :
cpu_to_le32(SAP_PLDR_STATUS_FAILURE),
};
mutex_lock(&iwl_mei_mutex);
if (!iwl_mei_is_connected())
goto out;
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
if (!mei || !mei->pldr_active)
goto out;
mei->pldr_active = false;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
out:
mutex_unlock(&iwl_mei_mutex);
}
EXPORT_SYMBOL_GPL(iwl_mei_alive_notif);
void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,
const struct iwl_mei_colloc_info *colloc_info)
{
@ -1413,10 +1516,7 @@ void iwl_mei_host_associated(const struct iwl_mei_conn_info *conn_info,
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
if (!mei)
goto out;
if (!mei->amt_enabled)
if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@ -1435,7 +1535,7 @@ void iwl_mei_host_disassociated(void)
struct iwl_sap_notif_host_link_down msg = {
.hdr.type = cpu_to_le16(SAP_MSG_NOTIF_HOST_LINK_DOWN),
.hdr.len = cpu_to_le16(sizeof(msg) - sizeof(msg.hdr)),
.type = HOST_LINK_DOWN_TYPE_LONG,
.type = HOST_LINK_DOWN_TYPE_TEMPORARY,
};
mutex_lock(&iwl_mei_mutex);
@ -1445,7 +1545,7 @@ void iwl_mei_host_disassociated(void)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
if (!mei)
if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@ -1481,7 +1581,7 @@ void iwl_mei_set_rfkill_state(bool hw_rfkill, bool sw_rfkill)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
if (!mei)
if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@ -1510,7 +1610,7 @@ void iwl_mei_set_nic_info(const u8 *mac_address, const u8 *nvm_address)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
if (!mei)
if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@ -1538,7 +1638,7 @@ void iwl_mei_set_country_code(u16 mcc)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
if (!mei)
if (!mei && !mei->amt_enabled)
goto out;
iwl_mei_send_sap_msg_payload(mei->cldev, &msg.hdr);
@ -1564,7 +1664,7 @@ void iwl_mei_set_power_limit(const __le16 *power_limit)
mei = mei_cldev_get_drvdata(iwl_mei_global_cldev);
if (!mei)
if (!mei && !mei->amt_enabled)
goto out;
memcpy(msg.sar_chain_info_table, power_limit, sizeof(msg.sar_chain_info_table));
@ -1616,7 +1716,7 @@ void iwl_mei_set_netdev(struct net_device *netdev)
}
EXPORT_SYMBOL_GPL(iwl_mei_set_netdev);
void iwl_mei_device_down(void)
void iwl_mei_device_state(bool up)
{
struct iwl_mei *mei;
@ -1630,7 +1730,9 @@ void iwl_mei_device_down(void)
if (!mei)
goto out;
if (!mei->csme_taking_ownership)
mei->device_down = !up;
if (up || !mei->csme_taking_ownership)
goto out;
iwl_mei_send_sap_msg(mei->cldev,
@ -1639,7 +1741,7 @@ void iwl_mei_device_down(void)
out:
mutex_unlock(&iwl_mei_mutex);
}
EXPORT_SYMBOL_GPL(iwl_mei_device_down);
EXPORT_SYMBOL_GPL(iwl_mei_device_state);
int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops)
{
@ -1669,9 +1771,10 @@ int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops)
/* we have already a SAP connection */
if (iwl_mei_is_connected()) {
iwl_mei_send_sap_msg(mei->cldev,
SAP_MSG_NOTIF_WIFIDR_UP);
ops->rfkill(priv, mei->link_prot_state);
if (mei->amt_enabled)
iwl_mei_send_sap_msg(mei->cldev,
SAP_MSG_NOTIF_WIFIDR_UP);
ops->rfkill(priv, mei->link_prot_state, false);
}
}
ret = 0;
@ -1817,10 +1920,13 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
INIT_DELAYED_WORK(&mei->csa_throttle_end_wk,
iwl_mei_csa_throttle_end_wk);
init_waitqueue_head(&mei->get_ownership_wq);
init_waitqueue_head(&mei->pldr_wq);
spin_lock_init(&mei->data_q_lock);
INIT_WORK(&mei->netdev_work, iwl_mei_netdev_work);
mei_cldev_set_drvdata(cldev, mei);
mei->cldev = cldev;
mei->device_down = true;
do {
ret = iwl_mei_alloc_shared_mem(cldev);
@ -1884,6 +1990,7 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
}
#define SEND_SAP_MAX_WAIT_ITERATION 10
#define IWLMEI_DEVICE_DOWN_WAIT_ITERATION 50
static void iwl_mei_remove(struct mei_cl_device *cldev)
{
@ -1894,8 +2001,26 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
* We are being removed while the bus is active, it means we are
* going to suspend/ shutdown, so the NIC will disappear.
*/
if (mei_cldev_enabled(cldev) && iwl_mei_cache.ops)
iwl_mei_cache.ops->nic_stolen(iwl_mei_cache.priv);
if (mei_cldev_enabled(cldev) && iwl_mei_cache.ops) {
unsigned int iter = IWLMEI_DEVICE_DOWN_WAIT_ITERATION;
bool down = false;
/*
* In case of suspend, wait for the mac to stop and don't remove
* the interface. This will allow the interface to come back
* on resume.
*/
while (!down && iter--) {
mdelay(1);
mutex_lock(&iwl_mei_mutex);
down = mei->device_down;
mutex_unlock(&iwl_mei_mutex);
}
if (!down)
iwl_mei_cache.ops->nic_stolen(iwl_mei_cache.priv);
}
if (rcu_access_pointer(iwl_mei_cache.netdev)) {
struct net_device *dev;
@ -1921,30 +2046,33 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
mutex_lock(&iwl_mei_mutex);
/*
* Tell CSME that we are going down so that it won't access the
* memory anymore, make sure this message goes through immediately.
*/
mei->csa_throttled = false;
iwl_mei_send_sap_msg(mei->cldev,
SAP_MSG_NOTIF_HOST_GOES_DOWN);
if (mei->amt_enabled) {
/*
* Tell CSME that we are going down so that it won't access the
* memory anymore, make sure this message goes through immediately.
*/
mei->csa_throttled = false;
iwl_mei_send_sap_msg(mei->cldev,
SAP_MSG_NOTIF_HOST_GOES_DOWN);
for (i = 0; i < SEND_SAP_MAX_WAIT_ITERATION; i++) {
if (!iwl_mei_host_to_me_data_pending(mei))
break;
for (i = 0; i < SEND_SAP_MAX_WAIT_ITERATION; i++) {
if (!iwl_mei_host_to_me_data_pending(mei))
break;
msleep(5);
msleep(20);
}
/*
* If we couldn't make sure that CSME saw the HOST_GOES_DOWN
* message, it means that it will probably keep reading memory
* that we are going to unmap and free, expect IOMMU error
* messages.
*/
if (i == SEND_SAP_MAX_WAIT_ITERATION)
dev_err(&mei->cldev->dev,
"Couldn't get ACK from CSME on HOST_GOES_DOWN message\n");
}
/*
* If we couldn't make sure that CSME saw the HOST_GOES_DOWN message,
* it means that it will probably keep reading memory that we are going
* to unmap and free, expect IOMMU error messages.
*/
if (i == SEND_SAP_MAX_WAIT_ITERATION)
dev_err(&mei->cldev->dev,
"Couldn't get ACK from CSME on HOST_GOES_DOWN message\n");
mutex_unlock(&iwl_mei_mutex);
/*
@ -1976,6 +2104,7 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
*/
cancel_work_sync(&mei->send_csa_msg_wk);
cancel_delayed_work_sync(&mei->csa_throttle_end_wk);
cancel_work_sync(&mei->netdev_work);
/*
* If someone waits for the ownership, let him know that we are going
@ -1983,6 +2112,7 @@ static void iwl_mei_remove(struct mei_cl_device *cldev)
* the device.
*/
wake_up_all(&mei->get_ownership_wq);
wake_up_all(&mei->pldr_wq);
mutex_lock(&iwl_mei_mutex);

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 Intel Corporation
* Copyright (C) 2021-2022 Intel Corporation
*/
#include <uapi/linux/if_ether.h>
@ -337,10 +337,14 @@ rx_handler_result_t iwl_mei_rx_filter(struct sk_buff *orig_skb,
if (!*pass_to_csme)
return RX_HANDLER_PASS;
if (ret == RX_HANDLER_PASS)
if (ret == RX_HANDLER_PASS) {
skb = skb_copy(orig_skb, GFP_ATOMIC);
else
if (!skb)
return RX_HANDLER_PASS;
} else {
skb = orig_skb;
}
/* CSME wants the MAC header as well, push it back */
skb_push(skb, skb->data - skb_mac_header(skb));

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 Intel Corporation
* Copyright (C) 2021 - 2022 Intel Corporation
*/
#ifndef __sap_h__
@ -203,6 +203,7 @@ struct iwl_sap_me_msg_start_ok {
* @SAP_MSG_NOTIF_NIC_OWNER: Payload is a DW. See &enum iwl_sap_nic_owner.
* @SAP_MSG_NOTIF_CSME_CONN_STATUS: See &struct iwl_sap_notif_conn_status.
* @SAP_MSG_NOTIF_NVM: See &struct iwl_sap_nvm.
* @SAP_MSG_NOTIF_PLDR_ACK: See &struct iwl_sap_pldr_ack_data.
* @SAP_MSG_NOTIF_FROM_CSME_MAX: Not used.
*
* @SAP_MSG_NOTIF_FROM_HOST_MIN: Not used.
@ -226,6 +227,8 @@ struct iwl_sap_me_msg_start_ok {
* @SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED: No payload.
* @SAP_MSG_NOTIF_SAR_LIMITS: See &struct iwl_sap_notif_sar_limits.
* @SAP_MSG_NOTIF_GET_NVM: No payload. Triggers %SAP_MSG_NOTIF_NVM.
* @SAP_MSG_NOTIF_PLDR: See &struct iwl_sap_pldr_data.
* @SAP_MSG_NOTIF_PLDR_END: See &struct iwl_sap_pldr_end_data.
* @SAP_MSG_NOTIF_FROM_HOST_MAX: Not used.
*
* @SAP_MSG_DATA_MIN: Not used.
@ -258,6 +261,8 @@ enum iwl_sap_msg {
SAP_MSG_NOTIF_NIC_OWNER = 511,
SAP_MSG_NOTIF_CSME_CONN_STATUS = 512,
SAP_MSG_NOTIF_NVM = 513,
/* 514 - 517 not supported */
SAP_MSG_NOTIF_PLDR_ACK = 518,
SAP_MSG_NOTIF_FROM_CSME_MAX,
SAP_MSG_NOTIF_FROM_HOST_MIN = 1000,
@ -279,6 +284,9 @@ enum iwl_sap_msg {
SAP_MSG_NOTIF_HOST_OWNERSHIP_CONFIRMED = 1015,
SAP_MSG_NOTIF_SAR_LIMITS = 1016,
SAP_MSG_NOTIF_GET_NVM = 1017,
/* 1018 - 1023 not supported */
SAP_MSG_NOTIF_PLDR = 1024,
SAP_MSG_NOTIF_PLDR_END = 1025,
SAP_MSG_NOTIF_FROM_HOST_MAX,
SAP_MSG_DATA_MIN = 2000,
@ -334,12 +342,14 @@ enum iwl_sap_wifi_auth_type {
/**
* enum iwl_sap_wifi_cipher_alg
* @SAP_WIFI_CIPHER_ALG_NONE: TBD
* @SAP_WIFI_CIPHER_ALG_TKIP: TBD
* @SAP_WIFI_CIPHER_ALG_CCMP: TBD
* @SAP_WIFI_CIPHER_ALG_GCMP: TBD
* @SAP_WIFI_CIPHER_ALG_GCMP_256: TBD
*/
enum iwl_sap_wifi_cipher_alg {
SAP_WIFI_CIPHER_ALG_NONE = IWL_MEI_CIPHER_NONE,
SAP_WIFI_CIPHER_ALG_TKIP = IWL_MEI_CIPHER_TKIP,
SAP_WIFI_CIPHER_ALG_CCMP = IWL_MEI_CIPHER_CCMP,
SAP_WIFI_CIPHER_ALG_GCMP = IWL_MEI_CIPHER_GCMP,
SAP_WIFI_CIPHER_ALG_GCMP_256 = IWL_MEI_CIPHER_GCMP_256,
@ -730,4 +740,47 @@ struct iwl_sap_cb_data {
u8 payload[];
};
/**
* struct iwl_sap_pldr_data - payload of %SAP_MSG_NOTIF_PLDR
* @hdr: The SAP header.
* @version: SAP message version
*/
struct iwl_sap_pldr_data {
struct iwl_sap_hdr hdr;
__le32 version;
} __packed;
/**
* enum iwl_sap_pldr_status -
* @SAP_PLDR_STATUS_SUCCESS: PLDR started/ended successfully
* @SAP_PLDR_STATUS_FAILURE: PLDR failed to start/end
*/
enum iwl_sap_pldr_status {
SAP_PLDR_STATUS_SUCCESS = 0,
SAP_PLDR_STATUS_FAILURE = 1,
};
/*
* struct iwl_sap_pldr_end_data - payload of %SAP_MSG_NOTIF_PLDR_END
* @hdr: The SAP header.
* @version: SAP message version
* @status: PLDR end status
*/
struct iwl_sap_pldr_end_data {
struct iwl_sap_hdr hdr;
__le32 version;
__le32 status;
} __packed;
/*
* struct iwl_sap_pldr_ack_data - payload of %SAP_MSG_NOTIF_PLDR_ACK
* @version: SAP message version
* @status: CSME accept/refuse to the PLDR request
*/
struct iwl_sap_pldr_ack_data {
struct iwl_sap_hdr hdr;
__le32 version;
__le32 status;
} __packed;
#endif /* __sap_h__ */

View file

@ -7,6 +7,7 @@ iwlmvm-y += power.o coex.o
iwlmvm-y += tt.o offloading.o tdls.o
iwlmvm-y += ftm-responder.o ftm-initiator.o
iwlmvm-y += rfi.o
iwlmvm-y += mld-key.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
iwlmvm-$(CONFIG_PM) += d3.o

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@ -1248,7 +1248,7 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len)
mvmvif = iwl_mvm_vif_from_mac80211(vif);
info = IEEE80211_SKB_CB(beacon);
rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif);
rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);
beacon_cmd.flags =
cpu_to_le16(iwl_mvm_mac_ctxt_get_beacon_flags(mvm->fw, rate));

View file

@ -404,6 +404,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
return -EIO;
}
iwl_mei_alive_notif(!ret);
ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait);
if (ret) {
IWL_ERR(mvm, "Timeout waiting for PNVM load!\n");
@ -1456,6 +1458,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
struct ieee80211_channel *chan;
struct cfg80211_chan_def chandef;
struct ieee80211_supported_band *sband = NULL;
u32 sb_cfg;
lockdep_assert_held(&mvm->mutex);
@ -1463,6 +1466,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (ret)
return ret;
sb_cfg = iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG);
if (!(sb_cfg & SB_CFG_RESIDES_IN_OTP_MASK) && iwl_mei_pldr_req())
return ret;
ret = iwl_mvm_load_rt_fw(mvm);
if (ret) {
IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret);
@ -1665,6 +1672,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
iwl_rfi_send_config_cmd(mvm, NULL);
}
iwl_mvm_mei_device_state(mvm, true);
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
return 0;
error:

View file

@ -788,14 +788,40 @@ static u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)
return ie - beacon;
}
u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
struct ieee80211_vif *vif)
static u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,
struct ieee80211_tx_info *info,
struct ieee80211_vif *vif)
{
struct ieee80211_supported_band *sband;
unsigned long basic = vif->bss_conf.basic_rates;
u16 lowest_cck = IWL_RATE_COUNT, lowest_ofdm = IWL_RATE_COUNT;
u8 rate;
if (info->band == NL80211_BAND_2GHZ && !vif->p2p)
rate = IWL_FIRST_CCK_RATE;
else
rate = IWL_FIRST_OFDM_RATE;
u32 i;
sband = mvm->hw->wiphy->bands[info->band];
for_each_set_bit(i, &basic, BITS_PER_LONG) {
u16 hw = sband->bitrates[i].hw_value;
if (hw >= IWL_FIRST_OFDM_RATE) {
if (lowest_ofdm > hw)
lowest_ofdm = hw;
} else if (lowest_cck > hw) {
lowest_cck = hw;
}
}
if (info->band == NL80211_BAND_2GHZ && !vif->p2p) {
if (lowest_cck != IWL_RATE_COUNT)
rate = lowest_cck;
else if (lowest_ofdm != IWL_RATE_COUNT)
rate = lowest_ofdm;
else
rate = IWL_RATE_1M_INDEX;
} else if (lowest_ofdm != IWL_RATE_COUNT) {
rate = lowest_ofdm;
} else {
rate = IWL_RATE_6M_INDEX;
}
return rate;
}
@ -812,6 +838,24 @@ u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)
return flags;
}
u8 iwl_mvm_mac_ctxt_get_beacon_rate(struct iwl_mvm *mvm,
struct ieee80211_tx_info *info,
struct ieee80211_vif *vif)
{
struct ieee80211_supported_band *sband =
mvm->hw->wiphy->bands[info->band];
u32 legacy = vif->bss_conf.beacon_tx_rate.control[info->band].legacy;
/* if beacon rate was configured try using it */
if (hweight32(legacy) == 1) {
u32 rate = ffs(legacy) - 1;
return sband->bitrates[rate].hw_value;
}
return iwl_mvm_mac_ctxt_get_lowest_rate(mvm, info, vif);
}
static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct sk_buff *beacon,
@ -842,7 +886,7 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
RATE_MCS_ANT_POS);
rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif);
rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);
tx->rate_n_flags |=
cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate));
@ -926,7 +970,7 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(beacon);
struct iwl_mac_beacon_cmd beacon_cmd = {};
u8 rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif);
u8 rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif);
u16 flags;
struct ieee80211_chanctx_conf *ctx;
int channel;

View file

@ -374,6 +374,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->n_cipher_suites++;
}
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_FTM_CALIBRATED)) {
wiphy_ext_feature_set(hw->wiphy,
@ -2306,6 +2309,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
*/
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
&mvm->status)) {
/* first remove remaining keys */
iwl_mvm_sec_key_remove_ap(mvm, vif);
/*
* Remove AP station now that
* the MAC is unassoc
@ -3059,6 +3065,9 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm,
return;
switch (mvm_sta->pairwise_cipher) {
case WLAN_CIPHER_SUITE_TKIP:
conn_info.pairwise_cipher = IWL_MEI_CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
conn_info.pairwise_cipher = IWL_MEI_CIPHER_CCMP;
break;
@ -3461,6 +3470,8 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
struct iwl_mvm_sta *mvmsta = NULL;
struct iwl_mvm_key_pn *ptk_pn;
int keyidx = key->keyidx;
u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
int ret, i;
u8 key_offset;
@ -3600,7 +3611,12 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
mvmsta->pairwise_cipher = key->cipher;
IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset);
if (sec_key_ver)
ret = iwl_mvm_sec_key_add(mvm, vif, sta, key);
else
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset);
if (ret) {
IWL_WARN(mvm, "set key failed\n");
key->hw_key_idx = STA_KEY_IDX_INVALID;
@ -3653,7 +3669,10 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
}
IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n");
ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);
if (sec_key_ver)
ret = iwl_mvm_sec_key_del(mvm, vif, sta, key);
else
ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);
break;
default:
ret = -EINVAL;

View file

@ -0,0 +1,226 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2022 Intel Corporation
*/
#include <linux/kernel.h>
#include <net/mac80211.h>
#include "mvm.h"
#include "fw/api/context.h"
#include "fw/api/datapath.h"
static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (vif->type == NL80211_IFTYPE_AP &&
!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return BIT(mvmvif->mcast_sta.sta_id);
if (sta) {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
return BIT(mvmsta->sta_id);
}
if (vif->type == NL80211_IFTYPE_STATION &&
mvmvif->ap_sta_id != IWL_MVM_INVALID_STA)
return BIT(mvmvif->ap_sta_id);
/* invalid */
return 0;
}
static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 flags = 0;
if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
flags |= IWL_SEC_KEY_FLAG_MCAST_KEY;
switch (keyconf->cipher) {
case WLAN_CIPHER_SUITE_WEP104:
flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
fallthrough;
case WLAN_CIPHER_SUITE_WEP40:
flags |= IWL_SEC_KEY_FLAG_CIPHER_WEP;
break;
case WLAN_CIPHER_SUITE_TKIP:
flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_CCMP:
flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP;
break;
case WLAN_CIPHER_SUITE_GCMP_256:
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
fallthrough;
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP;
break;
}
rcu_read_lock();
if (!sta && vif->type == NL80211_IFTYPE_STATION &&
mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) {
u8 sta_id = mvmvif->ap_sta_id;
sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
lockdep_is_held(&mvm->mutex));
}
if (!IS_ERR_OR_NULL(sta) && sta->mfp)
flags |= IWL_SEC_KEY_FLAG_MFP;
rcu_read_unlock();
return flags;
}
static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
u32 key_flags, u32 keyidx, u32 flags)
{
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
struct iwl_sec_key_cmd cmd = {
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
.u.remove.sta_mask = cpu_to_le32(sta_mask),
.u.remove.key_id = cpu_to_le32(keyidx),
.u.remove.key_flags = cpu_to_le32(key_flags),
};
return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
}
int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf)
{
u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
struct iwl_sec_key_cmd cmd = {
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
.u.add.sta_mask = cpu_to_le32(sta_mask),
.u.add.key_id = cpu_to_le32(keyconf->keyidx),
.u.add.key_flags = cpu_to_le32(key_flags),
.u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)),
};
int ret;
if (WARN_ON(keyconf->keylen > sizeof(cmd.u.add.key)))
return -EINVAL;
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key,
keyconf->keylen);
else
memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen);
if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) {
memcpy(cmd.u.add.tkip_mic_rx_key,
keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
8);
memcpy(cmd.u.add.tkip_mic_tx_key,
keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
8);
}
ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
if (ret)
return ret;
/*
* For WEP, the same key is used for multicast and unicast so need to
* upload it again. If this fails, remove the original as well.
*/
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY);
ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
if (ret)
__iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
keyconf->keyidx, 0);
}
return ret;
}
static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf,
u32 flags)
{
u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
int ret;
ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
flags);
if (ret)
return ret;
/* For WEP, delete the key again as unicast */
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
key_flags ^= IWL_SEC_KEY_FLAG_MCAST_KEY;
ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
keyconf->keyidx, flags);
}
return ret;
}
int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf)
{
return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0);
}
static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key,
void *data)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (key->hw_key_idx == STA_KEY_IDX_INVALID)
return;
if (sta)
return;
_iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
key->hw_key_idx = STA_KEY_IDX_INVALID;
}
void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
if (WARN_ON(vif->type != NL80211_IFTYPE_STATION ||
mvmvif->ap_sta_id == IWL_MVM_INVALID_STA))
return;
if (!sec_key_ver)
return;
ieee80211_iter_keys_rcu(mvm->hw, vif,
iwl_mvm_sec_key_remove_ap_iter,
NULL);
}

View file

@ -1644,7 +1644,8 @@ int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
struct sk_buff *beacon,
void *data, int len);
u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
u8 iwl_mvm_mac_ctxt_get_beacon_rate(struct iwl_mvm *mvm,
struct ieee80211_tx_info *info,
struct ieee80211_vif *vif);
u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw,
u8 rate_idx);
@ -2079,6 +2080,18 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,
struct dentry *dir);
#endif
/* new MLD related APIs */
int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf);
int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf);
void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm,
struct iwl_rfi_lut_entry *rfi_table);
struct iwl_rfi_freq_table_resp_cmd *iwl_rfi_get_freq_table(struct iwl_mvm *mvm);
@ -2201,10 +2214,10 @@ static inline void iwl_mvm_mei_host_disassociated(struct iwl_mvm *mvm)
iwl_mei_host_disassociated();
}
static inline void iwl_mvm_mei_device_down(struct iwl_mvm *mvm)
static inline void iwl_mvm_mei_device_state(struct iwl_mvm *mvm, bool up)
{
if (mvm->mei_registered)
iwl_mei_device_down();
iwl_mei_device_state(up);
}
static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm)

View file

@ -547,6 +547,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {
HCMD_NAME(TLC_MNG_CONFIG_CMD),
HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD),
HCMD_NAME(SCD_QUEUE_CONFIG_CMD),
HCMD_NAME(SEC_KEY_CMD),
HCMD_NAME(MONITOR_NOTIF),
HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST),
HCMD_NAME(STA_PM_NOTIF),
@ -1375,7 +1376,7 @@ void iwl_mvm_stop_device(struct iwl_mvm *mvm)
iwl_trans_stop_device(mvm->trans);
iwl_free_fw_paging(&mvm->fwrt);
iwl_fw_dump_conf_clear(&mvm->fwrt);
iwl_mvm_mei_device_down(mvm);
iwl_mvm_mei_device_state(mvm, false);
}
static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)

View file

@ -1747,10 +1747,12 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm,
rx_status->rate_idx = rate;
if (WARN_ONCE(rate < 0 || rate > 0xFF,
"Invalid rate flags 0x%x, band %d,\n",
rate_n_flags, rx_status->band))
if ((rate < 0 || rate > 0xFF) && net_ratelimit()) {
IWL_ERR(mvm, "Invalid rate flags 0x%x, band %d,\n",
rate_n_flags, rx_status->band);
rx_status->rate_idx = 0;
}
break;
}
}

View file

@ -1954,6 +1954,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
if (vif->cfg.assoc)
return ret;
/* first remove remaining keys */
iwl_mvm_sec_key_remove_ap(mvm, vif);
/* unassoc - go ahead - remove the AP STA now */
mvmvif->ap_sta_id = IWL_MVM_INVALID_STA;
}

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2012-2014, 2018-2022 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@ -183,7 +183,10 @@ static u32 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
struct ieee80211_tx_info *info,
bool amsdu)
{
if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ)
if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ ||
(mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_BZ &&
CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL &&
mvm->trans->hw_rev_step == SILICON_A_STEP))
return iwl_mvm_tx_csum_pre_bz(mvm, skb, info, amsdu);
return iwl_mvm_tx_csum_bz(mvm, skb, amsdu);
}
@ -1171,9 +1174,15 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
/* From now on, we cannot access info->control */
iwl_mvm_skb_prepare_status(skb, dev_cmd);
/*
* The IV is introduced by the HW for new tx api, and it is not present
* in the skb, hence, don't tell iwl_mvm_mei_tx_copy_to_csme about the
* IV for those devices.
*/
if (ieee80211_is_data(fc))
iwl_mvm_mei_tx_copy_to_csme(mvm, skb,
info->control.hw_key ?
info->control.hw_key &&
!iwl_mvm_has_new_tx_api(mvm) ?
info->control.hw_key->iv_len : 0);
if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id))