diff options
Diffstat (limited to 'drivers/net/wireless/p54')
| -rw-r--r-- | drivers/net/wireless/p54/p54common.c | 51 | ||||
| -rw-r--r-- | drivers/net/wireless/p54/p54spi.c | 2 | 
2 files changed, 31 insertions, 22 deletions
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index b618bd14583..22ca122bd79 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -823,30 +823,30 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)  	struct p54_tx_info *range;  	unsigned long flags; -	if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue))) +	if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))  		return; -	/* There used to be a check here to see if the SKB was on the -	 * TX queue or not.  This can never happen because all SKBs we -	 * see here successfully went through p54_assign_address() -	 * which means the SKB is on the ->tx_queue. +	/* +	 * don't try to free an already unlinked skb  	 */ +	if (unlikely((!skb->next) || (!skb->prev))) +		return;  	spin_lock_irqsave(&priv->tx_queue.lock, flags);  	info = IEEE80211_SKB_CB(skb);  	range = (void *)info->rate_driver_data; -	if (!skb_queue_is_first(&priv->tx_queue, skb)) { +	if (skb->prev != (struct sk_buff *)&priv->tx_queue) {  		struct ieee80211_tx_info *ni;  		struct p54_tx_info *mr; -		ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb)); +		ni = IEEE80211_SKB_CB(skb->prev);  		mr = (struct p54_tx_info *)ni->rate_driver_data;  	} -	if (!skb_queue_is_last(&priv->tx_queue, skb)) { +	if (skb->next != (struct sk_buff *)&priv->tx_queue) {  		struct ieee80211_tx_info *ni;  		struct p54_tx_info *mr; -		ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb)); +		ni = IEEE80211_SKB_CB(skb->next);  		mr = (struct p54_tx_info *)ni->rate_driver_data;  	}  	__skb_unlink(skb, &priv->tx_queue); @@ -864,13 +864,15 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,  	unsigned long flags;  	spin_lock_irqsave(&priv->tx_queue.lock, flags); -	skb_queue_walk(&priv->tx_queue, entry) { +	entry = priv->tx_queue.next; +	while (entry != (struct sk_buff *)&priv->tx_queue) {  		struct p54_hdr *hdr = (struct p54_hdr *) entry->data;  		if (hdr->req_id == req_id) {  			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);  			return entry;  		} +		entry = entry->next;  	}  	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);  	return NULL; @@ -888,33 +890,36 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)  	int count, idx;  	spin_lock_irqsave(&priv->tx_queue.lock, flags); -	skb_queue_walk(&priv->tx_queue, entry) { +	entry = (struct sk_buff *) priv->tx_queue.next; +	while (entry != (struct sk_buff *)&priv->tx_queue) {  		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);  		struct p54_hdr *entry_hdr;  		struct p54_tx_data *entry_data;  		unsigned int pad = 0, frame_len;  		range = (void *)info->rate_driver_data; -		if (range->start_addr != addr) +		if (range->start_addr != addr) { +			entry = entry->next;  			continue; +		} -		if (!skb_queue_is_last(&priv->tx_queue, entry)) { +		if (entry->next != (struct sk_buff *)&priv->tx_queue) {  			struct ieee80211_tx_info *ni;  			struct p54_tx_info *mr; -			ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, -							     entry)); +			ni = IEEE80211_SKB_CB(entry->next);  			mr = (struct p54_tx_info *)ni->rate_driver_data;  		}  		__skb_unlink(entry, &priv->tx_queue); -		spin_unlock_irqrestore(&priv->tx_queue.lock, flags);  		frame_len = entry->len;  		entry_hdr = (struct p54_hdr *) entry->data;  		entry_data = (struct p54_tx_data *) entry_hdr->data; -		priv->tx_stats[entry_data->hw_queue].len--; +		if (priv->tx_stats[entry_data->hw_queue].len) +			priv->tx_stats[entry_data->hw_queue].len--;  		priv->stats.dot11ACKFailureCount += payload->tries - 1; +		spin_unlock_irqrestore(&priv->tx_queue.lock, flags);  		/*  		 * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are @@ -1164,21 +1169,23 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,  		}  	} -	skb_queue_walk(&priv->tx_queue, entry) { +	entry = priv->tx_queue.next; +	while (left--) {  		u32 hole_size;  		info = IEEE80211_SKB_CB(entry);  		range = (void *)info->rate_driver_data;  		hole_size = range->start_addr - last_addr;  		if (!target_skb && hole_size >= len) { -			target_skb = skb_queue_prev(&priv->tx_queue, entry); +			target_skb = entry->prev;  			hole_size -= len;  			target_addr = last_addr;  		}  		largest_hole = max(largest_hole, hole_size);  		last_addr = range->end_addr; +		entry = entry->next;  	}  	if (!target_skb && priv->rx_end - last_addr >= len) { -		target_skb = skb_peek_tail(&priv->tx_queue); +		target_skb = priv->tx_queue.prev;  		largest_hole = max(largest_hole, priv->rx_end - last_addr - len);  		if (!skb_queue_empty(&priv->tx_queue)) {  			info = IEEE80211_SKB_CB(target_skb); @@ -2084,6 +2091,7 @@ out:  static void p54_stop(struct ieee80211_hw *dev)  {  	struct p54_common *priv = dev->priv; +	struct sk_buff *skb;  	mutex_lock(&priv->conf_mutex);  	priv->mode = NL80211_IFTYPE_UNSPECIFIED; @@ -2098,7 +2106,8 @@ static void p54_stop(struct ieee80211_hw *dev)  		p54_tx_cancel(dev, priv->cached_beacon);  	priv->stop(dev); -	skb_queue_purge(&priv->tx_queue); +	while ((skb = skb_dequeue(&priv->tx_queue))) +		kfree_skb(skb);  	priv->cached_beacon = NULL;  	priv->tsf_high32 = priv->tsf_low32 = 0;  	mutex_unlock(&priv->conf_mutex); diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 83116baeb11..72c7dbd39d0 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -635,7 +635,7 @@ static int __devinit p54spi_probe(struct spi_device *spi)  	hw = p54_init_common(sizeof(*priv));  	if (!hw) { -		dev_err(&priv->spi->dev, "could not alloc ieee80211_hw"); +		dev_err(&spi->dev, "could not alloc ieee80211_hw");  		return -ENOMEM;  	}  |