diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/qcu.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/qcu.c | 777 |
1 files changed, 449 insertions, 328 deletions
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 4186ff4c6e9c..b18c5021aac3 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c | |||
@@ -25,6 +25,68 @@ Queue Control Unit, DFS Control Unit Functions | |||
25 | #include "debug.h" | 25 | #include "debug.h" |
26 | #include "base.h" | 26 | #include "base.h" |
27 | 27 | ||
28 | |||
29 | /******************\ | ||
30 | * Helper functions * | ||
31 | \******************/ | ||
32 | |||
33 | /* | ||
34 | * Get number of pending frames | ||
35 | * for a specific queue [5211+] | ||
36 | */ | ||
37 | u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) | ||
38 | { | ||
39 | u32 pending; | ||
40 | AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); | ||
41 | |||
42 | /* Return if queue is declared inactive */ | ||
43 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) | ||
44 | return false; | ||
45 | |||
46 | /* XXX: How about AR5K_CFG_TXCNT ? */ | ||
47 | if (ah->ah_version == AR5K_AR5210) | ||
48 | return false; | ||
49 | |||
50 | pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue)); | ||
51 | pending &= AR5K_QCU_STS_FRMPENDCNT; | ||
52 | |||
53 | /* It's possible to have no frames pending even if TXE | ||
54 | * is set. To indicate that q has not stopped return | ||
55 | * true */ | ||
56 | if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) | ||
57 | return true; | ||
58 | |||
59 | return pending; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Set a transmit queue inactive | ||
64 | */ | ||
65 | void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) | ||
66 | { | ||
67 | if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) | ||
68 | return; | ||
69 | |||
70 | /* This queue will be skipped in further operations */ | ||
71 | ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE; | ||
72 | /*For SIMR setup*/ | ||
73 | AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Make sure cw is a power of 2 minus 1 and smaller than 1024 | ||
78 | */ | ||
79 | static u16 ath5k_cw_validate(u16 cw_req) | ||
80 | { | ||
81 | u32 cw = 1; | ||
82 | cw_req = min(cw_req, (u16)1023); | ||
83 | |||
84 | while (cw < cw_req) | ||
85 | cw = (cw << 1) | 1; | ||
86 | |||
87 | return cw; | ||
88 | } | ||
89 | |||
28 | /* | 90 | /* |
29 | * Get properties for a transmit queue | 91 | * Get properties for a transmit queue |
30 | */ | 92 | */ |
@@ -39,21 +101,41 @@ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, | |||
39 | * Set properties for a transmit queue | 101 | * Set properties for a transmit queue |
40 | */ | 102 | */ |
41 | int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, | 103 | int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, |
42 | const struct ath5k_txq_info *queue_info) | 104 | const struct ath5k_txq_info *qinfo) |
43 | { | 105 | { |
106 | struct ath5k_txq_info *qi; | ||
107 | |||
44 | AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); | 108 | AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); |
45 | 109 | ||
46 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) | 110 | qi = &ah->ah_txq[queue]; |
111 | |||
112 | if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE) | ||
47 | return -EIO; | 113 | return -EIO; |
48 | 114 | ||
49 | memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info)); | 115 | /* copy and validate values */ |
116 | qi->tqi_type = qinfo->tqi_type; | ||
117 | qi->tqi_subtype = qinfo->tqi_subtype; | ||
118 | qi->tqi_flags = qinfo->tqi_flags; | ||
119 | /* | ||
120 | * According to the docs: Although the AIFS field is 8 bit wide, | ||
121 | * the maximum supported value is 0xFC. Setting it higher than that | ||
122 | * will cause the DCU to hang. | ||
123 | */ | ||
124 | qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC); | ||
125 | qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min); | ||
126 | qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max); | ||
127 | qi->tqi_cbr_period = qinfo->tqi_cbr_period; | ||
128 | qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit; | ||
129 | qi->tqi_burst_time = qinfo->tqi_burst_time; | ||
130 | qi->tqi_ready_time = qinfo->tqi_ready_time; | ||
50 | 131 | ||
51 | /*XXX: Is this supported on 5210 ?*/ | 132 | /*XXX: Is this supported on 5210 ?*/ |
52 | if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA && | 133 | /*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/ |
53 | ((queue_info->tqi_subtype == AR5K_WME_AC_VI) || | 134 | if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA && |
54 | (queue_info->tqi_subtype == AR5K_WME_AC_VO))) || | 135 | ((qinfo->tqi_subtype == AR5K_WME_AC_VI) || |
55 | queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD) | 136 | (qinfo->tqi_subtype == AR5K_WME_AC_VO))) || |
56 | ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; | 137 | qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD) |
138 | qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; | ||
57 | 139 | ||
58 | return 0; | 140 | return 0; |
59 | } | 141 | } |
@@ -70,8 +152,8 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, | |||
70 | /* | 152 | /* |
71 | * Get queue by type | 153 | * Get queue by type |
72 | */ | 154 | */ |
73 | /*5210 only has 2 queues*/ | 155 | /* 5210 only has 2 queues */ |
74 | if (ah->ah_version == AR5K_AR5210) { | 156 | if (ah->ah_capabilities.cap_queues.q_tx_num == 2) { |
75 | switch (queue_type) { | 157 | switch (queue_type) { |
76 | case AR5K_TX_QUEUE_DATA: | 158 | case AR5K_TX_QUEUE_DATA: |
77 | queue = AR5K_TX_QUEUE_ID_NOQCU_DATA; | 159 | queue = AR5K_TX_QUEUE_ID_NOQCU_DATA; |
@@ -138,392 +220,431 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, | |||
138 | return queue; | 220 | return queue; |
139 | } | 221 | } |
140 | 222 | ||
141 | /* | ||
142 | * Get number of pending frames | ||
143 | * for a specific queue [5211+] | ||
144 | */ | ||
145 | u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) | ||
146 | { | ||
147 | u32 pending; | ||
148 | AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); | ||
149 | |||
150 | /* Return if queue is declared inactive */ | ||
151 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) | ||
152 | return false; | ||
153 | |||
154 | /* XXX: How about AR5K_CFG_TXCNT ? */ | ||
155 | if (ah->ah_version == AR5K_AR5210) | ||
156 | return false; | ||
157 | |||
158 | pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue)); | ||
159 | pending &= AR5K_QCU_STS_FRMPENDCNT; | ||
160 | |||
161 | /* It's possible to have no frames pending even if TXE | ||
162 | * is set. To indicate that q has not stopped return | ||
163 | * true */ | ||
164 | if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) | ||
165 | return true; | ||
166 | 223 | ||
167 | return pending; | 224 | /*******************************\ |
168 | } | 225 | * Single QCU/DCU initialization * |
226 | \*******************************/ | ||
169 | 227 | ||
170 | /* | 228 | /* |
171 | * Set a transmit queue inactive | 229 | * Set tx retry limits on DCU |
172 | */ | 230 | */ |
173 | void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) | 231 | void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah, |
232 | unsigned int queue) | ||
174 | { | 233 | { |
175 | if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) | 234 | /* Single data queue on AR5210 */ |
176 | return; | 235 | if (ah->ah_version == AR5K_AR5210) { |
236 | struct ath5k_txq_info *tq = &ah->ah_txq[queue]; | ||
177 | 237 | ||
178 | /* This queue will be skipped in further operations */ | 238 | if (queue > 0) |
179 | ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE; | 239 | return; |
180 | /*For SIMR setup*/ | 240 | |
181 | AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); | 241 | ath5k_hw_reg_write(ah, |
242 | (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) | ||
243 | | AR5K_REG_SM(ah->ah_retry_long, | ||
244 | AR5K_NODCU_RETRY_LMT_SLG_RETRY) | ||
245 | | AR5K_REG_SM(ah->ah_retry_short, | ||
246 | AR5K_NODCU_RETRY_LMT_SSH_RETRY) | ||
247 | | AR5K_REG_SM(ah->ah_retry_long, | ||
248 | AR5K_NODCU_RETRY_LMT_LG_RETRY) | ||
249 | | AR5K_REG_SM(ah->ah_retry_short, | ||
250 | AR5K_NODCU_RETRY_LMT_SH_RETRY), | ||
251 | AR5K_NODCU_RETRY_LMT); | ||
252 | /* DCU on AR5211+ */ | ||
253 | } else { | ||
254 | ath5k_hw_reg_write(ah, | ||
255 | AR5K_REG_SM(ah->ah_retry_long, | ||
256 | AR5K_DCU_RETRY_LMT_RTS) | ||
257 | | AR5K_REG_SM(ah->ah_retry_long, | ||
258 | AR5K_DCU_RETRY_LMT_STA_RTS) | ||
259 | | AR5K_REG_SM(max(ah->ah_retry_long, ah->ah_retry_short), | ||
260 | AR5K_DCU_RETRY_LMT_STA_DATA), | ||
261 | AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); | ||
262 | } | ||
182 | } | 263 | } |
183 | 264 | ||
184 | /* | 265 | /** |
185 | * Set DFS properties for a transmit queue on DCU | 266 | * ath5k_hw_reset_tx_queue - Initialize a single hw queue |
267 | * | ||
268 | * @ah The &struct ath5k_hw | ||
269 | * @queue The hw queue number | ||
270 | * | ||
271 | * Set DFS properties for the given transmit queue on DCU | ||
272 | * and configures all queue-specific parameters. | ||
186 | */ | 273 | */ |
187 | int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) | 274 | int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) |
188 | { | 275 | { |
189 | u32 cw_min, cw_max, retry_lg, retry_sh; | ||
190 | struct ath5k_txq_info *tq = &ah->ah_txq[queue]; | 276 | struct ath5k_txq_info *tq = &ah->ah_txq[queue]; |
191 | 277 | ||
192 | AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); | 278 | AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); |
193 | 279 | ||
194 | tq = &ah->ah_txq[queue]; | 280 | tq = &ah->ah_txq[queue]; |
195 | 281 | ||
196 | if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE) | 282 | /* Skip if queue inactive or if we are on AR5210 |
283 | * that doesn't have QCU/DCU */ | ||
284 | if ((ah->ah_version == AR5K_AR5210) || | ||
285 | (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)) | ||
197 | return 0; | 286 | return 0; |
198 | 287 | ||
199 | if (ah->ah_version == AR5K_AR5210) { | ||
200 | /* Only handle data queues, others will be ignored */ | ||
201 | if (tq->tqi_type != AR5K_TX_QUEUE_DATA) | ||
202 | return 0; | ||
203 | |||
204 | /* Set Slot time */ | ||
205 | ath5k_hw_reg_write(ah, ah->ah_turbo ? | ||
206 | AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME, | ||
207 | AR5K_SLOT_TIME); | ||
208 | /* Set ACK_CTS timeout */ | ||
209 | ath5k_hw_reg_write(ah, ah->ah_turbo ? | ||
210 | AR5K_INIT_ACK_CTS_TIMEOUT_TURBO : | ||
211 | AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME); | ||
212 | /* Set Transmit Latency */ | ||
213 | ath5k_hw_reg_write(ah, ah->ah_turbo ? | ||
214 | AR5K_INIT_TRANSMIT_LATENCY_TURBO : | ||
215 | AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210); | ||
216 | |||
217 | /* Set IFS0 */ | ||
218 | if (ah->ah_turbo) { | ||
219 | ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO + | ||
220 | (ah->ah_aifs + tq->tqi_aifs) * | ||
221 | AR5K_INIT_SLOT_TIME_TURBO) << | ||
222 | AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO, | ||
223 | AR5K_IFS0); | ||
224 | } else { | ||
225 | ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS + | ||
226 | (ah->ah_aifs + tq->tqi_aifs) * | ||
227 | AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) | | ||
228 | AR5K_INIT_SIFS, AR5K_IFS0); | ||
229 | } | ||
230 | |||
231 | /* Set IFS1 */ | ||
232 | ath5k_hw_reg_write(ah, ah->ah_turbo ? | ||
233 | AR5K_INIT_PROTO_TIME_CNTRL_TURBO : | ||
234 | AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1); | ||
235 | /* Set AR5K_PHY_SETTLING */ | ||
236 | ath5k_hw_reg_write(ah, ah->ah_turbo ? | ||
237 | (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) | ||
238 | | 0x38 : | ||
239 | (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F) | ||
240 | | 0x1C, | ||
241 | AR5K_PHY_SETTLING); | ||
242 | /* Set Frame Control Register */ | ||
243 | ath5k_hw_reg_write(ah, ah->ah_turbo ? | ||
244 | (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE | | ||
245 | AR5K_PHY_TURBO_SHORT | 0x2020) : | ||
246 | (AR5K_PHY_FRAME_CTL_INI | 0x1020), | ||
247 | AR5K_PHY_FRAME_CTL_5210); | ||
248 | } | ||
249 | |||
250 | /* | 288 | /* |
251 | * Calculate cwmin/max by channel mode | 289 | * Set contention window (cw_min/cw_max) |
290 | * and arbitrated interframe space (aifs)... | ||
252 | */ | 291 | */ |
253 | cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN; | 292 | ath5k_hw_reg_write(ah, |
254 | cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX; | 293 | AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | |
255 | ah->ah_aifs = AR5K_TUNE_AIFS; | 294 | AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | |
256 | /*XR is only supported on 5212*/ | 295 | AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS), |
257 | if (IS_CHAN_XR(ah->ah_current_channel) && | 296 | AR5K_QUEUE_DFS_LOCAL_IFS(queue)); |
258 | ah->ah_version == AR5K_AR5212) { | ||
259 | cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR; | ||
260 | cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR; | ||
261 | ah->ah_aifs = AR5K_TUNE_AIFS_XR; | ||
262 | /*B mode is not supported on 5210*/ | ||
263 | } else if (IS_CHAN_B(ah->ah_current_channel) && | ||
264 | ah->ah_version != AR5K_AR5210) { | ||
265 | cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B; | ||
266 | cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B; | ||
267 | ah->ah_aifs = AR5K_TUNE_AIFS_11B; | ||
268 | } | ||
269 | 297 | ||
270 | cw_min = 1; | 298 | /* |
271 | while (cw_min < ah->ah_cw_min) | 299 | * Set tx retry limits for this queue |
272 | cw_min = (cw_min << 1) | 1; | 300 | */ |
301 | ath5k_hw_set_tx_retry_limits(ah, queue); | ||
273 | 302 | ||
274 | cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) : | ||
275 | ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); | ||
276 | cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) : | ||
277 | ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1); | ||
278 | 303 | ||
279 | /* | 304 | /* |
280 | * Calculate and set retry limits | 305 | * Set misc registers |
281 | */ | 306 | */ |
282 | if (ah->ah_software_retry) { | ||
283 | /* XXX Need to test this */ | ||
284 | retry_lg = ah->ah_limit_tx_retries; | ||
285 | retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? | ||
286 | AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg; | ||
287 | } else { | ||
288 | retry_lg = AR5K_INIT_LG_RETRY; | ||
289 | retry_sh = AR5K_INIT_SH_RETRY; | ||
290 | } | ||
291 | 307 | ||
292 | /*No QCU/DCU [5210]*/ | 308 | /* Enable DCU to wait for next fragment from QCU */ |
293 | if (ah->ah_version == AR5K_AR5210) { | 309 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), |
294 | ath5k_hw_reg_write(ah, | 310 | AR5K_DCU_MISC_FRAG_WAIT); |
295 | (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) | ||
296 | | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, | ||
297 | AR5K_NODCU_RETRY_LMT_SLG_RETRY) | ||
298 | | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, | ||
299 | AR5K_NODCU_RETRY_LMT_SSH_RETRY) | ||
300 | | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY) | ||
301 | | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY), | ||
302 | AR5K_NODCU_RETRY_LMT); | ||
303 | } else { | ||
304 | /*QCU/DCU [5211+]*/ | ||
305 | ath5k_hw_reg_write(ah, | ||
306 | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, | ||
307 | AR5K_DCU_RETRY_LMT_SLG_RETRY) | | ||
308 | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, | ||
309 | AR5K_DCU_RETRY_LMT_SSH_RETRY) | | ||
310 | AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) | | ||
311 | AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY), | ||
312 | AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); | ||
313 | 311 | ||
314 | /*===Rest is also for QCU/DCU only [5211+]===*/ | 312 | /* On Maui and Spirit use the global seqnum on DCU */ |
313 | if (ah->ah_mac_version < AR5K_SREV_AR5211) | ||
314 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), | ||
315 | AR5K_DCU_MISC_SEQNUM_CTL); | ||
316 | |||
317 | /* Constant bit rate period */ | ||
318 | if (tq->tqi_cbr_period) { | ||
319 | ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period, | ||
320 | AR5K_QCU_CBRCFG_INTVAL) | | ||
321 | AR5K_REG_SM(tq->tqi_cbr_overflow_limit, | ||
322 | AR5K_QCU_CBRCFG_ORN_THRES), | ||
323 | AR5K_QUEUE_CBRCFG(queue)); | ||
315 | 324 | ||
316 | /* | ||
317 | * Set initial content window (cw_min/cw_max) | ||
318 | * and arbitrated interframe space (aifs)... | ||
319 | */ | ||
320 | ath5k_hw_reg_write(ah, | ||
321 | AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | | ||
322 | AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | | ||
323 | AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs, | ||
324 | AR5K_DCU_LCL_IFS_AIFS), | ||
325 | AR5K_QUEUE_DFS_LOCAL_IFS(queue)); | ||
326 | |||
327 | /* | ||
328 | * Set misc registers | ||
329 | */ | ||
330 | /* Enable DCU early termination for this queue */ | ||
331 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), | 325 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), |
332 | AR5K_QCU_MISC_DCU_EARLY); | 326 | AR5K_QCU_MISC_FRSHED_CBR); |
333 | 327 | ||
334 | /* Enable DCU to wait for next fragment from QCU */ | 328 | if (tq->tqi_cbr_overflow_limit) |
335 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), | ||
336 | AR5K_DCU_MISC_FRAG_WAIT); | ||
337 | |||
338 | /* On Maui and Spirit use the global seqnum on DCU */ | ||
339 | if (ah->ah_mac_version < AR5K_SREV_AR5211) | ||
340 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), | ||
341 | AR5K_DCU_MISC_SEQNUM_CTL); | ||
342 | |||
343 | if (tq->tqi_cbr_period) { | ||
344 | ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period, | ||
345 | AR5K_QCU_CBRCFG_INTVAL) | | ||
346 | AR5K_REG_SM(tq->tqi_cbr_overflow_limit, | ||
347 | AR5K_QCU_CBRCFG_ORN_THRES), | ||
348 | AR5K_QUEUE_CBRCFG(queue)); | ||
349 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), | 329 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), |
350 | AR5K_QCU_MISC_FRSHED_CBR); | ||
351 | if (tq->tqi_cbr_overflow_limit) | ||
352 | AR5K_REG_ENABLE_BITS(ah, | ||
353 | AR5K_QUEUE_MISC(queue), | ||
354 | AR5K_QCU_MISC_CBR_THRES_ENABLE); | 330 | AR5K_QCU_MISC_CBR_THRES_ENABLE); |
355 | } | 331 | } |
356 | 332 | ||
357 | if (tq->tqi_ready_time && | 333 | /* Ready time interval */ |
358 | (tq->tqi_type != AR5K_TX_QUEUE_CAB)) | 334 | if (tq->tqi_ready_time && (tq->tqi_type != AR5K_TX_QUEUE_CAB)) |
359 | ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, | 335 | ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, |
360 | AR5K_QCU_RDYTIMECFG_INTVAL) | | 336 | AR5K_QCU_RDYTIMECFG_INTVAL) | |
361 | AR5K_QCU_RDYTIMECFG_ENABLE, | 337 | AR5K_QCU_RDYTIMECFG_ENABLE, |
362 | AR5K_QUEUE_RDYTIMECFG(queue)); | 338 | AR5K_QUEUE_RDYTIMECFG(queue)); |
363 | 339 | ||
364 | if (tq->tqi_burst_time) { | 340 | if (tq->tqi_burst_time) { |
365 | ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time, | 341 | ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time, |
366 | AR5K_DCU_CHAN_TIME_DUR) | | 342 | AR5K_DCU_CHAN_TIME_DUR) | |
367 | AR5K_DCU_CHAN_TIME_ENABLE, | 343 | AR5K_DCU_CHAN_TIME_ENABLE, |
368 | AR5K_QUEUE_DFS_CHANNEL_TIME(queue)); | 344 | AR5K_QUEUE_DFS_CHANNEL_TIME(queue)); |
369 | 345 | ||
370 | if (tq->tqi_flags | 346 | if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) |
371 | & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE) | 347 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), |
372 | AR5K_REG_ENABLE_BITS(ah, | ||
373 | AR5K_QUEUE_MISC(queue), | ||
374 | AR5K_QCU_MISC_RDY_VEOL_POLICY); | 348 | AR5K_QCU_MISC_RDY_VEOL_POLICY); |
375 | } | 349 | } |
376 | 350 | ||
377 | if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) | 351 | /* Enable/disable Post frame backoff */ |
378 | ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS, | 352 | if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) |
379 | AR5K_QUEUE_DFS_MISC(queue)); | 353 | ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS, |
354 | AR5K_QUEUE_DFS_MISC(queue)); | ||
380 | 355 | ||
381 | if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) | 356 | /* Enable/disable fragmentation burst backoff */ |
382 | ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG, | 357 | if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) |
383 | AR5K_QUEUE_DFS_MISC(queue)); | 358 | ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG, |
359 | AR5K_QUEUE_DFS_MISC(queue)); | ||
384 | 360 | ||
385 | /* | 361 | /* |
386 | * Set registers by queue type | 362 | * Set registers by queue type |
387 | */ | 363 | */ |
388 | switch (tq->tqi_type) { | 364 | switch (tq->tqi_type) { |
389 | case AR5K_TX_QUEUE_BEACON: | 365 | case AR5K_TX_QUEUE_BEACON: |
390 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), | 366 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), |
391 | AR5K_QCU_MISC_FRSHED_DBA_GT | | 367 | AR5K_QCU_MISC_FRSHED_DBA_GT | |
392 | AR5K_QCU_MISC_CBREXP_BCN_DIS | | 368 | AR5K_QCU_MISC_CBREXP_BCN_DIS | |
393 | AR5K_QCU_MISC_BCN_ENABLE); | 369 | AR5K_QCU_MISC_BCN_ENABLE); |
394 | 370 | ||
395 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), | 371 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), |
396 | (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << | 372 | (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << |
397 | AR5K_DCU_MISC_ARBLOCK_CTL_S) | | 373 | AR5K_DCU_MISC_ARBLOCK_CTL_S) | |
398 | AR5K_DCU_MISC_ARBLOCK_IGNORE | | 374 | AR5K_DCU_MISC_ARBLOCK_IGNORE | |
399 | AR5K_DCU_MISC_POST_FR_BKOFF_DIS | | 375 | AR5K_DCU_MISC_POST_FR_BKOFF_DIS | |
400 | AR5K_DCU_MISC_BCN_ENABLE); | 376 | AR5K_DCU_MISC_BCN_ENABLE); |
401 | break; | 377 | break; |
402 | 378 | ||
403 | case AR5K_TX_QUEUE_CAB: | 379 | case AR5K_TX_QUEUE_CAB: |
404 | /* XXX: use BCN_SENT_GT, if we can figure out how */ | 380 | /* XXX: use BCN_SENT_GT, if we can figure out how */ |
405 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), | 381 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), |
406 | AR5K_QCU_MISC_FRSHED_DBA_GT | | 382 | AR5K_QCU_MISC_FRSHED_DBA_GT | |
407 | AR5K_QCU_MISC_CBREXP_DIS | | 383 | AR5K_QCU_MISC_CBREXP_DIS | |
408 | AR5K_QCU_MISC_CBREXP_BCN_DIS); | 384 | AR5K_QCU_MISC_CBREXP_BCN_DIS); |
409 | 385 | ||
410 | ath5k_hw_reg_write(ah, ((tq->tqi_ready_time - | 386 | ath5k_hw_reg_write(ah, ((tq->tqi_ready_time - |
411 | (AR5K_TUNE_SW_BEACON_RESP - | 387 | (AR5K_TUNE_SW_BEACON_RESP - |
412 | AR5K_TUNE_DMA_BEACON_RESP) - | 388 | AR5K_TUNE_DMA_BEACON_RESP) - |
413 | AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | | 389 | AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | |
414 | AR5K_QCU_RDYTIMECFG_ENABLE, | 390 | AR5K_QCU_RDYTIMECFG_ENABLE, |
415 | AR5K_QUEUE_RDYTIMECFG(queue)); | 391 | AR5K_QUEUE_RDYTIMECFG(queue)); |
416 | 392 | ||
417 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), | 393 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), |
418 | (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << | 394 | (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << |
419 | AR5K_DCU_MISC_ARBLOCK_CTL_S)); | 395 | AR5K_DCU_MISC_ARBLOCK_CTL_S)); |
420 | break; | 396 | break; |
421 | 397 | ||
422 | case AR5K_TX_QUEUE_UAPSD: | 398 | case AR5K_TX_QUEUE_UAPSD: |
423 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), | 399 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), |
424 | AR5K_QCU_MISC_CBREXP_DIS); | 400 | AR5K_QCU_MISC_CBREXP_DIS); |
425 | break; | 401 | break; |
426 | 402 | ||
427 | case AR5K_TX_QUEUE_DATA: | 403 | case AR5K_TX_QUEUE_DATA: |
428 | default: | 404 | default: |
429 | break; | 405 | break; |
430 | } | ||
431 | |||
432 | /* TODO: Handle frame compression */ | ||
433 | |||
434 | /* | ||
435 | * Enable interrupts for this tx queue | ||
436 | * in the secondary interrupt mask registers | ||
437 | */ | ||
438 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE) | ||
439 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue); | ||
440 | |||
441 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE) | ||
442 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue); | ||
443 | |||
444 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE) | ||
445 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue); | ||
446 | |||
447 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE) | ||
448 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue); | ||
449 | |||
450 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) | ||
451 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); | ||
452 | |||
453 | if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE) | ||
454 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue); | ||
455 | |||
456 | if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE) | ||
457 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue); | ||
458 | |||
459 | if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE) | ||
460 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue); | ||
461 | |||
462 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE) | ||
463 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue); | ||
464 | |||
465 | /* Update secondary interrupt mask registers */ | ||
466 | |||
467 | /* Filter out inactive queues */ | ||
468 | ah->ah_txq_imr_txok &= ah->ah_txq_status; | ||
469 | ah->ah_txq_imr_txerr &= ah->ah_txq_status; | ||
470 | ah->ah_txq_imr_txurn &= ah->ah_txq_status; | ||
471 | ah->ah_txq_imr_txdesc &= ah->ah_txq_status; | ||
472 | ah->ah_txq_imr_txeol &= ah->ah_txq_status; | ||
473 | ah->ah_txq_imr_cbrorn &= ah->ah_txq_status; | ||
474 | ah->ah_txq_imr_cbrurn &= ah->ah_txq_status; | ||
475 | ah->ah_txq_imr_qtrig &= ah->ah_txq_status; | ||
476 | ah->ah_txq_imr_nofrm &= ah->ah_txq_status; | ||
477 | |||
478 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, | ||
479 | AR5K_SIMR0_QCU_TXOK) | | ||
480 | AR5K_REG_SM(ah->ah_txq_imr_txdesc, | ||
481 | AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0); | ||
482 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr, | ||
483 | AR5K_SIMR1_QCU_TXERR) | | ||
484 | AR5K_REG_SM(ah->ah_txq_imr_txeol, | ||
485 | AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); | ||
486 | /* Update simr2 but don't overwrite rest simr2 settings */ | ||
487 | AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN); | ||
488 | AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, | ||
489 | AR5K_REG_SM(ah->ah_txq_imr_txurn, | ||
490 | AR5K_SIMR2_QCU_TXURN)); | ||
491 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn, | ||
492 | AR5K_SIMR3_QCBRORN) | | ||
493 | AR5K_REG_SM(ah->ah_txq_imr_cbrurn, | ||
494 | AR5K_SIMR3_QCBRURN), AR5K_SIMR3); | ||
495 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig, | ||
496 | AR5K_SIMR4_QTRIG), AR5K_SIMR4); | ||
497 | /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */ | ||
498 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm, | ||
499 | AR5K_TXNOFRM_QCU), AR5K_TXNOFRM); | ||
500 | /* No queue has TXNOFRM enabled, disable the interrupt | ||
501 | * by setting AR5K_TXNOFRM to zero */ | ||
502 | if (ah->ah_txq_imr_nofrm == 0) | ||
503 | ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM); | ||
504 | |||
505 | /* Set QCU mask for this DCU to save power */ | ||
506 | AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue); | ||
507 | } | 406 | } |
508 | 407 | ||
408 | /* TODO: Handle frame compression */ | ||
409 | |||
410 | /* | ||
411 | * Enable interrupts for this tx queue | ||
412 | * in the secondary interrupt mask registers | ||
413 | */ | ||
414 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE) | ||
415 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue); | ||
416 | |||
417 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE) | ||
418 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue); | ||
419 | |||
420 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE) | ||
421 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue); | ||
422 | |||
423 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE) | ||
424 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue); | ||
425 | |||
426 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) | ||
427 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); | ||
428 | |||
429 | if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE) | ||
430 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue); | ||
431 | |||
432 | if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE) | ||
433 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue); | ||
434 | |||
435 | if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE) | ||
436 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue); | ||
437 | |||
438 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE) | ||
439 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue); | ||
440 | |||
441 | /* Update secondary interrupt mask registers */ | ||
442 | |||
443 | /* Filter out inactive queues */ | ||
444 | ah->ah_txq_imr_txok &= ah->ah_txq_status; | ||
445 | ah->ah_txq_imr_txerr &= ah->ah_txq_status; | ||
446 | ah->ah_txq_imr_txurn &= ah->ah_txq_status; | ||
447 | ah->ah_txq_imr_txdesc &= ah->ah_txq_status; | ||
448 | ah->ah_txq_imr_txeol &= ah->ah_txq_status; | ||
449 | ah->ah_txq_imr_cbrorn &= ah->ah_txq_status; | ||
450 | ah->ah_txq_imr_cbrurn &= ah->ah_txq_status; | ||
451 | ah->ah_txq_imr_qtrig &= ah->ah_txq_status; | ||
452 | ah->ah_txq_imr_nofrm &= ah->ah_txq_status; | ||
453 | |||
454 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, | ||
455 | AR5K_SIMR0_QCU_TXOK) | | ||
456 | AR5K_REG_SM(ah->ah_txq_imr_txdesc, | ||
457 | AR5K_SIMR0_QCU_TXDESC), | ||
458 | AR5K_SIMR0); | ||
459 | |||
460 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr, | ||
461 | AR5K_SIMR1_QCU_TXERR) | | ||
462 | AR5K_REG_SM(ah->ah_txq_imr_txeol, | ||
463 | AR5K_SIMR1_QCU_TXEOL), | ||
464 | AR5K_SIMR1); | ||
465 | |||
466 | /* Update SIMR2 but don't overwrite rest simr2 settings */ | ||
467 | AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN); | ||
468 | AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, | ||
469 | AR5K_REG_SM(ah->ah_txq_imr_txurn, | ||
470 | AR5K_SIMR2_QCU_TXURN)); | ||
471 | |||
472 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn, | ||
473 | AR5K_SIMR3_QCBRORN) | | ||
474 | AR5K_REG_SM(ah->ah_txq_imr_cbrurn, | ||
475 | AR5K_SIMR3_QCBRURN), | ||
476 | AR5K_SIMR3); | ||
477 | |||
478 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig, | ||
479 | AR5K_SIMR4_QTRIG), AR5K_SIMR4); | ||
480 | |||
481 | /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */ | ||
482 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm, | ||
483 | AR5K_TXNOFRM_QCU), AR5K_TXNOFRM); | ||
484 | |||
485 | /* No queue has TXNOFRM enabled, disable the interrupt | ||
486 | * by setting AR5K_TXNOFRM to zero */ | ||
487 | if (ah->ah_txq_imr_nofrm == 0) | ||
488 | ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM); | ||
489 | |||
490 | /* Set QCU mask for this DCU to save power */ | ||
491 | AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue); | ||
492 | |||
509 | return 0; | 493 | return 0; |
510 | } | 494 | } |
511 | 495 | ||
512 | /* | 496 | |
513 | * Set slot time on DCU | 497 | /**************************\ |
498 | * Global QCU/DCU functions * | ||
499 | \**************************/ | ||
500 | |||
501 | /** | ||
502 | * ath5k_hw_set_ifs_intervals - Set global inter-frame spaces on DCU | ||
503 | * | ||
504 | * @ah The &struct ath5k_hw | ||
505 | * @slot_time Slot time in us | ||
506 | * | ||
507 | * Sets the global IFS intervals on DCU (also works on AR5210) for | ||
508 | * the given slot time and the current bwmode. | ||
514 | */ | 509 | */ |
515 | int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) | 510 | int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) |
516 | { | 511 | { |
512 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
513 | struct ath5k_softc *sc = ah->ah_sc; | ||
514 | struct ieee80211_rate *rate; | ||
515 | u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock; | ||
517 | u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); | 516 | u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); |
518 | 517 | ||
519 | if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX) | 518 | if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX) |
520 | return -EINVAL; | 519 | return -EINVAL; |
521 | 520 | ||
522 | if (ah->ah_version == AR5K_AR5210) | 521 | sifs = ath5k_hw_get_default_sifs(ah); |
523 | ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME); | 522 | sifs_clock = ath5k_hw_htoclock(ah, sifs - 2); |
523 | |||
524 | /* EIFS | ||
525 | * Txtime of ack at lowest rate + SIFS + DIFS | ||
526 | * (DIFS = SIFS + 2 * Slot time) | ||
527 | * | ||
528 | * Note: HAL has some predefined values for EIFS | ||
529 | * Turbo: (37 + 2 * 6) | ||
530 | * Default: (74 + 2 * 9) | ||
531 | * Half: (149 + 2 * 13) | ||
532 | * Quarter: (298 + 2 * 21) | ||
533 | * | ||
534 | * (74 + 2 * 6) for AR5210 default and turbo ! | ||
535 | * | ||
536 | * According to the formula we have | ||
537 | * ack_tx_time = 25 for turbo and | ||
538 | * ack_tx_time = 42.5 * clock multiplier | ||
539 | * for default/half/quarter. | ||
540 | * | ||
541 | * This can't be right, 42 is what we would get | ||
542 | * from ath5k_hw_get_frame_dur_for_bwmode or | ||
543 | * ieee80211_generic_frame_duration for zero frame | ||
544 | * length and without SIFS ! | ||
545 | * | ||
546 | * Also we have different lowest rate for 802.11a | ||
547 | */ | ||
548 | if (channel->hw_value & CHANNEL_5GHZ) | ||
549 | rate = &sc->sbands[IEEE80211_BAND_5GHZ].bitrates[0]; | ||
524 | else | 550 | else |
525 | ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT); | 551 | rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; |
552 | |||
553 | ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); | ||
554 | |||
555 | /* ack_tx_time includes an SIFS already */ | ||
556 | eifs = ack_tx_time + sifs + 2 * slot_time; | ||
557 | eifs_clock = ath5k_hw_htoclock(ah, eifs); | ||
558 | |||
559 | /* Set IFS settings on AR5210 */ | ||
560 | if (ah->ah_version == AR5K_AR5210) { | ||
561 | u32 pifs, pifs_clock, difs, difs_clock; | ||
562 | |||
563 | /* Set slot time */ | ||
564 | ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME); | ||
565 | |||
566 | /* Set EIFS */ | ||
567 | eifs_clock = AR5K_REG_SM(eifs_clock, AR5K_IFS1_EIFS); | ||
568 | |||
569 | /* PIFS = Slot time + SIFS */ | ||
570 | pifs = slot_time + sifs; | ||
571 | pifs_clock = ath5k_hw_htoclock(ah, pifs); | ||
572 | pifs_clock = AR5K_REG_SM(pifs_clock, AR5K_IFS1_PIFS); | ||
573 | |||
574 | /* DIFS = SIFS + 2 * Slot time */ | ||
575 | difs = sifs + 2 * slot_time; | ||
576 | difs_clock = ath5k_hw_htoclock(ah, difs); | ||
577 | |||
578 | /* Set SIFS/DIFS */ | ||
579 | ath5k_hw_reg_write(ah, (difs_clock << | ||
580 | AR5K_IFS0_DIFS_S) | sifs_clock, | ||
581 | AR5K_IFS0); | ||
582 | |||
583 | /* Set PIFS/EIFS and preserve AR5K_INIT_CARR_SENSE_EN */ | ||
584 | ath5k_hw_reg_write(ah, pifs_clock | eifs_clock | | ||
585 | (AR5K_INIT_CARR_SENSE_EN << AR5K_IFS1_CS_EN_S), | ||
586 | AR5K_IFS1); | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | /* Set IFS slot time */ | ||
592 | ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT); | ||
593 | |||
594 | /* Set EIFS interval */ | ||
595 | ath5k_hw_reg_write(ah, eifs_clock, AR5K_DCU_GBL_IFS_EIFS); | ||
596 | |||
597 | /* Set SIFS interval in usecs */ | ||
598 | AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC, | ||
599 | AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC, | ||
600 | sifs); | ||
601 | |||
602 | /* Set SIFS interval in clock cycles */ | ||
603 | ath5k_hw_reg_write(ah, sifs_clock, AR5K_DCU_GBL_IFS_SIFS); | ||
526 | 604 | ||
527 | return 0; | 605 | return 0; |
528 | } | 606 | } |
529 | 607 | ||
608 | |||
609 | int ath5k_hw_init_queues(struct ath5k_hw *ah) | ||
610 | { | ||
611 | int i, ret; | ||
612 | |||
613 | /* TODO: HW Compression support for data queues */ | ||
614 | /* TODO: Burst prefetch for data queues */ | ||
615 | |||
616 | /* | ||
617 | * Reset queues and start beacon timers at the end of the reset routine | ||
618 | * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping | ||
619 | * Note: If we want we can assign multiple qcus on one dcu. | ||
620 | */ | ||
621 | if (ah->ah_version != AR5K_AR5210) | ||
622 | for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) { | ||
623 | ret = ath5k_hw_reset_tx_queue(ah, i); | ||
624 | if (ret) { | ||
625 | ATH5K_ERR(ah->ah_sc, | ||
626 | "failed to reset TX queue #%d\n", i); | ||
627 | return ret; | ||
628 | } | ||
629 | } | ||
630 | else | ||
631 | /* No QCU/DCU on AR5210, just set tx | ||
632 | * retry limits. We set IFS parameters | ||
633 | * on ath5k_hw_set_ifs_intervals */ | ||
634 | ath5k_hw_set_tx_retry_limits(ah, 0); | ||
635 | |||
636 | /* Set the turbo flag when operating on 40MHz */ | ||
637 | if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) | ||
638 | AR5K_REG_ENABLE_BITS(ah, AR5K_DCU_GBL_IFS_MISC, | ||
639 | AR5K_DCU_GBL_IFS_MISC_TURBO_MODE); | ||
640 | |||
641 | /* If we didn't set IFS timings through | ||
642 | * ath5k_hw_set_coverage_class make sure | ||
643 | * we set them here */ | ||
644 | if (!ah->ah_coverage_class) { | ||
645 | unsigned int slot_time = ath5k_hw_get_default_slottime(ah); | ||
646 | ath5k_hw_set_ifs_intervals(ah, slot_time); | ||
647 | } | ||
648 | |||
649 | return 0; | ||
650 | } | ||