aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/time-event.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/time-event.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c81
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
231static 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) {