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

#include "wl1271.h"
#include "wl1271_acx.h"
#include "wl1271_reg.h"
#include "wl1271_rx.h"
T
Teemu Paasikivi 已提交
28
#include "wl1271_io.h"
L
Luciano Coelho 已提交
29 30 31 32

static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
				  u32 drv_rx_counter)
{
L
Luciano Coelho 已提交
33 34
	return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
		RX_MEM_BLOCK_MASK;
L
Luciano Coelho 已提交
35 36 37 38 39
}

static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status,
				 u32 drv_rx_counter)
{
L
Luciano Coelho 已提交
40 41
	return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
		RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
L
Luciano Coelho 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
}

/* The values of this table must match the wl1271_rates[] array */
static u8 wl1271_rx_rate_to_idx[] = {
	/* MCS rates are used only with 11n */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */

	11,                         /* WL1271_RATE_54   */
	10,                         /* WL1271_RATE_48   */
	9,                          /* WL1271_RATE_36   */
	8,                          /* WL1271_RATE_24   */

	/* TI-specific rate */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22   */

	7,                          /* WL1271_RATE_18   */
	6,                          /* WL1271_RATE_12   */
	3,                          /* WL1271_RATE_11   */
	5,                          /* WL1271_RATE_9    */
	4,                          /* WL1271_RATE_6    */
	2,                          /* WL1271_RATE_5_5  */
	1,                          /* WL1271_RATE_2    */
	0                           /* WL1271_RATE_1    */
};

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
/* The values of this table must match the wl1271_rates[] array */
static u8 wl1271_5_ghz_rx_rate_to_idx[] = {
	/* MCS rates are used only with 11n */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */

	7,                          /* WL1271_RATE_54   */
	6,                          /* WL1271_RATE_48   */
	5,                          /* WL1271_RATE_36   */
	4,                          /* WL1271_RATE_24   */

	/* TI-specific rate */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22   */

	3,                          /* WL1271_RATE_18   */
	2,                          /* WL1271_RATE_12   */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_11   */
	1,                          /* WL1271_RATE_9    */
	0,                          /* WL1271_RATE_6    */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_5_5  */
	WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_2    */
	WL1271_RX_RATE_UNSUPPORTED  /* WL1271_RATE_1    */
};

L
Luciano Coelho 已提交
104 105 106 107 108 109 110
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));

111 112
	if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
	    WL1271_RX_DESC_BAND_BG) {
L
Luciano Coelho 已提交
113
		status->band = IEEE80211_BAND_2GHZ;
114 115 116
		status->rate_idx = wl1271_rx_rate_to_idx[desc->rate];
	} else if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
		 WL1271_RX_DESC_BAND_A) {
117
		status->band = IEEE80211_BAND_5GHZ;
118 119
		status->rate_idx = wl1271_5_ghz_rx_rate_to_idx[desc->rate];
	} else
L
Luciano Coelho 已提交
120 121 122
		wl1271_warning("unsupported band 0x%x",
			       desc->flags & WL1271_RX_DESC_BAND_MASK);

123 124 125
	if (unlikely(status->rate_idx == WL1271_RX_RATE_UNSUPPORTED))
		wl1271_warning("unsupported rate");

L
Luciano Coelho 已提交
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	/*
	 * FIXME: Add mactime handling.  For IBSS (ad-hoc) we need to get the
	 * timestamp from the beacon (acx_tsf_info).  In BSS mode (infra) we
	 * only need the mactime for monitor mode.  For now the mactime is
	 * not valid, so RX_FLAG_TSFT should not be set
	 */
	status->signal = desc->rssi;

	/*
	 * 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.
	 */
	status->noise = desc->rssi - (desc->snr >> 1);

	status->freq = ieee80211_channel_to_frequency(desc->channel);

	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;

146
		if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL)))
L
Luciano Coelho 已提交
147
			status->flag |= RX_FLAG_DECRYPTED;
148 149
		if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL))
			status->flag |= RX_FLAG_MMIC_ERROR;
L
Luciano Coelho 已提交
150 151 152 153 154 155 156 157 158 159 160 161
	}
}

static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
{
	struct ieee80211_rx_status rx_status;
	struct wl1271_rx_descriptor *desc;
	struct sk_buff *skb;
	u16 *fc;
	u8 *buf;
	u8 beacon = 0;

162 163 164 165 166 167 168
	/*
	 * In PLT mode we seem to get frames and mac80211 warns about them,
	 * workaround this by not retrieving them at all.
	 */
	if (unlikely(wl->state == WL1271_STATE_PLT))
		return;

169
	skb = __dev_alloc_skb(length, GFP_KERNEL);
L
Luciano Coelho 已提交
170 171 172 173 174 175
	if (!skb) {
		wl1271_error("Couldn't allocate RX frame");
		return;
	}

	buf = skb_put(skb, length);
T
Teemu Paasikivi 已提交
176
	wl1271_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
L
Luciano Coelho 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

	/* the data read starts with the descriptor */
	desc = (struct wl1271_rx_descriptor *) buf;

	/* now we pull the descriptor out of the buffer */
	skb_pull(skb, sizeof(*desc));

	fc = (u16 *)skb->data;
	if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
		beacon = 1;

	wl1271_rx_status(wl, desc, &rx_status, beacon);

	wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
		     beacon ? "beacon" : "");

	memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
L
Luciano Coelho 已提交
194
	ieee80211_rx_ni(wl->hw, skb);
L
Luciano Coelho 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
}

void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
{
	struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
	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;
	u32 mem_block;

	while (drv_rx_counter != fw_rx_counter) {
		mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter);
		buf_size = wl1271_rx_get_buf_size(status, drv_rx_counter);

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

L
Luciano Coelho 已提交
214 215
		wl->rx_mem_pool_addr.addr = (mem_block << 8) +
			le32_to_cpu(wl_mem_map->packet_memory_pool_start);
L
Luciano Coelho 已提交
216 217 218 219
		wl->rx_mem_pool_addr.addr_extra =
			wl->rx_mem_pool_addr.addr + 4;

		/* Choose the block we want to read */
T
Teemu Paasikivi 已提交
220 221
		wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr,
			     sizeof(wl->rx_mem_pool_addr), false);
L
Luciano Coelho 已提交
222 223 224 225 226 227

		wl1271_rx_handle_data(wl, buf_size);

		wl->rx_counter++;
		drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
	}
228 229

	wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
L
Luciano Coelho 已提交
230
}