aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAviya Erenfeld <aviya.erenfeld@intel.com>2016-02-18 07:09:33 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2016-03-30 09:21:07 -0400
commit03098268a30d75188f15dd8fda8f0c896d2846e5 (patch)
tree3b702f12076d1b5ce32d96966697d5992769b565 /drivers
parent5b086414293f906d8c5692cbbfa3500458982e5d (diff)
iwlwifi: mvm: add LQM vendor command and notification
LQM stands for Link Quality Measurement. The firmware will collect a defined set of statitics (see the notification for details) that allow to know how busy the medium is. The driver issues a request to the firmware that includes the duration of the measurement (the firmware needs to be on channel for that amount of time) and the timeout (in case the firmware has a lot of offchannel activities). If the timeout elapses, the firmware will send partial results which are still valuable. In case of disassociation / channel switch and alike, the driver is in charge of stopping the measurements and the firmware will reply with partial results. The user space API for now is debugfs only and will be implmemented in an upcoming patch. Signed-off-by: Aviya Erenfeld <aviya.erenfeld@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h62
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c71
6 files changed, 166 insertions, 0 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
index 3a72b9715930..c82b94167ac6 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
@@ -326,6 +326,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
326 * regular image. 326 * regular image.
327 * @IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared 327 * @IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared
328 * memory addresses from the firmware. 328 * memory addresses from the firmware.
329 * @IWL_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement
329 * 330 *
330 * @NUM_IWL_UCODE_TLV_CAPA: number of bits used 331 * @NUM_IWL_UCODE_TLV_CAPA: number of bits used
331 */ 332 */
@@ -364,6 +365,7 @@ enum iwl_ucode_tlv_capa {
364 IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76, 365 IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76,
365 IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED = (__force iwl_ucode_tlv_capa_t)77, 366 IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED = (__force iwl_ucode_tlv_capa_t)77,
366 IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80, 367 IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80,
368 IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81,
367 369
368 NUM_IWL_UCODE_TLV_CAPA 370 NUM_IWL_UCODE_TLV_CAPA
369#ifdef __CHECKER__ 371#ifdef __CHECKER__
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
index 61711b10ff82..e6bd0c8d4cc0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
@@ -279,6 +279,11 @@ enum {
279/* Please keep this enum *SORTED* by hex value. 279/* Please keep this enum *SORTED* by hex value.
280 * Needed for binary search, otherwise a warning will be triggered. 280 * Needed for binary search, otherwise a warning will be triggered.
281 */ 281 */
282enum iwl_mac_conf_subcmd_ids {
283 LINK_QUALITY_MEASUREMENT_CMD = 0x1,
284 LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF = 0xFE,
285};
286
282enum iwl_phy_ops_subcmd_ids { 287enum iwl_phy_ops_subcmd_ids {
283 CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, 288 CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0,
284 CTDP_CONFIG_CMD = 0x03, 289 CTDP_CONFIG_CMD = 0x03,
@@ -307,6 +312,7 @@ enum {
307 LEGACY_GROUP = 0x0, 312 LEGACY_GROUP = 0x0,
308 LONG_GROUP = 0x1, 313 LONG_GROUP = 0x1,
309 SYSTEM_GROUP = 0x2, 314 SYSTEM_GROUP = 0x2,
315 MAC_CONF_GROUP = 0x3,
310 PHY_OPS_GROUP = 0x4, 316 PHY_OPS_GROUP = 0x4,
311 DATA_PATH_GROUP = 0x5, 317 DATA_PATH_GROUP = 0x5,
312 PROT_OFFLOAD_GROUP = 0xb, 318 PROT_OFFLOAD_GROUP = 0xb,
@@ -2017,4 +2023,60 @@ struct iwl_stored_beacon_notif {
2017 u8 data[MAX_STORED_BEACON_SIZE]; 2023 u8 data[MAX_STORED_BEACON_SIZE];
2018} __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_1 */ 2024} __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_1 */
2019 2025
2026#define LQM_NUMBER_OF_STATIONS_IN_REPORT 16
2027
2028enum iwl_lqm_cmd_operatrions {
2029 LQM_CMD_OPERATION_START_MEASUREMENT = 0x01,
2030 LQM_CMD_OPERATION_STOP_MEASUREMENT = 0x02,
2031};
2032
2033enum iwl_lqm_status {
2034 LQM_STATUS_SUCCESS = 0,
2035 LQM_STATUS_TIMEOUT = 1,
2036 LQM_STATUS_ABORT = 2,
2037};
2038
2039/**
2040 * Link Quality Measurement command
2041 * @cmd_operatrion: command operation to be performed (start or stop)
2042 * as defined above.
2043 * @mac_id: MAC ID the measurement applies to.
2044 * @measurement_time: time of the total measurement to be performed, in uSec.
2045 * @timeout: maximum time allowed until a response is sent, in uSec.
2046 */
2047struct iwl_link_qual_msrmnt_cmd {
2048 __le32 cmd_operation;
2049 __le32 mac_id;
2050 __le32 measurement_time;
2051 __le32 timeout;
2052} __packed /* LQM_CMD_API_S_VER_1 */;
2053
2054/**
2055 * Link Quality Measurement notification
2056 *
2057 * @frequent_stations_air_time: an array containing the total air time
2058 * (in uSec) used by the most frequently transmitting stations.
2059 * @number_of_stations: the number of uniqe stations included in the array
2060 * (a number between 0 to 16)
2061 * @total_air_time_other_stations: the total air time (uSec) used by all the
2062 * stations which are not included in the above report.
2063 * @time_in_measurement_window: the total time in uSec in which a measurement
2064 * took place.
2065 * @tx_frame_dropped: the number of TX frames dropped due to retry limit during
2066 * measurement
2067 * @mac_id: MAC ID the measurement applies to.
2068 * @status: return status. may be one of the LQM_STATUS_* defined above.
2069 * @reserved: reserved.
2070 */
2071struct iwl_link_qual_msrmnt_notif {
2072 __le32 frequent_stations_air_time[LQM_NUMBER_OF_STATIONS_IN_REPORT];
2073 __le32 number_of_stations;
2074 __le32 total_air_time_other_stations;
2075 __le32 time_in_measurement_window;
2076 __le32 tx_frame_dropped;
2077 __le32 mac_id;
2078 __le32 status;
2079 __le32 reserved[3];
2080} __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */
2081
2020#endif /* __fw_api_h__ */ 2082#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 76e649c680a1..cff9c16e4920 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -1821,6 +1821,11 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
1821 if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) 1821 if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
1822 iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); 1822 iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
1823 1823
1824 if (changes & BSS_CHANGED_ASSOC && !bss_conf->assoc &&
1825 mvmvif->lqm_active)
1826 iwl_mvm_send_lqm_cmd(vif, LQM_CMD_OPERATION_STOP_MEASUREMENT,
1827 0, 0);
1828
1824 /* 1829 /*
1825 * If we're not associated yet, take the (new) BSSID before associating 1830 * If we're not associated yet, take the (new) BSSID before associating
1826 * so the firmware knows. If we're already associated, then use the old 1831 * so the firmware knows. If we're already associated, then use the old
@@ -3628,6 +3633,11 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
3628 3633
3629 break; 3634 break;
3630 case NL80211_IFTYPE_STATION: 3635 case NL80211_IFTYPE_STATION:
3636 if (mvmvif->lqm_active)
3637 iwl_mvm_send_lqm_cmd(vif,
3638 LQM_CMD_OPERATION_STOP_MEASUREMENT,
3639 0, 0);
3640
3631 /* Schedule the time event to a bit before beacon 1, 3641 /* Schedule the time event to a bit before beacon 1,
3632 * to make sure we're in the new channel when the 3642 * to make sure we're in the new channel when the
3633 * GO/AP arrives. 3643 * GO/AP arrives.
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 6c67c0f631c5..0668601f377c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -453,6 +453,12 @@ struct iwl_mvm_vif {
453 453
454 /* TCP Checksum Offload */ 454 /* TCP Checksum Offload */
455 netdev_features_t features; 455 netdev_features_t features;
456
457 /*
458 * link quality measurement - used to check whether this interface
459 * is in the middle of a link quality measurement
460 */
461 bool lqm_active;
456}; 462};
457 463
458static inline struct iwl_mvm_vif * 464static inline struct iwl_mvm_vif *
@@ -1637,4 +1643,10 @@ unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm,
1637void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 1643void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1638 const char *errmsg); 1644 const char *errmsg);
1639 1645
1646/* Link Quality Measurement */
1647int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif,
1648 enum iwl_lqm_cmd_operatrions operation,
1649 u32 duration, u32 timeout);
1650bool iwl_mvm_lqm_active(struct iwl_mvm *mvm);
1651
1640#endif /* __IWL_MVM_H__ */ 1652#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index ccf6ecd21b18..46a22fd9f0d6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -428,6 +428,14 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = {
428/* Please keep this array *SORTED* by hex value. 428/* Please keep this array *SORTED* by hex value.
429 * Access is done through binary search 429 * Access is done through binary search
430 */ 430 */
431static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
432 HCMD_NAME(LINK_QUALITY_MEASUREMENT_CMD),
433 HCMD_NAME(LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF),
434};
435
436/* Please keep this array *SORTED* by hex value.
437 * Access is done through binary search
438 */
431static const struct iwl_hcmd_names iwl_mvm_phy_names[] = { 439static const struct iwl_hcmd_names iwl_mvm_phy_names[] = {
432 HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE), 440 HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE),
433 HCMD_NAME(CTDP_CONFIG_CMD), 441 HCMD_NAME(CTDP_CONFIG_CMD),
@@ -457,6 +465,7 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = {
457 [LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), 465 [LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),
458 [LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), 466 [LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),
459 [SYSTEM_GROUP] = HCMD_ARR(iwl_mvm_system_names), 467 [SYSTEM_GROUP] = HCMD_ARR(iwl_mvm_system_names),
468 [MAC_CONF_GROUP] = HCMD_ARR(iwl_mvm_mac_conf_names),
460 [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names), 469 [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names),
461 [DATA_PATH_GROUP] = HCMD_ARR(iwl_mvm_data_path_names), 470 [DATA_PATH_GROUP] = HCMD_ARR(iwl_mvm_data_path_names),
462 [PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names), 471 [PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names),
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 53cdc5760f68..2440248c8e69 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -1079,3 +1079,74 @@ void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1079out: 1079out:
1080 ieee80211_connection_loss(vif); 1080 ieee80211_connection_loss(vif);
1081} 1081}
1082
1083int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif,
1084 enum iwl_lqm_cmd_operatrions operation,
1085 u32 duration, u32 timeout)
1086{
1087 struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
1088 struct iwl_link_qual_msrmnt_cmd cmd = {
1089 .cmd_operation = cpu_to_le32(operation),
1090 .mac_id = cpu_to_le32(mvm_vif->id),
1091 .measurement_time = cpu_to_le32(duration),
1092 .timeout = cpu_to_le32(timeout),
1093 };
1094 u32 cmdid =
1095 iwl_cmd_id(LINK_QUALITY_MEASUREMENT_CMD, MAC_CONF_GROUP, 0);
1096 int ret;
1097
1098 if (!fw_has_capa(&mvm_vif->mvm->fw->ucode_capa,
1099 IWL_UCODE_TLV_CAPA_LQM_SUPPORT))
1100 return -EOPNOTSUPP;
1101
1102 if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
1103 return -EINVAL;
1104
1105 switch (operation) {
1106 case LQM_CMD_OPERATION_START_MEASUREMENT:
1107 if (iwl_mvm_lqm_active(mvm_vif->mvm))
1108 return -EBUSY;
1109 if (!vif->bss_conf.assoc)
1110 return -EINVAL;
1111 mvm_vif->lqm_active = true;
1112 break;
1113 case LQM_CMD_OPERATION_STOP_MEASUREMENT:
1114 if (!iwl_mvm_lqm_active(mvm_vif->mvm))
1115 return -EINVAL;
1116 break;
1117 default:
1118 return -EINVAL;
1119 }
1120
1121 ret = iwl_mvm_send_cmd_pdu(mvm_vif->mvm, cmdid, 0, sizeof(cmd),
1122 &cmd);
1123
1124 /* command failed - roll back lqm_active state */
1125 if (ret) {
1126 mvm_vif->lqm_active =
1127 operation == LQM_CMD_OPERATION_STOP_MEASUREMENT;
1128 }
1129
1130 return ret;
1131}
1132
1133static void iwl_mvm_lqm_active_iterator(void *_data, u8 *mac,
1134 struct ieee80211_vif *vif)
1135{
1136 struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
1137 bool *lqm_active = _data;
1138
1139 *lqm_active = *lqm_active || mvm_vif->lqm_active;
1140}
1141
1142bool iwl_mvm_lqm_active(struct iwl_mvm *mvm)
1143{
1144 bool ret = false;
1145
1146 lockdep_assert_held(&mvm->mutex);
1147 ieee80211_iterate_active_interfaces_atomic(
1148 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1149 iwl_mvm_lqm_active_iterator, &ret);
1150
1151 return ret;
1152}