Skip to content
Permalink
Browse files
iwlwifi: integrate with iwlmei
This allows to cooperate with iwlmei.

Co-Developed-by: Ayala Beker <ayala.beker@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
  • Loading branch information
egrumbach authored and intel-lab-lkp committed Apr 12, 2021
1 parent 3fa7e71 commit 282793cf36fcc2c1b65dd2ca6ba4abc0cff126ac
Show file tree
Hide file tree
Showing 10 changed files with 423 additions and 19 deletions.
@@ -22,6 +22,7 @@
#include "fw/api/commands.h"
#include "fw/api/cmdhdr.h"
#include "fw/img.h"
#include "mei/iwl-mei.h"

/* NVM offsets (in words) definitions */
enum nvm_offsets {
@@ -1060,6 +1061,66 @@ iwl_nvm_no_wide_in_5ghz(struct iwl_trans *trans, const struct iwl_cfg *cfg,
return false;
}

struct iwl_nvm_data *
iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_mei_nvm *mei_nvm,
const struct iwl_fw *fw)
{
struct iwl_nvm_data *data;
u32 sbands_flags = 0;
u8 rx_chains = fw->valid_rx_ant;
u8 tx_chains = fw->valid_rx_ant;

if (cfg->uhb_supported)
data = kzalloc(struct_size(data, channels,
IWL_NVM_NUM_CHANNELS_UHB),
GFP_KERNEL);
else
data = kzalloc(struct_size(data, channels,
IWL_NVM_NUM_CHANNELS_EXT),
GFP_KERNEL);
if (!data)
return NULL;

BUILD_BUG_ON(ARRAY_SIZE(mei_nvm->channels) !=
IWL_NVM_NUM_CHANNELS_UHB);
data->nvm_version = mei_nvm->nvm_version;

iwl_set_radio_cfg(cfg, data, mei_nvm->radio_cfg);
if (data->valid_tx_ant)
tx_chains &= data->valid_tx_ant;
if (data->valid_rx_ant)
rx_chains &= data->valid_rx_ant;

data->sku_cap_mimo_disabled = false;
data->sku_cap_band_24ghz_enable = true;
data->sku_cap_band_52ghz_enable = true;
data->sku_cap_11n_enable =
!(iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL);
data->sku_cap_11ac_enable = true;
data->sku_cap_11ax_enable =
mei_nvm->caps & MEI_NVM_CAPS_11AX_SUPPORT;

data->lar_enabled = mei_nvm->caps & MEI_NVM_CAPS_LARI_SUPPORT;

data->n_hw_addrs = mei_nvm->n_hw_addrs;
/* If no valid mac address was found - bail out */
if (iwl_set_hw_address(trans, cfg, data, NULL, NULL)) {
kfree(data);
return NULL;
}

if (data->lar_enabled &&
fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT))
sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR;

iwl_init_sbands(trans, data, mei_nvm->channels, tx_chains, rx_chains,
sbands_flags, true);

return data;
}
IWL_EXPORT_SYMBOL(iwl_parse_mei_nvm_data);

struct iwl_nvm_data *
iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_fw *fw,
@@ -1,13 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2005-2015, 2018-2020 Intel Corporation
* Copyright (C) 2005-2015, 2018-2021 Intel Corporation
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
#ifndef __iwl_nvm_parse_h__
#define __iwl_nvm_parse_h__

#include <net/cfg80211.h>
#include "iwl-eeprom-parse.h"
#include "mei/iwl-mei.h"

/**
* enum iwl_nvm_sbands_flags - modification flags for the channel profiles
@@ -81,4 +82,12 @@ void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data,
struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
const struct iwl_fw *fw);

/**
* iwl_parse_mei_nvm_data - parse the mei_nvm_data and get an iwl_nvm_data
*/
struct iwl_nvm_data *
iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_mei_nvm *mei_nvm,
const struct iwl_fw *fw);

#endif /* __iwl_nvm_parse_h__ */
@@ -902,6 +902,7 @@ struct iwl_trans_txqs {
/**
* struct iwl_trans - transport common data
*
* @csme_own - true if we couldn't get ownership on the device
* @ops - pointer to iwl_trans_ops
* @op_mode - pointer to the op_mode
* @trans_cfg: the trans-specific configuration part
@@ -936,6 +937,7 @@ struct iwl_trans_txqs {
* @iwl_trans_txqs: transport tx queues data.
*/
struct iwl_trans {
bool csme_own;
const struct iwl_trans_ops *ops;
struct iwl_op_mode *op_mode;
const struct iwl_cfg_trans_params *trans_cfg;
@@ -796,6 +796,8 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
if (ret)
return ret;

iwl_mei_set_power_limit(per_chain);

IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n");
return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd);
}
@@ -1392,7 +1394,6 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm)
if (iwl_mvm_has_unified_ucode(mvm))
return iwl_run_unified_mvm_ucode(mvm);

WARN_ON(!mvm->nvm_data);
ret = iwl_run_init_mvm_ucode(mvm);

if (ret) {
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2012-2014, 2018-2020 Intel Corporation
* Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -189,6 +189,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
if (IS_ERR_OR_NULL(resp)) {
IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n",
PTR_ERR_OR_ZERO(resp));
resp = NULL;
goto out;
}

@@ -210,7 +211,6 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
__le16_to_cpu(resp->cap), resp_ver);
/* Store the return source id */
src_id = resp->source_id;
kfree(resp);
if (IS_ERR_OR_NULL(regd)) {
IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n",
PTR_ERR_OR_ZERO(regd));
@@ -222,7 +222,10 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
mvm->lar_regdom_set = true;
mvm->mcc_src = src_id;

iwl_mei_set_country_code(__le16_to_cpu(resp->mcc));

out:
kfree(resp);
return regd;
}

@@ -1082,6 +1085,27 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)

lockdep_assert_held(&mvm->mutex);

ret = iwl_mvm_mei_get_ownership(mvm);
if (ret)
return ret;

if (mvm->mei_nvm_data) {
/* We got the NIC, we can now free the MEI NVM data */
kfree(mvm->mei_nvm_data);
mvm->mei_nvm_data = NULL;

/*
* We can't free the nvm_data we allocated based on the SAP
* data because we registered to cfg80211 with the channels
* allocated on mvm->nvm_data. Keep a pointer in temp_nvm_data
* just in order to be able free it later.
* NULLify nvm_data so that we will read the NVM from the
* firmware this time.
*/
mvm->temp_nvm_data = mvm->nvm_data;
mvm->nvm_data = NULL;
}

if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status)) {
/*
* Now convert the HW_RESTART_REQUESTED flag to IN_HW_RESTART
@@ -1506,6 +1530,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
mvm->monitor_on = true;

iwl_mvm_vif_dbgfs_register(mvm, vif);

if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
!mvm->csme_vif && mvm->mei_registered) {
iwl_mei_set_nic_info(vif->addr, mvm->nvm_data->hw_addr);
iwl_mei_set_netdev(ieee80211_vif_to_wdev(vif)->netdev);
mvm->csme_vif = vif;
}

goto out_unlock;

out_unbind:
@@ -1558,6 +1591,11 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,

mutex_lock(&mvm->mutex);

if (vif == mvm->csme_vif) {
iwl_mei_set_netdev(NULL);
mvm->csme_vif = NULL;
}

probe_data = rcu_dereference_protected(mvmvif->probe_resp_data,
lockdep_is_held(&mvm->mutex));
RCU_INIT_POINTER(mvmvif->probe_resp_data, NULL);
@@ -28,6 +28,7 @@
#include "fw/runtime.h"
#include "fw/dbg.h"
#include "fw/acpi.h"
#include "mei/iwl-mei.h"
#include "iwl-nvm-parse.h"

#include <linux/average.h>
@@ -828,6 +829,18 @@ struct iwl_mvm {

const char *nvm_file_name;
struct iwl_nvm_data *nvm_data;
struct iwl_mei_nvm *mei_nvm_data;
struct iwl_mvm_csme_conn_info __rcu *csme_conn_info;
bool mei_rfkill_blocked;
bool mei_registered;
struct work_struct sap_connected_wk;

/*
* NVM built based on the SAP data but that we can't free even after
* we get ownership because it contains the cfg80211's channel.
*/
struct iwl_nvm_data *temp_nvm_data;

/* NVM sections */
struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS];

@@ -1017,6 +1030,8 @@ struct iwl_mvm {
/* Indicate if 32Khz external clock is valid */
u32 ext_clock_valid;

/* This vif used by CSME to send / receive traffic */
struct ieee80211_vif *csme_vif;
struct ieee80211_vif __rcu *csa_vif;
struct ieee80211_vif __rcu *csa_tx_blocked_vif;
u8 csa_tx_block_bcn_timeout;
@@ -1129,6 +1144,11 @@ enum iwl_mvm_status {
IWL_MVM_STATUS_IN_D3,
};

struct iwl_mvm_csme_conn_info {
struct rcu_head rcu_head;
struct iwl_mei_conn_info conn_info;
};

/* Keep track of completed init configuration */
enum iwl_mvm_init_status {
IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE = BIT(0),
@@ -1920,6 +1940,7 @@ void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm);
int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm);
int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget);
struct iwl_mvm_csme_conn_info *iwl_mvm_get_csme_conn_info(struct iwl_mvm *mvm);

/* Location Aware Regulatory */
struct iwl_mcc_update_resp *
@@ -2138,4 +2159,53 @@ enum iwl_location_cipher iwl_mvm_cipher_to_location_cipher(u32 cipher)
return IWL_LOCATION_CIPHER_INVALID;
}
}

static inline int iwl_mvm_mei_get_ownership(struct iwl_mvm *mvm)
{
if (mvm->mei_registered)
return iwl_mei_get_ownership();
return 0;
}

static inline void iwl_mvm_mei_tx_copy_to_csme(struct iwl_mvm *mvm,
struct sk_buff *skb,
unsigned int ivlen)
{
if (mvm->mei_registered)
iwl_mei_tx_copy_to_csme(skb, ivlen);
}

static inline void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm,
const struct iwl_mei_conn_info *conn_info,
const struct iwl_mei_colloc_info *colloc_info)
{
if (mvm->mei_registered)
iwl_mei_host_associated(conn_info, colloc_info);
}

static inline void iwl_mvm_mei_host_disassociated(struct iwl_mvm *mvm, u8 type)
{
if (mvm->mei_registered)
iwl_mei_host_disassociated(type);
}

static inline void iwl_mvm_mei_device_down(struct iwl_mvm *mvm)
{
if (mvm->mei_registered)
iwl_mei_device_down();
}

static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm, bool sw_rfkill)
{
if (mvm->mei_registered)
iwl_mei_set_rfkill_state(iwl_mvm_is_radio_killed(mvm), sw_rfkill);
}

static inline void iwl_mvm_send_roaming_forbidden_event(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
bool forbidden)
{
/* TODO */
}

#endif /* __IWL_MVM_H__ */

0 comments on commit 282793c

Please sign in to comment.