static struct ieee80211_chanctx *
 ieee80211_new_chanctx(struct ieee80211_local *local,
                      const struct ieee80211_chan_req *chanreq,
-                     enum ieee80211_chanctx_mode mode)
+                     enum ieee80211_chanctx_mode mode,
+                     bool assign_on_failure)
 {
        struct ieee80211_chanctx *ctx;
        int err;
                return ERR_PTR(-ENOMEM);
 
        err = ieee80211_add_chanctx(local, ctx);
-       if (err) {
+       if (!assign_on_failure && err) {
                kfree(ctx);
                return ERR_PTR(err);
        }
+       /* We ignored a driver error, see _ieee80211_set_active_links */
+       WARN_ON_ONCE(err && !local->in_reconfig);
 
        list_add_rcu(&ctx->list, &local->chanctx_list);
        return ctx;
 }
 
 static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
-                                        struct ieee80211_chanctx *new_ctx)
+                                        struct ieee80211_chanctx *new_ctx,
+                                        bool assign_on_failure)
 {
        struct ieee80211_sub_if_data *sdata = link->sdata;
        struct ieee80211_local *local = sdata->local;
                ieee80211_recalc_chanctx_min_def(local, new_ctx, link);
 
                ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
-               if (!ret) {
+               if (assign_on_failure || !ret) {
+                       /* Need to continue, see _ieee80211_set_active_links */
+                       WARN_ON_ONCE(ret && !local->in_reconfig);
+                       ret = 0;
+
                        /* succeeded, so commit it to the data structures */
                        conf = &new_ctx->conf;
                        list_add(&link->assigned_chanctx_list,
        new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
        if (!new_ctx) {
                if (ieee80211_can_create_new_chanctx(local)) {
-                       new_ctx = ieee80211_new_chanctx(local, chanreq, mode);
+                       new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
+                                                       false);
                        if (IS_ERR(new_ctx))
                                return PTR_ERR(new_ctx);
                } else {
        list_del(&link->reserved_chanctx_list);
        link->reserved_chanctx = NULL;
 
-       err = ieee80211_assign_link_chanctx(link, new_ctx);
+       err = ieee80211_assign_link_chanctx(link, new_ctx, false);
        if (err) {
                if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
                        ieee80211_free_chanctx(local, new_ctx, false);
                ieee80211_link_unreserve_chanctx(link);
        }
 
-       ieee80211_assign_link_chanctx(link, NULL);
+       ieee80211_assign_link_chanctx(link, NULL, false);
        if (ieee80211_chanctx_refcount(local, ctx) == 0)
                ieee80211_free_chanctx(local, ctx, skip_idle_recalc);
 
                ieee80211_vif_use_reserved_switch(local);
 }
 
-int ieee80211_link_use_channel(struct ieee80211_link_data *link,
-                              const struct ieee80211_chan_req *chanreq,
-                              enum ieee80211_chanctx_mode mode)
+int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
+                               const struct ieee80211_chan_req *chanreq,
+                               enum ieee80211_chanctx_mode mode,
+                               bool assign_on_failure)
 {
        struct ieee80211_sub_if_data *sdata = link->sdata;
        struct ieee80211_local *local = sdata->local;
        if (ctx)
                reserved = true;
        else
-               ctx = ieee80211_new_chanctx(local, chanreq, mode);
+               ctx = ieee80211_new_chanctx(local, chanreq, mode,
+                                           assign_on_failure);
        if (IS_ERR(ctx)) {
                ret = PTR_ERR(ctx);
                goto out;
 
        ieee80211_link_update_chanreq(link, chanreq);
 
-       ret = ieee80211_assign_link_chanctx(link, ctx);
+       ret = ieee80211_assign_link_chanctx(link, ctx, assign_on_failure);
 
        if (reserved) {
                /* remove reservation */
 
                                 const struct ieee80211_chan_req *b);
 
 int __must_check
+_ieee80211_link_use_channel(struct ieee80211_link_data *link,
+                           const struct ieee80211_chan_req *req,
+                           enum ieee80211_chanctx_mode mode,
+                           bool assign_on_failure);
+
+static inline int __must_check
 ieee80211_link_use_channel(struct ieee80211_link_data *link,
                           const struct ieee80211_chan_req *req,
-                          enum ieee80211_chanctx_mode mode);
+                          enum ieee80211_chanctx_mode mode)
+{
+       return _ieee80211_link_use_channel(link, req, mode, false);
+}
+
 int __must_check
 ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
                               const struct ieee80211_chan_req *req,
 
 
                link = sdata_dereference(sdata->link[link_id], sdata);
 
-               ret = ieee80211_link_use_channel(link,
-                                                &link->conf->chanreq,
-                                                IEEE80211_CHANCTX_SHARED);
+               /*
+                * This call really should not fail. Unfortunately, it appears
+                * that this may happen occasionally with some drivers. Should
+                * it happen, we are stuck in a bad place as going backwards is
+                * not really feasible.
+                *
+                * So lets just tell link_use_channel that it must not fail to
+                * assign the channel context (from mac80211's perspective) and
+                * assume the driver is going to trigger a recovery flow if it
+                * had a failure.
+                * That really is not great nor guaranteed to work. But at least
+                * the internal mac80211 state remains consistent and there is
+                * a chance that we can recover.
+                */
+               ret = _ieee80211_link_use_channel(link,
+                                                 &link->conf->chanreq,
+                                                 IEEE80211_CHANCTX_SHARED,
+                                                 true);
                WARN_ON_ONCE(ret);
 
                ieee80211_mgd_set_link_qos_params(link);