From: Greg Kroah-Hartman Date: Wed, 5 Oct 2011 21:04:59 +0000 (-0700) Subject: 3.0 patches X-Git-Tag: v3.0.7~10 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1893af4b5725b9e8bda37278f657f4f708d9dba4;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0 patches --- diff --git a/queue-3.0/rt2x00-serialize-tx-operations-on-a-queue.patch b/queue-3.0/rt2x00-serialize-tx-operations-on-a-queue.patch new file mode 100644 index 00000000000..a842c58045e --- /dev/null +++ b/queue-3.0/rt2x00-serialize-tx-operations-on-a-queue.patch @@ -0,0 +1,118 @@ +From 77a861c405da75d81e9e6e32c50eb7f9777777e8 Mon Sep 17 00:00:00 2001 +From: Gertjan van Wingerde +Date: Wed, 6 Jul 2011 22:56:24 +0200 +Subject: rt2x00: Serialize TX operations on a queue. + +From: Gertjan van Wingerde + +commit 77a861c405da75d81e9e6e32c50eb7f9777777e8 upstream. + +The rt2x00 driver gets frequent occurrences of the following error message +when operating under load: +phy0 -> rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the +non-full queue 2. + +This is caused by simultaneous attempts from mac80211 to send a frame via +rt2x00, which are not properly serialized inside rt2x00queue_write_tx_frame, +causing the second frame to fail sending with the above mentioned error +message. + +Fix this by introducing a per-queue spinlock to serialize the TX operations +on that queue. + +Reported-by: Andreas Hartmann +Signed-off-by: Gertjan van Wingerde +Acked-by: Helmut Schaa +Signed-off-by: Ivo van Doorn +Signed-off-by: John W. Linville +Cc: Tim Gardner +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/rt2x00/rt2x00queue.c | 21 ++++++++++++++++----- + drivers/net/wireless/rt2x00/rt2x00queue.h | 2 ++ + 2 files changed, 18 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2x00queue.c ++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c +@@ -556,15 +556,21 @@ int rt2x00queue_write_tx_frame(struct da + 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; ++ int ret = 0; ++ ++ spin_lock(&queue->tx_lock); ++ ++ entry = rt2x00queue_get_entry(queue, Q_INDEX); + + if (unlikely(rt2x00queue_full(queue))) { + ERROR(queue->rt2x00dev, + "Dropping frame due to full tx queue %d.\n", queue->qid); +- return -ENOBUFS; ++ ret = -ENOBUFS; ++ goto out; + } + + if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, +@@ -573,7 +579,8 @@ int rt2x00queue_write_tx_frame(struct da + "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; + } + + /* +@@ -635,7 +642,8 @@ int rt2x00queue_write_tx_frame(struct da + 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 +652,9 @@ int rt2x00queue_write_tx_frame(struct da + 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, +@@ -1185,6 +1195,7 @@ static void rt2x00queue_init(struct rt2x + 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; +--- 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/queue-3.0/series b/queue-3.0/series index 1592d3ddb5a..dbcf9bbdcf7 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -17,3 +17,4 @@ drm-radeon-kms-fix-regression-in-dp-aux-defer-handling.patch drm-radeon-kms-add-retry-limits-for-native-dp-aux-defer.patch drm-radeon-kms-fix-channel_remap-setup-v2.patch ptp-fix-l2-event-message-recognition.patch +rt2x00-serialize-tx-operations-on-a-queue.patch