blob: 7468ef10194bef9a1974f84b09036e3954a831ed [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"
26#include "wl1271_spi.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020027#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030028#include "wl1271_event.h"
29#include "wl1271_ps.h"
Juuso Oikarinen66497dc2009-10-08 21:56:30 +030030#include "wl12xx_80211.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030031
32static int wl1271_event_scan_complete(struct wl1271 *wl,
33 struct event_mailbox *mbox)
34{
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030035 int size = sizeof(struct wl12xx_probe_req_template);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036 wl1271_debug(DEBUG_EVENT, "status: 0x%x",
37 mbox->scheduled_scan_status);
38
Juuso Oikarinen71449f82009-12-11 15:41:07 +020039 if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030040 if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
41 wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
42 NULL, size);
43 /* 2.4 GHz band scanned, scan 5 GHz band, pretend
44 * to the wl1271_cmd_scan function that we are not
45 * scanning as it checks that.
46 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +020047 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030048 wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
49 wl->scan.active,
50 wl->scan.high_prio,
51 WL1271_SCAN_BAND_5_GHZ,
52 wl->scan.probe_requests);
53 } else {
54 if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
55 wl1271_cmd_template_set(wl,
56 CMD_TEMPL_CFG_PROBE_REQ_2_4,
57 NULL, size);
58 else
59 wl1271_cmd_template_set(wl,
60 CMD_TEMPL_CFG_PROBE_REQ_5,
61 NULL, size);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030062
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030063 mutex_unlock(&wl->mutex);
64 ieee80211_scan_completed(wl->hw, false);
65 mutex_lock(&wl->mutex);
Juuso Oikarinen71449f82009-12-11 15:41:07 +020066 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030067 }
68 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030069 return 0;
70}
71
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020072static int wl1271_event_ps_report(struct wl1271 *wl,
73 struct event_mailbox *mbox,
74 bool *beacon_loss)
75{
76 int ret = 0;
77
78 wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
79
80 switch (mbox->ps_status) {
81 case EVENT_ENTER_POWER_SAVE_FAIL:
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020082 wl1271_debug(DEBUG_PSM, "PSM entry failed");
83
Juuso Oikarinen71449f82009-12-11 15:41:07 +020084 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020085 /* remain in active mode */
Juuso Oikarinen461fa132009-11-23 23:22:13 +020086 wl->psm_entry_retry = 0;
87 break;
88 }
89
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020090 if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
91 wl->psm_entry_retry++;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020092 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
93 true);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020094 } else {
Juuso Oikarinen461fa132009-11-23 23:22:13 +020095 wl1271_error("PSM entry failed, giving up.\n");
Juuso Oikarinen30240fc2010-02-18 13:25:38 +020096 /* FIXME: this may need to be reconsidered. for now it
97 is not possible to indicate to the mac80211
98 afterwards that PSM entry failed. To maximize
99 functionality (receiving data and remaining
100 associated) make sure that we are in sync with the
101 AP in regard of PSM mode. */
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200102 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
103 false);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200104 wl->psm_entry_retry = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200105 }
106 break;
107 case EVENT_ENTER_POWER_SAVE_SUCCESS:
108 wl->psm_entry_retry = 0;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200109
110 /* enable beacon filtering */
111 ret = wl1271_acx_beacon_filter_opt(wl, true);
112 if (ret < 0)
113 break;
114
115 /* enable beacon early termination */
116 ret = wl1271_acx_bet_enable(wl, true);
117 if (ret < 0)
118 break;
119
120 /* go to extremely low power mode */
121 wl1271_ps_elp_sleep(wl);
122 if (ret < 0)
123 break;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200124 break;
125 case EVENT_EXIT_POWER_SAVE_FAIL:
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200126 wl1271_debug(DEBUG_PSM, "PSM exit failed");
127
128 if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
129 wl->psm_entry_retry = 0;
130 break;
131 }
132
Juuso Oikarinen30240fc2010-02-18 13:25:38 +0200133 /* make sure the firmware goes to active mode - the frame to
134 be sent next will indicate to the AP, that we are active. */
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200135 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
136 false);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200137 break;
138 case EVENT_EXIT_POWER_SAVE_SUCCESS:
139 default:
140 break;
141 }
142
143 return ret;
144}
145
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300146static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
147{
148 wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
149 wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
150 wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
151}
152
153static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
154{
155 int ret;
156 u32 vector;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200157 bool beacon_loss = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300158
159 wl1271_event_mbox_dump(mbox);
160
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300161 vector = le32_to_cpu(mbox->events_vector);
162 vector &= ~(le32_to_cpu(mbox->events_mask));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300163 wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
164
165 if (vector & SCAN_COMPLETE_EVENT_ID) {
166 ret = wl1271_event_scan_complete(wl, mbox);
167 if (ret < 0)
168 return ret;
169 }
170
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300171 /*
172 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
173 * filtering) is enabled. Without PSM, the stack will receive all
174 * beacons and can detect beacon loss by itself.
175 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200176 if (vector & BSS_LOSE_EVENT_ID &&
177 test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300178 wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
179
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300180 /* indicate to the stack, that beacons have been lost */
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200181 beacon_loss = true;
182 }
183
184 if (vector & PS_REPORT_EVENT_ID) {
185 wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
186 ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
187 if (ret < 0)
188 return ret;
189 }
190
Juuso Oikarinen04477bf2009-12-11 15:41:09 +0200191 if (wl->vif && beacon_loss) {
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200192 /* Obviously, it's dangerous to release the mutex while
193 we are holding many of the variables in the wl struct.
194 That's why it's done last in the function, and care must
195 be taken that nothing more is done after this function
196 returns. */
197 mutex_unlock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300198 ieee80211_beacon_loss(wl->vif);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200199 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300200 }
201
202 return 0;
203}
204
205int wl1271_event_unmask(struct wl1271 *wl)
206{
207 int ret;
208
209 ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask));
210 if (ret < 0)
211 return ret;
212
213 return 0;
214}
215
216void wl1271_event_mbox_config(struct wl1271 *wl)
217{
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200218 wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300219 wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
220
221 wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
222 wl->mbox_ptr[0], wl->mbox_ptr[1]);
223}
224
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200225int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300226{
227 struct event_mailbox mbox;
228 int ret;
229
230 wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
231
232 if (mbox_num > 1)
233 return -EINVAL;
234
235 /* first we read the mbox descriptor */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200236 wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
237 sizeof(struct event_mailbox), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300238
239 /* process the descriptor */
240 ret = wl1271_event_process(wl, &mbox);
241 if (ret < 0)
242 return ret;
243
244 /* then we let the firmware know it can go on...*/
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200245 wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300246
247 return 0;
248}