From 49a086ec91d906f90799a4937300a60107c27df4 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Sun, 15 Feb 2015 01:38:39 +0200 Subject: [PATCH] wl1251: add powersave exit logic for transfers 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 | 14 +++----- drivers/net/wireless/wl1251/rx.c | 4 +-- drivers/net/wireless/wl1251/sdio.c | 51 ++++++++++++++++++++++++---- drivers/net/wireless/wl1251/tx.c | 2 +- drivers/net/wireless/wl1251/wl1251.h | 30 +++++++++++++++- 5 files changed, 80 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index b04da83cfb6b..e6a14754dd06 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -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; diff --git a/drivers/net/wireless/wl1251/rx.c b/drivers/net/wireless/wl1251/rx.c index e7781c7b242d..79a119dad440 100644 --- a/drivers/net/wireless/wl1251/rx.c +++ b/drivers/net/wireless/wl1251/rx.c @@ -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) diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index 7c55b3e32791..d141d838c800 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c @@ -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); diff --git a/drivers/net/wireless/wl1251/tx.c b/drivers/net/wireless/wl1251/tx.c index 6170a3b0029a..90379a87b78b 100644 --- a/drivers/net/wireless/wl1251/tx.c +++ b/drivers/net/wireless/wl1251/tx.c @@ -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 */ diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index 8b4efcd3bfb5..eca30a0884c5 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -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 */ -- 2.39.2