summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/eswin/fullmac/ecrnx_tx.h
blob: 03d1177114bb427656f8e9ad733103252a22047e (plain)
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/**
 ******************************************************************************
 *
 * @file ecrnx_tx.h
 *
 * Copyright (C) ESWIN 2015-2020
 *
 ******************************************************************************
 */
#ifndef _ECRNX_TX_H_
#define _ECRNX_TX_H_

#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <linux/netdevice.h>
#include "lmac_types.h"
#include "ipc_shared.h"
#include "ecrnx_txq.h"
#include "hal_desc.h"

#define ECRNX_HWQ_BK                     0
#define ECRNX_HWQ_BE                     1
#define ECRNX_HWQ_VI                     2
#define ECRNX_HWQ_VO                     3
#define ECRNX_HWQ_BCMC                   4
#define ECRNX_HWQ_NB                     NX_TXQ_CNT
#define ECRNX_HWQ_ALL_ACS (ECRNX_HWQ_BK | ECRNX_HWQ_BE | ECRNX_HWQ_VI | ECRNX_HWQ_VO)
#define ECRNX_HWQ_ALL_ACS_BIT ( BIT(ECRNX_HWQ_BK) | BIT(ECRNX_HWQ_BE) |    \
                               BIT(ECRNX_HWQ_VI) | BIT(ECRNX_HWQ_VO) )

#define ECRNX_TX_LIFETIME_MS             100
#define ECRNX_TX_MAX_RATES               NX_TX_MAX_RATES


#define AMSDU_PADDING(x) ((4 - ((x) & 0x3)) & 0x3)

#define TXU_CNTRL_RETRY        BIT(0)
#define TXU_CNTRL_MORE_DATA    BIT(2)
#define TXU_CNTRL_MGMT         BIT(3)
#define TXU_CNTRL_MGMT_NO_CCK  BIT(4)
#define TXU_CNTRL_AMSDU        BIT(6)
#define TXU_CNTRL_MGMT_ROBUST  BIT(7)
#define TXU_CNTRL_USE_4ADDR    BIT(8)
#define TXU_CNTRL_EOSP         BIT(9)
#define TXU_CNTRL_MESH_FWD     BIT(10)
#define TXU_CNTRL_TDLS         BIT(11)
#define TXU_CNTRL_NO_ENCRYPT   BIT(15)

extern const int ecrnx_tid2hwq[IEEE80211_NUM_TIDS];

/**
 * struct ecrnx_amsdu_txhdr - Structure added in skb headroom (instead of
 * ecrnx_txhdr) for amsdu subframe buffer (except for the first subframe
 * that has a normal ecrnx_txhdr)
 *
 * @list     List of other amsdu subframe (ecrnx_sw_txhdr.amsdu.hdrs)
 * @map_len  Length to be downloaded for this subframe
 * @dma_addr Buffer address form embedded point of view
 * @skb      skb
 * @pad      padding added before this subframe
 *           (only use when amsdu must be dismantled)
 * @msdu_len Size, in bytes, of the MSDU (without padding nor amsdu header)
 */
struct ecrnx_amsdu_txhdr {
    struct list_head list;
    size_t map_len;
#ifdef CONFIG_ECRNX_ESWIN
    u8 *send_pos; // offset from skb->data for send to slave.
#else    
    dma_addr_t dma_addr;
#endif
    struct sk_buff *skb;
    u16 pad;
    u16 msdu_len;
};

/**
 * struct ecrnx_amsdu - Structure to manage creation of an A-MSDU, updated
 * only In the first subframe of an A-MSDU
 *
 * @hdrs List of subframe of ecrnx_amsdu_txhdr
 * @len  Current size for this A-MDSU (doesn't take padding into account)
 *       0 means that no amsdu is in progress
 * @nb   Number of subframe in the amsdu
 * @pad  Padding to add before adding a new subframe
 */
struct ecrnx_amsdu {
    struct list_head hdrs;
    u16 len;
    u8 nb;
    u8 pad;
};

/**
 * struct ecrnx_sw_txhdr - Software part of tx header
 *
 * @ecrnx_sta sta to which this buffer is addressed
 * @ecrnx_vif vif that send the buffer
 * @txq pointer to TXQ used to send the buffer
 * @hw_queue Index of the HWQ used to push the buffer.
 *           May be different than txq->hwq->id on confirmation.
 * @frame_len Size of the frame (doesn't not include mac header)
 *            (Only used to update stat, can't we use skb->len instead ?)
 * @headroom Headroom added in skb to add ecrnx_txhdr
 *           (Only used to remove it before freeing skb, is it needed ?)
 * @amsdu Description of amsdu whose first subframe is this buffer
 *        (amsdu.nb = 0 means this buffer is not part of amsdu)
 * @skb skb received from transmission
 * @map_len  Length mapped for DMA (only ecrnx_hw_txhdr and data are mapped)
 * @dma_addr DMA address after mapping
 * @desc Buffer description that will be copied in shared mem for FW
 */
struct ecrnx_sw_txhdr {
    struct ecrnx_sta *ecrnx_sta;
    struct ecrnx_vif *ecrnx_vif;
    struct ecrnx_txq *txq;
    u8 hw_queue;
    u16 frame_len;
    u16 headroom;
#ifdef CONFIG_ECRNX_AMSDUS_TX
    struct ecrnx_amsdu amsdu;
#endif
    struct sk_buff *skb;

#ifdef CONFIG_ECRNX_ESWIN
    u32 offset; // offset from skb->data for send to slave.
#else
    size_t map_len;
    dma_addr_t dma_addr;
#endif
    struct txdesc_api desc;
    unsigned long jiffies;
};

/**
 * struct ecrnx_txhdr - Stucture to control transimission of packet
 * (Added in skb headroom)
 *
 * @sw_hdr: Information from driver
 * @cache_guard:
 * @hw_hdr: Information for/from hardware
 */
struct ecrnx_txhdr {
    struct ecrnx_sw_txhdr *sw_hdr;
    char cache_guard[L1_CACHE_BYTES];
    struct ecrnx_hw_txhdr hw_hdr;
};
#define ECRNX_TX_ALIGN_SIZE 4
#define ECRNX_TX_ALIGN_MASK (ECRNX_TX_ALIGN_SIZE - 1)
#define ECRNX_SWTXHDR_ALIGN_PADS(x) \
                    ((ECRNX_TX_ALIGN_SIZE - ((x) & ECRNX_TX_ALIGN_MASK)) \
                     & ECRNX_TX_ALIGN_MASK)

#define ECRNX_TX_TXDESC_API_ALIGN  ((sizeof(struct txdesc_api) + 3) & (~ECRNX_TX_ALIGN_MASK))
/**
 * ECRNX_TX_MAX_HEADROOM - Maximum size needed in skb headroom to prepare a buffer
 * for transmission
 * The headroom is used to store the 'struct ecrnx_txhdr' and moreover the part that is used
 * by the firmware to provide tx status (i.e. struct ecrnx_hw_txhdr) must be aligned on
 * 32bits because firmware used DMA to update it.
 */
#ifdef CONFIG_ECRNX_ESWIN
#define ECRNX_TX_MAX_HEADROOM (ECRNX_TX_TXDESC_API_ALIGN + sizeof(struct ecrnx_txhdr) + ECRNX_TX_ALIGN_SIZE)
#else
#define ECRNX_TX_MAX_HEADROOM (sizeof(struct ecrnx_txhdr) + ECRNX_TX_ALIGN_SIZE)
#endif

/**
 * ECRNX_TX_HEADROOM - Headroom to use to store struct ecrnx_txhdr
 *
 * Takes into account current aligment of data buffer to ensure that struct ecrnx_txhdr
 * (and as a consequence its field hw_hdr) will be aligned on 32bits boundary.
 */
#ifdef CONFIG_ECRNX_ESWIN
#define ECRNX_TX_HEADROOM(skb) (ECRNX_TX_TXDESC_API_ALIGN + sizeof(struct ecrnx_txhdr) + ((long)skb->data & ECRNX_TX_ALIGN_MASK))
#else
#define ECRNX_TX_HEADROOM(skb) (sizeof(struct ecrnx_txhdr) + ((long)skb->data & ECRNX_TX_ALIGN_MASK))
#endif

/**
 * ECRNX_TX_DMA_MAP_LEN - Length, in bytes, to map for DMA transfer
 * To be called with skb BEFORE reserving headroom to store struct ecrnx_txhdr.
 */
#define ECRNX_TX_DMA_MAP_LEN(skb) (                                      \
        (sizeof(struct ecrnx_txhdr) - offsetof(struct ecrnx_txhdr, hw_hdr)) + \
        ((long)skb->data & ECRNX_TX_ALIGN_MASK) + skb->len)

/**
 * ECRNX_TX_DATA_OFT - Offset, in bytes, between the location of the 'struct ecrnx_hw_txhdr'
 * and the beginning of frame (i.e. ethernet of 802.11 header). Cannot simply use
 * sizeof(struct ecrnx_hw_txhdr) because of padding added by compiler to align fields
 * in structure.
 */
#define ECRNX_TX_DATA_OFT(sw_txhdr) (                                    \
        (sizeof(struct ecrnx_txhdr) - offsetof(struct ecrnx_txhdr, hw_hdr)) \
        + (sw_txhdr->headroom & ECRNX_TX_ALIGN_MASK))

/**
 * SKB buffer format before it is pushed to MACSW
 *
 * For DATA frame
 *                    |--------------------|
 *                    | headroom           |
 *    skb->data ----> |--------------------| <------ skb->data
 *                    | struct ecrnx_txhdr  |
 *                    | * ecrnx_sw_txhdr *  |
 *                    | * [L1 guard]       |
 *               +--> | * ecrnx_hw_txhdr    | <---- desc.host.status_desc_addr
 *               :    |                    |
 *     memory    :    |--------------------|
 *     mapped    :    | padding (optional) |
 *     for DMA   :    |--------------------|
 *               :    | Ethernet Header    |
 *               :    |--------------------| <---- desc.host.packet_addr[0]
 *               :    | Data               |
 *               :    |                    |
 *               :    |                    |
 *               :    |                    |
 *               +--> |--------------------|
 *                    | tailroom           |
 *                    |--------------------|
 *
 *
 * For MGMT frame (skb is created by the driver so buffer is always aligned
 *                 with no headroom/tailroom)
 *
 *    skb->data ----> |--------------------| <------ skb->data
 *                    | struct ecrnx_txhdr  |
 *                    | * ecrnx_sw_txhdr *  |
 *                    | * [L1 guard]       |
 *               +--> | * ecrnx_hw_txhdr    | <---- desc.host.status_desc_addr
 *     memory    :    |                    |
 *     mapped    :    |--------------------| <---- desc.host.packet_addr[0]
 *     for DMA   :    | 802.11 HDR         |
 *               :    |--------------------|
 *               :    | Data               |
 *               :    |                    |
 *               +--> |--------------------|
 *
 */

u16 ecrnx_select_txq(struct ecrnx_vif *ecrnx_vif, struct sk_buff *skb);
int ecrnx_start_xmit(struct sk_buff *skb, struct net_device *dev);

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
int ecrnx_start_mgmt_xmit(struct ecrnx_vif *vif, struct ecrnx_sta *sta,
                         struct cfg80211_mgmt_tx_params *params, bool offchan,
                         u64 *cookie);
#else
int ecrnx_start_mgmt_xmit(struct ecrnx_vif *vif, struct ecrnx_sta *sta,
                         struct ieee80211_channel *channel, bool offchan,
                         unsigned int wait, const u8* buf, size_t len,
                    #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
                         bool no_cck,
                    #endif
                    #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
                         bool dont_wait_for_ack,
                    #endif
                         u64 *cookie);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */

int ecrnx_txdatacfm(void *pthis, void *host_id);
int ecrnx_handle_tx_datacfm(void *priv, void *host_id);

struct ecrnx_hw;
struct ecrnx_sta;
void ecrnx_set_traffic_status(struct ecrnx_hw *ecrnx_hw,
                             struct ecrnx_sta *sta,
                             bool available,
                             u8 ps_id);
void ecrnx_ps_bh_enable(struct ecrnx_hw *ecrnx_hw, struct ecrnx_sta *sta,
                       bool enable);
void ecrnx_ps_bh_traffic_req(struct ecrnx_hw *ecrnx_hw, struct ecrnx_sta *sta,
                            u16 pkt_req, u8 ps_id);

void ecrnx_switch_vif_sta_txq(struct ecrnx_sta *sta, struct ecrnx_vif *old_vif,
                             struct ecrnx_vif *new_vif);

int ecrnx_dbgfs_print_sta(char *buf, size_t size, struct ecrnx_sta *sta,
                         struct ecrnx_hw *ecrnx_hw);
void ecrnx_txq_credit_update(struct ecrnx_hw *ecrnx_hw, int sta_idx, u8 tid,
                            s8 update);
void ecrnx_tx_push(struct ecrnx_hw *ecrnx_hw, struct ecrnx_txhdr *txhdr, int flags);

#endif /* _ECRNX_TX_H_ */