162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is part of wl1251
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 1998-2007 Texas Instruments Incorporated
662306a36Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/skbuff.h>
1062306a36Sopenharmony_ci#include <linux/gfp.h>
1162306a36Sopenharmony_ci#include <net/mac80211.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "wl1251.h"
1462306a36Sopenharmony_ci#include "reg.h"
1562306a36Sopenharmony_ci#include "io.h"
1662306a36Sopenharmony_ci#include "rx.h"
1762306a36Sopenharmony_ci#include "cmd.h"
1862306a36Sopenharmony_ci#include "acx.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic void wl1251_rx_header(struct wl1251 *wl,
2162306a36Sopenharmony_ci			     struct wl1251_rx_descriptor *desc)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	u32 rx_packet_ring_addr;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr;
2662306a36Sopenharmony_ci	if (wl->rx_current_buffer)
2762306a36Sopenharmony_ci		rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	wl1251_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc));
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic void wl1251_rx_status(struct wl1251 *wl,
3362306a36Sopenharmony_ci			     struct wl1251_rx_descriptor *desc,
3462306a36Sopenharmony_ci			     struct ieee80211_rx_status *status,
3562306a36Sopenharmony_ci			     u8 beacon)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	u64 mactime;
3862306a36Sopenharmony_ci	int ret;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	memset(status, 0, sizeof(struct ieee80211_rx_status));
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	status->band = NL80211_BAND_2GHZ;
4362306a36Sopenharmony_ci	status->mactime = desc->timestamp;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/*
4662306a36Sopenharmony_ci	 * The rx status timestamp is a 32 bits value while the TSF is a
4762306a36Sopenharmony_ci	 * 64 bits one.
4862306a36Sopenharmony_ci	 * For IBSS merging, TSF is mandatory, so we have to get it
4962306a36Sopenharmony_ci	 * somehow, so we ask for ACX_TSF_INFO.
5062306a36Sopenharmony_ci	 * That could be moved to the get_tsf() hook, but unfortunately,
5162306a36Sopenharmony_ci	 * this one must be atomic, while our SPI routines can sleep.
5262306a36Sopenharmony_ci	 */
5362306a36Sopenharmony_ci	if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) {
5462306a36Sopenharmony_ci		ret = wl1251_acx_tsf_info(wl, &mactime);
5562306a36Sopenharmony_ci		if (ret == 0)
5662306a36Sopenharmony_ci			status->mactime = mactime;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	status->signal = desc->rssi;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/*
6262306a36Sopenharmony_ci	 * FIXME: guessing that snr needs to be divided by two, otherwise
6362306a36Sopenharmony_ci	 * the values don't make any sense
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	wl->noise = desc->rssi - desc->snr / 2;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	status->freq = ieee80211_channel_to_frequency(desc->channel,
6862306a36Sopenharmony_ci						      status->band);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	status->flag |= RX_FLAG_MACTIME_START;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (!wl->monitor_present && (desc->flags & RX_DESC_ENCRYPTION_MASK)) {
7362306a36Sopenharmony_ci		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL)))
7662306a36Sopenharmony_ci			status->flag |= RX_FLAG_DECRYPTED;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		if (unlikely(desc->flags & RX_DESC_MIC_FAIL))
7962306a36Sopenharmony_ci			status->flag |= RX_FLAG_MMIC_ERROR;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (unlikely(!(desc->flags & RX_DESC_VALID_FCS)))
8362306a36Sopenharmony_ci		status->flag |= RX_FLAG_FAILED_FCS_CRC;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	switch (desc->rate) {
8662306a36Sopenharmony_ci		/* skip 1 and 12 Mbps because they have same value 0x0a */
8762306a36Sopenharmony_ci	case RATE_2MBPS:
8862306a36Sopenharmony_ci		status->rate_idx = 1;
8962306a36Sopenharmony_ci		break;
9062306a36Sopenharmony_ci	case RATE_5_5MBPS:
9162306a36Sopenharmony_ci		status->rate_idx = 2;
9262306a36Sopenharmony_ci		break;
9362306a36Sopenharmony_ci	case RATE_11MBPS:
9462306a36Sopenharmony_ci		status->rate_idx = 3;
9562306a36Sopenharmony_ci		break;
9662306a36Sopenharmony_ci	case RATE_6MBPS:
9762306a36Sopenharmony_ci		status->rate_idx = 4;
9862306a36Sopenharmony_ci		break;
9962306a36Sopenharmony_ci	case RATE_9MBPS:
10062306a36Sopenharmony_ci		status->rate_idx = 5;
10162306a36Sopenharmony_ci		break;
10262306a36Sopenharmony_ci	case RATE_18MBPS:
10362306a36Sopenharmony_ci		status->rate_idx = 7;
10462306a36Sopenharmony_ci		break;
10562306a36Sopenharmony_ci	case RATE_24MBPS:
10662306a36Sopenharmony_ci		status->rate_idx = 8;
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	case RATE_36MBPS:
10962306a36Sopenharmony_ci		status->rate_idx = 9;
11062306a36Sopenharmony_ci		break;
11162306a36Sopenharmony_ci	case RATE_48MBPS:
11262306a36Sopenharmony_ci		status->rate_idx = 10;
11362306a36Sopenharmony_ci		break;
11462306a36Sopenharmony_ci	case RATE_54MBPS:
11562306a36Sopenharmony_ci		status->rate_idx = 11;
11662306a36Sopenharmony_ci		break;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* for 1 and 12 Mbps we have to check the modulation */
12062306a36Sopenharmony_ci	if (desc->rate == RATE_1MBPS) {
12162306a36Sopenharmony_ci		if (!(desc->mod_pre & OFDM_RATE_BIT))
12262306a36Sopenharmony_ci			/* CCK -> RATE_1MBPS */
12362306a36Sopenharmony_ci			status->rate_idx = 0;
12462306a36Sopenharmony_ci		else
12562306a36Sopenharmony_ci			/* OFDM -> RATE_12MBPS */
12662306a36Sopenharmony_ci			status->rate_idx = 6;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (desc->mod_pre & SHORT_PREAMBLE_BIT)
13062306a36Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void wl1251_rx_body(struct wl1251 *wl,
13462306a36Sopenharmony_ci			   struct wl1251_rx_descriptor *desc)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct sk_buff *skb;
13762306a36Sopenharmony_ci	struct ieee80211_rx_status status;
13862306a36Sopenharmony_ci	u8 *rx_buffer, beacon = 0;
13962306a36Sopenharmony_ci	u16 length, *fc;
14062306a36Sopenharmony_ci	u32 curr_id, last_id_inc, rx_packet_ring_addr;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	length = WL1251_RX_ALIGN(desc->length  - PLCP_HEADER_LENGTH);
14362306a36Sopenharmony_ci	curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT;
14462306a36Sopenharmony_ci	last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (last_id_inc != curr_id) {
14762306a36Sopenharmony_ci		wl1251_warning("curr ID:%d, last ID inc:%d",
14862306a36Sopenharmony_ci			       curr_id, last_id_inc);
14962306a36Sopenharmony_ci		wl->rx_last_id = curr_id;
15062306a36Sopenharmony_ci	} else {
15162306a36Sopenharmony_ci		wl->rx_last_id = last_id_inc;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr +
15562306a36Sopenharmony_ci		sizeof(struct wl1251_rx_descriptor) + 20;
15662306a36Sopenharmony_ci	if (wl->rx_current_buffer)
15762306a36Sopenharmony_ci		rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	skb = __dev_alloc_skb(length, GFP_KERNEL);
16062306a36Sopenharmony_ci	if (!skb) {
16162306a36Sopenharmony_ci		wl1251_error("Couldn't allocate RX frame");
16262306a36Sopenharmony_ci		return;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	rx_buffer = skb_put(skb, length);
16662306a36Sopenharmony_ci	wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* The actual length doesn't include the target's alignment */
16962306a36Sopenharmony_ci	skb_trim(skb, desc->length - PLCP_HEADER_LENGTH);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	fc = (u16 *)skb->data;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
17462306a36Sopenharmony_ci		beacon = 1;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	wl1251_rx_status(wl, desc, &status, beacon);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
17962306a36Sopenharmony_ci		     beacon ? "beacon" : "");
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
18262306a36Sopenharmony_ci	ieee80211_rx_ni(wl->hw, skb);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic void wl1251_rx_ack(struct wl1251 *wl)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	u32 data, addr;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (wl->rx_current_buffer) {
19062306a36Sopenharmony_ci		addr = ACX_REG_INTERRUPT_TRIG_H;
19162306a36Sopenharmony_ci		data = INTR_TRIG_RX_PROC1;
19262306a36Sopenharmony_ci	} else {
19362306a36Sopenharmony_ci		addr = ACX_REG_INTERRUPT_TRIG;
19462306a36Sopenharmony_ci		data = INTR_TRIG_RX_PROC0;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	wl1251_reg_write32(wl, addr, data);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* Toggle buffer ring */
20062306a36Sopenharmony_ci	wl->rx_current_buffer = !wl->rx_current_buffer;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_civoid wl1251_rx(struct wl1251 *wl)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct wl1251_rx_descriptor *rx_desc;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if (wl->state != WL1251_STATE_ON)
20962306a36Sopenharmony_ci		return;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	rx_desc = wl->rx_descriptor;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* We first read the frame's header */
21462306a36Sopenharmony_ci	wl1251_rx_header(wl, rx_desc);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	/* Now we can read the body */
21762306a36Sopenharmony_ci	wl1251_rx_body(wl, rx_desc);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* Finally, we need to ACK the RX */
22062306a36Sopenharmony_ci	wl1251_rx_ack(wl);
22162306a36Sopenharmony_ci}
222