return 0;
 }
 
-static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int adm8211_config(struct ieee80211_hw *dev, u32 changed)
 {
        struct adm8211_priv *priv = dev->priv;
+       struct ieee80211_conf *conf = &dev->conf;
        int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
 
        if (channel != priv->channel) {
 
                struct ieee80211_if_init_conf *conf);
 static void ath5k_remove_interface(struct ieee80211_hw *hw,
                struct ieee80211_if_init_conf *conf);
-static int ath5k_config(struct ieee80211_hw *hw,
-               struct ieee80211_conf *conf);
+static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
 static int ath5k_config_interface(struct ieee80211_hw *hw,
                struct ieee80211_vif *vif,
                struct ieee80211_if_conf *conf);
  * TODO: Phy disable/diversity etc
  */
 static int
-ath5k_config(struct ieee80211_hw *hw,
-                       struct ieee80211_conf *conf)
+ath5k_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct ath5k_softc *sc = hw->priv;
+       struct ieee80211_conf *conf = &hw->conf;
 
        sc->bintval = conf->beacon_int;
        sc->power_level = conf->power_level;
 
                        __func__, error);
 }
 
-static int ath9k_config(struct ieee80211_hw *hw,
-                       struct ieee80211_conf *conf)
+static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct ath_softc *sc = hw->priv;
        struct ieee80211_channel *curchan = hw->conf.channel;
+       struct ieee80211_conf *conf = &hw->conf;
        int pos;
 
        DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
 
        return err;
 }
 
-static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
        struct b43_phy *phy;
+       struct ieee80211_conf *conf = &hw->conf;
        unsigned long flags;
        int antenna;
        int err = 0;
 
 }
 
 static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
-                                  struct ieee80211_conf *conf)
+                                  u32 changed)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        struct b43legacy_wldev *dev;
        struct b43legacy_phy *phy;
+       struct ieee80211_conf *conf = &hw->conf;
        unsigned long flags;
        unsigned int new_phymode = 0xFFFF;
        int antenna_tx;
 
  * be set inappropriately and the driver currently sets the hardware up to
  * use it whenever needed.
  */
-static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct iwl_priv *priv = hw->priv;
        const struct iwl_channel_info *ch_info;
+       struct ieee80211_conf *conf = &hw->conf;
        unsigned long flags;
        int ret = 0;
        u16 channel;
 
        mutex_unlock(&priv->mutex);
 }
 
-static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed);
 
 static void iwl3945_bg_scan_completed(struct work_struct *work)
 {
                return;
 
        if (test_bit(STATUS_CONF_PENDING, &priv->status))
-               iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
+               iwl3945_mac_config(priv->hw, 0);
 
        ieee80211_scan_completed(priv->hw);
 
  * be set inappropriately and the driver currently sets the hardware up to
  * use it whenever needed.
  */
-static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct iwl3945_priv *priv = hw->priv;
        const struct iwl3945_channel_info *ch_info;
+       struct ieee80211_conf *conf = &hw->conf;
        unsigned long flags;
        int ret = 0;
 
 
        priv->vif = NULL;
 }
 
-static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct lbtf_private *priv = hw->priv;
+       struct ieee80211_conf *conf = &hw->conf;
+
        if (conf->channel->center_freq != priv->cur_freq) {
                priv->cur_freq = conf->channel->center_freq;
                lbtf_set_channel(priv, conf->channel->hw_value);
 
 }
 
 
-static int mac80211_hwsim_config(struct ieee80211_hw *hw,
-                                struct ieee80211_conf *conf)
+static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct mac80211_hwsim_data *data = hw->priv;
+       struct ieee80211_conf *conf = &hw->conf;
 
        printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n",
               wiphy_name(hw->wiphy), __func__,
 
        p54_set_filter(dev, 0, NULL);
 }
 
-static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int p54_config(struct ieee80211_hw *dev, u32 changed)
 {
        int ret;
        struct p54_common *priv = dev->priv;
+       struct ieee80211_conf *conf = &dev->conf;
 
        mutex_lock(&priv->conf_mutex);
        priv->rx_antenna = 2; /* automatic */
 
                            struct ieee80211_if_init_conf *conf);
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
                                struct ieee80211_if_init_conf *conf);
-int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
 int rt2x00mac_config_interface(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
                               struct ieee80211_if_conf *conf);
 
        /*
         * Reconfigure device.
         */
-       retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf);
+       retval = rt2x00mac_config(rt2x00dev->hw, ~0);
        if (retval)
                goto exit;
 
 
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
 
-int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
+       struct ieee80211_conf *conf = &hw->conf;
        int radio_on;
        int status;
 
 
        priv->vif = NULL;
 }
 
-static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int rtl8180_config(struct ieee80211_hw *dev, u32 changed)
 {
        struct rtl8180_priv *priv = dev->priv;
+       struct ieee80211_conf *conf = &dev->conf;
 
        priv->rf->set_chan(dev, conf);
 
 
        mutex_unlock(&priv->conf_mutex);
 }
 
-static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+static int rtl8187_config(struct ieee80211_hw *dev, u32 changed)
 {
        struct rtl8187_priv *priv = dev->priv;
+       struct ieee80211_conf *conf = &dev->conf;
        u32 reg;
 
        mutex_lock(&priv->conf_mutex);
 
        zd_write_mac_addr(&mac->chip, NULL);
 }
 
-static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int zd_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct zd_mac *mac = zd_hw_mac(hw);
+       struct ieee80211_conf *conf = &hw->conf;
+
        return zd_chip_set_channel(&mac->chip, conf->channel->hw_value);
 }
 
 
 }
 #define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME())
 
+/**
+ * enum ieee80211_conf_changed - denotes which configuration changed
+ *
+ * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed
+ * @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed
+ * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed
+ * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed
+ * @IEEE80211_CONF_CHANGE_PS: the PS flag changed
+ * @IEEE80211_CONF_CHANGE_POWER: the TX power changed
+ * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed
+ */
+enum ieee80211_conf_changed {
+       IEEE80211_CONF_CHANGE_RADIO_ENABLED     = BIT(0),
+       IEEE80211_CONF_CHANGE_BEACON_INTERVAL   = BIT(1),
+       IEEE80211_CONF_CHANGE_LISTEN_INTERVAL   = BIT(2),
+       IEEE80211_CONF_CHANGE_RADIOTAP          = BIT(3),
+       IEEE80211_CONF_CHANGE_PS                = BIT(4),
+       IEEE80211_CONF_CHANGE_POWER             = BIT(5),
+       IEEE80211_CONF_CHANGE_CHANNEL           = BIT(6),
+};
+
 /**
  * struct ieee80211_conf - configuration of the device
  *
  * This struct indicates how the driver shall configure the hardware.
  *
  * @radio_enabled: when zero, driver is required to switch off the radio.
- *     TODO make a flag
  * @beacon_int: beacon interval (TODO make interface config)
  * @listen_interval: listen interval in units of beacon interval
  * @flags: configuration flags defined above
  * @channel: the channel to tune to
  */
 struct ieee80211_conf {
-       int radio_enabled;
-
        int beacon_int;
-       u16 listen_interval;
        u32 flags;
        int power_level;
 
+       u16 listen_interval;
+       bool radio_enabled;
+
        struct ieee80211_channel *channel;
 
        struct ieee80211_sta_ht_cap ht_cap;
                             struct ieee80211_if_init_conf *conf);
        void (*remove_interface)(struct ieee80211_hw *hw,
                                 struct ieee80211_if_init_conf *conf);
-       int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+       int (*config)(struct ieee80211_hw *hw, u32 changed);
        int (*config_interface)(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif,
                                struct ieee80211_if_conf *conf);
 
         */
        if (params->interval) {
                sdata->local->hw.conf.beacon_int = params->interval;
-               ieee80211_hw_config(sdata->local);
+               ieee80211_hw_config(sdata->local,
+                                   IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
                /*
                 * We updated some parameter so if below bails out
                 * it's not an error.
 
 }
 
 
-int ieee80211_hw_config(struct ieee80211_local *local);
+int ieee80211_hw_config(struct ieee80211_local *local, u32 changed);
 int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
 void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 
        struct ieee80211_if_init_conf conf;
        u32 changed = 0;
        int res;
-       bool need_hw_reconfig = 0;
+       u32 hw_reconf_flags = 0;
        u8 null_addr[ETH_ALEN] = {0};
 
        /* fail early if user set an invalid address */
                        res = local->ops->start(local_to_hw(local));
                if (res)
                        goto err_del_bss;
-               need_hw_reconfig = 1;
+               /* we're brought up, everything changes */
+               hw_reconf_flags = ~0;
                ieee80211_led_radio(local, local->hw.conf.radio_enabled);
        }
 
 
                /* must be before the call to ieee80211_configure_filter */
                local->monitors++;
-               if (local->monitors == 1)
+               if (local->monitors == 1) {
                        local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+                       hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP;
+               }
 
                if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
                        local->fif_fcsfail++;
                atomic_inc(&local->iff_promiscs);
 
        local->open_count++;
-       if (need_hw_reconfig) {
-               ieee80211_hw_config(local);
+       if (hw_reconf_flags) {
+               ieee80211_hw_config(local, hw_reconf_flags);
                /*
                 * set default queue parameters so drivers don't
                 * need to initialise the hardware if the hardware
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_init_conf conf;
        struct sta_info *sta;
+       u32 hw_reconf_flags = 0;
 
        /*
         * Stop TX on this interface first.
                }
 
                local->monitors--;
-               if (local->monitors == 0)
+               if (local->monitors == 0) {
                        local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+                       hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP;
+               }
 
                if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
                        local->fif_fcsfail--;
 
                tasklet_disable(&local->tx_pending_tasklet);
                tasklet_disable(&local->tasklet);
+
+               /* no reconfiguring after stop! */
+               hw_reconf_flags = 0;
        }
 
+       /* do after stop to avoid reconfiguring when we stop anyway */
+       if (hw_reconf_flags)
+               ieee80211_hw_config(local, hw_reconf_flags);
+
        return 0;
 }
 
 
                                            &sdata->vif, &conf);
 }
 
-int ieee80211_hw_config(struct ieee80211_local *local)
+int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
        struct ieee80211_channel *chan;
        int ret = 0;
+       int power;
 
        if (local->sw_scanning)
                chan = local->scan_channel;
        else
                chan = local->oper_channel;
 
-       local->hw.conf.channel = chan;
+       if (chan != local->hw.conf.channel) {
+               local->hw.conf.channel = chan;
+               changed |= IEEE80211_CONF_CHANGE_CHANNEL;
+       }
+
 
        if (!local->hw.conf.power_level)
-               local->hw.conf.power_level = chan->max_power;
+               power = chan->max_power;
        else
-               local->hw.conf.power_level = min(chan->max_power,
-                                              local->hw.conf.power_level);
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n",
-              wiphy_name(local->hw.wiphy), chan->center_freq);
-#endif
+               power = min(chan->max_power, local->hw.conf.power_level);
+       if (local->hw.conf.power_level != power) {
+               changed |= IEEE80211_CONF_CHANGE_POWER;
+               local->hw.conf.power_level = power;
+       }
 
-       if (local->open_count) {
-               ret = local->ops->config(local_to_hw(local), &local->hw.conf);
+       if (changed && local->open_count) {
+               ret = local->ops->config(local_to_hw(local), changed);
                /*
                 * HW reconfiguration should never fail, the driver has told
                 * us what it can support so it should live up to that promise.
        local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
        local->short_retry_limit = 7;
        local->long_retry_limit = 4;
-       local->hw.conf.radio_enabled = 1;
+       local->hw.conf.radio_enabled = true;
 
        INIT_LIST_HEAD(&local->interfaces);
 
 
 
        if (local->hw_scanning) {
                local->hw_scanning = false;
-               ieee80211_hw_config(local);
+               /*
+                * Somebody might have requested channel change during scan
+                * that we won't have acted upon, try now. ieee80211_hw_config
+                * will set the flag based on actual changes.
+                */
+               ieee80211_hw_config(local, 0);
                goto done;
        }
 
        local->sw_scanning = false;
-       ieee80211_hw_config(local);
+       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
        netif_tx_lock_bh(local->mdev);
        netif_addr_lock(local->mdev);
 
                if (!skip) {
                        local->scan_channel = chan;
-                       if (ieee80211_hw_config(local))
+                       if (ieee80211_hw_config(local,
+                                               IEEE80211_CONF_CHANGE_CHANNEL))
                                skip = 1;
                }
 
 
                if (local->sw_scanning || local->hw_scanning)
                        ret = 0;
                else
-                       ret = ieee80211_hw_config(local);
+                       ret = ieee80211_hw_config(
+                               local, IEEE80211_CONF_CHANGE_CHANNEL);
 
                rate_control_clear(local);
        }
 
                                      union iwreq_data *data, char *extra)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       bool need_reconfig = 0;
+       u32 reconf_flags = 0;
        int new_power_level;
 
        if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
 
        if (local->hw.conf.power_level != new_power_level) {
                local->hw.conf.power_level = new_power_level;
-               need_reconfig = 1;
+               reconf_flags |= IEEE80211_CONF_CHANGE_POWER;
        }
 
        if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
                local->hw.conf.radio_enabled = !(data->txpower.disabled);
-               need_reconfig = 1;
+               reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
                ieee80211_led_radio(local, local->hw.conf.radio_enabled);
        }
 
-       if (need_reconfig)
-               ieee80211_hw_config(local);
+       if (reconf_flags)
+               ieee80211_hw_config(local, reconf_flags);
 
        return 0;
 }
 
        if (wrq->disabled) {
                conf->flags &= ~IEEE80211_CONF_PS;
-               return ieee80211_hw_config(local);
+               return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
        }
 
        switch (wrq->flags & IW_POWER_MODE) {
                return -EINVAL;
        }
 
-       return ieee80211_hw_config(local);
+       return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 }
 
 static int ieee80211_ioctl_giwpower(struct net_device *dev,