wl1271: Clean up firmware block allocation calculation
[deliverable/linux.git] / drivers / net / wireless / wl12xx / wl1271_tx.c
index 00af065c77c20e14b5dc5f79dc86ef092054515d..d3ed63e92cf4fa5fa7ce23d938eff996de64f67c 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/module.h>
 
 #include "wl1271.h"
-#include "wl1271_spi.h"
+#include "wl1271_io.h"
 #include "wl1271_reg.h"
 #include "wl1271_ps.h"
 #include "wl1271_tx.h"
@@ -46,7 +46,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
 {
        struct wl1271_tx_hw_descr *desc;
        u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
-       u32 total_blocks, excluded;
+       u32 total_blocks;
        int id, ret = -EBUSY;
 
        /* allocate free identifier for the packet */
@@ -56,12 +56,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
 
        /* approximate the number of blocks required for this packet
           in the firmware */
-       /* FIXME: try to figure out what is done here and make it cleaner */
-       total_blocks = (total_len + 20) >> TX_HW_BLOCK_SHIFT_DIV;
-       excluded = (total_blocks << 2) + ((total_len + 20) & 0xff) + 34;
-       total_blocks += (excluded > 252) ? 2 : 1;
-       total_blocks += TX_HW_BLOCK_SPARE;
-
+       total_blocks = total_len + TX_HW_BLOCK_SIZE - 1;
+       total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE;
        if (total_blocks <= wl->tx_blocks_available) {
                desc = (struct wl1271_tx_hw_descr *)skb_push(
                        skb, total_len - skb->len);
@@ -86,8 +82,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
 static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
                              u32 extra, struct ieee80211_tx_info *control)
 {
+       struct timespec ts;
        struct wl1271_tx_hw_descr *desc;
-       int pad;
+       int pad, ac;
+       s64 hosttime;
        u16 tx_attr;
 
        desc = (struct wl1271_tx_hw_descr *) skb->data;
@@ -101,15 +99,18 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
        }
 
        /* configure packet life time */
-       desc->start_time = cpu_to_le32(jiffies_to_usecs(jiffies) -
-                                      wl->time_offset);
+       getnstimeofday(&ts);
+       hosttime = (timespec_to_ns(&ts) >> 10);
+       desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
        desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
 
        /* configure the tx attributes */
        tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
-       /* FIXME: do we know the packet priority? can we identify mgmt
-          packets, and use max prio for them at least? */
-       desc->tid = 0;
+
+       /* queue */
+       ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+       desc->tid = wl1271_tx_ac_to_tid(ac);
+
        desc->aid = TX_HW_DEFAULT_AID;
        desc->reserved = 0;
 
@@ -121,6 +122,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
        pad = pad - skb->len;
        tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
 
+       /* if the packets are destined for AP (have a STA entry) send them
+          with AP rate policies, otherwise use default basic rates */
+       if (control->control.sta)
+               tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY;
+
        desc->tx_attr = cpu_to_le16(tx_attr);
 
        wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
@@ -158,11 +164,10 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
        len = WL1271_TX_ALIGN(skb->len);
 
        /* perform a fixed address block write with the packet */
-       wl1271_spi_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
+       wl1271_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
 
        /* write packet new counter into the write access register */
        wl->tx_packets_count++;
-       wl1271_spi_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
 
        desc = (struct wl1271_tx_hw_descr *) skb->data;
        wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
@@ -196,6 +201,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
                        ret = wl1271_cmd_set_default_wep_key(wl, idx);
                        if (ret < 0)
                                return ret;
+                       wl->default_key = idx;
                }
        }
 
@@ -214,47 +220,77 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
        return ret;
 }
 
+static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
+{
+       struct ieee80211_supported_band *band;
+       u32 enabled_rates = 0;
+       int bit;
+
+       band = wl->hw->wiphy->bands[wl->band];
+       for (bit = 0; bit < band->n_bitrates; bit++) {
+               if (rate_set & 0x1)
+                       enabled_rates |= band->bitrates[bit].hw_value;
+               rate_set >>= 1;
+       }
+
+       return enabled_rates;
+}
+
 void wl1271_tx_work(struct work_struct *work)
 {
        struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
        struct sk_buff *skb;
        bool woken_up = false;
+       u32 sta_rates = 0;
+       u32 prev_tx_packets_count;
        int ret;
 
+       /* check if the rates supported by the AP have changed */
+       if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED,
+                                       &wl->flags))) {
+               unsigned long flags;
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               sta_rates = wl->sta_rate_set;
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
+       }
+
        mutex_lock(&wl->mutex);
 
        if (unlikely(wl->state == WL1271_STATE_OFF))
                goto out;
 
+       prev_tx_packets_count = wl->tx_packets_count;
+
+       /* if rates have changed, re-configure the rate policy */
+       if (unlikely(sta_rates)) {
+               wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
+               wl1271_acx_rate_policies(wl);
+       }
+
        while ((skb = skb_dequeue(&wl->tx_queue))) {
                if (!woken_up) {
                        ret = wl1271_ps_elp_wakeup(wl, false);
                        if (ret < 0)
-                               goto out;
+                               goto out_ack;
                        woken_up = true;
                }
 
                ret = wl1271_tx_frame(wl, skb);
                if (ret == -EBUSY) {
-                       /* firmware buffer is full, stop queues */
-                       wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, "
-                                    "stop queues");
-                       ieee80211_stop_queues(wl->hw);
-                       wl->tx_queue_stopped = true;
+                       /* firmware buffer is full, lets stop transmitting. */
                        skb_queue_head(&wl->tx_queue, skb);
-                       goto out;
+                       goto out_ack;
                } else if (ret < 0) {
                        dev_kfree_skb(skb);
-                       goto out;
-               } else if (wl->tx_queue_stopped) {
-                       /* firmware buffer has space, restart queues */
-                       wl1271_debug(DEBUG_TX,
-                                    "complete_packet: waking queues");
-                       ieee80211_wake_queues(wl->hw);
-                       wl->tx_queue_stopped = false;
+                       goto out_ack;
                }
        }
 
+out_ack:
+       /* interrupt the firmware with the new packets */
+       if (prev_tx_packets_count != wl->tx_packets_count)
+               wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+
 out:
        if (woken_up)
                wl1271_ps_elp_sleep(wl);
@@ -271,7 +307,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        int id = result->id;
 
        /* check for id legality */
-       if (id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL) {
+       if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) {
                wl1271_warning("TX result illegal id: %d", id);
                return;
        }
@@ -326,23 +362,29 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 }
 
 /* Called upon reception of a TX complete interrupt */
-void wl1271_tx_complete(struct wl1271 *wl, u32 count)
+void wl1271_tx_complete(struct wl1271 *wl)
 {
        struct wl1271_acx_mem_map *memmap =
                (struct wl1271_acx_mem_map *)wl->target_mem_map;
+       u32 count, fw_counter;
        u32 i;
 
-       wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
-
        /* read the tx results from the chipset */
-       wl1271_spi_read(wl, le32_to_cpu(memmap->tx_result),
-                       wl->tx_res_if, sizeof(*wl->tx_res_if), false);
+       wl1271_read(wl, le32_to_cpu(memmap->tx_result),
+                   wl->tx_res_if, sizeof(*wl->tx_res_if), false);
+       fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter);
+
+       /* write host counter to chipset (to ack) */
+       wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
+                      offsetof(struct wl1271_tx_hw_res_if,
+                               tx_result_host_counter), fw_counter);
+
+       count = fw_counter - wl->tx_results_count;
+       wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
 
        /* verify that the result buffer is not getting overrun */
-       if (count > TX_HW_RESULT_QUEUE_LEN) {
+       if (unlikely(count > TX_HW_RESULT_QUEUE_LEN))
                wl1271_warning("TX result overflow from chipset: %d", count);
-               count = TX_HW_RESULT_QUEUE_LEN;
-       }
 
        /* process the results */
        for (i = 0; i < count; i++) {
@@ -356,11 +398,18 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
                wl->tx_results_count++;
        }
 
-       /* write host counter to chipset (to ack) */
-       wl1271_spi_write32(wl, le32_to_cpu(memmap->tx_result) +
-                          offsetof(struct wl1271_tx_hw_res_if,
-                                   tx_result_host_counter),
-                          le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
+       if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
+           skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) {
+               unsigned long flags;
+
+               /* firmware buffer has space, restart queues */
+               wl1271_debug(DEBUG_TX, "tx_complete: waking queues");
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               ieee80211_wake_queues(wl->hw);
+               clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
+               ieee80211_queue_work(wl->hw, &wl->tx_work);
+       }
 }
 
 /* caller must hold wl->mutex */
This page took 0.029173 seconds and 5 git commands to generate.