iwlwifi: add support for getting HW address from CSR

From 9000 family on, we need to get HW address from host
CSR registers.
OEM can override it by fusing the override registers - read
those first, and if those are 0 - read the OTP registers instead.

In addition - bail out if no valid mac address is present. Make
it shared for all NICs.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This commit is contained in:
Sara Sharon 2016-03-07 14:18:29 +02:00 коммит произвёл Emmanuel Grumbach
Родитель 7b5424361e
Коммит 17c867bfe8
4 изменённых файлов: 67 добавлений и 21 удалений

Просмотреть файл

@ -140,7 +140,8 @@ static const struct iwl_tt_params iwl9000_tt_params = {
.thermal_params = &iwl9000_tt_params, \
.apmg_not_supported = true, \
.mq_rx_supported = true, \
.vht_mu_mimo_supported = true
.vht_mu_mimo_supported = true, \
.mac_addr_from_csr = true
const struct iwl_cfg iwl9260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 9260",

Просмотреть файл

@ -297,6 +297,7 @@ struct iwl_pwr_tx_backoff {
* @host_interrupt_operation_mode: device needs host interrupt operation
* mode set
* @nvm_hw_section_num: the ID of the HW NVM section
* @mac_addr_from_csr: read HW address from CSR registers
* @features: hw features, any combination of feature_whitelist
* @pwr_tx_backoffs: translation table between power limits and backoffs
* @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
@ -345,6 +346,7 @@ struct iwl_cfg {
const bool host_interrupt_operation_mode;
bool high_temp;
u8 nvm_hw_section_num;
bool mac_addr_from_csr;
bool lp_xtal_workaround;
const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
bool no_power_up_nic_in_init;

Просмотреть файл

@ -598,4 +598,14 @@ enum msix_hw_int_causes {
#define MSIX_AUTO_CLEAR_CAUSE 0
#define MSIX_NON_AUTO_CLEAR_CAUSE BIT(7)
/*****************************************************************************
* HW address related registers *
*****************************************************************************/
#define CSR_ADDR_BASE (0x380)
#define CSR_MAC_ADDR0_OTP (CSR_ADDR_BASE)
#define CSR_MAC_ADDR1_OTP (CSR_ADDR_BASE + 4)
#define CSR_MAC_ADDR0_STRAP (CSR_ADDR_BASE + 8)
#define CSR_MAC_ADDR1_STRAP (CSR_ADDR_BASE + 0xC)
#endif /* !__iwl_csr_h__ */

Просмотреть файл

@ -71,6 +71,8 @@
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
#include "iwl-prph.h"
#include "iwl-io.h"
#include "iwl-csr.h"
/* NVM offsets (in words) definitions */
enum wkp_nvm_offsets {
@ -524,6 +526,36 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg);
}
static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest)
{
const u8 *hw_addr;
hw_addr = (const u8 *)&mac_addr0;
dest[0] = hw_addr[3];
dest[1] = hw_addr[2];
dest[2] = hw_addr[1];
dest[3] = hw_addr[0];
hw_addr = (const u8 *)&mac_addr1;
dest[4] = hw_addr[1];
dest[5] = hw_addr[0];
}
static void iwl_set_hw_address_from_csr(struct iwl_trans *trans,
struct iwl_nvm_data *data)
{
__le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP));
__le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP));
/* If OEM did not fuse address - get it from OTP */
if (!mac_addr0 && !mac_addr1) {
mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP));
mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP));
}
iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
}
static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
@ -564,21 +596,8 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
WFMP_MAC_ADDR_0));
__le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans,
WFMP_MAC_ADDR_1));
/* read the MAC address from HW resisters */
hw_addr = (const u8 *)&mac_addr0;
data->hw_addr[0] = hw_addr[3];
data->hw_addr[1] = hw_addr[2];
data->hw_addr[2] = hw_addr[1];
data->hw_addr[3] = hw_addr[0];
hw_addr = (const u8 *)&mac_addr1;
data->hw_addr[4] = hw_addr[1];
data->hw_addr[5] = hw_addr[0];
if (!is_valid_ether_addr(data->hw_addr))
IWL_ERR(trans,
"mac address (%pM) from hw section is not valid\n",
data->hw_addr);
iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
return;
}
@ -586,12 +605,14 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
IWL_ERR(trans, "mac address is not found\n");
}
static void iwl_set_hw_address(struct iwl_trans *trans,
const struct iwl_cfg *cfg,
struct iwl_nvm_data *data, const __le16 *nvm_hw,
const __le16 *mac_override)
static int iwl_set_hw_address(struct iwl_trans *trans,
const struct iwl_cfg *cfg,
struct iwl_nvm_data *data, const __le16 *nvm_hw,
const __le16 *mac_override)
{
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
if (cfg->mac_addr_from_csr) {
iwl_set_hw_address_from_csr(trans, data);
} else if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR);
/* The byte order is little endian 16 bit, meaning 214365 */
@ -605,6 +626,13 @@ static void iwl_set_hw_address(struct iwl_trans *trans,
iwl_set_hw_address_family_8000(trans, cfg, data,
mac_override, nvm_hw);
}
if (!is_valid_ether_addr(data->hw_addr)) {
IWL_ERR(trans, "no valid mac address was found\n");
return -EINVAL;
}
return 0;
}
struct iwl_nvm_data *
@ -680,7 +708,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
ch_section = regulatory;
}
iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override);
/* If no valid mac address was found - bail out */
if (iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override)) {
kfree(data);
return NULL;
}
iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains,
lar_fw_supported && lar_enabled);
data->calib_version = 255;