aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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