Merge commit 'origin/master' into next
[sfrench/cifs-2.6.git] / drivers / net / wireless / ath9k / regd.c
index 8c2b56ac55ff250c68f8914d00c3c2377a8cfea6..4ca625102291178f9656e96a71a71619d30d3443 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008 Atheros Communications Inc.
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -106,19 +106,20 @@ static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = {
        }
 };
 
-static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)
+static inline bool is_wwr_sku(u16 regd)
 {
-       return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;
+       return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
+               (regd == WORLD);
 }
 
-u16 ath9k_regd_get_rd(struct ath_hw *ah)
+static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)
 {
-       return ath9k_regd_get_eepromRD(ah);
+       return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;
 }
 
 bool ath9k_is_world_regd(struct ath_hw *ah)
 {
-       return isWwrSKU(ah);
+       return is_wwr_sku(ath9k_regd_get_eepromRD(ah));
 }
 
 const struct ieee80211_regdomain *ath9k_default_world_regdomain(void)
@@ -159,13 +160,19 @@ static bool ath9k_is_radar_freq(u16 center_freq)
 }
 
 /*
- * Enable adhoc on 5 GHz if allowed by 11d.
- * Remove passive scan if channel is allowed by 11d,
- * except when on radar frequencies.
+ * N.B: These exception rules do not apply radar freqs.
+ *
+ * - We enable adhoc (or beaconing) if allowed by 11d
+ * - We enable active scan if the channel is allowed by 11d
+ * - If no country IE has been processed and a we determine we have
+ *   received a beacon on a channel we can enable active scan and
+ *   adhoc (or beaconing).
  */
-static void ath9k_reg_apply_5ghz_beaconing_flags(struct wiphy *wiphy,
-                                            enum reg_set_by setby)
+static void ath9k_reg_apply_beaconing_flags(
+       struct wiphy *wiphy,
+       enum nl80211_reg_initiator initiator)
 {
+       enum ieee80211_band band;
        struct ieee80211_supported_band *sband;
        const struct ieee80211_reg_rule *reg_rule;
        struct ieee80211_channel *ch;
@@ -173,34 +180,56 @@ static void ath9k_reg_apply_5ghz_beaconing_flags(struct wiphy *wiphy,
        u32 bandwidth = 0;
        int r;
 
-       if (setby != REGDOM_SET_BY_COUNTRY_IE)
-               return;
-       if (!wiphy->bands[IEEE80211_BAND_5GHZ])
-               return;
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 
-       sband = wiphy->bands[IEEE80211_BAND_5GHZ];
-       for (i = 0; i < sband->n_channels; i++) {
-               ch = &sband->channels[i];
-               r = freq_reg_info(wiphy, ch->center_freq,
-                       &bandwidth, &reg_rule);
-               if (r)
+               if (!wiphy->bands[band])
                        continue;
-               /* If 11d had a rule for this channel ensure we enable adhoc
-                * if it allows us to use it. Note that we would have disabled
-                * it by applying our static world regdomain by default during
-                * probe */
-               if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
-                       ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
-               if (!ath9k_is_radar_freq(ch->center_freq))
-                       continue;
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+
+               sband = wiphy->bands[band];
+
+               for (i = 0; i < sband->n_channels; i++) {
+
+                       ch = &sband->channels[i];
+
+                       if (ath9k_is_radar_freq(ch->center_freq) ||
+                           (ch->flags & IEEE80211_CHAN_RADAR))
+                               continue;
+
+                       if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+                               r = freq_reg_info(wiphy, ch->center_freq,
+                                       &bandwidth, &reg_rule);
+                               if (r)
+                                       continue;
+                               /*
+                                * If 11d had a rule for this channel ensure
+                                * we enable adhoc/beaconing if it allows us to
+                                * use it. Note that we would have disabled it
+                                * by applying our static world regdomain by
+                                * default during init, prior to calling our
+                                * regulatory_hint().
+                                */
+                               if (!(reg_rule->flags &
+                                   NL80211_RRF_NO_IBSS))
+                                       ch->flags &=
+                                         ~IEEE80211_CHAN_NO_IBSS;
+                               if (!(reg_rule->flags &
+                                   NL80211_RRF_PASSIVE_SCAN))
+                                       ch->flags &=
+                                         ~IEEE80211_CHAN_PASSIVE_SCAN;
+                       } else {
+                               if (ch->beacon_found)
+                                       ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+                                         IEEE80211_CHAN_PASSIVE_SCAN);
+                       }
+               }
        }
+
 }
 
 /* Allows active scan scan on Ch 12 and 13 */
-static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
-                                             enum reg_set_by setby)
+static void ath9k_reg_apply_active_scan_flags(
+       struct wiphy *wiphy,
+       enum nl80211_reg_initiator initiator)
 {
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *ch;
@@ -208,12 +237,13 @@ static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
        u32 bandwidth = 0;
        int r;
 
-       /* Force passive scan on Channels 12-13 */
        sband = wiphy->bands[IEEE80211_BAND_2GHZ];
 
-       /* If no country IE has been received always enable active scan
-        * on these channels */
-       if (setby != REGDOM_SET_BY_COUNTRY_IE) {
+       /*
+        * If no country IE has been received always enable active scan
+        * on these channels. This is only done for specific regulatory SKUs
+        */
+       if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
                ch = &sband->channels[11]; /* CH 12 */
                if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
                        ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
@@ -223,10 +253,12 @@ static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
                return;
        }
 
-       /* If a country IE has been recieved check its rule for this
+       /*
+        * If a country IE has been recieved check its rule for this
         * channel first before enabling active scan. The passive scan
-        * would have been enforced by the initial probe processing on
-        * our custom regulatory domain. */
+        * would have been enforced by the initial processing of our
+        * custom regulatory domain.
+        */
 
        ch = &sband->channels[11]; /* CH 12 */
        r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
@@ -278,10 +310,12 @@ void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
        }
 }
 
-void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
+void ath9k_reg_apply_world_flags(struct wiphy *wiphy,
+                                enum nl80211_reg_initiator initiator)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath_hw *ah = sc->sc_ah;
 
        switch (ah->regulatory.regpair->regDmnEnum) {
@@ -289,11 +323,11 @@ void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
        case 0x63:
        case 0x66:
        case 0x67:
-               ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby);
+               ath9k_reg_apply_beaconing_flags(wiphy, initiator);
                break;
        case 0x68:
-               ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby);
-               ath9k_reg_apply_active_scan_flags(wiphy, setby);
+               ath9k_reg_apply_beaconing_flags(wiphy, initiator);
+               ath9k_reg_apply_active_scan_flags(wiphy, initiator);
                break;
        }
        return;
@@ -302,18 +336,18 @@ void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
 int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
 
        /* We always apply this */
        ath9k_reg_apply_radar_flags(wiphy);
 
        switch (request->initiator) {
-       case REGDOM_SET_BY_DRIVER:
-       case REGDOM_SET_BY_INIT:
-       case REGDOM_SET_BY_CORE:
-       case REGDOM_SET_BY_USER:
+       case NL80211_REGDOM_SET_BY_DRIVER:
+       case NL80211_REGDOM_SET_BY_CORE:
+       case NL80211_REGDOM_SET_BY_USER:
                break;
-       case REGDOM_SET_BY_COUNTRY_IE:
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
                if (ath9k_is_world_regd(sc->sc_ah))
                        ath9k_reg_apply_world_flags(wiphy, request->initiator);
                break;
@@ -371,11 +405,8 @@ ath9k_regd_find_country_by_rd(int regdmn)
 }
 
 /* Returns the map of the EEPROM set RD to a country code */
-static u16 ath9k_regd_get_default_country(struct ath_hw *ah)
+static u16 ath9k_regd_get_default_country(u16 rd)
 {
-       u16 rd;
-
-       rd = ath9k_regd_get_eepromRD(ah);
        if (rd & COUNTRY_ERD_FLAG) {
                struct country_code_to_enum_rd *country = NULL;
                u16 cc = rd & ~COUNTRY_ERD_FLAG;
@@ -405,7 +436,7 @@ ath9k_get_regpair(int regdmn)
 int ath9k_regd_init(struct ath_hw *ah)
 {
        struct country_code_to_enum_rd *country = NULL;
-       int regdmn;
+       u16 regdmn;
 
        if (!ath9k_regd_is_eeprom_valid(ah)) {
                DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
@@ -413,14 +444,14 @@ int ath9k_regd_init(struct ath_hw *ah)
                return -EINVAL;
        }
 
-       ah->regulatory.country_code = ath9k_regd_get_default_country(ah);
+       regdmn = ath9k_regd_get_eepromRD(ah);
+       ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn);
 
        if (ah->regulatory.country_code == CTRY_DEFAULT &&
-           ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)
+           regdmn == CTRY_DEFAULT)
                ah->regulatory.country_code = CTRY_UNITED_STATES;
 
        if (ah->regulatory.country_code == CTRY_DEFAULT) {
-               regdmn = ath9k_regd_get_eepromRD(ah);
                country = NULL;
        } else {
                country = ath9k_regd_find_country(ah->regulatory.country_code);
@@ -433,7 +464,6 @@ int ath9k_regd_init(struct ath_hw *ah)
                        regdmn = country->regDmnEnum;
        }
 
-       ah->regulatory.current_rd_inuse = regdmn;
        ah->regulatory.regpair = ath9k_get_regpair(regdmn);
 
        if (!ah->regulatory.regpair) {
@@ -467,7 +497,8 @@ u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan)
        u32 ctl = NO_CTL;
 
        if (!ah->regulatory.regpair ||
-           (ah->regulatory.country_code == CTRY_DEFAULT && isWwrSKU(ah))) {
+           (ah->regulatory.country_code == CTRY_DEFAULT &&
+            is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) {
                if (IS_CHAN_B(chan))
                        ctl = SD_NO_CTL | CTL_11B;
                else if (IS_CHAN_G(chan))
@@ -480,7 +511,7 @@ u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan)
        if (IS_CHAN_B(chan))
                ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B;
        else if (IS_CHAN_G(chan))
-               ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11G;
+               ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G;
        else
                ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A;