blob: daacf176cf09d9ea9348a5b79004524c840eaa35 [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 Oikarinen1a186a52010-04-01 11:38:23 +030084 wl1271_info("No ack to nullfunc from AP.");
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020085 wl->psm_entry_retry = 0;
Juuso Oikarinend60772f2010-03-26 12:53:29 +020086 *beacon_loss = true;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020087 }
88 break;
89 case EVENT_ENTER_POWER_SAVE_SUCCESS:
90 wl->psm_entry_retry = 0;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +020091
92 /* enable beacon filtering */
93 ret = wl1271_acx_beacon_filter_opt(wl, true);
94 if (ret < 0)
95 break;
96
97 /* enable beacon early termination */
98 ret = wl1271_acx_bet_enable(wl, true);
99 if (ret < 0)
100 break;
101
102 /* go to extremely low power mode */
103 wl1271_ps_elp_sleep(wl);
104 if (ret < 0)
105 break;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200106 break;
107 case EVENT_EXIT_POWER_SAVE_FAIL:
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200108 wl1271_debug(DEBUG_PSM, "PSM exit failed");
109
110 if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
111 wl->psm_entry_retry = 0;
112 break;
113 }
114
Juuso Oikarinen30240fc2010-02-18 13:25:38 +0200115 /* make sure the firmware goes to active mode - the frame to
116 be sent next will indicate to the AP, that we are active. */
Juuso Oikarinend8c42c02010-02-18 13:25:36 +0200117 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
118 false);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200119 break;
120 case EVENT_EXIT_POWER_SAVE_SUCCESS:
121 default:
122 break;
123 }
124
125 return ret;
126}
127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300128static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
129{
130 wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
131 wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
132 wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
133}
134
135static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
136{
137 int ret;
138 u32 vector;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200139 bool beacon_loss = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300140
141 wl1271_event_mbox_dump(mbox);
142
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300143 vector = le32_to_cpu(mbox->events_vector);
144 vector &= ~(le32_to_cpu(mbox->events_mask));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300145 wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
146
147 if (vector & SCAN_COMPLETE_EVENT_ID) {
148 ret = wl1271_event_scan_complete(wl, mbox);
149 if (ret < 0)
150 return ret;
151 }
152
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300153 /*
154 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
155 * filtering) is enabled. Without PSM, the stack will receive all
156 * beacons and can detect beacon loss by itself.
Teemu Paasikivi64e29e442010-03-26 12:53:26 +0200157 *
158 * As there's possibility that the driver disables PSM before receiving
159 * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
160 *
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300161 */
Teemu Paasikivi64e29e442010-03-26 12:53:26 +0200162 if (vector & BSS_LOSE_EVENT_ID) {
Juuso Oikarinen1a186a52010-04-01 11:38:23 +0300163 wl1271_info("Beacon loss detected.");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300164
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300165 /* indicate to the stack, that beacons have been lost */
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200166 beacon_loss = true;
167 }
168
169 if (vector & PS_REPORT_EVENT_ID) {
170 wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
171 ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
172 if (ret < 0)
173 return ret;
174 }
175
Juuso Oikarinend60772f2010-03-26 12:53:29 +0200176 if (wl->vif && beacon_loss)
177 ieee80211_connection_loss(wl->vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300178
179 return 0;
180}
181
182int wl1271_event_unmask(struct wl1271 *wl)
183{
184 int ret;
185
186 ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask));
187 if (ret < 0)
188 return ret;
189
190 return 0;
191}
192
193void wl1271_event_mbox_config(struct wl1271 *wl)
194{
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200195 wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300196 wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
197
198 wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
199 wl->mbox_ptr[0], wl->mbox_ptr[1]);
200}
201
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200202int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300203{
204 struct event_mailbox mbox;
205 int ret;
206
207 wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
208
209 if (mbox_num > 1)
210 return -EINVAL;
211
212 /* first we read the mbox descriptor */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200213 wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
214 sizeof(struct event_mailbox), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300215
216 /* process the descriptor */
217 ret = wl1271_event_process(wl, &mbox);
218 if (ret < 0)
219 return ret;
220
221 /* then we let the firmware know it can go on...*/
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200222 wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300223
224 return 0;
225}