aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/rt2x00
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rt2x00')
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c36
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c38
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c36
5 files changed, 70 insertions, 45 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index fdbd0ef2be4..61e59c17a60 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -138,11 +138,8 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- return;
- }
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+ goto exit_fail;
/*
* Write the data into the BBP.
@@ -155,6 +152,13 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ return;
+
+exit_fail:
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
}
static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -168,10 +172,8 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
- return;
- }
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+ goto exit_fail;
/*
* Write the request into the BBP.
@@ -186,17 +188,21 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
- *value = 0xff;
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- return;
- }
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+ goto exit_fail;
rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ return;
+
+exit_fail:
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+ *value = 0xff;
}
static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 611d9832059..b4bf1e09cf9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -821,6 +821,7 @@ struct rt2x00_dev {
/*
* Scheduled work.
*/
+ struct workqueue_struct *workqueue;
struct work_struct intf_work;
struct work_struct filter_work;
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 2673d568bca..c997d4f28ab 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -75,7 +75,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
rt2x00lib_reset_link_tuner(rt2x00dev);
- queue_delayed_work(rt2x00dev->hw->workqueue,
+ queue_delayed_work(rt2x00dev->workqueue,
&rt2x00dev->link.work, LINK_TUNE_INTERVAL);
}
@@ -137,14 +137,6 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
return;
/*
- * Stop all scheduled work.
- */
- if (work_pending(&rt2x00dev->intf_work))
- cancel_work_sync(&rt2x00dev->intf_work);
- if (work_pending(&rt2x00dev->filter_work))
- cancel_work_sync(&rt2x00dev->filter_work);
-
- /*
* Stop the TX queues.
*/
ieee80211_stop_queues(rt2x00dev->hw);
@@ -398,8 +390,8 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
* Increase tuner counter, and reschedule the next link tuner run.
*/
rt2x00dev->link.count++;
- queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work,
- LINK_TUNE_INTERVAL);
+ queue_delayed_work(rt2x00dev->workqueue,
+ &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
}
static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
@@ -433,6 +425,15 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
spin_unlock(&intf->lock);
+ /*
+ * It is possible the radio was disabled while the work had been
+ * scheduled. If that happens we should return here immediately,
+ * note that in the spinlock protected area above the delayed_flags
+ * have been cleared correctly.
+ */
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
if (delayed_flags & DELAYED_UPDATE_BEACON) {
skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control);
if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
@@ -441,7 +442,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
}
if (delayed_flags & DELAYED_CONFIG_ERP)
- rt2x00lib_config_erp(rt2x00dev, intf, &intf->conf);
+ rt2x00lib_config_erp(rt2x00dev, intf, &conf);
if (delayed_flags & DELAYED_LED_ASSOC)
rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
@@ -487,7 +488,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
rt2x00lib_beacondone_iter,
rt2x00dev);
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
@@ -1130,6 +1131,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
/*
* Initialize configuration work.
*/
+ rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib");
+ if (!rt2x00dev->workqueue)
+ goto exit;
+
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
@@ -1190,6 +1195,13 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
rt2x00leds_unregister(rt2x00dev);
/*
+ * Stop all queued work. Note that most tasks will already be halted
+ * during rt2x00lib_disable_radio() and rt2x00lib_uninitialize().
+ */
+ flush_workqueue(rt2x00dev->workqueue);
+ destroy_workqueue(rt2x00dev->workqueue);
+
+ /*
* Free ieee80211_hw memory.
*/
rt2x00lib_remove_hw(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 87e280a2197..9cb023edd2e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -428,7 +428,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
else
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->filter_work);
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
@@ -509,7 +509,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
if (delayed) {
intf->delayed_flags |= delayed;
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
}
spin_unlock(&intf->lock);
}
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index fff8386e816..83cc0147f69 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -134,11 +134,8 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- return;
- }
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ goto exit_fail;
/*
* Write the data into the BBP.
@@ -151,6 +148,13 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ return;
+
+exit_fail:
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
}
static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -164,11 +168,8 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- return;
- }
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ goto exit_fail;
/*
* Write the request into the BBP.
@@ -184,14 +185,19 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
- *value = 0xff;
- return;
- }
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ goto exit_fail;
*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ return;
+
+exit_fail:
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ *value = 0xff;
}
static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,