diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-22 14:43:13 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-22 14:43:13 -0700 | 
| commit | 951cc93a7493a81a47e20231441bc6cf17c98a37 (patch) | |
| tree | f53934f0f225e0215a85c8c59af4c6513e89e3f1 /drivers/net/wireless/rt2x00/rt2x00queue.c | |
| parent | a7e1aabb28e8154ce987b622fd78d80a1ca39361 (diff) | |
| parent | 415b3334a21aa67806c52d1acf4e72e14f7f402f (diff) | |
| download | olio-linux-3.10-951cc93a7493a81a47e20231441bc6cf17c98a37.tar.xz olio-linux-3.10-951cc93a7493a81a47e20231441bc6cf17c98a37.zip  | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1287 commits)
  icmp: Fix regression in nexthop resolution during replies.
  net: Fix ppc64 BPF JIT dependencies.
  acenic: include NET_SKB_PAD headroom to incoming skbs
  ixgbe: convert to ndo_fix_features
  ixgbe: only enable WoL for magic packet by default
  ixgbe: remove ifdef check for non-existent define
  ixgbe: Pass staterr instead of re-reading status and error bits from descriptor
  ixgbe: Move interrupt related values out of ring and into q_vector
  ixgbe: add structure for containing RX/TX rings to q_vector
  ixgbe: inline the ixgbe_maybe_stop_tx function
  ixgbe: Update ATR to use recorded TX queues instead of CPU for routing
  igb: Fix for DH89xxCC near end loopback test
  e1000: always call e1000_check_for_link() on e1000_ce4100 MACs.
  netxen: add fw version compatibility check
  be2net: request native mode each time the card is reset
  ipv4: Constrain UFO fragment sizes to multiples of 8 bytes
  virtio_net: Fix panic in virtnet_remove
  ipv6: make fragment identifications less predictable
  ipv6: unshare inetpeers
  can: make function can_get_bittiming static
  ...
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00queue.c')
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 113 | 
1 files changed, 64 insertions, 49 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index ab8c16f8bca..29edb9fbe6f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -200,20 +200,20 @@ 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); -	unsigned long irqflags;  	if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))  		return;  	__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;  	/* @@ -227,23 +227,23 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,  	 * sequence counting per-frame, since those will override the  	 * sequence counter given by mac80211.  	 */ -	spin_lock_irqsave(&intf->seqlock, irqflags); +	spin_lock(&intf->seqlock);  	if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))  		intf->seqno += 0x10;  	hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);  	hdr->seq_ctrl |= cpu_to_le16(intf->seqno); -	spin_unlock_irqrestore(&intf->seqlock, irqflags); +	spin_unlock(&intf->seqlock);  } -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; @@ -260,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 @@ -302,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 = @@ -381,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; @@ -396,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. @@ -472,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, @@ -556,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, @@ -594,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; @@ -623,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 @@ -635,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); @@ -644,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, @@ -698,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 @@ -1185,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;  |