event.c 12.0 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
	if (!test_and_clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags))
53 54
		goto out;

55
	if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
56 57 58 59 60 61 62
		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
{
	int delay = wl->conf.conn.ps_poll_recovery_period;
	int ret;

81 82
	wlvif->ps_poll_failures++;
	if (wlvif->ps_poll_failures == 1)
83 84 85 86
		wl1271_info("AP with dysfunctional ps-poll, "
			    "trying to work around it.");

	/* force active mode receive data from the AP */
87
	if (test_bit(WLVIF_FLAG_PSM, &wlvif->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
		if (ret < 0)
			return;
92
		set_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->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(WLVIF_FLAG_PSM, &wlvif->flags)) {
J
Juuso Oikarinen 已提交
120
			/* remain in active mode */
121
			wlvif->psm_entry_retry = 0;
122 123 124
			break;
		}

125 126
		if (wlvif->psm_entry_retry < total_retries) {
			wlvif->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
			wlvif->psm_entry_retry = 0;
133
			*beacon_loss = true;
134 135 136
		}
		break;
	case EVENT_ENTER_POWER_SAVE_SUCCESS:
137
		wlvif->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
		/*
		 * BET has only a minor effect in 5GHz and masks
		 * channel switch IEs, so we only enable BET on 2.4GHz
		*/
E
Eliad Peller 已提交
148
		if (wlvif->band == IEEE80211_BAND_2GHZ)
149
			/* enable beacon early termination */
E
Eliad Peller 已提交
150
			ret = wl1271_acx_bet_enable(wl, wlvif, true);
151

E
Eliad Peller 已提交
152 153 154
		if (wlvif->ps_compl) {
			complete(wlvif->ps_compl);
			wlvif->ps_compl = NULL;
155
		}
156 157 158 159 160 161 162 163
		break;
	default:
		break;
	}

	return ret;
}

164
static void wl1271_event_rssi_trigger(struct wl1271 *wl,
165
				      struct wl12xx_vif *wlvif,
166 167
				      struct event_mailbox *mbox)
{
168
	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
169 170 171 172 173
	enum nl80211_cqm_rssi_threshold_event event;
	s8 metric = mbox->rssi_snr_trigger_metric[0];

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

174
	if (metric <= wlvif->rssi_thold)
175 176 177 178
		event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
	else
		event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;

179 180 181
	if (event != wlvif->last_rssi_event)
		ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
	wlvif->last_rssi_event = event;
182 183
}

E
Eliad Peller 已提交
184
static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
185
{
186 187
	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);

E
Eliad Peller 已提交
188
	if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
E
Eliad Peller 已提交
189
		if (!wlvif->sta.ba_rx_bitmap)
190
			return;
191 192
		ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap,
					     vif->bss_conf.bssid);
193
	} else {
194
		u8 hlid;
195
		struct wl1271_link *lnk;
196 197 198 199
		for_each_set_bit(hlid, wlvif->ap.sta_hlid_map,
				 WL12XX_MAX_LINKS) {
			lnk = &wl->links[hlid];
			if (!lnk->ba_bitmap)
200 201
				continue;

202
			ieee80211_stop_rx_ba_session(vif,
203 204 205 206
						     lnk->ba_bitmap,
						     lnk->addr);
		}
	}
207 208
}

209 210 211
static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
					       u8 enable)
{
212 213 214
	struct ieee80211_vif *vif;
	struct wl12xx_vif *wlvif;

215 216
	if (enable) {
		/* disable dynamic PS when requested by the firmware */
217 218 219 220
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
			vif = wl12xx_wlvif_to_vif(wlvif);
			ieee80211_disable_dyn_ps(vif);
		}
221 222
		set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
	} else {
E
Eliad Peller 已提交
223
		clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
224 225 226
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
			vif = wl12xx_wlvif_to_vif(wlvif);
			ieee80211_enable_dyn_ps(vif);
E
Eliad Peller 已提交
227
			wl1271_recalc_rx_streaming(wl, wlvif);
228
		}
229 230 231 232
	}

}

L
Luciano Coelho 已提交
233 234 235 236 237 238 239 240 241
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)
{
242 243
	struct ieee80211_vif *vif;
	struct wl12xx_vif *wlvif;
L
Luciano Coelho 已提交
244 245
	int ret;
	u32 vector;
246
	bool beacon_loss = false;
247 248
	bool disconnect_sta = false;
	unsigned long sta_bitmap = 0;
L
Luciano Coelho 已提交
249 250 251

	wl1271_event_mbox_dump(mbox);

L
Luciano Coelho 已提交
252 253
	vector = le32_to_cpu(mbox->events_vector);
	vector &= ~(le32_to_cpu(mbox->events_mask));
L
Luciano Coelho 已提交
254 255 256
	wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);

	if (vector & SCAN_COMPLETE_EVENT_ID) {
257 258 259
		wl1271_debug(DEBUG_EVENT, "status: 0x%x",
			     mbox->scheduled_scan_status);

260
		wl1271_scan_stm(wl, wl->scan_vif);
L
Luciano Coelho 已提交
261 262
	}

263 264 265
	if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT "
			     "(status 0x%0x)", mbox->scheduled_scan_status);
266 267

		wl1271_scan_sched_scan_results(wl);
268 269 270 271 272
	}

	if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT "
			     "(status 0x%0x)", mbox->scheduled_scan_status);
273 274 275 276
		if (wl->sched_scanning) {
			wl1271_scan_sched_scan_stop(wl);
			ieee80211_sched_scan_stopped(wl->hw);
		}
277 278
	}

279
	if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
280 281
		wl12xx_event_soft_gemini_sense(wl,
					       mbox->soft_gemini_sense_info);
282

283 284 285 286
	/*
	 * 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.
287 288 289 290
	 *
	 * As there's possibility that the driver disables PSM before receiving
	 * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
	 *
291
	 */
292 293
	if (vector & BSS_LOSE_EVENT_ID) {
		/* TODO: check for multi-role */
294
		wl1271_info("Beacon loss detected.");
L
Luciano Coelho 已提交
295

296
		/* indicate to the stack, that beacons have been lost */
297 298 299
		beacon_loss = true;
	}

300
	if (vector & PS_REPORT_EVENT_ID) {
301
		wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
302 303 304 305 306 307
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
			ret = wl1271_event_ps_report(wl, wlvif,
						     mbox, &beacon_loss);
			if (ret < 0)
				return ret;
		}
308 309
	}

310 311 312 313
	if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
			wl1271_event_pspoll_delivery_fail(wl, wlvif);
		}
314

315
	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
316
		/* TODO: check actual multi-role support */
317
		wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
318 319 320
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
			wl1271_event_rssi_trigger(wl, wlvif, mbox);
		}
321 322
	}

323 324
	if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) {
		u8 role_id = mbox->role_id;
325
		wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
326 327
			     "ba_allowed = 0x%x, role_id=%d",
			     mbox->rx_ba_allowed, role_id);
328

329 330 331
		wl12xx_for_each_wlvif(wl, wlvif) {
			if (role_id != 0xff && role_id != wlvif->role_id)
				continue;
332

333 334 335 336
			wlvif->ba_allowed = !!mbox->rx_ba_allowed;
			if (!wlvif->ba_allowed)
				wl1271_stop_ba_event(wl, wlvif);
		}
337 338
	}

339
	if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) {
340 341 342 343 344 345 346 347
		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
		 */
348 349 350 351 352 353 354 355 356 357 358 359

		/* TODO: configure only the relevant vif */
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
			struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
			bool success;

			if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
						&wl->flags))
				continue;

			success = mbox->channel_switch_status ? false : true;
			ieee80211_chswitch_done(vif, success);
360
		}
361 362
	}

363
	if ((vector & DUMMY_PACKET_EVENT_ID)) {
364
		wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
365
		wl1271_tx_dummy_packet(wl);
366 367
	}

368 369 370 371
	/*
	 * "TX retries exceeded" has a different meaning according to mode.
	 * In AP mode the offending station is disconnected.
	 */
372
	if (vector & MAX_TX_RETRY_EVENT_ID) {
373 374 375 376 377
		wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
		sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
		disconnect_sta = true;
	}

378
	if (vector & INACTIVE_STA_EVENT_ID) {
379 380 381 382 383
		wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
		sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
		disconnect_sta = true;
	}

384
	if (disconnect_sta) {
385 386 387 388 389
		u32 num_packets = wl->conf.tx.max_tx_retries;
		struct ieee80211_sta *sta;
		const u8 *addr;
		int h;

390
		for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
391 392 393 394 395 396 397 398 399
			bool found = false;
			/* find the ap vif connected to this sta */
			wl12xx_for_each_wlvif_ap(wl, wlvif) {
				if (!test_bit(h, wlvif->ap.sta_hlid_map))
					continue;
				found = true;
				break;
			}
			if (!found)
400 401
				continue;

402
			vif = wl12xx_wlvif_to_vif(wlvif);
403 404 405
			addr = wl->links[h].addr;

			rcu_read_lock();
406
			sta = ieee80211_find_sta(vif, addr);
407 408 409 410 411 412 413 414
			if (sta) {
				wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
				ieee80211_report_low_ack(sta, num_packets);
			}
			rcu_read_unlock();
		}
	}

415 416 417 418 419
	if (beacon_loss)
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
			vif = wl12xx_wlvif_to_vif(wlvif);
			ieee80211_connection_loss(vif);
		}
L
Luciano Coelho 已提交
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436

	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 已提交
437
	wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
L
Luciano Coelho 已提交
438 439 440 441 442 443
	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]);
}

444
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
L
Luciano Coelho 已提交
445 446 447 448 449 450 451 452 453 454
{
	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 已提交
455 456
	wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
		    sizeof(struct event_mailbox), false);
L
Luciano Coelho 已提交
457 458 459 460 461 462 463

	/* 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 已提交
464
	wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
L
Luciano Coelho 已提交
465 466 467

	return 0;
}