aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2008-03-09 17:38:18 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-03-13 16:02:33 -0400
commitf855c10b6e7b0c448c35b88266f788dd3738375e (patch)
tree0144787573334e3b87b957347d01453196dc870b /drivers/net/wireless/rt2x00
parent40e024de932cca8b54fbcd0e5faf8f364cc84ec0 (diff)
rt2x00: Align RX descriptor to 4 bytes
Some architectures give problems when reading RX frame descriptor words when the descriptor is not aligned on a 4 byte boundrary. Due to optimalizations for the ieee80211 payload 4 byte alignment, it is no longer guarenteed that the descriptor is placed on the 4 byte boundrary (In fact, for rt73usb it is absolutely never aligned to 4 bytes, for rt2500usb it depends on the length of the payload). This will copy the descriptor to a 4 byte aligned location before it is read for the first time. This will also move the payload data alignment in rt2x00usb (instead of inside the driver) where it has always belonged. 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')
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c37
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c17
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c39
3 files changed, 49 insertions, 44 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 9f59db91cfc2..86cd9a5eee2b 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1117,11 +1117,24 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
1117 __le32 *rxd = 1117 __le32 *rxd =
1118 (__le32 *)(entry->skb->data + 1118 (__le32 *)(entry->skb->data +
1119 (priv_rx->urb->actual_length - entry->queue->desc_size)); 1119 (priv_rx->urb->actual_length - entry->queue->desc_size));
1120 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; 1120 unsigned int offset = entry->queue->desc_size + 2;
1121 int header_size = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
1122 u32 word0; 1121 u32 word0;
1123 u32 word1; 1122 u32 word1;
1124 1123
1124 /*
1125 * Copy descriptor to the available headroom inside the skbuffer.
1126 * Remove the original copy by trimming the skbuffer.
1127 */
1128 skb_push(entry->skb, offset);
1129 memcpy(entry->skb->data, rxd, entry->queue->desc_size);
1130 rxd = (__le32 *)entry->skb->data;
1131 skb_pull(entry->skb, offset);
1132 skb_trim(entry->skb, rxdesc->size);
1133
1134 /*
1135 * The descriptor is now aligned to 4 bytes and thus it is
1136 * now safe to read it on all architectures.
1137 */
1125 rt2x00_desc_read(rxd, 0, &word0); 1138 rt2x00_desc_read(rxd, 0, &word0);
1126 rt2x00_desc_read(rxd, 1, &word1); 1139 rt2x00_desc_read(rxd, 1, &word1);
1127 1140
@@ -1142,28 +1155,12 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
1142 rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); 1155 rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
1143 1156
1144 /* 1157 /*
1145 * The data behind the ieee80211 header must be 1158 * Set descriptor and data pointer.
1146 * aligned on a 4 byte boundary.
1147 */
1148 if (header_size % 4 == 0) {
1149 skb_push(entry->skb, 2);
1150 memmove(entry->skb->data, entry->skb->data + 2,
1151 entry->skb->len - 2);
1152 }
1153
1154 /*
1155 * Set descriptor pointer.
1156 */ 1159 */
1157 skbdesc->data = entry->skb->data; 1160 skbdesc->data = entry->skb->data;
1158 skbdesc->data_len = rxdesc->size; 1161 skbdesc->data_len = rxdesc->size;
1159 skbdesc->desc = entry->skb->data + rxdesc->size; 1162 skbdesc->desc = entry->skb->data - offset;
1160 skbdesc->desc_len = entry->queue->desc_size; 1163 skbdesc->desc_len = entry->queue->desc_size;
1161
1162 /*
1163 * Remove descriptor from skb buffer and trim the whole thing
1164 * down to only contain data.
1165 */
1166 skb_trim(entry->skb, rxdesc->size);
1167} 1164}
1168 1165
1169/* 1166/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 063b167da31e..512ff3914813 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -247,11 +247,11 @@ static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue)
247 * advance. 247 * advance.
248 */ 248 */
249 frame_size = queue->data_size + queue->desc_size; 249 frame_size = queue->data_size + queue->desc_size;
250 skb = dev_alloc_skb(frame_size + 2); 250 skb = dev_alloc_skb(queue->desc_size + frame_size + 2);
251 if (!skb) 251 if (!skb)
252 return NULL; 252 return NULL;
253 253
254 skb_reserve(skb, 2); 254 skb_reserve(skb, queue->desc_size + 2);
255 skb_put(skb, frame_size); 255 skb_put(skb, frame_size);
256 256
257 return skb; 257 return skb;
@@ -264,6 +264,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
264 struct sk_buff *skb; 264 struct sk_buff *skb;
265 struct skb_frame_desc *skbdesc; 265 struct skb_frame_desc *skbdesc;
266 struct rxdone_entry_desc rxdesc; 266 struct rxdone_entry_desc rxdesc;
267 int header_size;
267 268
268 if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || 269 if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
269 !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) 270 !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
@@ -288,6 +289,18 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
288 rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); 289 rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
289 290
290 /* 291 /*
292 * The data behind the ieee80211 header must be
293 * aligned on a 4 byte boundary.
294 */
295 header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
296 if (header_size % 4 == 0) {
297 skb_push(entry->skb, 2);
298 memmove(entry->skb->data, entry->skb->data + 2,
299 entry->skb->len - 2);
300 skbdesc->data = entry->skb->data;
301 }
302
303 /*
291 * Allocate a new sk buffer to replace the current one. 304 * Allocate a new sk buffer to replace the current one.
292 * If allocation fails, we should drop the current frame 305 * If allocation fails, we should drop the current frame
293 * so we can recycle the existing sk buffer for the new frame. 306 * so we can recycle the existing sk buffer for the new frame.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 6546b0d607b9..b4b70850edfc 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1370,12 +1370,24 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
1370{ 1370{
1371 struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 1371 struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
1372 __le32 *rxd = (__le32 *)entry->skb->data; 1372 __le32 *rxd = (__le32 *)entry->skb->data;
1373 struct ieee80211_hdr *hdr = 1373 unsigned int offset = entry->queue->desc_size + 2;
1374 (struct ieee80211_hdr *)entry->skb->data + entry->queue->desc_size;
1375 int header_size = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
1376 u32 word0; 1374 u32 word0;
1377 u32 word1; 1375 u32 word1;
1378 1376
1377 /*
1378 * Copy descriptor to the available headroom inside the skbuffer.
1379 * Remove the original copy by pulling the skbuffer.
1380 */
1381 skb_push(entry->skb, offset);
1382 memcpy(entry->skb->data, rxd, entry->queue->desc_size);
1383 rxd = (__le32 *)entry->skb->data;
1384 skb_pull(entry->skb, offset + skbdesc->desc_len);
1385 skb_trim(entry->skb, rxdesc->size);
1386
1387 /*
1388 * The descriptor is now aligned to 4 bytes and thus it is
1389 * now safe to read it on all architectures.
1390 */
1379 rt2x00_desc_read(rxd, 0, &word0); 1391 rt2x00_desc_read(rxd, 0, &word0);
1380 rt2x00_desc_read(rxd, 1, &word1); 1392 rt2x00_desc_read(rxd, 1, &word1);
1381 1393
@@ -1393,29 +1405,12 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
1393 rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); 1405 rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
1394 1406
1395 /* 1407 /*
1396 * The data behind the ieee80211 header must be
1397 * aligned on a 4 byte boundary.
1398 */
1399 if (header_size % 4 == 0) {
1400 skb_push(entry->skb, 2);
1401 memmove(entry->skb->data, entry->skb->data + 2,
1402 entry->skb->len - 2);
1403 }
1404
1405 /*
1406 * Set descriptor and data pointer. 1408 * Set descriptor and data pointer.
1407 */ 1409 */
1408 skbdesc->data = entry->skb->data + entry->queue->desc_size; 1410 skbdesc->data = entry->skb->data;
1409 skbdesc->data_len = rxdesc->size; 1411 skbdesc->data_len = rxdesc->size;
1410 skbdesc->desc = entry->skb->data; 1412 skbdesc->desc = entry->skb->data - offset;
1411 skbdesc->desc_len = entry->queue->desc_size; 1413 skbdesc->desc_len = entry->queue->desc_size;
1412
1413 /*
1414 * Remove descriptor from skb buffer and trim the whole thing
1415 * down to only contain data.
1416 */
1417 skb_pull(entry->skb, skbdesc->desc_len);
1418 skb_trim(entry->skb, rxdesc->size);
1419} 1414}
1420 1415
1421/* 1416/*