921eca35719d2d2a6ad8d3f861971f42c05239be
[safe/jmp/linux-2.6] / drivers / net / wireless / rt2x00 / rt2x00queue.c
1 /*
2         Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
3         <http://rt2x00.serialmonkey.com>
4
5         This program is free software; you can redistribute it and/or modify
6         it under the terms of the GNU General Public License as published by
7         the Free Software Foundation; either version 2 of the License, or
8         (at your option) any later version.
9
10         This program is distributed in the hope that it will be useful,
11         but WITHOUT ANY WARRANTY; without even the implied warranty of
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13         GNU General Public License for more details.
14
15         You should have received a copy of the GNU General Public License
16         along with this program; if not, write to the
17         Free Software Foundation, Inc.,
18         59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 /*
22         Module: rt2x00lib
23         Abstract: rt2x00 queue specific routines.
24  */
25
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28
29 #include "rt2x00.h"
30 #include "rt2x00lib.h"
31
32 struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
33                                          const enum ieee80211_tx_queue queue)
34 {
35         int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
36
37         if (queue < rt2x00dev->hw->queues && rt2x00dev->tx)
38                 return &rt2x00dev->tx[queue];
39
40         if (!rt2x00dev->bcn)
41                 return NULL;
42
43         if (queue == IEEE80211_TX_QUEUE_BEACON)
44                 return &rt2x00dev->bcn[0];
45         else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON && atim)
46                 return &rt2x00dev->bcn[1];
47
48         return NULL;
49 }
50 EXPORT_SYMBOL_GPL(rt2x00queue_get_queue);
51
52 struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
53                                           enum queue_index index)
54 {
55         struct queue_entry *entry;
56
57         if (unlikely(index >= Q_INDEX_MAX)) {
58                 ERROR(queue->rt2x00dev,
59                       "Entry requested from invalid index type (%d)\n", index);
60                 return NULL;
61         }
62
63         spin_lock(&queue->lock);
64
65         entry = &queue->entries[queue->index[index]];
66
67         spin_unlock(&queue->lock);
68
69         return entry;
70 }
71 EXPORT_SYMBOL_GPL(rt2x00queue_get_entry);
72
73 void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
74 {
75         if (unlikely(index >= Q_INDEX_MAX)) {
76                 ERROR(queue->rt2x00dev,
77                       "Index change on invalid index type (%d)\n", index);
78                 return;
79         }
80
81         spin_lock(&queue->lock);
82
83         queue->index[index]++;
84         if (queue->index[index] >= queue->limit)
85                 queue->index[index] = 0;
86
87         queue->length--;
88         queue->count += (index == Q_INDEX_DONE);
89
90         spin_unlock(&queue->lock);
91 }
92 EXPORT_SYMBOL_GPL(rt2x00queue_index_inc);
93
94 static void rt2x00queue_reset(struct data_queue *queue)
95 {
96         spin_lock(&queue->lock);
97
98         queue->count = 0;
99         queue->length = 0;
100         memset(queue->index, 0, sizeof(queue->index));
101
102         spin_unlock(&queue->lock);
103 }
104
105 void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev)
106 {
107         struct data_queue *queue = rt2x00dev->rx;
108         unsigned int i;
109
110         rt2x00queue_reset(queue);
111
112         if (!rt2x00dev->ops->lib->init_rxentry)
113                 return;
114
115         for (i = 0; i < queue->limit; i++)
116                 rt2x00dev->ops->lib->init_rxentry(rt2x00dev,
117                                                   &queue->entries[i]);
118 }
119
120 void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev)
121 {
122         struct data_queue *queue;
123         unsigned int i;
124
125         txall_queue_for_each(rt2x00dev, queue) {
126                 rt2x00queue_reset(queue);
127
128                 if (!rt2x00dev->ops->lib->init_txentry)
129                         continue;
130
131                 for (i = 0; i < queue->limit; i++)
132                         rt2x00dev->ops->lib->init_txentry(rt2x00dev,
133                                                           &queue->entries[i]);
134         }
135 }
136
137 static int rt2x00queue_alloc_entries(struct data_queue *queue,
138                                      const struct data_queue_desc *qdesc)
139 {
140         struct queue_entry *entries;
141         unsigned int entry_size;
142         unsigned int i;
143
144         rt2x00queue_reset(queue);
145
146         queue->limit = qdesc->entry_num;
147         queue->data_size = qdesc->data_size;
148         queue->desc_size = qdesc->desc_size;
149
150         /*
151          * Allocate all queue entries.
152          */
153         entry_size = sizeof(*entries) + qdesc->priv_size;
154         entries = kzalloc(queue->limit * entry_size, GFP_KERNEL);
155         if (!entries)
156                 return -ENOMEM;
157
158 #define QUEUE_ENTRY_PRIV_OFFSET(__base, __index, __limit, __esize, __psize) \
159         ( (__base) + ((__limit) * (__esize)) + ((__index) * (__psize)) )
160
161         for (i = 0; i < queue->limit; i++) {
162                 entries[i].flags = 0;
163                 entries[i].queue = queue;
164                 entries[i].skb = NULL;
165                 entries[i].entry_idx = i;
166                 entries[i].priv_data =
167                     QUEUE_ENTRY_PRIV_OFFSET(entries, i, queue->limit,
168                                             sizeof(*entries), qdesc->priv_size);
169         }
170
171 #undef QUEUE_ENTRY_PRIV_OFFSET
172
173         queue->entries = entries;
174
175         return 0;
176 }
177
178 int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
179 {
180         struct data_queue *queue;
181         int status;
182
183
184         status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx);
185         if (status)
186                 goto exit;
187
188         tx_queue_for_each(rt2x00dev, queue) {
189                 status = rt2x00queue_alloc_entries(queue, rt2x00dev->ops->tx);
190                 if (status)
191                         goto exit;
192         }
193
194         status = rt2x00queue_alloc_entries(rt2x00dev->bcn, rt2x00dev->ops->bcn);
195         if (status)
196                 goto exit;
197
198         if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
199                 return 0;
200
201         status = rt2x00queue_alloc_entries(&rt2x00dev->bcn[1],
202                                            rt2x00dev->ops->atim);
203         if (status)
204                 goto exit;
205
206         return 0;
207
208 exit:
209         ERROR(rt2x00dev, "Queue entries allocation failed.\n");
210
211         rt2x00queue_uninitialize(rt2x00dev);
212
213         return status;
214 }
215
216 void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
217 {
218         struct data_queue *queue;
219
220         queue_for_each(rt2x00dev, queue) {
221                 kfree(queue->entries);
222                 queue->entries = NULL;
223         }
224 }
225
226 int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
227 {
228         struct data_queue *queue;
229         enum data_queue_qid qid;
230         unsigned int req_atim =
231             !!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
232
233         /*
234          * We need the following queues:
235          * RX: 1
236          * TX: hw->queues
237          * Beacon: 1
238          * Atim: 1 (if required)
239          */
240         rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim;
241
242         queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
243         if (!queue) {
244                 ERROR(rt2x00dev, "Queue allocation failed.\n");
245                 return -ENOMEM;
246         }
247
248         /*
249          * Initialize pointers
250          */
251         rt2x00dev->rx = queue;
252         rt2x00dev->tx = &queue[1];
253         rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues];
254
255         /*
256          * Initialize queue parameters.
257          * RX: qid = QID_RX
258          * TX: qid = QID_AC_BE + index
259          * TX: cw_min: 2^5 = 32.
260          * TX: cw_max: 2^10 = 1024.
261          * BCN & Atim: qid = QID_MGMT
262          */
263         qid = QID_AC_BE;
264         queue_for_each(rt2x00dev, queue) {
265                 spin_lock_init(&queue->lock);
266
267                 queue->rt2x00dev = rt2x00dev;
268                 queue->qid = qid++;
269                 queue->aifs = 2;
270                 queue->cw_min = 5;
271                 queue->cw_max = 10;
272         }
273
274         /*
275          * Fix non-TX data qid's
276          */
277         rt2x00dev->rx->qid = QID_RX;
278         rt2x00dev->bcn[0].qid = QID_MGMT;
279         if (req_atim)
280                 rt2x00dev->bcn[1].qid = QID_MGMT;
281
282         return 0;
283 }
284
285 void rt2x00queue_free(struct rt2x00_dev *rt2x00dev)
286 {
287         kfree(rt2x00dev->rx);
288         rt2x00dev->rx = NULL;
289         rt2x00dev->tx = NULL;
290         rt2x00dev->bcn = NULL;
291 }