wl1251: add powersave exit logic for transfers
authorGrazvydas Ignotas <notasas@gmail.com>
Sat, 14 Feb 2015 23:38:39 +0000 (01:38 +0200)
committerGrazvydas Ignotas <notasas@gmail.com>
Fri, 20 Feb 2015 22:05:31 +0000 (00:05 +0200)
Exiting powersave during transfers improves data rates.
Now that mac80211 no longer manages PS, the driver has to do it itself.

drivers/net/wireless/wl1251/main.c
drivers/net/wireless/wl1251/rx.c
drivers/net/wireless/wl1251/sdio.c
drivers/net/wireless/wl1251/tx.c
drivers/net/wireless/wl1251/wl1251.h

index b04da83..e6a1475 100644 (file)
@@ -654,8 +654,9 @@ static void wl1251_ps_work(struct work_struct *work)
                }
        }
 
-       need_ps = wl->psm_requested && !wl->bss_lost;
        have_ps = wl->station_mode == STATION_POWER_SAVE_MODE;
+       need_ps = wl->psm_requested && !wl->bss_lost
+               && wl->rate < wl->ps_rate_threshold;
 
        if (need_ps == have_ps) {
                //wl1251_info("ps: already in mode %d", have_ps);
@@ -674,13 +675,6 @@ static void wl1251_ps_work(struct work_struct *work)
                if (diff < msecs_to_jiffies(3000))
                        wait += msecs_to_jiffies(1000);
 
-               diff = jiffies - wl->last_io_jiffies;
-               if (diff < msecs_to_jiffies(150)) {
-                       //wl1251_info("ps: postponed psm, j %ld", diff);
-                       if (wait < msecs_to_jiffies(150) - diff + 1)
-                               wait = msecs_to_jiffies(150) - diff + 1;
-               }
-
                for (i = 0; i < ARRAY_SIZE(wl->tx_frames); i++) {
                        if (wl->tx_frames[i] != NULL) {
                                //wl1251_error("  frm %d busy", i);
@@ -709,8 +703,7 @@ static void wl1251_ps_work(struct work_struct *work)
        if (ret < 0)
                goto out_sleep;
 
-       //wl1251_info("psm %d, j %ld, d %ld", need_ps,
-       //      jiffies - wl->last_io_jiffies);
+       // wl1251_info("psm %d, r %u", need_ps, wl->rate);
 
 out_sleep:
        wl1251_ps_elp_sleep(wl);
@@ -1689,6 +1682,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
        wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
        wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD;
        wl->vif = NULL;
+       wl->ps_rate_threshold = 100000;
 
        for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
                wl->tx_frames[i] = NULL;
index e7781c7..79a119d 100644 (file)
@@ -186,8 +186,6 @@ static void wl1251_rx_body(struct wl1251 *wl,
 
        if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
                beacon = 1;
-       else
-               wl->last_io_jiffies = jiffies;
 
        wl1251_rx_status(wl, desc, &status, beacon);
 
@@ -196,6 +194,8 @@ static void wl1251_rx_body(struct wl1251 *wl,
 
        memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
        ieee80211_rx_ni(wl->hw, skb);
+
+       wl1251_update_rate(wl, length);
 }
 
 static void wl1251_rx_ack(struct wl1251 *wl)
index 7c55b3e..d141d83 100644 (file)
@@ -239,13 +239,42 @@ wl1251_set_long_doze(struct device *dev, struct device_attribute *attr,
        wl->long_doze_mode = !!val;
        return count;
 }
-static DEVICE_ATTR(long_doze_mode, S_IRUGO | S_IWUSR,
-       wl1251_show_long_doze, wl1251_set_long_doze);
+
+static ssize_t
+wl1251_show_ps_rate_thr(struct device *dev, struct device_attribute *attr,
+       char *buf)
+{
+       struct wl1251 *wl = dev_get_drvdata(dev);
+       return sprintf(buf, "%u\n", wl->ps_rate_threshold);
+}
+
+static ssize_t
+wl1251_set_ps_rate_thr(struct device *dev, struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       struct wl1251 *wl = dev_get_drvdata(dev);
+       unsigned int val;
+       int ret;
+
+       ret = kstrtouint(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       wl->ps_rate_threshold = val;
+       return count;
+}
+
+static struct device_attribute wl1251_attrs[] = {
+       __ATTR(long_doze_mode, S_IRUGO | S_IWUGO,
+               wl1251_show_long_doze, wl1251_set_long_doze),
+       __ATTR(ps_rate_threshold, S_IRUGO | S_IWUGO,
+               wl1251_show_ps_rate_thr, wl1251_set_ps_rate_thr),
+};
 
 static int wl1251_sdio_probe(struct sdio_func *func,
                             const struct sdio_device_id *id)
 {
-       int ret;
+       int ret, t;
        struct wl1251 *wl;
        struct ieee80211_hw *hw;
        struct wl1251_sdio *wl_sdio;
@@ -316,9 +345,15 @@ static int wl1251_sdio_probe(struct sdio_func *func,
 
        sdio_set_drvdata(func, wl);
 
-       ret = device_create_file(&func->dev, &dev_attr_long_doze_mode);
-       if (ret)
-               goto out_free_irq;
+       for (t = 0; t < ARRAY_SIZE(wl1251_attrs); t++) {
+               ret = device_create_file(&func->dev, &wl1251_attrs[t]);
+               if (ret) {
+                       while (--t >= 0)
+                               device_remove_file(&func->dev,
+                                                  &wl1251_attrs[t]);
+                       goto out_free_irq;
+               }
+       }
 
        /* Tell PM core that we don't need the card to be powered now */
        pm_runtime_put_noidle(&func->dev);
@@ -343,11 +378,13 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func)
 {
        struct wl1251 *wl = sdio_get_drvdata(func);
        struct wl1251_sdio *wl_sdio = wl->if_priv;
+       int t;
 
        /* Undo decrement done above in wl1251_probe */
        pm_runtime_get_noresume(&func->dev);
 
-       device_remove_file(&func->dev, &dev_attr_long_doze_mode);
+       for (t = 0; t < ARRAY_SIZE(wl1251_attrs); t++)
+               device_remove_file(&func->dev, &wl1251_attrs[t]);
 
        if (wl->irq)
                free_irq(wl->irq, wl);
index 6170a3b..90379a8 100644 (file)
@@ -256,6 +256,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
 
        wl1251_mem_write(wl, addr, skb->data, len);
 
+       wl1251_update_rate(wl, len);
        wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x "
                     "queue %d", tx_hdr->id, skb, tx_hdr->length,
                     tx_hdr->rate, tx_hdr->xmit_queue);
@@ -556,7 +557,6 @@ void wl1251_tx_complete(struct wl1251 *wl)
        }
 
        wl->next_tx_complete = result_index;
-       wl->last_io_jiffies = jiffies;
 }
 
 /* caller must hold wl->mutex */
index 8b4efcd..eca30a0 100644 (file)
@@ -406,12 +406,17 @@ struct wl1251 {
 
        /* PS hacks.. */
        unsigned long ps_change_jiffies;
-       unsigned long last_io_jiffies;
        /* when we had PS "unfriendly" event like sync loss */
        unsigned long last_no_ps_jiffies[2];
        struct delayed_work ps_work;
        bool bss_lost;
        bool ps_transitioning;
+
+       /* rate accounting */
+       u32 ps_rate_threshold;
+       unsigned long rate_jiffies;
+       u32 rate_counter;
+       u32 rate;
 };
 
 int wl1251_plt_start(struct wl1251 *wl);
@@ -430,6 +435,29 @@ static inline void wl1251_no_ps_event(struct wl1251 *wl)
        wl->last_no_ps_jiffies[1] = jiffies;
 }
 
+static inline void wl1251_update_rate(struct wl1251 *wl, u32 length)
+{
+       bool in_psm, rate_above_eq;
+       unsigned long diff;
+
+       diff = jiffies - wl->rate_jiffies;
+       if (diff >= msecs_to_jiffies(2000)) {
+               wl->rate_jiffies = jiffies;
+               wl->rate = wl->rate_counter = 0;
+       }
+       else if (diff >= msecs_to_jiffies(1000)) {
+               wl->rate_jiffies += msecs_to_jiffies(1000);
+               wl->rate = wl->rate_counter;
+               wl->rate_counter = 0;
+       }
+       wl->rate_counter += length;
+
+       in_psm = wl->station_mode == STATION_POWER_SAVE_MODE;
+       rate_above_eq = wl->rate >= wl->ps_rate_threshold;
+       if (in_psm == rate_above_eq)
+               ieee80211_queue_delayed_work(wl->hw, &wl->ps_work, 0);
+}
+
 #define DEFAULT_HW_GEN_MODULATION_TYPE    CCK_LONG /* Long Preamble */
 #define DEFAULT_HW_GEN_TX_RATE          RATE_2MBPS
 #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */