aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2500usb.c
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/rt2500usb.c
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/rt2500usb.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c37
1 files changed, 17 insertions, 20 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/*