Commit aa8a7219 authored by Kalle Valo's avatar Kalle Valo

Merge tag 'iwlwifi-next-for-kalle-2016-01-07_2' of...

Merge tag 'iwlwifi-next-for-kalle-2016-01-07_2' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

* bug fixes and improvements for firmware debug system (Golan and myself)
* fixes for D0i3 (Eliad)
* prevent muliple stations with the same MAC address
* advertise support for Rx A-MSDU in A-MPDU
* scan related fixes
* support -20.ucode
* fix WoWLAN for iwldvm
* preparations towards multiple Rx queues
* platform power improvements for GO mode when no clients are associated
parents 236c52ca 62d7476d
...@@ -1154,6 +1154,9 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) ...@@ -1154,6 +1154,9 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
priv->ucode_loaded = false; priv->ucode_loaded = false;
iwl_trans_stop_device(priv->trans); iwl_trans_stop_device(priv->trans);
ret = iwl_trans_start_hw(priv->trans);
if (ret)
goto out;
priv->wowlan = true; priv->wowlan = true;
......
...@@ -72,8 +72,8 @@ ...@@ -72,8 +72,8 @@
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL7260_UCODE_API_MAX 17 #define IWL7260_UCODE_API_MAX 17
#define IWL7265_UCODE_API_MAX 19 #define IWL7265_UCODE_API_MAX 17
#define IWL7265D_UCODE_API_MAX 19 #define IWL7265D_UCODE_API_MAX 20
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 13 #define IWL7260_UCODE_API_OK 13
......
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL8000_UCODE_API_MAX 19 #define IWL8000_UCODE_API_MAX 20
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 13 #define IWL8000_UCODE_API_OK 13
......
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL9000_UCODE_API_MAX 16 #define IWL9000_UCODE_API_MAX 20
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL9000_UCODE_API_OK 13 #define IWL9000_UCODE_API_OK 13
......
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
* &struct iwl_fw_error_dump_rb * &struct iwl_fw_error_dump_rb
* @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were * @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were
* paged to the DRAM. * paged to the DRAM.
* @IWL_FW_ERROR_DUMP_RADIO_REG: Dump the radio registers.
*/ */
enum iwl_fw_error_dump_type { enum iwl_fw_error_dump_type {
/* 0 is deprecated */ /* 0 is deprecated */
...@@ -103,6 +104,7 @@ enum iwl_fw_error_dump_type { ...@@ -103,6 +104,7 @@ enum iwl_fw_error_dump_type {
IWL_FW_ERROR_DUMP_ERROR_INFO = 10, IWL_FW_ERROR_DUMP_ERROR_INFO = 10,
IWL_FW_ERROR_DUMP_RB = 11, IWL_FW_ERROR_DUMP_RB = 11,
IWL_FW_ERROR_DUMP_PAGING = 12, IWL_FW_ERROR_DUMP_PAGING = 12,
IWL_FW_ERROR_DUMP_RADIO_REG = 13,
IWL_FW_ERROR_DUMP_MAX, IWL_FW_ERROR_DUMP_MAX,
}; };
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -309,6 +311,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; ...@@ -309,6 +311,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
* @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
* @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
* @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
* @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what
* antenna the beacon should be transmitted
* @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2
* *
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used * @NUM_IWL_UCODE_TLV_CAPA: number of bits used
*/ */
...@@ -336,6 +341,8 @@ enum iwl_ucode_tlv_capa { ...@@ -336,6 +341,8 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64,
IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65,
IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67,
IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71,
IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73,
NUM_IWL_UCODE_TLV_CAPA NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__ #ifdef __CHECKER__
...@@ -550,6 +557,8 @@ enum iwl_fw_dbg_trigger_vif_type { ...@@ -550,6 +557,8 @@ enum iwl_fw_dbg_trigger_vif_type {
* @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what * @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what
* configuration should be applied when the triggers kicks in. * configuration should be applied when the triggers kicks in.
* @occurrences: number of occurrences. 0 means the trigger will never fire. * @occurrences: number of occurrences. 0 means the trigger will never fire.
* @trig_dis_ms: the time, in milliseconds, after an occurrence of this
* trigger in which another occurrence should be ignored.
*/ */
struct iwl_fw_dbg_trigger_tlv { struct iwl_fw_dbg_trigger_tlv {
__le32 id; __le32 id;
...@@ -559,7 +568,8 @@ struct iwl_fw_dbg_trigger_tlv { ...@@ -559,7 +568,8 @@ struct iwl_fw_dbg_trigger_tlv {
u8 mode; u8 mode;
u8 start_conf_id; u8 start_conf_id;
__le16 occurrences; __le16 occurrences;
__le32 reserved[2]; __le16 trig_dis_ms;
__le16 reserved[3];
u8 data[0]; u8 data[0];
} __packed; } __packed;
......
...@@ -345,6 +345,12 @@ enum secure_load_status_reg { ...@@ -345,6 +345,12 @@ enum secure_load_status_reg {
#define TXF_READ_MODIFY_DATA (0xa00448) #define TXF_READ_MODIFY_DATA (0xa00448)
#define TXF_READ_MODIFY_ADDR (0xa0044c) #define TXF_READ_MODIFY_ADDR (0xa0044c)
/* Radio registers access */
#define RSP_RADIO_CMD (0xa02804)
#define RSP_RADIO_RDDAT (0xa02814)
#define RADIO_RSP_ADDR_POS (6)
#define RADIO_RSP_RD_CMD (3)
/* FW monitor */ /* FW monitor */
#define MON_BUFF_SAMPLE_CTL (0xa03c00) #define MON_BUFF_SAMPLE_CTL (0xa03c00)
#define MON_BUFF_BASE_ADDR (0xa03c3c) #define MON_BUFF_BASE_ADDR (0xa03c3c)
......
...@@ -663,7 +663,7 @@ struct iwl_trans_ops { ...@@ -663,7 +663,7 @@ struct iwl_trans_ops {
void (*resume)(struct iwl_trans *trans); void (*resume)(struct iwl_trans *trans);
struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans, struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans,
struct iwl_fw_dbg_trigger_tlv const struct iwl_fw_dbg_trigger_tlv
*trigger); *trigger);
}; };
...@@ -966,7 +966,7 @@ static inline void iwl_trans_resume(struct iwl_trans *trans) ...@@ -966,7 +966,7 @@ static inline void iwl_trans_resume(struct iwl_trans *trans)
static inline struct iwl_trans_dump_data * static inline struct iwl_trans_dump_data *
iwl_trans_dump_data(struct iwl_trans *trans, iwl_trans_dump_data(struct iwl_trans *trans,
struct iwl_fw_dbg_trigger_tlv *trigger) const struct iwl_fw_dbg_trigger_tlv *trigger)
{ {
if (!trans->ops->dump_data) if (!trans->ops->dump_data)
return NULL; return NULL;
......
...@@ -137,6 +137,28 @@ static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out) ...@@ -137,6 +137,28 @@ static void iwl_mvm_convert_p1k(u16 *p1k, __le16 *out)
out[i] = cpu_to_le16(p1k[i]); out[i] = cpu_to_le16(p1k[i]);
} }
static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key,
struct iwl_mvm_key_pn *ptk_pn,
struct ieee80211_key_seq *seq,
int tid, int queues)
{
const u8 *ret = seq->ccmp.pn;
int i;
/* get the PN from mac80211, used on the default queue */
ieee80211_get_key_rx_seq(key, tid, seq);
/* and use the internal data for the other queues */
for (i = 1; i < queues; i++) {
const u8 *tmp = ptk_pn->q[i].pn[tid];
if (memcmp(ret, tmp, IEEE80211_CCMP_PN_LEN) <= 0)
ret = tmp;
}
return ret;
}
struct wowlan_key_data { struct wowlan_key_data {
struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
struct iwl_wowlan_tkip_params_cmd *tkip; struct iwl_wowlan_tkip_params_cmd *tkip;
...@@ -294,8 +316,31 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, ...@@ -294,8 +316,31 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
/* /*
* For non-QoS this relies on the fact that both the uCode and * For non-QoS this relies on the fact that both the uCode and
* mac80211 use TID 0 for checking the IV in the frames. * mac80211/our RX code use TID 0 for checking the PN.
*/ */
if (sta && iwl_mvm_has_new_rx_api(mvm)) {
struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_key_pn *ptk_pn;
const u8 *pn;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
ptk_pn = rcu_dereference_protected(
mvmsta->ptk_pn[key->keyidx],
lockdep_is_held(&mvm->mutex));
if (WARN_ON(!ptk_pn))
break;
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
pn = iwl_mvm_find_max_pn(key, ptk_pn, &seq, i,
mvm->trans->num_rx_queues);
aes_sc[i].pn = cpu_to_le64((u64)pn[5] |
((u64)pn[4] << 8) |
((u64)pn[3] << 16) |
((u64)pn[2] << 24) |
((u64)pn[1] << 32) |
((u64)pn[0] << 40));
}
} else {
for (i = 0; i < IWL_NUM_RSC; i++) { for (i = 0; i < IWL_NUM_RSC; i++) {
u8 *pn = seq.ccmp.pn; u8 *pn = seq.ccmp.pn;
...@@ -307,6 +352,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, ...@@ -307,6 +352,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
((u64)pn[1] << 32) | ((u64)pn[1] << 32) |
((u64)pn[0] << 40)); ((u64)pn[0] << 40));
} }
}
data->use_rsc_tsc = true; data->use_rsc_tsc = true;
break; break;
} }
...@@ -1426,19 +1472,43 @@ static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc, ...@@ -1426,19 +1472,43 @@ static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc,
seq->tkip.iv16 = le16_to_cpu(sc->iv16); seq->tkip.iv16 = le16_to_cpu(sc->iv16);
} }
static void iwl_mvm_set_aes_rx_seq(struct aes_sc *scs, static void iwl_mvm_set_aes_rx_seq(struct iwl_mvm *mvm, struct aes_sc *scs,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key) struct ieee80211_key_conf *key)
{ {
int tid; int tid;
BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS); BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
if (sta && iwl_mvm_has_new_rx_api(mvm)) {
struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_key_pn *ptk_pn;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
ptk_pn = rcu_dereference_protected(mvmsta->ptk_pn[key->keyidx],
lockdep_is_held(&mvm->mutex));
if (WARN_ON(!ptk_pn))
return;
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
struct ieee80211_key_seq seq = {};
int i;
iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
ieee80211_set_key_rx_seq(key, tid, &seq);
for (i = 1; i < mvm->trans->num_rx_queues; i++)
memcpy(ptk_pn->q[i].pn[tid],
seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
}
} else {
for (tid = 0; tid < IWL_NUM_RSC; tid++) { for (tid = 0; tid < IWL_NUM_RSC; tid++) {
struct ieee80211_key_seq seq = {}; struct ieee80211_key_seq seq = {};
iwl_mvm_aes_sc_to_seq(&scs[tid], &seq); iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
ieee80211_set_key_rx_seq(key, tid, &seq); ieee80211_set_key_rx_seq(key, tid, &seq);
} }
}
} }
static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs, static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs,
...@@ -1456,14 +1526,15 @@ static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs, ...@@ -1456,14 +1526,15 @@ static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs,
} }
} }
static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm,
struct ieee80211_key_conf *key,
struct iwl_wowlan_status *status) struct iwl_wowlan_status *status)
{ {
union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc; union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc;
switch (key->cipher) { switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
iwl_mvm_set_aes_rx_seq(rsc->aes.multicast_rsc, key); iwl_mvm_set_aes_rx_seq(mvm, rsc->aes.multicast_rsc, NULL, key);
break; break;
case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_TKIP:
iwl_mvm_set_tkip_rx_seq(rsc->tkip.multicast_rsc, key); iwl_mvm_set_tkip_rx_seq(rsc->tkip.multicast_rsc, key);
...@@ -1474,6 +1545,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, ...@@ -1474,6 +1545,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
} }
struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm_d3_gtk_iter_data {
struct iwl_mvm *mvm;
struct iwl_wowlan_status *status; struct iwl_wowlan_status *status;
void *last_gtk; void *last_gtk;
u32 cipher; u32 cipher;
...@@ -1522,7 +1594,8 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, ...@@ -1522,7 +1594,8 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
switch (key->cipher) { switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
iwl_mvm_set_aes_rx_seq(sc->aes.unicast_rsc, key); iwl_mvm_set_aes_rx_seq(data->mvm, sc->aes.unicast_rsc,
sta, key);
atomic64_set(&key->tx_pn, le64_to_cpu(sc->aes.tsc.pn)); atomic64_set(&key->tx_pn, le64_to_cpu(sc->aes.tsc.pn));
break; break;
case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_TKIP:
...@@ -1545,7 +1618,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, ...@@ -1545,7 +1618,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
if (data->status->num_of_gtk_rekeys) if (data->status->num_of_gtk_rekeys)
ieee80211_remove_key(key); ieee80211_remove_key(key);
else if (data->last_gtk == key) else if (data->last_gtk == key)
iwl_mvm_set_key_rx_seq(key, data->status); iwl_mvm_set_key_rx_seq(data->mvm, key, data->status);
} }
static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
...@@ -1554,6 +1627,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, ...@@ -1554,6 +1627,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_d3_gtk_iter_data gtkdata = { struct iwl_mvm_d3_gtk_iter_data gtkdata = {
.mvm = mvm,
.status = status, .status = status,
}; };
u32 disconnection_reasons = u32 disconnection_reasons =
...@@ -1615,7 +1689,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, ...@@ -1615,7 +1689,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
key = ieee80211_gtk_rekey_add(vif, &conf.conf); key = ieee80211_gtk_rekey_add(vif, &conf.conf);
if (IS_ERR(key)) if (IS_ERR(key))
return false; return false;
iwl_mvm_set_key_rx_seq(key, status); iwl_mvm_set_key_rx_seq(mvm, key, status);
} }
if (status->num_of_gtk_rekeys) { if (status->num_of_gtk_rekeys) {
...@@ -1769,6 +1843,7 @@ void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm, ...@@ -1769,6 +1843,7 @@ void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm,
struct iwl_wowlan_status *status) struct iwl_wowlan_status *status)
{ {
struct iwl_mvm_d3_gtk_iter_data gtkdata = { struct iwl_mvm_d3_gtk_iter_data gtkdata = {
.mvm = mvm,
.status = status, .status = status,
}; };
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -1451,6 +1453,22 @@ struct iwl_sf_cfg_cmd { ...@@ -1451,6 +1453,22 @@ struct iwl_sf_cfg_cmd {
* Location Aware Regulatory (LAR) API - MCC updates * Location Aware Regulatory (LAR) API - MCC updates
***********************************/ ***********************************/
/**
* struct iwl_mcc_update_cmd_v1 - Request the device to update geographic
* regulatory profile according to the given MCC (Mobile Country Code).
* The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain.
* 'ZZ' MCC will be used to switch to NVM default profile; in this case, the
* MCC in the cmd response will be the relevant MCC in the NVM.
* @mcc: given mobile country code
* @source_id: the source from where we got the MCC, see iwl_mcc_source
* @reserved: reserved for alignment
*/
struct iwl_mcc_update_cmd_v1 {
__le16 mcc;
u8 source_id;
u8 reserved;
} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */
/** /**
* struct iwl_mcc_update_cmd - Request the device to update geographic * struct iwl_mcc_update_cmd - Request the device to update geographic
* regulatory profile according to the given MCC (Mobile Country Code). * regulatory profile according to the given MCC (Mobile Country Code).
...@@ -1460,12 +1478,39 @@ struct iwl_sf_cfg_cmd { ...@@ -1460,12 +1478,39 @@ struct iwl_sf_cfg_cmd {
* @mcc: given mobile country code * @mcc: given mobile country code
* @source_id: the source from where we got the MCC, see iwl_mcc_source * @source_id: the source from where we got the MCC, see iwl_mcc_source
* @reserved: reserved for alignment * @reserved: reserved for alignment
* @key: integrity key for MCC API OEM testing
* @reserved2: reserved
*/ */
struct iwl_mcc_update_cmd { struct iwl_mcc_update_cmd {
__le16 mcc; __le16 mcc;
u8 source_id; u8 source_id;
u8 reserved; u8 reserved;
} __packed; /* LAR_UPDATE_MCC_CMD_API_S */ __le32 key;
__le32 reserved2[5];
} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */
/**
* iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD.
* Contains the new channel control profile map, if changed, and the new MCC
* (mobile country code).
* The new MCC may be different than what was requested in MCC_UPDATE_CMD.
* @status: see &enum iwl_mcc_update_status
* @mcc: the new applied MCC
* @cap: capabilities for all channels which matches the MCC
* @source_id: the MCC source, see iwl_mcc_source
* @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
* channels, depending on platform)
* @channels: channel control data map, DWORD for each channel. Only the first
* 16bits are used.
*/
struct iwl_mcc_update_resp_v1 {
__le32 status;
__le16 mcc;
u8 cap;
u8 source_id;
__le32 n_channels;
__le32 channels[0];
} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */
/** /**
* iwl_mcc_update_resp - response to MCC_UPDATE_CMD. * iwl_mcc_update_resp - response to MCC_UPDATE_CMD.
...@@ -1476,6 +1521,8 @@ struct iwl_mcc_update_cmd { ...@@ -1476,6 +1521,8 @@ struct iwl_mcc_update_cmd {
* @mcc: the new applied MCC * @mcc: the new applied MCC
* @cap: capabilities for all channels which matches the MCC * @cap: capabilities for all channels which matches the MCC
* @source_id: the MCC source, see iwl_mcc_source * @source_id: the MCC source, see iwl_mcc_source
* @time: time elapsed from the MCC test start (in 30 seconds TU)
* @reserved: reserved.
* @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51
* channels, depending on platform) * channels, depending on platform)
* @channels: channel control data map, DWORD for each channel. Only the first * @channels: channel control data map, DWORD for each channel. Only the first
...@@ -1486,9 +1533,11 @@ struct iwl_mcc_update_resp { ...@@ -1486,9 +1533,11 @@ struct iwl_mcc_update_resp {
__le16 mcc; __le16 mcc;
u8 cap; u8 cap;
u8 source_id; u8 source_id;
__le16 time;
__le16 reserved;
__le32 n_channels; __le32 n_channels;
__le32 channels[0]; __le32 channels[0];
} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */ } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */
/** /**
* struct iwl_mcc_chub_notif - chub notifies of mcc change * struct iwl_mcc_chub_notif - chub notifies of mcc change
...@@ -1518,6 +1567,9 @@ enum iwl_mcc_update_status { ...@@ -1518,6 +1567,9 @@ enum iwl_mcc_update_status {
MCC_RESP_NVM_DISABLED, MCC_RESP_NVM_DISABLED,
MCC_RESP_ILLEGAL, MCC_RESP_ILLEGAL,
MCC_RESP_LOW_PRIORITY, MCC_RESP_LOW_PRIORITY,
MCC_RESP_TEST_MODE_ACTIVE,
MCC_RESP_TEST_MODE_NOT_ACTIVE,
MCC_RESP_TEST_MODE_DENIAL_OF_SERVICE,
}; };
enum iwl_mcc_source { enum iwl_mcc_source {
...@@ -1530,7 +1582,9 @@ enum iwl_mcc_source { ...@@ -1530,7 +1582,9 @@ enum iwl_mcc_source {
MCC_SOURCE_RESERVED = 6, MCC_SOURCE_RESERVED = 6,
MCC_SOURCE_DEFAULT = 7, MCC_SOURCE_DEFAULT = 7,
MCC_SOURCE_UNINITIALIZED = 8, MCC_SOURCE_UNINITIALIZED = 8,
MCC_SOURCE_GET_CURRENT = 0x10 MCC_SOURCE_MCC_API = 9,
MCC_SOURCE_GET_CURRENT = 0x10,
MCC_SOURCE_GETTING_MCC_TEST_MODE = 0x11,
}; };
/* DTS measurements */ /* DTS measurements */
......
...@@ -113,6 +113,35 @@ static void iwl_mvm_free_coredump(const void *data) ...@@ -113,6 +113,35 @@ static void iwl_mvm_free_coredump(const void *data)
kfree(fw_error_dump); kfree(fw_error_dump);
} }
#define RADIO_REG_MAX_READ 0x2ad
static void iwl_mvm_read_radio_reg(struct iwl_mvm *mvm,
struct iwl_fw_error_dump_data **dump_data)
{
u8 *pos = (void *)(*dump_data)->data;
unsigned long flags;
int i;
if (!iwl_trans_grab_nic_access(mvm->trans, &flags))
return;
(*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RADIO_REG);
(*dump_data)->len = cpu_to_le32(RADIO_REG_MAX_READ);
for (i = 0; i < RADIO_REG_MAX_READ; i++) {
u32 rd_cmd = RADIO_RSP_RD_CMD;
rd_cmd |= i << RADIO_RSP_ADDR_POS;
iwl_write_prph_no_grab(mvm->trans, RSP_RADIO_CMD, rd_cmd);
*pos = (u8)iwl_read_prph_no_grab(mvm->trans, RSP_RADIO_RDDAT);
pos++;
}
*dump_data = iwl_fw_error_next_data(*dump_data);
iwl_trans_release_nic_access(mvm->trans, &flags);
}
static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
struct iwl_fw_error_dump_data **dump_data) struct iwl_fw_error_dump_data **dump_data)
{ {
...@@ -241,8 +270,7 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, ...@@ -241,8 +270,7 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm) void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm)
{ {
if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert || if (mvm->fw_dump_desc == &iwl_mvm_dump_desc_assert)
!mvm->fw_dump_desc)
return; return;
kfree(mvm->fw_dump_desc); kfree(mvm->fw_dump_desc);
...@@ -401,7 +429,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -401,7 +429,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
struct iwl_fw_error_dump_trigger_desc *dump_trig; struct iwl_fw_error_dump_trigger_desc *dump_trig;
struct iwl_mvm_dump_ptrs *fw_error_dump; struct iwl_mvm_dump_ptrs *fw_error_dump;
u32 sram_len, sram_ofs; u32 sram_len, sram_ofs;
u32 file_len, fifo_data_len = 0, prph_len = 0; u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0;
u32 smem_len = mvm->cfg->smem_len; u32 smem_len = mvm->cfg->smem_len;
u32 sram2_len = mvm->cfg->dccm2_len; u32 sram2_len = mvm->cfg->dccm2_len;
bool monitor_dump_only = false; bool monitor_dump_only = false;
...@@ -412,7 +440,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -412,7 +440,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
/* there's no point in fw dump if the bus is dead */ /* there's no point in fw dump if the bus is dead */
if (test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) { if (test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) {
IWL_ERR(mvm, "Skip fw error dump since bus is dead\n"); IWL_ERR(mvm, "Skip fw error dump since bus is dead\n");
return; goto out;
} }
if (mvm->fw_dump_trig && if (mvm->fw_dump_trig &&
...@@ -421,7 +449,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -421,7 +449,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
if (!fw_error_dump) if (!fw_error_dump)
return; goto out;
/* SRAM - include stack CCM if driver knows the values for it */ /* SRAM - include stack CCM if driver knows the values for it */
if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) { if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) {
...@@ -472,6 +500,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -472,6 +500,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sizeof(struct iwl_fw_error_dump_prph) + sizeof(struct iwl_fw_error_dump_prph) +
num_bytes_in_chunk; num_bytes_in_chunk;
} }
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
} }
file_len = sizeof(*dump_file) + file_len = sizeof(*dump_file) +
...@@ -479,6 +510,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -479,6 +510,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sram_len + sizeof(*dump_mem) + sram_len + sizeof(*dump_mem) +
fifo_data_len + fifo_data_len +
prph_len + prph_len +
radio_len +
sizeof(*dump_info); sizeof(*dump_info);
/* Make room for the SMEM, if it exists */ /* Make room for the SMEM, if it exists */
...@@ -517,8 +549,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -517,8 +549,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_file = vzalloc(file_len); dump_file = vzalloc(file_len);
if (!dump_file) { if (!dump_file) {
kfree(fw_error_dump); kfree(fw_error_dump);
iwl_mvm_free_fw_dump_desc(mvm); goto out;
return;
} }
fw_error_dump->op_mode_ptr = dump_file; fw_error_dump->op_mode_ptr = dump_file;
...@@ -543,8 +574,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -543,8 +574,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_data = iwl_fw_error_next_data(dump_data); dump_data = iwl_fw_error_next_data(dump_data);
/* We only dump the FIFOs if the FW is in error state */ /* We only dump the FIFOs if the FW is in error state */
if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) {
iwl_mvm_dump_fifos(mvm, &dump_data); iwl_mvm_dump_fifos(mvm, &dump_data);
if (radio_len)
iwl_mvm_read_radio_reg(mvm, &dump_data);
}
if (mvm->fw_dump_desc) { if (mvm->fw_dump_desc) {
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
...@@ -554,8 +588,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -554,8 +588,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
memcpy(dump_trig, &mvm->fw_dump_desc->trig_desc, memcpy(dump_trig, &mvm->fw_dump_desc->trig_desc,
sizeof(*dump_trig) + mvm->fw_dump_desc->len); sizeof(*dump_trig) + mvm->fw_dump_desc->len);
/* now we can free this copy */
iwl_mvm_free_fw_dump_desc(mvm);
dump_data = iwl_fw_error_next_data(dump_data); dump_data = iwl_fw_error_next_data(dump_data);
} }
...@@ -641,19 +673,21 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) ...@@ -641,19 +673,21 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0, dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
out:
iwl_mvm_free_fw_dump_desc(mvm);
mvm->fw_dump_trig = NULL; mvm->fw_dump_trig = NULL;
clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status); clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status);
} }
struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert = { const struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert = {
.trig_desc = { .trig_desc = {
.type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT), .type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT),
}, },
}; };
int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
struct iwl_mvm_dump_desc *desc, const struct iwl_mvm_dump_desc *desc,
struct iwl_fw_dbg_trigger_tlv *trigger) const struct iwl_fw_dbg_trigger_tlv *trigger)
{ {
unsigned int delay = 0; unsigned int delay = 0;
...@@ -679,7 +713,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, ...@@ -679,7 +713,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
const char *str, size_t len, const char *str, size_t len,
struct iwl_fw_dbg_trigger_tlv *trigger) const struct iwl_fw_dbg_trigger_tlv *trigger)
{ {
struct iwl_mvm_dump_desc *desc; struct iwl_mvm_dump_desc *desc;
......
...@@ -72,11 +72,11 @@ ...@@ -72,11 +72,11 @@
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm); void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm);
int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
struct iwl_mvm_dump_desc *desc, const struct iwl_mvm_dump_desc *desc,
struct iwl_fw_dbg_trigger_tlv *trigger); const struct iwl_fw_dbg_trigger_tlv *trigger);
int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
const char *str, size_t len, const char *str, size_t len,
struct iwl_fw_dbg_trigger_tlv *trigger); const struct iwl_fw_dbg_trigger_tlv *trigger);
int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_tlv *trigger, struct iwl_fw_dbg_trigger_tlv *trigger,
const char *fmt, ...) __printf(3, 4); const char *fmt, ...) __printf(3, 4);
...@@ -117,6 +117,24 @@ iwl_fw_dbg_trigger_stop_conf_match(struct iwl_mvm *mvm, ...@@ -117,6 +117,24 @@ iwl_fw_dbg_trigger_stop_conf_match(struct iwl_mvm *mvm,
(BIT(mvm->fw_dbg_conf) & le32_to_cpu(trig->stop_conf_ids)))); (BIT(mvm->fw_dbg_conf) & le32_to_cpu(trig->stop_conf_ids))));
} }
static inline bool
iwl_fw_dbg_no_trig_window(struct iwl_mvm *mvm,
struct iwl_fw_dbg_trigger_tlv *trig)
{
unsigned long wind_jiff =
msecs_to_jiffies(le16_to_cpu(trig->trig_dis_ms));
u32 id = le32_to_cpu(trig->id);
/* If this is the first event checked, jump to update start ts */
if (mvm->fw_dbg_non_collect_ts_start[id] &&
(time_after(mvm->fw_dbg_non_collect_ts_start[id] + wind_jiff,
jiffies)))
return true;
mvm->fw_dbg_non_collect_ts_start[id] = jiffies;
return false;
}
static inline bool static inline bool
iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm, iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
...@@ -125,6 +143,12 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm, ...@@ -125,6 +143,12 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm,
if (vif && !iwl_fw_dbg_trigger_vif_match(trig, vif)) if (vif && !iwl_fw_dbg_trigger_vif_match(trig, vif))
return false; return false;
if (iwl_fw_dbg_no_trig_window(mvm, trig)) {
IWL_WARN(mvm, "Trigger %d occurred while no-collect window.\n",
trig->id);
return false;
}
return iwl_fw_dbg_trigger_stop_conf_match(mvm, trig); return iwl_fw_dbg_trigger_stop_conf_match(mvm, trig);
} }
......
...@@ -943,6 +943,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ...@@ -943,6 +943,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
} }
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
mvm->scan_type = IWL_SCAN_TYPE_NOT_SET;
ret = iwl_mvm_config_scan(mvm); ret = iwl_mvm_config_scan(mvm);
if (ret) if (ret)
goto error; goto error;
......
...@@ -717,6 +717,8 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, ...@@ -717,6 +717,8 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cpu_to_le32(vif->bss_conf.use_short_slot ? cpu_to_le32(vif->bss_conf.use_short_slot ?
MAC_FLG_SHORT_SLOT : 0); MAC_FLG_SHORT_SLOT : 0);
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
for (i = 0; i < IEEE80211_NUM_ACS; i++) { for (i = 0; i < IEEE80211_NUM_ACS; i++) {
u8 txf = iwl_mvm_ac_to_tx_fifo[i]; u8 txf = iwl_mvm_ac_to_tx_fifo[i];
...@@ -730,11 +732,26 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, ...@@ -730,11 +732,26 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->ac[txf].fifos_mask = BIT(txf); cmd->ac[txf].fifos_mask = BIT(txf);
} }
if (vif->type == NL80211_IFTYPE_AP) {
/* in AP mode, the MCAST FIFO takes the EDCA params from VO */ /* in AP mode, the MCAST FIFO takes the EDCA params from VO */
if (vif->type == NL80211_IFTYPE_AP)
cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |= cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |=
BIT(IWL_MVM_TX_FIFO_MCAST); BIT(IWL_MVM_TX_FIFO_MCAST);
/*
* in AP mode, pass probe requests and beacons from other APs
* (needed for ht protection); when there're no any associated
* station don't ask FW to pass beacons to prevent unnecessary
* wake-ups.
*/
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
if (mvmvif->ap_assoc_sta_count) {
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
} else {
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
}
}
if (vif->bss_conf.qos) if (vif->bss_conf.qos)
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
...@@ -748,8 +765,6 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, ...@@ -748,8 +765,6 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN); cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_TGN);
if (ht_enabled) if (ht_enabled)
iwl_mvm_mac_ctxt_set_ht_flags(mvm, vif, cmd); iwl_mvm_mac_ctxt_set_ht_flags(mvm, vif, cmd);
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP);
} }
static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm, static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
...@@ -1012,9 +1027,12 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, ...@@ -1012,9 +1027,12 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
TX_CMD_FLG_BT_PRIO_POS; TX_CMD_FLG_BT_PRIO_POS;
beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags); beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);
if (!fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) {
mvm->mgmt_last_antenna_idx = mvm->mgmt_last_antenna_idx =
iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm),
mvm->mgmt_last_antenna_idx); mvm->mgmt_last_antenna_idx);
}
beacon_cmd.tx.rate_n_flags = beacon_cmd.tx.rate_n_flags =
cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
...@@ -1153,7 +1171,6 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, ...@@ -1153,7 +1171,6 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
u32 action) u32 action)
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mac_ctx_cmd cmd = {}; struct iwl_mac_ctx_cmd cmd = {};
WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p); WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p);
...@@ -1161,19 +1178,6 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, ...@@ -1161,19 +1178,6 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */ /* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/*
* pass probe requests and beacons from other APs (needed
* for ht protection); when there're no any associated station
* don't ask FW to pass beacons to prevent unnecessary wake-ups.
*/
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
if (mvmvif->ap_assoc_sta_count) {
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
} else {
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
}
/* Fill the data specific for ap mode */ /* Fill the data specific for ap mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap, iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap,
action == FW_CTXT_ACTION_ADD); action == FW_CTXT_ACTION_ADD);
...@@ -1193,13 +1197,6 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm, ...@@ -1193,13 +1197,6 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */ /* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/*
* pass probe requests and beacons from other APs (needed
* for ht protection)
*/
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST |
MAC_FILTER_IN_BEACON);
/* Fill the data specific for GO mode */ /* Fill the data specific for GO mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap, iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap,
action == FW_CTXT_ACTION_ADD); action == FW_CTXT_ACTION_ADD);
......
...@@ -438,6 +438,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -438,6 +438,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
ieee80211_hw_set(hw, CHANCTX_STA_CSA); ieee80211_hw_set(hw, CHANCTX_STA_CSA);
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
if (mvm->trans->max_skb_frags) if (mvm->trans->max_skb_frags)
hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG; hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;
...@@ -1002,7 +1004,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ...@@ -1002,7 +1004,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
mvm->vif_count = 0; mvm->vif_count = 0;
mvm->rx_ba_sessions = 0; mvm->rx_ba_sessions = 0;
mvm->fw_dbg_conf = FW_DBG_INVALID; mvm->fw_dbg_conf = FW_DBG_INVALID;
mvm->scan_type = IWL_SCAN_TYPE_NOT_SET;
/* keep statistics ticking */ /* keep statistics ticking */
iwl_mvm_accu_radio_stats(mvm); iwl_mvm_accu_radio_stats(mvm);
...@@ -2567,6 +2568,9 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2567,6 +2568,9 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
struct ieee80211_key_conf *key) struct ieee80211_key_conf *key)
{ {
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_key_pn *ptk_pn;
int keyidx = key->keyidx;
int ret; int ret;
u8 key_offset; u8 key_offset;
...@@ -2634,6 +2638,36 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2634,6 +2638,36 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break; break;
} }
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
sta && iwl_mvm_has_new_rx_api(mvm) &&
key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
(key->cipher == WLAN_CIPHER_SUITE_CCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP)) {
struct ieee80211_key_seq seq;
int tid, q;
mvmsta = iwl_mvm_sta_from_mac80211(sta);
WARN_ON(rcu_access_pointer(mvmsta->ptk_pn[keyidx]));
ptk_pn = kzalloc(sizeof(*ptk_pn) +
mvm->trans->num_rx_queues *
sizeof(ptk_pn->q[0]),
GFP_KERNEL);
if (!ptk_pn) {
ret = -ENOMEM;
break;
}
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
ieee80211_get_key_rx_seq(key, tid, &seq);
for (q = 0; q < mvm->trans->num_rx_queues; q++)
memcpy(ptk_pn->q[q].pn[tid],
seq.ccmp.pn,
IEEE80211_CCMP_PN_LEN);
}
rcu_assign_pointer(mvmsta->ptk_pn[keyidx], ptk_pn);
}
/* in HW restart reuse the index, otherwise request a new one */ /* in HW restart reuse the index, otherwise request a new one */
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
key_offset = key->hw_key_idx; key_offset = key->hw_key_idx;
...@@ -2659,6 +2693,19 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ...@@ -2659,6 +2693,19 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break; break;
} }
if (sta && iwl_mvm_has_new_rx_api(mvm) &&
key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
(key->cipher == WLAN_CIPHER_SUITE_CCMP ||
key->cipher == WLAN_CIPHER_SUITE_GCMP)) {
mvmsta = iwl_mvm_sta_from_mac80211(sta);
ptk_pn = rcu_dereference_protected(
mvmsta->ptk_pn[keyidx],
lockdep_is_held(&mvm->mutex));
RCU_INIT_POINTER(mvmsta->ptk_pn[keyidx], NULL);
if (ptk_pn)
kfree_rcu(ptk_pn, rcu_head);
}
IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n"); IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n");
ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key); ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);
break; break;
......
...@@ -157,7 +157,7 @@ struct iwl_mvm_dump_desc { ...@@ -157,7 +157,7 @@ struct iwl_mvm_dump_desc {
struct iwl_fw_error_dump_trigger_desc trig_desc; struct iwl_fw_error_dump_trigger_desc trig_desc;
}; };
extern struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert; extern const struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert;
struct iwl_mvm_phy_ctxt { struct iwl_mvm_phy_ctxt {
u16 id; u16 id;
...@@ -658,6 +658,9 @@ struct iwl_mvm { ...@@ -658,6 +658,9 @@ struct iwl_mvm {
/* max number of simultaneous scans the FW supports */ /* max number of simultaneous scans the FW supports */
unsigned int max_scans; unsigned int max_scans;
/* ts of the beginning of a non-collect fw dbg data period */
unsigned long fw_dbg_non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1];
/* UMAC scan tracking */ /* UMAC scan tracking */
u32 scan_uid_status[IWL_MVM_MAX_UMAC_SCANS]; u32 scan_uid_status[IWL_MVM_MAX_UMAC_SCANS];
...@@ -729,8 +732,8 @@ struct iwl_mvm { ...@@ -729,8 +732,8 @@ struct iwl_mvm {
s8 restart_fw; s8 restart_fw;
u8 fw_dbg_conf; u8 fw_dbg_conf;
struct delayed_work fw_dump_wk; struct delayed_work fw_dump_wk;
struct iwl_mvm_dump_desc *fw_dump_desc; const struct iwl_mvm_dump_desc *fw_dump_desc;
struct iwl_fw_dbg_trigger_tlv *fw_dump_trig; const struct iwl_fw_dbg_trigger_tlv *fw_dump_trig;
#ifdef CONFIG_IWLWIFI_LEDS #ifdef CONFIG_IWLWIFI_LEDS
struct led_classdev led; struct led_classdev led;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -640,7 +642,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) ...@@ -640,7 +642,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
else else
mvm->nvm_file_name = nvm_file_C; mvm->nvm_file_name = nvm_file_C;
if (ret == -EFAULT && mvm->nvm_file_name) { if ((ret == -EFAULT || ret == -ENOENT) &&
mvm->nvm_file_name) {
/* in case nvm file was failed try again */ /* in case nvm file was failed try again */
ret = iwl_mvm_read_external_nvm(mvm); ret = iwl_mvm_read_external_nvm(mvm);
if (ret) if (ret)
...@@ -670,6 +673,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, ...@@ -670,6 +673,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
.source_id = (u8)src_id, .source_id = (u8)src_id,
}; };
struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL; struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL;
struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = NULL;
struct iwl_rx_packet *pkt; struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
.id = MCC_UPDATE_CMD, .id = MCC_UPDATE_CMD,
...@@ -681,11 +685,15 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, ...@@ -681,11 +685,15 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
u32 status; u32 status;
int resp_len, n_channels; int resp_len, n_channels;
u16 mcc; u16 mcc;
bool resp_v2 = fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2);
if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
cmd.len[0] = sizeof(struct iwl_mcc_update_cmd); cmd.len[0] = sizeof(struct iwl_mcc_update_cmd);
if (!resp_v2)
cmd.len[0] = sizeof(struct iwl_mcc_update_cmd_v1);
IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n", IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n",
alpha2[0], alpha2[1], src_id); alpha2[0], alpha2[1], src_id);
...@@ -697,31 +705,50 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, ...@@ -697,31 +705,50 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
pkt = cmd.resp_pkt; pkt = cmd.resp_pkt;
/* Extract MCC response */ /* Extract MCC response */
if (resp_v2) {
mcc_resp = (void *)pkt->data; mcc_resp = (void *)pkt->data;
status = le32_to_cpu(mcc_resp->status); n_channels = __le32_to_cpu(mcc_resp->n_channels);
} else {
mcc_resp_v1 = (void *)pkt->data;
n_channels = __le32_to_cpu(mcc_resp_v1->n_channels);
}
resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels *
sizeof(__le32);
resp_cp = kzalloc(resp_len, GFP_KERNEL);
if (!resp_cp) {
ret = -ENOMEM;
goto exit;
}
if (resp_v2) {
memcpy(resp_cp, mcc_resp, resp_len);
} else {
resp_cp->status = mcc_resp_v1->status;
resp_cp->mcc = mcc_resp_v1->mcc;
resp_cp->cap = mcc_resp_v1->cap;
resp_cp->source_id = mcc_resp_v1->source_id;
resp_cp->n_channels = mcc_resp_v1->n_channels;
memcpy(resp_cp->channels, mcc_resp_v1->channels,
n_channels * sizeof(__le32));
}
status = le32_to_cpu(resp_cp->status);
mcc = le16_to_cpu(mcc_resp->mcc); mcc = le16_to_cpu(resp_cp->mcc);
/* W/A for a FW/NVM issue - returns 0x00 for the world domain */ /* W/A for a FW/NVM issue - returns 0x00 for the world domain */
if (mcc == 0) { if (mcc == 0) {
mcc = 0x3030; /* "00" - world */ mcc = 0x3030; /* "00" - world */
mcc_resp->mcc = cpu_to_le16(mcc); resp_cp->mcc = cpu_to_le16(mcc);
} }
n_channels = __le32_to_cpu(mcc_resp->n_channels);
IWL_DEBUG_LAR(mvm, IWL_DEBUG_LAR(mvm,
"MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n", "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n",
status, mcc, mcc >> 8, mcc & 0xff, status, mcc, mcc >> 8, mcc & 0xff,
!!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels); !!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels);
resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32);
resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
if (!resp_cp) {
ret = -ENOMEM;
goto exit;
}
ret = 0;
exit: exit:
iwl_free_resp(&cmd); iwl_free_resp(&cmd);
if (ret) if (ret)
......
...@@ -613,8 +613,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac, ...@@ -613,8 +613,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
break; break;
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
/* only a single MAC of the same type */
WARN_ON(power_iterator->bss_vif);
power_iterator->bss_vif = vif; power_iterator->bss_vif = vif;
if (mvmvif->phy_ctxt) if (mvmvif->phy_ctxt)
if (mvmvif->phy_ctxt->id < MAX_PHYS) if (mvmvif->phy_ctxt->id < MAX_PHYS)
......
...@@ -78,11 +78,82 @@ void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) ...@@ -78,11 +78,82 @@ void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
#endif #endif
} }
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
struct napi_struct *napi, int queue, struct ieee80211_sta *sta)
struct sk_buff *skb, {
struct ieee80211_hdr *hdr, u16 len, struct iwl_mvm_sta *mvmsta;
u32 ampdu_status, u8 crypt_len, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);
struct iwl_mvm_key_pn *ptk_pn;
u8 tid, keyidx;
u8 pn[IEEE80211_CCMP_PN_LEN];
u8 *extiv;
/* do PN checking */
/* multicast and non-data only arrives on default queue */
if (!ieee80211_is_data(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1))
return 0;
/* do not check PN for open AP */
if (!(stats->flag & RX_FLAG_DECRYPTED))
return 0;
/*
* avoid checking for default queue - we don't want to replicate
* all the logic that's necessary for checking the PN on fragmented
* frames, leave that to mac80211
*/
if (queue == 0)
return 0;
/* if we are here - this for sure is either CCMP or GCMP */
if (IS_ERR_OR_NULL(sta)) {
IWL_ERR(mvm,
"expected hw-decrypted unicast frame for station\n");
return -1;
}
mvmsta = iwl_mvm_sta_from_mac80211(sta);
extiv = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
keyidx = extiv[3] >> 6;
ptk_pn = rcu_dereference(mvmsta->ptk_pn[keyidx]);
if (!ptk_pn)
return -1;
if (ieee80211_is_data_qos(hdr->frame_control))
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
else
tid = 0;
/* we don't use HCCA/802.11 QoS TSPECs, so drop such frames */
if (tid >= IWL_MAX_TID_COUNT)
return -1;
/* load pn */
pn[0] = extiv[7];
pn[1] = extiv[6];
pn[2] = extiv[5];
pn[3] = extiv[4];
pn[4] = extiv[1];
pn[5] = extiv[0];
if (memcmp(pn, ptk_pn->q[queue].pn[tid],
IEEE80211_CCMP_PN_LEN) <= 0)
return -1;
memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN);
stats->flag |= RX_FLAG_PN_VALIDATED;
return 0;
}
/* iwl_mvm_create_skb Adds the rxb to a new skb */
static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr,
u16 len, u8 crypt_len,
struct iwl_rx_cmd_buffer *rxb) struct iwl_rx_cmd_buffer *rxb)
{ {
unsigned int hdrlen, fraglen; unsigned int hdrlen, fraglen;
...@@ -112,7 +183,17 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, ...@@ -112,7 +183,17 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
fraglen, rxb->truesize); fraglen, rxb->truesize);
} }
}
/* iwl_mvm_pass_packet_to_mac80211 - passes the packet for mac80211 */
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
struct napi_struct *napi,
struct sk_buff *skb, int queue,
struct ieee80211_sta *sta)
{
if (iwl_mvm_check_pn(mvm, skb, queue, sta))
kfree_skb(skb);
else
ieee80211_rx_napi(mvm->hw, skb, napi); ieee80211_rx_napi(mvm->hw, skb, napi);
} }
...@@ -141,7 +222,7 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, ...@@ -141,7 +222,7 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
rx_status->chain_signal[2] = energy_c; rx_status->chain_signal[2] = energy_c;
} }
static u32 iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
struct ieee80211_rx_status *stats, struct ieee80211_rx_status *stats,
struct iwl_rx_mpdu_desc *desc, int queue, struct iwl_rx_mpdu_desc *desc, int queue,
u8 *crypt_len) u8 *crypt_len)
...@@ -158,6 +239,7 @@ static u32 iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, ...@@ -158,6 +239,7 @@ static u32 iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
switch (status & IWL_RX_MPDU_STATUS_SEC_MASK) { switch (status & IWL_RX_MPDU_STATUS_SEC_MASK) {
case IWL_RX_MPDU_STATUS_SEC_CCM: case IWL_RX_MPDU_STATUS_SEC_CCM:
case IWL_RX_MPDU_STATUS_SEC_GCM: case IWL_RX_MPDU_STATUS_SEC_GCM:
BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != IEEE80211_GCMP_PN_LEN);
/* alg is CCM: check MIC only */ /* alg is CCM: check MIC only */
if (!(status & IWL_RX_MPDU_STATUS_MIC_OK)) if (!(status & IWL_RX_MPDU_STATUS_MIC_OK))
return -1; return -1;
...@@ -217,7 +299,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -217,7 +299,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags); u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags);
struct ieee80211_sta *sta = NULL; struct ieee80211_sta *sta = NULL;
struct sk_buff *skb; struct sk_buff *skb;
u32 ampdu_status;
u8 crypt_len = 0; u8 crypt_len = 0;
/* Dont use dev_alloc_skb(), we'll have enough headroom once /* Dont use dev_alloc_skb(), we'll have enough headroom once
...@@ -311,8 +392,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -311,8 +392,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
iwl_mvm_rx_csum(sta, skb, desc); iwl_mvm_rx_csum(sta, skb, desc);
} }
rcu_read_unlock();
/* /*
* TODO: PHY info. * TODO: PHY info.
* Verify we don't have the information in the MPDU descriptor and * Verify we don't have the information in the MPDU descriptor and
...@@ -367,8 +446,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -367,8 +446,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
/* TODO: PHY info - update ampdu queue statistics (for debugfs) */ /* TODO: PHY info - update ampdu queue statistics (for debugfs) */
/* TODO: PHY info - gscan */ /* TODO: PHY info - gscan */
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status, iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb);
crypt_len, rxb); iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta);
rcu_read_unlock();
} }
void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm,
......
...@@ -92,7 +92,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { ...@@ -92,7 +92,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
.dwell_active = 10, .dwell_active = 10,
.dwell_passive = 110, .dwell_passive = 110,
.dwell_fragmented = 44, .dwell_fragmented = 44,
.dwell_extended = 100, .dwell_extended = 90,
.suspend_time = 0, .suspend_time = 0,
.max_out_time = 0, .max_out_time = 0,
}, },
...@@ -100,7 +100,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { ...@@ -100,7 +100,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
.dwell_active = 10, .dwell_active = 10,
.dwell_passive = 110, .dwell_passive = 110,
.dwell_fragmented = 44, .dwell_fragmented = 44,
.dwell_extended = 100, .dwell_extended = 90,
.suspend_time = 30, .suspend_time = 30,
.max_out_time = 120, .max_out_time = 120,
}, },
...@@ -108,7 +108,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { ...@@ -108,7 +108,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
.dwell_active = 10, .dwell_active = 10,
.dwell_passive = 110, .dwell_passive = 110,
.dwell_fragmented = 44, .dwell_fragmented = 44,
.dwell_extended = 100, .dwell_extended = 90,
.suspend_time = 120, .suspend_time = 120,
.max_out_time = 120, .max_out_time = 120,
}, },
...@@ -116,7 +116,6 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = { ...@@ -116,7 +116,6 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
.dwell_active = 10, .dwell_active = 10,
.dwell_passive = 110, .dwell_passive = 110,
.dwell_fragmented = 44, .dwell_fragmented = 44,
.dwell_extended = 44,
.suspend_time = 95, .suspend_time = 95,
.max_out_time = 44, .max_out_time = 44,
}, },
...@@ -790,7 +789,8 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm, ...@@ -790,7 +789,8 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
#endif #endif
if (iwl_mvm_is_regular_scan(params) && if (iwl_mvm_is_regular_scan(params) &&
vif->type != NL80211_IFTYPE_P2P_DEVICE) vif->type != NL80211_IFTYPE_P2P_DEVICE &&
params->type != IWL_SCAN_TYPE_FRAGMENTED)
flags |= IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL; flags |= IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL;
return flags; return flags;
...@@ -1072,7 +1072,8 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, ...@@ -1072,7 +1072,8 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
#endif #endif
if (iwl_mvm_is_regular_scan(params) && if (iwl_mvm_is_regular_scan(params) &&
vif->type != NL80211_IFTYPE_P2P_DEVICE) vif->type != NL80211_IFTYPE_P2P_DEVICE &&
params->type != IWL_SCAN_TYPE_FRAGMENTED)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL; flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL;
return flags; return flags;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -284,6 +286,13 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) ...@@ -284,6 +286,13 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
tid_data->next_reclaimed); tid_data->next_reclaimed);
} }
struct iwl_mvm_key_pn {
struct rcu_head rcu_head;
struct {
u8 pn[IWL_MAX_TID_COUNT][IEEE80211_CCMP_PN_LEN];
} ____cacheline_aligned_in_smp q[];
};
/** /**
* struct iwl_mvm_sta - representation of a station in the driver * struct iwl_mvm_sta - representation of a station in the driver
* @sta_id: the index of the station in the fw (will be replaced by id_n_color) * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
...@@ -308,6 +317,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data) ...@@ -308,6 +317,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
* gets empty before all the frames were sent, which can happen when * gets empty before all the frames were sent, which can happen when
* we are sending frames from an AMPDU queue and there was a hole in * we are sending frames from an AMPDU queue and there was a hole in
* the BA window. To be used for UAPSD only. * the BA window. To be used for UAPSD only.
* @ptk_pn: per-queue PTK PN data structures
* *
* When mac80211 creates a station it reserves some space (hw->sta_data_size) * When mac80211 creates a station it reserves some space (hw->sta_data_size)
* in the structure for use by driver. This structure is placed in that * in the structure for use by driver. This structure is placed in that
...@@ -328,6 +338,8 @@ struct iwl_mvm_sta { ...@@ -328,6 +338,8 @@ struct iwl_mvm_sta {
struct iwl_lq_sta lq_sta; struct iwl_lq_sta lq_sta;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
struct iwl_mvm_key_pn __rcu *ptk_pn[4];
/* Temporary, until the new TLC will control the Tx protection */ /* Temporary, until the new TLC will control the Tx protection */
s8 tx_protection; s8 tx_protection;
bool tt_tx_protection; bool tt_tx_protection;
......
...@@ -120,7 +120,7 @@ static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm, ...@@ -120,7 +120,7 @@ static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm,
int len = iwl_rx_packet_payload_len(pkt); int len = iwl_rx_packet_payload_len(pkt);
int temp; int temp;
if (WARN_ON_ONCE(len != sizeof(*notif))) { if (WARN_ON_ONCE(len < sizeof(*notif))) {
IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -388,6 +388,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { ...@@ -388,6 +388,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5C10, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5412, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5412, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)},
...@@ -405,10 +406,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = { ...@@ -405,10 +406,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x095A, 0x900A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x900A, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x9210, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095B, 0x9200, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x9200, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x9310, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9410, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9410, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x5020, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5020, iwl7265_2n_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x502A, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x502A, iwl7265_2n_cfg)},
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
* *
* Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -924,9 +926,16 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans) ...@@ -924,9 +926,16 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans)
if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) {
iwl_write_prph(trans, le32_to_cpu(dest->base_reg), iwl_write_prph(trans, le32_to_cpu(dest->base_reg),
trans_pcie->fw_mon_phys >> dest->base_shift); trans_pcie->fw_mon_phys >> dest->base_shift);
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
(trans_pcie->fw_mon_phys +
trans_pcie->fw_mon_size - 256) >>
dest->end_shift);
else
iwl_write_prph(trans, le32_to_cpu(dest->end_reg), iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
(trans_pcie->fw_mon_phys + (trans_pcie->fw_mon_phys +
trans_pcie->fw_mon_size) >> dest->end_shift); trans_pcie->fw_mon_size) >>
dest->end_shift);
} }
} }
...@@ -2364,7 +2373,7 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, ...@@ -2364,7 +2373,7 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
static struct iwl_trans_dump_data static struct iwl_trans_dump_data
*iwl_trans_pcie_dump_data(struct iwl_trans *trans, *iwl_trans_pcie_dump_data(struct iwl_trans *trans,
struct iwl_fw_dbg_trigger_tlv *trigger) const struct iwl_fw_dbg_trigger_tlv *trigger)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_fw_error_dump_data *data; struct iwl_fw_error_dump_data *data;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment