Hi,
I have made the following changes to kernel-adaptation-n900 in project
Trunk:Testing. Please review and accept ASAP.
Thank You,
Marko Saukko
[This message was auto-generated]
---
Request #16720:
submit: devel:devices:n900/kernel-adaptation-n900(r28) ->
Trunk:Testing/kernel-adaptation-n900
Message:
* Thu Apr 21 2011 Kimmo Jukarainen<[email protected]> -
2.6.37
- Add patches to support wl1251 idle mode, reducing power consumption when
the wlan interface is up, but not associated with a wlan ap (BMC#11242).
(forwarded request 16719 from kimju)
State: new 2011-04-21T07:30:08 marko.saukko
Comment: None
changes files:
--------------
--- kernel.changes
+++ kernel.changes
@@ -0,0 +1,4 @@
+* Thu Apr 21 2011 Kimmo Jukarainen<[email protected]> - 2.6.37
+- Add patches to support wl1251 idle mode, reducing power consumption when
+ the wlan interface is up, but not associated with a wlan ap (BMC#11242).
+
new:
----
linux-2.6.39-0001-wl1251-enable-beacon-early-termination-while-in-powe.patch
linux-2.6.39-0002-wl1251-implement-connection-quality-monitoring.patch
linux-2.6.39-0003-wl1251-remove-wl1251_ps_set_elp-function.patch
linux-2.6.39-0004-wl1251-fix-elp_work-race-condition.patch
linux-2.6.39-0005-wl1251-Prepare-for-idle-mode-support.patch
linux-2.6.39-0006-wl1251-Add-support-for-idle-mode.patch
spec files:
-----------
--- kernel-adaptation-n900.spec
+++ kernel-adaptation-n900.spec
@@ -355,6 +355,14 @@
Patch388:
linux-2.6-dvfs-0030-OMAP3-cpufreq-Use-dpll1_ck-clock-instead-of-arm_fck-.patch
Patch389:
linux-2.6-dvfs-0032-rx51-add-board-OPP-init-to-disable-125MHz-from-avail.patch
+# wl1251 idle mode
+Patch390:
linux-2.6.39-0001-wl1251-enable-beacon-early-termination-while-in-powe.patch
+Patch391:
linux-2.6.39-0002-wl1251-implement-connection-quality-monitoring.patch
+Patch392: linux-2.6.39-0003-wl1251-remove-wl1251_ps_set_elp-function.patch
+Patch393: linux-2.6.39-0004-wl1251-fix-elp_work-race-condition.patch
+Patch394: linux-2.6.39-0005-wl1251-Prepare-for-idle-mode-support.patch
+Patch395: linux-2.6.39-0006-wl1251-Add-support-for-idle-mode.patch
+
#
# End of the Nokia N900 patches
#
@@ -846,6 +854,20 @@
#
linux-2.6-dvfs-0032-rx51-add-board-OPP-init-to-disable-125MHz-from-avail.patch
%patch389 -p1
+# wl1251 idle mode
+# linux-2.6.39-0001-wl1251-enable-beacon-early-termination-while-in-powe.patch
+%patch390 -p1
+# linux-2.6.39-0002-wl1251-implement-connection-quality-monitoring.patch
+%patch391 -p1
+# linux-2.6.39-0003-wl1251-remove-wl1251_ps_set_elp-function.patch
+%patch392 -p1
+# linux-2.6.39-0004-wl1251-fix-elp_work-race-condition.patch
+%patch393 -p1
+# linux-2.6.39-0005-wl1251-Prepare-for-idle-mode-support.patch
+%patch394 -p1
+# linux-2.6.39-0006-wl1251-Add-support-for-idle-mode.patch
+%patch395 -p1
+
#
# End of the Nokia N900 patches
#
other changes:
--------------
++++++
linux-2.6.39-0001-wl1251-enable-beacon-early-termination-while-in-powe.patch
(new)
--- linux-2.6.39-0001-wl1251-enable-beacon-early-termination-while-in-powe.patch
+++ linux-2.6.39-0001-wl1251-enable-beacon-early-termination-while-in-powe.patch
+From 467ecdc9c4668f8fab9b490d105e9e430dc2d428 Mon Sep 17 00:00:00 2001
+From: David Gnedt<[email protected]>
+Date: Sun, 30 Jan 2011 20:10:57 +0100
+Subject: [PATCH 1/6] wl1251: enable beacon early termination while in
power-saving mode
+
+Port the beacon early termination feature from wl1251 driver version
+included in the Maemo Fremantle kernel.
+It is enabled when going to power-saving mode and disabled when leaving
+power-saving mode.
+
+Signed-off-by: David Gnedt<[email protected]>
+Acked-by: Kalle Valo<[email protected]>
+Signed-off-by: John W. Linville<[email protected]>
+---
+ drivers/net/wireless/wl1251/acx.c | 28 ++++++++++++++++++++++++++++
+ drivers/net/wireless/wl1251/acx.h | 27 +++++++++++++++++++++++++++
+ drivers/net/wireless/wl1251/ps.c | 11 +++++++++++
+ drivers/net/wireless/wl1251/wl1251.h | 2 ++
+ 4 files changed, 68 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/wireless/wl1251/acx.c
b/drivers/net/wireless/wl1251/acx.c
+index 64a0214..8c94366 100644
+--- a/drivers/net/wireless/wl1251/acx.c
++++ b/drivers/net/wireless/wl1251/acx.c
+@@ -978,6 +978,34 @@ out:
+ return ret;
+ }
+
++int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode,
++ u8 max_consecutive)
++{
++ struct wl1251_acx_bet_enable *acx;
++ int ret;
++
++ wl1251_debug(DEBUG_ACX, "acx bet enable");
++
++ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
++ if (!acx) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ acx->enable = mode;
++ acx->max_consecutive = max_consecutive;
++
++ ret = wl1251_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx));
++ if (ret< 0) {
++ wl1251_warning("wl1251 acx bet enable failed: %d", ret);
++ goto out;
++ }
++
++out:
++ kfree(acx);
++ return ret;
++}
++
+ int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+ u8 aifs, u16 txop)
+ {
+diff --git a/drivers/net/wireless/wl1251/acx.h
b/drivers/net/wireless/wl1251/acx.h
+index e54b21a..7c6ffec 100644
+--- a/drivers/net/wireless/wl1251/acx.h
++++ b/drivers/net/wireless/wl1251/acx.h
+@@ -1164,6 +1164,31 @@ struct wl1251_acx_wr_tbtt_and_dtim {
+ u8 padding;
+ } __packed;
+
++enum wl1251_acx_bet_mode {
++ WL1251_ACX_BET_DISABLE = 0,
++ WL1251_ACX_BET_ENABLE = 1,
++};
++
++struct wl1251_acx_bet_enable {
++ struct acx_header header;
++
++ /*
++ * Specifies if beacon early termination procedure is enabled or
++ * disabled, see enum wl1251_acx_bet_mode.
++ */
++ u8 enable;
++
++ /*
++ * Specifies the maximum number of consecutive beacons that may be
++ * early terminated. After this number is reached at least one full
++ * beacon must be correctly received in FW before beacon ET
++ * resumes. Range 0 - 255.
++ */
++ u8 max_consecutive;
++
++ u8 padding[2];
++} __packed;
++
+ struct wl1251_acx_ac_cfg {
+ struct acx_header header;
+
+@@ -1401,6 +1426,8 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
+ int wl1251_acx_rate_policies(struct wl1251 *wl);
+ int wl1251_acx_mem_cfg(struct wl1251 *wl);
+ int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
++int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode,
++ u8 max_consecutive);
+ int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+ u8 aifs, u16 txop);
+ int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
+diff --git a/drivers/net/wireless/wl1251/ps.c
b/drivers/net/wireless/wl1251/ps.c
+index 5ed47c8..9ba23ed 100644
+--- a/drivers/net/wireless/wl1251/ps.c
++++ b/drivers/net/wireless/wl1251/ps.c
+@@ -153,6 +153,11 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum
wl1251_cmd_ps_mode mode)
+ if (ret< 0)
+ return ret;
+
++ ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_ENABLE,
++ WL1251_DEFAULT_BET_CONSECUTIVE);
++ if (ret< 0)
++ return ret;
++
+ ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ if (ret< 0)
+ return ret;
+@@ -170,6 +175,12 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum
wl1251_cmd_ps_mode mode)
+ if (ret< 0)
+ return ret;
+
++ /* disable BET */
++ ret = wl1251_acx_bet_enable(wl, WL1251_ACX_BET_DISABLE,
++ WL1251_DEFAULT_BET_CONSECUTIVE);
++ if (ret< 0)
++ return ret;
++
+ /* disable beacon filtering */
+ ret = wl1251_acx_beacon_filter_opt(wl, false);
+ if (ret< 0)
+diff --git a/drivers/net/wireless/wl1251/wl1251.h
b/drivers/net/wireless/wl1251/wl1251.h
+index e113d4c..acc4c75 100644
+--- a/drivers/net/wireless/wl1251/wl1251.h
++++ b/drivers/net/wireless/wl1251/wl1251.h
+@@ -409,6 +409,8 @@ void wl1251_disable_interrupts(struct wl1251 *wl);
+
+ #define WL1251_DEFAULT_CHANNEL 0
+
++#define WL1251_DEFAULT_BET_CONSECUTIVE 10
++
+ #define CHIP_ID_1251_PG10 (0x7010101)
+ #define CHIP_ID_1251_PG11 (0x7020101)
+ #define CHIP_ID_1251_PG12 (0x7030101)
+--
+1.7.0.4
+
++++++ linux-2.6.39-0002-wl1251-implement-connection-quality-monitoring.patch
(new)
--- linux-2.6.39-0002-wl1251-implement-connection-quality-monitoring.patch
+++ linux-2.6.39-0002-wl1251-implement-connection-quality-monitoring.patch
+From 3fa981fcf3a045389700e3de7fbc304909b76352 Mon Sep 17 00:00:00 2001
+From: David Gnedt<[email protected]>
+Date: Sun, 30 Jan 2011 20:11:00 +0100
+Subject: [PATCH 2/6] wl1251: implement connection quality monitoring
+
+Implement connection quality monitoring similar to the wl1271 driver.
+It triggers ieee80211_cqm_rssi_notify with the corresponding event when
+RSSI drops blow RSSI threshold or rises again above the RSSI threshold.
+It should be noted that wl1251 doesn't support RSSI hysteresis, instead it
+uses RSSI averageing and delays events until a certain count of frames
+proved RSSI change.
+
+Signed-off-by: David Gnedt<[email protected]>
+Acked-by: Kalle Valo<[email protected]>
+Signed-off-by: John W. Linville<[email protected]>
+---
+ drivers/net/wireless/wl1251/acx.c | 25 +++++++++++++++++++
+ drivers/net/wireless/wl1251/acx.h | 45 ++++++++++++++++++++++++++++++++++
+ drivers/net/wireless/wl1251/event.c | 18 +++++++++++++
+ drivers/net/wireless/wl1251/main.c | 15 ++++++++++-
+ drivers/net/wireless/wl1251/wl1251.h | 5 ++++
+ 5 files changed, 107 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/wireless/wl1251/acx.c
b/drivers/net/wireless/wl1251/acx.c
+index 8c94366..ef8370e 100644
+--- a/drivers/net/wireless/wl1251/acx.c
++++ b/drivers/net/wireless/wl1251/acx.c
+@@ -776,6 +776,31 @@ out:
+ return ret;
+ }
+
++int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight,
++ u8 depth, enum wl1251_acx_low_rssi_type type)
++{
++ struct acx_low_rssi *rssi;
++ int ret;
++
++ wl1251_debug(DEBUG_ACX, "acx low rssi");
++
++ rssi = kzalloc(sizeof(*rssi), GFP_KERNEL);
++ if (!rssi)
++ return -ENOMEM;
++
++ rssi->threshold = threshold;
++ rssi->weight = weight;
++ rssi->depth = depth;
++ rssi->type = type;
++
++ ret = wl1251_cmd_configure(wl, ACX_LOW_RSSI, rssi, sizeof(*rssi));
++ if (ret< 0)
++ wl1251_warning("failed to set low rssi threshold: %d", ret);
++
++ kfree(rssi);
++ return ret;
++}
++
+ int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type
preamble)
+ {
+ struct acx_preamble *acx;
+diff --git a/drivers/net/wireless/wl1251/acx.h
b/drivers/net/wireless/wl1251/acx.h
+index 7c6ffec..51b62d6 100644
+--- a/drivers/net/wireless/wl1251/acx.h
++++ b/drivers/net/wireless/wl1251/acx.h
+@@ -399,6 +399,49 @@ struct acx_rts_threshold {
+ u8 pad[2];
+ } __packed;
+
++enum wl1251_acx_low_rssi_type {
++ /*
++ * The event is a "Level" indication which keeps triggering
++ * as long as the average RSSI is below the threshold.
++ */
++ WL1251_ACX_LOW_RSSI_TYPE_LEVEL = 0,
++
++ /*
++ * The event is an "Edge" indication which triggers
++ * only when the RSSI threshold is crossed from above.
++ */
++ WL1251_ACX_LOW_RSSI_TYPE_EDGE = 1,
++};
++
++struct acx_low_rssi {
++ struct acx_header header;
++
++ /*
++ * The threshold (in dBm) below (or above after low rssi
++ * indication) which the firmware generates an interrupt to the
++ * host. This parameter is signed.
++ */
++ s8 threshold;
++
++ /*
++ * The weight of the current RSSI sample, before adding the new
++ * sample, that is used to calculate the average RSSI.
++ */
++ u8 weight;
++
++ /*
++ * The number of Beacons/Probe response frames that will be
++ * received before issuing the Low or Regained RSSI event.
++ */
++ u8 depth;
++
++ /*
++ * Configures how the Low RSSI Event is triggered. Refer to
++ * enum wl1251_acx_low_rssi_type for more.
++ */
++ u8 type;
++} __packed;
++
+ struct acx_beacon_filter_option {
+ struct acx_header header;
+
+@@ -1418,6 +1461,8 @@ int wl1251_acx_cca_threshold(struct wl1251 *wl);
+ int wl1251_acx_bcn_dtim_options(struct wl1251 *wl);
+ int wl1251_acx_aid(struct wl1251 *wl, u16 aid);
+ int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask);
++int wl1251_acx_low_rssi(struct wl1251 *wl, s8 threshold, u8 weight,
++ u8 depth, enum wl1251_acx_low_rssi_type type);
+ int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type
preamble);
+ int wl1251_acx_cts_protect(struct wl1251 *wl,
+ enum acx_ctsprotect_type ctsprotect);
+diff --git a/drivers/net/wireless/wl1251/event.c
b/drivers/net/wireless/wl1251/event.c
+index 712372e..dfc4579 100644
+--- a/drivers/net/wireless/wl1251/event.c
++++ b/drivers/net/wireless/wl1251/event.c
+@@ -90,6 +90,24 @@ static int wl1251_event_process(struct wl1251 *wl, struct
event_mailbox *mbox)
+ }
+ }
+
++ if (wl->vif&& wl->rssi_thold) {
++ if (vector& ROAMING_TRIGGER_LOW_RSSI_EVENT_ID) {
++ wl1251_debug(DEBUG_EVENT,
++ "ROAMING_TRIGGER_LOW_RSSI_EVENT");
++ ieee80211_cqm_rssi_notify(wl->vif,
++ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
++ GFP_KERNEL);
++ }
++
++ if (vector& ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) {
++ wl1251_debug(DEBUG_EVENT,
++ "ROAMING_TRIGGER_REGAINED_RSSI_EVENT");
++ ieee80211_cqm_rssi_notify(wl->vif,
++ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
++ GFP_KERNEL);
++ }
++ }
++
+ return 0;
+ }
+
+diff --git a/drivers/net/wireless/wl1251/main.c
b/drivers/net/wireless/wl1251/main.c
+index e270d97..e47c124 100644
+--- a/drivers/net/wireless/wl1251/main.c
++++ b/drivers/net/wireless/wl1251/main.c
+@@ -580,6 +580,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
+ wl->psm = 0;
+ wl->tx_queue_stopped = false;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
++ wl->rssi_thold = 0;
+ wl->channel = WL1251_DEFAULT_CHANNEL;
+
+ wl1251_debugfs_reset(wl);
+@@ -1037,6 +1038,16 @@ static void wl1251_op_bss_info_changed(struct
ieee80211_hw *hw,
+ if (ret< 0)
+ goto out;
+
++ if (changed& BSS_CHANGED_CQM) {
++ ret = wl1251_acx_low_rssi(wl, bss_conf->cqm_rssi_thold,
++ WL1251_DEFAULT_LOW_RSSI_WEIGHT,
++ WL1251_DEFAULT_LOW_RSSI_DEPTH,
++ WL1251_ACX_LOW_RSSI_TYPE_EDGE);
++ if (ret< 0)
++ goto out;
++ wl->rssi_thold = bss_conf->cqm_rssi_thold;
++ }
++
+ if (changed& BSS_CHANGED_BSSID) {
+ memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
+
+@@ -1388,7 +1399,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
+ wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_BEACON_FILTER |
+- IEEE80211_HW_SUPPORTS_UAPSD;
++ IEEE80211_HW_SUPPORTS_UAPSD |
++ IEEE80211_HW_SUPPORTS_CQM_RSSI;
+
+ wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ wl->hw->wiphy->max_scan_ssids = 1;
+@@ -1456,6 +1468,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
+ wl->psm_requested = false;
+ wl->tx_queue_stopped = false;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
++ wl->rssi_thold = 0;
+ wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
+ wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD;
+ wl->vif = NULL;
(24 more lines skipped)
++++++ linux-2.6.39-0003-wl1251-remove-wl1251_ps_set_elp-function.patch (new)
--- linux-2.6.39-0003-wl1251-remove-wl1251_ps_set_elp-function.patch
+++ linux-2.6.39-0003-wl1251-remove-wl1251_ps_set_elp-function.patch
+From d96dbe47537fad4c708c7433bd67dfabc870d540 Mon Sep 17 00:00:00 2001
+From: Grazvydas Ignotas<[email protected]>
+Date: Sun, 6 Mar 2011 19:23:36 +0200
+Subject: [PATCH 3/6] wl1251: remove wl1251_ps_set_elp function
+
+wl1251_ps_set_elp() only does acx_sleep_auth call and takes the chip
+from/to ELP, however all callers of wl1251_ps_set_mode() have already
+taken the chip out of ELP and puts it back to ELP when they finish.
+This makes ELP calls (and register writes they result in) superfluous.
+
+So remove wl1251_ps_set_elp function and call acx_sleep_auth directly.
+
+Signed-off-by: Grazvydas Ignotas<[email protected]>
+Acked-by: Kalle Valo<[email protected]>
+Signed-off-by: John W. Linville<[email protected]>
+---
+ drivers/net/wireless/wl1251/ps.c | 37 +++----------------------------------
+ 1 files changed, 3 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/net/wireless/wl1251/ps.c
b/drivers/net/wireless/wl1251/ps.c
+index 9ba23ed..842155e 100644
+--- a/drivers/net/wireless/wl1251/ps.c
++++ b/drivers/net/wireless/wl1251/ps.c
+@@ -102,38 +102,6 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
+ return 0;
+ }
+
+-static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable)
+-{
+- int ret;
+-
+- if (enable) {
+- wl1251_debug(DEBUG_PSM, "sleep auth psm/elp");
+-
+- ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
+- if (ret< 0)
+- return ret;
+-
+- wl1251_ps_elp_sleep(wl);
+- } else {
+- wl1251_debug(DEBUG_PSM, "sleep auth cam");
+-
+- /*
+- * When the target is in ELP, we can only
+- * access the ELP control register. Thus,
+- * we have to wake the target up before
+- * changing the power authorization.
+- */
+-
+- wl1251_ps_elp_wakeup(wl);
+-
+- ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
+- if (ret< 0)
+- return ret;
+- }
+-
+- return 0;
+-}
+-
+ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
+ {
+ int ret;
+@@ -162,7 +130,7 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum
wl1251_cmd_ps_mode mode)
+ if (ret< 0)
+ return ret;
+
+- ret = wl1251_ps_set_elp(wl, true);
++ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
+ if (ret< 0)
+ return ret;
+
+@@ -171,7 +139,8 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum
wl1251_cmd_ps_mode mode)
+ case STATION_ACTIVE_MODE:
+ default:
+ wl1251_debug(DEBUG_PSM, "leaving psm");
+- ret = wl1251_ps_set_elp(wl, false);
++
++ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
+ if (ret< 0)
+ return ret;
+
+--
+1.7.0.4
+
++++++ linux-2.6.39-0004-wl1251-fix-elp_work-race-condition.patch (new)
--- linux-2.6.39-0004-wl1251-fix-elp_work-race-condition.patch
+++ linux-2.6.39-0004-wl1251-fix-elp_work-race-condition.patch
+From cecde56fd7e93226aeed0ebe97523946a5e59ea5 Mon Sep 17 00:00:00 2001
+From: Grazvydas Ignotas<[email protected]>
+Date: Sun, 6 Mar 2011 19:23:37 +0200
+Subject: [PATCH 4/6] wl1251: fix elp_work race condition
+
+While working on PS I've noticed elp_work is kicking rather often, and
+sometimes the chip is put to sleep before 5ms delay expires. This
+seems to happen because by the time wl1251_ps_elp_wakeup is called
+elp_work might still be pending. After wakeup is done, the processing
+may take some time, during which 5ms might expire and elp_work might
+get scheduled. In this case, ss soon as 1st thread finishes work and
+releases the mutex, elp_work will then put the device to sleep without
+5ms delay. In addition 1st thread will queue additional elp_work
+needlessly.
+
+Fix this by cancelling work in wl1251_ps_elp_wakeup instead.
+
+Signed-off-by: Grazvydas Ignotas<[email protected]>
+Acked-by: Kalle Valo<[email protected]>
+Signed-off-by: John W. Linville<[email protected]>
+---
+ drivers/net/wireless/wl1251/ps.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/wireless/wl1251/ps.c
b/drivers/net/wireless/wl1251/ps.c
+index 842155e..9cc5147 100644
+--- a/drivers/net/wireless/wl1251/ps.c
++++ b/drivers/net/wireless/wl1251/ps.c
+@@ -58,7 +58,6 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl)
+ unsigned long delay;
+
+ if (wl->psm) {
+- cancel_delayed_work(&wl->elp_work);
+ delay = msecs_to_jiffies(ELP_ENTRY_DELAY);
+ ieee80211_queue_delayed_work(wl->hw,&wl->elp_work, delay);
+ }
+@@ -69,6 +68,9 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
+ unsigned long timeout, start;
+ u32 elp_reg;
+
++ if (delayed_work_pending(&wl->elp_work))
++ cancel_delayed_work(&wl->elp_work);
++
+ if (!wl->elp)
+ return 0;
+
+--
+1.7.0.4
+
++++++ linux-2.6.39-0005-wl1251-Prepare-for-idle-mode-support.patch (new)
--- linux-2.6.39-0005-wl1251-Prepare-for-idle-mode-support.patch
+++ linux-2.6.39-0005-wl1251-Prepare-for-idle-mode-support.patch
+From caf0914fa216ce3101f32e23ca02c89009de40b7 Mon Sep 17 00:00:00 2001
+From: Jarkko Nikula<[email protected]>
+Date: Mon, 4 Apr 2011 11:04:57 +0300
+Subject: [PATCH 5/6] wl1251: Prepare for idle mode support
+
+RFC for WL1251 idle mode support brought a few issues that are worth to
+update before adding the idle mode support.
+
+Since the idle mode can reuse the code that is now used in Power Save Mode
+(PSM), the flag psm in struct wl1251 is changed to variable station_mode
+to be able to distinguish between PSM and idle modes.
+
+As the station mode is different than the power power save mode command
+that is sent to chip, the enum wl1251_cmd_ps_mod values are used only when
+communicating with the chip and new enum wl1251_station_mode values are used
+inside the driver.
+
+Confusing comment about psm and elp relation is removed since the PSM is
+actually activated by putting the chip into Entreme Low Power (ELP) mode.
+
+Signed-off-by: Jarkko Nikula<[email protected]>
+Acked-by: Kalle Valo<[email protected]>
+Signed-off-by: John W. Linville<[email protected]>
+---
+ drivers/net/wireless/wl1251/cmd.h | 4 ++--
+ drivers/net/wireless/wl1251/event.c | 6 ++++--
+ drivers/net/wireless/wl1251/main.c | 6 +++---
+ drivers/net/wireless/wl1251/ps.c | 14 ++++++--------
+ drivers/net/wireless/wl1251/ps.h | 2 +-
+ drivers/net/wireless/wl1251/wl1251.h | 8 ++++++--
+ 6 files changed, 22 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/net/wireless/wl1251/cmd.h
b/drivers/net/wireless/wl1251/cmd.h
+index e5c74c6..79ca527 100644
+--- a/drivers/net/wireless/wl1251/cmd.h
++++ b/drivers/net/wireless/wl1251/cmd.h
+@@ -313,8 +313,8 @@ struct wl1251_cmd_vbm_update {
+ } __packed;
+
+ enum wl1251_cmd_ps_mode {
+- STATION_ACTIVE_MODE,
+- STATION_POWER_SAVE_MODE
++ CHIP_ACTIVE_MODE,
++ CHIP_POWER_SAVE_MODE
+ };
+
+ struct wl1251_cmd_ps_params {
+diff --git a/drivers/net/wireless/wl1251/event.c
b/drivers/net/wireless/wl1251/event.c
+index dfc4579..9f15cca 100644
+--- a/drivers/net/wireless/wl1251/event.c
++++ b/drivers/net/wireless/wl1251/event.c
+@@ -68,14 +68,16 @@ static int wl1251_event_process(struct wl1251 *wl, struct
event_mailbox *mbox)
+ if (vector& BSS_LOSE_EVENT_ID) {
+ wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
+
+- if (wl->psm_requested&& wl->psm) {
++ if (wl->psm_requested&&
++ wl->station_mode != STATION_ACTIVE_MODE) {
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ if (ret< 0)
+ return ret;
+ }
+ }
+
+- if (vector& SYNCHRONIZATION_TIMEOUT_EVENT_ID&& wl->psm) {
++ if (vector& SYNCHRONIZATION_TIMEOUT_EVENT_ID&&
++ wl->station_mode != STATION_ACTIVE_MODE) {
+ wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT");
+
+ /* indicate to the stack, that beacons have been lost */
+diff --git a/drivers/net/wireless/wl1251/main.c
b/drivers/net/wireless/wl1251/main.c
+index e47c124..705a406 100644
+--- a/drivers/net/wireless/wl1251/main.c
++++ b/drivers/net/wireless/wl1251/main.c
+@@ -577,7 +577,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
+ wl->rx_last_id = 0;
+ wl->next_tx_complete = 0;
+ wl->elp = false;
+- wl->psm = 0;
++ wl->station_mode = STATION_ACTIVE_MODE;
+ wl->tx_queue_stopped = false;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
+ wl->rssi_thold = 0;
+@@ -712,7 +712,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32
changed)
+
+ wl->psm_requested = false;
+
+- if (wl->psm) {
++ if (wl->station_mode != STATION_ACTIVE_MODE) {
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ if (ret< 0)
+ goto out_sleep;
+@@ -1464,7 +1464,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
+ wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
+ wl->elp = false;
+- wl->psm = 0;
++ wl->station_mode = STATION_ACTIVE_MODE;
+ wl->psm_requested = false;
+ wl->tx_queue_stopped = false;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
+diff --git a/drivers/net/wireless/wl1251/ps.c
b/drivers/net/wireless/wl1251/ps.c
+index 9cc5147..97a5b8c 100644
+--- a/drivers/net/wireless/wl1251/ps.c
++++ b/drivers/net/wireless/wl1251/ps.c
+@@ -39,7 +39,7 @@ void wl1251_elp_work(struct work_struct *work)
+
+ mutex_lock(&wl->mutex);
+
+- if (wl->elp || !wl->psm)
++ if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE)
+ goto out;
+
+ wl1251_debug(DEBUG_PSM, "chip to elp");
+@@ -57,7 +57,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl)
+ {
+ unsigned long delay;
+
+- if (wl->psm) {
++ if (wl->station_mode != STATION_ACTIVE_MODE) {
+ delay = msecs_to_jiffies(ELP_ENTRY_DELAY);
+ ieee80211_queue_delayed_work(wl->hw,&wl->elp_work, delay);
+ }
+@@ -104,7 +104,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
+ return 0;
+ }
+
+-int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
++int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode)
+ {
+ int ret;
+
+@@ -128,15 +128,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum
wl1251_cmd_ps_mode mode)
+ if (ret< 0)
+ return ret;
+
+- ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
++ ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE);
+ if (ret< 0)
+ return ret;
+
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
+ if (ret< 0)
+ return ret;
+-
+- wl->psm = 1;
+ break;
+ case STATION_ACTIVE_MODE:
+ default:
+@@ -163,13 +161,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum
wl1251_cmd_ps_mode mode)
+ if (ret< 0)
+ return ret;
+
+- ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
++ ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE);
+ if (ret< 0)
+ return ret;
+
+- wl->psm = 0;
+ break;
+ }
++ wl->station_mode = mode;
+
+ return ret;
+ }
+diff --git a/drivers/net/wireless/wl1251/ps.h
b/drivers/net/wireless/wl1251/ps.h
+index 55c3dda..75efad2 100644
+--- a/drivers/net/wireless/wl1251/ps.h
++++ b/drivers/net/wireless/wl1251/ps.h
+@@ -26,7 +26,7 @@
+ #include "wl1251.h"
+ #include "acx.h"
+
+-int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
++int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode);
+ void wl1251_ps_elp_sleep(struct wl1251 *wl);
+ int wl1251_ps_elp_wakeup(struct wl1251 *wl);
+ void wl1251_elp_work(struct work_struct *work);
+diff --git a/drivers/net/wireless/wl1251/wl1251.h
b/drivers/net/wireless/wl1251/wl1251.h
+index 13d66d6..502ab94 100644
+--- a/drivers/net/wireless/wl1251/wl1251.h
++++ b/drivers/net/wireless/wl1251/wl1251.h
+@@ -129,6 +129,11 @@ enum wl1251_partition_type {
+ PART_TABLE_LEN
+ };
+
++enum wl1251_station_mode {
++ STATION_ACTIVE_MODE,
++ STATION_POWER_SAVE_MODE,
++};
++
+ struct wl1251_partition {
+ u32 size;
+ u32 start;
+@@ -357,8 +362,7 @@ struct wl1251 {
+
+ struct delayed_work elp_work;
+
(9 more lines skipped)
++++++ linux-2.6.39-0006-wl1251-Add-support-for-idle-mode.patch (new)
--- linux-2.6.39-0006-wl1251-Add-support-for-idle-mode.patch
+++ linux-2.6.39-0006-wl1251-Add-support-for-idle-mode.patch
+From effb0537a158e4cd1e4f5ecc1ac00b1a9e34f60d Mon Sep 17 00:00:00 2001
+From: Jarkko Nikula<[email protected]>
+Date: Mon, 4 Apr 2011 11:04:58 +0300
+Subject: [PATCH 6/6] wl1251: Add support for idle mode
+
+On Nokia N900 the wl1251 consumes the most power when the interface is up
+but not associated to access point (that supports PSM). In terms of battery
+current consumption, the consumption is ~180 mA higher when the interface is
+up but not associated and only ~5 mA higher when associated compared to
+interface down and driver not loaded cases.
+
+This patch adds support for the mac80211 idle notifications. Chip is put into
+idle very much the same way when entering into PSM by utilizing the Extreme
+Low Power (ELP) mode. I.e. idle is entered by setting necessary conditions
+in wl1251_ps_set_mode followed by a call to wl1251_ps_elp_sleep.
+
+It seems it is just enough the authorize ELP mode followed by
+CMD_DISCONNECT (thanks to Kalle Valo about the idea to use it).
+Without disconnect command the chip remains somewhat active and stays
+consuming ~20 mA. Idle mode is left by same way than PSM. The wl1251_join
+call is used to revert the CMD_DISCONNECT. Without it association to AP
+doesn't work when trying second time.
+
+With this patch the interface up but not associated case the battery current
+consumption is less than 1 mA higher compared to interface down case.
+
+Signed-off-by: Jarkko Nikula<[email protected]>
+Acked-by: Kalle Valo<[email protected]>
+Signed-off-by: John W. Linville<[email protected]>
+---
+ drivers/net/wireless/wl1251/main.c | 16 ++++++++++++++++
+ drivers/net/wireless/wl1251/ps.c | 11 +++++++++++
+ drivers/net/wireless/wl1251/wl1251.h | 1 +
+ 3 files changed, 28 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/wireless/wl1251/main.c
b/drivers/net/wireless/wl1251/main.c
+index 705a406..413f7b6 100644
+--- a/drivers/net/wireless/wl1251/main.c
++++ b/drivers/net/wireless/wl1251/main.c
+@@ -719,6 +719,22 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32
changed)
+ }
+ }
+
++ if (changed& IEEE80211_CONF_CHANGE_IDLE) {
++ if (conf->flags& IEEE80211_CONF_IDLE) {
++ ret = wl1251_ps_set_mode(wl, STATION_IDLE);
++ if (ret< 0)
++ goto out_sleep;
++ } else {
++ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
++ if (ret< 0)
++ goto out_sleep;
++ ret = wl1251_join(wl, wl->bss_type, wl->channel,
++ wl->beacon_int, wl->dtim_period);
++ if (ret< 0)
++ goto out_sleep;
++ }
++ }
++
+ if (conf->power_level != wl->power_level) {
+ ret = wl1251_acx_tx_power(wl, conf->power_level);
+ if (ret< 0)
+diff --git a/drivers/net/wireless/wl1251/ps.c
b/drivers/net/wireless/wl1251/ps.c
+index 97a5b8c..db719f7 100644
+--- a/drivers/net/wireless/wl1251/ps.c
++++ b/drivers/net/wireless/wl1251/ps.c
+@@ -136,6 +136,17 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum
wl1251_station_mode mode)
+ if (ret< 0)
+ return ret;
+ break;
++ case STATION_IDLE:
++ wl1251_debug(DEBUG_PSM, "entering idle");
++
++ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
++ if (ret< 0)
++ return ret;
++
++ ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0);
++ if (ret< 0)
++ return ret;
++ break;
+ case STATION_ACTIVE_MODE:
+ default:
+ wl1251_debug(DEBUG_PSM, "leaving psm");
+diff --git a/drivers/net/wireless/wl1251/wl1251.h
b/drivers/net/wireless/wl1251/wl1251.h
+index 502ab94..b7c777f 100644
+--- a/drivers/net/wireless/wl1251/wl1251.h
++++ b/drivers/net/wireless/wl1251/wl1251.h
+@@ -132,6 +132,7 @@ enum wl1251_partition_type {
+ enum wl1251_station_mode {
+ STATION_ACTIVE_MODE,
+ STATION_POWER_SAVE_MODE,
++ STATION_IDLE,
+ };
+
+ struct wl1251_partition {
+--
+1.7.0.4
+
++++++ series
--- series
+++ series
@@ -198,6 +198,14 @@
linux-2.6-dvfs-0030-OMAP3-cpufreq-Use-dpll1_ck-clock-instead-of-arm_fck-.patch
linux-2.6-dvfs-0032-rx51-add-board-OPP-init-to-disable-125MHz-from-avail.patch
+# wl1251 idle mode
+linux-2.6.39-0001-wl1251-enable-beacon-early-termination-while-in-powe.patch
+linux-2.6.39-0002-wl1251-implement-connection-quality-monitoring.patch
+linux-2.6.39-0003-wl1251-remove-wl1251_ps_set_elp-function.patch
+linux-2.6.39-0004-wl1251-fix-elp_work-race-condition.patch
+linux-2.6.39-0005-wl1251-Prepare-for-idle-mode-support.patch
+linux-2.6.39-0006-wl1251-Add-support-for-idle-mode.patch
+
#
# End of the Nokia N900 patches
#
_______________________________________________
MeeGo-commits mailing list
[email protected]
http://lists.meego.com/listinfo/meego-commits