diff options
author | Ido Yariv <ido@wizery.com> | 2010-10-12 10:20:06 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-11-15 13:25:06 -0500 |
commit | 25eeb9e3876a161e3afcc820c6cb72e13f9b7c7e (patch) | |
tree | 433aef6e8bc0ec254c99ebbfce150cb104078185 | |
parent | a522550a283de31c7cfc30c7a129ce584e38c582 (diff) |
wl1271: Allocate TX descriptors more efficiently
On each TX descriptor allocation, a free entry is found by traversing the TX
descriptors array.
Improve this by holding a bitmap of all TX descriptors, and using efficient
bit operations to search for free entries.
Signed-off-by: Ido Yariv <ido@wizery.com>
Reviewed-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.c | 38 |
3 files changed, 24 insertions, 16 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 4a034a3f7148..718e96d97d0b 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h | |||
@@ -398,6 +398,7 @@ struct wl1271 { | |||
398 | struct work_struct tx_work; | 398 | struct work_struct tx_work; |
399 | 399 | ||
400 | /* Pending TX frames */ | 400 | /* Pending TX frames */ |
401 | unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)]; | ||
401 | struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; | 402 | struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; |
402 | int tx_frames_cnt; | 403 | int tx_frames_cnt; |
403 | 404 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 18aff225bf82..0fd472597fa6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -2532,6 +2532,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
2532 | wl->sg_enabled = true; | 2532 | wl->sg_enabled = true; |
2533 | wl->hw_pg_ver = -1; | 2533 | wl->hw_pg_ver = -1; |
2534 | 2534 | ||
2535 | memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); | ||
2535 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 2536 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
2536 | wl->tx_frames[i] = NULL; | 2537 | wl->tx_frames[i] = NULL; |
2537 | 2538 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index cf32a77a4ff5..85878e5e7526 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c | |||
@@ -30,17 +30,26 @@ | |||
30 | #include "wl1271_ps.h" | 30 | #include "wl1271_ps.h" |
31 | #include "wl1271_tx.h" | 31 | #include "wl1271_tx.h" |
32 | 32 | ||
33 | static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) | 33 | static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) |
34 | { | 34 | { |
35 | int i; | 35 | int id; |
36 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 36 | |
37 | if (wl->tx_frames[i] == NULL) { | 37 | id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); |
38 | wl->tx_frames[i] = skb; | 38 | if (id >= ACX_TX_DESCRIPTORS) |
39 | wl->tx_frames_cnt++; | 39 | return -EBUSY; |
40 | return i; | 40 | |
41 | } | 41 | __set_bit(id, wl->tx_frames_map); |
42 | wl->tx_frames[id] = skb; | ||
43 | wl->tx_frames_cnt++; | ||
44 | return id; | ||
45 | } | ||
42 | 46 | ||
43 | return -EBUSY; | 47 | static void wl1271_free_tx_id(struct wl1271 *wl, int id) |
48 | { | ||
49 | if (__test_and_clear_bit(id, wl->tx_frames_map)) { | ||
50 | wl->tx_frames[id] = NULL; | ||
51 | wl->tx_frames_cnt--; | ||
52 | } | ||
44 | } | 53 | } |
45 | 54 | ||
46 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | 55 | static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, |
@@ -55,7 +64,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | |||
55 | return -EAGAIN; | 64 | return -EAGAIN; |
56 | 65 | ||
57 | /* allocate free identifier for the packet */ | 66 | /* allocate free identifier for the packet */ |
58 | id = wl1271_tx_id(wl, skb); | 67 | id = wl1271_alloc_tx_id(wl, skb); |
59 | if (id < 0) | 68 | if (id < 0) |
60 | return id; | 69 | return id; |
61 | 70 | ||
@@ -79,8 +88,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, | |||
79 | "tx_allocate: size: %d, blocks: %d, id: %d", | 88 | "tx_allocate: size: %d, blocks: %d, id: %d", |
80 | total_len, total_blocks, id); | 89 | total_len, total_blocks, id); |
81 | } else { | 90 | } else { |
82 | wl->tx_frames[id] = NULL; | 91 | wl1271_free_tx_id(wl, id); |
83 | wl->tx_frames_cnt--; | ||
84 | } | 92 | } |
85 | 93 | ||
86 | return ret; | 94 | return ret; |
@@ -352,8 +360,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, | |||
352 | 360 | ||
353 | /* return the packet to the stack */ | 361 | /* return the packet to the stack */ |
354 | ieee80211_tx_status(wl->hw, skb); | 362 | ieee80211_tx_status(wl->hw, skb); |
355 | wl->tx_frames[result->id] = NULL; | 363 | wl1271_free_tx_id(wl, result->id); |
356 | wl->tx_frames_cnt--; | ||
357 | } | 364 | } |
358 | 365 | ||
359 | /* Called upon reception of a TX complete interrupt */ | 366 | /* Called upon reception of a TX complete interrupt */ |
@@ -422,11 +429,10 @@ void wl1271_tx_reset(struct wl1271 *wl) | |||
422 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 429 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
423 | if (wl->tx_frames[i] != NULL) { | 430 | if (wl->tx_frames[i] != NULL) { |
424 | skb = wl->tx_frames[i]; | 431 | skb = wl->tx_frames[i]; |
425 | wl->tx_frames[i] = NULL; | 432 | wl1271_free_tx_id(wl, i); |
426 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); | 433 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); |
427 | ieee80211_tx_status(wl->hw, skb); | 434 | ieee80211_tx_status(wl->hw, skb); |
428 | } | 435 | } |
429 | wl->tx_frames_cnt = 0; | ||
430 | } | 436 | } |
431 | 437 | ||
432 | #define WL1271_TX_FLUSH_TIMEOUT 500000 | 438 | #define WL1271_TX_FLUSH_TIMEOUT 500000 |