aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2800pci.c
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2010-10-02 05:29:30 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-05 13:35:27 -0400
commit95192339c2de1e1a61baf289af3e3332403371c9 (patch)
treea6120e7e1828de19b8b6eda5b366db45a85cd45d /drivers/net/wireless/rt2x00/rt2800pci.c
parentd13a97f07d86f462096007dbf0f2e0338692abc0 (diff)
rt2x00: Fix race between dma mapping and clearing rx entries in rt2800pci
During rx, rt2x00lib calls rt2800pci_fill_rxdone to read the RX descriptor. At that time the skb is already dma unmapped but no new skb was dma mapped for this entry again. However, rt2800pci_fill_rxdone also moves the hw rx queue index, marking this entry to be available for reuse. Since no new skb was dma mapped and also the previous skb was unmapped this might lead to strange hw behavior. To fix this issue move the hw rx queue index increment to rt2800pci_clear_entry where a new skb was already dma mapped and can be safely used by the hw. Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com> 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/rt2800pci.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 3806454b827b..85a134cd62bf 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -241,6 +241,7 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
241{ 241{
242 struct queue_entry_priv_pci *entry_priv = entry->priv_data; 242 struct queue_entry_priv_pci *entry_priv = entry->priv_data;
243 struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); 243 struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
244 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
244 u32 word; 245 u32 word;
245 246
246 if (entry->queue->qid == QID_RX) { 247 if (entry->queue->qid == QID_RX) {
@@ -251,6 +252,13 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
251 rt2x00_desc_read(entry_priv->desc, 1, &word); 252 rt2x00_desc_read(entry_priv->desc, 1, &word);
252 rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0); 253 rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0);
253 rt2x00_desc_write(entry_priv->desc, 1, word); 254 rt2x00_desc_write(entry_priv->desc, 1, word);
255
256 /*
257 * Set RX IDX in register to inform hardware that we have
258 * handled this entry and it is available for reuse again.
259 */
260 rt2800_register_write(rt2x00dev, RX_CRX_IDX,
261 entry->entry_idx);
254 } else { 262 } else {
255 rt2x00_desc_read(entry_priv->desc, 1, &word); 263 rt2x00_desc_read(entry_priv->desc, 1, &word);
256 rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1); 264 rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1);
@@ -599,7 +607,6 @@ static void rt2800pci_kill_tx_queue(struct data_queue *queue)
599static void rt2800pci_fill_rxdone(struct queue_entry *entry, 607static void rt2800pci_fill_rxdone(struct queue_entry *entry,
600 struct rxdone_entry_desc *rxdesc) 608 struct rxdone_entry_desc *rxdesc)
601{ 609{
602 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
603 struct queue_entry_priv_pci *entry_priv = entry->priv_data; 610 struct queue_entry_priv_pci *entry_priv = entry->priv_data;
604 __le32 *rxd = entry_priv->desc; 611 __le32 *rxd = entry_priv->desc;
605 u32 word; 612 u32 word;
@@ -641,12 +648,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
641 * Process the RXWI structure that is at the start of the buffer. 648 * Process the RXWI structure that is at the start of the buffer.
642 */ 649 */
643 rt2800_process_rxwi(entry, rxdesc); 650 rt2800_process_rxwi(entry, rxdesc);
644
645 /*
646 * Set RX IDX in register to inform hardware that we have handled
647 * this entry and it is available for reuse again.
648 */
649 rt2800_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
650} 651}
651 652
652/* 653/*