aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2x00dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c33
1 files changed, 30 insertions, 3 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index c3e1aa7c1a80..fc9901e027c1 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -88,6 +88,8 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00queue_start_queues(rt2x00dev);
rt2x00link_start_tuner(rt2x00dev);
rt2x00link_start_agc(rt2x00dev);
+ if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+ rt2x00link_start_vcocal(rt2x00dev);
/*
* Start watchdog monitoring.
@@ -111,6 +113,8 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
* Stop all queues
*/
rt2x00link_stop_agc(rt2x00dev);
+ if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+ rt2x00link_stop_vcocal(rt2x00dev);
rt2x00link_stop_tuner(rt2x00dev);
rt2x00queue_stop_queues(rt2x00dev);
rt2x00queue_flush_queues(rt2x00dev, true);
@@ -426,10 +430,14 @@ void rt2x00lib_txdone(struct queue_entry *entry,
/*
* If the data queue was below the threshold before the txdone
* handler we must make sure the packet queue in the mac80211 stack
- * is reenabled when the txdone handler has finished.
+ * is reenabled when the txdone handler has finished. This has to be
+ * serialized with rt2x00mac_tx(), otherwise we can wake up queue
+ * before it was stopped.
*/
+ spin_lock_bh(&entry->queue->tx_lock);
if (!rt2x00queue_threshold(entry->queue))
rt2x00queue_unpause_queue(entry->queue);
+ spin_unlock_bh(&entry->queue->tx_lock);
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
@@ -1121,6 +1129,18 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
{
int retval = -ENOMEM;
+ /*
+ * Allocate the driver data memory, if necessary.
+ */
+ if (rt2x00dev->ops->drv_data_size > 0) {
+ rt2x00dev->drv_data = kzalloc(rt2x00dev->ops->drv_data_size,
+ GFP_KERNEL);
+ if (!rt2x00dev->drv_data) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ }
+
spin_lock_init(&rt2x00dev->irqmask_lock);
mutex_init(&rt2x00dev->csr_mutex);
@@ -1216,11 +1236,12 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
cancel_work_sync(&rt2x00dev->sleep_work);
if (rt2x00_is_usb(rt2x00dev)) {
- del_timer_sync(&rt2x00dev->txstatus_timer);
+ hrtimer_cancel(&rt2x00dev->txstatus_timer);
cancel_work_sync(&rt2x00dev->rxdone_work);
cancel_work_sync(&rt2x00dev->txdone_work);
}
- destroy_workqueue(rt2x00dev->workqueue);
+ if (rt2x00dev->workqueue)
+ destroy_workqueue(rt2x00dev->workqueue);
/*
* Free the tx status fifo.
@@ -1261,6 +1282,12 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
* Free queue structures.
*/
rt2x00queue_free(rt2x00dev);
+
+ /*
+ * Free the driver data.
+ */
+ if (rt2x00dev->drv_data)
+ kfree(rt2x00dev->drv_data);
}
EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);