Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 31 Jan 2011 20:24:31 +0000 (15:24 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 31 Jan 2011 20:24:31 +0000 (15:24 -0500)
Conflicts:
drivers/net/wireless/wl12xx/spi.c

1  2 
drivers/net/wireless/ath/ath9k/main.c

@@@ -73,7 -73,7 +73,7 @@@ static struct ath9k_channel *ath_get_cu
  
        chan_idx = curchan->hw_value;
        channel = &sc->sc_ah->channels[chan_idx];
 -      ath9k_update_ichannel(sc, hw, channel);
 +      ath9k_cmn_update_ichannel(channel, curchan, hw->conf.channel_type);
        return channel;
  }
  
@@@ -215,6 -215,7 +215,6 @@@ static void ath_update_survey_stats(str
  int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
                    struct ath9k_channel *hchan)
  {
 -      struct ath_wiphy *aphy = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ieee80211_conf *conf = &common->hw->conf;
        cancel_work_sync(&sc->paprd_work);
        cancel_work_sync(&sc->hw_check_work);
        cancel_delayed_work_sync(&sc->tx_complete_work);
 +      cancel_delayed_work_sync(&sc->hw_pll_work);
  
        ath9k_ps_wakeup(sc);
  
        if (!ath_stoprecv(sc))
                stopped = false;
  
 +      if (!ath9k_hw_check_alive(ah))
 +              stopped = false;
 +
        /* XXX: do not flush receive queue here. We don't want
         * to flush data frames already in queue because of
         * changing channel. */
                fastcc = false;
  
        if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
 -              caldata = &aphy->caldata;
 +              caldata = &sc->caldata;
  
        ath_dbg(common, ATH_DBG_CONFIG,
                "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
                if (sc->sc_flags & SC_OP_BEACONS)
                        ath_beacon_config(sc, NULL);
                ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
 +              ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
                ath_start_ani(common);
        }
  
   ps_restore:
 +      ieee80211_wake_queues(hw);
 +
        spin_unlock_bh(&sc->sc_pcu_lock);
  
        ath9k_ps_restore(sc);
@@@ -331,6 -325,8 +331,8 @@@ static bool ath_paprd_send_frame(struc
  {
        struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_tx_control txctl;
        int time_left;
  
        init_completion(&sc->paprd_complete);
        sc->paprd_pending = true;
        txctl.paprd = BIT(chain);
-       if (ath_tx_start(hw, skb, &txctl) != 0)
+       if (ath_tx_start(hw, skb, &txctl) != 0) {
+               ath_dbg(common, ATH_DBG_XMIT, "PAPRD TX failed\n");
+               dev_kfree_skb_any(skb);
                return false;
+       }
  
        time_left = wait_for_completion_timeout(&sc->paprd_complete,
                        msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
@@@ -551,12 -551,6 +557,12 @@@ static void ath_node_attach(struct ath_
        struct ath_hw *ah = sc->sc_ah;
        an = (struct ath_node *)sta->drv_priv;
  
 +#ifdef CONFIG_ATH9K_DEBUGFS
 +      spin_lock(&sc->nodes_lock);
 +      list_add(&an->list, &sc->nodes);
 +      spin_unlock(&sc->nodes_lock);
 +      an->sta = sta;
 +#endif
        if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM)
                sc->sc_flags |= SC_OP_ENABLE_APM;
  
@@@ -572,13 -566,6 +578,13 @@@ static void ath_node_detach(struct ath_
  {
        struct ath_node *an = (struct ath_node *)sta->drv_priv;
  
 +#ifdef CONFIG_ATH9K_DEBUGFS
 +      spin_lock(&sc->nodes_lock);
 +      list_del(&an->list);
 +      spin_unlock(&sc->nodes_lock);
 +      an->sta = NULL;
 +#endif
 +
        if (sc->sc_flags & SC_OP_TXAGGR)
                ath_tx_node_cleanup(sc, an);
  }
@@@ -619,15 -606,7 +625,15 @@@ void ath9k_tasklet(unsigned long data
        ath9k_ps_wakeup(sc);
        spin_lock(&sc->sc_pcu_lock);
  
 -      if (!ath9k_hw_check_alive(ah))
 +      /*
 +       * Only run the baseband hang check if beacons stop working in AP or
 +       * IBSS mode, because it has a high false positive rate. For station
 +       * mode it should not be necessary, since the upper layers will detect
 +       * this through a beacon miss automatically and the following channel
 +       * change will trigger a hardware reset anyway
 +       */
 +      if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 &&
 +          !ath9k_hw_check_alive(ah))
                ieee80211_queue_work(sc->hw, &sc->hw_check_work);
  
        if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
@@@ -806,11 -785,54 +812,11 @@@ chip_reset
  #undef SCHED_INTR
  }
  
 -static u32 ath_get_extchanmode(struct ath_softc *sc,
 -                             struct ieee80211_channel *chan,
 -                             enum nl80211_channel_type channel_type)
 -{
 -      u32 chanmode = 0;
 -
 -      switch (chan->band) {
 -      case IEEE80211_BAND_2GHZ:
 -              switch(channel_type) {
 -              case NL80211_CHAN_NO_HT:
 -              case NL80211_CHAN_HT20:
 -                      chanmode = CHANNEL_G_HT20;
 -                      break;
 -              case NL80211_CHAN_HT40PLUS:
 -                      chanmode = CHANNEL_G_HT40PLUS;
 -                      break;
 -              case NL80211_CHAN_HT40MINUS:
 -                      chanmode = CHANNEL_G_HT40MINUS;
 -                      break;
 -              }
 -              break;
 -      case IEEE80211_BAND_5GHZ:
 -              switch(channel_type) {
 -              case NL80211_CHAN_NO_HT:
 -              case NL80211_CHAN_HT20:
 -                      chanmode = CHANNEL_A_HT20;
 -                      break;
 -              case NL80211_CHAN_HT40PLUS:
 -                      chanmode = CHANNEL_A_HT40PLUS;
 -                      break;
 -              case NL80211_CHAN_HT40MINUS:
 -                      chanmode = CHANNEL_A_HT40MINUS;
 -                      break;
 -              }
 -              break;
 -      default:
 -              break;
 -      }
 -
 -      return chanmode;
 -}
 -
  static void ath9k_bss_assoc_info(struct ath_softc *sc,
                                 struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_bss_conf *bss_conf)
  {
 -      struct ath_wiphy *aphy = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
  
                ath_beacon_config(sc, vif);
  
                /* Reset rssi stats */
 -              aphy->last_rssi = ATH_RSSI_DUMMY_MARKER;
 +              sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
  
                sc->sc_flags |= SC_OP_ANI_RUN;
@@@ -1001,13 -1023,38 +1007,13 @@@ int ath_reset(struct ath_softc *sc, boo
        return r;
  }
  
 -/* XXX: Remove me once we don't depend on ath9k_channel for all
 - * this redundant data */
 -void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
 -                         struct ath9k_channel *ichan)
 -{
 -      struct ieee80211_channel *chan = hw->conf.channel;
 -      struct ieee80211_conf *conf = &hw->conf;
 -
 -      ichan->channel = chan->center_freq;
 -      ichan->chan = chan;
 -
 -      if (chan->band == IEEE80211_BAND_2GHZ) {
 -              ichan->chanmode = CHANNEL_G;
 -              ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G;
 -      } else {
 -              ichan->chanmode = CHANNEL_A;
 -              ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
 -      }
 -
 -      if (conf_is_ht(conf))
 -              ichan->chanmode = ath_get_extchanmode(sc, chan,
 -                                          conf->channel_type);
 -}
 -
  /**********************/
  /* mac80211 callbacks */
  /**********************/
  
  static int ath9k_start(struct ieee80211_hw *hw)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ieee80211_channel *curchan = hw->conf.channel;
  
        mutex_lock(&sc->mutex);
  
 -      if (ath9k_wiphy_started(sc)) {
 -              if (sc->chan_idx == curchan->hw_value) {
 -                      /*
 -                       * Already on the operational channel, the new wiphy
 -                       * can be marked active.
 -                       */
 -                      aphy->state = ATH_WIPHY_ACTIVE;
 -                      ieee80211_wake_queues(hw);
 -              } else {
 -                      /*
 -                       * Another wiphy is on another channel, start the new
 -                       * wiphy in paused state.
 -                       */
 -                      aphy->state = ATH_WIPHY_PAUSED;
 -                      ieee80211_stop_queues(hw);
 -              }
 -              mutex_unlock(&sc->mutex);
 -              return 0;
 -      }
 -      aphy->state = ATH_WIPHY_ACTIVE;
 -
        /* setup initial channel */
 -
        sc->chan_idx = curchan->hw_value;
  
        init_channel = ath_get_curchannel(sc, hw);
@@@ -1124,11 -1193,19 +1130,11 @@@ mutex_unlock
  static int ath9k_tx(struct ieee80211_hw *hw,
                    struct sk_buff *skb)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_tx_control txctl;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
  
 -      if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
 -              ath_dbg(common, ATH_DBG_XMIT,
 -                      "ath9k: %s: TX in unexpected wiphy state %d\n",
 -                      wiphy_name(hw->wiphy), aphy->state);
 -              goto exit;
 -      }
 -
        if (sc->ps_enabled) {
                /*
                 * mac80211 does not set PM field for normal data frames, so we
@@@ -1187,26 -1264,44 +1193,26 @@@ exit
  
  static void ath9k_stop(struct ieee80211_hw *hw)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
 -      int i;
  
        mutex_lock(&sc->mutex);
  
 -      aphy->state = ATH_WIPHY_INACTIVE;
 -
        if (led_blink)
                cancel_delayed_work_sync(&sc->ath_led_blink_work);
  
        cancel_delayed_work_sync(&sc->tx_complete_work);
 +      cancel_delayed_work_sync(&sc->hw_pll_work);
        cancel_work_sync(&sc->paprd_work);
        cancel_work_sync(&sc->hw_check_work);
  
 -      for (i = 0; i < sc->num_sec_wiphy; i++) {
 -              if (sc->sec_wiphy[i])
 -                      break;
 -      }
 -
 -      if (i == sc->num_sec_wiphy) {
 -              cancel_delayed_work_sync(&sc->wiphy_work);
 -              cancel_work_sync(&sc->chan_work);
 -      }
 -
        if (sc->sc_flags & SC_OP_INVALID) {
                ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
                mutex_unlock(&sc->mutex);
                return;
        }
  
 -      if (ath9k_wiphy_started(sc)) {
 -              mutex_unlock(&sc->mutex);
 -              return; /* another wiphy still in use */
 -      }
 -
        /* Ensure HW is awake when we try to shut it down. */
        ath9k_ps_wakeup(sc);
  
        } else
                sc->rx.rxlink = NULL;
  
 +      if (sc->rx.frag) {
 +              dev_kfree_skb_any(sc->rx.frag);
 +              sc->rx.frag = NULL;
 +      }
 +
        /* disable HAL and put h/w to sleep */
        ath9k_hw_disable(ah);
        ath9k_hw_configpcipowersave(ah, 1, 1);
        ath9k_ps_restore(sc);
  
        sc->ps_idle = true;
 -      ath9k_set_wiphy_idle(aphy, true);
        ath_radio_disable(sc, hw);
  
        sc->sc_flags |= SC_OP_INVALID;
        ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
  }
  
 -static int ath9k_add_interface(struct ieee80211_hw *hw,
 -                             struct ieee80211_vif *vif)
 +bool ath9k_uses_beacons(int type)
 +{
 +      switch (type) {
 +      case NL80211_IFTYPE_AP:
 +      case NL80211_IFTYPE_ADHOC:
 +      case NL80211_IFTYPE_MESH_POINT:
 +              return true;
 +      default:
 +              return false;
 +      }
 +}
 +
 +static void ath9k_reclaim_beacon(struct ath_softc *sc,
 +                               struct ieee80211_vif *vif)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 -      struct ath_hw *ah = sc->sc_ah;
 -      struct ath_common *common = ath9k_hw_common(ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
 -      enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
 -      int ret = 0;
  
 -      mutex_lock(&sc->mutex);
 +      /* Disable SWBA interrupt */
 +      sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
 +      ath9k_ps_wakeup(sc);
 +      ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
 +      ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 +      tasklet_kill(&sc->bcon_tasklet);
 +      ath9k_ps_restore(sc);
 +
 +      ath_beacon_return(sc, avp);
 +      sc->sc_flags &= ~SC_OP_BEACONS;
 +
 +      if (sc->nbcnvifs > 0) {
 +              /* Re-enable beaconing */
 +              sc->sc_ah->imask |= ATH9K_INT_SWBA;
 +              ath9k_ps_wakeup(sc);
 +              ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
 +              ath9k_ps_restore(sc);
 +      }
 +}
 +
 +static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 +{
 +      struct ath9k_vif_iter_data *iter_data = data;
 +      int i;
 +
 +      if (iter_data->hw_macaddr)
 +              for (i = 0; i < ETH_ALEN; i++)
 +                      iter_data->mask[i] &=
 +                              ~(iter_data->hw_macaddr[i] ^ mac[i]);
  
        switch (vif->type) {
 -      case NL80211_IFTYPE_STATION:
 -              ic_opmode = NL80211_IFTYPE_STATION;
 +      case NL80211_IFTYPE_AP:
 +              iter_data->naps++;
                break;
 -      case NL80211_IFTYPE_WDS:
 -              ic_opmode = NL80211_IFTYPE_WDS;
 +      case NL80211_IFTYPE_STATION:
 +              iter_data->nstations++;
                break;
        case NL80211_IFTYPE_ADHOC:
 -      case NL80211_IFTYPE_AP:
 +              iter_data->nadhocs++;
 +              break;
        case NL80211_IFTYPE_MESH_POINT:
 -              if (sc->nbcnvifs >= ATH_BCBUF) {
 -                      ret = -ENOBUFS;
 -                      goto out;
 -              }
 -              ic_opmode = vif->type;
 +              iter_data->nmeshes++;
 +              break;
 +      case NL80211_IFTYPE_WDS:
 +              iter_data->nwds++;
                break;
        default:
 -              ath_err(common, "Interface type %d not yet supported\n",
 -                      vif->type);
 -              ret = -EOPNOTSUPP;
 -              goto out;
 +              iter_data->nothers++;
 +              break;
        }
 +}
  
 -      ath_dbg(common, ATH_DBG_CONFIG,
 -              "Attach a VIF of type: %d\n", ic_opmode);
 +/* Called with sc->mutex held. */
 +void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
 +                             struct ieee80211_vif *vif,
 +                             struct ath9k_vif_iter_data *iter_data)
 +{
 +      struct ath_softc *sc = hw->priv;
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ath_common *common = ath9k_hw_common(ah);
  
 -      /* Set the VIF opmode */
 -      avp->av_opmode = ic_opmode;
 -      avp->av_bslot = -1;
 +      /*
 +       * Use the hardware MAC address as reference, the hardware uses it
 +       * together with the BSSID mask when matching addresses.
 +       */
 +      memset(iter_data, 0, sizeof(*iter_data));
 +      iter_data->hw_macaddr = common->macaddr;
 +      memset(&iter_data->mask, 0xff, ETH_ALEN);
  
 -      sc->nvifs++;
 +      if (vif)
 +              ath9k_vif_iter(iter_data, vif->addr, vif);
 +
 +      /* Get list of all active MAC addresses */
 +      ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
 +                                                 iter_data);
 +}
 +
 +/* Called with sc->mutex held. */
 +static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
 +                                        struct ieee80211_vif *vif)
 +{
 +      struct ath_softc *sc = hw->priv;
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ath_common *common = ath9k_hw_common(ah);
 +      struct ath9k_vif_iter_data iter_data;
  
 -      ath9k_set_bssid_mask(hw, vif);
 +      ath9k_calculate_iter_data(hw, vif, &iter_data);
  
 -      if (sc->nvifs > 1)
 -              goto out; /* skip global settings for secondary vif */
 +      /* Set BSSID mask. */
 +      memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
 +      ath_hw_setbssidmask(common);
  
 -      if (ic_opmode == NL80211_IFTYPE_AP) {
 +      /* Set op-mode & TSF */
 +      if (iter_data.naps > 0) {
                ath9k_hw_set_tsfadjust(ah, 1);
                sc->sc_flags |= SC_OP_TSF_RESET;
 -      }
 +              ah->opmode = NL80211_IFTYPE_AP;
 +      } else {
 +              ath9k_hw_set_tsfadjust(ah, 0);
 +              sc->sc_flags &= ~SC_OP_TSF_RESET;
  
 -      /* Set the device opmode */
 -      ah->opmode = ic_opmode;
 +              if (iter_data.nwds + iter_data.nmeshes)
 +                      ah->opmode = NL80211_IFTYPE_AP;
 +              else if (iter_data.nadhocs)
 +                      ah->opmode = NL80211_IFTYPE_ADHOC;
 +              else
 +                      ah->opmode = NL80211_IFTYPE_STATION;
 +      }
  
        /*
         * Enable MIB interrupts when there are hardware phy counters.
 -       * Note we only do this (at the moment) for station mode.
         */
 -      if ((vif->type == NL80211_IFTYPE_STATION) ||
 -          (vif->type == NL80211_IFTYPE_ADHOC) ||
 -          (vif->type == NL80211_IFTYPE_MESH_POINT)) {
 +      if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) {
                if (ah->config.enable_ani)
                        ah->imask |= ATH9K_INT_MIB;
                ah->imask |= ATH9K_INT_TSFOOR;
 +      } else {
 +              ah->imask &= ~ATH9K_INT_MIB;
 +              ah->imask &= ~ATH9K_INT_TSFOOR;
        }
  
        ath9k_hw_set_interrupts(ah, ah->imask);
  
 -      if (vif->type == NL80211_IFTYPE_AP    ||
 -          vif->type == NL80211_IFTYPE_ADHOC) {
 +      /* Set up ANI */
 +      if ((iter_data.naps + iter_data.nadhocs) > 0) {
                sc->sc_flags |= SC_OP_ANI_RUN;
                ath_start_ani(common);
 +      } else {
 +              sc->sc_flags &= ~SC_OP_ANI_RUN;
 +              del_timer_sync(&common->ani.timer);
        }
 +}
  
 -out:
 -      mutex_unlock(&sc->mutex);
 -      return ret;
 +/* Called with sc->mutex held, vif counts set up properly. */
 +static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
 +                                 struct ieee80211_vif *vif)
 +{
 +      struct ath_softc *sc = hw->priv;
 +
 +      ath9k_calculate_summary_state(hw, vif);
 +
 +      if (ath9k_uses_beacons(vif->type)) {
 +              int error;
 +              ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 +              /* This may fail because upper levels do not have beacons
 +               * properly configured yet.  That's OK, we assume it
 +               * will be properly configured and then we will be notified
 +               * in the info_changed method and set up beacons properly
 +               * there.
 +               */
 +              error = ath_beacon_alloc(sc, vif);
 +              if (error)
 +                      ath9k_reclaim_beacon(sc, vif);
 +              else
 +                      ath_beacon_config(sc, vif);
 +      }
  }
  
 -static void ath9k_reclaim_beacon(struct ath_softc *sc,
 -                               struct ieee80211_vif *vif)
 +
 +static int ath9k_add_interface(struct ieee80211_hw *hw,
 +                             struct ieee80211_vif *vif)
  {
 +      struct ath_softc *sc = hw->priv;
 +      struct ath_hw *ah = sc->sc_ah;
 +      struct ath_common *common = ath9k_hw_common(ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
 +      int ret = 0;
  
 -      /* Disable SWBA interrupt */
 -      sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
 -      ath9k_ps_wakeup(sc);
 -      ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
 -      ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 -      tasklet_kill(&sc->bcon_tasklet);
 -      ath9k_ps_restore(sc);
 +      mutex_lock(&sc->mutex);
  
 -      ath_beacon_return(sc, avp);
 -      sc->sc_flags &= ~SC_OP_BEACONS;
 +      switch (vif->type) {
 +      case NL80211_IFTYPE_STATION:
 +      case NL80211_IFTYPE_WDS:
 +      case NL80211_IFTYPE_ADHOC:
 +      case NL80211_IFTYPE_AP:
 +      case NL80211_IFTYPE_MESH_POINT:
 +              break;
 +      default:
 +              ath_err(common, "Interface type %d not yet supported\n",
 +                      vif->type);
 +              ret = -EOPNOTSUPP;
 +              goto out;
 +      }
  
 -      if (sc->nbcnvifs > 0) {
 -              /* Re-enable beaconing */
 -              sc->sc_ah->imask |= ATH9K_INT_SWBA;
 -              ath9k_ps_wakeup(sc);
 -              ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
 -              ath9k_ps_restore(sc);
 +      if (ath9k_uses_beacons(vif->type)) {
 +              if (sc->nbcnvifs >= ATH_BCBUF) {
 +                      ath_err(common, "Not enough beacon buffers when adding"
 +                              " new interface of type: %i\n",
 +                              vif->type);
 +                      ret = -ENOBUFS;
 +                      goto out;
 +              }
 +      }
 +
 +      if ((vif->type == NL80211_IFTYPE_ADHOC) &&
 +          sc->nvifs > 0) {
 +              ath_err(common, "Cannot create ADHOC interface when other"
 +                      " interfaces already exist.\n");
 +              ret = -EINVAL;
 +              goto out;
        }
 +
 +      ath_dbg(common, ATH_DBG_CONFIG,
 +              "Attach a VIF of type: %d\n", vif->type);
 +
 +      /* Set the VIF opmode */
 +      avp->av_opmode = vif->type;
 +      avp->av_bslot = -1;
 +
 +      sc->nvifs++;
 +
 +      ath9k_do_vif_add_setup(hw, vif);
 +out:
 +      mutex_unlock(&sc->mutex);
 +      return ret;
  }
  
  static int ath9k_change_interface(struct ieee80211_hw *hw,
                                  enum nl80211_iftype new_type,
                                  bool p2p)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int ret = 0;
  
        ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n");
        mutex_lock(&sc->mutex);
  
 -      switch (new_type) {
 -      case NL80211_IFTYPE_AP:
 -      case NL80211_IFTYPE_ADHOC:
 +      /* See if new interface type is valid. */
 +      if ((new_type == NL80211_IFTYPE_ADHOC) &&
 +          (sc->nvifs > 1)) {
 +              ath_err(common, "When using ADHOC, it must be the only"
 +                      " interface.\n");
 +              ret = -EINVAL;
 +              goto out;
 +      }
 +
 +      if (ath9k_uses_beacons(new_type) &&
 +          !ath9k_uses_beacons(vif->type)) {
                if (sc->nbcnvifs >= ATH_BCBUF) {
                        ath_err(common, "No beacon slot available\n");
                        ret = -ENOBUFS;
                        goto out;
                }
 -              break;
 -      case NL80211_IFTYPE_STATION:
 -              /* Stop ANI */
 -              sc->sc_flags &= ~SC_OP_ANI_RUN;
 -              del_timer_sync(&common->ani.timer);
 -              if ((vif->type == NL80211_IFTYPE_AP) ||
 -                  (vif->type == NL80211_IFTYPE_ADHOC))
 -                      ath9k_reclaim_beacon(sc, vif);
 -              break;
 -      default:
 -              ath_err(common, "Interface type %d not yet supported\n",
 -                              vif->type);
 -              ret = -ENOTSUPP;
 -              goto out;
        }
 +
 +      /* Clean up old vif stuff */
 +      if (ath9k_uses_beacons(vif->type))
 +              ath9k_reclaim_beacon(sc, vif);
 +
 +      /* Add new settings */
        vif->type = new_type;
        vif->p2p = p2p;
  
 +      ath9k_do_vif_add_setup(hw, vif);
  out:
        mutex_unlock(&sc->mutex);
        return ret;
  static void ath9k_remove_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
  
        ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n");
  
        mutex_lock(&sc->mutex);
  
 -      /* Stop ANI */
 -      sc->sc_flags &= ~SC_OP_ANI_RUN;
 -      del_timer_sync(&common->ani.timer);
 +      sc->nvifs--;
  
        /* Reclaim beacon resources */
 -      if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
 -          (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) ||
 -          (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT))
 +      if (ath9k_uses_beacons(vif->type))
                ath9k_reclaim_beacon(sc, vif);
  
 -      sc->nvifs--;
 +      ath9k_calculate_summary_state(hw, NULL);
  
        mutex_unlock(&sc->mutex);
  }
@@@ -1598,11 -1568,12 +1604,11 @@@ static void ath9k_disable_ps(struct ath
  
  static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ieee80211_conf *conf = &hw->conf;
 -      bool disable_radio;
 +      bool disable_radio = false;
  
        mutex_lock(&sc->mutex);
  
         * the end.
         */
        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
 -              bool enable_radio;
 -              bool all_wiphys_idle;
 -              bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 -
 -              spin_lock_bh(&sc->wiphy_lock);
 -              all_wiphys_idle =  ath9k_all_wiphys_idle(sc);
 -              ath9k_set_wiphy_idle(aphy, idle);
 -
 -              enable_radio = (!idle && all_wiphys_idle);
 -
 -              /*
 -               * After we unlock here its possible another wiphy
 -               * can be re-renabled so to account for that we will
 -               * only disable the radio toward the end of this routine
 -               * if by then all wiphys are still idle.
 -               */
 -              spin_unlock_bh(&sc->wiphy_lock);
 -
 -              if (enable_radio) {
 -                      sc->ps_idle = false;
 +              sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 +              if (!sc->ps_idle) {
                        ath_radio_enable(sc, hw);
                        ath_dbg(common, ATH_DBG_CONFIG,
                                "not-idle: enabling radio\n");
 +              } else {
 +                      disable_radio = true;
                }
        }
  
                if (ah->curchan)
                        old_pos = ah->curchan - &ah->channels[0];
  
 -              aphy->chan_idx = pos;
 -              aphy->chan_is_ht = conf_is_ht(conf);
                if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
                        sc->sc_flags |= SC_OP_OFFCHANNEL;
                else
                        sc->sc_flags &= ~SC_OP_OFFCHANNEL;
  
 -              if (aphy->state == ATH_WIPHY_SCAN ||
 -                  aphy->state == ATH_WIPHY_ACTIVE)
 -                      ath9k_wiphy_pause_all_forced(sc, aphy);
 -              else {
 -                      /*
 -                       * Do not change operational channel based on a paused
 -                       * wiphy changes.
 -                       */
 -                      goto skip_chan_change;
 -              }
 -
                ath_dbg(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
                        curchan->center_freq);
  
 -              /* XXX: remove me eventualy */
 -              ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]);
 +              ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
 +                                        curchan, conf->channel_type);
  
                /* update survey stats for the old channel before switching */
                spin_lock_irqsave(&common->cc_lock, flags);
                        ath_update_survey_nf(sc, old_pos);
        }
  
 -skip_chan_change:
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
                sc->config.txpowlimit = 2 * conf->power_level;
                ath9k_ps_wakeup(sc);
                ath9k_ps_restore(sc);
        }
  
 -      spin_lock_bh(&sc->wiphy_lock);
 -      disable_radio = ath9k_all_wiphys_idle(sc);
 -      spin_unlock_bh(&sc->wiphy_lock);
 -
        if (disable_radio) {
                ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
 -              sc->ps_idle = true;
                ath_radio_disable(sc, hw);
        }
  
@@@ -1744,7 -1750,8 +1750,7 @@@ static void ath9k_configure_filter(stru
                                   unsigned int *total_flags,
                                   u64 multicast)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        u32 rfilt;
  
        changed_flags &= SUPPORTED_FILTERS;
@@@ -1764,7 -1771,8 +1770,7 @@@ static int ath9k_sta_add(struct ieee802
                         struct ieee80211_vif *vif,
                         struct ieee80211_sta *sta)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
  
        ath_node_attach(sc, sta);
  
@@@ -1775,7 -1783,8 +1781,7 @@@ static int ath9k_sta_remove(struct ieee
                            struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
  
        ath_node_detach(sc, sta);
  
  static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
                         const struct ieee80211_tx_queue_params *params)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_txq *txq;
        struct ath9k_tx_queue_info qi;
@@@ -1829,7 -1839,8 +1835,7 @@@ static int ath9k_set_key(struct ieee802
                         struct ieee80211_sta *sta,
                         struct ieee80211_key_conf *key)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int ret = 0;
  
@@@ -1873,7 -1884,8 +1879,7 @@@ static void ath9k_bss_info_changed(stru
                                   struct ieee80211_bss_conf *bss_conf,
                                   u32 changed)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
        if ((changed & BSS_CHANGED_BEACON) ||
            ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) {
                ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 -              error = ath_beacon_alloc(aphy, vif);
 +              error = ath_beacon_alloc(sc, vif);
                if (!error)
                        ath_beacon_config(sc, vif);
        }
                if (vif->type == NL80211_IFTYPE_AP) {
                        sc->sc_flags |= SC_OP_TSF_RESET;
                        ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 -                      error = ath_beacon_alloc(aphy, vif);
 +                      error = ath_beacon_alloc(sc, vif);
                        if (!error)
                                ath_beacon_config(sc, vif);
                } else {
  
  static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
  {
 +      struct ath_softc *sc = hw->priv;
        u64 tsf;
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
  
        mutex_lock(&sc->mutex);
        ath9k_ps_wakeup(sc);
  
  static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
  
        mutex_lock(&sc->mutex);
        ath9k_ps_wakeup(sc);
  
  static void ath9k_reset_tsf(struct ieee80211_hw *hw)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
  
        mutex_lock(&sc->mutex);
  
@@@ -2018,9 -2033,10 +2024,9 @@@ static int ath9k_ampdu_action(struct ie
                              struct ieee80211_vif *vif,
                              enum ieee80211_ampdu_mlme_action action,
                              struct ieee80211_sta *sta,
 -                            u16 tid, u16 *ssn)
 +                            u16 tid, u16 *ssn, u8 buf_size)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        int ret = 0;
  
        local_bh_disable();
  static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
                             struct survey_info *survey)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *chan;
        return 0;
  }
  
 -static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 -{
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 -
 -      mutex_lock(&sc->mutex);
 -      if (ath9k_wiphy_scanning(sc)) {
 -              /*
 -               * There is a race here in mac80211 but fixing it requires
 -               * we revisit how we handle the scan complete callback.
 -               * After mac80211 fixes we will not have configured hardware
 -               * to the home channel nor would we have configured the RX
 -               * filter yet.
 -               */
 -              mutex_unlock(&sc->mutex);
 -              return;
 -      }
 -
 -      aphy->state = ATH_WIPHY_SCAN;
 -      ath9k_wiphy_pause_all_forced(sc, aphy);
 -      mutex_unlock(&sc->mutex);
 -}
 -
 -/*
 - * XXX: this requires a revisit after the driver
 - * scan_complete gets moved to another place/removed in mac80211.
 - */
 -static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 -{
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 -
 -      mutex_lock(&sc->mutex);
 -      aphy->state = ATH_WIPHY_ACTIVE;
 -      mutex_unlock(&sc->mutex);
 -}
 -
  static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
  {
 -      struct ath_wiphy *aphy = hw->priv;
 -      struct ath_softc *sc = aphy->sc;
 +      struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
  
        mutex_lock(&sc->mutex);
@@@ -2129,6 -2184,8 +2135,6 @@@ struct ieee80211_ops ath9k_ops = 
        .reset_tsf          = ath9k_reset_tsf,
        .ampdu_action       = ath9k_ampdu_action,
        .get_survey         = ath9k_get_survey,
 -      .sw_scan_start      = ath9k_sw_scan_start,
 -      .sw_scan_complete   = ath9k_sw_scan_complete,
        .rfkill_poll        = ath9k_rfkill_poll_state,
        .set_coverage_class = ath9k_set_coverage_class,
  };