diff options
author | David S. Miller <davem@davemloft.net> | 2008-06-14 20:15:39 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-06-14 20:15:39 -0400 |
commit | 942e7b102a4827fdb69a39c7f07c544542589ef9 (patch) | |
tree | 4c47174c91eb76aaa31abc141adbee1acc649987 /drivers/net/wireless/rt2x00/rt2x00usb.c | |
parent | 7d06b2e053d2d536348e3a0f6bb02982a41bea37 (diff) | |
parent | 87291c0269e77b029282676448fed3706a54211a (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00usb.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00usb.c | 165 |
1 files changed, 58 insertions, 107 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 52d12fdc0ccf..68d87f09e054 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -130,16 +130,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) | |||
130 | struct queue_entry *entry = (struct queue_entry *)urb->context; | 130 | struct queue_entry *entry = (struct queue_entry *)urb->context; |
131 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 131 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
132 | struct txdone_entry_desc txdesc; | 132 | struct txdone_entry_desc txdesc; |
133 | __le32 *txd = (__le32 *)entry->skb->data; | ||
134 | enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); | 133 | enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); |
135 | u32 word; | ||
136 | 134 | ||
137 | if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || | 135 | if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || |
138 | !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) | 136 | !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) |
139 | return; | 137 | return; |
140 | 138 | ||
141 | rt2x00_desc_read(txd, 0, &word); | ||
142 | |||
143 | /* | 139 | /* |
144 | * Remove the descriptor data from the buffer. | 140 | * Remove the descriptor data from the buffer. |
145 | */ | 141 | */ |
@@ -169,124 +165,101 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) | |||
169 | rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); | 165 | rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); |
170 | 166 | ||
171 | /* | 167 | /* |
172 | * If the data queue was full before the txdone handler | 168 | * If the data queue was below the threshold before the txdone |
173 | * we must make sure the packet queue in the mac80211 stack | 169 | * handler we must make sure the packet queue in the mac80211 stack |
174 | * is reenabled when the txdone handler has finished. | 170 | * is reenabled when the txdone handler has finished. |
175 | */ | 171 | */ |
176 | if (!rt2x00queue_full(entry->queue)) | 172 | if (!rt2x00queue_threshold(entry->queue)) |
177 | ieee80211_wake_queue(rt2x00dev->hw, qid); | 173 | ieee80211_wake_queue(rt2x00dev->hw, qid); |
178 | } | 174 | } |
179 | 175 | ||
180 | int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, | 176 | int rt2x00usb_write_tx_data(struct queue_entry *entry) |
181 | struct data_queue *queue, struct sk_buff *skb) | ||
182 | { | 177 | { |
178 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | ||
183 | struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); | 179 | struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); |
184 | struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); | ||
185 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; | 180 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; |
186 | struct skb_frame_desc *skbdesc; | 181 | struct skb_frame_desc *skbdesc; |
187 | struct txentry_desc txdesc; | ||
188 | u32 length; | 182 | u32 length; |
189 | 183 | ||
190 | if (rt2x00queue_full(queue)) | ||
191 | return -EINVAL; | ||
192 | |||
193 | if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { | ||
194 | ERROR(rt2x00dev, | ||
195 | "Arrived at non-free entry in the non-full queue %d.\n" | ||
196 | "Please file bug report to %s.\n", | ||
197 | entry->queue->qid, DRV_PROJECT); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Copy all TX descriptor information into txdesc, | ||
203 | * after that we are free to use the skb->cb array | ||
204 | * for our information. | ||
205 | */ | ||
206 | entry->skb = skb; | ||
207 | rt2x00queue_create_tx_descriptor(entry, &txdesc); | ||
208 | |||
209 | /* | 184 | /* |
210 | * Add the descriptor in front of the skb. | 185 | * Add the descriptor in front of the skb. |
211 | */ | 186 | */ |
212 | skb_push(skb, queue->desc_size); | 187 | skb_push(entry->skb, entry->queue->desc_size); |
213 | memset(skb->data, 0, queue->desc_size); | 188 | memset(entry->skb->data, 0, entry->queue->desc_size); |
214 | 189 | ||
215 | /* | 190 | /* |
216 | * Fill in skb descriptor | 191 | * Fill in skb descriptor |
217 | */ | 192 | */ |
218 | skbdesc = get_skb_frame_desc(skb); | 193 | skbdesc = get_skb_frame_desc(entry->skb); |
219 | memset(skbdesc, 0, sizeof(*skbdesc)); | 194 | memset(skbdesc, 0, sizeof(*skbdesc)); |
220 | skbdesc->data = skb->data + queue->desc_size; | 195 | skbdesc->desc = entry->skb->data; |
221 | skbdesc->data_len = skb->len - queue->desc_size; | 196 | skbdesc->desc_len = entry->queue->desc_size; |
222 | skbdesc->desc = skb->data; | ||
223 | skbdesc->desc_len = queue->desc_size; | ||
224 | skbdesc->entry = entry; | 197 | skbdesc->entry = entry; |
225 | 198 | ||
226 | rt2x00queue_write_tx_descriptor(entry, &txdesc); | ||
227 | |||
228 | /* | 199 | /* |
229 | * USB devices cannot blindly pass the skb->len as the | 200 | * USB devices cannot blindly pass the skb->len as the |
230 | * length of the data to usb_fill_bulk_urb. Pass the skb | 201 | * length of the data to usb_fill_bulk_urb. Pass the skb |
231 | * to the driver to determine what the length should be. | 202 | * to the driver to determine what the length should be. |
232 | */ | 203 | */ |
233 | length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, skb); | 204 | length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb); |
234 | 205 | ||
235 | /* | 206 | usb_fill_bulk_urb(entry_priv->urb, usb_dev, |
236 | * Initialize URB and send the frame to the device. | 207 | usb_sndbulkpipe(usb_dev, 1), |
237 | */ | 208 | entry->skb->data, length, |
238 | __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); | 209 | rt2x00usb_interrupt_txdone, entry); |
239 | usb_fill_bulk_urb(entry_priv->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1), | ||
240 | skb->data, length, rt2x00usb_interrupt_txdone, entry); | ||
241 | usb_submit_urb(entry_priv->urb, GFP_ATOMIC); | ||
242 | |||
243 | rt2x00queue_index_inc(queue, Q_INDEX); | ||
244 | 210 | ||
245 | return 0; | 211 | return 0; |
246 | } | 212 | } |
247 | EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); | 213 | EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); |
248 | 214 | ||
249 | /* | 215 | static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) |
250 | * RX data handlers. | ||
251 | */ | ||
252 | static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue) | ||
253 | { | 216 | { |
254 | struct sk_buff *skb; | 217 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; |
255 | unsigned int frame_size; | ||
256 | unsigned int reserved_size; | ||
257 | 218 | ||
258 | /* | 219 | if (__test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) |
259 | * The frame size includes descriptor size, because the | 220 | usb_submit_urb(entry_priv->urb, GFP_ATOMIC); |
260 | * hardware directly receive the frame into the skbuffer. | 221 | } |
261 | */ | 222 | |
262 | frame_size = queue->data_size + queue->desc_size; | 223 | void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, |
224 | const enum data_queue_qid qid) | ||
225 | { | ||
226 | struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid); | ||
227 | unsigned long irqflags; | ||
228 | unsigned int index; | ||
229 | unsigned int index_done; | ||
230 | unsigned int i; | ||
263 | 231 | ||
264 | /* | 232 | /* |
265 | * For the allocation we should keep a few things in mind: | 233 | * Only protect the range we are going to loop over, |
266 | * 1) 4byte alignment of 802.11 payload | 234 | * if during our loop a extra entry is set to pending |
267 | * | 235 | * it should not be kicked during this run, since it |
268 | * For (1) we need at most 4 bytes to guarentee the correct | 236 | * is part of another TX operation. |
269 | * alignment. We are going to optimize the fact that the chance | ||
270 | * that the 802.11 header_size % 4 == 2 is much bigger then | ||
271 | * anything else. However since we need to move the frame up | ||
272 | * to 3 bytes to the front, which means we need to preallocate | ||
273 | * 6 bytes. | ||
274 | */ | 237 | */ |
275 | reserved_size = 6; | 238 | spin_lock_irqsave(&queue->lock, irqflags); |
239 | index = queue->index[Q_INDEX]; | ||
240 | index_done = queue->index[Q_INDEX_DONE]; | ||
241 | spin_unlock_irqrestore(&queue->lock, irqflags); | ||
276 | 242 | ||
277 | /* | 243 | /* |
278 | * Allocate skbuffer. | 244 | * Start from the TX done pointer, this guarentees that we will |
245 | * send out all frames in the correct order. | ||
279 | */ | 246 | */ |
280 | skb = dev_alloc_skb(frame_size + reserved_size); | 247 | if (index_done < index) { |
281 | if (!skb) | 248 | for (i = index_done; i < index; i++) |
282 | return NULL; | 249 | rt2x00usb_kick_tx_entry(&queue->entries[i]); |
283 | 250 | } else { | |
284 | skb_reserve(skb, reserved_size); | 251 | for (i = index_done; i < queue->limit; i++) |
285 | skb_put(skb, frame_size); | 252 | rt2x00usb_kick_tx_entry(&queue->entries[i]); |
286 | 253 | ||
287 | return skb; | 254 | for (i = 0; i < index; i++) |
255 | rt2x00usb_kick_tx_entry(&queue->entries[i]); | ||
256 | } | ||
288 | } | 257 | } |
258 | EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue); | ||
289 | 259 | ||
260 | /* | ||
261 | * RX data handlers. | ||
262 | */ | ||
290 | static void rt2x00usb_interrupt_rxdone(struct urb *urb) | 263 | static void rt2x00usb_interrupt_rxdone(struct urb *urb) |
291 | { | 264 | { |
292 | struct queue_entry *entry = (struct queue_entry *)urb->context; | 265 | struct queue_entry *entry = (struct queue_entry *)urb->context; |
@@ -294,8 +267,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) | |||
294 | struct sk_buff *skb; | 267 | struct sk_buff *skb; |
295 | struct skb_frame_desc *skbdesc; | 268 | struct skb_frame_desc *skbdesc; |
296 | struct rxdone_entry_desc rxdesc; | 269 | struct rxdone_entry_desc rxdesc; |
297 | unsigned int header_size; | 270 | u8 rxd[32]; |
298 | unsigned int align; | ||
299 | 271 | ||
300 | if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || | 272 | if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || |
301 | !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) | 273 | !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) |
@@ -315,39 +287,18 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) | |||
315 | skbdesc = get_skb_frame_desc(entry->skb); | 287 | skbdesc = get_skb_frame_desc(entry->skb); |
316 | memset(skbdesc, 0, sizeof(*skbdesc)); | 288 | memset(skbdesc, 0, sizeof(*skbdesc)); |
317 | skbdesc->entry = entry; | 289 | skbdesc->entry = entry; |
290 | skbdesc->desc = rxd; | ||
291 | skbdesc->desc_len = entry->queue->desc_size; | ||
318 | 292 | ||
319 | memset(&rxdesc, 0, sizeof(rxdesc)); | 293 | memset(&rxdesc, 0, sizeof(rxdesc)); |
320 | rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); | 294 | rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); |
321 | 295 | ||
322 | header_size = ieee80211_get_hdrlen_from_skb(entry->skb); | ||
323 | |||
324 | /* | ||
325 | * The data behind the ieee80211 header must be | ||
326 | * aligned on a 4 byte boundary. We already reserved | ||
327 | * 2 bytes for header_size % 4 == 2 optimization. | ||
328 | * To determine the number of bytes which the data | ||
329 | * should be moved to the left, we must add these | ||
330 | * 2 bytes to the header_size. | ||
331 | */ | ||
332 | align = (header_size + 2) % 4; | ||
333 | |||
334 | if (align) { | ||
335 | skb_push(entry->skb, align); | ||
336 | /* Move entire frame in 1 command */ | ||
337 | memmove(entry->skb->data, entry->skb->data + align, | ||
338 | rxdesc.size); | ||
339 | } | ||
340 | |||
341 | /* Update data pointers, trim buffer to correct size */ | ||
342 | skbdesc->data = entry->skb->data; | ||
343 | skb_trim(entry->skb, rxdesc.size); | ||
344 | |||
345 | /* | 296 | /* |
346 | * Allocate a new sk buffer to replace the current one. | 297 | * Allocate a new sk buffer to replace the current one. |
347 | * If allocation fails, we should drop the current frame | 298 | * If allocation fails, we should drop the current frame |
348 | * so we can recycle the existing sk buffer for the new frame. | 299 | * so we can recycle the existing sk buffer for the new frame. |
349 | */ | 300 | */ |
350 | skb = rt2x00usb_alloc_rxskb(entry->queue); | 301 | skb = rt2x00queue_alloc_rxskb(entry->queue); |
351 | if (!skb) | 302 | if (!skb) |
352 | goto skip_entry; | 303 | goto skip_entry; |
353 | 304 | ||
@@ -519,7 +470,7 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) | |||
519 | */ | 470 | */ |
520 | entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size; | 471 | entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size; |
521 | for (i = 0; i < rt2x00dev->rx->limit; i++) { | 472 | for (i = 0; i < rt2x00dev->rx->limit; i++) { |
522 | skb = rt2x00usb_alloc_rxskb(rt2x00dev->rx); | 473 | skb = rt2x00queue_alloc_rxskb(rt2x00dev->rx); |
523 | if (!skb) | 474 | if (!skb) |
524 | goto exit; | 475 | goto exit; |
525 | 476 | ||