aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandrea merello <andrea.merello@gmail.com>2014-02-17 20:10:45 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-03-04 13:07:52 -0500
commit4c552a5be78bd66abd59441a21fec348ee376b49 (patch)
treecfbf800800d32c35bdf742d277dc037b99eecf27
parentf3b6a488a670f1be2666ab97e31dcfc0b1648884 (diff)
rtl818x: Make sure the TX descriptor "valid" flag is written by last
The TX descriptors are consumed by the HW using DMA. Even if in the driver code the memory write that sets the "valid" flag appears after all other writes, the CPU may reorder writes, causing the HW to consider as valid a not-fully-written yet descriptor. This may cause HW incorrect behaviour. This can happen because (AFAIK) the HW may attempt DMA asynchronously without waiting to be kicked by the following register write. This patch adds a write memory barrier to enforce writes ordering. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Andrea Merello <andrea.merello@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/dev.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 1f2462e92528..45d2cc14d71c 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -335,6 +335,11 @@ static void rtl8180_tx(struct ieee80211_hw *dev,
335 entry->flags2 = info->control.rates[1].idx >= 0 ? 335 entry->flags2 = info->control.rates[1].idx >= 0 ?
336 ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; 336 ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
337 entry->retry_limit = info->control.rates[0].count; 337 entry->retry_limit = info->control.rates[0].count;
338
339 /* We must be sure that tx_flags is written last because the HW
340 * looks at it to check if the rest of data is valid or not
341 */
342 wmb();
338 entry->flags = cpu_to_le32(tx_flags); 343 entry->flags = cpu_to_le32(tx_flags);
339 __skb_queue_tail(&ring->queue, skb); 344 __skb_queue_tail(&ring->queue, skb);
340 if (ring->entries - skb_queue_len(&ring->queue) < 2) 345 if (ring->entries - skb_queue_len(&ring->queue) < 2)