blob: 0e0808fa4e32d30725dda58c0d610faac72a6658 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-2009 Nokia Corporation
5 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include "wl1271.h"
25#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020026#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include "wl1271_event.h"
28#include "wl1271_ps.h"
Juuso Oikarinen66497dc2009-10-08 21:56:30 +030029#include "wl12xx_80211.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030030
31static int wl1271_event_scan_complete(struct wl1271 *wl,
32 struct event_mailbox *mbox)
33{
34 wl1271_debug(DEBUG_EVENT, "status: 0x%x",
35 mbox->scheduled_scan_status);
36
Juuso Oikarinen71449f82009-12-11 15:41:07 +020037 if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030038 if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030039 /* 2.4 GHz band scanned, scan 5 GHz band, pretend
40 * to the wl1271_cmd_scan function that we are not
41 * scanning as it checks that.
42 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +020043 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
Kalle Valo818e3062010-03-18 12:26:35 +020044 /* FIXME: ie missing! */
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030045 wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
Kalle Valo818e3062010-03-18 12:26:35 +020046 NULL, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030047 wl->scan.active,
48 wl->scan.high_prio,
49 WL1271_SCAN_BAND_5_GHZ,
50 wl->scan.probe_requests);
51 } else {
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030052 mutex_unlock(&wl->mutex);
53 ieee80211_scan_completed(wl->hw, false);
54 mutex_lock(&wl->mutex);
Juuso Oikarinen71449f82009-12-11 15:41:07 +020055 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030056 }
57 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030058 return 0;
59}
60
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020061static int wl1271_event_ps_report(struct wl1271 *wl,
62 struct event_mailbox *mbox,
63 bool *beacon_loss)
64{
65 int ret = 0;
66
67 wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
68
69 switch (mbox->ps_status) {
70 case EVENT_ENTER_POWER_SAVE_FAIL:
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020071 wl1271_debug(DEBUG_PSM, "PSM entry failed");
72
Juuso Oikarinen71449f82009-12-11 15:41:07 +020073 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020074 /* remain in active mode */
Juuso Oikarinen461fa132009-11-23 23:22:13 +020075 wl->psm_entry_retry = 0;
76 break;
77 }
78
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020079 if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
80 wl->psm_entry_retry++;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020081 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
82 true);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020083 } else {
Juuso Oikarinen461fa132009-11-23 23:22:13 +020084 wl1271_error("PSM entry failed, giving up.\n");
Juuso Oikarinen30240fc2010-02-18 13:25:38 +020085 /* FIXME: this may need to be reconsidered. for now it
86 is not possible to indicate to the mac80211
87 afterwards that PSM entry failed. To maximize
88 functionality (receiving data and remaining
89 associated) make sure that we are in sync with the
90 AP in regard of PSM mode. */
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020091 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
92 false);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020093 wl->psm_entry_retry = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020094 }
95 break;
96 case EVENT_ENTER_POWER_SAVE_SUCCESS:
97 wl->psm_entry_retry = 0;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020098
99 /* enable beacon filtering */
100 ret = wl1271_acx_beacon_filter_opt(wl, true);
101 if (ret < 0)
102 break;
103
104 /* enable beacon early termination */
105 ret = wl1271_acx_bet_enable(wl, true);
106 if (ret < 0)
107 break;
108
109 /* go to extremely low power mode */
110 wl1271_ps_elp_sleep(wl);
111 if (ret < 0)
112 break;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200113 break;
114 case EVENT_EXIT_POWER_SAVE_FAIL:
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200115 wl1271_debug(DEBUG_PSM, "PSM exit failed");
116
117 if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
118 wl->psm_entry_retry = 0;
119 break;
120 }
121
Juuso Oikarinen30240fc2010-02-18 13:25:38 +0200122 /* make sure the firmware goes to active mode - the frame to
123 be sent next will indicate to the AP, that we are active. */
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200124 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
125 false);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200126 break;
127 case EVENT_EXIT_POWER_SAVE_SUCCESS:
128 default:
129 break;
130 }
131
132 return ret;
133}
134
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300135static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
136{
137 wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
138 wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
139 wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
140}
141
142static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
143{
144 int ret;
145 u32 vector;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200146 bool beacon_loss = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300147
148 wl1271_event_mbox_dump(mbox);
149
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300150 vector = le32_to_cpu(mbox->events_vector);
151 vector &= ~(le32_to_cpu(mbox->events_mask));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300152 wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
153
154 if (vector & SCAN_COMPLETE_EVENT_ID) {
155 ret = wl1271_event_scan_complete(wl, mbox);
156 if (ret < 0)
157 return ret;
158 }
159
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300160 /*
161 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
162 * filtering) is enabled. Without PSM, the stack will receive all
163 * beacons and can detect beacon loss by itself.
Teemu Paasikivi64e29e42010-03-26 12:53:26 +0200164 *
165 * As there's possibility that the driver disables PSM before receiving
166 * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
167 *
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300168 */
Teemu Paasikivi64e29e42010-03-26 12:53:26 +0200169 if (vector & BSS_LOSE_EVENT_ID) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300170 wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
171
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300172 /* indicate to the stack, that beacons have been lost */
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200173 beacon_loss = true;
174 }
175
176 if (vector & PS_REPORT_EVENT_ID) {
177 wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
178 ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
179 if (ret < 0)
180 return ret;
181 }
182
Juuso Oikarinen04477bf2009-12-11 15:41:09 +0200183 if (wl->vif && beacon_loss) {
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200184 /* Obviously, it's dangerous to release the mutex while
185 we are holding many of the variables in the wl struct.
186 That's why it's done last in the function, and care must
187 be taken that nothing more is done after this function
188 returns. */
189 mutex_unlock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300190 ieee80211_beacon_loss(wl->vif);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200191 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300192 }
193
194 return 0;
195}
196
197int wl1271_event_unmask(struct wl1271 *wl)
198{
199 int ret;
200
201 ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask));
202 if (ret < 0)
203 return ret;
204
205 return 0;
206}
207
208void wl1271_event_mbox_config(struct wl1271 *wl)
209{
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200210 wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300211 wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
212
213 wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
214 wl->mbox_ptr[0], wl->mbox_ptr[1]);
215}
216
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200217int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300218{
219 struct event_mailbox mbox;
220 int ret;
221
222 wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
223
224 if (mbox_num > 1)
225 return -EINVAL;
226
227 /* first we read the mbox descriptor */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200228 wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
229 sizeof(struct event_mailbox), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300230
231 /* process the descriptor */
232 ret = wl1271_event_process(wl, &mbox);
233 if (ret < 0)
234 return ret;
235
236 /* then we let the firmware know it can go on...*/
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200237 wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300238
239 return 0;
240}