diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00queue.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 99 |
1 files changed, 75 insertions, 24 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 06af823efd83..577029efe320 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -148,35 +148,89 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) | |||
148 | dev_kfree_skb_any(skb); | 148 | dev_kfree_skb_any(skb); |
149 | } | 149 | } |
150 | 150 | ||
151 | void rt2x00queue_payload_align(struct sk_buff *skb, | 151 | void rt2x00queue_align_frame(struct sk_buff *skb) |
152 | bool l2pad, unsigned int header_length) | ||
153 | { | 152 | { |
154 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); | ||
155 | unsigned int frame_length = skb->len; | 153 | unsigned int frame_length = skb->len; |
156 | unsigned int align = ALIGN_SIZE(skb, header_length); | 154 | unsigned int align = ALIGN_SIZE(skb, 0); |
157 | 155 | ||
158 | if (!align) | 156 | if (!align) |
159 | return; | 157 | return; |
160 | 158 | ||
161 | if (l2pad) { | 159 | skb_push(skb, align); |
162 | if (skbdesc->flags & SKBDESC_L2_PADDED) { | 160 | memmove(skb->data, skb->data + align, frame_length); |
163 | /* Remove L2 padding */ | 161 | skb_trim(skb, frame_length); |
164 | memmove(skb->data + align, skb->data, header_length); | 162 | } |
165 | skb_pull(skb, align); | 163 | |
166 | skbdesc->flags &= ~SKBDESC_L2_PADDED; | 164 | void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt) |
167 | } else { | 165 | { |
168 | /* Add L2 padding */ | 166 | unsigned int frame_length = skb->len; |
169 | skb_push(skb, align); | 167 | unsigned int align = ALIGN_SIZE(skb, header_lengt); |
170 | memmove(skb->data, skb->data + align, header_length); | 168 | |
171 | skbdesc->flags |= SKBDESC_L2_PADDED; | 169 | if (!align) |
172 | } | 170 | return; |
171 | |||
172 | skb_push(skb, align); | ||
173 | memmove(skb->data, skb->data + align, frame_length); | ||
174 | skb_trim(skb, frame_length); | ||
175 | } | ||
176 | |||
177 | void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) | ||
178 | { | ||
179 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); | ||
180 | unsigned int frame_length = skb->len; | ||
181 | unsigned int header_align = ALIGN_SIZE(skb, 0); | ||
182 | unsigned int payload_align = ALIGN_SIZE(skb, header_length); | ||
183 | unsigned int l2pad = 4 - (payload_align - header_align); | ||
184 | |||
185 | if (header_align == payload_align) { | ||
186 | /* | ||
187 | * Both header and payload must be moved the same | ||
188 | * amount of bytes to align them properly. This means | ||
189 | * we don't use the L2 padding but just move the entire | ||
190 | * frame. | ||
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; | ||
173 | } else { | 201 | } else { |
174 | /* Generic payload alignment to 4-byte boundary */ | 202 | /* |
175 | skb_push(skb, align); | 203 | * |
176 | memmove(skb->data, skb->data + align, frame_length); | 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 | |||
213 | skb_push(skb, header_align); | ||
214 | memmove(skb->data, skb->data + header_align, header_length); | ||
215 | memmove(skb->data + header_length + l2pad, | ||
216 | skb->data + header_length + l2pad + header_align, | ||
217 | frame_length - header_length); | ||
218 | skbdesc->flags |= SKBDESC_L2_PADDED; | ||
177 | } | 219 | } |
178 | } | 220 | } |
179 | 221 | ||
222 | void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) | ||
223 | { | ||
224 | struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); | ||
225 | unsigned int l2pad = 4 - (header_length & 3); | ||
226 | |||
227 | if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED)) | ||
228 | return; | ||
229 | |||
230 | memmove(skb->data + l2pad, skb->data, header_length); | ||
231 | skb_pull(skb, l2pad); | ||
232 | } | ||
233 | |||
180 | static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, | 234 | static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, |
181 | struct txentry_desc *txdesc) | 235 | struct txentry_desc *txdesc) |
182 | { | 236 | { |
@@ -456,18 +510,15 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) | |||
456 | /* | 510 | /* |
457 | * When DMA allocation is required we should guarentee to the | 511 | * When DMA allocation is required we should guarentee to the |
458 | * driver that the DMA is aligned to a 4-byte boundary. | 512 | * driver that the DMA is aligned to a 4-byte boundary. |
459 | * Aligning the header to this boundary can be done by calling | ||
460 | * rt2x00queue_payload_align with the header length of 0. | ||
461 | * However some drivers require L2 padding to pad the payload | 513 | * However some drivers require L2 padding to pad the payload |
462 | * rather then the header. This could be a requirement for | 514 | * rather then the header. This could be a requirement for |
463 | * PCI and USB devices, while header alignment only is valid | 515 | * PCI and USB devices, while header alignment only is valid |
464 | * for PCI devices. | 516 | * for PCI devices. |
465 | */ | 517 | */ |
466 | if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) | 518 | if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) |
467 | rt2x00queue_payload_align(entry->skb, true, | 519 | rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length); |
468 | txdesc.header_length); | ||
469 | else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) | 520 | else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) |
470 | rt2x00queue_payload_align(entry->skb, false, 0); | 521 | rt2x00queue_align_frame(entry->skb); |
471 | 522 | ||
472 | /* | 523 | /* |
473 | * It could be possible that the queue was corrupted and this | 524 | * It could be possible that the queue was corrupted and this |