diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/time-event.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/time-event.c | 81 |
1 files changed, 67 insertions, 14 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 8d179ab67cc2..fd7b0d36f9a6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -119,7 +119,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) | |||
119 | 119 | ||
120 | /* | 120 | /* |
121 | * Flush the offchannel queue -- this is called when the time | 121 | * Flush the offchannel queue -- this is called when the time |
122 | * event finishes or is cancelled, so that frames queued for it | 122 | * event finishes or is canceled, so that frames queued for it |
123 | * won't get stuck on the queue and be transmitted in the next | 123 | * won't get stuck on the queue and be transmitted in the next |
124 | * time event. | 124 | * time event. |
125 | * We have to send the command asynchronously since this cannot | 125 | * We have to send the command asynchronously since this cannot |
@@ -187,7 +187,8 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, | |||
187 | return false; | 187 | return false; |
188 | if (errmsg) | 188 | if (errmsg) |
189 | IWL_ERR(mvm, "%s\n", errmsg); | 189 | IWL_ERR(mvm, "%s\n", errmsg); |
190 | ieee80211_connection_loss(vif); | 190 | |
191 | iwl_mvm_connection_loss(mvm, vif, errmsg); | ||
191 | return true; | 192 | return true; |
192 | } | 193 | } |
193 | 194 | ||
@@ -196,19 +197,24 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, | |||
196 | struct iwl_mvm_time_event_data *te_data, | 197 | struct iwl_mvm_time_event_data *te_data, |
197 | struct iwl_time_event_notif *notif) | 198 | struct iwl_time_event_notif *notif) |
198 | { | 199 | { |
199 | if (!le32_to_cpu(notif->status)) { | 200 | struct ieee80211_vif *vif = te_data->vif; |
200 | if (te_data->vif->type == NL80211_IFTYPE_STATION) | 201 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
201 | ieee80211_connection_loss(te_data->vif); | 202 | |
203 | if (!notif->status) | ||
202 | IWL_DEBUG_TE(mvm, "CSA time event failed to start\n"); | 204 | IWL_DEBUG_TE(mvm, "CSA time event failed to start\n"); |
203 | iwl_mvm_te_clear_data(mvm, te_data); | ||
204 | return; | ||
205 | } | ||
206 | 205 | ||
207 | switch (te_data->vif->type) { | 206 | switch (te_data->vif->type) { |
208 | case NL80211_IFTYPE_AP: | 207 | case NL80211_IFTYPE_AP: |
208 | if (!notif->status) | ||
209 | mvmvif->csa_failed = true; | ||
209 | iwl_mvm_csa_noa_start(mvm); | 210 | iwl_mvm_csa_noa_start(mvm); |
210 | break; | 211 | break; |
211 | case NL80211_IFTYPE_STATION: | 212 | case NL80211_IFTYPE_STATION: |
213 | if (!notif->status) { | ||
214 | iwl_mvm_connection_loss(mvm, vif, | ||
215 | "CSA TE failed to start"); | ||
216 | break; | ||
217 | } | ||
212 | iwl_mvm_csa_client_absent(mvm, te_data->vif); | 218 | iwl_mvm_csa_client_absent(mvm, te_data->vif); |
213 | ieee80211_chswitch_done(te_data->vif, true); | 219 | ieee80211_chswitch_done(te_data->vif, true); |
214 | break; | 220 | break; |
@@ -222,6 +228,44 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, | |||
222 | iwl_mvm_te_clear_data(mvm, te_data); | 228 | iwl_mvm_te_clear_data(mvm, te_data); |
223 | } | 229 | } |
224 | 230 | ||
231 | static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm, | ||
232 | struct iwl_time_event_notif *notif, | ||
233 | struct iwl_mvm_time_event_data *te_data) | ||
234 | { | ||
235 | struct iwl_fw_dbg_trigger_tlv *trig; | ||
236 | struct iwl_fw_dbg_trigger_time_event *te_trig; | ||
237 | int i; | ||
238 | |||
239 | if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT)) | ||
240 | return; | ||
241 | |||
242 | trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT); | ||
243 | te_trig = (void *)trig->data; | ||
244 | |||
245 | if (!iwl_fw_dbg_trigger_check_stop(mvm, te_data->vif, trig)) | ||
246 | return; | ||
247 | |||
248 | for (i = 0; i < ARRAY_SIZE(te_trig->time_events); i++) { | ||
249 | u32 trig_te_id = le32_to_cpu(te_trig->time_events[i].id); | ||
250 | u32 trig_action_bitmap = | ||
251 | le32_to_cpu(te_trig->time_events[i].action_bitmap); | ||
252 | u32 trig_status_bitmap = | ||
253 | le32_to_cpu(te_trig->time_events[i].status_bitmap); | ||
254 | |||
255 | if (trig_te_id != te_data->id || | ||
256 | !(trig_action_bitmap & le32_to_cpu(notif->action)) || | ||
257 | !(trig_status_bitmap & BIT(le32_to_cpu(notif->status)))) | ||
258 | continue; | ||
259 | |||
260 | iwl_mvm_fw_dbg_collect_trig(mvm, trig, | ||
261 | "Time event %d Action 0x%x received status: %d", | ||
262 | te_data->id, | ||
263 | le32_to_cpu(notif->action), | ||
264 | le32_to_cpu(notif->status)); | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | |||
225 | /* | 269 | /* |
226 | * Handles a FW notification for an event that is known to the driver. | 270 | * Handles a FW notification for an event that is known to the driver. |
227 | * | 271 | * |
@@ -239,6 +283,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
239 | le32_to_cpu(notif->unique_id), | 283 | le32_to_cpu(notif->unique_id), |
240 | le32_to_cpu(notif->action)); | 284 | le32_to_cpu(notif->action)); |
241 | 285 | ||
286 | iwl_mvm_te_check_trigger(mvm, notif, te_data); | ||
287 | |||
242 | /* | 288 | /* |
243 | * The FW sends the start/end time event notifications even for events | 289 | * The FW sends the start/end time event notifications even for events |
244 | * that it fails to schedule. This is indicated in the status field of | 290 | * that it fails to schedule. This is indicated in the status field of |
@@ -248,11 +294,16 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
248 | * events in the system). | 294 | * events in the system). |
249 | */ | 295 | */ |
250 | if (!le32_to_cpu(notif->status)) { | 296 | if (!le32_to_cpu(notif->status)) { |
251 | bool start = le32_to_cpu(notif->action) & | 297 | const char *msg; |
252 | TE_V2_NOTIF_HOST_EVENT_START; | 298 | |
253 | IWL_WARN(mvm, "Time Event %s notification failure\n", | 299 | if (notif->action & cpu_to_le32(TE_V2_NOTIF_HOST_EVENT_START)) |
254 | start ? "start" : "end"); | 300 | msg = "Time Event start notification failure"; |
255 | if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, NULL)) { | 301 | else |
302 | msg = "Time Event end notification failure"; | ||
303 | |||
304 | IWL_DEBUG_TE(mvm, "%s\n", msg); | ||
305 | |||
306 | if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, msg)) { | ||
256 | iwl_mvm_te_clear_data(mvm, te_data); | 307 | iwl_mvm_te_clear_data(mvm, te_data); |
257 | return; | 308 | return; |
258 | } | 309 | } |
@@ -315,6 +366,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm, | |||
315 | if (!aux_roc_te) /* Not a Aux ROC time event */ | 366 | if (!aux_roc_te) /* Not a Aux ROC time event */ |
316 | return -EINVAL; | 367 | return -EINVAL; |
317 | 368 | ||
369 | iwl_mvm_te_check_trigger(mvm, notif, te_data); | ||
370 | |||
318 | if (!le32_to_cpu(notif->status)) { | 371 | if (!le32_to_cpu(notif->status)) { |
319 | IWL_DEBUG_TE(mvm, | 372 | IWL_DEBUG_TE(mvm, |
320 | "ERROR: Aux ROC Time Event %s notification failure\n", | 373 | "ERROR: Aux ROC Time Event %s notification failure\n", |
@@ -769,7 +822,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm) | |||
769 | * Iterate over the list of aux roc time events and find the time | 822 | * Iterate over the list of aux roc time events and find the time |
770 | * event that is associated with a BSS interface. | 823 | * event that is associated with a BSS interface. |
771 | * This assumes that a BSS interface can have only a single time | 824 | * This assumes that a BSS interface can have only a single time |
772 | * event at any given time and this time event coresponds to a ROC | 825 | * event at any given time and this time event corresponds to a ROC |
773 | * request | 826 | * request |
774 | */ | 827 | */ |
775 | list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) { | 828 | list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) { |