aboutsummaryrefslogtreecommitdiff
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.c883
1 files changed, 714 insertions, 169 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 06c43ca39bf..4fa43a2eeb7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+ Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@@ -13,9 +14,7 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the
- Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/*
@@ -25,11 +24,29 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/log2.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
/*
+ * Utility functions.
+ */
+u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_vif *vif)
+{
+ /*
+ * When in STA mode, bssidx is always 0 otherwise local_address[5]
+ * contains the bss number, see BSS_ID_MASK comments for details.
+ */
+ if (rt2x00dev->intf_sta_count)
+ return 0;
+ return vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_get_bssidx);
+
+/*
* Radio control handlers.
*/
int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -64,14 +81,18 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);
/*
- * Enable RX.
+ * Enable queues.
*/
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ rt2x00queue_start_queues(rt2x00dev);
+ rt2x00link_start_tuner(rt2x00dev);
+ rt2x00link_start_agc(rt2x00dev);
+ if (rt2x00_has_cap_vco_recalibration(rt2x00dev))
+ rt2x00link_start_vcocal(rt2x00dev);
/*
- * Start the TX queues.
+ * Start watchdog monitoring.
*/
- ieee80211_wake_queues(rt2x00dev->hw);
+ rt2x00link_start_watchdog(rt2x00dev);
return 0;
}
@@ -82,15 +103,19 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
return;
/*
- * Stop the TX queues in mac80211.
+ * Stop watchdog monitoring.
*/
- ieee80211_stop_queues(rt2x00dev->hw);
- rt2x00queue_stop_queues(rt2x00dev);
+ rt2x00link_stop_watchdog(rt2x00dev);
/*
- * Disable RX.
+ * Stop all queues
*/
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+ rt2x00link_stop_agc(rt2x00dev);
+ if (rt2x00_has_cap_vco_recalibration(rt2x00dev))
+ rt2x00link_stop_vcocal(rt2x00dev);
+ rt2x00link_stop_tuner(rt2x00dev);
+ rt2x00queue_stop_queues(rt2x00dev);
+ rt2x00queue_flush_queues(rt2x00dev, true);
/*
* Disable radio.
@@ -101,41 +126,11 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00leds_led_radio(rt2x00dev, false);
}
-void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
-{
- /*
- * When we are disabling the RX, we should also stop the link tuner.
- */
- if (state == STATE_RADIO_RX_OFF)
- rt2x00link_stop_tuner(rt2x00dev);
-
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
-
- /*
- * When we are enabling the RX, we should also start the link tuner.
- */
- if (state == STATE_RADIO_RX_ON)
- rt2x00link_start_tuner(rt2x00dev);
-}
-
static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);
- int delayed_flags;
-
- /*
- * Copy all data we need during this action under the protection
- * of a spinlock. Otherwise race conditions might occur which results
- * into an invalid configuration.
- */
- spin_lock(&intf->lock);
-
- delayed_flags = intf->delayed_flags;
- intf->delayed_flags = 0;
-
- spin_unlock(&intf->lock);
/*
* It is possible the radio was disabled while the work had been
@@ -146,8 +141,8 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
- if (delayed_flags & DELAYED_UPDATE_BEACON)
- rt2x00queue_update_beacon(rt2x00dev, vif, true);
+ if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags))
+ rt2x00queue_update_beacon(rt2x00dev, vif);
}
static void rt2x00lib_intf_scheduled(struct work_struct *work)
@@ -160,17 +155,54 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
* requested configurations.
*/
ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
rt2x00lib_intf_scheduled_iter,
rt2x00dev);
}
+static void rt2x00lib_autowakeup(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, autowakeup_work.work);
+
+ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+ return;
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ rt2x00_err(rt2x00dev, "Device failed to wakeup\n");
+ clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
+}
+
/*
* Interrupt context handlers.
*/
-static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
- struct ieee80211_vif *vif)
+static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
{
- struct rt2x00_intf *intf = vif_to_intf(vif);
+ struct ieee80211_tx_control control = {};
+ struct rt2x00_dev *rt2x00dev = data;
+ struct sk_buff *skb;
+
+ /*
+ * Only AP mode interfaces do broad- and multicast buffering
+ */
+ if (vif->type != NL80211_IFTYPE_AP)
+ return;
+
+ /*
+ * Send out buffered broad- and multicast frames
+ */
+ skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
+ while (skb) {
+ rt2x00mac_tx(rt2x00dev->hw, &control, skb);
+ skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif);
+ }
+}
+
+static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct rt2x00_dev *rt2x00dev = data;
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_ADHOC &&
@@ -178,9 +210,13 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac,
vif->type != NL80211_IFTYPE_WDS)
return;
- spin_lock(&intf->lock);
- intf->delayed_flags |= DELAYED_UPDATE_BEACON;
- spin_unlock(&intf->lock);
+ /*
+ * Update the beacon without locking. This is safe on PCI devices
+ * as they only update the beacon periodically here. This should
+ * never be called for USB devices.
+ */
+ WARN_ON(rt2x00_is_usb(rt2x00dev));
+ rt2x00queue_update_beacon_locked(rt2x00dev, vif);
}
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
@@ -188,45 +224,140 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
- ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
- rt2x00lib_beacondone_iter,
- rt2x00dev);
+ /* send buffered bc/mc frames out for every bssid */
+ ieee80211_iterate_active_interfaces_atomic(
+ rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+ rt2x00lib_bc_buffer_iter, rt2x00dev);
+ /*
+ * Devices with pre tbtt interrupt don't need to update the beacon
+ * here as they will fetch the next beacon directly prior to
+ * transmission.
+ */
+ if (rt2x00_has_cap_pre_tbtt_interrupt(rt2x00dev))
+ return;
- ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
+ /* fetch next beacon */
+ ieee80211_iterate_active_interfaces_atomic(
+ rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+ rt2x00lib_beaconupdate_iter, rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
+void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ /* fetch next beacon */
+ ieee80211_iterate_active_interfaces_atomic(
+ rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+ rt2x00lib_beaconupdate_iter, rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
+
+void rt2x00lib_dmastart(struct queue_entry *entry)
+{
+ set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+ rt2x00queue_index_inc(entry, Q_INDEX);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_dmastart);
+
+void rt2x00lib_dmadone(struct queue_entry *entry)
+{
+ set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags);
+ clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+ rt2x00queue_index_inc(entry, Q_INDEX_DMA_DONE);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
+
+static inline int rt2x00lib_txdone_bar_status(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct ieee80211_bar *bar = (void *) entry->skb->data;
+ struct rt2x00_bar_list_entry *bar_entry;
+ int ret;
+
+ if (likely(!ieee80211_is_back_req(bar->frame_control)))
+ return 0;
+
+ /*
+ * Unlike all other frames, the status report for BARs does
+ * not directly come from the hardware as it is incapable of
+ * matching a BA to a previously send BAR. The hardware will
+ * report all BARs as if they weren't acked at all.
+ *
+ * Instead the RX-path will scan for incoming BAs and set the
+ * block_acked flag if it sees one that was likely caused by
+ * a BAR from us.
+ *
+ * Remove remaining BARs here and return their status for
+ * TX done processing.
+ */
+ ret = 0;
+ rcu_read_lock();
+ list_for_each_entry_rcu(bar_entry, &rt2x00dev->bar_list, list) {
+ if (bar_entry->entry != entry)
+ continue;
+
+ spin_lock_bh(&rt2x00dev->bar_list_lock);
+ /* Return whether this BAR was blockacked or not */
+ ret = bar_entry->block_acked;
+ /* Remove the BAR from our checklist */
+ list_del_rcu(&bar_entry->list);
+ spin_unlock_bh(&rt2x00dev->bar_list_lock);
+ kfree_rcu(bar_entry, head);
+
+ break;
+ }
+ rcu_read_unlock();
+
+ return ret;
+}
+
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
- unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
+ unsigned int header_length, i;
u8 rate_idx, rate_flags, retry_rates;
u8 skbdesc_flags = skbdesc->flags;
- unsigned int i;
bool success;
/*
* Unmap the skb.
*/
- rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+ rt2x00queue_unmap_skb(entry);
+
+ /*
+ * Remove the extra tx headroom from the skb.
+ */
+ skb_pull(entry->skb, rt2x00dev->extra_tx_headroom);
+
+ /*
+ * Signal that the TX descriptor is no longer in the skb.
+ */
+ skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;
+
+ /*
+ * Determine the length of 802.11 header.
+ */
+ header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
/*
* Remove L2 padding which was added during
*/
- if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
+ if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags))
rt2x00queue_remove_l2pad(entry->skb, header_length);
/*
* If the IV/EIV data was stripped from the frame before it was
* passed to the hardware, we should now reinsert it again because
- * mac80211 will expect the the same data to be present it the
+ * mac80211 will expect the same data to be present it the
* frame as it was passed to us.
*/
- if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+ if (rt2x00_has_cap_hw_crypto(rt2x00dev))
rt2x00crypto_tx_insert_iv(entry->skb, header_length);
/*
@@ -236,12 +367,14 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
/*
- * Determine if the frame has been successfully transmitted.
+ * Determine if the frame has been successfully transmitted and
+ * remove BARs from our check list while checking for their
+ * TX status.
*/
success =
+ rt2x00lib_txdone_bar_status(entry) ||
test_bit(TXDONE_SUCCESS, &txdesc->flags) ||
- test_bit(TXDONE_UNKNOWN, &txdesc->flags) ||
- test_bit(TXDONE_FALLBACK, &txdesc->flags);
+ test_bit(TXDONE_UNKNOWN, &txdesc->flags);
/*
* Update TX statistics.
@@ -263,11 +396,22 @@ void rt2x00lib_txdone(struct queue_entry *entry,
/*
* Frame was send with retries, hardware tried
* different rates to send out the frame, at each
- * retry it lowered the rate 1 step.
+ * retry it lowered the rate 1 step except when the
+ * lowest rate was used.
*/
for (i = 0; i < retry_rates && i < IEEE80211_TX_MAX_RATES; i++) {
tx_info->status.rates[i].idx = rate_idx - i;
tx_info->status.rates[i].flags = rate_flags;
+
+ if (rate_idx - i == 0) {
+ /*
+ * The lowest rate (index 0) was used until the
+ * number of max retries was reached.
+ */
+ tx_info->status.rates[i].count = retry_rates - i;
+ i++;
+ break;
+ }
tx_info->status.rates[i].count = 1;
}
if (i < (IEEE80211_TX_MAX_RATES - 1))
@@ -280,6 +424,25 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00dev->low_level_stats.dot11ACKFailureCount++;
}
+ /*
+ * Every single frame has it's own tx status, hence report
+ * every frame as ampdu of size 1.
+ *
+ * TODO: if we can find out how many frames were aggregated
+ * by the hw we could provide the real ampdu_len to mac80211
+ * which would allow the rc algorithm to better decide on
+ * which rates are suitable.
+ */
+ if (test_bit(TXDONE_AMPDU, &txdesc->flags) ||
+ tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
+ tx_info->status.ampdu_len = 1;
+ tx_info->status.ampdu_ack_len = success ? 1 : 0;
+
+ if (!success)
+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+ }
+
if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
if (success)
rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
@@ -293,10 +456,13 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* through a mac80211 library call (RTS/CTS) then we should not
* send the status report back.
*/
- if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
- ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
- else
- dev_kfree_skb_irq(entry->skb);
+ if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) {
+ if (test_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags))
+ ieee80211_tx_status(rt2x00dev->hw, entry->skb);
+ else
+ ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb);
+ } else
+ dev_kfree_skb_any(entry->skb);
/*
* Make this entry available for reuse.
@@ -306,78 +472,239 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00dev->ops->lib->clear_entry(entry);
- clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
+ rt2x00queue_index_inc(entry, Q_INDEX_DONE);
/*
* 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))
- ieee80211_wake_queue(rt2x00dev->hw, qid);
+ rt2x00queue_unpause_queue(entry->queue);
+ spin_unlock_bh(&entry->queue->tx_lock);
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
-static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
- struct rxdone_entry_desc *rxdesc)
+void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status)
{
- struct ieee80211_supported_band *sband;
- const struct rt2x00_rate *rate;
- unsigned int i;
- int signal;
- int type;
+ struct txdone_entry_desc txdesc;
+
+ txdesc.flags = 0;
+ __set_bit(status, &txdesc.flags);
+ txdesc.retry = 0;
+
+ rt2x00lib_txdone(entry, &txdesc);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo);
+
+static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie)
+{
+ struct ieee80211_mgmt *mgmt = (void *)data;
+ u8 *pos, *end;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = data + len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end)
+ return NULL;
+
+ if (pos[0] == ie)
+ return pos;
+
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+static void rt2x00lib_sleep(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, sleep_work);
+
+ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+ return;
/*
- * For non-HT rates the MCS value needs to contain the
- * actually used rate modulation (CCK or OFDM).
+ * Check again is powersaving is enabled, to prevent races from delayed
+ * work execution.
*/
- if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS)
- signal = RATE_MCS(rxdesc->rate_mode, rxdesc->signal);
- else
- signal = rxdesc->signal;
+ if (!test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags))
+ rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf,
+ IEEE80211_CONF_CHANGE_PS);
+}
+
+static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev,
+ struct sk_buff *skb,
+ struct rxdone_entry_desc *rxdesc)
+{
+ struct rt2x00_bar_list_entry *entry;
+ struct ieee80211_bar *ba = (void *)skb->data;
+
+ if (likely(!ieee80211_is_back(ba->frame_control)))
+ return;
+
+ if (rxdesc->size < sizeof(*ba) + FCS_LEN)
+ return;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(entry, &rt2x00dev->bar_list, list) {
+
+ if (ba->start_seq_num != entry->start_seq_num)
+ continue;
+
+#define TID_CHECK(a, b) ( \
+ ((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) == \
+ ((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK))) \
+
+ if (!TID_CHECK(ba->control, entry->control))
+ continue;
- type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK);
+#undef TID_CHECK
+
+ if (!ether_addr_equal_64bits(ba->ra, entry->ta))
+ continue;
+
+ if (!ether_addr_equal_64bits(ba->ta, entry->ra))
+ continue;
+
+ /* Mark BAR since we received the according BA */
+ spin_lock_bh(&rt2x00dev->bar_list_lock);
+ entry->block_acked = 1;
+ spin_unlock_bh(&rt2x00dev->bar_list_lock);
+ break;
+ }
+ rcu_read_unlock();
+
+}
+
+static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
+ struct sk_buff *skb,
+ struct rxdone_entry_desc *rxdesc)
+{
+ struct ieee80211_hdr *hdr = (void *) skb->data;
+ struct ieee80211_tim_ie *tim_ie;
+ u8 *tim;
+ u8 tim_len;
+ bool cam;
+
+ /* If this is not a beacon, or if mac80211 has no powersaving
+ * configured, or if the device is already in powersaving mode
+ * we can exit now. */
+ if (likely(!ieee80211_is_beacon(hdr->frame_control) ||
+ !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS)))
+ return;
+
+ /* min. beacon length + FCS_LEN */
+ if (skb->len <= 40 + FCS_LEN)
+ return;
+
+ /* and only beacons from the associated BSSID, please */
+ if (!(rxdesc->dev_flags & RXDONE_MY_BSS) ||
+ !rt2x00dev->aid)
+ return;
+
+ rt2x00dev->last_beacon = jiffies;
+
+ tim = rt2x00lib_find_ie(skb->data, skb->len - FCS_LEN, WLAN_EID_TIM);
+ if (!tim)
+ return;
+
+ if (tim[1] < sizeof(*tim_ie))
+ return;
- sband = &rt2x00dev->bands[rt2x00dev->curr_band];
- for (i = 0; i < sband->n_bitrates; i++) {
- rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
+ tim_len = tim[1];
+ tim_ie = (struct ieee80211_tim_ie *) &tim[2];
- if (((type == RXDONE_SIGNAL_PLCP) &&
- (rate->plcp == signal)) ||
- ((type == RXDONE_SIGNAL_BITRATE) &&
- (rate->bitrate == signal)) ||
- ((type == RXDONE_SIGNAL_MCS) &&
- (rate->mcs == signal))) {
- return i;
+ /* Check whenever the PHY can be turned off again. */
+
+ /* 1. What about buffered unicast traffic for our AID? */
+ cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid);
+
+ /* 2. Maybe the AP wants to send multicast/broadcast data? */
+ cam |= (tim_ie->bitmap_ctrl & 0x01);
+
+ if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags))
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->sleep_work);
+}
+
+static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
+ struct rxdone_entry_desc *rxdesc)
+{
+ struct ieee80211_supported_band *sband;
+ const struct rt2x00_rate *rate;
+ unsigned int i;
+ int signal = rxdesc->signal;
+ int type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK);
+
+ switch (rxdesc->rate_mode) {
+ case RATE_MODE_CCK:
+ case RATE_MODE_OFDM:
+ /*
+ * For non-HT rates the MCS value needs to contain the
+ * actually used rate modulation (CCK or OFDM).
+ */
+ if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS)
+ signal = RATE_MCS(rxdesc->rate_mode, signal);
+
+ sband = &rt2x00dev->bands[rt2x00dev->curr_band];
+ for (i = 0; i < sband->n_bitrates; i++) {
+ rate = rt2x00_get_rate(sband->bitrates[i].hw_value);
+ if (((type == RXDONE_SIGNAL_PLCP) &&
+ (rate->plcp == signal)) ||
+ ((type == RXDONE_SIGNAL_BITRATE) &&
+ (rate->bitrate == signal)) ||
+ ((type == RXDONE_SIGNAL_MCS) &&
+ (rate->mcs == signal))) {
+ return i;
+ }
}
+ break;
+ case RATE_MODE_HT_MIX:
+ case RATE_MODE_HT_GREENFIELD:
+ if (signal >= 0 && signal <= 76)
+ return signal;
+ break;
+ default:
+ break;
}
- WARNING(rt2x00dev, "Frame received with unrecognized signal, "
- "signal=0x%.4x, type=%d.\n", signal, type);
+ rt2x00_warn(rt2x00dev, "Frame received with unrecognized signal, mode=0x%.4x, signal=0x%.4x, type=%d\n",
+ rxdesc->rate_mode, signal, type);
return 0;
}
-void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
- struct queue_entry *entry)
+void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp)
{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct rxdone_entry_desc rxdesc;
struct sk_buff *skb;
- struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
+ struct ieee80211_rx_status *rx_status;
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;
+
/*
* Allocate a new sk_buffer. If no new buffer available, drop the
* received frame and reuse the existing buffer.
*/
- skb = rt2x00queue_alloc_rxskb(rt2x00dev, entry);
+ skb = rt2x00queue_alloc_rxskb(entry, gfp);
if (!skb)
- return;
+ goto submit_entry;
/*
* Unmap the skb.
*/
- rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+ rt2x00queue_unmap_skb(entry);
/*
* Extract the RXD details.
@@ -385,8 +712,17 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
- /* Trim buffer to correct size */
- skb_trim(entry->skb, rxdesc.size);
+ /*
+ * Check for valid size in case we get corrupted descriptor from
+ * hardware.
+ */
+ if (unlikely(rxdesc.size == 0 ||
+ rxdesc.size > entry->queue->data_size)) {
+ rt2x00_err(rt2x00dev, "Wrong frame size %d max %d\n",
+ rxdesc.size, entry->queue->data_size);
+ dev_kfree_skb(entry->skb);
+ goto renew_skb;
+ }
/*
* The data behind the ieee80211 header must be
@@ -397,62 +733,83 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
/*
* Hardware might have stripped the IV/EIV/ICV data,
* in that case it is possible that the data was
- * provided seperately (through hardware descriptor)
+ * provided separately (through hardware descriptor)
* in which case we should reinsert the data into the frame.
*/
if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) &&
(rxdesc.flags & RX_FLAG_IV_STRIPPED))
rt2x00crypto_rx_insert_iv(entry->skb, header_length,
&rxdesc);
- else if (rxdesc.dev_flags & RXDONE_L2PAD)
+ else if (header_length &&
+ (rxdesc.size > header_length) &&
+ (rxdesc.dev_flags & RXDONE_L2PAD))
rt2x00queue_remove_l2pad(entry->skb, header_length);
- else
- rt2x00queue_align_payload(entry->skb, header_length);
+
+ /* Trim buffer to correct size */
+ skb_trim(entry->skb, rxdesc.size);
/*
- * Check if the frame was received using HT. In that case,
- * the rate is the MCS index and should be passed to mac80211
- * directly. Otherwise we need to translate the signal to
- * the correct bitrate index.
+ * Translate the signal to the correct bitrate index.
*/
- if (rxdesc.rate_mode == RATE_MODE_CCK ||
- rxdesc.rate_mode == RATE_MODE_OFDM) {
- rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc);
- } else {
+ rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc);
+ if (rxdesc.rate_mode == RATE_MODE_HT_MIX ||
+ rxdesc.rate_mode == RATE_MODE_HT_GREENFIELD)
rxdesc.flags |= RX_FLAG_HT;
- rate_idx = rxdesc.signal;
- }
+
+ /*
+ * Check if this is a beacon, and more frames have been
+ * buffered while we were in powersaving mode.
+ */
+ rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc);
+
+ /*
+ * Check for incoming BlockAcks to match to the BlockAckReqs
+ * we've send out.
+ */
+ rt2x00lib_rxdone_check_ba(rt2x00dev, entry->skb, &rxdesc);
/*
* Update extra components
*/
rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
rt2x00debug_update_crypto(rt2x00dev, &rxdesc);
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
+
+ /*
+ * Initialize RX status information, and send frame
+ * to mac80211.
+ */
+ rx_status = IEEE80211_SKB_RXCB(entry->skb);
+
+ /* Ensure that all fields of rx_status are initialized
+ * properly. The skb->cb array was used for driver
+ * specific informations, so rx_status might contain
+ * garbage.
+ */
+ memset(rx_status, 0, sizeof(*rx_status));
rx_status->mactime = rxdesc.timestamp;
+ rx_status->band = rt2x00dev->curr_band;
+ rx_status->freq = rt2x00dev->curr_freq;
rx_status->rate_idx = rate_idx;
rx_status->signal = rxdesc.rssi;
- rx_status->noise = rxdesc.noise;
rx_status->flag = rxdesc.flags;
rx_status->antenna = rt2x00dev->link.ant.active.rx;
- /*
- * Send frame to mac80211 & debugfs.
- * mac80211 will clean up the skb structure.
- */
- rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
- memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
- ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
+ ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
+renew_skb:
/*
* Replace the skb with the freshly allocated one.
*/
entry->skb = skb;
- entry->flags = 0;
- rt2x00dev->ops->lib->clear_entry(entry);
-
- rt2x00queue_index_inc(entry->queue, Q_INDEX);
+submit_entry:
+ entry->flags = 0;
+ rt2x00queue_index_inc(entry, 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);
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
@@ -550,7 +907,10 @@ static void rt2x00lib_channel(struct ieee80211_channel *entry,
const int channel, const int tx_power,
const int value)
{
- entry->center_freq = ieee80211_channel_to_frequency(channel);
+ /* XXX: this assumption about the band is wrong for 802.11j */
+ entry->band = channel <= 14 ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ entry->center_freq = ieee80211_channel_to_frequency(channel,
+ entry->band);
entry->hw_value = value;
entry->max_power = tx_power;
entry->max_antenna_gain = 0xff;
@@ -561,7 +921,7 @@ static void rt2x00lib_rate(struct ieee80211_rate *entry,
{
entry->flags = 0;
entry->bitrate = rate->bitrate;
- entry->hw_value =index;
+ entry->hw_value = index;
entry->hw_value_short = index;
if (rate->flags & DEV_RATE_SHORT_PREAMBLE)
@@ -583,11 +943,11 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
if (spec->supported_rates & SUPPORT_RATE_OFDM)
num_rates += 8;
- channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL);
+ channels = kcalloc(spec->num_channels, sizeof(*channels), GFP_KERNEL);
if (!channels)
return -ENOMEM;
- rates = kzalloc(sizeof(*rates) * num_rates, GFP_KERNEL);
+ rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL);
if (!rates)
goto exit_free_channels;
@@ -603,7 +963,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
for (i = 0; i < spec->num_channels; i++) {
rt2x00lib_channel(&channels[i],
spec->channels[i].channel,
- spec->channels_info[i].tx_power1, i);
+ spec->channels_info[i].max_power, i);
}
/*
@@ -644,7 +1004,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
exit_free_channels:
kfree(channels);
- ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n");
+ rt2x00_err(rt2x00dev, "Allocation ieee80211 modes failed\n");
return -ENOMEM;
}
@@ -686,7 +1046,64 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Initialize extra TX headroom required.
*/
- rt2x00dev->hw->extra_tx_headroom = rt2x00dev->ops->extra_tx_headroom;
+ rt2x00dev->hw->extra_tx_headroom =
+ max_t(unsigned int, IEEE80211_TX_STATUS_HEADROOM,
+ rt2x00dev->extra_tx_headroom);
+
+ /*
+ * Take TX headroom required for alignment into account.
+ */
+ if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags))
+ rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE;
+ else if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
+ rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE;
+
+ /*
+ * Tell mac80211 about the size of our private STA structure.
+ */
+ rt2x00dev->hw->sta_data_size = sizeof(struct rt2x00_sta);
+
+ /*
+ * Allocate tx status FIFO for driver use.
+ */
+ if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) {
+ /*
+ * Allocate the txstatus fifo. In the worst case the tx
+ * status fifo has to hold the tx status of all entries
+ * in all tx queues. Hence, calculate the kfifo size as
+ * tx_queues * entry_num and round up to the nearest
+ * power of 2.
+ */
+ int kfifo_size =
+ roundup_pow_of_two(rt2x00dev->ops->tx_queues *
+ rt2x00dev->tx->limit *
+ sizeof(u32));
+
+ status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size,
+ GFP_KERNEL);
+ if (status)
+ return status;
+ }
+
+ /*
+ * Initialize tasklets if used by the driver. Tasklets are
+ * disabled until the interrupts are turned on. The driver
+ * has to handle that.
+ */
+#define RT2X00_TASKLET_INIT(taskletname) \
+ if (rt2x00dev->ops->lib->taskletname) { \
+ tasklet_init(&rt2x00dev->taskletname, \
+ rt2x00dev->ops->lib->taskletname, \
+ (unsigned long)rt2x00dev); \
+ }
+
+ RT2X00_TASKLET_INIT(txstatus_tasklet);
+ RT2X00_TASKLET_INIT(pretbtt_tasklet);
+ RT2X00_TASKLET_INIT(tbtt_tasklet);
+ RT2X00_TASKLET_INIT(rxdone_tasklet);
+ RT2X00_TASKLET_INIT(autowake_tasklet);
+
+#undef RT2X00_TASKLET_INIT
/*
* Register HW.
@@ -709,9 +1126,10 @@ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
return;
/*
- * Unregister extra components.
+ * Stop rfkill polling.
*/
- rt2x00rfkill_unregister(rt2x00dev);
+ if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
+ rt2x00rfkill_unregister(rt2x00dev);
/*
* Allow the HW to uninitialize.
@@ -750,9 +1168,10 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags);
/*
- * Register the extra components.
+ * Start rfkill polling.
*/
- rt2x00rfkill_register(rt2x00dev);
+ if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
+ rt2x00rfkill_register(rt2x00dev);
return 0;
}
@@ -785,10 +1204,8 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
/* Enable the radio */
retval = rt2x00lib_enable_radio(rt2x00dev);
- if (retval) {
- rt2x00queue_uninitialize(rt2x00dev);
+ if (retval)
return retval;
- }
set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags);
@@ -811,6 +1228,51 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
rt2x00dev->intf_associated = 0;
}
+static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev)
+{
+ struct ieee80211_iface_limit *if_limit;
+ struct ieee80211_iface_combination *if_combination;
+
+ if (rt2x00dev->ops->max_ap_intf < 2)
+ return;
+
+ /*
+ * Build up AP interface limits structure.
+ */
+ if_limit = &rt2x00dev->if_limits_ap;
+ if_limit->max = rt2x00dev->ops->max_ap_intf;
+ if_limit->types = BIT(NL80211_IFTYPE_AP);
+#ifdef CONFIG_MAC80211_MESH
+ if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT);
+#endif
+
+ /*
+ * Build up AP interface combinations structure.
+ */
+ if_combination = &rt2x00dev->if_combinations[IF_COMB_AP];
+ if_combination->limits = if_limit;
+ if_combination->n_limits = 1;
+ if_combination->max_interfaces = if_limit->max;
+ if_combination->num_different_channels = 1;
+
+ /*
+ * Finally, specify the possible combinations to mac80211.
+ */
+ rt2x00dev->hw->wiphy->iface_combinations = rt2x00dev->if_combinations;
+ rt2x00dev->hw->wiphy->n_iface_combinations = 1;
+}
+
+static unsigned int rt2x00dev_extra_tx_headroom(struct rt2x00_dev *rt2x00dev)
+{
+ if (WARN_ON(!rt2x00dev->tx))
+ return 0;
+
+ if (rt2x00_is_usb(rt2x00dev))
+ return rt2x00dev->tx[0].winfo_size + rt2x00dev->tx[0].desc_size;
+
+ return rt2x00dev->tx[0].winfo_size;
+}
+
/*
* driver allocation handlers.
*/
@@ -818,7 +1280,27 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
{
int retval = -ENOMEM;
+ /*
+ * Set possible interface combinations.
+ */
+ rt2x00lib_set_if_combinations(rt2x00dev);
+
+ /*
+ * 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);
+ INIT_LIST_HEAD(&rt2x00dev->bar_list);
+ spin_lock_init(&rt2x00dev->bar_list_lock);
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
@@ -829,31 +1311,34 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf);
/*
- * Determine which operating modes are supported, all modes
- * which require beaconing, depend on the availability of
- * beacon entries.
+ * rt2x00 devices can only use the last n bits of the MAC address
+ * for virtual interfaces.
*/
- rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
- if (rt2x00dev->ops->bcn->entry_num > 0)
- rt2x00dev->hw->wiphy->interface_modes |=
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_MESH_POINT) |
- BIT(NL80211_IFTYPE_WDS);
+ rt2x00dev->hw->wiphy->addr_mask[ETH_ALEN - 1] =
+ (rt2x00dev->ops->max_ap_intf - 1);
/*
- * Let the driver probe the device to detect the capabilities.
+ * Initialize work.
*/
- retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev);
- if (retval) {
- ERROR(rt2x00dev, "Failed to allocate device.\n");
+ rt2x00dev->workqueue =
+ alloc_ordered_workqueue("%s", 0, wiphy_name(rt2x00dev->hw->wiphy));
+ if (!rt2x00dev->workqueue) {
+ retval = -ENOMEM;
goto exit;
}
+ INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
+ INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
+ INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
+
/*
- * Initialize configuration work.
+ * Let the driver probe the device to detect the capabilities.
*/
- INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
+ retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev);
+ if (retval) {
+ rt2x00_err(rt2x00dev, "Failed to allocate device\n");
+ goto exit;
+ }
/*
* Allocate queue array.
@@ -862,12 +1347,32 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
if (retval)
goto exit;
+ /* Cache TX headroom value */
+ rt2x00dev->extra_tx_headroom = rt2x00dev_extra_tx_headroom(rt2x00dev);
+
+ /*
+ * Determine which operating modes are supported, all modes
+ * which require beaconing, depend on the availability of
+ * beacon entries.
+ */
+ rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ if (rt2x00dev->bcn->limit > 0)
+ rt2x00dev->hw->wiphy->interface_modes |=
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+ BIT(NL80211_IFTYPE_WDS);
+
+ rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
/*
* Initialize ieee80211 structure.
*/
retval = rt2x00lib_probe_hw(rt2x00dev);
if (retval) {
- ERROR(rt2x00dev, "Failed to initialize hw.\n");
+ rt2x00_err(rt2x00dev, "Failed to initialize hw\n");
goto exit;
}
@@ -878,6 +1383,12 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
rt2x00leds_register(rt2x00dev);
rt2x00debug_register(rt2x00dev);
+ /*
+ * Start rfkill polling.
+ */
+ if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
+ rt2x00rfkill_register(rt2x00dev);
+
return 0;
exit:
@@ -892,6 +1403,12 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
/*
+ * Stop rfkill polling.
+ */
+ if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
+ rt2x00rfkill_unregister(rt2x00dev);
+
+ /*
* Disable radio.
*/
rt2x00lib_disable_radio(rt2x00dev);
@@ -900,6 +1417,29 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
* Stop all work.
*/
cancel_work_sync(&rt2x00dev->intf_work);
+ cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
+ cancel_work_sync(&rt2x00dev->sleep_work);
+ if (rt2x00_is_usb(rt2x00dev)) {
+ hrtimer_cancel(&rt2x00dev->txstatus_timer);
+ cancel_work_sync(&rt2x00dev->rxdone_work);
+ cancel_work_sync(&rt2x00dev->txdone_work);
+ }
+ if (rt2x00dev->workqueue)
+ destroy_workqueue(rt2x00dev->workqueue);
+
+ /*
+ * Free the tx status fifo.
+ */
+ kfifo_free(&rt2x00dev->txstatus_fifo);
+
+ /*
+ * Kill the tx status tasklet.
+ */
+ tasklet_kill(&rt2x00dev->txstatus_tasklet);
+ tasklet_kill(&rt2x00dev->pretbtt_tasklet);
+ tasklet_kill(&rt2x00dev->tbtt_tasklet);
+ tasklet_kill(&rt2x00dev->rxdone_tasklet);
+ tasklet_kill(&rt2x00dev->autowake_tasklet);
/*
* Uninitialize device.
@@ -926,6 +1466,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);
@@ -935,7 +1481,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
#ifdef CONFIG_PM
int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
{
- NOTICE(rt2x00dev, "Going to sleep.\n");
+ rt2x00_dbg(rt2x00dev, "Going to sleep\n");
/*
* Prevent mac80211 from accessing driver while suspended.
@@ -966,8 +1512,7 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
* device is as good as disabled.
*/
if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_SLEEP))
- WARNING(rt2x00dev, "Device failed to enter sleep state, "
- "continue suspending.\n");
+ rt2x00_warn(rt2x00dev, "Device failed to enter sleep state, continue suspending\n");
return 0;
}
@@ -975,7 +1520,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_suspend);
int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
{
- NOTICE(rt2x00dev, "Waking up.\n");
+ rt2x00_dbg(rt2x00dev, "Waking up\n");
/*
* Restore/enable extra components.