diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/wl12xx/wl1271_tx.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_tx.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.c | 135 |
1 files changed, 98 insertions, 37 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index ff221258b941..811e739d05bf 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include "wl1271.h" | 27 | #include "wl1271.h" |
28 | #include "wl1271_spi.h" | 28 | #include "wl1271_spi.h" |
29 | #include "wl1271_io.h" | ||
29 | #include "wl1271_reg.h" | 30 | #include "wl1271_reg.h" |
30 | #include "wl1271_ps.h" | 31 | #include "wl1271_ps.h" |
31 | #include "wl1271_tx.h" | 32 | #include "wl1271_tx.h" |
@@ -33,8 +34,7 @@ | |||
33 | static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) | 34 | static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) |
34 | { | 35 | { |
35 | int i; | 36 | int i; |
36 | 37 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | |
37 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | ||
38 | if (wl->tx_frames[i] == NULL) { | 38 | if (wl->tx_frames[i] == NULL) { |
39 | wl->tx_frames[i] = skb; | 39 | wl->tx_frames[i] = skb; |
40 | return i; | 40 | return i; |
@@ -58,8 +58,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) | |||
58 | /* approximate the number of blocks required for this packet | 58 | /* approximate the number of blocks required for this packet |
59 | in the firmware */ | 59 | in the firmware */ |
60 | /* FIXME: try to figure out what is done here and make it cleaner */ | 60 | /* FIXME: try to figure out what is done here and make it cleaner */ |
61 | total_blocks = (skb->len) >> TX_HW_BLOCK_SHIFT_DIV; | 61 | total_blocks = (total_len + 20) >> TX_HW_BLOCK_SHIFT_DIV; |
62 | excluded = (total_blocks << 2) + (skb->len & 0xff) + 34; | 62 | excluded = (total_blocks << 2) + ((total_len + 20) & 0xff) + 34; |
63 | total_blocks += (excluded > 252) ? 2 : 1; | 63 | total_blocks += (excluded > 252) ? 2 : 1; |
64 | total_blocks += TX_HW_BLOCK_SPARE; | 64 | total_blocks += TX_HW_BLOCK_SPARE; |
65 | 65 | ||
@@ -88,29 +88,48 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | |||
88 | u32 extra, struct ieee80211_tx_info *control) | 88 | u32 extra, struct ieee80211_tx_info *control) |
89 | { | 89 | { |
90 | struct wl1271_tx_hw_descr *desc; | 90 | struct wl1271_tx_hw_descr *desc; |
91 | int pad; | 91 | int pad, ac; |
92 | u16 tx_attr; | ||
92 | 93 | ||
93 | desc = (struct wl1271_tx_hw_descr *) skb->data; | 94 | desc = (struct wl1271_tx_hw_descr *) skb->data; |
94 | 95 | ||
96 | /* relocate space for security header */ | ||
97 | if (extra) { | ||
98 | void *framestart = skb->data + sizeof(*desc); | ||
99 | u16 fc = *(u16 *)(framestart + extra); | ||
100 | int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc)); | ||
101 | memmove(framestart, framestart + extra, hdrlen); | ||
102 | } | ||
103 | |||
95 | /* configure packet life time */ | 104 | /* configure packet life time */ |
96 | desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset; | 105 | desc->start_time = cpu_to_le32(jiffies_to_usecs(jiffies) - |
97 | desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU; | 106 | wl->time_offset); |
107 | desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); | ||
98 | 108 | ||
99 | /* configure the tx attributes */ | 109 | /* configure the tx attributes */ |
100 | desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; | 110 | tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; |
101 | /* FIXME: do we know the packet priority? can we identify mgmt | 111 | |
102 | packets, and use max prio for them at least? */ | 112 | /* queue */ |
103 | desc->tid = 0; | 113 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); |
114 | desc->tid = wl1271_tx_ac_to_tid(ac); | ||
115 | |||
104 | desc->aid = TX_HW_DEFAULT_AID; | 116 | desc->aid = TX_HW_DEFAULT_AID; |
105 | desc->reserved = 0; | 117 | desc->reserved = 0; |
106 | 118 | ||
107 | /* align the length (and store in terms of words) */ | 119 | /* align the length (and store in terms of words) */ |
108 | pad = WL1271_TX_ALIGN(skb->len); | 120 | pad = WL1271_TX_ALIGN(skb->len); |
109 | desc->length = pad >> 2; | 121 | desc->length = cpu_to_le16(pad >> 2); |
110 | 122 | ||
111 | /* calculate number of padding bytes */ | 123 | /* calculate number of padding bytes */ |
112 | pad = pad - skb->len; | 124 | pad = pad - skb->len; |
113 | desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; | 125 | tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; |
126 | |||
127 | /* if the packets are destined for AP (have a STA entry) send them | ||
128 | with AP rate policies, otherwise use default basic rates */ | ||
129 | if (control->control.sta) | ||
130 | tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY; | ||
131 | |||
132 | desc->tx_attr = cpu_to_le16(tx_attr); | ||
114 | 133 | ||
115 | wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); | 134 | wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); |
116 | return 0; | 135 | return 0; |
@@ -147,11 +166,11 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, | |||
147 | len = WL1271_TX_ALIGN(skb->len); | 166 | len = WL1271_TX_ALIGN(skb->len); |
148 | 167 | ||
149 | /* perform a fixed address block write with the packet */ | 168 | /* perform a fixed address block write with the packet */ |
150 | wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); | 169 | wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); |
151 | 170 | ||
152 | /* write packet new counter into the write access register */ | 171 | /* write packet new counter into the write access register */ |
153 | wl->tx_packets_count++; | 172 | wl->tx_packets_count++; |
154 | wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); | 173 | wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); |
155 | 174 | ||
156 | desc = (struct wl1271_tx_hw_descr *) skb->data; | 175 | desc = (struct wl1271_tx_hw_descr *) skb->data; |
157 | wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", | 176 | wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", |
@@ -185,6 +204,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) | |||
185 | ret = wl1271_cmd_set_default_wep_key(wl, idx); | 204 | ret = wl1271_cmd_set_default_wep_key(wl, idx); |
186 | if (ret < 0) | 205 | if (ret < 0) |
187 | return ret; | 206 | return ret; |
207 | wl->default_key = idx; | ||
188 | } | 208 | } |
189 | } | 209 | } |
190 | 210 | ||
@@ -203,18 +223,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) | |||
203 | return ret; | 223 | return ret; |
204 | } | 224 | } |
205 | 225 | ||
226 | static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) | ||
227 | { | ||
228 | struct ieee80211_supported_band *band; | ||
229 | u32 enabled_rates = 0; | ||
230 | int bit; | ||
231 | |||
232 | band = wl->hw->wiphy->bands[wl->band]; | ||
233 | for (bit = 0; bit < band->n_bitrates; bit++) { | ||
234 | if (rate_set & 0x1) | ||
235 | enabled_rates |= band->bitrates[bit].hw_value; | ||
236 | rate_set >>= 1; | ||
237 | } | ||
238 | |||
239 | return enabled_rates; | ||
240 | } | ||
241 | |||
206 | void wl1271_tx_work(struct work_struct *work) | 242 | void wl1271_tx_work(struct work_struct *work) |
207 | { | 243 | { |
208 | struct wl1271 *wl = container_of(work, struct wl1271, tx_work); | 244 | struct wl1271 *wl = container_of(work, struct wl1271, tx_work); |
209 | struct sk_buff *skb; | 245 | struct sk_buff *skb; |
210 | bool woken_up = false; | 246 | bool woken_up = false; |
247 | u32 sta_rates = 0; | ||
211 | int ret; | 248 | int ret; |
212 | 249 | ||
250 | /* check if the rates supported by the AP have changed */ | ||
251 | if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED, | ||
252 | &wl->flags))) { | ||
253 | unsigned long flags; | ||
254 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
255 | sta_rates = wl->sta_rate_set; | ||
256 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
257 | } | ||
258 | |||
213 | mutex_lock(&wl->mutex); | 259 | mutex_lock(&wl->mutex); |
214 | 260 | ||
215 | if (unlikely(wl->state == WL1271_STATE_OFF)) | 261 | if (unlikely(wl->state == WL1271_STATE_OFF)) |
216 | goto out; | 262 | goto out; |
217 | 263 | ||
264 | /* if rates have changed, re-configure the rate policy */ | ||
265 | if (unlikely(sta_rates)) { | ||
266 | wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); | ||
267 | wl1271_acx_rate_policies(wl); | ||
268 | } | ||
269 | |||
218 | while ((skb = skb_dequeue(&wl->tx_queue))) { | 270 | while ((skb = skb_dequeue(&wl->tx_queue))) { |
219 | if (!woken_up) { | 271 | if (!woken_up) { |
220 | ret = wl1271_ps_elp_wakeup(wl, false); | 272 | ret = wl1271_ps_elp_wakeup(wl, false); |
@@ -229,18 +281,18 @@ void wl1271_tx_work(struct work_struct *work) | |||
229 | wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " | 281 | wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " |
230 | "stop queues"); | 282 | "stop queues"); |
231 | ieee80211_stop_queues(wl->hw); | 283 | ieee80211_stop_queues(wl->hw); |
232 | wl->tx_queue_stopped = true; | 284 | set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); |
233 | skb_queue_head(&wl->tx_queue, skb); | 285 | skb_queue_head(&wl->tx_queue, skb); |
234 | goto out; | 286 | goto out; |
235 | } else if (ret < 0) { | 287 | } else if (ret < 0) { |
236 | dev_kfree_skb(skb); | 288 | dev_kfree_skb(skb); |
237 | goto out; | 289 | goto out; |
238 | } else if (wl->tx_queue_stopped) { | 290 | } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, |
291 | &wl->flags)) { | ||
239 | /* firmware buffer has space, restart queues */ | 292 | /* firmware buffer has space, restart queues */ |
240 | wl1271_debug(DEBUG_TX, | 293 | wl1271_debug(DEBUG_TX, |
241 | "complete_packet: waking queues"); | 294 | "complete_packet: waking queues"); |
242 | ieee80211_wake_queues(wl->hw); | 295 | ieee80211_wake_queues(wl->hw); |
243 | wl->tx_queue_stopped = false; | ||
244 | } | 296 | } |
245 | } | 297 | } |
246 | 298 | ||
@@ -254,14 +306,13 @@ out: | |||
254 | static void wl1271_tx_complete_packet(struct wl1271 *wl, | 306 | static void wl1271_tx_complete_packet(struct wl1271 *wl, |
255 | struct wl1271_tx_hw_res_descr *result) | 307 | struct wl1271_tx_hw_res_descr *result) |
256 | { | 308 | { |
257 | |||
258 | struct ieee80211_tx_info *info; | 309 | struct ieee80211_tx_info *info; |
259 | struct sk_buff *skb; | 310 | struct sk_buff *skb; |
260 | u32 header_len; | 311 | u16 seq; |
261 | int id = result->id; | 312 | int id = result->id; |
262 | 313 | ||
263 | /* check for id legality */ | 314 | /* check for id legality */ |
264 | if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) { | 315 | if (id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL) { |
265 | wl1271_warning("TX result illegal id: %d", id); | 316 | wl1271_warning("TX result illegal id: %d", id); |
266 | return; | 317 | return; |
267 | } | 318 | } |
@@ -284,22 +335,32 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
284 | /* info->status.retry_count = result->ack_failures; */ | 335 | /* info->status.retry_count = result->ack_failures; */ |
285 | wl->stats.retry_count += result->ack_failures; | 336 | wl->stats.retry_count += result->ack_failures; |
286 | 337 | ||
287 | /* get header len */ | 338 | /* update security sequence number */ |
339 | seq = wl->tx_security_seq_16 + | ||
340 | (result->lsb_security_sequence_number - | ||
341 | wl->tx_security_last_seq); | ||
342 | wl->tx_security_last_seq = result->lsb_security_sequence_number; | ||
343 | |||
344 | if (seq < wl->tx_security_seq_16) | ||
345 | wl->tx_security_seq_32++; | ||
346 | wl->tx_security_seq_16 = seq; | ||
347 | |||
348 | /* remove private header from packet */ | ||
349 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); | ||
350 | |||
351 | /* remove TKIP header space if present */ | ||
288 | if (info->control.hw_key && | 352 | if (info->control.hw_key && |
289 | info->control.hw_key->alg == ALG_TKIP) | 353 | info->control.hw_key->alg == ALG_TKIP) { |
290 | header_len = WL1271_TKIP_IV_SPACE + | 354 | int hdrlen = ieee80211_get_hdrlen_from_skb(skb); |
291 | sizeof(struct wl1271_tx_hw_descr); | 355 | memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); |
292 | else | 356 | skb_pull(skb, WL1271_TKIP_IV_SPACE); |
293 | header_len = sizeof(struct wl1271_tx_hw_descr); | 357 | } |
294 | 358 | ||
295 | wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" | 359 | wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" |
296 | " status 0x%x", | 360 | " status 0x%x", |
297 | result->id, skb, result->ack_failures, | 361 | result->id, skb, result->ack_failures, |
298 | result->rate_class_index, result->status); | 362 | result->rate_class_index, result->status); |
299 | 363 | ||
300 | /* remove private header from packet */ | ||
301 | skb_pull(skb, header_len); | ||
302 | |||
303 | /* return the packet to the stack */ | 364 | /* return the packet to the stack */ |
304 | ieee80211_tx_status(wl->hw, skb); | 365 | ieee80211_tx_status(wl->hw, skb); |
305 | wl->tx_frames[result->id] = NULL; | 366 | wl->tx_frames[result->id] = NULL; |
@@ -315,8 +376,8 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count) | |||
315 | wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); | 376 | wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); |
316 | 377 | ||
317 | /* read the tx results from the chipset */ | 378 | /* read the tx results from the chipset */ |
318 | wl1271_spi_mem_read(wl, memmap->tx_result, | 379 | wl1271_read(wl, le32_to_cpu(memmap->tx_result), |
319 | wl->tx_res_if, sizeof(*wl->tx_res_if)); | 380 | wl->tx_res_if, sizeof(*wl->tx_res_if), false); |
320 | 381 | ||
321 | /* verify that the result buffer is not getting overrun */ | 382 | /* verify that the result buffer is not getting overrun */ |
322 | if (count > TX_HW_RESULT_QUEUE_LEN) { | 383 | if (count > TX_HW_RESULT_QUEUE_LEN) { |
@@ -337,10 +398,10 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count) | |||
337 | } | 398 | } |
338 | 399 | ||
339 | /* write host counter to chipset (to ack) */ | 400 | /* write host counter to chipset (to ack) */ |
340 | wl1271_mem_write32(wl, memmap->tx_result + | 401 | wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + |
341 | offsetof(struct wl1271_tx_hw_res_if, | 402 | offsetof(struct wl1271_tx_hw_res_if, |
342 | tx_result_host_counter), | 403 | tx_result_host_counter), |
343 | wl->tx_res_if->tx_result_fw_counter); | 404 | le32_to_cpu(wl->tx_res_if->tx_result_fw_counter)); |
344 | } | 405 | } |
345 | 406 | ||
346 | /* caller must hold wl->mutex */ | 407 | /* caller must hold wl->mutex */ |
@@ -364,7 +425,7 @@ void wl1271_tx_flush(struct wl1271 *wl) | |||
364 | ieee80211_tx_status(wl->hw, skb); | 425 | ieee80211_tx_status(wl->hw, skb); |
365 | } | 426 | } |
366 | 427 | ||
367 | for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) | 428 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
368 | if (wl->tx_frames[i] != NULL) { | 429 | if (wl->tx_frames[i] != NULL) { |
369 | skb = wl->tx_frames[i]; | 430 | skb = wl->tx_frames[i]; |
370 | info = IEEE80211_SKB_CB(skb); | 431 | info = IEEE80211_SKB_CB(skb); |