aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/main.c
diff options
context:
space:
mode:
authorIdo Yariv <ido@wizery.com>2011-03-31 10:06:59 +0200
committerLuciano Coelho <coelho@ti.com>2011-04-19 16:49:19 +0300
commit990f5de7384f9e5922e4c7c7572cbf4f29a9441e (patch)
tree3294cf7224a4aadfefc35660cbe5406f01ab6c94 /drivers/net/wireless/wl12xx/main.c
parent0da13da767cd568c1fe2a7b5b936e86e521b5ae7 (diff)
downloadkernel_samsung_smdk4412-990f5de7384f9e5922e4c7c7572cbf4f29a9441e.zip
kernel_samsung_smdk4412-990f5de7384f9e5922e4c7c7572cbf4f29a9441e.tar.gz
kernel_samsung_smdk4412-990f5de7384f9e5922e4c7c7572cbf4f29a9441e.tar.bz2
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/net/wireless/wl12xx/main.c')
-rw-r--r--drivers/net/wireless/wl12xx/main.c79
1 files changed, 54 insertions, 25 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 1cd3963..7dce24c 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);