diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/wl12xx/wl1271_ps.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_ps.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_ps.c | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index 1dc74b0c7736..e2b1ebf096e8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c | |||
@@ -24,28 +24,43 @@ | |||
24 | #include "wl1271_reg.h" | 24 | #include "wl1271_reg.h" |
25 | #include "wl1271_ps.h" | 25 | #include "wl1271_ps.h" |
26 | #include "wl1271_spi.h" | 26 | #include "wl1271_spi.h" |
27 | #include "wl1271_io.h" | ||
27 | 28 | ||
28 | #define WL1271_WAKEUP_TIMEOUT 500 | 29 | #define WL1271_WAKEUP_TIMEOUT 500 |
29 | 30 | ||
31 | void wl1271_elp_work(struct work_struct *work) | ||
32 | { | ||
33 | struct delayed_work *dwork; | ||
34 | struct wl1271 *wl; | ||
35 | |||
36 | dwork = container_of(work, struct delayed_work, work); | ||
37 | wl = container_of(dwork, struct wl1271, elp_work); | ||
38 | |||
39 | wl1271_debug(DEBUG_PSM, "elp work"); | ||
40 | |||
41 | mutex_lock(&wl->mutex); | ||
42 | |||
43 | if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || | ||
44 | !test_bit(WL1271_FLAG_PSM, &wl->flags)) | ||
45 | goto out; | ||
46 | |||
47 | wl1271_debug(DEBUG_PSM, "chip to elp"); | ||
48 | wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | ||
49 | set_bit(WL1271_FLAG_IN_ELP, &wl->flags); | ||
50 | |||
51 | out: | ||
52 | mutex_unlock(&wl->mutex); | ||
53 | } | ||
54 | |||
55 | #define ELP_ENTRY_DELAY 5 | ||
56 | |||
30 | /* Routines to toggle sleep mode while in ELP */ | 57 | /* Routines to toggle sleep mode while in ELP */ |
31 | void wl1271_ps_elp_sleep(struct wl1271 *wl) | 58 | void wl1271_ps_elp_sleep(struct wl1271 *wl) |
32 | { | 59 | { |
33 | /* | 60 | if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { |
34 | * FIXME: due to a problem in the firmware (causing a firmware | 61 | cancel_delayed_work(&wl->elp_work); |
35 | * crash), ELP entry is prevented below. Remove the "true" to | 62 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, |
36 | * re-enable ELP entry. | 63 | msecs_to_jiffies(ELP_ENTRY_DELAY)); |
37 | */ | ||
38 | if (true || wl->elp || !wl->psm) | ||
39 | return; | ||
40 | |||
41 | /* | ||
42 | * Go to ELP unless there is work already pending - pending work | ||
43 | * will immediately wakeup the chipset anyway. | ||
44 | */ | ||
45 | if (!work_pending(&wl->irq_work) && !work_pending(&wl->tx_work)) { | ||
46 | wl1271_debug(DEBUG_PSM, "chip to elp"); | ||
47 | wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | ||
48 | wl->elp = true; | ||
49 | } | 64 | } |
50 | } | 65 | } |
51 | 66 | ||
@@ -57,7 +72,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) | |||
57 | u32 start_time = jiffies; | 72 | u32 start_time = jiffies; |
58 | bool pending = false; | 73 | bool pending = false; |
59 | 74 | ||
60 | if (!wl->elp) | 75 | if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) |
61 | return 0; | 76 | return 0; |
62 | 77 | ||
63 | wl1271_debug(DEBUG_PSM, "waking up chip from elp"); | 78 | wl1271_debug(DEBUG_PSM, "waking up chip from elp"); |
@@ -73,7 +88,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) | |||
73 | wl->elp_compl = &compl; | 88 | wl->elp_compl = &compl; |
74 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 89 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
75 | 90 | ||
76 | wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); | 91 | wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); |
77 | 92 | ||
78 | if (!pending) { | 93 | if (!pending) { |
79 | ret = wait_for_completion_timeout( | 94 | ret = wait_for_completion_timeout( |
@@ -88,7 +103,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) | |||
88 | } | 103 | } |
89 | } | 104 | } |
90 | 105 | ||
91 | wl->elp = false; | 106 | clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); |
92 | 107 | ||
93 | wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", | 108 | wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", |
94 | jiffies_to_msecs(jiffies - start_time)); | 109 | jiffies_to_msecs(jiffies - start_time)); |
@@ -104,22 +119,20 @@ out: | |||
104 | return 0; | 119 | return 0; |
105 | } | 120 | } |
106 | 121 | ||
107 | int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) | 122 | int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, |
123 | bool send) | ||
108 | { | 124 | { |
109 | int ret; | 125 | int ret; |
110 | 126 | ||
111 | switch (mode) { | 127 | switch (mode) { |
112 | case STATION_POWER_SAVE_MODE: | 128 | case STATION_POWER_SAVE_MODE: |
113 | wl1271_debug(DEBUG_PSM, "entering psm"); | 129 | wl1271_debug(DEBUG_PSM, "entering psm"); |
114 | ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); | ||
115 | if (ret < 0) | ||
116 | return ret; | ||
117 | 130 | ||
118 | wl1271_ps_elp_sleep(wl); | 131 | ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE, send); |
119 | if (ret < 0) | 132 | if (ret < 0) |
120 | return ret; | 133 | return ret; |
121 | 134 | ||
122 | wl->psm = 1; | 135 | set_bit(WL1271_FLAG_PSM, &wl->flags); |
123 | break; | 136 | break; |
124 | case STATION_ACTIVE_MODE: | 137 | case STATION_ACTIVE_MODE: |
125 | default: | 138 | default: |
@@ -128,11 +141,21 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) | |||
128 | if (ret < 0) | 141 | if (ret < 0) |
129 | return ret; | 142 | return ret; |
130 | 143 | ||
131 | ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); | 144 | /* disable beacon early termination */ |
145 | ret = wl1271_acx_bet_enable(wl, false); | ||
146 | if (ret < 0) | ||
147 | return ret; | ||
148 | |||
149 | /* disable beacon filtering */ | ||
150 | ret = wl1271_acx_beacon_filter_opt(wl, false); | ||
151 | if (ret < 0) | ||
152 | return ret; | ||
153 | |||
154 | ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE, send); | ||
132 | if (ret < 0) | 155 | if (ret < 0) |
133 | return ret; | 156 | return ret; |
134 | 157 | ||
135 | wl->psm = 0; | 158 | clear_bit(WL1271_FLAG_PSM, &wl->flags); |
136 | break; | 159 | break; |
137 | } | 160 | } |
138 | 161 | ||