return ERR_PTR(rc);
 }
 
-int wil_vif_prepare_stop(struct wil6210_priv *wil, struct wil6210_vif *vif)
+int wil_vif_prepare_stop(struct wil6210_vif *vif)
 {
+       struct wil6210_priv *wil = vif_to_wil(vif);
        struct wireless_dev *wdev = vif_to_wdev(vif);
        struct net_device *ndev;
        int rc;
                                 rc);
                        /* continue */
                }
+               wil_bcast_fini(vif);
                netif_carrier_off(ndev);
        }
 
                return -EINVAL;
        }
 
-       rc = wil_vif_prepare_stop(wil, vif);
+       rc = wil_vif_prepare_stop(vif);
        if (rc)
                goto out;
 
        struct wil6210_vif *vif = ndev_to_vif(ndev);
        struct wireless_dev *wdev = vif_to_wdev(vif);
        int rc;
+       bool fw_reset = false;
 
        wil_dbg_misc(wil, "change_iface: type=%d\n", type);
 
        /* do not reset FW when there are active VIFs,
         * because it can cause significant disruption
         */
-       if (!wil_has_other_up_ifaces(wil, ndev) &&
+       if (!wil_has_other_active_ifaces(wil, ndev, true, false) &&
            netif_running(ndev) && !wil_is_recovery_blocked(wil)) {
                wil_dbg_misc(wil, "interface is up. resetting...\n");
                mutex_lock(&wil->mutex);
 
                if (rc)
                        return rc;
+               fw_reset = true;
        }
 
        switch (type) {
                return -EOPNOTSUPP;
        }
 
-       if (vif->mid != 0 && wil_has_up_ifaces(wil)) {
-               wil_vif_prepare_stop(wil, vif);
+       if (vif->mid != 0 && wil_has_active_ifaces(wil, true, false)) {
+               if (!fw_reset)
+                       wil_vif_prepare_stop(vif);
                rc = wmi_port_delete(wil, vif->mid);
                if (rc)
                        return rc;
 
        mutex_lock(&wil->mutex);
 
-       __wil_down(wil);
-       rc = __wil_up(wil);
-       if (rc)
-               goto out;
+       if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
+               __wil_down(wil);
+               rc = __wil_up(wil);
+               if (rc)
+                       goto out;
+       }
 
        rc = wmi_set_ssid(vif, ssid_len, ssid);
        if (rc)
        vif->pbss = pbss;
 
        netif_carrier_on(ndev);
-       wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
+       if (!wil_has_other_active_ifaces(wil, ndev, false, true))
+               wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
 
        rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, hidden_ssid, is_go);
        if (rc)
        wmi_pcp_stop(vif);
 err_pcp_start:
        netif_carrier_off(ndev);
-       wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
+       if (!wil_has_other_active_ifaces(wil, ndev, false, true))
+               wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
 out:
        mutex_unlock(&wil->mutex);
        return rc;
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
        struct wil6210_vif *vif = ndev_to_vif(ndev);
+       bool last;
 
-       wil_dbg_misc(wil, "stop_ap\n");
+       wil_dbg_misc(wil, "stop_ap, mid=%d\n", vif->mid);
 
        netif_carrier_off(ndev);
-       wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
-       wil_set_recovery_state(wil, fw_recovery_idle);
-
-       set_bit(wil_status_resetting, wil->status);
+       last = !wil_has_other_active_ifaces(wil, ndev, false, true);
+       if (last) {
+               wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
+               wil_set_recovery_state(wil, fw_recovery_idle);
+               set_bit(wil_status_resetting, wil->status);
+       }
 
        mutex_lock(&wil->mutex);
 
        wmi_pcp_stop(vif);
 
-       __wil_down(wil);
+       if (last)
+               __wil_down(wil);
+       else
+               wil_bcast_fini(vif);
 
        mutex_unlock(&wil->mutex);
 
 
        wil_vring_fini_tx(wil, ri);
 }
 
+void wil_bcast_fini_all(struct wil6210_priv *wil)
+{
+       int i;
+       struct wil6210_vif *vif;
+
+       for (i = 0; i < wil->max_vifs; i++) {
+               vif = wil->vifs[i];
+               if (vif)
+                       wil_bcast_fini(vif);
+       }
+}
+
 int wil_priv_init(struct wil6210_priv *wil)
 {
        uint i;
 
        cancel_work_sync(&vif->disconnect_worker);
        wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
-       wil_bcast_fini(vif);
+       wil_bcast_fini_all(wil);
 
        /* Disable device led before reset*/
        wmi_led_cfg(wil, false);
 
 #include "wil6210.h"
 #include "txrx.h"
 
-bool wil_has_other_up_ifaces(struct wil6210_priv *wil,
-                            struct net_device *ndev)
+bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
+                                struct net_device *ndev, bool up, bool ok)
 {
        int i;
        struct wil6210_vif *vif;
                vif = wil->vifs[i];
                if (vif) {
                        ndev_i = vif_to_ndev(vif);
-                       if (ndev_i != ndev && ndev_i->flags & IFF_UP)
-                               return true;
+                       if (ndev_i != ndev)
+                               if ((up && (ndev_i->flags & IFF_UP)) ||
+                                   (ok && netif_carrier_ok(ndev_i)))
+                                       return true;
                }
        }
 
        return false;
 }
 
-bool wil_has_up_ifaces(struct wil6210_priv *wil)
+bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok)
 {
-       return wil_has_other_up_ifaces(wil, NULL);
+       return wil_has_other_active_ifaces(wil, NULL, up, ok);
 }
 
 static int wil_open(struct net_device *ndev)
                return -EINVAL;
        }
 
-       if (!wil_has_other_up_ifaces(wil, ndev)) {
+       if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
                wil_dbg_misc(wil, "open, first iface\n");
                rc = wil_pm_runtime_get(wil);
                if (rc < 0)
 
        wil_dbg_misc(wil, "stop\n");
 
-       if (!wil_has_other_up_ifaces(wil, ndev)) {
+       if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
                wil_dbg_misc(wil, "stop, last iface\n");
                rc = wil_down(wil);
                if (!rc)
 {
        struct net_device *ndev = vif_to_ndev(vif);
        struct wireless_dev *wdev = vif_to_wdev(vif);
-       bool any_active = wil_has_up_ifaces(wil);
+       bool any_active = wil_has_active_ifaces(wil, true, false);
        int rc;
 
        ASSERT_RTNL();
 {
        struct wil6210_vif *vif;
        struct net_device *ndev;
-       bool any_active = wil_has_up_ifaces(wil);
+       bool any_active = wil_has_active_ifaces(wil, true, false);
 
        ASSERT_RTNL();
        if (mid >= wil->max_vifs) {
 
        for (i = 1; i < wil->max_vifs; i++) {
                vif = wil->vifs[i];
                if (vif) {
-                       wil_vif_prepare_stop(wil, vif);
+                       wil_vif_prepare_stop(vif);
                        wil_vif_remove(wil, vif->mid);
                }
        }
 
              unsigned char name_assign_type, enum nl80211_iftype iftype);
 void wil_vif_free(struct wil6210_vif *vif);
 void *wil_if_alloc(struct device *dev);
-bool wil_has_other_up_ifaces(struct wil6210_priv *wil,
-                            struct net_device *ndev);
-bool wil_has_up_ifaces(struct wil6210_priv *wil);
+bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
+                                struct net_device *ndev, bool up, bool ok);
+bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok);
 void wil_if_free(struct wil6210_priv *wil);
 int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif);
 int wil_if_add(struct wil6210_priv *wil);
 int wil_cfg80211_iface_combinations_from_fw(
        struct wil6210_priv *wil,
        const struct wil_fw_record_concurrency *conc);
-int wil_vif_prepare_stop(struct wil6210_priv *wil, struct wil6210_vif *vif);
+int wil_vif_prepare_stop(struct wil6210_vif *vif);
 
 #if defined(CONFIG_WIL6210_DEBUGFS)
 int wil6210_debugfs_init(struct wil6210_priv *wil);
 int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size);
 int wil_bcast_init(struct wil6210_vif *vif);
 void wil_bcast_fini(struct wil6210_vif *vif);
+void wil_bcast_fini_all(struct wil6210_priv *wil);
 
 void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
                           bool should_stop);
 
                return "WMI_GET_PCP_CHANNEL_CMD";
        case WMI_P2P_CFG_CMDID:
                return "WMI_P2P_CFG_CMD";
+       case WMI_PORT_ALLOCATE_CMDID:
+               return "WMI_PORT_ALLOCATE_CMD";
+       case WMI_PORT_DELETE_CMDID:
+               return "WMI_PORT_DELETE_CMD";
        case WMI_START_LISTEN_CMDID:
                return "WMI_START_LISTEN_CMD";
        case WMI_START_SEARCH_CMDID:
                return "WMI_GET_PCP_CHANNEL_EVENT";
        case WMI_P2P_CFG_DONE_EVENTID:
                return "WMI_P2P_CFG_DONE_EVENT";
+       case WMI_PORT_ALLOCATED_EVENTID:
+               return "WMI_PORT_ALLOCATED_EVENT";
+       case WMI_PORT_DELETED_EVENTID:
+               return "WMI_PORT_DELETED_EVENT";
        case WMI_LISTEN_STARTED_EVENTID:
                return "WMI_LISTEN_STARTED_EVENT";
        case WMI_SEARCH_STARTED_EVENTID: