event.c 11.2 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
{
	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 87
		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
			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 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

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 ieee80211_vif *vif,
166 167
				      struct event_mailbox *mbox)
{
168
	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
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
{
E
Eliad Peller 已提交
186
	if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
187 188 189
		if (!wl->ba_rx_bitmap)
			return;
		ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap,
190
					     wl->vif->bss_conf.bssid);
191 192 193
	} else {
		int i;
		struct wl1271_link *lnk;
194
		for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) {
195 196 197 198 199 200 201 202 203
			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);
		}
	}
204 205
}

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
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 已提交
221 222 223 224 225 226 227 228 229
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 已提交
230 231
	struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
L
Luciano Coelho 已提交
232 233
	int ret;
	u32 vector;
234
	bool beacon_loss = false;
E
Eliad Peller 已提交
235
	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
236 237
	bool disconnect_sta = false;
	unsigned long sta_bitmap = 0;
L
Luciano Coelho 已提交
238 239 240

	wl1271_event_mbox_dump(mbox);

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

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

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

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

		wl1271_scan_sched_scan_results(wl);
257 258 259 260 261
	}

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

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

273 274 275 276
	/*
	 * 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.
277 278 279 280
	 *
	 * As there's possibility that the driver disables PSM before receiving
	 * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
	 *
281
	 */
282
	if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
283
		wl1271_info("Beacon loss detected.");
L
Luciano Coelho 已提交
284

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

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

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

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

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

309 310 311
		wl->ba_allowed = !!mbox->rx_ba_allowed;

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

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
	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);
	}

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

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 374 375
	/*
	 * "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();
		}
	}

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

	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 已提交
395
	wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
L
Luciano Coelho 已提交
396 397 398 399 400 401
	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]);
}

402
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
L
Luciano Coelho 已提交
403 404 405 406 407 408 409 410 411 412
{
	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 已提交
413 414
	wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
		    sizeof(struct event_mailbox), false);
L
Luciano Coelho 已提交
415 416 417 418 419 420 421

	/* 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 已提交
422
	wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
L
Luciano Coelho 已提交
423 424 425

	return 0;
}