wl12xx: 1281/1283 support - Add dummy packet support
authorShahar Levi <shahar_levi@ti.com>
Sun, 6 Mar 2011 14:32:14 +0000 (16:32 +0200)
committerLuciano Coelho <coelho@ti.com>
Tue, 19 Apr 2011 13:49:01 +0000 (16:49 +0300)
Support sending dummy packet to wl128x FW as results of
dummy packet event. That is part of dynamic TX mem blocks mechanism.

Only send dummy packet when not in AP mode.

[Even though the DUMMY_PACKET_EVENT_ID and the
STA_REMOVE_COMPLETE_EVENT_ID events are defined to the same value, we
need to treat them separately in the code.  Keep the check and enable
STA_REMOVE_COMPLETE_EVENT_ID for AP mode and DUMMY_PACKET_EVENT_ID for
STA.  Moved one warning to a cleaner place.  Use WL1271_TID_MGMT for
dummy packets -- Luca]

Signed-off-by: Shahar Levi <shahar_levi@ti.com>
Reviewed-by: Luciano Coelho <coelho@ti.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/wl12xx/boot.c
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/event.h
drivers/net/wireless/wl12xx/io.h
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.h

index 9d742c1e75a920ee4d6269d0b82be882d32e7366..34bf2fe47dc77a824e8b372912b00275bfa268ae 100644 (file)
@@ -482,6 +482,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
 
        if (wl->bss_type == BSS_TYPE_AP_BSS)
                wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
+       else
+               wl->event_mask |= DUMMY_PACKET_EVENT_ID;
 
        ret = wl1271_event_unmask(wl);
        if (ret < 0) {
index 1b170c5cc595f22dde0b1c494b7276059e278960..413d901985feeba5ade8f2787a6994feaecc4169 100644 (file)
@@ -228,6 +228,12 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                        wl1271_event_rssi_trigger(wl, mbox);
        }
 
+       if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) {
+               wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
+               if (wl->vif)
+                       wl1271_tx_dummy_packet(wl);
+       }
+
        if (wl->vif && beacon_loss)
                ieee80211_connection_loss(wl->vif);
 
index 0e80886f3031fe740fa74b1ff4faaa4294f4e387..b6cf06e565a470aa65c4ab501489821007223ac0 100644 (file)
@@ -59,7 +59,10 @@ enum {
        BSS_LOSE_EVENT_ID                        = BIT(18),
        REGAINED_BSS_EVENT_ID                    = BIT(19),
        ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID    = BIT(20),
-       STA_REMOVE_COMPLETE_EVENT_ID             = BIT(21), /* AP */
+       /* STA: dummy paket for dynamic mem blocks */
+       DUMMY_PACKET_EVENT_ID                    = BIT(21),
+       /* AP: STA remove complete */
+       STA_REMOVE_COMPLETE_EVENT_ID             = BIT(21),
        SOFT_GEMINI_SENSE_EVENT_ID               = BIT(22),
        SOFT_GEMINI_PREDICTION_EVENT_ID          = BIT(23),
        SOFT_GEMINI_AVALANCHE_EVENT_ID           = BIT(24),
index 84454f6d81697280db897860903ce3047871a717..e6199eb519360e4d1710adc63d873d925d21c4c9 100644 (file)
@@ -170,5 +170,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void);
 int wl1271_free_hw(struct wl1271 *wl);
 irqreturn_t wl1271_irq(int irq, void *data);
 bool wl1271_set_block_size(struct wl1271 *wl);
+int wl1271_tx_dummy_packet(struct wl1271 *wl);
 
 #endif
index 3c381ceadb98f7d62486551a720d056eb598ca9e..54ac6757c39ba105843bf6782ad399ad26f17a4f 100644 (file)
@@ -1174,6 +1174,48 @@ 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;
+       struct ieee80211_hdr_3addr *hdr;
+       int ret = 0;
+
+       skb = dev_alloc_skb(
+               sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) +
+               TX_DUMMY_PACKET_SIZE);
+       if (!skb) {
+               wl1271_warning("failed to allocate buffer for dummy packet");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
+
+       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);
+
+       skb_put(skb, TX_DUMMY_PACKET_SIZE);
+
+       memset(skb->data, 0, TX_DUMMY_PACKET_SIZE);
+
+       skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ;
+       /* CONF_TX_AC_VO */
+       skb->queue_mapping = 0;
+
+       wl1271_op_tx(wl->hw, skb);
+
+out:
+       return ret;
+}
+
 static struct notifier_block wl1271_dev_notifier = {
        .notifier_call = wl1271_dev_notify,
 };
index afc8505abeb6cf3066b0182897497fabb447cc1b..75222a6812962542b7cc96de5a1ad143884adac6 100644 (file)
@@ -215,13 +215,29 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
        else
                desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
 
-       /* configure the tx attributes */
-       tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
-
        /* queue (we use same identifiers for tid's and ac's */
        ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
        desc->tid = ac;
 
+       if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+               /*
+                * FW expects the dummy packet to have an invalid session id -
+                * any session id that is different than the one set in the join
+                */
+               tx_attr = ((~wl->session_counter) <<
+                          TX_HW_ATTR_OFST_SESSION_COUNTER) &
+                          TX_HW_ATTR_SESSION_COUNTER;
+
+               tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
+
+               /* Dummy packets require the TID to be management */
+               desc->tid = WL1271_TID_MGMT;
+       } else {
+               /* configure the tx attributes */
+               tx_attr =
+                       wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
+       }
+
        if (wl->bss_type != BSS_TYPE_AP_BSS) {
                desc->aid = hlid;
 
@@ -587,6 +603,12 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        skb = wl->tx_frames[id];
        info = IEEE80211_SKB_CB(skb);
 
+       if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+               dev_kfree_skb(skb);
+               wl1271_free_tx_id(wl, id);
+               return;
+       }
+
        /* update the TX status info */
        if (result->status == TX_SUCCESS) {
                if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
@@ -716,10 +738,15 @@ void wl1271_tx_reset(struct wl1271 *wl)
                        while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
                                wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
                                             skb);
-                               info = IEEE80211_SKB_CB(skb);
-                               info->status.rates[0].idx = -1;
-                               info->status.rates[0].count = 0;
-                               ieee80211_tx_status(wl->hw, skb);
+
+                               if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+                                       dev_kfree_skb(skb);
+                               } else {
+                                       info = IEEE80211_SKB_CB(skb);
+                                       info->status.rates[0].idx = -1;
+                                       info->status.rates[0].count = 0;
+                                       ieee80211_tx_status(wl->hw, skb);
+                               }
                        }
                }
        }
@@ -740,21 +767,29 @@ void wl1271_tx_reset(struct wl1271 *wl)
                wl1271_free_tx_id(wl, i);
                wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
 
-               /* Remove private headers before passing the skb to mac80211 */
-               info = IEEE80211_SKB_CB(skb);
-               skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
-               if (info->control.hw_key &&
-                   info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
-                       int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-                       memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data,
-                               hdrlen);
-                       skb_pull(skb, WL1271_TKIP_IV_SPACE);
-               }
+               if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+                       dev_kfree_skb(skb);
+               } else {
+                       /*
+                        * Remove private headers before passing the skb to
+                        * mac80211
+                        */
+                       info = IEEE80211_SKB_CB(skb);
+                       skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+                       if (info->control.hw_key &&
+                           info->control.hw_key->cipher ==
+                           WLAN_CIPHER_SUITE_TKIP) {
+                               int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+                               memmove(skb->data + WL1271_TKIP_IV_SPACE,
+                                       skb->data, hdrlen);
+                               skb_pull(skb, WL1271_TKIP_IV_SPACE);
+                       }
 
-               info->status.rates[0].idx = -1;
-               info->status.rates[0].count = 0;
+                       info->status.rates[0].idx = -1;
+                       info->status.rates[0].count = 0;
 
-               ieee80211_tx_status(wl->hw, skb);
+                       ieee80211_tx_status(wl->hw, skb);
+               }
        }
 }
 
index e31317717ab2f755da22b2cf1e2ffddf7368e8eb..6f45e9108d9a6eccc9a8c0f5a3ad7e4e99d24a7d 100644 (file)
@@ -41,6 +41,9 @@
                                          BIT(8) | BIT(9))
 #define TX_HW_ATTR_LAST_WORD_PAD         (BIT(10) | BIT(11))
 #define TX_HW_ATTR_TX_CMPLT_REQ          BIT(12)
+#define TX_HW_ATTR_TX_DUMMY_REQ          BIT(13)
+
+#define TX_PKT_TYPE_DUMMY_REQ            5
 
 #define TX_HW_ATTR_OFST_SAVE_RETRIES     0
 #define TX_HW_ATTR_OFST_HEADER_PAD       1
@@ -55,6 +58,9 @@
 #define WL1271_TX_ALIGN_TO 4
 #define WL1271_TKIP_IV_SPACE 4
 
+/* Used for management frames and dummy packets */
+#define WL1271_TID_MGMT 7
+
 struct wl127x_tx_mem {
        /*
         * Number of extra memory blocks to allocate for this packet