event.c 5.8 KB
Newer Older
K
Kalle Valo 已提交
1
/*
2
 * This file is part of wl1251
K
Kalle Valo 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * Copyright (c) 1998-2007 Texas Instruments Incorporated
 * Copyright (C) 2008 Nokia Corporation
 *
 * 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
 *
 */

K
Kalle Valo 已提交
23
#include "wl1251.h"
K
Kalle Valo 已提交
24 25 26 27
#include "reg.h"
#include "io.h"
#include "event.h"
#include "ps.h"
K
Kalle Valo 已提交
28

29
static int wl1251_event_scan_complete(struct wl1251 *wl,
K
Kalle Valo 已提交
30 31
				      struct event_mailbox *mbox)
{
32 33
	int ret = 0;

34
	wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
K
Kalle Valo 已提交
35 36 37 38
		     mbox->scheduled_scan_status,
		     mbox->scheduled_scan_channels);

	if (wl->scanning) {
39 40 41 42 43
		struct cfg80211_scan_info info = {
			.aborted = false,
		};

		ieee80211_scan_completed(wl->hw, &info);
44
		wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
K
Kalle Valo 已提交
45
		wl->scanning = false;
46 47
		if (wl->hw->conf.flags & IEEE80211_CONF_IDLE)
			ret = wl1251_ps_set_mode(wl, STATION_IDLE);
K
Kalle Valo 已提交
48 49
	}

50
	return ret;
K
Kalle Valo 已提交
51 52
}

D
David Gnedt 已提交
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
#define WL1251_PSM_ENTRY_RETRIES  3
static int wl1251_event_ps_report(struct wl1251 *wl,
				  struct event_mailbox *mbox)
{
	int ret = 0;

	wl1251_debug(DEBUG_EVENT, "ps status: %x", mbox->ps_status);

	switch (mbox->ps_status) {
	case EVENT_ENTER_POWER_SAVE_FAIL:
		wl1251_debug(DEBUG_PSM, "PSM entry failed");

		if (wl->station_mode != STATION_POWER_SAVE_MODE) {
			/* remain in active mode */
			wl->psm_entry_retry = 0;
			break;
		}

		if (wl->psm_entry_retry < WL1251_PSM_ENTRY_RETRIES) {
			wl->psm_entry_retry++;
			ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
		} else {
			wl1251_error("Power save entry failed, giving up");
			wl->psm_entry_retry = 0;
		}
		break;
	case EVENT_ENTER_POWER_SAVE_SUCCESS:
	case EVENT_EXIT_POWER_SAVE_FAIL:
	case EVENT_EXIT_POWER_SAVE_SUCCESS:
	default:
		wl->psm_entry_retry = 0;
		break;
	}

	return 0;
}

90
static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
K
Kalle Valo 已提交
91
{
92 93 94
	wl1251_debug(DEBUG_EVENT, "MBOX DUMP:");
	wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
	wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
K
Kalle Valo 已提交
95 96
}

97
static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
K
Kalle Valo 已提交
98 99 100 101
{
	int ret;
	u32 vector;

102
	wl1251_event_mbox_dump(mbox);
K
Kalle Valo 已提交
103 104

	vector = mbox->events_vector & ~(mbox->events_mask);
105
	wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector);
K
Kalle Valo 已提交
106 107

	if (vector & SCAN_COMPLETE_EVENT_ID) {
108
		ret = wl1251_event_scan_complete(wl, mbox);
K
Kalle Valo 已提交
109 110 111 112 113
		if (ret < 0)
			return ret;
	}

	if (vector & BSS_LOSE_EVENT_ID) {
114
		wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
K
Kalle Valo 已提交
115

116 117
		if (wl->psm_requested &&
		    wl->station_mode != STATION_ACTIVE_MODE) {
118
			ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
K
Kalle Valo 已提交
119 120 121 122 123
			if (ret < 0)
				return ret;
		}
	}

D
David Gnedt 已提交
124 125 126 127 128 129 130
	if (vector & PS_REPORT_EVENT_ID) {
		wl1251_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
		ret = wl1251_event_ps_report(wl, mbox);
		if (ret < 0)
			return ret;
	}

131
	if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) {
132 133 134
		wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT");

		/* indicate to the stack, that beacons have been lost */
135 136
		if (wl->vif && wl->vif->type == NL80211_IFTYPE_STATION)
			ieee80211_beacon_loss(wl->vif);
137 138
	}

139 140 141 142 143 144 145 146
	if (vector & REGAINED_BSS_EVENT_ID) {
		if (wl->psm_requested) {
			ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
			if (ret < 0)
				return ret;
		}
	}

147 148 149 150 151 152
	if (wl->vif && wl->rssi_thold) {
		if (vector & ROAMING_TRIGGER_LOW_RSSI_EVENT_ID) {
			wl1251_debug(DEBUG_EVENT,
				     "ROAMING_TRIGGER_LOW_RSSI_EVENT");
			ieee80211_cqm_rssi_notify(wl->vif,
				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
153
				0, GFP_KERNEL);
154 155 156 157 158 159 160
		}

		if (vector & ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) {
			wl1251_debug(DEBUG_EVENT,
				     "ROAMING_TRIGGER_REGAINED_RSSI_EVENT");
			ieee80211_cqm_rssi_notify(wl->vif,
				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
161
				0, GFP_KERNEL);
162 163 164
		}
	}

K
Kalle Valo 已提交
165 166 167
	return 0;
}

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/*
 * Poll the mailbox event field until any of the bits in the mask is set or a
 * timeout occurs (WL1251_EVENT_TIMEOUT in msecs)
 */
int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms)
{
	u32 events_vector, event;
	unsigned long timeout;

	timeout = jiffies + msecs_to_jiffies(timeout_ms);

	do {
		if (time_after(jiffies, timeout))
			return -ETIMEDOUT;

		msleep(1);

		/* read from both event fields */
		wl1251_mem_read(wl, wl->mbox_ptr[0], &events_vector,
				sizeof(events_vector));
		event = events_vector & mask;
		wl1251_mem_read(wl, wl->mbox_ptr[1], &events_vector,
				sizeof(events_vector));
		event |= events_vector & mask;
	} while (!event);

	return 0;
}

197
int wl1251_event_unmask(struct wl1251 *wl)
K
Kalle Valo 已提交
198 199 200
{
	int ret;

201
	ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask));
K
Kalle Valo 已提交
202 203 204 205 206 207
	if (ret < 0)
		return ret;

	return 0;
}

208
void wl1251_event_mbox_config(struct wl1251 *wl)
K
Kalle Valo 已提交
209
{
210
	wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
K
Kalle Valo 已提交
211 212
	wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);

213
	wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
K
Kalle Valo 已提交
214 215 216
		     wl->mbox_ptr[0], wl->mbox_ptr[1]);
}

217
int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num)
K
Kalle Valo 已提交
218 219 220 221
{
	struct event_mailbox mbox;
	int ret;

222
	wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
K
Kalle Valo 已提交
223 224 225 226 227

	if (mbox_num > 1)
		return -EINVAL;

	/* first we read the mbox descriptor */
228
	wl1251_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
K
Kalle Valo 已提交
229 230 231
			    sizeof(struct event_mailbox));

	/* process the descriptor */
232
	ret = wl1251_event_process(wl, &mbox);
K
Kalle Valo 已提交
233 234 235 236
	if (ret < 0)
		return ret;

	/* then we let the firmware know it can go on...*/
237
	wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
K
Kalle Valo 已提交
238 239 240

	return 0;
}