event.c 11.1 KB
Newer Older
L
Luciano Coelho 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * This file is part of wl1271
 *
 * Copyright (C) 2008-2009 Nokia Corporation
 *
 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

S
Shahar Levi 已提交
24 25 26 27 28 29
#include "wl12xx.h"
#include "reg.h"
#include "io.h"
#include "event.h"
#include "ps.h"
#include "scan.h"
30
#include "wl12xx_80211.h"
L
Luciano Coelho 已提交
31

32 33
void wl1271_pspoll_work(struct work_struct *work)
{
E
Eliad Peller 已提交
34 35
	struct ieee80211_vif *vif;
	struct wl12xx_vif *wlvif;
36 37
	struct delayed_work *dwork;
	struct wl1271 *wl;
38
	int ret;
39 40

	dwork = container_of(work, struct delayed_work, work);
E
Eliad Peller 已提交
41 42 43
	wlvif = container_of(dwork, struct wl12xx_vif, pspoll_work);
	vif = container_of((void *)wlvif, struct ieee80211_vif, drv_priv);
	wl = wlvif->wl;
44 45 46 47 48

	wl1271_debug(DEBUG_EVENT, "pspoll work");

	mutex_lock(&wl->mutex);

49 50 51
	if (unlikely(wl->state == WL1271_STATE_OFF))
		goto out;

52 53 54 55 56 57 58 59 60 61 62
	if (!test_and_clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags))
		goto out;

	if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
		goto out;

	/*
	 * if we end up here, then we were in powersave when the pspoll
	 * delivery failure occurred, and no-one changed state since, so
	 * we should go back to powersave.
	 */
63 64 65 66
	ret = wl1271_ps_elp_wakeup(wl);
	if (ret < 0)
		goto out;

E
Eliad Peller 已提交
67 68
	wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
			   wlvif->basic_rate, true);
69

70
	wl1271_ps_elp_sleep(wl);
71 72 73 74
out:
	mutex_unlock(&wl->mutex);
};

E
Eliad Peller 已提交
75 76
static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl,
					      struct wl12xx_vif *wlvif)
77 78 79 80 81 82 83 84 85 86 87
{
	int delay = wl->conf.conn.ps_poll_recovery_period;
	int ret;

	wl->ps_poll_failures++;
	if (wl->ps_poll_failures == 1)
		wl1271_info("AP with dysfunctional ps-poll, "
			    "trying to work around it.");

	/* force active mode receive data from the AP */
	if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
E
Eliad Peller 已提交
88
		ret = wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
E
Eliad Peller 已提交
89
					 wlvif->basic_rate, true);
90 91 92
		if (ret < 0)
			return;
		set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
E
Eliad Peller 已提交
93
		ieee80211_queue_delayed_work(wl->hw, &wlvif->pspoll_work,
94 95 96 97 98 99 100 101 102 103 104
					     msecs_to_jiffies(delay));
	}

	/*
	 * If already in active mode, lets we should be getting data from
	 * the AP right away. If we enter PSM too fast after this, and data
	 * remains on the AP, we will get another event like this, and we'll
	 * go into active once more.
	 */
}

105
static int wl1271_event_ps_report(struct wl1271 *wl,
E
Eliad Peller 已提交
106
				  struct wl12xx_vif *wlvif,
107 108 109 110
				  struct event_mailbox *mbox,
				  bool *beacon_loss)
{
	int ret = 0;
111
	u32 total_retries = wl->conf.conn.psm_entry_retries;
112 113 114 115 116

	wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status);

	switch (mbox->ps_status) {
	case EVENT_ENTER_POWER_SAVE_FAIL:
J
Juuso Oikarinen 已提交
117 118
		wl1271_debug(DEBUG_PSM, "PSM entry failed");

119
		if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
J
Juuso Oikarinen 已提交
120
			/* remain in active mode */
121 122 123 124
			wl->psm_entry_retry = 0;
			break;
		}

125
		if (wl->psm_entry_retry < total_retries) {
126
			wl->psm_entry_retry++;
E
Eliad Peller 已提交
127 128
			ret = wl1271_ps_set_mode(wl, wlvif,
						 STATION_POWER_SAVE_MODE,
E
Eliad Peller 已提交
129
						 wlvif->basic_rate, true);
130
		} else {
131
			wl1271_info("No ack to nullfunc from AP.");
132
			wl->psm_entry_retry = 0;
133
			*beacon_loss = true;
134 135 136 137
		}
		break;
	case EVENT_ENTER_POWER_SAVE_SUCCESS:
		wl->psm_entry_retry = 0;
J
Juuso Oikarinen 已提交
138 139

		/* enable beacon filtering */
E
Eliad Peller 已提交
140
		ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
J
Juuso Oikarinen 已提交
141 142 143
		if (ret < 0)
			break;

144 145 146 147 148 149
		/*
		 * BET has only a minor effect in 5GHz and masks
		 * channel switch IEs, so we only enable BET on 2.4GHz
		*/
		if (wl->band == IEEE80211_BAND_2GHZ)
			/* enable beacon early termination */
E
Eliad Peller 已提交
150
			ret = wl1271_acx_bet_enable(wl, wlvif, true);
151 152 153 154 155

		if (wl->ps_compl) {
			complete(wl->ps_compl);
			wl->ps_compl = NULL;
		}
156 157 158 159 160 161 162 163
		break;
	default:
		break;
	}

	return ret;
}

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
static void wl1271_event_rssi_trigger(struct wl1271 *wl,
				      struct event_mailbox *mbox)
{
	enum nl80211_cqm_rssi_threshold_event event;
	s8 metric = mbox->rssi_snr_trigger_metric[0];

	wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric);

	if (metric <= wl->rssi_thold)
		event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
	else
		event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;

	if (event != wl->last_rssi_event)
		ieee80211_cqm_rssi_notify(wl->vif, event, GFP_KERNEL);
	wl->last_rssi_event = event;
}

E
Eliad Peller 已提交
182
static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
183
{
E
Eliad Peller 已提交
184
	if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
185 186 187
		if (!wl->ba_rx_bitmap)
			return;
		ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap,
188
					     wl->vif->bss_conf.bssid);
189 190 191
	} else {
		int i;
		struct wl1271_link *lnk;
192
		for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) {
193 194 195 196 197 198 199 200 201
			lnk = &wl->links[i];
			if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap)
				continue;

			ieee80211_stop_rx_ba_session(wl->vif,
						     lnk->ba_bitmap,
						     lnk->addr);
		}
	}
202 203
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
					       u8 enable)
{
	if (enable) {
		/* disable dynamic PS when requested by the firmware */
		ieee80211_disable_dyn_ps(wl->vif);
		set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
	} else {
		ieee80211_enable_dyn_ps(wl->vif);
		clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
		wl1271_recalc_rx_streaming(wl);
	}

}

L
Luciano Coelho 已提交
219 220 221 222 223 224 225 226 227
static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
{
	wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
	wl1271_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
	wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
}

static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
{
E
Eliad Peller 已提交
228 229
	struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
L
Luciano Coelho 已提交
230 231
	int ret;
	u32 vector;
232
	bool beacon_loss = false;
E
Eliad Peller 已提交
233
	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
234 235
	bool disconnect_sta = false;
	unsigned long sta_bitmap = 0;
L
Luciano Coelho 已提交
236 237 238

	wl1271_event_mbox_dump(mbox);

L
Luciano Coelho 已提交
239 240
	vector = le32_to_cpu(mbox->events_vector);
	vector &= ~(le32_to_cpu(mbox->events_mask));
L
Luciano Coelho 已提交
241 242 243
	wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);

	if (vector & SCAN_COMPLETE_EVENT_ID) {
244 245 246
		wl1271_debug(DEBUG_EVENT, "status: 0x%x",
			     mbox->scheduled_scan_status);

247
		wl1271_scan_stm(wl, wl->scan_vif);
L
Luciano Coelho 已提交
248 249
	}

250 251 252
	if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT "
			     "(status 0x%0x)", mbox->scheduled_scan_status);
253 254

		wl1271_scan_sched_scan_results(wl);
255 256 257 258 259
	}

	if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT "
			     "(status 0x%0x)", mbox->scheduled_scan_status);
260 261 262 263
		if (wl->sched_scanning) {
			wl1271_scan_sched_scan_stop(wl);
			ieee80211_sched_scan_stopped(wl->hw);
		}
264 265
	}

266
	if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
E
Eliad Peller 已提交
267
	    wlvif->bss_type == BSS_TYPE_STA_BSS)
268 269
		wl12xx_event_soft_gemini_sense(wl,
					       mbox->soft_gemini_sense_info);
270

271 272 273 274
	/*
	 * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
	 * filtering) is enabled. Without PSM, the stack will receive all
	 * beacons and can detect beacon loss by itself.
275 276 277 278
	 *
	 * As there's possibility that the driver disables PSM before receiving
	 * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
	 *
279
	 */
280
	if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
281
		wl1271_info("Beacon loss detected.");
L
Luciano Coelho 已提交
282

283
		/* indicate to the stack, that beacons have been lost */
284 285 286
		beacon_loss = true;
	}

287
	if ((vector & PS_REPORT_EVENT_ID) && !is_ap) {
288
		wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
E
Eliad Peller 已提交
289
		ret = wl1271_event_ps_report(wl, wlvif, mbox, &beacon_loss);
290 291 292 293
		if (ret < 0)
			return ret;
	}

294
	if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap)
E
Eliad Peller 已提交
295
		wl1271_event_pspoll_delivery_fail(wl, wlvif);
296

297 298 299 300 301 302
	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
		if (wl->vif)
			wl1271_event_rssi_trigger(wl, mbox);
	}

303
	if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) {
304
		wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
E
Eliad Peller 已提交
305
			     "ba_allowed = 0x%x", mbox->rx_ba_allowed);
306

307 308 309
		wl->ba_allowed = !!mbox->rx_ba_allowed;

		if (wl->vif && !wl->ba_allowed)
E
Eliad Peller 已提交
310
			wl1271_stop_ba_event(wl, wlvif);
311 312
	}

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
	if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) {
		wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
					  "status = 0x%x",
					  mbox->channel_switch_status);
		/*
		 * That event uses for two cases:
		 * 1) channel switch complete with status=0
		 * 2) channel switch failed status=1
		 */
		if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) &&
		    (wl->vif))
			ieee80211_chswitch_done(wl->vif,
				mbox->channel_switch_status ? false : true);
	}

328
	if ((vector & DUMMY_PACKET_EVENT_ID)) {
329 330 331 332 333
		wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
		if (wl->vif)
			wl1271_tx_dummy_packet(wl);
	}

334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
	/*
	 * "TX retries exceeded" has a different meaning according to mode.
	 * In AP mode the offending station is disconnected.
	 */
	if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) {
		wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
		sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
		disconnect_sta = true;
	}

	if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
		wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
		sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
		disconnect_sta = true;
	}

	if (is_ap && disconnect_sta) {
		u32 num_packets = wl->conf.tx.max_tx_retries;
		struct ieee80211_sta *sta;
		const u8 *addr;
		int h;

		for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
		     h < AP_MAX_LINKS;
		     h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
			if (!wl1271_is_active_sta(wl, h))
				continue;

			addr = wl->links[h].addr;

			rcu_read_lock();
			sta = ieee80211_find_sta(wl->vif, addr);
			if (sta) {
				wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
				ieee80211_report_low_ack(sta, num_packets);
			}
			rcu_read_unlock();
		}
	}

374 375
	if (wl->vif && beacon_loss)
		ieee80211_connection_loss(wl->vif);
L
Luciano Coelho 已提交
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

	return 0;
}

int wl1271_event_unmask(struct wl1271 *wl)
{
	int ret;

	ret = wl1271_acx_event_mbox_mask(wl, ~(wl->event_mask));
	if (ret < 0)
		return ret;

	return 0;
}

void wl1271_event_mbox_config(struct wl1271 *wl)
{
T
Teemu Paasikivi 已提交
393
	wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
L
Luciano Coelho 已提交
394 395 396 397 398 399
	wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);

	wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
		     wl->mbox_ptr[0], wl->mbox_ptr[1]);
}

400
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
L
Luciano Coelho 已提交
401 402 403 404 405 406 407 408 409 410
{
	struct event_mailbox mbox;
	int ret;

	wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);

	if (mbox_num > 1)
		return -EINVAL;

	/* first we read the mbox descriptor */
T
Teemu Paasikivi 已提交
411 412
	wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
		    sizeof(struct event_mailbox), false);
L
Luciano Coelho 已提交
413 414 415 416 417 418 419

	/* process the descriptor */
	ret = wl1271_event_process(wl, &mbox);
	if (ret < 0)
		return ret;

	/* then we let the firmware know it can go on...*/
T
Teemu Paasikivi 已提交
420
	wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
L
Luciano Coelho 已提交
421 422 423

	return 0;
}