diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00queue.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 103 |
1 files changed, 52 insertions, 51 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 577029efe320..a0bd36fc4d2e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2004 - 2009 rt2x00 SourceForge Project | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
3 | Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com> | ||
3 | <http://rt2x00.serialmonkey.com> | 4 | <http://rt2x00.serialmonkey.com> |
4 | 5 | ||
5 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
@@ -23,6 +24,7 @@ | |||
23 | Abstract: rt2x00 queue specific routines. | 24 | Abstract: rt2x00 queue specific routines. |
24 | */ | 25 | */ |
25 | 26 | ||
27 | #include <linux/slab.h> | ||
26 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
27 | #include <linux/module.h> | 29 | #include <linux/module.h> |
28 | #include <linux/dma-mapping.h> | 30 | #include <linux/dma-mapping.h> |
@@ -103,7 +105,7 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) | |||
103 | * is also mapped to the DMA so it can be used for transfering | 105 | * is also mapped to the DMA so it can be used for transfering |
104 | * additional descriptor information to the hardware. | 106 | * additional descriptor information to the hardware. |
105 | */ | 107 | */ |
106 | skb_push(skb, rt2x00dev->hw->extra_tx_headroom); | 108 | skb_push(skb, rt2x00dev->ops->extra_tx_headroom); |
107 | 109 | ||
108 | skbdesc->skb_dma = | 110 | skbdesc->skb_dma = |
109 | dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); | 111 | dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); |
@@ -111,7 +113,7 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) | |||
111 | /* | 113 | /* |
112 | * Restore data pointer to original location again. | 114 | * Restore data pointer to original location again. |
113 | */ | 115 | */ |
114 | skb_pull(skb, rt2x00dev->hw->extra_tx_headroom); | 116 | skb_pull(skb, rt2x00dev->ops->extra_tx_headroom); |
115 | 117 | ||
116 | skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; | 118 | skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; |
117 | } | 119 | } |
@@ -133,7 +135,7 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) | |||
133 | * by the driver, but it was actually mapped to DMA. | 135 | * by the driver, but it was actually mapped to DMA. |
134 | */ | 136 | */ |
135 | dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, | 137 | dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, |
136 | skb->len + rt2x00dev->hw->extra_tx_headroom, | 138 | skb->len + rt2x00dev->ops->extra_tx_headroom, |
137 | DMA_TO_DEVICE); | 139 | DMA_TO_DEVICE); |
138 | skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; | 140 | skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; |
139 | } | 141 | } |
@@ -161,10 +163,10 @@ void rt2x00queue_align_frame(struct sk_buff *skb) | |||
161 | skb_trim(skb, frame_length); | 163 | skb_trim(skb, frame_length); |
162 | } | 164 | } |
163 | 165 | ||
164 | void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt) | 166 | void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) |
165 | { | 167 | { |
166 | unsigned int frame_length = skb->len; | 168 | unsigned int frame_length = skb->len; |
167 | unsigned int align = ALIGN_SIZE(skb, header_lengt); | 169 | unsigned int align = ALIGN_SIZE(skb, header_length); |
168 | 170 | ||
169 | if (!align) | 171 | if (!align) |
170 | return; | 172 | return; |
@@ -176,55 +178,45 @@ void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt) | |||
176 | 178 | ||
177 | void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) | 179 | void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) |
178 | { | 180 | { |
179 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); | 181 | unsigned int payload_length = skb->len - header_length; |
180 | unsigned int frame_length = skb->len; | ||
181 | unsigned int header_align = ALIGN_SIZE(skb, 0); | 182 | unsigned int header_align = ALIGN_SIZE(skb, 0); |
182 | unsigned int payload_align = ALIGN_SIZE(skb, header_length); | 183 | unsigned int payload_align = ALIGN_SIZE(skb, header_length); |
183 | unsigned int l2pad = 4 - (payload_align - header_align); | 184 | unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0; |
184 | 185 | ||
185 | if (header_align == payload_align) { | 186 | /* |
186 | /* | 187 | * Adjust the header alignment if the payload needs to be moved more |
187 | * Both header and payload must be moved the same | 188 | * than the header. |
188 | * amount of bytes to align them properly. This means | 189 | */ |
189 | * we don't use the L2 padding but just move the entire | 190 | if (payload_align > header_align) |
190 | * frame. | 191 | header_align += 4; |
191 | */ | ||
192 | rt2x00queue_align_frame(skb); | ||
193 | } else if (!payload_align) { | ||
194 | /* | ||
195 | * Simple L2 padding, only the header needs to be moved, | ||
196 | * the payload is already properly aligned. | ||
197 | */ | ||
198 | skb_push(skb, header_align); | ||
199 | memmove(skb->data, skb->data + header_align, frame_length); | ||
200 | skbdesc->flags |= SKBDESC_L2_PADDED; | ||
201 | } else { | ||
202 | /* | ||
203 | * | ||
204 | * Complicated L2 padding, both header and payload need | ||
205 | * to be moved. By default we only move to the start | ||
206 | * of the buffer, so our header alignment needs to be | ||
207 | * increased if there is not enough room for the header | ||
208 | * to be moved. | ||
209 | */ | ||
210 | if (payload_align > header_align) | ||
211 | header_align += 4; | ||
212 | 192 | ||
213 | skb_push(skb, header_align); | 193 | /* There is nothing to do if no alignment is needed */ |
214 | memmove(skb->data, skb->data + header_align, header_length); | 194 | if (!header_align) |
195 | return; | ||
196 | |||
197 | /* Reserve the amount of space needed in front of the frame */ | ||
198 | skb_push(skb, header_align); | ||
199 | |||
200 | /* | ||
201 | * Move the header. | ||
202 | */ | ||
203 | memmove(skb->data, skb->data + header_align, header_length); | ||
204 | |||
205 | /* Move the payload, if present and if required */ | ||
206 | if (payload_length && payload_align) | ||
215 | memmove(skb->data + header_length + l2pad, | 207 | memmove(skb->data + header_length + l2pad, |
216 | skb->data + header_length + l2pad + header_align, | 208 | skb->data + header_length + l2pad + payload_align, |
217 | frame_length - header_length); | 209 | payload_length); |
218 | skbdesc->flags |= SKBDESC_L2_PADDED; | 210 | |
219 | } | 211 | /* Trim the skb to the correct size */ |
212 | skb_trim(skb, header_length + l2pad + payload_length); | ||
220 | } | 213 | } |
221 | 214 | ||
222 | void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) | 215 | void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) |
223 | { | 216 | { |
224 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); | 217 | unsigned int l2pad = L2PAD_SIZE(header_length); |
225 | unsigned int l2pad = 4 - (header_length & 3); | ||
226 | 218 | ||
227 | if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED)) | 219 | if (!l2pad) |
228 | return; | 220 | return; |
229 | 221 | ||
230 | memmove(skb->data + l2pad, skb->data, header_length); | 222 | memmove(skb->data + l2pad, skb->data, header_length); |
@@ -345,7 +337,9 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, | |||
345 | * Header and alignment information. | 337 | * Header and alignment information. |
346 | */ | 338 | */ |
347 | txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); | 339 | txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); |
348 | txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length); | 340 | if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) && |
341 | (entry->skb->len > txdesc->header_length)) | ||
342 | txdesc->l2pad = L2PAD_SIZE(txdesc->header_length); | ||
349 | 343 | ||
350 | /* | 344 | /* |
351 | * Check whether this frame is to be acked. | 345 | * Check whether this frame is to be acked. |
@@ -386,10 +380,13 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, | |||
386 | 380 | ||
387 | /* | 381 | /* |
388 | * Beacons and probe responses require the tsf timestamp | 382 | * Beacons and probe responses require the tsf timestamp |
389 | * to be inserted into the frame. | 383 | * to be inserted into the frame, except for a frame that has been injected |
384 | * through a monitor interface. This latter is needed for testing a | ||
385 | * monitor interface. | ||
390 | */ | 386 | */ |
391 | if (ieee80211_is_beacon(hdr->frame_control) || | 387 | if ((ieee80211_is_beacon(hdr->frame_control) || |
392 | ieee80211_is_probe_resp(hdr->frame_control)) | 388 | ieee80211_is_probe_resp(hdr->frame_control)) && |
389 | (!(tx_info->flags & IEEE80211_TX_CTL_INJECTED))) | ||
393 | __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); | 390 | __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); |
394 | 391 | ||
395 | /* | 392 | /* |
@@ -453,7 +450,8 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, | |||
453 | rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid); | 450 | rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid); |
454 | } | 451 | } |
455 | 452 | ||
456 | int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) | 453 | int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, |
454 | bool local) | ||
457 | { | 455 | { |
458 | struct ieee80211_tx_info *tx_info; | 456 | struct ieee80211_tx_info *tx_info; |
459 | struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); | 457 | struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); |
@@ -494,10 +492,13 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) | |||
494 | skbdesc->tx_rate_idx = rate_idx; | 492 | skbdesc->tx_rate_idx = rate_idx; |
495 | skbdesc->tx_rate_flags = rate_flags; | 493 | skbdesc->tx_rate_flags = rate_flags; |
496 | 494 | ||
495 | if (local) | ||
496 | skbdesc->flags |= SKBDESC_NOT_MAC80211; | ||
497 | |||
497 | /* | 498 | /* |
498 | * When hardware encryption is supported, and this frame | 499 | * When hardware encryption is supported, and this frame |
499 | * is to be encrypted, we should strip the IV/EIV data from | 500 | * is to be encrypted, we should strip the IV/EIV data from |
500 | * the frame so we can provide it to the driver seperately. | 501 | * the frame so we can provide it to the driver separately. |
501 | */ | 502 | */ |
502 | if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && | 503 | if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && |
503 | !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { | 504 | !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { |