cfg80211: Replace zero-length array with flexible-array
[carl9170fw.git] / carlfw / src / dma.c
1 /*
2  * carl9170 firmware - used by the ar9170 wireless device
3  *
4  * DMA descriptor handling functions
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 #include "carl9170.h"
26 #include "wl.h"
27 #include "printf.h"
28
29 struct ar9170_dma_memory dma_mem __in_section(sram);
30
31 static void copy_dma_desc(struct dma_desc *dst,
32                           struct dma_desc *src)
33 {
34         memcpy(dst, src, sizeof(struct dma_desc));
35 }
36
37 static void clear_descriptor(struct dma_desc *d)
38 {
39         d->status = AR9170_OWN_BITS_SW;
40         d->ctrl = 0;
41         d->dataSize = 0;
42         d->totalLen = 0;
43         d->lastAddr = d;
44         d->dataAddr = NULL;
45         d->nextAddr = d;
46 }
47
48 static void fill_descriptor(struct dma_desc *d, uint16_t size, uint8_t *data)
49 {
50         d->status = AR9170_OWN_BITS_SW;
51         d->ctrl = 0;
52         d->dataSize = size;
53         d->totalLen = 0;
54         d->lastAddr = d;
55         d->dataAddr = data;
56         d->nextAddr = NULL;
57 }
58
59 static void init_queue(struct dma_queue *q, struct dma_desc *d)
60 {
61         q->head = q->terminator = d;
62 }
63
64 /*
65  *  - Init up_queue, down_queue, tx_queue[5], rx_queue.
66  *  - Setup descriptors and data buffer address.
67  *  - Ring descriptors rx_queue and down_queue by dma_reclaim().
68  *
69  * NOTE: LastAddr tempary point (same) to nextAddr after initialize.
70  *       Because LastAddr is don't care in function dma_reclaim().
71  */
72 void dma_init_descriptors(void)
73 {
74         unsigned int i, j;
75
76         for (i = 0; i < ARRAY_SIZE(dma_mem.terminator); i++)
77                 clear_descriptor(&dma_mem.terminator[i]);
78
79         /* Assign terminators to DMA queues */
80         i = 0;
81         init_queue(&fw.pta.up_queue, &dma_mem.terminator[i++]);
82         init_queue(&fw.pta.down_queue, &dma_mem.terminator[i++]);
83         for (j = 0; j < __AR9170_NUM_TX_QUEUES; j++)
84                 init_queue(&fw.wlan.tx_queue[j], &dma_mem.terminator[i++]);
85         init_queue(&fw.wlan.tx_retry, &dma_mem.terminator[i++]);
86         init_queue(&fw.wlan.rx_queue, &dma_mem.terminator[i++]);
87         fw.usb.int_desc = &dma_mem.terminator[i++];
88         fw.wlan.fw_desc = &dma_mem.terminator[i++];
89
90         for (j = 0; j < CARL9170_INTF_NUM; j++)
91                 init_queue(&fw.wlan.cab_queue[j], &dma_mem.terminator[i++]);
92
93         BUG_ON(AR9170_TERMINATOR_NUMBER != i);
94
95         DBG("Blocks:%d [tx:%d, rx:%d] Terminators:%d/%d\n",
96             AR9170_BLOCK_NUMBER, AR9170_TX_BLOCK_NUMBER,
97             AR9170_RX_BLOCK_NUMBER, AR9170_TERMINATOR_NUMBER, i);
98
99         /* Init descriptors and memory blocks */
100         for (i = 0; i < AR9170_BLOCK_NUMBER; i++) {
101                 fill_descriptor(&dma_mem.block[i], AR9170_BLOCK_SIZE, dma_mem.data[i].data);
102
103                 if (i < AR9170_TX_BLOCK_NUMBER)
104                         dma_reclaim(&fw.pta.down_queue, &dma_mem.block[i]);
105                 else
106                         dma_reclaim(&fw.wlan.rx_queue, &dma_mem.block[i]);
107         }
108
109         /* Set DMA address registers */
110         set(AR9170_PTA_REG_DN_DMA_ADDRH, (uint32_t) fw.pta.down_queue.head >> 16);
111         set(AR9170_PTA_REG_DN_DMA_ADDRL, (uint32_t) fw.pta.down_queue.head & 0xffff);
112         set(AR9170_PTA_REG_UP_DMA_ADDRH, (uint32_t) fw.pta.up_queue.head >> 16);
113         set(AR9170_PTA_REG_UP_DMA_ADDRL, (uint32_t) fw.pta.up_queue.head & 0xffff);
114
115         for (i = 0; i < __AR9170_NUM_TX_QUEUES; i++)
116                 set_wlan_txq_dma_addr(i, (uint32_t) fw.wlan.tx_queue[i].head);
117
118         set(AR9170_MAC_REG_DMA_RXQ_ADDR, (uint32_t) fw.wlan.rx_queue.head);
119         fw.usb.int_desc->dataSize = AR9170_BLOCK_SIZE;
120         fw.usb.int_desc->dataAddr = (void *) &dma_mem.reserved.rsp;
121
122         memset(DESC_PAYLOAD(fw.usb.int_desc), 0xff,
123                AR9170_INT_MAGIC_HEADER_SIZE);
124         memset(DESC_PAYLOAD_OFF(fw.usb.int_desc, AR9170_INT_MAGIC_HEADER_SIZE),
125                0, AR9170_BLOCK_SIZE - AR9170_INT_MAGIC_HEADER_SIZE);
126
127         /* rsp is now available for use */
128         fw.usb.int_desc_available = 1;
129
130         memset(DESC_PAYLOAD(fw.wlan.fw_desc), 0, 128);
131         fw.wlan.fw_desc_available = 1;
132 }
133
134 /*
135  * Free descriptor.
136  *
137  * Exchange the terminator and the first descriptor of the packet
138  * for hardware ascy...
139  */
140 void dma_reclaim(struct dma_queue *q, struct dma_desc *desc)
141 {
142         struct dma_desc *tmpDesc, *last;
143         struct dma_desc tdesc;
144
145         /* 1. Set OWN bit to HW for all TDs to be added, clear ctrl and size */
146         tmpDesc = desc;
147         last = desc->lastAddr;
148
149         while (1) {
150                 tmpDesc->status = AR9170_OWN_BITS_HW;
151                 tmpDesc->ctrl = 0;
152                 tmpDesc->totalLen = 0;
153                 tmpDesc->dataSize = AR9170_BLOCK_SIZE;
154
155                 /* TODO : Exception handle */
156
157                 tmpDesc->lastAddr = tmpDesc;
158
159                 if (tmpDesc == last)
160                         break;
161
162                 tmpDesc = tmpDesc->nextAddr;
163         }
164
165         /* 2. Next address of Last TD to be added = first TD */
166         tmpDesc->nextAddr = desc;
167
168         /* Link first TD to self */
169         desc->lastAddr = q->terminator;
170
171         /* 3. Copy first TD to be added to TTD */
172         copy_dma_desc(&tdesc, desc);
173
174         /* 4. Initialize new terminator */
175         clear_descriptor(desc);
176
177         /* 5. Copy TTD to last TD */
178         tdesc.status = 0;
179         copy_dma_desc((void *)q->terminator, (void *)&tdesc);
180         q->terminator->status |= AR9170_OWN_BITS_HW;
181
182         /* Update terminator pointer */
183         q->terminator = desc;
184 }
185
186 /*
187  * Put a complete packet into the tail of the Queue q.
188  * Exchange the terminator and the first descriptor of the packet
189  * for hardware ascy...
190  */
191 void dma_put(struct dma_queue *q, struct dma_desc *desc)
192 {
193         struct dma_desc *tmpDesc;
194         struct dma_desc tdesc;
195
196         tmpDesc = desc;
197
198         while (1) {
199                 /* update totalLen */
200                 tmpDesc->totalLen = desc->totalLen;
201
202                 /* 1. Set OWN bit to HW for all TDs to be added */
203                 tmpDesc->status = AR9170_OWN_BITS_HW;
204                 /* TODO : Exception handle */
205
206                 tmpDesc->lastAddr = desc->lastAddr;
207
208                 if (desc->lastAddr == tmpDesc)
209                         break;
210
211                 tmpDesc = tmpDesc->nextAddr;
212         }
213
214         /* 2. Next address of Last TD to be added = first TD */
215         desc->lastAddr->nextAddr = desc;
216
217         /* If there is only one descriptor, update pointer of last descriptor */
218         if (desc->lastAddr == desc)
219                 desc->lastAddr = q->terminator;
220
221         /* 3. Copy first TD to be added to TTD */
222         copy_dma_desc(&tdesc, desc);
223
224         /* 4. Initialize new terminator */
225         clear_descriptor(desc);
226
227         /* 5. Copy TTD to last TD */
228         tdesc.status &= (~AR9170_OWN_BITS);
229         copy_dma_desc((void *)q->terminator, (void *)&tdesc);
230         q->terminator->status |= AR9170_OWN_BITS_HW;
231
232         /* Update terminator pointer */
233         q->terminator = desc;
234 }
235
236 struct dma_desc *dma_unlink_head(struct dma_queue *queue)
237 {
238         struct dma_desc *desc;
239
240         if (queue_empty(queue))
241                 return NULL;
242
243         desc = queue->head;
244
245         queue->head = desc->lastAddr->nextAddr;
246
247         /* poison nextAddr address */
248         desc->lastAddr->nextAddr = desc->lastAddr;
249         desc->lastAddr->lastAddr = desc->lastAddr;
250
251         return desc;
252 }