mac80211: implement Operating Mode Notification extended NSS support
[carl9170fw.git] / 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, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include "carl9170.h"
26 #include "shared/phy.h"
27 #include "hostif.h"
28 #include "timer.h"
29 #include "wl.h"
30 #include "printf.h"
31 #include "rf.h"
32 #include "linux/ieee80211.h"
33 #include "wol.h"
34
35 static struct carl9170_bar_ctx *wlan_get_bar_cache_buffer(void)
36 {
37         struct carl9170_bar_ctx *tmp;
38
39         tmp = &fw.wlan.ba_cache[fw.wlan.ba_tail_idx];
40         fw.wlan.ba_tail_idx++;
41         fw.wlan.ba_tail_idx %= CONFIG_CARL9170FW_BACK_REQS_NUM;
42         if (fw.wlan.queued_ba < CONFIG_CARL9170FW_BACK_REQS_NUM)
43                 fw.wlan.queued_ba++;
44
45         return tmp;
46 }
47
48 static void handle_bar(struct dma_desc *desc __unused, struct ieee80211_hdr *hdr,
49                        unsigned int len, unsigned int mac_err)
50 {
51         struct ieee80211_bar *bar;
52         struct carl9170_bar_ctx *ctx;
53
54         if (unlikely(mac_err)) {
55                 /*
56                  * This check does a number of things:
57                  * 1. checks if the frame is in good nick
58                  * 2. checks if the RA (MAC) matches
59                  */
60                 return ;
61         }
62
63         if (unlikely(len < (sizeof(struct ieee80211_bar) + FCS_LEN))) {
64                 /*
65                  * Sneaky, corrupted BARs... but not with us!
66                  */
67
68                 return ;
69         }
70
71         bar = (void *) hdr;
72
73         if ((bar->control & cpu_to_le16(IEEE80211_BAR_CTRL_MULTI_TID)) ||
74             !(bar->control & cpu_to_le16(IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA))) {
75                 /* not implemented yet */
76
77                 return ;
78         }
79
80         ctx = wlan_get_bar_cache_buffer();
81
82         memcpy(ctx->ra, bar->ra, 6);
83         memcpy(ctx->ta, bar->ta, 6);
84         ctx->control = bar->control;
85         ctx->start_seq_num = bar->start_seq_num;
86 }
87
88 static unsigned int wlan_rx_filter(struct dma_desc *desc)
89 {
90         struct ieee80211_hdr *hdr;
91         unsigned int data_len;
92         unsigned int rx_filter;
93         unsigned int mac_err;
94
95         data_len = ar9170_get_rx_mpdu_len(desc);
96         mac_err = ar9170_get_rx_macstatus_error(desc);
97
98 #define AR9170_RX_ERROR_BAD (AR9170_RX_ERROR_FCS | AR9170_RX_ERROR_PLCP)
99
100         if (unlikely(data_len < (4 + 6 + FCS_LEN) ||
101             desc->totalLen > CONFIG_CARL9170FW_RX_FRAME_LEN) ||
102             mac_err & AR9170_RX_ERROR_BAD) {
103                 /*
104                  * This frame is too damaged to do anything
105                  * useful with it.
106                  */
107
108                 return CARL9170_RX_FILTER_BAD;
109         }
110
111         rx_filter = 0;
112         if (mac_err & AR9170_RX_ERROR_WRONG_RA)
113                 rx_filter |= CARL9170_RX_FILTER_OTHER_RA;
114
115         if (mac_err & AR9170_RX_ERROR_DECRYPT)
116                 rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL;
117
118         hdr = ar9170_get_rx_i3e(desc);
119         if (likely(ieee80211_is_data(hdr->frame_control))) {
120                 rx_filter |= CARL9170_RX_FILTER_DATA;
121         } else if (ieee80211_is_ctl(hdr->frame_control)) {
122                 switch (le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE) {
123                 case IEEE80211_STYPE_BACK_REQ:
124                         handle_bar(desc, hdr, data_len, mac_err);
125                         rx_filter |= CARL9170_RX_FILTER_CTL_BACKR;
126                         break;
127                 case IEEE80211_STYPE_PSPOLL:
128                         rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL;
129                         break;
130                 case IEEE80211_STYPE_BACK:
131                         if (fw.wlan.queued_bar) {
132                                 /*
133                                  * Don't filter block acks when the application
134                                  * has queued BARs. This is because the firmware
135                                  * can't do the accouting and the application
136                                  * has to sort out if the BA belongs to any BARs.
137                                  */
138                                 break;
139                         }
140                         /* fall through */
141                 default:
142                         rx_filter |= CARL9170_RX_FILTER_CTL_OTHER;
143                         break;
144                 }
145         } else {
146                 /* ieee80211_is_mgmt */
147                 rx_filter |= CARL9170_RX_FILTER_MGMT;
148         }
149
150         if (unlikely(fw.suspend_mode == CARL9170_HOST_SUSPENDED)) {
151                 wol_rx(rx_filter, hdr, min(data_len,
152                         (unsigned int)AR9170_BLOCK_SIZE));
153         }
154
155 #undef AR9170_RX_ERROR_BAD
156
157         return rx_filter;
158 }
159
160 void handle_wlan_rx(void)
161 {
162         struct dma_desc *desc;
163
164         for_each_desc_not_bits(desc, &fw.wlan.rx_queue, AR9170_OWN_BITS_HW) {
165                 if (!(wlan_rx_filter(desc) & fw.wlan.rx_filter)) {
166                         dma_put(&fw.pta.up_queue, desc);
167                         up_trigger();
168                 } else {
169                         dma_reclaim(&fw.wlan.rx_queue, desc);
170                         wlan_trigger(AR9170_DMA_TRIGGER_RXQ);
171                 }
172         }
173 }