Commit 95192339 authored by Helmut Schaa's avatar Helmut Schaa Committed by John W. Linville

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: default avatarHelmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent d13a97f0
...@@ -241,6 +241,7 @@ static void rt2800pci_clear_entry(struct queue_entry *entry) ...@@ -241,6 +241,7 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
{ {
struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
u32 word; u32 word;
if (entry->queue->qid == QID_RX) { if (entry->queue->qid == QID_RX) {
...@@ -251,6 +252,13 @@ static void rt2800pci_clear_entry(struct queue_entry *entry) ...@@ -251,6 +252,13 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
rt2x00_desc_read(entry_priv->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0); rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0);
rt2x00_desc_write(entry_priv->desc, 1, word); rt2x00_desc_write(entry_priv->desc, 1, word);
/*
* Set RX IDX in register to inform hardware that we have
* handled this entry and it is available for reuse again.
*/
rt2800_register_write(rt2x00dev, RX_CRX_IDX,
entry->entry_idx);
} else { } else {
rt2x00_desc_read(entry_priv->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1); rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1);
...@@ -599,7 +607,6 @@ static void rt2800pci_kill_tx_queue(struct data_queue *queue) ...@@ -599,7 +607,6 @@ static void rt2800pci_kill_tx_queue(struct data_queue *queue)
static void rt2800pci_fill_rxdone(struct queue_entry *entry, static void rt2800pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc) struct rxdone_entry_desc *rxdesc)
{ {
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
__le32 *rxd = entry_priv->desc; __le32 *rxd = entry_priv->desc;
u32 word; u32 word;
...@@ -641,12 +648,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, ...@@ -641,12 +648,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
* Process the RXWI structure that is at the start of the buffer. * Process the RXWI structure that is at the start of the buffer.
*/ */
rt2800_process_rxwi(entry, rxdesc); rt2800_process_rxwi(entry, rxdesc);
/*
* Set RX IDX in register to inform hardware that we have handled
* this entry and it is available for reuse again.
*/
rt2800_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment