aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/pcu.c
diff options
context:
space:
mode:
authorNick Kossifidis <mickflemm@gmail.com>2010-11-23 13:36:45 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-11-30 13:52:29 -0500
commit9320b5c4a7260d9593102f378201d17e3f030739 (patch)
treed4a85a6286b47f86a66a82ad3e756f5117af2b39 /drivers/net/wireless/ath/ath5k/pcu.c
parentea066d5a91f2610116dcd27054f749e4f07799d8 (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.c438
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 */
46int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) 43static 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 */
61static 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 */
131static 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 */
153static 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 */
208unsigned 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 */
218unsigned 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 */
229void 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 */
254static 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 */
272static 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 */
379void 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 */
393void 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 */
705void 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 */
717void 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 */
730int 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
797void 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}