diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/utils.c')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 71 |
1 files changed, 71 insertions, 0 deletions
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, | |||
1079 | out: | 1079 | out: |
1080 | ieee80211_connection_loss(vif); | 1080 | ieee80211_connection_loss(vif); |
1081 | } | 1081 | } |
1082 | |||
1083 | int 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 | |||
1133 | static 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 | |||
1142 | bool 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 | } | ||