event.c 11.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 41

	dwork = container_of(work, struct delayed_work, work);
	wl = container_of(dwork, struct wl1271, pspoll_work);
E
Eliad Peller 已提交
42 43
	vif = wl->vif; /* TODO: move work into vif struct */
	wlvif = wl12xx_vif_to_data(vif);
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, 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)) {
88
		ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
E
Eliad Peller 已提交
89
					 wlvif->basic_rate, true);
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
		if (ret < 0)
			return;
		set_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
		ieee80211_queue_delayed_work(wl->hw, &wl->pspoll_work,
					     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++;
J
Juuso Oikarinen 已提交
127
			ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
E
Eliad Peller 已提交
128
						 wlvif->basic_rate, true);
129
		} else {
130
			wl1271_info("No ack to nullfunc from AP.");
131
			wl->psm_entry_retry = 0;
132
			*beacon_loss = true;
133 134 135 136
		}
		break;
	case EVENT_ENTER_POWER_SAVE_SUCCESS:
		wl->psm_entry_retry = 0;
J
Juuso Oikarinen 已提交
137 138 139 140 141 142

		/* enable beacon filtering */
		ret = wl1271_acx_beacon_filter_opt(wl, true);
		if (ret < 0)
			break;

143 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 */
			ret = wl1271_acx_bet_enable(wl, true);
150 151 152 153 154

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

	return ret;
}

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
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;
}

181
static void wl1271_stop_ba_event(struct wl1271 *wl)
182
{
183 184 185 186
	if (wl->bss_type != BSS_TYPE_AP_BSS) {
		if (!wl->ba_rx_bitmap)
			return;
		ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap,
187
					     wl->vif->bss_conf.bssid);
188 189 190
	} else {
		int i;
		struct wl1271_link *lnk;
191
		for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) {
192 193 194 195 196 197 198 199 200
			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);
		}
	}
201 202
}

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

	wl1271_event_mbox_dump(mbox);

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

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

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

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

		wl1271_scan_sched_scan_results(wl);
254 255 256 257 258
	}

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

265
	if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
266 267 268
	    wl->bss_type == BSS_TYPE_STA_BSS)
		wl12xx_event_soft_gemini_sense(wl,
					       mbox->soft_gemini_sense_info);
269

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

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

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

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

296 297 298 299 300 301
	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);
	}

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

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

		if (wl->vif && !wl->ba_allowed)
			wl1271_stop_ba_event(wl);
310 311
	}

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
	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);
	}

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

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

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

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

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

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

	return 0;
}