diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/event.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/event.c | 64 |
1 files changed, 59 insertions, 5 deletions
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 1b170c5cc595..d7be3aec6fc3 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c | |||
@@ -33,6 +33,7 @@ void wl1271_pspoll_work(struct work_struct *work) | |||
33 | { | 33 | { |
34 | struct delayed_work *dwork; | 34 | struct delayed_work *dwork; |
35 | struct wl1271 *wl; | 35 | struct wl1271 *wl; |
36 | int ret; | ||
36 | 37 | ||
37 | dwork = container_of(work, struct delayed_work, work); | 38 | dwork = container_of(work, struct delayed_work, work); |
38 | wl = container_of(dwork, struct wl1271, pspoll_work); | 39 | wl = container_of(dwork, struct wl1271, pspoll_work); |
@@ -55,8 +56,13 @@ void wl1271_pspoll_work(struct work_struct *work) | |||
55 | * delivery failure occurred, and no-one changed state since, so | 56 | * delivery failure occurred, and no-one changed state since, so |
56 | * we should go back to powersave. | 57 | * we should go back to powersave. |
57 | */ | 58 | */ |
59 | ret = wl1271_ps_elp_wakeup(wl); | ||
60 | if (ret < 0) | ||
61 | goto out; | ||
62 | |||
58 | wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); | 63 | wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); |
59 | 64 | ||
65 | wl1271_ps_elp_sleep(wl); | ||
60 | out: | 66 | out: |
61 | mutex_unlock(&wl->mutex); | 67 | mutex_unlock(&wl->mutex); |
62 | }; | 68 | }; |
@@ -129,11 +135,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl, | |||
129 | 135 | ||
130 | /* enable beacon early termination */ | 136 | /* enable beacon early termination */ |
131 | ret = wl1271_acx_bet_enable(wl, true); | 137 | ret = wl1271_acx_bet_enable(wl, true); |
132 | if (ret < 0) | ||
133 | break; | ||
134 | |||
135 | /* go to extremely low power mode */ | ||
136 | wl1271_ps_elp_sleep(wl); | ||
137 | break; | 138 | break; |
138 | default: | 139 | default: |
139 | break; | 140 | break; |
@@ -173,6 +174,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | |||
173 | u32 vector; | 174 | u32 vector; |
174 | bool beacon_loss = false; | 175 | bool beacon_loss = false; |
175 | bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); | 176 | bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); |
177 | bool disconnect_sta = false; | ||
178 | unsigned long sta_bitmap = 0; | ||
176 | 179 | ||
177 | wl1271_event_mbox_dump(mbox); | 180 | wl1271_event_mbox_dump(mbox); |
178 | 181 | ||
@@ -228,9 +231,60 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | |||
228 | wl1271_event_rssi_trigger(wl, mbox); | 231 | wl1271_event_rssi_trigger(wl, mbox); |
229 | } | 232 | } |
230 | 233 | ||
234 | if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { | ||
235 | wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); | ||
236 | if (wl->vif) | ||
237 | wl1271_tx_dummy_packet(wl); | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * "TX retries exceeded" has a different meaning according to mode. | ||
242 | * In AP mode the offending station is disconnected. In STA mode we | ||
243 | * report connection loss. | ||
244 | */ | ||
245 | if (vector & MAX_TX_RETRY_EVENT_ID) { | ||
246 | wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); | ||
247 | if (is_ap) { | ||
248 | sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); | ||
249 | disconnect_sta = true; | ||
250 | } else { | ||
251 | beacon_loss = true; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { | ||
256 | wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); | ||
257 | sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); | ||
258 | disconnect_sta = true; | ||
259 | } | ||
260 | |||
231 | if (wl->vif && beacon_loss) | 261 | if (wl->vif && beacon_loss) |
232 | ieee80211_connection_loss(wl->vif); | 262 | ieee80211_connection_loss(wl->vif); |
233 | 263 | ||
264 | if (is_ap && disconnect_sta) { | ||
265 | u32 num_packets = wl->conf.tx.max_tx_retries; | ||
266 | struct ieee80211_sta *sta; | ||
267 | const u8 *addr; | ||
268 | int h; | ||
269 | |||
270 | for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); | ||
271 | h < AP_MAX_LINKS; | ||
272 | h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { | ||
273 | if (!wl1271_is_active_sta(wl, h)) | ||
274 | continue; | ||
275 | |||
276 | addr = wl->links[h].addr; | ||
277 | |||
278 | rcu_read_lock(); | ||
279 | sta = ieee80211_find_sta(wl->vif, addr); | ||
280 | if (sta) { | ||
281 | wl1271_debug(DEBUG_EVENT, "remove sta %d", h); | ||
282 | ieee80211_report_low_ack(sta, num_packets); | ||
283 | } | ||
284 | rcu_read_unlock(); | ||
285 | } | ||
286 | } | ||
287 | |||
234 | return 0; | 288 | return 0; |
235 | } | 289 | } |
236 | 290 | ||