diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_tx.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.c | 133 |
1 files changed, 64 insertions, 69 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 811e739d05bf..62db79508ddf 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | 26 | ||
27 | #include "wl1271.h" | 27 | #include "wl1271.h" |
28 | #include "wl1271_spi.h" | ||
29 | #include "wl1271_io.h" | 28 | #include "wl1271_io.h" |
30 | #include "wl1271_reg.h" | 29 | #include "wl1271_reg.h" |
31 | #include "wl1271_ps.h" | 30 | #include "wl1271_ps.h" |
@@ -47,7 +46,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) | |||
47 | { | 46 | { |
48 | struct wl1271_tx_hw_descr *desc; | 47 | struct wl1271_tx_hw_descr *desc; |
49 | u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; | 48 | u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; |
50 | u32 total_blocks, excluded; | 49 | u32 total_blocks; |
51 | int id, ret = -EBUSY; | 50 | int id, ret = -EBUSY; |
52 | 51 | ||
53 | /* allocate free identifier for the packet */ | 52 | /* allocate free identifier for the packet */ |
@@ -57,12 +56,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) | |||
57 | 56 | ||
58 | /* approximate the number of blocks required for this packet | 57 | /* approximate the number of blocks required for this packet |
59 | in the firmware */ | 58 | in the firmware */ |
60 | /* FIXME: try to figure out what is done here and make it cleaner */ | 59 | total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; |
61 | total_blocks = (total_len + 20) >> TX_HW_BLOCK_SHIFT_DIV; | 60 | total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; |
62 | excluded = (total_blocks << 2) + ((total_len + 20) & 0xff) + 34; | ||
63 | total_blocks += (excluded > 252) ? 2 : 1; | ||
64 | total_blocks += TX_HW_BLOCK_SPARE; | ||
65 | |||
66 | if (total_blocks <= wl->tx_blocks_available) { | 61 | if (total_blocks <= wl->tx_blocks_available) { |
67 | desc = (struct wl1271_tx_hw_descr *)skb_push( | 62 | desc = (struct wl1271_tx_hw_descr *)skb_push( |
68 | skb, total_len - skb->len); | 63 | skb, total_len - skb->len); |
@@ -87,8 +82,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) | |||
87 | static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | 82 | static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, |
88 | u32 extra, struct ieee80211_tx_info *control) | 83 | u32 extra, struct ieee80211_tx_info *control) |
89 | { | 84 | { |
85 | struct timespec ts; | ||
90 | struct wl1271_tx_hw_descr *desc; | 86 | struct wl1271_tx_hw_descr *desc; |
91 | int pad, ac; | 87 | int pad, ac; |
88 | s64 hosttime; | ||
92 | u16 tx_attr; | 89 | u16 tx_attr; |
93 | 90 | ||
94 | desc = (struct wl1271_tx_hw_descr *) skb->data; | 91 | desc = (struct wl1271_tx_hw_descr *) skb->data; |
@@ -102,8 +99,9 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | |||
102 | } | 99 | } |
103 | 100 | ||
104 | /* configure packet life time */ | 101 | /* configure packet life time */ |
105 | desc->start_time = cpu_to_le32(jiffies_to_usecs(jiffies) - | 102 | getnstimeofday(&ts); |
106 | wl->time_offset); | 103 | hosttime = (timespec_to_ns(&ts) >> 10); |
104 | desc->start_time = cpu_to_le32(hosttime - wl->time_offset); | ||
107 | desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); | 105 | desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); |
108 | 106 | ||
109 | /* configure the tx attributes */ | 107 | /* configure the tx attributes */ |
@@ -170,7 +168,6 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, | |||
170 | 168 | ||
171 | /* write packet new counter into the write access register */ | 169 | /* write packet new counter into the write access register */ |
172 | wl->tx_packets_count++; | 170 | wl->tx_packets_count++; |
173 | wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); | ||
174 | 171 | ||
175 | desc = (struct wl1271_tx_hw_descr *) skb->data; | 172 | desc = (struct wl1271_tx_hw_descr *) skb->data; |
176 | wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", | 173 | wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", |
@@ -223,7 +220,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) | |||
223 | return ret; | 220 | return ret; |
224 | } | 221 | } |
225 | 222 | ||
226 | static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) | 223 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) |
227 | { | 224 | { |
228 | struct ieee80211_supported_band *band; | 225 | struct ieee80211_supported_band *band; |
229 | u32 enabled_rates = 0; | 226 | u32 enabled_rates = 0; |
@@ -245,6 +242,7 @@ void wl1271_tx_work(struct work_struct *work) | |||
245 | struct sk_buff *skb; | 242 | struct sk_buff *skb; |
246 | bool woken_up = false; | 243 | bool woken_up = false; |
247 | u32 sta_rates = 0; | 244 | u32 sta_rates = 0; |
245 | u32 prev_tx_packets_count; | ||
248 | int ret; | 246 | int ret; |
249 | 247 | ||
250 | /* check if the rates supported by the AP have changed */ | 248 | /* check if the rates supported by the AP have changed */ |
@@ -261,6 +259,8 @@ void wl1271_tx_work(struct work_struct *work) | |||
261 | if (unlikely(wl->state == WL1271_STATE_OFF)) | 259 | if (unlikely(wl->state == WL1271_STATE_OFF)) |
262 | goto out; | 260 | goto out; |
263 | 261 | ||
262 | prev_tx_packets_count = wl->tx_packets_count; | ||
263 | |||
264 | /* if rates have changed, re-configure the rate policy */ | 264 | /* if rates have changed, re-configure the rate policy */ |
265 | if (unlikely(sta_rates)) { | 265 | if (unlikely(sta_rates)) { |
266 | wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); | 266 | wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); |
@@ -271,31 +271,26 @@ void wl1271_tx_work(struct work_struct *work) | |||
271 | if (!woken_up) { | 271 | if (!woken_up) { |
272 | ret = wl1271_ps_elp_wakeup(wl, false); | 272 | ret = wl1271_ps_elp_wakeup(wl, false); |
273 | if (ret < 0) | 273 | if (ret < 0) |
274 | goto out; | 274 | goto out_ack; |
275 | woken_up = true; | 275 | woken_up = true; |
276 | } | 276 | } |
277 | 277 | ||
278 | ret = wl1271_tx_frame(wl, skb); | 278 | ret = wl1271_tx_frame(wl, skb); |
279 | if (ret == -EBUSY) { | 279 | if (ret == -EBUSY) { |
280 | /* firmware buffer is full, stop queues */ | 280 | /* firmware buffer is full, lets stop transmitting. */ |
281 | wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " | ||
282 | "stop queues"); | ||
283 | ieee80211_stop_queues(wl->hw); | ||
284 | set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); | ||
285 | skb_queue_head(&wl->tx_queue, skb); | 281 | skb_queue_head(&wl->tx_queue, skb); |
286 | goto out; | 282 | goto out_ack; |
287 | } else if (ret < 0) { | 283 | } else if (ret < 0) { |
288 | dev_kfree_skb(skb); | 284 | dev_kfree_skb(skb); |
289 | goto out; | 285 | goto out_ack; |
290 | } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, | ||
291 | &wl->flags)) { | ||
292 | /* firmware buffer has space, restart queues */ | ||
293 | wl1271_debug(DEBUG_TX, | ||
294 | "complete_packet: waking queues"); | ||
295 | ieee80211_wake_queues(wl->hw); | ||
296 | } | 286 | } |
297 | } | 287 | } |
298 | 288 | ||
289 | out_ack: | ||
290 | /* interrupt the firmware with the new packets */ | ||
291 | if (prev_tx_packets_count != wl->tx_packets_count) | ||
292 | wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); | ||
293 | |||
299 | out: | 294 | out: |
300 | if (woken_up) | 295 | if (woken_up) |
301 | wl1271_ps_elp_sleep(wl); | 296 | wl1271_ps_elp_sleep(wl); |
@@ -308,11 +303,12 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
308 | { | 303 | { |
309 | struct ieee80211_tx_info *info; | 304 | struct ieee80211_tx_info *info; |
310 | struct sk_buff *skb; | 305 | struct sk_buff *skb; |
311 | u16 seq; | ||
312 | int id = result->id; | 306 | int id = result->id; |
307 | int rate = -1; | ||
308 | u8 retries = 0; | ||
313 | 309 | ||
314 | /* check for id legality */ | 310 | /* check for id legality */ |
315 | if (id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL) { | 311 | if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) { |
316 | wl1271_warning("TX result illegal id: %d", id); | 312 | wl1271_warning("TX result illegal id: %d", id); |
317 | return; | 313 | return; |
318 | } | 314 | } |
@@ -320,31 +316,29 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
320 | skb = wl->tx_frames[id]; | 316 | skb = wl->tx_frames[id]; |
321 | info = IEEE80211_SKB_CB(skb); | 317 | info = IEEE80211_SKB_CB(skb); |
322 | 318 | ||
323 | /* update packet status */ | 319 | /* update the TX status info */ |
324 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { | 320 | if (result->status == TX_SUCCESS) { |
325 | if (result->status == TX_SUCCESS) | 321 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) |
326 | info->flags |= IEEE80211_TX_STAT_ACK; | 322 | info->flags |= IEEE80211_TX_STAT_ACK; |
327 | if (result->status & TX_RETRY_EXCEEDED) { | 323 | rate = wl1271_rate_to_idx(wl, result->rate_class_index); |
328 | /* FIXME */ | 324 | retries = result->ack_failures; |
329 | /* info->status.excessive_retries = 1; */ | 325 | } else if (result->status == TX_RETRY_EXCEEDED) { |
330 | wl->stats.excessive_retries++; | 326 | wl->stats.excessive_retries++; |
331 | } | 327 | retries = result->ack_failures; |
332 | } | 328 | } |
333 | 329 | ||
334 | /* FIXME */ | 330 | info->status.rates[0].idx = rate; |
335 | /* info->status.retry_count = result->ack_failures; */ | 331 | info->status.rates[0].count = retries; |
332 | info->status.rates[0].flags = 0; | ||
333 | info->status.ack_signal = -1; | ||
334 | |||
336 | wl->stats.retry_count += result->ack_failures; | 335 | wl->stats.retry_count += result->ack_failures; |
337 | 336 | ||
338 | /* update security sequence number */ | 337 | /* update security sequence number */ |
339 | seq = wl->tx_security_seq_16 + | 338 | wl->tx_security_seq += (result->lsb_security_sequence_number - |
340 | (result->lsb_security_sequence_number - | 339 | wl->tx_security_last_seq); |
341 | wl->tx_security_last_seq); | ||
342 | wl->tx_security_last_seq = result->lsb_security_sequence_number; | 340 | wl->tx_security_last_seq = result->lsb_security_sequence_number; |
343 | 341 | ||
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 */ | 342 | /* remove private header from packet */ |
349 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); | 343 | skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); |
350 | 344 | ||
@@ -367,23 +361,29 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
367 | } | 361 | } |
368 | 362 | ||
369 | /* Called upon reception of a TX complete interrupt */ | 363 | /* Called upon reception of a TX complete interrupt */ |
370 | void wl1271_tx_complete(struct wl1271 *wl, u32 count) | 364 | void wl1271_tx_complete(struct wl1271 *wl) |
371 | { | 365 | { |
372 | struct wl1271_acx_mem_map *memmap = | 366 | struct wl1271_acx_mem_map *memmap = |
373 | (struct wl1271_acx_mem_map *)wl->target_mem_map; | 367 | (struct wl1271_acx_mem_map *)wl->target_mem_map; |
368 | u32 count, fw_counter; | ||
374 | u32 i; | 369 | u32 i; |
375 | 370 | ||
376 | wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); | ||
377 | |||
378 | /* read the tx results from the chipset */ | 371 | /* read the tx results from the chipset */ |
379 | wl1271_read(wl, le32_to_cpu(memmap->tx_result), | 372 | wl1271_read(wl, le32_to_cpu(memmap->tx_result), |
380 | wl->tx_res_if, sizeof(*wl->tx_res_if), false); | 373 | wl->tx_res_if, sizeof(*wl->tx_res_if), false); |
374 | fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); | ||
375 | |||
376 | /* write host counter to chipset (to ack) */ | ||
377 | wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + | ||
378 | offsetof(struct wl1271_tx_hw_res_if, | ||
379 | tx_result_host_counter), fw_counter); | ||
380 | |||
381 | count = fw_counter - wl->tx_results_count; | ||
382 | wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); | ||
381 | 383 | ||
382 | /* verify that the result buffer is not getting overrun */ | 384 | /* verify that the result buffer is not getting overrun */ |
383 | if (count > TX_HW_RESULT_QUEUE_LEN) { | 385 | if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) |
384 | wl1271_warning("TX result overflow from chipset: %d", count); | 386 | wl1271_warning("TX result overflow from chipset: %d", count); |
385 | count = TX_HW_RESULT_QUEUE_LEN; | ||
386 | } | ||
387 | 387 | ||
388 | /* process the results */ | 388 | /* process the results */ |
389 | for (i = 0; i < count; i++) { | 389 | for (i = 0; i < count; i++) { |
@@ -397,11 +397,18 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count) | |||
397 | wl->tx_results_count++; | 397 | wl->tx_results_count++; |
398 | } | 398 | } |
399 | 399 | ||
400 | /* write host counter to chipset (to ack) */ | 400 | if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && |
401 | wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + | 401 | skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) { |
402 | offsetof(struct wl1271_tx_hw_res_if, | 402 | unsigned long flags; |
403 | tx_result_host_counter), | 403 | |
404 | le32_to_cpu(wl->tx_res_if->tx_result_fw_counter)); | 404 | /* firmware buffer has space, restart queues */ |
405 | wl1271_debug(DEBUG_TX, "tx_complete: waking queues"); | ||
406 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
407 | ieee80211_wake_queues(wl->hw); | ||
408 | clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); | ||
409 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
410 | ieee80211_queue_work(wl->hw, &wl->tx_work); | ||
411 | } | ||
405 | } | 412 | } |
406 | 413 | ||
407 | /* caller must hold wl->mutex */ | 414 | /* caller must hold wl->mutex */ |
@@ -409,31 +416,19 @@ void wl1271_tx_flush(struct wl1271 *wl) | |||
409 | { | 416 | { |
410 | int i; | 417 | int i; |
411 | struct sk_buff *skb; | 418 | struct sk_buff *skb; |
412 | struct ieee80211_tx_info *info; | ||
413 | 419 | ||
414 | /* TX failure */ | 420 | /* TX failure */ |
415 | /* control->flags = 0; FIXME */ | 421 | /* control->flags = 0; FIXME */ |
416 | 422 | ||
417 | while ((skb = skb_dequeue(&wl->tx_queue))) { | 423 | while ((skb = skb_dequeue(&wl->tx_queue))) { |
418 | info = IEEE80211_SKB_CB(skb); | ||
419 | |||
420 | wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb); | 424 | wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb); |
421 | |||
422 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
423 | continue; | ||
424 | |||
425 | ieee80211_tx_status(wl->hw, skb); | 425 | ieee80211_tx_status(wl->hw, skb); |
426 | } | 426 | } |
427 | 427 | ||
428 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 428 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
429 | if (wl->tx_frames[i] != NULL) { | 429 | if (wl->tx_frames[i] != NULL) { |
430 | skb = wl->tx_frames[i]; | 430 | skb = wl->tx_frames[i]; |
431 | info = IEEE80211_SKB_CB(skb); | ||
432 | |||
433 | if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) | ||
434 | continue; | ||
435 | |||
436 | ieee80211_tx_status(wl->hw, skb); | ||
437 | wl->tx_frames[i] = NULL; | 431 | wl->tx_frames[i] = NULL; |
432 | ieee80211_tx_status(wl->hw, skb); | ||
438 | } | 433 | } |
439 | } | 434 | } |