rt2x00: Fix crash on USB unplug
authorIvo van Doorn <ivdoorn@gmail.com>
Thu, 4 Nov 2010 19:41:05 +0000 (20:41 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 15 Nov 2010 18:26:07 +0000 (13:26 -0500)
By not scheduling the TX/RX completion worker threads
when Radio is disabled, or hardware has been unplugged,
the queues cannot be completely cleaned.

This causes crashes when the hardware has been unplugged while
the radio is still enabled.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Gertjan van Wingerde <gwingerde@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00usb.c

index 5ba79b935f09f5bed56f999653338501584cf141..0f34d996975b7e8ac2fc71c22d485deadfb685fc 100644 (file)
@@ -483,6 +483,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry)
        unsigned int header_length;
        int rate_idx;
 
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
+           !test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+               goto submit_entry;
+
        if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
                goto submit_entry;
 
@@ -567,9 +571,13 @@ void rt2x00lib_rxdone(struct queue_entry *entry)
        entry->skb = skb;
 
 submit_entry:
-       rt2x00dev->ops->lib->clear_entry(entry);
-       rt2x00queue_index_inc(entry->queue, Q_INDEX);
+       entry->flags = 0;
        rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
+       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+           test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) {
+               rt2x00dev->ops->lib->clear_entry(entry);
+               rt2x00queue_index_inc(entry->queue, Q_INDEX);
+       }
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
 
index 6dd96192dd91ea19d3d91085ce99104f8e110e3f..9ac14598e2a0e614833a879cb226f345e2d86178 100644 (file)
@@ -226,9 +226,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
         * Schedule the delayed work for reading the TX status
         * from the device.
         */
-       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
-           test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
-               ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
+       ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
 }
 
 static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
@@ -409,9 +407,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
         * Schedule the delayed work for reading the RX status
         * from the device.
         */
-       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
-           test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
-               ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
+       ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
 }
 
 /*