blob: 8d0c18dec2cd49282446465d7e36f416d39b3533 [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"
27#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
38 if (wl->scanning) {
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 */
46 wl->scanning = false;
47 wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
48 wl->scan.active,
49 wl->scan.high_prio,
50 WL1271_SCAN_BAND_5_GHZ,
51 wl->scan.probe_requests);
52 } else {
53 if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
54 wl1271_cmd_template_set(wl,
55 CMD_TEMPL_CFG_PROBE_REQ_2_4,
56 NULL, size);
57 else
58 wl1271_cmd_template_set(wl,
59 CMD_TEMPL_CFG_PROBE_REQ_5,
60 NULL, size);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030061
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +030062 mutex_unlock(&wl->mutex);
63 ieee80211_scan_completed(wl->hw, false);
64 mutex_lock(&wl->mutex);
65 wl->scanning = false;
66 }
67 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030068 return 0;
69}
70
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020071static int wl1271_event_ps_report(struct wl1271 *wl,
72 struct event_mailbox *mbox,
73 bool *beacon_loss)
74{
75 int ret = 0;
76
77 wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);
78
79 switch (mbox->ps_status) {
80 case EVENT_ENTER_POWER_SAVE_FAIL:
Juuso Oikarinen461fa132009-11-23 23:22:13 +020081 if (!wl->psm) {
82 wl->psm_entry_retry = 0;
83 break;
84 }
85
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020086 if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
87 wl->psm_entry_retry++;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020088 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
89 } else {
Juuso Oikarinen461fa132009-11-23 23:22:13 +020090 wl1271_error("PSM entry failed, giving up.\n");
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020091 wl->psm_entry_retry = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +020092 }
93 break;
94 case EVENT_ENTER_POWER_SAVE_SUCCESS:
95 wl->psm_entry_retry = 0;
96 break;
97 case EVENT_EXIT_POWER_SAVE_FAIL:
98 wl1271_info("PSM exit failed");
99 break;
100 case EVENT_EXIT_POWER_SAVE_SUCCESS:
101 default:
102 break;
103 }
104
105 return ret;
106}
107
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300108static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
109{
110 wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
111 wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
112 wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
113}
114
115static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
116{
117 int ret;
118 u32 vector;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200119 bool beacon_loss = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300120
121 wl1271_event_mbox_dump(mbox);
122
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300123 vector = le32_to_cpu(mbox->events_vector);
124 vector &= ~(le32_to_cpu(mbox->events_mask));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300125 wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
126
127 if (vector & SCAN_COMPLETE_EVENT_ID) {
128 ret = wl1271_event_scan_complete(wl, mbox);
129 if (ret < 0)
130 return ret;
131 }
132
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300133 /*
134 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
135 * filtering) is enabled. Without PSM, the stack will receive all
136 * beacons and can detect beacon loss by itself.
137 */
138 if (vector & BSS_LOSE_EVENT_ID && wl->psm) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300139 wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
140
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300141 /* indicate to the stack, that beacons have been lost */
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200142 beacon_loss = true;
143 }
144
145 if (vector & PS_REPORT_EVENT_ID) {
146 wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
147 ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
148 if (ret < 0)
149 return ret;
150 }
151
152 if (beacon_loss) {
153 /* Obviously, it's dangerous to release the mutex while
154 we are holding many of the variables in the wl struct.
155 That's why it's done last in the function, and care must
156 be taken that nothing more is done after this function
157 returns. */
158 mutex_unlock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +0300159 ieee80211_beacon_loss(wl->vif);
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200160 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300161 }
162
163 return 0;
164}
165
166int wl1271_event_unmask(struct wl1271 *wl)
167{
168 int ret;
169
170 ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask));
171 if (ret < 0)
172 return ret;
173
174 return 0;
175}
176
177void wl1271_event_mbox_config(struct wl1271 *wl)
178{
Juuso Oikarinen74621412009-10-12 15:08:54 +0300179 wl->mbox_ptr[0] = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300180 wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
181
182 wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
183 wl->mbox_ptr[0], wl->mbox_ptr[1]);
184}
185
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200186int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300187{
188 struct event_mailbox mbox;
189 int ret;
190
191 wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
192
193 if (mbox_num > 1)
194 return -EINVAL;
195
196 /* first we read the mbox descriptor */
Juuso Oikarinen74621412009-10-12 15:08:54 +0300197 wl1271_spi_read(wl, wl->mbox_ptr[mbox_num], &mbox,
198 sizeof(struct event_mailbox), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300199
200 /* process the descriptor */
201 ret = wl1271_event_process(wl, &mbox);
202 if (ret < 0)
203 return ret;
204
205 /* then we let the firmware know it can go on...*/
Juuso Oikarinen13f2dc52009-12-11 15:40:59 +0200206 wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300207
208 return 0;
209}