wireless: align to draft 11ax D3.0
[carl9170fw.git] / carlfw / include / wl.h
1 /*
2  * carl9170 firmware - used by the ar9170 wireless device
3  *
4  * shared WLAN functions, interfaces and definitions
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-2011  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 #ifndef __CARL9170FW_WLAN_H
26 #define __CARL9170FW_WLAN_H
27
28 #include "config.h"
29 #include "carl9170.h"
30 #include "io.h"
31
32 struct ieee80211_hdr;
33
34 static inline __inline void set_wlan_txq_dma_addr(const unsigned int q, const uint32_t v)
35 {
36         set(AR9170_MAC_REG_DMA_TXQ_ADDR + (q << 3), v);
37 }
38
39 static inline __inline void set_wlan_txq_dma_curr_addr(const unsigned int q, const uint32_t v)
40 {
41         set(AR9170_MAC_REG_DMA_TXQ_CURR_ADDR + (q << 3), v);
42 }
43
44 static inline __inline volatile struct dma_desc *get_wlan_txq_dma_addr(const unsigned int q)
45 {
46         return getp(AR9170_MAC_REG_DMA_TXQ_ADDR + (q << 3));
47 }
48
49 static inline __inline volatile struct dma_desc *get_wlan_txq_addr(const unsigned int q)
50 {
51         return getp(AR9170_MAC_REG_DMA_TXQ_CURR_ADDR + (q << 3));
52 }
53
54 static inline __inline volatile struct dma_desc *get_wlan_txq_last_addr(const unsigned int q)
55 {
56         return getp(AR9170_MAC_REG_DMA_TXQ_LAST_ADDR + (q << 2));
57 }
58
59 static inline __inline void wlan_trigger(const uint32_t queue_bit)
60 {
61         set(AR9170_MAC_REG_DMA_TRIGGER, queue_bit);
62 }
63
64 static inline __inline uint8_t ar9170_get_rx_macstatus_status(struct dma_desc *desc)
65 {
66         return *((uint8_t *) DESC_PAYLOAD_OFF(desc->lastAddr,
67                 (unsigned int) desc->lastAddr->dataSize - 1));
68 }
69
70 static inline __inline uint8_t ar9170_get_rx_macstatus_error(struct dma_desc *desc)
71 {
72         unsigned int offset;
73
74         if (desc->lastAddr->dataSize == 1) {
75                 while (desc->lastAddr != desc->nextAddr)
76                         desc = desc->nextAddr;
77
78                 offset = (unsigned int) (desc->dataSize - 1);
79         } else {
80                 desc = desc->lastAddr;
81                 offset = desc->dataSize -
82                         (sizeof(struct ar9170_rx_macstatus) -
83                          offsetof(struct ar9170_rx_macstatus, error));
84         }
85
86         return *((uint8_t *) DESC_PAYLOAD_OFF(desc, offset));
87 }
88
89 static inline __inline struct ieee80211_hdr *ar9170_get_rx_i3e(struct dma_desc *desc)
90 {
91         if (!((ar9170_get_rx_macstatus_status(desc) &
92                 AR9170_RX_STATUS_MPDU) & AR9170_RX_STATUS_MPDU_LAST)) {
93                 return (void *)(DESC_PAYLOAD_OFF(desc,
94                         offsetof(struct ar9170_rx_frame_head, i3e)));
95         } else {
96                 return (void *)(DESC_PAYLOAD_OFF(desc,
97                         offsetof(struct ar9170_rx_frame_tail, i3e)));
98         }
99 }
100
101 static inline __inline struct ar9170_rx_head *ar9170_get_rx_head(struct dma_desc *desc)
102 {
103         if (!((ar9170_get_rx_macstatus_status(desc) &
104                 AR9170_RX_STATUS_MPDU) & AR9170_RX_STATUS_MPDU_LAST)) {
105                 return (void *)((uint8_t *)DESC_PAYLOAD(desc) +
106                         offsetof(struct ar9170_rx_frame_head, phy_head));
107         } else {
108                 return (void *) NULL;
109         }
110 }
111
112 static inline __inline uint32_t ar9170_rx_to_phy(struct dma_desc *rx)
113 {
114         struct ar9170_tx_hw_phy_control phy;
115         struct ar9170_rx_head *head;
116         uint8_t mac_status;
117
118         phy.set = 0;
119
120         head = ar9170_get_rx_head(rx);
121         if (!head)
122                 return le32_to_cpu(phy.set);
123
124         mac_status = ar9170_get_rx_macstatus_status(rx);
125
126         phy.modulation = mac_status & AR9170_RX_STATUS_MODULATION;
127         phy.chains = AR9170_TX_PHY_TXCHAIN_1;
128
129         switch (phy.modulation) {
130         case AR9170_RX_STATUS_MODULATION_CCK:
131                 if (mac_status & AR9170_RX_STATUS_SHORT_PREAMBLE)
132                         phy.preamble = 1;
133
134                 switch (head->plcp[0]) {
135                 case AR9170_RX_PHY_RATE_CCK_2M:
136                         phy.mcs = AR9170_TX_PHY_RATE_CCK_2M;
137                         break;
138
139                 case AR9170_RX_PHY_RATE_CCK_5M:
140                         phy.mcs = AR9170_TX_PHY_RATE_CCK_5M;
141                         break;
142
143                 case AR9170_RX_PHY_RATE_CCK_11M:
144                         phy.mcs = AR9170_TX_PHY_RATE_CCK_11M;
145                         break;
146
147                 case AR9170_RX_PHY_RATE_CCK_1M:
148                 default:
149                         phy.mcs = AR9170_TX_PHY_RATE_CCK_1M;
150                         break;
151
152                 }
153                 break;
154
155         case AR9170_RX_STATUS_MODULATION_DUPOFDM:
156         case AR9170_RX_STATUS_MODULATION_OFDM:
157                 phy.mcs = head->plcp[0] & 0xf;
158                 break;
159
160         case AR9170_RX_STATUS_MODULATION_HT:
161                 if (head->plcp[3] & 0x80)
162                         phy.bandwidth = 2;
163
164                 if (head->plcp[6] & 0x80)
165                         phy.short_gi = 1;
166
167                 /* TODO: Enable both chains for MCS > 7 */
168                 phy.mcs = head->plcp[6] & 0x7;
169                 break;
170         }
171
172         return le32_to_cpu(phy.set);
173 }
174
175 static inline __inline unsigned int ar9170_get_rx_mpdu_len(struct dma_desc *desc)
176 {
177         /*
178          * WARNING: you have to check the error bits in macstatus first!
179          */
180
181         unsigned int mpdu_len = desc->totalLen;
182
183         mpdu_len -= sizeof(struct ar9170_rx_macstatus);
184
185         switch (ar9170_get_rx_macstatus_status(desc) & AR9170_RX_STATUS_MPDU) {
186         case AR9170_RX_STATUS_MPDU_LAST:
187                 mpdu_len -= sizeof(struct ar9170_rx_phystatus);
188                 break;
189
190         case AR9170_RX_STATUS_MPDU_SINGLE:
191                 /* MPDU single has both */
192                 mpdu_len -= sizeof(struct ar9170_rx_phystatus);
193                 /* fall through */
194         case AR9170_RX_STATUS_MPDU_FIRST:
195                 mpdu_len -= sizeof(struct ar9170_rx_head);
196                 break;
197
198         case AR9170_RX_STATUS_MPDU_MIDDLE:
199         default:
200                 break;
201         }
202
203         return mpdu_len;
204 }
205
206 static inline __inline bool ar9170_tx_length_check(const uint16_t len)
207 {
208         return len > (sizeof(struct carl9170_tx_superframe) + 24 +
209                          FCS_LEN);
210 }
211
212 static inline __inline struct carl9170_tx_superframe *get_super(struct dma_desc *desc)
213 {
214         return container_of(DESC_PAYLOAD(desc), struct carl9170_tx_superframe,
215                             f);
216 }
217
218 static inline __inline struct carl9170_tx_superframe *__get_super(struct dma_desc *desc)
219 {
220         return DESC_PAYLOAD(desc);
221 }
222
223 static inline __inline void hide_super(struct dma_desc *desc)
224 {
225         desc->dataAddr = (uint8_t *)
226                 (((unsigned long)(DESC_PAYLOAD(desc)) +
227                 offsetof(struct carl9170_tx_superframe, f)));
228
229         desc->dataSize -= sizeof(struct carl9170_tx_superdesc);
230         desc->totalLen -= sizeof(struct carl9170_tx_superdesc);
231 }
232
233 static inline __inline void unhide_super(struct dma_desc *desc)
234 {
235         desc->dataAddr = (uint8_t *) get_super(desc);
236         desc->dataSize += sizeof(struct carl9170_tx_superdesc);
237         desc->totalLen += sizeof(struct carl9170_tx_superdesc);
238 }
239
240 static inline __inline __hot void read_tsf(uint32_t tsf[static 2])
241 {
242         /*
243          * "According to the [hardware] documentation:
244          *  > when TSF_LOW is read, TSF_HI is automatically concurrently
245          *  > copied into a temporary register so that an immediate read
246          *  > of TSF_HI will get the value that was present when TSF_LOW
247          *  > was read. "
248          *
249          * (David H. Lynch Jr. - mail from 2010-05-22)
250          * http://permalink.gmane.org/gmane.linux.kernel.wireless.general/51249
251          */
252
253         tsf[0] = get(AR9170_MAC_REG_TSF_L);
254         tsf[1] = get(AR9170_MAC_REG_TSF_H);
255 }
256
257 /* This function will only work on uint32_t-aligned pointers! */
258 static inline bool compare_ether_address(const void *_d0, const void *_d1)
259 {
260         const uint32_t *d0 = _d0;
261         const uint32_t *d1 = _d1;
262
263         /* BUG_ON((unsigned long)d0 & 3 || (unsigned long)d1 & 3)) */
264         return !((d0[0] ^ d1[0]) | (unsigned short)(d0[1] ^ d1[1]));
265 }
266
267 void wlan_tx(struct dma_desc *desc);
268 void wlan_tx_fw(struct carl9170_tx_superdesc *super, fw_desc_callback_t cb);
269 void wlan_timer(void);
270 void handle_wlan(void);
271
272 void handle_wlan_rx(void);
273
274 void wlan_send_buffered_tx_status(void);
275 void wlan_send_buffered_cab(void);
276 void wlan_send_buffered_ba(void);
277 void handle_wlan_tx_completion(void);
278 void wlan_dma_bump(unsigned int qidx);
279
280 void wlan_cab_flush_queue(const unsigned int vif);
281 void wlan_modify_beacon(const unsigned int vif,
282                         const unsigned int bcn_addr,
283                         const unsigned int bcn_len);
284
285 void wlan_tx_complete(struct carl9170_tx_superframe *super, bool txs);
286 void wlan_prepare_wol(void);
287
288 static inline void __check_wlantx(void)
289 {
290         BUILD_BUG_ON(CARL9170_TX_SUPERDESC_LEN & 3);
291         BUILD_BUG_ON(sizeof(struct carl9170_tx_superdesc) != CARL9170_TX_SUPERDESC_LEN);
292         BUILD_BUG_ON(sizeof(struct _carl9170_tx_superdesc) != CARL9170_TX_SUPERDESC_LEN);
293         BUILD_BUG_ON(sizeof(struct _carl9170_tx_superframe) != CARL9170_TX_SUPERFRAME_LEN);
294         BUILD_BUG_ON((offsetof(struct carl9170_tx_superframe, f) & 3) != 0);
295         BUILD_BUG_ON(offsetof(struct _carl9170_tx_superframe, f) !=
296                      (offsetof(struct _carl9170_tx_superframe, f)));
297         BUILD_BUG_ON(sizeof(struct ar9170_tx_hwdesc) != AR9170_TX_HWDESC_LEN);
298         BUILD_BUG_ON(sizeof(struct _ar9170_tx_hwdesc) != AR9170_TX_HWDESC_LEN);
299         BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != AR9170_RX_HEAD_LEN);
300         BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != AR9170_RX_PHYSTATUS_LEN);
301         BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != AR9170_RX_MACSTATUS_LEN);
302 }
303
304 #endif /* __CARL9170FW_WLAN_H */