From patchwork Sun Dec 6 13:40:30 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gertjan van Wingerde X-Patchwork-Id: 65154 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id nB6DegDa031394 for ; Sun, 6 Dec 2009 13:40:42 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751526AbZLFNk1 (ORCPT ); Sun, 6 Dec 2009 08:40:27 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751428AbZLFNk1 (ORCPT ); Sun, 6 Dec 2009 08:40:27 -0500 Received: from Cpsmtpm-eml108.kpnxchange.com ([195.121.3.12]:54018 "EHLO CPSMTPM-EML108.kpnxchange.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751371AbZLFNkZ (ORCPT ); Sun, 6 Dec 2009 08:40:25 -0500 Received: from wingerd.gvw.nl ([86.87.118.224]) by CPSMTPM-EML108.kpnxchange.com with Microsoft SMTPSVC(7.0.6001.18000); Sun, 6 Dec 2009 14:40:31 +0100 Received: from [127.0.0.1] (localhost [127.0.0.1]) by wingerd.gvw.nl (Postfix) with ESMTP id AC45F60162; Sun, 6 Dec 2009 14:40:30 +0100 (CET) Message-ID: <4B1BB44E.90706@gmail.com> Date: Sun, 06 Dec 2009 14:40:30 +0100 From: Gertjan van Wingerde User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.5) Gecko/20091205 Lightning/1.0pre Shredder/3.0 MIME-Version: 1.0 To: Andi Kleen , Tim Blechmann CC: rjw@sisk.pl, IvDoorn@gmail.com, linville@tuxdriver.com, linux-wireless@vger.kernel.org Subject: Re: regression: rt2561 frequent "Arrived at non-free entry" errors in 2.6.32 References: <20091204233202.GA13658@basil.fritz.box> In-Reply-To: <20091204233202.GA13658@basil.fritz.box> X-OriginalArrivalTime: 06 Dec 2009 13:40:31.0251 (UTC) FILETIME=[ADCD3E30:01CA7679] Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index e7f4640..6f10de1 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1193,6 +1193,9 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; + unsigned long irqflags; + + spin_lock_irqsave(&queue->lock, irqflags); while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); @@ -1222,6 +1225,8 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, rt2x00lib_txdone(entry, &txdesc); } + + spin_unlock_irqrestore(&queue->lock, irqflags); } static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 408fcfc..7e3a724 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1330,6 +1330,9 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry; struct txdone_entry_desc txdesc; u32 word; + unsigned long irqflags; + + spin_lock_irqsave(&queue->lock, irqflags); while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); @@ -1359,6 +1362,8 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, rt2x00lib_txdone(entry, &txdesc); } + + spin_unlock_irqrestore(&queue->lock, irqflags); } static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 801be43..60c0be5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -101,6 +101,9 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) struct queue_entry *entry; struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; + unsigned long irqflags; + + spin_lock_irqsave(&queue->lock, irqflags); while (1) { entry = rt2x00queue_get_entry(queue, Q_INDEX); @@ -121,6 +124,8 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) */ rt2x00lib_rxdone(rt2x00dev, entry); } + + spin_unlock_irqrestore(&queue->lock, irqflags); } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 3d8fb68..3577627 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -453,20 +453,29 @@ 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; + unsigned long irqflags; + int ret = 0; - if (unlikely(rt2x00queue_full(queue))) - return -ENOBUFS; + spin_lock_irqsave(&queue->lock, irqflags); + + entry = rt2x00queue_get_entry(queue, Q_INDEX); + + if (unlikely(rt2x00queue_full(queue))) { + ret = -ENOBUFS; + goto out; + } if (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; + ret = -EINVAL; + goto out; } /* @@ -528,7 +537,8 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); entry->skb = NULL; - return -EIO; + ret = -EIO; + goto out; } if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) @@ -539,6 +549,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, rt2x00queue_index_inc(queue, Q_INDEX); rt2x00queue_write_tx_descriptor(entry, &txdesc); +out: + spin_unlock_irqrestore(&queue->lock, irqflags); + return 0; } @@ -642,7 +655,6 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, enum queue_index index) { struct queue_entry *entry; - unsigned long irqflags; if (unlikely(index >= Q_INDEX_MAX)) { ERROR(queue->rt2x00dev, @@ -650,28 +662,20 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, return NULL; } - spin_lock_irqsave(&queue->lock, irqflags); - entry = &queue->entries[queue->index[index]]; - spin_unlock_irqrestore(&queue->lock, irqflags); - return entry; } EXPORT_SYMBOL_GPL(rt2x00queue_get_entry); void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) { - unsigned long irqflags; - if (unlikely(index >= Q_INDEX_MAX)) { ERROR(queue->rt2x00dev, "Index change on invalid index type (%d)\n", index); return; } - spin_lock_irqsave(&queue->lock, irqflags); - queue->index[index]++; if (queue->index[index] >= queue->limit) queue->index[index] = 0; @@ -682,8 +686,6 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) queue->length--; queue->count++; } - - spin_unlock_irqrestore(&queue->lock, irqflags); } static void rt2x00queue_reset(struct data_queue *queue) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 0a751e7..3b05a29 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -270,7 +270,6 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid qid) { struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid); - unsigned long irqflags; unsigned int index; unsigned int index_done; unsigned int i; @@ -281,10 +280,8 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, * it should not be kicked during this run, since it * is part of another TX operation. */ - spin_lock_irqsave(&queue->lock, irqflags); index = queue->index[Q_INDEX]; index_done = queue->index[Q_INDEX_DONE]; - spin_unlock_irqrestore(&queue->lock, irqflags); /* * Start from the TX done pointer, this guarentees that we will diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 687e17d..6ed29c8 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2037,6 +2037,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) u32 old_reg; int type; int index; + unsigned long irqflags; /* * During each loop we will compare the freshly read @@ -2074,13 +2075,17 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) if (unlikely(index >= queue->limit)) continue; + spin_lock_irqsave(&queue->lock, irqflags); + entry = &queue->entries[index]; entry_priv = entry->priv_data; rt2x00_desc_read(entry_priv->desc, 0, &word); if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || - !rt2x00_get_field32(word, TXD_W0_VALID)) + !rt2x00_get_field32(word, TXD_W0_VALID)) { + spin_unlock_irqrestore(&queue->lock, irqflags); return; + } entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); while (entry != entry_done) { @@ -2116,6 +2121,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); rt2x00lib_txdone(entry, &txdesc); + + spin_unlock_irqrestore(&queue->lock, irqflags); } }