diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2008-03-09 17:38:18 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-13 16:02:33 -0400 |
commit | f855c10b6e7b0c448c35b88266f788dd3738375e (patch) | |
tree | 0144787573334e3b87b957347d01453196dc870b /drivers/net/wireless/rt2x00/rt2500usb.c | |
parent | 40e024de932cca8b54fbcd0e5faf8f364cc84ec0 (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.c | 37 |
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 | /* |