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,
                                    struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_channel *channel,
 
                /* If it has already started, it's more difficult ... */
                if (local->ops->remain_on_channel) {
-                       unsigned long j = jiffies;
-
                        /*
                         * In the offloaded ROC case, if it hasn't begun, add
                         * this new one to the dependent list to be handled
                                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;
-                       }
                } else if (del_timer_sync(&tmp->work.timer)) {
                        unsigned long new_end;