diff options
author | Nick Kossifidis <mickflemm@gmail.com> | 2010-11-23 13:36:45 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-11-30 13:52:29 -0500 |
commit | 9320b5c4a7260d9593102f378201d17e3f030739 (patch) | |
tree | d4a85a6286b47f86a66a82ad3e756f5117af2b39 /drivers/net/wireless/ath/ath5k/pcu.c | |
parent | ea066d5a91f2610116dcd27054f749e4f07799d8 (diff) |
ath5k: Reset cleanup and generic cleanup
* No functional changes
* Clean up reset:
Introduce init functions for each unit and call them instead
of having everything inside ath5k_hw_reset (it's just c/p for
now so nothing changes except calling order -I tested it with
various cards and it's ok-)
* Further cleanups:
ofdm_timings belongs to phy.c
rate_duration belongs to pcu.c
clock functions are general and belong to reset.c (more to follow)
* Reorder functions for better organization:
We start with helpers and other functions follow in categories,
init functions are last
Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/pcu.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/pcu.c | 438 |
1 files changed, 261 insertions, 177 deletions
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 074b4c644399..2c2ea1539849 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c | |||
@@ -32,86 +32,47 @@ | |||
32 | #include "base.h" | 32 | #include "base.h" |
33 | 33 | ||
34 | /*******************\ | 34 | /*******************\ |
35 | * Generic functions * | 35 | * Helper functions * |
36 | \*******************/ | 36 | \*******************/ |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * ath5k_hw_set_opmode - Set PCU operating mode | 39 | * ath5k_hw_get_default_slottime - Get the default slot time for current mode |
40 | * | 40 | * |
41 | * @ah: The &struct ath5k_hw | 41 | * @ah: The &struct ath5k_hw |
42 | * @op_mode: &enum nl80211_iftype operating mode | ||
43 | * | ||
44 | * Initialize PCU for the various operating modes (AP/STA etc) | ||
45 | */ | 42 | */ |
46 | int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) | 43 | static unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) |
47 | { | 44 | { |
48 | struct ath_common *common = ath5k_hw_common(ah); | 45 | struct ieee80211_channel *channel = ah->ah_current_channel; |
49 | u32 pcu_reg, beacon_reg, low_id, high_id; | ||
50 | |||
51 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode); | ||
52 | |||
53 | /* Preserve rest settings */ | ||
54 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; | ||
55 | pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP | ||
56 | | AR5K_STA_ID1_KEYSRCH_MODE | ||
57 | | (ah->ah_version == AR5K_AR5210 ? | ||
58 | (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); | ||
59 | |||
60 | beacon_reg = 0; | ||
61 | 46 | ||
62 | switch (op_mode) { | 47 | if (channel->hw_value & CHANNEL_TURBO) |
63 | case NL80211_IFTYPE_ADHOC: | 48 | return 6; /* both turbo modes */ |
64 | pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; | ||
65 | beacon_reg |= AR5K_BCR_ADHOC; | ||
66 | if (ah->ah_version == AR5K_AR5210) | ||
67 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | ||
68 | else | ||
69 | AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | ||
70 | break; | ||
71 | 49 | ||
72 | case NL80211_IFTYPE_AP: | 50 | if (channel->hw_value & CHANNEL_CCK) |
73 | case NL80211_IFTYPE_MESH_POINT: | 51 | return 20; /* 802.11b */ |
74 | pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; | ||
75 | beacon_reg |= AR5K_BCR_AP; | ||
76 | if (ah->ah_version == AR5K_AR5210) | ||
77 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | ||
78 | else | ||
79 | AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | ||
80 | break; | ||
81 | 52 | ||
82 | case NL80211_IFTYPE_STATION: | 53 | return 9; /* 802.11 a/g */ |
83 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | 54 | } |
84 | | (ah->ah_version == AR5K_AR5210 ? | ||
85 | AR5K_STA_ID1_PWR_SV : 0); | ||
86 | case NL80211_IFTYPE_MONITOR: | ||
87 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | ||
88 | | (ah->ah_version == AR5K_AR5210 ? | ||
89 | AR5K_STA_ID1_NO_PSPOLL : 0); | ||
90 | break; | ||
91 | 55 | ||
92 | default: | 56 | /** |
93 | return -EINVAL; | 57 | * ath5k_hw_get_default_sifs - Get the default SIFS for current mode |
94 | } | 58 | * |
59 | * @ah: The &struct ath5k_hw | ||
60 | */ | ||
61 | static unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) | ||
62 | { | ||
63 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
95 | 64 | ||
96 | /* | 65 | if (channel->hw_value & CHANNEL_TURBO) |
97 | * Set PCU registers | 66 | return 8; /* both turbo modes */ |
98 | */ | ||
99 | low_id = get_unaligned_le32(common->macaddr); | ||
100 | high_id = get_unaligned_le16(common->macaddr + 4); | ||
101 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); | ||
102 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); | ||
103 | 67 | ||
104 | /* | 68 | if (channel->hw_value & CHANNEL_5GHZ) |
105 | * Set Beacon Control Register on 5210 | 69 | return 16; /* 802.11a */ |
106 | */ | ||
107 | if (ah->ah_version == AR5K_AR5210) | ||
108 | ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); | ||
109 | 70 | ||
110 | return 0; | 71 | return 10; /* 802.11 b/g */ |
111 | } | 72 | } |
112 | 73 | ||
113 | /** | 74 | /** |
114 | * ath5k_hw_update - Update MIB counters (mac layer statistics) | 75 | * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics) |
115 | * | 76 | * |
116 | * @ah: The &struct ath5k_hw | 77 | * @ah: The &struct ath5k_hw |
117 | * | 78 | * |
@@ -163,6 +124,82 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) | |||
163 | * ACK/CTS Timeouts * | 124 | * ACK/CTS Timeouts * |
164 | \******************/ | 125 | \******************/ |
165 | 126 | ||
127 | /* | ||
128 | * index into rates for control rates, we can set it up like this because | ||
129 | * this is only used for AR5212 and we know it supports G mode | ||
130 | */ | ||
131 | static const unsigned int control_rates[] = | ||
132 | { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 }; | ||
133 | |||
134 | /** | ||
135 | * ath5k_hw_write_rate_duration - fill rate code to duration table | ||
136 | * | ||
137 | * @ah: the &struct ath5k_hw | ||
138 | * @mode: one of enum ath5k_driver_mode | ||
139 | * | ||
140 | * Write the rate code to duration table upon hw reset. This is a helper for | ||
141 | * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on | ||
142 | * the hardware, based on current mode, for each rate. The rates which are | ||
143 | * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have | ||
144 | * different rate code so we write their value twice (one for long preamble | ||
145 | * and one for short). | ||
146 | * | ||
147 | * Note: Band doesn't matter here, if we set the values for OFDM it works | ||
148 | * on both a and g modes. So all we have to do is set values for all g rates | ||
149 | * that include all OFDM and CCK rates. If we operate in turbo or xr/half/ | ||
150 | * quarter rate mode, we need to use another set of bitrates (that's why we | ||
151 | * need the mode parameter) but we don't handle these proprietary modes yet. | ||
152 | */ | ||
153 | static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, | ||
154 | unsigned int mode) | ||
155 | { | ||
156 | struct ath5k_softc *sc = ah->ah_sc; | ||
157 | struct ieee80211_rate *rate; | ||
158 | unsigned int i; | ||
159 | |||
160 | /* Write rate duration table */ | ||
161 | for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) { | ||
162 | u32 reg; | ||
163 | u16 tx_time; | ||
164 | |||
165 | rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]]; | ||
166 | |||
167 | /* Set ACK timeout */ | ||
168 | reg = AR5K_RATE_DUR(rate->hw_value); | ||
169 | |||
170 | /* An ACK frame consists of 10 bytes. If you add the FCS, | ||
171 | * which ieee80211_generic_frame_duration() adds, | ||
172 | * its 14 bytes. Note we use the control rate and not the | ||
173 | * actual rate for this rate. See mac80211 tx.c | ||
174 | * ieee80211_duration() for a brief description of | ||
175 | * what rate we should choose to TX ACKs. */ | ||
176 | tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, | ||
177 | NULL, 10, rate)); | ||
178 | |||
179 | ath5k_hw_reg_write(ah, tx_time, reg); | ||
180 | |||
181 | if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) | ||
182 | continue; | ||
183 | |||
184 | /* | ||
185 | * We're not distinguishing short preamble here, | ||
186 | * This is true, all we'll get is a longer value here | ||
187 | * which is not necessarilly bad. We could use | ||
188 | * export ieee80211_frame_duration() but that needs to be | ||
189 | * fixed first to be properly used by mac802111 drivers: | ||
190 | * | ||
191 | * - remove erp stuff and let the routine figure ofdm | ||
192 | * erp rates | ||
193 | * - remove passing argument ieee80211_local as | ||
194 | * drivers don't have access to it | ||
195 | * - move drivers using ieee80211_generic_frame_duration() | ||
196 | * to this | ||
197 | */ | ||
198 | ath5k_hw_reg_write(ah, tx_time, | ||
199 | reg + (AR5K_SET_SHORT_PREAMBLE << 2)); | ||
200 | } | ||
201 | } | ||
202 | |||
166 | /** | 203 | /** |
167 | * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU | 204 | * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU |
168 | * | 205 | * |
@@ -199,88 +236,10 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) | |||
199 | return 0; | 236 | return 0; |
200 | } | 237 | } |
201 | 238 | ||
202 | /** | ||
203 | * ath5k_hw_htoclock - Translate usec to hw clock units | ||
204 | * | ||
205 | * @ah: The &struct ath5k_hw | ||
206 | * @usec: value in microseconds | ||
207 | */ | ||
208 | unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) | ||
209 | { | ||
210 | struct ath_common *common = ath5k_hw_common(ah); | ||
211 | return usec * common->clockrate; | ||
212 | } | ||
213 | |||
214 | /** | ||
215 | * ath5k_hw_clocktoh - Translate hw clock units to usec | ||
216 | * @clock: value in hw clock units | ||
217 | */ | ||
218 | unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) | ||
219 | { | ||
220 | struct ath_common *common = ath5k_hw_common(ah); | ||
221 | return clock / common->clockrate; | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * ath5k_hw_set_clockrate - Set common->clockrate for the current channel | ||
226 | * | ||
227 | * @ah: The &struct ath5k_hw | ||
228 | */ | ||
229 | void ath5k_hw_set_clockrate(struct ath5k_hw *ah) | ||
230 | { | ||
231 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
232 | struct ath_common *common = ath5k_hw_common(ah); | ||
233 | int clock; | ||
234 | |||
235 | if (channel->hw_value & CHANNEL_5GHZ) | ||
236 | clock = 40; /* 802.11a */ | ||
237 | else if (channel->hw_value & CHANNEL_CCK) | ||
238 | clock = 22; /* 802.11b */ | ||
239 | else | ||
240 | clock = 44; /* 802.11g */ | ||
241 | |||
242 | /* Clock rate in turbo modes is twice the normal rate */ | ||
243 | if (channel->hw_value & CHANNEL_TURBO) | ||
244 | clock *= 2; | ||
245 | |||
246 | common->clockrate = clock; | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * ath5k_hw_get_default_slottime - Get the default slot time for current mode | ||
251 | * | ||
252 | * @ah: The &struct ath5k_hw | ||
253 | */ | ||
254 | static unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) | ||
255 | { | ||
256 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
257 | |||
258 | if (channel->hw_value & CHANNEL_TURBO) | ||
259 | return 6; /* both turbo modes */ | ||
260 | |||
261 | if (channel->hw_value & CHANNEL_CCK) | ||
262 | return 20; /* 802.11b */ | ||
263 | |||
264 | return 9; /* 802.11 a/g */ | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * ath5k_hw_get_default_sifs - Get the default SIFS for current mode | ||
269 | * | ||
270 | * @ah: The &struct ath5k_hw | ||
271 | */ | ||
272 | static unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) | ||
273 | { | ||
274 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
275 | |||
276 | if (channel->hw_value & CHANNEL_TURBO) | ||
277 | return 8; /* both turbo modes */ | ||
278 | |||
279 | if (channel->hw_value & CHANNEL_5GHZ) | ||
280 | return 16; /* 802.11a */ | ||
281 | 239 | ||
282 | return 10; /* 802.11 b/g */ | 240 | /*******************\ |
283 | } | 241 | * RX filter Control * |
242 | \*******************/ | ||
284 | 243 | ||
285 | /** | 244 | /** |
286 | * ath5k_hw_set_lladdr - Set station id | 245 | * ath5k_hw_set_lladdr - Set station id |
@@ -362,39 +321,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) | |||
362 | ath_hw_setbssidmask(common); | 321 | ath_hw_setbssidmask(common); |
363 | } | 322 | } |
364 | 323 | ||
365 | /************\ | ||
366 | * RX Control * | ||
367 | \************/ | ||
368 | |||
369 | /** | ||
370 | * ath5k_hw_start_rx_pcu - Start RX engine | ||
371 | * | ||
372 | * @ah: The &struct ath5k_hw | ||
373 | * | ||
374 | * Starts RX engine on PCU so that hw can process RXed frames | ||
375 | * (ACK etc). | ||
376 | * | ||
377 | * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma | ||
378 | */ | ||
379 | void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) | ||
380 | { | ||
381 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * at5k_hw_stop_rx_pcu - Stop RX engine | ||
386 | * | ||
387 | * @ah: The &struct ath5k_hw | ||
388 | * | ||
389 | * Stops RX engine on PCU | ||
390 | * | ||
391 | * TODO: Detach ANI here | ||
392 | */ | ||
393 | void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) | ||
394 | { | ||
395 | AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | ||
396 | } | ||
397 | |||
398 | /* | 324 | /* |
399 | * Set multicast filter | 325 | * Set multicast filter |
400 | */ | 326 | */ |
@@ -761,3 +687,161 @@ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) | |||
761 | 687 | ||
762 | ah->ah_coverage_class = coverage_class; | 688 | ah->ah_coverage_class = coverage_class; |
763 | } | 689 | } |
690 | |||
691 | /***************************\ | ||
692 | * Init/Start/Stop functions * | ||
693 | \***************************/ | ||
694 | |||
695 | /** | ||
696 | * ath5k_hw_start_rx_pcu - Start RX engine | ||
697 | * | ||
698 | * @ah: The &struct ath5k_hw | ||
699 | * | ||
700 | * Starts RX engine on PCU so that hw can process RXed frames | ||
701 | * (ACK etc). | ||
702 | * | ||
703 | * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma | ||
704 | */ | ||
705 | void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) | ||
706 | { | ||
707 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | ||
708 | } | ||
709 | |||
710 | /** | ||
711 | * at5k_hw_stop_rx_pcu - Stop RX engine | ||
712 | * | ||
713 | * @ah: The &struct ath5k_hw | ||
714 | * | ||
715 | * Stops RX engine on PCU | ||
716 | */ | ||
717 | void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) | ||
718 | { | ||
719 | AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); | ||
720 | } | ||
721 | |||
722 | /** | ||
723 | * ath5k_hw_set_opmode - Set PCU operating mode | ||
724 | * | ||
725 | * @ah: The &struct ath5k_hw | ||
726 | * @op_mode: &enum nl80211_iftype operating mode | ||
727 | * | ||
728 | * Configure PCU for the various operating modes (AP/STA etc) | ||
729 | */ | ||
730 | int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) | ||
731 | { | ||
732 | struct ath_common *common = ath5k_hw_common(ah); | ||
733 | u32 pcu_reg, beacon_reg, low_id, high_id; | ||
734 | |||
735 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode); | ||
736 | |||
737 | /* Preserve rest settings */ | ||
738 | pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; | ||
739 | pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP | ||
740 | | AR5K_STA_ID1_KEYSRCH_MODE | ||
741 | | (ah->ah_version == AR5K_AR5210 ? | ||
742 | (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); | ||
743 | |||
744 | beacon_reg = 0; | ||
745 | |||
746 | switch (op_mode) { | ||
747 | case NL80211_IFTYPE_ADHOC: | ||
748 | pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; | ||
749 | beacon_reg |= AR5K_BCR_ADHOC; | ||
750 | if (ah->ah_version == AR5K_AR5210) | ||
751 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | ||
752 | else | ||
753 | AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | ||
754 | break; | ||
755 | |||
756 | case NL80211_IFTYPE_AP: | ||
757 | case NL80211_IFTYPE_MESH_POINT: | ||
758 | pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; | ||
759 | beacon_reg |= AR5K_BCR_AP; | ||
760 | if (ah->ah_version == AR5K_AR5210) | ||
761 | pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; | ||
762 | else | ||
763 | AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS); | ||
764 | break; | ||
765 | |||
766 | case NL80211_IFTYPE_STATION: | ||
767 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | ||
768 | | (ah->ah_version == AR5K_AR5210 ? | ||
769 | AR5K_STA_ID1_PWR_SV : 0); | ||
770 | case NL80211_IFTYPE_MONITOR: | ||
771 | pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | ||
772 | | (ah->ah_version == AR5K_AR5210 ? | ||
773 | AR5K_STA_ID1_NO_PSPOLL : 0); | ||
774 | break; | ||
775 | |||
776 | default: | ||
777 | return -EINVAL; | ||
778 | } | ||
779 | |||
780 | /* | ||
781 | * Set PCU registers | ||
782 | */ | ||
783 | low_id = get_unaligned_le32(common->macaddr); | ||
784 | high_id = get_unaligned_le16(common->macaddr + 4); | ||
785 | ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); | ||
786 | ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); | ||
787 | |||
788 | /* | ||
789 | * Set Beacon Control Register on 5210 | ||
790 | */ | ||
791 | if (ah->ah_version == AR5K_AR5210) | ||
792 | ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | ||
798 | u8 mode) | ||
799 | { | ||
800 | /* Set bssid and bssid mask */ | ||
801 | ath5k_hw_set_bssid(ah); | ||
802 | |||
803 | /* Set PCU config */ | ||
804 | ath5k_hw_set_opmode(ah, op_mode); | ||
805 | |||
806 | /* Write rate duration table only on AR5212 and if | ||
807 | * virtual interface has already been brought up | ||
808 | * XXX: rethink this after new mode changes to | ||
809 | * mac80211 are integrated */ | ||
810 | if (ah->ah_version == AR5K_AR5212 && | ||
811 | ah->ah_sc->nvifs) | ||
812 | ath5k_hw_write_rate_duration(ah, mode); | ||
813 | |||
814 | /* Set RSSI/BRSSI thresholds | ||
815 | * | ||
816 | * Note: If we decide to set this value | ||
817 | * dynamicaly, have in mind that when AR5K_RSSI_THR | ||
818 | * register is read it might return 0x40 if we haven't | ||
819 | * wrote anything to it plus BMISS RSSI threshold is zeroed. | ||
820 | * So doing a save/restore procedure here isn't the right | ||
821 | * choice. Instead store it on ath5k_hw */ | ||
822 | ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES | | ||
823 | AR5K_TUNE_BMISS_THRES << | ||
824 | AR5K_RSSI_THR_BMISS_S), | ||
825 | AR5K_RSSI_THR); | ||
826 | |||
827 | /* MIC QoS support */ | ||
828 | if (ah->ah_mac_srev >= AR5K_SREV_AR2413) { | ||
829 | ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL); | ||
830 | ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL); | ||
831 | } | ||
832 | |||
833 | /* QoS NOACK Policy */ | ||
834 | if (ah->ah_version == AR5K_AR5212) { | ||
835 | ath5k_hw_reg_write(ah, | ||
836 | AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) | | ||
837 | AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET) | | ||
838 | AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET), | ||
839 | AR5K_QOS_NOACK); | ||
840 | } | ||
841 | |||
842 | /* Restore slot time and ACK timeouts */ | ||
843 | if (ah->ah_coverage_class > 0) | ||
844 | ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class); | ||
845 | |||
846 | return; | ||
847 | } | ||