Setting up repository
[linux-libre-firmware.git] / carl9170fw / carlfw / src / wlanrx.c
1 /*
2  * carl9170 firmware - used by the ar9170 wireless device
3  *
4  * WLAN receive routines
5  *
6  * Copyright (c) 2000-2005 ZyDAS Technology Corporation
7  * Copyright (c) 2007-2009 Atheros Communications, Inc.
8  * Copyright    2009    Johannes Berg <johannes@sipsolutions.net>
9  * Copyright 2009-2012  Christian Lamparter <chunkeey@googlemail.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "carl9170.h"
27 #include "shared/phy.h"
28 #include "hostif.h"
29 #include "timer.h"
30 #include "wl.h"
31 #include "printf.h"
32 #include "rf.h"
33 #include "linux/ieee80211.h"
34 #include "wol.h"
35
36 static struct carl9170_bar_ctx *wlan_get_bar_cache_buffer(void)
37 {
38         struct carl9170_bar_ctx *tmp;
39
40         tmp = &fw.wlan.ba_cache[fw.wlan.ba_tail_idx];
41         fw.wlan.ba_tail_idx++;
42         fw.wlan.ba_tail_idx %= CONFIG_CARL9170FW_BACK_REQS_NUM;
43         if (fw.wlan.queued_ba < CONFIG_CARL9170FW_BACK_REQS_NUM)
44                 fw.wlan.queued_ba++;
45
46         return tmp;
47 }
48
49 static void handle_bar(struct dma_desc *desc __unused, struct ieee80211_hdr *hdr,
50                        unsigned int len, unsigned int mac_err)
51 {
52         struct ieee80211_bar *bar;
53         struct carl9170_bar_ctx *ctx;
54
55         if (unlikely(mac_err)) {
56                 /*
57                  * This check does a number of things:
58                  * 1. checks if the frame is in good nick
59                  * 2. checks if the RA (MAC) matches
60                  */
61                 return ;
62         }
63
64         if (unlikely(len < (sizeof(struct ieee80211_bar) + FCS_LEN))) {
65                 /*
66                  * Sneaky, corrupted BARs... but not with us!
67                  */
68
69                 return ;
70         }
71
72         bar = (void *) hdr;
73
74         if ((bar->control & cpu_to_le16(IEEE80211_BAR_CTRL_MULTI_TID)) ||
75             !(bar->control & cpu_to_le16(IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA))) {
76                 /* not implemented yet */
77
78                 return ;
79         }
80
81         ctx = wlan_get_bar_cache_buffer();
82
83         memcpy(ctx->ra, bar->ra, 6);
84         memcpy(ctx->ta, bar->ta, 6);
85         ctx->control = bar->control;
86         ctx->start_seq_num = bar->start_seq_num;
87 }
88
89 static unsigned int wlan_rx_filter(struct dma_desc *desc)
90 {
91         struct ieee80211_hdr *hdr;
92         unsigned int data_len;
93         unsigned int rx_filter;
94         unsigned int mac_err;
95
96         data_len = ar9170_get_rx_mpdu_len(desc);
97         mac_err = ar9170_get_rx_macstatus_error(desc);
98
99 #define AR9170_RX_ERROR_BAD (AR9170_RX_ERROR_FCS | AR9170_RX_ERROR_PLCP)
100
101         if (unlikely(data_len < (4 + 6 + FCS_LEN) ||
102             desc->totalLen > CONFIG_CARL9170FW_RX_FRAME_LEN) ||
103             mac_err & AR9170_RX_ERROR_BAD) {
104                 /*
105                  * This frame is too damaged to do anything
106                  * useful with it.
107                  */
108
109                 return CARL9170_RX_FILTER_BAD;
110         }
111
112         rx_filter = 0;
113         if (mac_err & AR9170_RX_ERROR_WRONG_RA)
114                 rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
115
116         if (mac_err & AR9170_RX_ERROR_DECRYPT)
117                 rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
118
119         hdr = ar9170_get_rx_i3e(desc);
120         if (likely(ieee80211_is_data(hdr->frame_control))) {
121                 rx_filter |= CARL9170_RX_FILTER_DATA;
122         } else if (ieee80211_is_ctl(hdr->frame_control)) {
123                 switch (le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE) {
124                 case IEEE80211_STYPE_BACK_REQ:
125                         handle_bar(desc, hdr, data_len, mac_err);
126                         rx_filter |= CARL9170_RX_FILTER_CTL_BACKR;
127                         break;
128                 case IEEE80211_STYPE_PSPOLL:
129                         rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
130                         break;
131                 case IEEE80211_STYPE_BACK:
132                         if (fw.wlan.queued_bar) {
133                                 /*
134                                  * Don't filter block acks when the application
135                                  * has queued BARs. This is because the firmware
136                                  * can't do the accouting and the application
137                                  * has to sort out if the BA belongs to any BARs.
138                                  */
139                                 break;
140                         }
141                         /* otherwise fall through */
142                 default:
143                         rx_filter |= CARL9170_RX_FILTER_CTL_OTHER;
144                         break;
145                 }
146         } else {
147                 /* ieee80211_is_mgmt */
148                 rx_filter |= CARL9170_RX_FILTER_MGMT;
149         }
150
151         if (unlikely(fw.suspend_mode == CARL9170_HOST_SUSPENDED)) {
152                 wol_rx(rx_filter, hdr, min(data_len,
153                         (unsigned int)AR9170_BLOCK_SIZE));
154         }
155
156 #undef AR9170_RX_ERROR_BAD
157
158         return rx_filter;
159 }
160
161 void handle_wlan_rx(void)
162 {
163         struct dma_desc *desc;
164
165         for_each_desc_not_bits(desc, &fw.wlan.rx_queue, AR9170_OWN_BITS_HW) {
166                 if (!(wlan_rx_filter(desc) & fw.wlan.rx_filter)) {
167                         dma_put(&fw.pta.up_queue, desc);
168                         up_trigger();
169                 } else {
170                         dma_reclaim(&fw.wlan.rx_queue, desc);
171                         wlan_trigger(AR9170_DMA_TRIGGER_RXQ);
172                 }
173         }
174 }