Exiting powersave during transfers improves data rates.
Now that mac80211 no longer manages PS, the driver has to do it itself.
}
}
- 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);
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);
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);
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;
if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
beacon = 1;
- else
- wl->last_io_jiffies = jiffies;
wl1251_rx_status(wl, desc, &status, beacon);
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)
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;
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);
{
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);
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);
}
wl->next_tx_complete = result_index;
- wl->last_io_jiffies = jiffies;
}
/* caller must hold wl->mutex */
/* 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);
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 */