wl1271_event.c 5.5 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 24 25 26 27 28
/*
 * 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
 *
 */

#include "wl1271.h"
#include "wl1271_reg.h"
#include "wl1271_spi.h"
#include "wl1271_event.h"
#include "wl1271_ps.h"
29
#include "wl12xx_80211.h"
L
Luciano Coelho 已提交
30 31 32 33

static int wl1271_event_scan_complete(struct wl1271 *wl,
				      struct event_mailbox *mbox)
{
34
	int size = sizeof(struct wl12xx_probe_req_template);
L
Luciano Coelho 已提交
35 36 37
	wl1271_debug(DEBUG_EVENT, "status: 0x%x",
		     mbox->scheduled_scan_status);

38
	if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
39 40 41 42 43 44 45
		if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
			wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
						NULL, size);
			/* 2.4 GHz band scanned, scan 5 GHz band, pretend
			 * to the wl1271_cmd_scan function that we are not
			 * scanning as it checks that.
			 */
46
			clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
47 48 49 50 51 52 53 54 55 56 57 58 59 60
			wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
						wl->scan.active,
						wl->scan.high_prio,
						WL1271_SCAN_BAND_5_GHZ,
						wl->scan.probe_requests);
		} else {
			if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
				wl1271_cmd_template_set(wl,
						CMD_TEMPL_CFG_PROBE_REQ_2_4,
						NULL, size);
			else
				wl1271_cmd_template_set(wl,
						CMD_TEMPL_CFG_PROBE_REQ_5,
						NULL, size);
L
Luciano Coelho 已提交
61

62 63 64
			mutex_unlock(&wl->mutex);
			ieee80211_scan_completed(wl->hw, false);
			mutex_lock(&wl->mutex);
65
			clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
66 67
		}
	}
L
Luciano Coelho 已提交
68 69 70
	return 0;
}

71 72 73 74 75 76 77 78 79 80
static int wl1271_event_ps_report(struct wl1271 *wl,
				  struct event_mailbox *mbox,
				  bool *beacon_loss)
{
	int ret = 0;

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

	switch (mbox->ps_status) {
	case EVENT_ENTER_POWER_SAVE_FAIL:
81
		if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
82 83 84 85
			wl->psm_entry_retry = 0;
			break;
		}

86 87 88 89
		if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) {
			wl->psm_entry_retry++;
			ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
		} else {
90
			wl1271_error("PSM entry failed, giving up.\n");
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
			wl->psm_entry_retry = 0;
		}
		break;
	case EVENT_ENTER_POWER_SAVE_SUCCESS:
		wl->psm_entry_retry = 0;
		break;
	case EVENT_EXIT_POWER_SAVE_FAIL:
		wl1271_info("PSM exit failed");
		break;
	case EVENT_EXIT_POWER_SAVE_SUCCESS:
	default:
		break;
	}

	return ret;
}

L
Luciano Coelho 已提交
108 109 110 111 112 113 114 115 116 117 118
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;
119
	bool beacon_loss = false;
L
Luciano Coelho 已提交
120 121 122

	wl1271_event_mbox_dump(mbox);

L
Luciano Coelho 已提交
123 124
	vector = le32_to_cpu(mbox->events_vector);
	vector &= ~(le32_to_cpu(mbox->events_mask));
L
Luciano Coelho 已提交
125 126 127 128 129 130 131 132
	wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);

	if (vector & SCAN_COMPLETE_EVENT_ID) {
		ret = wl1271_event_scan_complete(wl, mbox);
		if (ret < 0)
			return ret;
	}

133 134 135 136 137
	/*
	 * 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.
	 */
138 139
	if (vector & BSS_LOSE_EVENT_ID &&
	    test_bit(WL1271_FLAG_PSM, &wl->flags)) {
L
Luciano Coelho 已提交
140 141
		wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");

142
		/* indicate to the stack, that beacons have been lost */
143 144 145 146 147 148 149 150 151 152
		beacon_loss = true;
	}

	if (vector & PS_REPORT_EVENT_ID) {
		wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
		ret = wl1271_event_ps_report(wl, mbox, &beacon_loss);
		if (ret < 0)
			return ret;
	}

153
	if (wl->vif && beacon_loss) {
154 155 156 157 158 159
		/* Obviously, it's dangerous to release the mutex while
		   we are holding many of the variables in the wl struct.
		   That's why it's done last in the function, and care must
		   be taken that nothing more is done after this function
		   returns. */
		mutex_unlock(&wl->mutex);
160
		ieee80211_beacon_loss(wl->vif);
161
		mutex_lock(&wl->mutex);
L
Luciano Coelho 已提交
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	}

	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)
{
180
	wl->mbox_ptr[0] = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
L
Luciano Coelho 已提交
181 182 183 184 185 186
	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]);
}

187
int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
L
Luciano Coelho 已提交
188 189 190 191 192 193 194 195 196 197
{
	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 */
198 199
	wl1271_spi_read(wl, wl->mbox_ptr[mbox_num], &mbox,
			sizeof(struct event_mailbox), false);
L
Luciano Coelho 已提交
200 201 202 203 204 205 206

	/* process the descriptor */
	ret = wl1271_event_process(wl, &mbox);
	if (ret < 0)
		return ret;

	/* then we let the firmware know it can go on...*/
207
	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
L
Luciano Coelho 已提交
208 209 210

	return 0;
}