diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2400pci.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500pci.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500usb.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800pci.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800usb.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00crypto.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00lib.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00mac.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 108 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt61pci.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt73usb.c | 1 |
13 files changed, 94 insertions, 52 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 937f9e8..76bcc354 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1723,6 +1723,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index d27d7b8..c288d95 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -2016,6 +2016,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 15237c2..53c5f87 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1827,6 +1827,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 9ccc537..ebc17ad 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1031,6 +1031,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = { .flush = rt2x00mac_flush, .get_survey = rt2800_get_survey, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2800_ops rt2800pci_rt2800_ops = { @@ -1160,6 +1161,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { #endif #ifdef CONFIG_RT2800PCI_RT53XX { PCI_DEVICE(0x1814, 0x5390) }, + { PCI_DEVICE(0x1814, 0x539f) }, #endif { 0, } }; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 6e92298..59e7779 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -757,6 +757,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .flush = rt2x00mac_flush, .get_survey = rt2800_get_survey, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2800_ops rt2800usb_rt2800_ops = { @@ -1020,6 +1021,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x0048) }, { USB_DEVICE(0x0df6, 0x0051) }, { USB_DEVICE(0x0df6, 0x005f) }, + { USB_DEVICE(0x0df6, 0x0060) }, /* SMC */ { USB_DEVICE(0x083a, 0x6618) }, { USB_DEVICE(0x083a, 0x7511) }, @@ -1076,6 +1078,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x148f, 0x3572) }, /* Sitecom */ { USB_DEVICE(0x0df6, 0x0041) }, + { USB_DEVICE(0x0df6, 0x0062) }, /* Toshiba */ { USB_DEVICE(0x0930, 0x0a07) }, /* Zinwell */ @@ -1174,8 +1177,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x004a) }, { USB_DEVICE(0x0df6, 0x004d) }, { USB_DEVICE(0x0df6, 0x0053) }, - { USB_DEVICE(0x0df6, 0x0060) }, - { USB_DEVICE(0x0df6, 0x0062) }, /* SMC */ { USB_DEVICE(0x083a, 0xa512) }, { USB_DEVICE(0x083a, 0xc522) }, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 4efaf886..f82bfeb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1277,6 +1277,7 @@ int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); +bool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw); /* * Driver allocation handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 1bb9d46..1ca4c7f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -45,11 +45,11 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) } } -void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, +void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc) { - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key) diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 322cc4f..15cdc7e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -336,7 +336,8 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, */ #ifdef CONFIG_RT2X00_LIB_CRYPTO enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key); -void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, +void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc); unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 93bec14..8efab39 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -818,3 +818,17 @@ void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, *rx_max = rt2x00dev->rx->limit; } EXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam); + +bool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + + tx_queue_for_each(rt2x00dev, queue) { + if (!rt2x00queue_empty(queue)) + return true; + } + + return false; +} +EXPORT_SYMBOL_GPL(rt2x00mac_tx_frames_pending); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index c7fc9de..29edb9f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -200,11 +200,12 @@ void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length) skb_pull(skb, l2pad); } -static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, +static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc) { - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif); if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) @@ -212,7 +213,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); - if (!test_bit(REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->cap_flags)) + if (!test_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags)) return; /* @@ -237,12 +238,12 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, } -static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, +static void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc, const struct rt2x00_rate *hwrate) { - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; unsigned int data_length; unsigned int duration; @@ -259,8 +260,8 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, txdesc->u.plcp.ifs = IFS_SIFS; /* Data length + CRC + Crypto overhead (IV/EIV/ICV/MIC) */ - data_length = entry->skb->len + 4; - data_length += rt2x00crypto_tx_overhead(rt2x00dev, entry->skb); + data_length = skb->len + 4; + data_length += rt2x00crypto_tx_overhead(rt2x00dev, skb); /* * PLCP setup @@ -301,13 +302,14 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, } } -static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry, +static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc, const struct rt2x00_rate *hwrate) { - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (tx_info->control.sta) txdesc->u.ht.mpdu_density = @@ -380,12 +382,12 @@ static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry, txdesc->u.ht.txop = TXOP_HTTXOP; } -static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, +static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc) { - struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; struct ieee80211_rate *rate; const struct rt2x00_rate *hwrate = NULL; @@ -395,8 +397,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Header and frame information. */ - txdesc->length = entry->skb->len; - txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb); + txdesc->length = skb->len; + txdesc->header_length = ieee80211_get_hdrlen_from_skb(skb); /* * Check whether this frame is to be acked. @@ -471,13 +473,15 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Apply TX descriptor handling by components */ - rt2x00crypto_create_tx_descriptor(entry, txdesc); - rt2x00queue_create_tx_descriptor_seq(entry, txdesc); + rt2x00crypto_create_tx_descriptor(rt2x00dev, skb, txdesc); + rt2x00queue_create_tx_descriptor_seq(rt2x00dev, skb, txdesc); if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) - rt2x00queue_create_tx_descriptor_ht(entry, txdesc, hwrate); + rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc, + hwrate); else - rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); + rt2x00queue_create_tx_descriptor_plcp(rt2x00dev, skb, txdesc, + hwrate); } static int rt2x00queue_write_tx_data(struct queue_entry *entry, @@ -555,33 +559,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, bool local) { struct ieee80211_tx_info *tx_info; - struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); + struct queue_entry *entry; struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; u8 rate_idx, rate_flags; - - if (unlikely(rt2x00queue_full(queue))) { - ERROR(queue->rt2x00dev, - "Dropping frame due to full tx queue %d.\n", queue->qid); - return -ENOBUFS; - } - - if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, - &entry->flags))) { - ERROR(queue->rt2x00dev, - "Arrived at non-free entry in the non-full queue %d.\n" - "Please file bug report to %s.\n", - queue->qid, DRV_PROJECT); - return -EINVAL; - } + int ret = 0; /* * Copy all TX descriptor information into txdesc, * after that we are free to use the skb->cb array * for our information. */ - entry->skb = skb; - rt2x00queue_create_tx_descriptor(entry, &txdesc); + rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc); /* * All information is retrieved from the skb->cb array, @@ -593,7 +582,6 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, rate_flags = tx_info->control.rates[0].flags; skbdesc = get_skb_frame_desc(skb); memset(skbdesc, 0, sizeof(*skbdesc)); - skbdesc->entry = entry; skbdesc->tx_rate_idx = rate_idx; skbdesc->tx_rate_flags = rate_flags; @@ -622,9 +610,33 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, * for PCI devices. */ if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags)) - rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length); + rt2x00queue_insert_l2pad(skb, txdesc.header_length); else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags)) - rt2x00queue_align_frame(entry->skb); + rt2x00queue_align_frame(skb); + + spin_lock(&queue->tx_lock); + + if (unlikely(rt2x00queue_full(queue))) { + ERROR(queue->rt2x00dev, + "Dropping frame due to full tx queue %d.\n", queue->qid); + ret = -ENOBUFS; + goto out; + } + + entry = rt2x00queue_get_entry(queue, Q_INDEX); + + if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, + &entry->flags))) { + ERROR(queue->rt2x00dev, + "Arrived at non-free entry in the non-full queue %d.\n" + "Please file bug report to %s.\n", + queue->qid, DRV_PROJECT); + ret = -EINVAL; + goto out; + } + + skbdesc->entry = entry; + entry->skb = skb; /* * It could be possible that the queue was corrupted and this @@ -634,7 +646,8 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) { clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); entry->skb = NULL; - return -EIO; + ret = -EIO; + goto out; } set_bit(ENTRY_DATA_PENDING, &entry->flags); @@ -643,7 +656,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, rt2x00queue_write_tx_descriptor(entry, &txdesc); rt2x00queue_kick_tx_queue(queue, &txdesc); - return 0; +out: + spin_unlock(&queue->tx_lock); + return ret; } int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev, @@ -697,7 +712,7 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, * after that we are free to use the skb->cb array * for our information. */ - rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc); + rt2x00queue_create_tx_descriptor(rt2x00dev, intf->beacon->skb, &txdesc); /* * Fill in skb descriptor @@ -1184,6 +1199,7 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, struct data_queue *queue, enum data_queue_qid qid) { mutex_init(&queue->status_lock); + spin_lock_init(&queue->tx_lock); spin_lock_init(&queue->index_lock); queue->rt2x00dev = rt2x00dev; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 5900474..f2100f4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -432,6 +432,7 @@ enum data_queue_flags { * @flags: Entry flags, see &enum queue_entry_flags. * @status_lock: The mutex for protecting the start/stop/flush * handling on this queue. + * @tx_lock: Spinlock to serialize tx operations on this queue. * @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or * @index_crypt needs to be changed this lock should be grabbed to prevent * index corruption due to concurrency. @@ -458,6 +459,7 @@ struct data_queue { unsigned long flags; struct mutex status_lock; + spinlock_t tx_lock; spinlock_t index_lock; unsigned int count; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 9d35ec1..53110b8 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2982,6 +2982,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ad20953..6a93939 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2314,6 +2314,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .set_antenna = rt2x00mac_set_antenna, .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, + .tx_frames_pending = rt2x00mac_tx_frames_pending, }; static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { |