event.c 11.9 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
#include "wl12xx.h"
25
#include "debug.h"
S
Shahar Levi 已提交
26 27 28 29 30
#include "reg.h"
#include "io.h"
#include "event.h"
#include "ps.h"
#include "scan.h"
31
#include "wl12xx_80211.h"
L
Luciano Coelho 已提交
32

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

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

	wl1271_debug(DEBUG_EVENT, "pspoll work");

	mutex_lock(&wl->mutex);

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

53
	if (!test_and_clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags))
54 55
		goto out;

56
	if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
57 58 59 60 61 62 63
		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.
	 */
64 65 66 67
	ret = wl1271_ps_elp_wakeup(wl);
	if (ret < 0)
		goto out;

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

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

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

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

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

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

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

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

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

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

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

E
Eliad Peller 已提交
148 149 150
		if (wlvif->ps_compl) {
			complete(wlvif->ps_compl);
			wlvif->ps_compl = NULL;
151
		}
152 153 154 155 156 157 158 159
		break;
	default:
		break;
	}

	return ret;
}

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

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

170
	if (metric <= wlvif->rssi_thold)
171 172 173 174
		event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
	else
		event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;

175 176 177
	if (event != wlvif->last_rssi_event)
		ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
	wlvif->last_rssi_event = event;
178 179
}

E
Eliad Peller 已提交
180
static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
181
{
182 183
	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);

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

198
			ieee80211_stop_rx_ba_session(vif,
199 200 201 202
						     lnk->ba_bitmap,
						     lnk->addr);
		}
	}
203 204
}

205 206 207
static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
					       u8 enable)
{
208 209 210
	struct ieee80211_vif *vif;
	struct wl12xx_vif *wlvif;

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

}

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

	wl1271_event_mbox_dump(mbox);

L
Luciano Coelho 已提交
248 249
	vector = le32_to_cpu(mbox->events_vector);
	vector &= ~(le32_to_cpu(mbox->events_mask));
L
Luciano Coelho 已提交
250 251 252
	wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);

	if (vector & SCAN_COMPLETE_EVENT_ID) {
253 254 255
		wl1271_debug(DEBUG_EVENT, "status: 0x%x",
			     mbox->scheduled_scan_status);

256
		wl1271_scan_stm(wl, wl->scan_vif);
L
Luciano Coelho 已提交
257 258
	}

259 260 261
	if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT "
			     "(status 0x%0x)", mbox->scheduled_scan_status);
262 263

		wl1271_scan_sched_scan_results(wl);
264 265 266 267 268
	}

	if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT "
			     "(status 0x%0x)", mbox->scheduled_scan_status);
269 270
		if (wl->sched_scanning) {
			ieee80211_sched_scan_stopped(wl->hw);
271
			wl->sched_scanning = false;
272
		}
273 274
	}

275
	if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
276 277
		wl12xx_event_soft_gemini_sense(wl,
					       mbox->soft_gemini_sense_info);
278

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

292
		/* indicate to the stack, that beacons have been lost */
293 294 295
		beacon_loss = true;
	}

296
	if (vector & PS_REPORT_EVENT_ID) {
297
		wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
298 299 300 301 302 303
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
			ret = wl1271_event_ps_report(wl, wlvif,
						     mbox, &beacon_loss);
			if (ret < 0)
				return ret;
		}
304 305
	}

306 307 308 309
	if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
			wl1271_event_pspoll_delivery_fail(wl, wlvif);
		}
310

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

319 320
	if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) {
		u8 role_id = mbox->role_id;
321
		wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
322 323
			     "ba_allowed = 0x%x, role_id=%d",
			     mbox->rx_ba_allowed, role_id);
324

325 326 327
		wl12xx_for_each_wlvif(wl, wlvif) {
			if (role_id != 0xff && role_id != wlvif->role_id)
				continue;
328

329 330 331 332
			wlvif->ba_allowed = !!mbox->rx_ba_allowed;
			if (!wlvif->ba_allowed)
				wl1271_stop_ba_event(wl, wlvif);
		}
333 334
	}

335
	if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) {
336 337 338 339 340 341 342 343
		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
		 */
344 345 346 347 348 349 350 351 352 353

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

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

			success = mbox->channel_switch_status ? false : true;
354 355
			vif = wl12xx_wlvif_to_vif(wlvif);

356
			ieee80211_chswitch_done(vif, success);
357
		}
358 359
	}

360
	if ((vector & DUMMY_PACKET_EVENT_ID)) {
361
		wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
362
		wl1271_tx_dummy_packet(wl);
363 364
	}

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

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

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

387
		for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
388 389 390 391 392 393 394 395 396
			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)
397 398
				continue;

399
			vif = wl12xx_wlvif_to_vif(wlvif);
400 401 402
			addr = wl->links[h].addr;

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

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

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

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

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

	return 0;
}