rx.c 8.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
/*
 * This file is part of wl1271
 *
 * Copyright (C) 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 <linux/gfp.h>
25
#include <linux/sched.h>
26

27
#include "wlcore.h"
28
#include "debug.h"
S
Shahar Levi 已提交
29 30
#include "acx.h"
#include "rx.h"
E
Eliad Peller 已提交
31
#include "tx.h"
S
Shahar Levi 已提交
32
#include "io.h"
33
#include "hw_ops.h"
L
Luciano Coelho 已提交
34

35 36 37 38 39 40
/*
 * TODO: this is here just for now, it must be removed when the data
 * operations are in place.
 */
#include "../wl12xx/reg.h"

41 42
static u32 wlcore_rx_get_buf_size(struct wl1271 *wl,
				  u32 rx_pkt_desc)
L
Luciano Coelho 已提交
43
{
44 45 46 47 48 49 50 51 52 53 54 55 56
	if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN)
		return (rx_pkt_desc & ALIGNED_RX_BUF_SIZE_MASK) >>
		       ALIGNED_RX_BUF_SIZE_SHIFT;

	return (rx_pkt_desc & RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
}

static u32 wlcore_rx_get_align_buf_size(struct wl1271 *wl, u32 pkt_len)
{
	if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN)
		return ALIGN(pkt_len, WL12XX_BUS_BLOCK_SIZE);

	return pkt_len;
L
Luciano Coelho 已提交
57 58 59 60 61 62 63 64 65
}

static void wl1271_rx_status(struct wl1271 *wl,
			     struct wl1271_rx_descriptor *desc,
			     struct ieee80211_rx_status *status,
			     u8 beacon)
{
	memset(status, 0, sizeof(struct ieee80211_rx_status));

66
	if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
67
		status->band = IEEE80211_BAND_2GHZ;
68
	else
69
		status->band = IEEE80211_BAND_5GHZ;
70

71
	status->rate_idx = wlcore_rate_to_idx(wl, desc->rate, status->band);
72

73
	/* 11n support */
74
	if (desc->rate <= wl->hw_min_ht_rate)
75 76
		status->flag |= RX_FLAG_HT;

L
Luciano Coelho 已提交
77 78
	status->signal = desc->rssi;

79 80 81 82 83 84 85
	/*
	 * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we
	 * need to divide by two for now, but TI has been discussing about
	 * changing it.  This needs to be rechecked.
	 */
	wl->noise = desc->rssi - (desc->snr >> 1);

86 87
	status->freq = ieee80211_channel_to_frequency(desc->channel,
						      status->band);
L
Luciano Coelho 已提交
88 89

	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
90
		u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK;
L
Luciano Coelho 已提交
91

92 93 94 95
		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
				RX_FLAG_DECRYPTED;

		if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) {
96
			status->flag |= RX_FLAG_MMIC_ERROR;
97 98
			wl1271_warning("Michael MIC error");
		}
L
Luciano Coelho 已提交
99 100 101
	}
}

102
static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
103
				 enum wl_rx_buf_align rx_align, u8 *hlid)
L
Luciano Coelho 已提交
104 105 106
{
	struct wl1271_rx_descriptor *desc;
	struct sk_buff *skb;
107
	struct ieee80211_hdr *hdr;
L
Luciano Coelho 已提交
108 109
	u8 *buf;
	u8 beacon = 0;
110
	u8 is_data = 0;
111
	u8 reserved = 0;
112
	u16 seq_num;
113
	u32 pkt_data_len;
L
Luciano Coelho 已提交
114

115 116 117 118
	/*
	 * In PLT mode we seem to get frames and mac80211 warns about them,
	 * workaround this by not retrieving them at all.
	 */
119
	if (unlikely(wl->plt))
120
		return -EINVAL;
121

122 123 124 125 126 127 128
	pkt_data_len = wlcore_hw_get_rx_packet_len(wl, data, length);
	if (!pkt_data_len) {
		wl1271_error("Invalid packet arrived from HW. length %d",
			     length);
		return -EINVAL;
	}

129 130 131
	if (rx_align == WLCORE_RX_BUF_UNALIGNED)
		reserved = NET_IP_ALIGN;

132 133 134
	/* the data read starts with the descriptor */
	desc = (struct wl1271_rx_descriptor *) data;

135 136 137 138 139 140 141
	if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) {
		size_t len = length - sizeof(*desc);
		wl12xx_copy_fwlog(wl, data + sizeof(*desc), len);
		wake_up_interruptible(&wl->fwlog_waitq);
		return 0;
	}

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
	/* discard corrupted packets */
	case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
	case WL1271_RX_DESC_DECRYPT_FAIL:
		wl1271_warning("corrupted packet in RX with status: 0x%x",
			       desc->status & WL1271_RX_DESC_STATUS_MASK);
		return -EINVAL;
	case WL1271_RX_DESC_SUCCESS:
	case WL1271_RX_DESC_MIC_FAIL:
		break;
	default:
		wl1271_error("invalid RX descriptor status: 0x%x",
			     desc->status & WL1271_RX_DESC_STATUS_MASK);
		return -EINVAL;
	}

158 159
	/* skb length not including rx descriptor */
	skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL);
L
Luciano Coelho 已提交
160 161
	if (!skb) {
		wl1271_error("Couldn't allocate RX frame");
162
		return -ENOMEM;
L
Luciano Coelho 已提交
163 164
	}

165 166 167
	/* reserve the unaligned payload(if any) */
	skb_reserve(skb, reserved);

168
	buf = skb_put(skb, pkt_data_len);
L
Luciano Coelho 已提交
169

170 171 172 173 174 175
	/*
	 * Copy packets from aggregation buffer to the skbs without rx
	 * descriptor and with packet payload aligned care. In case of unaligned
	 * packets copy the packets in offset of 2 bytes guarantee IP header
	 * payload aligned to 4 bytes.
	 */
176
	memcpy(buf, data + sizeof(*desc), pkt_data_len);
177 178 179
	if (rx_align == WLCORE_RX_BUF_PADDED)
		skb_pull(skb, NET_IP_ALIGN);

E
Eliad Peller 已提交
180
	*hlid = desc->hlid;
L
Luciano Coelho 已提交
181

182 183
	hdr = (struct ieee80211_hdr *)skb->data;
	if (ieee80211_is_beacon(hdr->frame_control))
L
Luciano Coelho 已提交
184
		beacon = 1;
185 186
	if (ieee80211_is_data_present(hdr->frame_control))
		is_data = 1;
L
Luciano Coelho 已提交
187

188
	wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
L
Luciano Coelho 已提交
189

190
	seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
E
Eliad Peller 已提交
191
	wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb,
192
		     skb->len - desc->pad_len,
193
		     beacon ? "beacon" : "",
E
Eliad Peller 已提交
194
		     seq_num, *hlid);
L
Luciano Coelho 已提交
195

196
	skb_queue_tail(&wl->deferred_rx_queue, skb);
197
	queue_work(wl->freezable_wq, &wl->netstack_work);
198

199
	return is_data;
L
Luciano Coelho 已提交
200 201
}

202
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
L
Luciano Coelho 已提交
203
{
E
Eliad Peller 已提交
204
	unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0};
L
Luciano Coelho 已提交
205 206 207
	u32 buf_size;
	u32 fw_rx_counter  = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
	u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
208
	u32 rx_counter;
209 210
	u32 pkt_len, align_pkt_len;
	u32 pkt_offset, des;
E
Eliad Peller 已提交
211
	u8 hlid;
212
	enum wl_rx_buf_align rx_align;
L
Luciano Coelho 已提交
213 214

	while (drv_rx_counter != fw_rx_counter) {
215 216 217
		buf_size = 0;
		rx_counter = drv_rx_counter;
		while (rx_counter != fw_rx_counter) {
218 219 220 221 222
			des = le32_to_cpu(status->rx_pkt_descs[rx_counter]);
			pkt_len = wlcore_rx_get_buf_size(wl, des);
			align_pkt_len = wlcore_rx_get_align_buf_size(wl,
								     pkt_len);
			if (buf_size + align_pkt_len > WL1271_AGGR_BUFFER_SIZE)
223
				break;
224
			buf_size += align_pkt_len;
225 226 227
			rx_counter++;
			rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
		}
L
Luciano Coelho 已提交
228 229 230 231 232 233

		if (buf_size == 0) {
			wl1271_warning("received empty data");
			break;
		}

234
		/* Read all available packets at once */
235 236
		des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
		wlcore_hw_prepare_read(wl, des, buf_size);
237 238
		wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
				 buf_size, true);
239 240 241 242

		/* Split data into separate packets */
		pkt_offset = 0;
		while (pkt_offset < buf_size) {
243 244
			des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]);
			pkt_len = wlcore_rx_get_buf_size(wl, des);
245
			rx_align = wlcore_hw_get_rx_buf_align(wl, des);
246

J
Juuso Oikarinen 已提交
247 248 249 250 251
			/*
			 * the handle data call can only fail in memory-outage
			 * conditions, in that case the received frame will just
			 * be dropped.
			 */
252 253
			if (wl1271_rx_handle_data(wl,
						  wl->aggr_buf + pkt_offset,
254
						  pkt_len, rx_align,
E
Eliad Peller 已提交
255
						  &hlid) == 1) {
256 257 258 259 260 261
				if (hlid < WL12XX_MAX_LINKS)
					__set_bit(hlid, active_hlids);
				else
					WARN(1,
					     "hlid exceeded WL12XX_MAX_LINKS "
					     "(%d)\n", hlid);
E
Eliad Peller 已提交
262
			}
263

264 265 266
			wl->rx_counter++;
			drv_rx_counter++;
			drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK;
267
			pkt_offset += wlcore_rx_get_align_buf_size(wl, pkt_len);
268
		}
L
Luciano Coelho 已提交
269
	}
270 271 272 273 274

	/*
	 * Write the driver's packet counter to the FW. This is only required
	 * for older hardware revisions
	 */
275
	if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION)
276 277
		wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER,
			       wl->rx_counter);
278

E
Eliad Peller 已提交
279
	wl12xx_rearm_rx_streaming(wl, active_hlids);
L
Luciano Coelho 已提交
280
}
281

282
#ifdef CONFIG_PM
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
int wl1271_rx_filter_enable(struct wl1271 *wl,
			    int index, bool enable,
			    struct wl12xx_rx_filter *filter)
{
	int ret;

	if (wl->rx_filter_enabled[index] == enable) {
		wl1271_warning("Request to enable an already "
			     "enabled rx filter %d", index);
		return 0;
	}

	ret = wl1271_acx_set_rx_filter(wl, index, enable, filter);

	if (ret) {
		wl1271_error("Failed to %s rx data filter %d (err=%d)",
			     enable ? "enable" : "disable", index, ret);
		return ret;
	}

	wl->rx_filter_enabled[index] = enable;

	return 0;
}

void wl1271_rx_filter_clear_all(struct wl1271 *wl)
{
	int i;

	for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) {
		if (!wl->rx_filter_enabled[i])
			continue;
		wl1271_rx_filter_enable(wl, i, 0, NULL);
	}
}
318
#endif /* CONFIG_PM */