event.c 10.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 34 35
void wl1271_pspoll_work(struct work_struct *work)
{
	struct delayed_work *dwork;
	struct wl1271 *wl;
36
	int ret;
37 38 39 40 41 42 43 44

	dwork = container_of(work, struct delayed_work, work);
	wl = container_of(dwork, struct wl1271, pspoll_work);

	wl1271_debug(DEBUG_EVENT, "pspoll work");

	mutex_lock(&wl->mutex);

45 46 47
	if (unlikely(wl->state == WL1271_STATE_OFF))
		goto out;

48 49 50 51 52 53 54 55 56 57 58
	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.
	 */
59 60 61 62
	ret = wl1271_ps_elp_wakeup(wl);
	if (ret < 0)
		goto out;

63
	wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true);
64

65
	wl1271_ps_elp_sleep(wl);
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
out:
	mutex_unlock(&wl->mutex);
};

static void wl1271_event_pspoll_delivery_fail(struct wl1271 *wl)
{
	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)) {
82 83
		ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
					 wl->basic_rate, true);
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
		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.
	 */
}

99 100 101 102 103
static int wl1271_event_ps_report(struct wl1271 *wl,
				  struct event_mailbox *mbox,
				  bool *beacon_loss)
{
	int ret = 0;
104
	u32 total_retries = wl->conf.conn.psm_entry_retries;
105 106 107 108 109

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

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

112
		if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
J
Juuso Oikarinen 已提交
113
			/* remain in active mode */
114 115 116 117
			wl->psm_entry_retry = 0;
			break;
		}

118
		if (wl->psm_entry_retry < total_retries) {
119
			wl->psm_entry_retry++;
J
Juuso Oikarinen 已提交
120
			ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
121
						 wl->basic_rate, true);
122
		} else {
123
			wl1271_info("No ack to nullfunc from AP.");
124
			wl->psm_entry_retry = 0;
125
			*beacon_loss = true;
126 127 128 129
		}
		break;
	case EVENT_ENTER_POWER_SAVE_SUCCESS:
		wl->psm_entry_retry = 0;
J
Juuso Oikarinen 已提交
130 131 132 133 134 135

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

136 137 138 139 140 141 142
		/*
		 * 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);
143 144 145 146 147

		if (wl->ps_compl) {
			complete(wl->ps_compl);
			wl->ps_compl = NULL;
		}
148 149 150 151 152 153 154 155
		break;
	default:
		break;
	}

	return ret;
}

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
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;
}

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed)
{
	/* Convert the value to bool */
	wl->ba_allowed = !!ba_allowed;

	/*
	 * Return in case:
	 * there are not BA open or the event indication is to allowed BA
	 */
	if ((!wl->ba_rx_bitmap) || (wl->ba_allowed))
		return;

	ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid);
}

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
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 已提交
204 205 206 207 208 209 210 211 212 213 214
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)
{
	int ret;
	u32 vector;
215
	bool beacon_loss = false;
216
	bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
217 218
	bool disconnect_sta = false;
	unsigned long sta_bitmap = 0;
L
Luciano Coelho 已提交
219 220 221

	wl1271_event_mbox_dump(mbox);

L
Luciano Coelho 已提交
222 223
	vector = le32_to_cpu(mbox->events_vector);
	vector &= ~(le32_to_cpu(mbox->events_mask));
L
Luciano Coelho 已提交
224 225 226
	wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);

	if (vector & SCAN_COMPLETE_EVENT_ID) {
227 228 229
		wl1271_debug(DEBUG_EVENT, "status: 0x%x",
			     mbox->scheduled_scan_status);

L
Luciano Coelho 已提交
230
		wl1271_scan_stm(wl);
L
Luciano Coelho 已提交
231 232
	}

233 234 235
	if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT "
			     "(status 0x%0x)", mbox->scheduled_scan_status);
236 237

		wl1271_scan_sched_scan_results(wl);
238 239 240 241 242
	}

	if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT "
			     "(status 0x%0x)", mbox->scheduled_scan_status);
243 244 245 246
		if (wl->sched_scanning) {
			wl1271_scan_sched_scan_stop(wl);
			ieee80211_sched_scan_stopped(wl->hw);
		}
247 248
	}

249
	if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
250 251 252
	    wl->bss_type == BSS_TYPE_STA_BSS)
		wl12xx_event_soft_gemini_sense(wl,
					       mbox->soft_gemini_sense_info);
253

254 255 256 257
	/*
	 * 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.
258 259 260 261
	 *
	 * As there's possibility that the driver disables PSM before receiving
	 * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
	 *
262
	 */
263
	if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
264
		wl1271_info("Beacon loss detected.");
L
Luciano Coelho 已提交
265

266
		/* indicate to the stack, that beacons have been lost */
267 268 269
		beacon_loss = true;
	}

270
	if ((vector & PS_REPORT_EVENT_ID) && !is_ap) {
271 272 273 274 275 276
		wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
		ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
		if (ret < 0)
			return ret;
	}

277
	if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap)
278 279
		wl1271_event_pspoll_delivery_fail(wl);

280 281 282 283 284 285
	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);
	}

286 287
	if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) {
		wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
E
Eliad Peller 已提交
288
			     "ba_allowed = 0x%x", mbox->rx_ba_allowed);
289 290

		if (wl->vif)
E
Eliad Peller 已提交
291
			wl1271_stop_ba_event(wl, mbox->rx_ba_allowed);
292 293
	}

294
	if ((vector & DUMMY_PACKET_EVENT_ID)) {
295 296 297 298 299
		wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
		if (wl->vif)
			wl1271_tx_dummy_packet(wl);
	}

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
	/*
	 * "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();
		}
	}

340 341
	if (wl->vif && beacon_loss)
		ieee80211_connection_loss(wl->vif);
L
Luciano Coelho 已提交
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358

	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 已提交
359
	wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR);
L
Luciano Coelho 已提交
360 361 362 363 364 365
	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]);
}

366
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
L
Luciano Coelho 已提交
367 368 369 370 371 372 373 374 375 376
{
	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 已提交
377 378
	wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox,
		    sizeof(struct event_mailbox), false);
L
Luciano Coelho 已提交
379 380 381 382 383 384 385

	/* 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 已提交
386
	wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
L
Luciano Coelho 已提交
387 388 389

	return 0;
}