blob: a5c1910a0247935774842536b4c08a77c9bf54f3 [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{
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030034 int size = sizeof(struct wl12xx_probe_req_template);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035 wl1271_debug(DEBUG_EVENT, "status: 0x%x",
36 mbox->scheduled_scan_status);
37
Juuso Oikarinen71449f82009-12-11 15:41:07 +020038 if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030039 if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
40 wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
41 NULL, size);
42 /* 2.4 GHz band scanned, scan 5 GHz band, pretend
43 * to the wl1271_cmd_scan function that we are not
44 * scanning as it checks that.
45 */
Juuso Oikarinen71449f82009-12-11 15:41:07 +020046 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
Kalle Valo818e3062010-03-18 12:26:35 +020047 /* FIXME: ie missing! */
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030048 wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
Kalle Valo818e3062010-03-18 12:26:35 +020049 NULL, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030050 wl->scan.active,
51 wl->scan.high_prio,
52 WL1271_SCAN_BAND_5_GHZ,
53 wl->scan.probe_requests);
54 } else {
55 if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
56 wl1271_cmd_template_set(wl,
57 CMD_TEMPL_CFG_PROBE_REQ_2_4,
58 NULL, size);
59 else
60 wl1271_cmd_template_set(wl,
61 CMD_TEMPL_CFG_PROBE_REQ_5,
62 NULL, size);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030063
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030064 mutex_unlock(&wl->mutex);
65 ieee80211_scan_completed(wl->hw, false);
66 mutex_lock(&wl->mutex);
Juuso Oikarinen71449f82009-12-11 15:41:07 +020067 clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030068 }
69 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030070 return 0;
71}
72
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020073static int wl1271_event_ps_report(struct wl1271 *wl,
74 struct event_mailbox *mbox,
75 bool *beacon_loss)
76{
77 int ret = 0;
78
79 wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
80
81 switch (mbox->ps_status) {
82 case EVENT_ENTER_POWER_SAVE_FAIL:
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020083 wl1271_debug(DEBUG_PSM, "PSM entry failed");
84
Juuso Oikarinen71449f82009-12-11 15:41:07 +020085 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020086 /* remain in active mode */
Juuso Oikarinen461fa132009-11-23 23:22:13 +020087 wl->psm_entry_retry = 0;
88 break;
89 }
90
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020091 if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
92 wl->psm_entry_retry++;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020093 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
94 true);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020095 } else {
Juuso Oikarinen461fa132009-11-23 23:22:13 +020096 wl1271_error("PSM entry failed, giving up.\n");
Juuso Oikarinen30240fc2010-02-18 13:25:38 +020097 /* FIXME: this may need to be reconsidered. for now it
98 is not possible to indicate to the mac80211
99 afterwards that PSM entry failed. To maximize
100 functionality (receiving data and remaining
101 associated) make sure that we are in sync with the
102 AP in regard of PSM mode. */
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200103 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
104 false);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200105 wl->psm_entry_retry = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200106 }
107 break;
108 case EVENT_ENTER_POWER_SAVE_SUCCESS:
109 wl->psm_entry_retry = 0;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200110
111 /* enable beacon filtering */
112 ret = wl1271_acx_beacon_filter_opt(wl, true);
113 if (ret < 0)
114 break;
115
116 /* enable beacon early termination */
117 ret = wl1271_acx_bet_enable(wl, true);
118 if (ret < 0)
119 break;
120
121 /* go to extremely low power mode */
122 wl1271_ps_elp_sleep(wl);
123 if (ret < 0)
124 break;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200125 break;
126 case EVENT_EXIT_POWER_SAVE_FAIL:
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200127 wl1271_debug(DEBUG_PSM, "PSM exit failed");
128
129 if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
130 wl->psm_entry_retry = 0;
131 break;
132 }
133
Juuso Oikarinen30240fc2010-02-18 13:25:38 +0200134 /* make sure the firmware goes to active mode - the frame to
135 be sent next will indicate to the AP, that we are active. */
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200136 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
137 false);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200138 break;
139 case EVENT_EXIT_POWER_SAVE_SUCCESS:
140 default:
141 break;
142 }
143
144 return ret;
145}
146
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300147static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
148{
149 wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
150 wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
151 wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
152}
153
154static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
155{
156 int ret;
157 u32 vector;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200158 bool beacon_loss = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300159
160 wl1271_event_mbox_dump(mbox);
161
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300162 vector = le32_to_cpu(mbox->events_vector);
163 vector &= ~(le32_to_cpu(mbox->events_mask));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300164 wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
165
166 if (vector & SCAN_COMPLETE_EVENT_ID) {
167 ret = wl1271_event_scan_complete(wl, mbox);
168 if (ret < 0)
169 return ret;
170 }
171
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300172 /*
173 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
174 * filtering) is enabled. Without PSM, the stack will receive all
175 * beacons and can detect beacon loss by itself.
Teemu Paasikivi64e29e42010-03-26 12:53:26 +0200176 *
177 * As there's possibility that the driver disables PSM before receiving
178 * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
179 *
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300180 */
Teemu Paasikivi64e29e42010-03-26 12:53:26 +0200181 if (vector & BSS_LOSE_EVENT_ID) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300182 wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
183
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300184 /* indicate to the stack, that beacons have been lost */
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200185 beacon_loss = true;
186 }
187
188 if (vector & PS_REPORT_EVENT_ID) {
189 wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
190 ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
191 if (ret < 0)
192 return ret;
193 }
194
Juuso Oikarinen04477bf2009-12-11 15:41:09 +0200195 if (wl->vif && beacon_loss) {
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200196 /* Obviously, it's dangerous to release the mutex while
197 we are holding many of the variables in the wl struct.
198 That's why it's done last in the function, and care must
199 be taken that nothing more is done after this function
200 returns. */
201 mutex_unlock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300202 ieee80211_beacon_loss(wl->vif);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200203 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300204 }
205
206 return 0;
207}
208
209int wl1271_event_unmask(struct wl1271 *wl)
210{
211 int ret;
212
213 ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask));
214 if (ret < 0)
215 return ret;
216
217 return 0;
218}
219
220void wl1271_event_mbox_config(struct wl1271 *wl)
221{
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200222 wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300223 wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
224
225 wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
226 wl->mbox_ptr[0], wl->mbox_ptr[1]);
227}
228
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200229int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300230{
231 struct event_mailbox mbox;
232 int ret;
233
234 wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
235
236 if (mbox_num > 1)
237 return -EINVAL;
238
239 /* first we read the mbox descriptor */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200240 wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
241 sizeof(struct event_mailbox), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300242
243 /* process the descriptor */
244 ret = wl1271_event_process(wl, &mbox);
245 if (ret < 0)
246 return ret;
247
248 /* then we let the firmware know it can go on...*/
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200249 wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300250
251 return 0;
252}