summaryrefslogtreecommitdiffstats
path: root/carl9170fw/carlfw/include/dma.h
blob: 8f3a9df63e0dd65baac0496f72e3f8755a17b5ac (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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/*
 * carl9170 firmware - used by the ar9170 wireless device
 *
 * This module contains DMA descriptor related definitions.
 *
 * Copyright (c) 2000-2005 ZyDAS Technology Corporation
 * Copyright (c) 2007-2009 Atheros Communications, Inc.
 * Copyright	2009	Johannes Berg <johannes@sipsolutions.net>
 * Copyright 2009-2011  Christian Lamparter <chunkeey@googlemail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef __CARL9170FW_DMA_H
#define __CARL9170FW_DMA_H

#include "config.h"
#include "types.h"
#include "compiler.h"
#include "hw.h"
#include "ieee80211.h"
#include "wlan.h"

struct dma_desc {
	volatile uint16_t status;	/* Descriptor status */
	volatile uint16_t ctrl;		/* Descriptor control */
	volatile uint16_t dataSize;	/* Data size */
	volatile uint16_t totalLen;	/* Total length */
	struct dma_desc *lastAddr;	/* Last address of this chain */
	union {
		uint8_t *_dataAddr;	/* Data buffer address */
		void *dataAddr;
	} __packed;
	struct dma_desc *nextAddr;	/* Next TD address */
} __packed __aligned(4);

/* Up, Dn, 5x Tx, retry, Rx, [USB Int], (CAB), FW */
#define AR9170_TERMINATOR_NUMBER_B	10

#define AR9170_TERMINATOR_NUMBER_INT	1

#ifdef CONFIG_CARL9170FW_CAB_QUEUE
#define AR9170_TERMINATOR_NUMBER_CAB	CARL9170_INTF_NUM
#else
#define AR9170_TERMINATOR_NUMBER_CAB	0
#endif /* CONFIG_CARL9170FW_CAB_QUEUE */

#define AR9170_TERMINATOR_NUMBER (AR9170_TERMINATOR_NUMBER_B + \
				  AR9170_TERMINATOR_NUMBER_INT + \
				  AR9170_TERMINATOR_NUMBER_CAB)

#define AR9170_BLOCK_SIZE           (256 + 64)

#define AR9170_DESCRIPTOR_SIZE      (sizeof(struct dma_desc))

struct ar9170_tx_ba_frame {
	struct ar9170_tx_hwdesc hdr;
	struct ieee80211_ba ba;
} __packed;

struct carl9170_tx_ba_superframe {
	struct carl9170_tx_superdesc s;
	struct ar9170_tx_ba_frame f;
} __packed;

struct ar9170_tx_null_frame {
	struct ar9170_tx_hwdesc hdr;
	struct ieee80211_hdr null;
} __packed;

struct carl9170_tx_null_superframe {
	struct carl9170_tx_superdesc s;
	struct ar9170_tx_null_frame f;
} __packed;

#define CARL9170_BA_BUFFER_LEN	(__roundup(sizeof(struct carl9170_tx_ba_superframe), 16))
#define CARL9170_RSP_BUFFER_LEN	AR9170_BLOCK_SIZE

struct carl9170_sram_reserved {
	union {
		uint32_t buf[CARL9170_BA_BUFFER_LEN / sizeof(uint32_t)];
		struct carl9170_tx_ba_superframe ba;
	} ba;

	union {
		uint32_t buf[CARL9170_MAX_CMD_LEN / sizeof(uint32_t)];
		struct carl9170_cmd cmd;

#ifdef CONFIG_CARL9170FW_WOL
		struct carl9170_tx_null_superframe null;
#endif /* CONFIG_CARL9170FW_WOL */
	} cmd;

	union {
		uint32_t buf[CARL9170_RSP_BUFFER_LEN / sizeof(uint32_t)];
		struct carl9170_rsp rsp;
	} rsp;

	union {
		uint32_t buf[CARL9170_INTF_NUM][AR9170_MAC_BCN_LENGTH_MAX / sizeof(uint32_t)];
	} bcn;
};

/*
 * Memory layout in RAM:
 *
 * 0x100000			+--
 *				| terminator descriptors (dma_desc)
 *				|  - Up (to USB host)
 *				|  - Down (from USB host)
 *				|  - TX (5x, to wifi)
 *				|  - AMPDU TX retry
 *				|  - RX (from wifi)
 *				|  - CAB Queue
 *				|  - FW cmd & req descriptor
 *				|  - BlockAck descriptor
 *				| total: AR9170_TERMINATOR_NUMBER
 *				+--
 *				| block descriptors (dma_desc)
 *				| (AR9170_BLOCK_NUMBER)
 * AR9170_BLOCK_BUFFER_BASE	+-- align to multiple of 64
 *				| block buffers (AR9170_BLOCK_SIZE each)
 *				| (AR9170_BLOCK_NUMBER)
 * approx. 0x117c00		+--
 *				| BA buffer (128 bytes)
 *				+--
 *				| CMD buffer (128 bytes)
 *				| - used as NULLFRAME buffer (128 bytes) for WOL
 *				+--
 *				| RSP buffer (320 bytes)
 *				+--
 *				| BEACON buffer (256 bytes)
 *				+--
 *				| unaccounted space / padding
 *				+--
 * 0x18000
 */

#define CARL9170_SRAM_RESERVED		(sizeof(struct carl9170_sram_reserved))

#define AR9170_FRAME_MEMORY_SIZE	(AR9170_SRAM_SIZE - CARL9170_SRAM_RESERVED)

#define BLOCK_ALIGNMENT		64

#define NONBLOCK_DESCRIPTORS_SIZE	\
	(AR9170_DESCRIPTOR_SIZE * (AR9170_TERMINATOR_NUMBER))

#define NONBLOCK_DESCRIPTORS_SIZE_ALIGNED	\
	(ALIGN(NONBLOCK_DESCRIPTORS_SIZE, BLOCK_ALIGNMENT))

#define AR9170_BLOCK_NUMBER	((AR9170_FRAME_MEMORY_SIZE - NONBLOCK_DESCRIPTORS_SIZE_ALIGNED) / \
				 (AR9170_BLOCK_SIZE + AR9170_DESCRIPTOR_SIZE))

struct ar9170_data_block {
	uint8_t	data[AR9170_BLOCK_SIZE];
};

struct ar9170_dma_memory {
	struct dma_desc			terminator[AR9170_TERMINATOR_NUMBER];
	struct dma_desc			block[AR9170_BLOCK_NUMBER];
	struct ar9170_data_block	data[AR9170_BLOCK_NUMBER] __aligned(BLOCK_ALIGNMENT);
	struct carl9170_sram_reserved	reserved __aligned(BLOCK_ALIGNMENT);
};

extern struct ar9170_dma_memory dma_mem;

#define AR9170_DOWN_BLOCK_RATIO	2
#define AR9170_RX_BLOCK_RATIO	1
/* Tx 16*2 = 32 packets => 32*(5*320) */
#define AR9170_TX_BLOCK_NUMBER	(AR9170_BLOCK_NUMBER * AR9170_DOWN_BLOCK_RATIO / \
				(AR9170_RX_BLOCK_RATIO + AR9170_DOWN_BLOCK_RATIO))
#define AR9170_RX_BLOCK_NUMBER	(AR9170_BLOCK_NUMBER - AR9170_TX_BLOCK_NUMBER)

/* Error code */
#define AR9170_ERR_FS_BIT	1
#define AR9170_ERR_LS_BIT	2
#define AR9170_ERR_OWN_BITS	3
#define AR9170_ERR_DATA_SIZE	4
#define AR9170_ERR_TOTAL_LEN	5
#define AR9170_ERR_DATA		6
#define AR9170_ERR_SEQ		7
#define AR9170_ERR_LEN		8

/* Status bits definitions */
/* Own bits definitions */
#define AR9170_OWN_BITS		0x3
#define AR9170_OWN_BITS_S	0
#define AR9170_OWN_BITS_SW	0x0
#define AR9170_OWN_BITS_HW	0x1
#define AR9170_OWN_BITS_SE	0x2

/* Control bits definitions */
#define AR9170_CTRL_TXFAIL	1
#define AR9170_CTRL_BAFAIL	2
#define AR9170_CTRL_FAIL	(AR9170_CTRL_TXFAIL | AR9170_CTRL_BAFAIL)

/* First segament bit */
#define AR9170_CTRL_LS_BIT	0x100
/* Last segament bit */
#define AR9170_CTRL_FS_BIT	0x200

struct dma_queue {
	struct dma_desc *head;
	struct dma_desc *terminator;
};

#define DESC_PAYLOAD(a)			((void *)a->dataAddr)
#define DESC_PAYLOAD_OFF(a, offset)	((void *)((unsigned long)(a->_dataAddr) + offset))

struct dma_desc *dma_unlink_head(struct dma_queue *queue);
void dma_init_descriptors(void);
void dma_reclaim(struct dma_queue *q, struct dma_desc *desc);
void dma_put(struct dma_queue *q, struct dma_desc *desc);

static inline __inline bool is_terminator(struct dma_queue *q, struct dma_desc *desc)
{
	return q->terminator == desc;
}

static inline __inline bool queue_empty(struct dma_queue *q)
{
	return q->head == q->terminator;
}

/*
 * Get a completed packet with # descriptors. Return the first
 * descriptor and pointer the head directly by lastAddr->nextAddr
 */
static inline __inline struct dma_desc *dma_dequeue_bits(struct dma_queue *q,
						uint16_t bits)
{
	struct dma_desc *desc = NULL;

	if ((q->head->status & AR9170_OWN_BITS) == bits)
		desc = dma_unlink_head(q);

	return desc;
}

static inline __inline struct dma_desc *dma_dequeue_not_bits(struct dma_queue *q,
						    uint16_t bits)
{
	struct dma_desc *desc = NULL;

	/* AR9170_OWN_BITS_HW will be filtered out here too. */
	if ((q->head->status & AR9170_OWN_BITS) != bits)
		desc = dma_unlink_head(q);

	return desc;
}

#define for_each_desc_bits(desc, queue, bits)				\
	while ((desc = dma_dequeue_bits(queue, bits)))

#define for_each_desc_not_bits(desc, queue, bits)			\
	while ((desc = dma_dequeue_not_bits(queue, bits)))

#define for_each_desc(desc, queue)					\
	while ((desc = dma_unlink_head(queue)))

#define __for_each_desc_bits(desc, queue, bits)				\
	for (desc = (queue)->head;					\
	     (desc != (queue)->terminator &&				\
	     (desc->status & AR9170_OWN_BITS) == bits);			\
	     desc = desc->lastAddr->nextAddr)

#define __while_desc_bits(desc, queue, bits)				\
	for (desc = (queue)->head;					\
	     (!queue_empty(queue) &&					\
	     (desc->status & AR9170_OWN_BITS) == bits);			\
	     desc = (queue)->head)

#define __for_each_desc_continue(desc, queue)				\
	for (; desc != (queue)->terminator;				\
	     desc = (desc)->lastAddr->nextAddr)

#define __for_each_desc(desc, queue)					\
	for (desc = (queue)->head;					\
	     desc != (queue)->terminator;				\
	     desc = (desc)->lastAddr->nextAddr)

#define __for_each_desc_safe(desc, tmp, queue)				\
	for (desc = (queue)->head, tmp = desc->lastAddr->nextAddr;	\
	     desc != (queue)->terminator;				\
	     desc = tmp, tmp = tmp->lastAddr->nextAddr)

#define __while_subdesc(desc, queue)					\
	for (desc = (queue)->head;					\
	     desc != (queue)->terminator;				\
	     desc = (desc)->nextAddr)

static inline __inline unsigned int queue_len(struct dma_queue *q)
{
	struct dma_desc *desc;
	unsigned int i = 0;

	__while_subdesc(desc, q)
		i++;

	return i;
}

/*
 * rearm a completed packet, so it will be processed agian.
 */
static inline __inline void dma_rearm(struct dma_desc *desc)
{
	/* Set OWN bit to HW */
	desc->status = ((desc->status & (~AR9170_OWN_BITS)) |
			AR9170_OWN_BITS_HW);
}

static inline __inline void dma_fix_downqueue(struct dma_desc *desc)
{
	desc->status = AR9170_OWN_BITS_HW;
	desc->ctrl = 0;
	desc->dataSize = 0;
	desc->totalLen = AR9170_BLOCK_SIZE;
	desc->lastAddr = desc;
}

static inline void __check_desc(void)
{
	struct ar9170_dma_memory mem;
	BUILD_BUG_ON(sizeof(struct ar9170_data_block) != AR9170_BLOCK_SIZE);
	BUILD_BUG_ON(sizeof(struct dma_desc) != 20);

	BUILD_BUG_ON(sizeof(mem) > AR9170_SRAM_SIZE);

	BUILD_BUG_ON(offsetof(struct carl9170_sram_reserved, ba.buf) & (BLOCK_ALIGNMENT - 1));
	BUILD_BUG_ON(offsetof(struct carl9170_sram_reserved, cmd.buf) & (BLOCK_ALIGNMENT - 1));
	BUILD_BUG_ON(offsetof(struct carl9170_sram_reserved, rsp.buf) & (BLOCK_ALIGNMENT - 1));
	BUILD_BUG_ON(offsetof(struct carl9170_sram_reserved, bcn.buf) & (BLOCK_ALIGNMENT - 1));
	BUILD_BUG_ON(sizeof(struct carl9170_tx_null_superframe) > CARL9170_MAX_CMD_LEN);
}

#endif /* __CARL9170FW_DMA_H */