|
@@ -2352,6 +2352,58 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static bool ieee80211_coalesce_started_roc(struct ieee80211_local *local,
|
|
|
|
|
+ struct ieee80211_roc_work *new_roc,
|
|
|
|
|
+ struct ieee80211_roc_work *cur_roc)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long j = jiffies;
|
|
|
|
|
+ unsigned long cur_roc_end = cur_roc->hw_start_time +
|
|
|
|
|
+ msecs_to_jiffies(cur_roc->duration);
|
|
|
|
|
+ struct ieee80211_roc_work *next_roc;
|
|
|
|
|
+ int new_dur;
|
|
|
|
|
+
|
|
|
|
|
+ if (WARN_ON(!cur_roc->started || !cur_roc->hw_begun))
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ if (time_after(j + IEEE80211_ROC_MIN_LEFT, cur_roc_end))
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ ieee80211_handle_roc_started(new_roc);
|
|
|
|
|
+
|
|
|
|
|
+ new_dur = new_roc->duration - jiffies_to_msecs(cur_roc_end - j);
|
|
|
|
|
+
|
|
|
|
|
+ /* cur_roc is long enough - add new_roc to the dependents list. */
|
|
|
|
|
+ if (new_dur <= 0) {
|
|
|
|
|
+ list_add_tail(&new_roc->list, &cur_roc->dependents);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ new_roc->duration = new_dur;
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * if cur_roc was already coalesced before, we might
|
|
|
|
|
+ * want to extend the next roc instead of adding
|
|
|
|
|
+ * a new one.
|
|
|
|
|
+ */
|
|
|
|
|
+ next_roc = list_entry(cur_roc->list.next,
|
|
|
|
|
+ struct ieee80211_roc_work, list);
|
|
|
|
|
+ if (&next_roc->list != &local->roc_list &&
|
|
|
|
|
+ next_roc->chan == new_roc->chan &&
|
|
|
|
|
+ next_roc->sdata == new_roc->sdata &&
|
|
|
|
|
+ !WARN_ON(next_roc->started)) {
|
|
|
|
|
+ list_add_tail(&new_roc->list, &next_roc->dependents);
|
|
|
|
|
+ next_roc->duration = max(next_roc->duration,
|
|
|
|
|
+ new_roc->duration);
|
|
|
|
|
+ next_roc->type = max(next_roc->type, new_roc->type);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* add right after cur_roc */
|
|
|
|
|
+ list_add(&new_roc->list, &cur_roc->list);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
|
static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
|
|
struct ieee80211_sub_if_data *sdata,
|
|
struct ieee80211_sub_if_data *sdata,
|
|
|
struct ieee80211_channel *channel,
|
|
struct ieee80211_channel *channel,
|
|
@@ -2457,8 +2509,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
|
|
|
|
|
|
|
/* If it has already started, it's more difficult ... */
|
|
/* If it has already started, it's more difficult ... */
|
|
|
if (local->ops->remain_on_channel) {
|
|
if (local->ops->remain_on_channel) {
|
|
|
- unsigned long j = jiffies;
|
|
|
|
|
-
|
|
|
|
|
/*
|
|
/*
|
|
|
* In the offloaded ROC case, if it hasn't begun, add
|
|
* In the offloaded ROC case, if it hasn't begun, add
|
|
|
* this new one to the dependent list to be handled
|
|
* this new one to the dependent list to be handled
|
|
@@ -2481,29 +2531,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (time_before(j + IEEE80211_ROC_MIN_LEFT,
|
|
|
|
|
- tmp->hw_start_time +
|
|
|
|
|
- msecs_to_jiffies(tmp->duration))) {
|
|
|
|
|
- int new_dur;
|
|
|
|
|
-
|
|
|
|
|
- ieee80211_handle_roc_started(roc);
|
|
|
|
|
-
|
|
|
|
|
- new_dur = roc->duration -
|
|
|
|
|
- jiffies_to_msecs(tmp->hw_start_time +
|
|
|
|
|
- msecs_to_jiffies(
|
|
|
|
|
- tmp->duration) -
|
|
|
|
|
- j);
|
|
|
|
|
-
|
|
|
|
|
- if (new_dur > 0) {
|
|
|
|
|
- /* add right after tmp */
|
|
|
|
|
- roc->duration = new_dur;
|
|
|
|
|
- list_add(&roc->list, &tmp->list);
|
|
|
|
|
- } else {
|
|
|
|
|
- list_add_tail(&roc->list,
|
|
|
|
|
- &tmp->dependents);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (ieee80211_coalesce_started_roc(local, roc, tmp))
|
|
|
queued = true;
|
|
queued = true;
|
|
|
- }
|
|
|
|
|
} else if (del_timer_sync(&tmp->work.timer)) {
|
|
} else if (del_timer_sync(&tmp->work.timer)) {
|
|
|
unsigned long new_end;
|
|
unsigned long new_end;
|
|
|
|
|
|