aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath9k/main.c
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2009-01-22 18:16:48 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:01:20 -0500
commit5f8e077c0adc0dc7cfad64cdc05276e1961a1394 (patch)
treedc918d9eacab12998d8e67f259de32dbbb409e81 /drivers/net/wireless/ath9k/main.c
parent24ed1da1337b92e3b0a89f2c2b7cd33b9a8fcb62 (diff)
ath9k: simplify regulatory code
Now that cfg80211 has its own regulatory infrastructure we can condense ath9k's regulatory code considerably. We only keep data we need to provide our own regulatory_hint(), reg_notifier() and information necessary for calibration. Atheros hardware supports 12 world regulatory domains, since these are custom we apply them through the the new wiphy_apply_custom_regulatory(). Although we have 12 we can consolidate these into 5 structures based on frequency and apply a different set of flags that differentiate them on a case by case basis through the reg_notifier(). If CRDA is not found our own custom world regulatory domain is applied, this is identical to cfg80211's except we enable passive scan on most frequencies. Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k/main.c')
-rw-r--r--drivers/net/wireless/ath9k/main.c263
1 files changed, 142 insertions, 121 deletions
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index b494a0d7e8b5..561a2c3adbbe 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -28,6 +28,77 @@ MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
28MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); 28MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
29MODULE_LICENSE("Dual BSD/GPL"); 29MODULE_LICENSE("Dual BSD/GPL");
30 30
31/* We use the hw_value as an index into our private channel structure */
32
33#define CHAN2G(_freq, _idx) { \
34 .center_freq = (_freq), \
35 .hw_value = (_idx), \
36 .max_power = 30, \
37}
38
39#define CHAN5G(_freq, _idx) { \
40 .band = IEEE80211_BAND_5GHZ, \
41 .center_freq = (_freq), \
42 .hw_value = (_idx), \
43 .max_power = 30, \
44}
45
46/* Some 2 GHz radios are actually tunable on 2312-2732
47 * on 5 MHz steps, we support the channels which we know
48 * we have calibration data for all cards though to make
49 * this static */
50static struct ieee80211_channel ath9k_2ghz_chantable[] = {
51 CHAN2G(2412, 0), /* Channel 1 */
52 CHAN2G(2417, 1), /* Channel 2 */
53 CHAN2G(2422, 2), /* Channel 3 */
54 CHAN2G(2427, 3), /* Channel 4 */
55 CHAN2G(2432, 4), /* Channel 5 */
56 CHAN2G(2437, 5), /* Channel 6 */
57 CHAN2G(2442, 6), /* Channel 7 */
58 CHAN2G(2447, 7), /* Channel 8 */
59 CHAN2G(2452, 8), /* Channel 9 */
60 CHAN2G(2457, 9), /* Channel 10 */
61 CHAN2G(2462, 10), /* Channel 11 */
62 CHAN2G(2467, 11), /* Channel 12 */
63 CHAN2G(2472, 12), /* Channel 13 */
64 CHAN2G(2484, 13), /* Channel 14 */
65};
66
67/* Some 5 GHz radios are actually tunable on XXXX-YYYY
68 * on 5 MHz steps, we support the channels which we know
69 * we have calibration data for all cards though to make
70 * this static */
71static struct ieee80211_channel ath9k_5ghz_chantable[] = {
72 /* _We_ call this UNII 1 */
73 CHAN5G(5180, 14), /* Channel 36 */
74 CHAN5G(5200, 15), /* Channel 40 */
75 CHAN5G(5220, 16), /* Channel 44 */
76 CHAN5G(5240, 17), /* Channel 48 */
77 /* _We_ call this UNII 2 */
78 CHAN5G(5260, 18), /* Channel 52 */
79 CHAN5G(5280, 19), /* Channel 56 */
80 CHAN5G(5300, 20), /* Channel 60 */
81 CHAN5G(5320, 21), /* Channel 64 */
82 /* _We_ call this "Middle band" */
83 CHAN5G(5500, 22), /* Channel 100 */
84 CHAN5G(5520, 23), /* Channel 104 */
85 CHAN5G(5540, 24), /* Channel 108 */
86 CHAN5G(5560, 25), /* Channel 112 */
87 CHAN5G(5580, 26), /* Channel 116 */
88 CHAN5G(5600, 27), /* Channel 120 */
89 CHAN5G(5620, 28), /* Channel 124 */
90 CHAN5G(5640, 29), /* Channel 128 */
91 CHAN5G(5660, 30), /* Channel 132 */
92 CHAN5G(5680, 31), /* Channel 136 */
93 CHAN5G(5700, 32), /* Channel 140 */
94 /* _We_ call this UNII 3 */
95 CHAN5G(5745, 33), /* Channel 149 */
96 CHAN5G(5765, 34), /* Channel 153 */
97 CHAN5G(5785, 35), /* Channel 157 */
98 CHAN5G(5805, 36), /* Channel 161 */
99 CHAN5G(5825, 37), /* Channel 165 */
100};
101
31static void ath_cache_conf_rate(struct ath_softc *sc, 102static void ath_cache_conf_rate(struct ath_softc *sc,
32 struct ieee80211_conf *conf) 103 struct ieee80211_conf *conf)
33{ 104{
@@ -152,75 +223,6 @@ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
152 } 223 }
153} 224}
154 225
155static int ath_setup_channels(struct ath_softc *sc)
156{
157 struct ath_hal *ah = sc->sc_ah;
158 int nchan, i, a = 0, b = 0;
159 u8 regclassids[ATH_REGCLASSIDS_MAX];
160 u32 nregclass = 0;
161 struct ieee80211_supported_band *band_2ghz;
162 struct ieee80211_supported_band *band_5ghz;
163 struct ieee80211_channel *chan_2ghz;
164 struct ieee80211_channel *chan_5ghz;
165 struct ath9k_channel *c;
166
167 /* Fill in ah->ah_channels */
168 if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan,
169 regclassids, ATH_REGCLASSIDS_MAX,
170 &nregclass, CTRY_DEFAULT, false, 1)) {
171 u32 rd = ah->ah_currentRD;
172 DPRINTF(sc, ATH_DBG_FATAL,
173 "Unable to collect channel list; "
174 "regdomain likely %u country code %u\n",
175 rd, CTRY_DEFAULT);
176 return -EINVAL;
177 }
178
179 band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ];
180 band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ];
181 chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ];
182 chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ];
183
184 for (i = 0; i < nchan; i++) {
185 c = &ah->ah_channels[i];
186 if (IS_CHAN_2GHZ(c)) {
187 chan_2ghz[a].band = IEEE80211_BAND_2GHZ;
188 chan_2ghz[a].center_freq = c->channel;
189 chan_2ghz[a].max_power = c->maxTxPower;
190 c->chan = &chan_2ghz[a];
191
192 if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
193 chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS;
194 if (c->channelFlags & CHANNEL_PASSIVE)
195 chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
196
197 band_2ghz->n_channels = ++a;
198
199 DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, "
200 "channelFlags: 0x%x\n",
201 c->channel, c->channelFlags);
202 } else if (IS_CHAN_5GHZ(c)) {
203 chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
204 chan_5ghz[b].center_freq = c->channel;
205 chan_5ghz[b].max_power = c->maxTxPower;
206 c->chan = &chan_5ghz[a];
207
208 if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
209 chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS;
210 if (c->channelFlags & CHANNEL_PASSIVE)
211 chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
212
213 band_5ghz->n_channels = ++b;
214
215 DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, "
216 "channelFlags: 0x%x\n",
217 c->channel, c->channelFlags);
218 }
219 }
220
221 return 0;
222}
223
224/* 226/*
225 * Set/change channels. If the channel is really being changed, it's done 227 * Set/change channels. If the channel is really being changed, it's done
226 * by reseting the chip. To accomplish this we must first cleanup any pending 228 * by reseting the chip. To accomplish this we must first cleanup any pending
@@ -582,19 +584,6 @@ irqreturn_t ath_isr(int irq, void *dev)
582 return IRQ_HANDLED; 584 return IRQ_HANDLED;
583} 585}
584 586
585static int ath_get_channel(struct ath_softc *sc,
586 struct ieee80211_channel *chan)
587{
588 int i;
589
590 for (i = 0; i < sc->sc_ah->ah_nchan; i++) {
591 if (sc->sc_ah->ah_channels[i].channel == chan->center_freq)
592 return i;
593 }
594
595 return -1;
596}
597
598static u32 ath_get_extchanmode(struct ath_softc *sc, 587static u32 ath_get_extchanmode(struct ath_softc *sc,
599 struct ieee80211_channel *chan, 588 struct ieee80211_channel *chan,
600 enum nl80211_channel_type channel_type) 589 enum nl80211_channel_type channel_type)
@@ -1349,16 +1338,12 @@ static int ath_init(u16 devid, struct ath_softc *sc)
1349 for (i = 0; i < sc->sc_keymax; i++) 1338 for (i = 0; i < sc->sc_keymax; i++)
1350 ath9k_hw_keyreset(ah, (u16) i); 1339 ath9k_hw_keyreset(ah, (u16) i);
1351 1340
1352 /* Collect the channel list using the default country code */ 1341 if (ath9k_regd_init(sc->sc_ah))
1353
1354 error = ath_setup_channels(sc);
1355 if (error)
1356 goto bad; 1342 goto bad;
1357 1343
1358 /* default to MONITOR mode */ 1344 /* default to MONITOR mode */
1359 sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR; 1345 sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR;
1360 1346
1361
1362 /* Setup rate tables */ 1347 /* Setup rate tables */
1363 1348
1364 ath_rate_attach(sc); 1349 ath_rate_attach(sc);
@@ -1490,18 +1475,20 @@ static int ath_init(u16 devid, struct ath_softc *sc)
1490 1475
1491 /* setup channels and rates */ 1476 /* setup channels and rates */
1492 1477
1493 sc->sbands[IEEE80211_BAND_2GHZ].channels = 1478 sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
1494 sc->channels[IEEE80211_BAND_2GHZ];
1495 sc->sbands[IEEE80211_BAND_2GHZ].bitrates = 1479 sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
1496 sc->rates[IEEE80211_BAND_2GHZ]; 1480 sc->rates[IEEE80211_BAND_2GHZ];
1497 sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; 1481 sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
1482 sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
1483 ARRAY_SIZE(ath9k_2ghz_chantable);
1498 1484
1499 if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { 1485 if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
1500 sc->sbands[IEEE80211_BAND_5GHZ].channels = 1486 sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
1501 sc->channels[IEEE80211_BAND_5GHZ];
1502 sc->sbands[IEEE80211_BAND_5GHZ].bitrates = 1487 sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
1503 sc->rates[IEEE80211_BAND_5GHZ]; 1488 sc->rates[IEEE80211_BAND_5GHZ];
1504 sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; 1489 sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
1490 sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
1491 ARRAY_SIZE(ath9k_5ghz_chantable);
1505 } 1492 }
1506 1493
1507 if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_BT_COEX) 1494 if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_BT_COEX)
@@ -1550,6 +1537,9 @@ int ath_attach(u16 devid, struct ath_softc *sc)
1550 BIT(NL80211_IFTYPE_STATION) | 1537 BIT(NL80211_IFTYPE_STATION) |
1551 BIT(NL80211_IFTYPE_ADHOC); 1538 BIT(NL80211_IFTYPE_ADHOC);
1552 1539
1540 hw->wiphy->reg_notifier = ath9k_reg_notifier;
1541 hw->wiphy->strict_regulatory = true;
1542
1553 hw->queues = 4; 1543 hw->queues = 4;
1554 hw->max_rates = 4; 1544 hw->max_rates = 4;
1555 hw->max_rate_tries = ATH_11N_TXMAXTRY; 1545 hw->max_rate_tries = ATH_11N_TXMAXTRY;
@@ -1588,11 +1578,36 @@ int ath_attach(u16 devid, struct ath_softc *sc)
1588 goto detach; 1578 goto detach;
1589#endif 1579#endif
1590 1580
1581 if (ath9k_is_world_regd(sc->sc_ah)) {
1582 /* Anything applied here (prior to wiphy registratoin) gets
1583 * saved on the wiphy orig_* parameters */
1584 const struct ieee80211_regdomain *regd =
1585 ath9k_world_regdomain(sc->sc_ah);
1586 hw->wiphy->custom_regulatory = true;
1587 hw->wiphy->strict_regulatory = false;
1588 wiphy_apply_custom_regulatory(sc->hw->wiphy, regd);
1589 ath9k_reg_apply_radar_flags(hw->wiphy);
1590 ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT);
1591 } else {
1592 /* This gets applied in the case of the absense of CRDA,
1593 * its our own custom world regulatory domain, similar to
1594 * cfg80211's but we enable passive scanning */
1595 const struct ieee80211_regdomain *regd =
1596 ath9k_default_world_regdomain();
1597 wiphy_apply_custom_regulatory(sc->hw->wiphy, regd);
1598 ath9k_reg_apply_radar_flags(hw->wiphy);
1599 ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT);
1600 }
1601
1591 error = ieee80211_register_hw(hw); 1602 error = ieee80211_register_hw(hw);
1592 1603
1604 if (!ath9k_is_world_regd(sc->sc_ah))
1605 regulatory_hint(hw->wiphy, sc->sc_ah->alpha2);
1606
1593 /* Initialize LED control */ 1607 /* Initialize LED control */
1594 ath_init_leds(sc); 1608 ath_init_leds(sc);
1595 1609
1610
1596 return 0; 1611 return 0;
1597detach: 1612detach:
1598 ath_detach(sc); 1613 ath_detach(sc);
@@ -1818,6 +1833,37 @@ int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
1818 return qnum; 1833 return qnum;
1819} 1834}
1820 1835
1836/* XXX: Remove me once we don't depend on ath9k_channel for all
1837 * this redundant data */
1838static void ath9k_update_ichannel(struct ath_softc *sc,
1839 struct ath9k_channel *ichan)
1840{
1841 struct ieee80211_hw *hw = sc->hw;
1842 struct ieee80211_channel *chan = hw->conf.channel;
1843 struct ieee80211_conf *conf = &hw->conf;
1844
1845 ichan->channel = chan->center_freq;
1846 ichan->chan = chan;
1847
1848 if (chan->band == IEEE80211_BAND_2GHZ) {
1849 ichan->chanmode = CHANNEL_G;
1850 ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM;
1851 } else {
1852 ichan->chanmode = CHANNEL_A;
1853 ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
1854 }
1855
1856 sc->tx_chan_width = ATH9K_HT_MACMODE_20;
1857
1858 if (conf_is_ht(conf)) {
1859 if (conf_is_ht40(conf))
1860 sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
1861
1862 ichan->chanmode = ath_get_extchanmode(sc, chan,
1863 conf->channel_type);
1864 }
1865}
1866
1821/**********************/ 1867/**********************/
1822/* mac80211 callbacks */ 1868/* mac80211 callbacks */
1823/**********************/ 1869/**********************/
@@ -1834,16 +1880,10 @@ static int ath9k_start(struct ieee80211_hw *hw)
1834 1880
1835 /* setup initial channel */ 1881 /* setup initial channel */
1836 1882
1837 pos = ath_get_channel(sc, curchan); 1883 pos = curchan->hw_value;
1838 if (pos == -1) {
1839 DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq);
1840 return -EINVAL;
1841 }
1842 1884
1843 sc->tx_chan_width = ATH9K_HT_MACMODE_20;
1844 sc->sc_ah->ah_channels[pos].chanmode =
1845 (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
1846 init_channel = &sc->sc_ah->ah_channels[pos]; 1885 init_channel = &sc->sc_ah->ah_channels[pos];
1886 ath9k_update_ichannel(sc, init_channel);
1847 1887
1848 /* Reset SERDES registers */ 1888 /* Reset SERDES registers */
1849 ath9k_hw_configpcipowersave(sc->sc_ah, 0); 1889 ath9k_hw_configpcipowersave(sc->sc_ah, 0);
@@ -2127,32 +2167,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
2127 2167
2128 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 2168 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2129 struct ieee80211_channel *curchan = hw->conf.channel; 2169 struct ieee80211_channel *curchan = hw->conf.channel;
2130 int pos; 2170 int pos = curchan->hw_value;
2131 2171
2132 DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", 2172 DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
2133 curchan->center_freq); 2173 curchan->center_freq);
2134 2174
2135 pos = ath_get_channel(sc, curchan); 2175 /* XXX: remove me eventualy */
2136 if (pos == -1) { 2176 ath9k_update_ichannel(sc, &sc->sc_ah->ah_channels[pos]);
2137 DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n",
2138 curchan->center_freq);
2139 mutex_unlock(&sc->mutex);
2140 return -EINVAL;
2141 }
2142
2143 sc->tx_chan_width = ATH9K_HT_MACMODE_20;
2144 sc->sc_ah->ah_channels[pos].chanmode =
2145 (curchan->band == IEEE80211_BAND_2GHZ) ?
2146 CHANNEL_G : CHANNEL_A;
2147
2148 if (conf_is_ht(conf)) {
2149 if (conf_is_ht40(conf))
2150 sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
2151
2152 sc->sc_ah->ah_channels[pos].chanmode =
2153 ath_get_extchanmode(sc, curchan,
2154 conf->channel_type);
2155 }
2156 2177
2157 ath_update_chainmask(sc, conf_is_ht(conf)); 2178 ath_update_chainmask(sc, conf_is_ht(conf));
2158 2179