aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2x00queue.c
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2009-08-29 14:30:45 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-31 14:42:14 -0400
commitdaee6c092aa49ea090612738253ef0d11d120344 (patch)
tree97ab49a8a465b2e0fa470a6e9c5f0264e5db94d3 /drivers/net/wireless/rt2x00/rt2x00queue.c
parent2e27cff871dec9371e41022aaaebb3452ec069c0 (diff)
rt2x00: Reorganize padding & L2 padding
The old function rt2x00queue_payload_align() handled both adding and removing L2 padding and some basic frame alignment. The entire function was being abused because it had multiple functions and the header length argument was somtimes used to align the header instead of the payload. Additionally there was a bug when inserting L2 padding that only the payload was aligned but not the header. This happens when the header wasn't aligned properly by mac80211, but rt2x00lib only moves the payload. A secondary problem was that when removing L2 padding during TXdone or RX the skb wasn't resized to the proper size. Split the function into seperate functions each handling its task as it should. Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00queue.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c99
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
151void rt2x00queue_payload_align(struct sk_buff *skb, 151void 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; 164void 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
177void 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
222void 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
180static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, 234static 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