diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/main.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 79 |
1 files changed, 54 insertions, 25 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 1cd396306e7..7dce24c0b33 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) spin_unlock_irqrestore(&wl->wl_lock, flags); } -#define TX_DUMMY_PACKET_SIZE 1400 int wl1271_tx_dummy_packet(struct wl1271 *wl) { - struct sk_buff *skb = NULL; + unsigned long flags; + + spin_lock_irqsave(&wl->wl_lock, flags); + set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); + wl->tx_queue_count++; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + /* The FW is low on RX memory blocks, so send the dummy packet asap */ + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) + wl1271_tx_work_locked(wl); + + /* + * If the FW TX is busy, TX work will be scheduled by the threaded + * interrupt handler function + */ + return 0; +} + +/* + * The size of the dummy packet should be at least 1400 bytes. However, in + * order to minimize the number of bus transactions, aligning it to 512 bytes + * boundaries could be beneficial, performance wise + */ +#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512)) + +struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) +{ + struct sk_buff *skb; struct ieee80211_hdr_3addr *hdr; - int ret = 0; + unsigned int dummy_packet_size; + + dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE - + sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr); - skb = dev_alloc_skb( - sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) + - TX_DUMMY_PACKET_SIZE); + skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE); if (!skb) { - wl1271_warning("failed to allocate buffer for dummy packet"); - ret = -ENOMEM; - goto out; + wl1271_warning("Failed to allocate a dummy packet skb"); + return NULL; } skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); @@ -1233,29 +1259,22 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl) hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_FCTL_TODS | - IEEE80211_STYPE_NULLFUNC); - - memcpy(hdr->addr1, wl->bssid, ETH_ALEN); - memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN); - memcpy(hdr->addr3, wl->bssid, ETH_ALEN); + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); - skb_put(skb, TX_DUMMY_PACKET_SIZE); + memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size); - memset(skb->data, 0, TX_DUMMY_PACKET_SIZE); - - skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ; /* Dummy packets require the TID to be management */ skb->priority = WL1271_TID_MGMT; - /* CONF_TX_AC_VO */ - skb->queue_mapping = 0; - wl1271_op_tx(wl->hw, skb); + /* Initialize all fields that might be used */ + skb->queue_mapping = 0; + memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info)); -out: - return ret; + return skb; } + static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; @@ -3653,11 +3672,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void) goto err_hw; } + wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); + if (!wl->dummy_packet) { + ret = -ENOMEM; + goto err_aggr; + } + /* Register platform device */ ret = platform_device_register(wl->plat_dev); if (ret) { wl1271_error("couldn't register platform device"); - goto err_aggr; + goto err_dummy_packet; } dev_set_drvdata(&wl->plat_dev->dev, wl); @@ -3683,6 +3708,9 @@ err_bt_coex_state: err_platform: platform_device_unregister(wl->plat_dev); +err_dummy_packet: + dev_kfree_skb(wl->dummy_packet); + err_aggr: free_pages((unsigned long)wl->aggr_buf, order); @@ -3702,6 +3730,7 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw); int wl1271_free_hw(struct wl1271 *wl) { platform_device_unregister(wl->plat_dev); + dev_kfree_skb(wl->dummy_packet); free_pages((unsigned long)wl->aggr_buf, get_order(WL1271_AGGR_BUFFER_SIZE)); kfree(wl->plat_dev); |