aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorIdo Yariv <ido@wizery.com>2011-03-31 04:06:59 -0400
committerLuciano Coelho <coelho@ti.com>2011-04-19 09:49:19 -0400
commit990f5de7384f9e5922e4c7c7572cbf4f29a9441e (patch)
tree3294cf7224a4aadfefc35660cbe5406f01ab6c94 /drivers
parent0da13da767cd568c1fe2a7b5b936e86e521b5ae7 (diff)
wl12xx: Clean up the dummy packet mechanism
The current implementation allocates a skb each time one is requested by the firmware. Since dummy packets are handled differently than regular packets, the skb needs to be marked. Currently, this is done by setting the pkt_type member to 5. This might not be safe, as we cannot be sure that there won't be any other packets with this pkt_type value. Since the packet does not change from one request to another, we can simply allocate a dummy packet template and always send it. All changes to the skb done during packet preparation must be reverted, so the same skb can be reused. The dummy packets are not transmitted, therefore there's no need to set the BSSID or our own MAC address. In addition, the header portion of the packet was zeroed by mistake, so fix that as well. Signed-off-by: Ido Yariv <ido@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/wl12xx/main.c79
-rw-r--r--drivers/net/wireless/wl12xx/tx.c43
-rw-r--r--drivers/net/wireless/wl12xx/tx.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h4
4 files changed, 89 insertions, 39 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 1cd396306e7b..7dce24c0b331 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1212,20 +1212,46 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1212 spin_unlock_irqrestore(&wl->wl_lock, flags); 1212 spin_unlock_irqrestore(&wl->wl_lock, flags);
1213} 1213}
1214 1214
1215#define TX_DUMMY_PACKET_SIZE 1400
1216int wl1271_tx_dummy_packet(struct wl1271 *wl) 1215int wl1271_tx_dummy_packet(struct wl1271 *wl)
1217{ 1216{
1218 struct sk_buff *skb = NULL; 1217 unsigned long flags;
1218
1219 spin_lock_irqsave(&wl->wl_lock, flags);
1220 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1221 wl->tx_queue_count++;
1222 spin_unlock_irqrestore(&wl->wl_lock, flags);
1223
1224 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1225 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1226 wl1271_tx_work_locked(wl);
1227
1228 /*
1229 * If the FW TX is busy, TX work will be scheduled by the threaded
1230 * interrupt handler function
1231 */
1232 return 0;
1233}
1234
1235/*
1236 * The size of the dummy packet should be at least 1400 bytes. However, in
1237 * order to minimize the number of bus transactions, aligning it to 512 bytes
1238 * boundaries could be beneficial, performance wise
1239 */
1240#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1241
1242struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
1243{
1244 struct sk_buff *skb;
1219 struct ieee80211_hdr_3addr *hdr; 1245 struct ieee80211_hdr_3addr *hdr;
1220 int ret = 0; 1246 unsigned int dummy_packet_size;
1247
1248 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1249 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1221 1250
1222 skb = dev_alloc_skb( 1251 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
1223 sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) +
1224 TX_DUMMY_PACKET_SIZE);
1225 if (!skb) { 1252 if (!skb) {
1226 wl1271_warning("failed to allocate buffer for dummy packet"); 1253 wl1271_warning("Failed to allocate a dummy packet skb");
1227 ret = -ENOMEM; 1254 return NULL;
1228 goto out;
1229 } 1255 }
1230 1256
1231 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); 1257 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
@@ -1233,29 +1259,22 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl)
1233 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); 1259 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1234 memset(hdr, 0, sizeof(*hdr)); 1260 memset(hdr, 0, sizeof(*hdr));
1235 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | 1261 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
1236 IEEE80211_FCTL_TODS | 1262 IEEE80211_STYPE_NULLFUNC |
1237 IEEE80211_STYPE_NULLFUNC); 1263 IEEE80211_FCTL_TODS);
1238
1239 memcpy(hdr->addr1, wl->bssid, ETH_ALEN);
1240 memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN);
1241 memcpy(hdr->addr3, wl->bssid, ETH_ALEN);
1242 1264
1243 skb_put(skb, TX_DUMMY_PACKET_SIZE); 1265 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
1244 1266
1245 memset(skb->data, 0, TX_DUMMY_PACKET_SIZE);
1246
1247 skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ;
1248 /* Dummy packets require the TID to be management */ 1267 /* Dummy packets require the TID to be management */
1249 skb->priority = WL1271_TID_MGMT; 1268 skb->priority = WL1271_TID_MGMT;
1250 /* CONF_TX_AC_VO */
1251 skb->queue_mapping = 0;
1252 1269
1253 wl1271_op_tx(wl->hw, skb); 1270 /* Initialize all fields that might be used */
1271 skb->queue_mapping = 0;
1272 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
1254 1273
1255out: 1274 return skb;
1256 return ret;
1257} 1275}
1258 1276
1277
1259static struct notifier_block wl1271_dev_notifier = { 1278static struct notifier_block wl1271_dev_notifier = {
1260 .notifier_call = wl1271_dev_notify, 1279 .notifier_call = wl1271_dev_notify,
1261}; 1280};
@@ -3653,11 +3672,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
3653 goto err_hw; 3672 goto err_hw;
3654 } 3673 }
3655 3674
3675 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3676 if (!wl->dummy_packet) {
3677 ret = -ENOMEM;
3678 goto err_aggr;
3679 }
3680
3656 /* Register platform device */ 3681 /* Register platform device */
3657 ret = platform_device_register(wl->plat_dev); 3682 ret = platform_device_register(wl->plat_dev);
3658 if (ret) { 3683 if (ret) {
3659 wl1271_error("couldn't register platform device"); 3684 wl1271_error("couldn't register platform device");
3660 goto err_aggr; 3685 goto err_dummy_packet;
3661 } 3686 }
3662 dev_set_drvdata(&wl->plat_dev->dev, wl); 3687 dev_set_drvdata(&wl->plat_dev->dev, wl);
3663 3688
@@ -3683,6 +3708,9 @@ err_bt_coex_state:
3683err_platform: 3708err_platform:
3684 platform_device_unregister(wl->plat_dev); 3709 platform_device_unregister(wl->plat_dev);
3685 3710
3711err_dummy_packet:
3712 dev_kfree_skb(wl->dummy_packet);
3713
3686err_aggr: 3714err_aggr:
3687 free_pages((unsigned long)wl->aggr_buf, order); 3715 free_pages((unsigned long)wl->aggr_buf, order);
3688 3716
@@ -3702,6 +3730,7 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
3702int wl1271_free_hw(struct wl1271 *wl) 3730int wl1271_free_hw(struct wl1271 *wl)
3703{ 3731{
3704 platform_device_unregister(wl->plat_dev); 3732 platform_device_unregister(wl->plat_dev);
3733 dev_kfree_skb(wl->dummy_packet);
3705 free_pages((unsigned long)wl->aggr_buf, 3734 free_pages((unsigned long)wl->aggr_buf,
3706 get_order(WL1271_AGGR_BUFFER_SIZE)); 3735 get_order(WL1271_AGGR_BUFFER_SIZE));
3707 kfree(wl->plat_dev); 3736 kfree(wl->plat_dev);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index ba69ba7051fa..67245ad396ea 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -219,6 +219,11 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
219 return ret; 219 return ret;
220} 220}
221 221
222static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
223{
224 return wl->dummy_packet == skb;
225}
226
222static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, 227static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
223 u32 extra, struct ieee80211_tx_info *control, 228 u32 extra, struct ieee80211_tx_info *control,
224 u8 hlid) 229 u8 hlid)
@@ -253,7 +258,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
253 ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 258 ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
254 desc->tid = skb->priority; 259 desc->tid = skb->priority;
255 260
256 if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { 261 if (wl12xx_is_dummy_packet(wl, skb)) {
257 /* 262 /*
258 * FW expects the dummy packet to have an invalid session id - 263 * FW expects the dummy packet to have an invalid session id -
259 * any session id that is different than the one set in the join 264 * any session id that is different than the one set in the join
@@ -396,6 +401,10 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
396 memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); 401 memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
397 memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); 402 memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
398 403
404 /* Revert side effects in the dummy packet skb, so it can be reused */
405 if (wl12xx_is_dummy_packet(wl, skb))
406 skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
407
399 return total_len; 408 return total_len;
400} 409}
401 410
@@ -508,10 +517,23 @@ out:
508 517
509static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) 518static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
510{ 519{
520 unsigned long flags;
521 struct sk_buff *skb = NULL;
522
511 if (wl->bss_type == BSS_TYPE_AP_BSS) 523 if (wl->bss_type == BSS_TYPE_AP_BSS)
512 return wl1271_ap_skb_dequeue(wl); 524 skb = wl1271_ap_skb_dequeue(wl);
525 else
526 skb = wl1271_sta_skb_dequeue(wl);
513 527
514 return wl1271_sta_skb_dequeue(wl); 528 if (!skb &&
529 test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
530 skb = wl->dummy_packet;
531 spin_lock_irqsave(&wl->wl_lock, flags);
532 wl->tx_queue_count--;
533 spin_unlock_irqrestore(&wl->wl_lock, flags);
534 }
535
536 return skb;
515} 537}
516 538
517static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) 539static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
@@ -519,7 +541,9 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
519 unsigned long flags; 541 unsigned long flags;
520 int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 542 int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
521 543
522 if (wl->bss_type == BSS_TYPE_AP_BSS) { 544 if (wl12xx_is_dummy_packet(wl, skb)) {
545 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
546 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
523 u8 hlid = wl1271_tx_get_hlid(skb); 547 u8 hlid = wl1271_tx_get_hlid(skb);
524 skb_queue_head(&wl->links[hlid].tx_queue[q], skb); 548 skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
525 549
@@ -628,8 +652,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
628 skb = wl->tx_frames[id]; 652 skb = wl->tx_frames[id];
629 info = IEEE80211_SKB_CB(skb); 653 info = IEEE80211_SKB_CB(skb);
630 654
631 if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { 655 if (wl12xx_is_dummy_packet(wl, skb)) {
632 dev_kfree_skb(skb);
633 wl1271_free_tx_id(wl, id); 656 wl1271_free_tx_id(wl, id);
634 return; 657 return;
635 } 658 }
@@ -764,9 +787,7 @@ void wl1271_tx_reset(struct wl1271 *wl)
764 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", 787 wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
765 skb); 788 skb);
766 789
767 if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { 790 if (!wl12xx_is_dummy_packet(wl, skb)) {
768 dev_kfree_skb(skb);
769 } else {
770 info = IEEE80211_SKB_CB(skb); 791 info = IEEE80211_SKB_CB(skb);
771 info->status.rates[0].idx = -1; 792 info->status.rates[0].idx = -1;
772 info->status.rates[0].count = 0; 793 info->status.rates[0].count = 0;
@@ -792,9 +813,7 @@ void wl1271_tx_reset(struct wl1271 *wl)
792 wl1271_free_tx_id(wl, i); 813 wl1271_free_tx_id(wl, i);
793 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); 814 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
794 815
795 if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { 816 if (!wl12xx_is_dummy_packet(wl, skb)) {
796 dev_kfree_skb(skb);
797 } else {
798 /* 817 /*
799 * Remove private headers before passing the skb to 818 * Remove private headers before passing the skb to
800 * mac80211 819 * mac80211
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index d6b05d980626..fc7835c4cf63 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -42,8 +42,6 @@
42#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) 42#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12)
43#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) 43#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13)
44 44
45#define TX_PKT_TYPE_DUMMY_REQ 5
46
47#define TX_HW_ATTR_OFST_SAVE_RETRIES 0 45#define TX_HW_ATTR_OFST_SAVE_RETRIES 0
48#define TX_HW_ATTR_OFST_HEADER_PAD 1 46#define TX_HW_ATTR_OFST_HEADER_PAD 1
49#define TX_HW_ATTR_OFST_SESSION_COUNTER 2 47#define TX_HW_ATTR_OFST_SESSION_COUNTER 2
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index c7c42b687f5e..1b430d2aec4e 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -356,6 +356,7 @@ enum wl12xx_flags {
356 WL1271_FLAG_FW_TX_BUSY, 356 WL1271_FLAG_FW_TX_BUSY,
357 WL1271_FLAG_AP_STARTED, 357 WL1271_FLAG_AP_STARTED,
358 WL1271_FLAG_IF_INITIALIZED, 358 WL1271_FLAG_IF_INITIALIZED,
359 WL1271_FLAG_DUMMY_PACKET_PENDING,
359}; 360};
360 361
361struct wl1271_link { 362struct wl1271_link {
@@ -461,6 +462,9 @@ struct wl1271 {
461 /* Intermediate buffer, used for packet aggregation */ 462 /* Intermediate buffer, used for packet aggregation */
462 u8 *aggr_buf; 463 u8 *aggr_buf;
463 464
465 /* Reusable dummy packet template */
466 struct sk_buff *dummy_packet;
467
464 /* Network stack work */ 468 /* Network stack work */
465 struct work_struct netstack_work; 469 struct work_struct netstack_work;
466 470