event.c 7.7 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
 *
 */

24
#include "wlcore.h"
25
#include "debug.h"
S
Shahar Levi 已提交
26 27 28 29
#include "io.h"
#include "event.h"
#include "ps.h"
#include "scan.h"
30
#include "wl12xx_80211.h"
L
Luciano Coelho 已提交
31

32
void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr)
33
{
34 35
	struct wl12xx_vif *wlvif;
	struct ieee80211_vif *vif;
36
	enum nl80211_cqm_rssi_threshold_event event;
37
	s8 metric = metric_arr[0];
38 39 40

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

41 42 43 44 45 46 47 48 49 50 51 52
	/* TODO: check actual multi-role support */
	wl12xx_for_each_wlvif_sta(wl, wlvif) {
		if (metric <= wlvif->rssi_thold)
			event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
		else
			event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;

		vif = wl12xx_wlvif_to_vif(wlvif);
		if (event != wlvif->last_rssi_event)
			ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
		wlvif->last_rssi_event = event;
	}
53
}
54
EXPORT_SYMBOL_GPL(wlcore_event_rssi_trigger);
55

E
Eliad Peller 已提交
56
static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
57
{
58 59
	struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);

E
Eliad Peller 已提交
60
	if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
E
Eliad Peller 已提交
61
		if (!wlvif->sta.ba_rx_bitmap)
62
			return;
63 64
		ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap,
					     vif->bss_conf.bssid);
65
	} else {
66
		u8 hlid;
67
		struct wl1271_link *lnk;
68 69 70 71
		for_each_set_bit(hlid, wlvif->ap.sta_hlid_map,
				 WL12XX_MAX_LINKS) {
			lnk = &wl->links[hlid];
			if (!lnk->ba_bitmap)
72 73
				continue;

74
			ieee80211_stop_rx_ba_session(vif,
75 76 77 78
						     lnk->ba_bitmap,
						     lnk->addr);
		}
	}
79 80
}

81
void wlcore_event_soft_gemini_sense(struct wl1271 *wl, u8 enable)
82
{
83 84
	struct wl12xx_vif *wlvif;

85 86 87
	if (enable) {
		set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
	} else {
E
Eliad Peller 已提交
88
		clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
89
		wl12xx_for_each_wlvif_sta(wl, wlvif) {
E
Eliad Peller 已提交
90
			wl1271_recalc_rx_streaming(wl, wlvif);
91
		}
92 93
	}
}
94
EXPORT_SYMBOL_GPL(wlcore_event_soft_gemini_sense);
95

96 97
void wlcore_event_sched_scan_report(struct wl1271 *wl,
				    u8 status)
L
Luciano Coelho 已提交
98
{
99 100 101 102
	wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT (status 0x%0x)",
		     status);

	wl1271_scan_sched_scan_results(wl);
L
Luciano Coelho 已提交
103
}
104
EXPORT_SYMBOL_GPL(wlcore_event_sched_scan_report);
L
Luciano Coelho 已提交
105

106 107
void wlcore_event_sched_scan_completed(struct wl1271 *wl,
				       u8 status)
L
Luciano Coelho 已提交
108
{
109 110
	wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT (status 0x%0x)",
		     status);
L
Luciano Coelho 已提交
111

112 113 114 115 116 117
	if (wl->sched_scanning) {
		ieee80211_sched_scan_stopped(wl->hw);
		wl->sched_scanning = false;
	}
}
EXPORT_SYMBOL_GPL(wlcore_event_sched_scan_completed);
L
Luciano Coelho 已提交
118

119 120 121 122 123
void wlcore_event_ba_rx_constraint(struct wl1271 *wl,
				   unsigned long roles_bitmap,
				   unsigned long allowed_bitmap)
{
	struct wl12xx_vif *wlvif;
L
Luciano Coelho 已提交
124

125 126
	wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx allowed=0x%lx",
		     __func__, roles_bitmap, allowed_bitmap);
127

128 129 130 131
	wl12xx_for_each_wlvif(wl, wlvif) {
		if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
		    !test_bit(wlvif->role_id , &roles_bitmap))
			continue;
L
Luciano Coelho 已提交
132

133 134 135 136
		wlvif->ba_allowed = !!test_bit(wlvif->role_id,
					       &allowed_bitmap);
		if (!wlvif->ba_allowed)
			wl1271_stop_ba_event(wl, wlvif);
137
	}
138 139
}
EXPORT_SYMBOL_GPL(wlcore_event_ba_rx_constraint);
140

141 142 143 144 145 146
void wlcore_event_channel_switch(struct wl1271 *wl,
				 unsigned long roles_bitmap,
				 bool success)
{
	struct wl12xx_vif *wlvif;
	struct ieee80211_vif *vif;
147

148 149
	wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d",
		     __func__, roles_bitmap, success);
150

151 152 153 154
	wl12xx_for_each_wlvif_sta(wl, wlvif) {
		if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
		    !test_bit(wlvif->role_id , &roles_bitmap))
			continue;
155

156 157 158
		if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS,
					&wlvif->flags))
			continue;
159

160
		vif = wl12xx_wlvif_to_vif(wlvif);
161

162 163
		ieee80211_chswitch_done(vif, success);
		cancel_delayed_work(&wlvif->channel_switch_work);
164
	}
165 166
}
EXPORT_SYMBOL_GPL(wlcore_event_channel_switch);
L
Luciano Coelho 已提交
167

168 169 170 171 172 173
void wlcore_event_dummy_packet(struct wl1271 *wl)
{
	wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
	wl1271_tx_dummy_packet(wl);
}
EXPORT_SYMBOL_GPL(wlcore_event_dummy_packet);
174

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
static void wlcore_disconnect_sta(struct wl1271 *wl, unsigned long sta_bitmap)
{
	u32 num_packets = wl->conf.tx.max_tx_retries;
	struct wl12xx_vif *wlvif;
	struct ieee80211_vif *vif;
	struct ieee80211_sta *sta;
	const u8 *addr;
	int h;

	for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
		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;
192
		}
193 194
		if (!found)
			continue;
195

196 197
		vif = wl12xx_wlvif_to_vif(wlvif);
		addr = wl->links[h].addr;
198

199 200 201 202 203
		rcu_read_lock();
		sta = ieee80211_find_sta(vif, addr);
		if (sta) {
			wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
			ieee80211_report_low_ack(sta, num_packets);
204
		}
205
		rcu_read_unlock();
206
	}
207
}
208

209 210 211 212 213 214
void wlcore_event_max_tx_failure(struct wl1271 *wl, unsigned long sta_bitmap)
{
	wl1271_debug(DEBUG_EVENT, "MAX_TX_FAILURE_EVENT_ID");
	wlcore_disconnect_sta(wl, sta_bitmap);
}
EXPORT_SYMBOL_GPL(wlcore_event_max_tx_failure);
215

216 217 218 219 220 221
void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap)
{
	wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
	wlcore_disconnect_sta(wl, sta_bitmap);
}
EXPORT_SYMBOL_GPL(wlcore_event_inactive_sta);
222

223 224 225 226 227 228 229
void wlcore_event_roc_complete(struct wl1271 *wl)
{
	wl1271_debug(DEBUG_EVENT, "REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID");
	if (wl->roc_vif)
		ieee80211_ready_on_channel(wl->hw);
}
EXPORT_SYMBOL_GPL(wlcore_event_roc_complete);
230

231 232
void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
{
233
	/*
234 235
	 * We are HW_MONITOR device. On beacon loss - queue
	 * connection loss work. Cancel it on REGAINED event.
236
	 */
237 238 239 240
	struct wl12xx_vif *wlvif;
	struct ieee80211_vif *vif;
	int delay = wl->conf.conn.synch_fail_thold *
				wl->conf.conn.bss_lose_timeout;
241

242
	wl1271_info("Beacon loss detected. roles:0x%lx", roles_bitmap);
243

244 245 246 247
	wl12xx_for_each_wlvif_sta(wl, wlvif) {
		if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
		    !test_bit(wlvif->role_id , &roles_bitmap))
			continue;
248

249 250 251 252 253 254 255 256
		/*
		 * if the work is already queued, it should take place.
		 * We don't want to delay the connection loss
		 * indication any more.
		 */
		ieee80211_queue_delayed_work(wl->hw,
					     &wlvif->connection_loss_work,
					     msecs_to_jiffies(delay));
257

258 259 260 261 262
		vif = wl12xx_wlvif_to_vif(wlvif);
		ieee80211_cqm_rssi_notify(
				vif,
				NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
				GFP_KERNEL);
263
	}
L
Luciano Coelho 已提交
264
}
265
EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss);
L
Luciano Coelho 已提交
266 267 268 269 270 271 272 273 274 275 276 277

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;
}

278
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
L
Luciano Coelho 已提交
279 280 281 282 283 284 285 286 287
{
	int ret;

	wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);

	if (mbox_num > 1)
		return -EINVAL;

	/* first we read the mbox descriptor */
288
	ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox,
289
			  wl->mbox_size, false);
290 291
	if (ret < 0)
		return ret;
L
Luciano Coelho 已提交
292 293

	/* process the descriptor */
294
	ret = wl->ops->process_mailbox_events(wl);
L
Luciano Coelho 已提交
295 296 297
	if (ret < 0)
		return ret;

298 299 300 301
	/*
	 * TODO: we just need this because one bit is in a different
	 * place.  Is there any better way?
	 */
302
	ret = wl->ops->ack_event(wl);
L
Luciano Coelho 已提交
303

304
	return ret;
L
Luciano Coelho 已提交
305
}