diff options
| author | Ivo van Doorn <ivdoorn@gmail.com> | 2010-12-13 12:35:40 +0100 | 
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2010-12-13 15:23:35 -0500 | 
| commit | 5be65609fec2e331c7d804471be3d59089a30d98 (patch) | |
| tree | 6c6967c7835d6ec3a8ce79c2c9b84bf95aefca31 /drivers/net/wireless/rt2x00/rt2x00queue.c | |
| parent | 0b7fde54f94979edc67bbf86b5adba702ebfefe8 (diff) | |
| download | olio-linux-3.10-5be65609fec2e331c7d804471be3d59089a30d98.tar.xz olio-linux-3.10-5be65609fec2e331c7d804471be3d59089a30d98.zip  | |
rt2x00: Add "flush" queue command
Add a new command to the queue handlers: "flush",
this moves the flush() callback from mac80211
into rt2x00queue and adds support for flushing
the RX queue as well.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Helmut Schaa <helmut.schaa@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00queue.c')
| -rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 85 | 
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 558965fb41b..313a8faa5fa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -780,6 +780,12 @@ void rt2x00queue_unpause_queue(struct data_queue *queue)  		 */  		ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);  		break; +	case QID_RX: +		/* +		 * For RX we need to kick the queue now in order to +		 * receive frames. +		 */ +		queue->rt2x00dev->ops->lib->kick_queue(queue);  	default:  		break;  	} @@ -823,6 +829,74 @@ void rt2x00queue_stop_queue(struct data_queue *queue)  }  EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue); +void rt2x00queue_flush_queue(struct data_queue *queue, bool drop) +{ +	unsigned int i; +	bool started; +	bool tx_queue = +		(queue->qid == QID_AC_BE) || +		(queue->qid == QID_AC_BK) || +		(queue->qid == QID_AC_VI) || +		(queue->qid == QID_AC_VO); + +	mutex_lock(&queue->status_lock); + +	/* +	 * If the queue has been started, we must stop it temporarily +	 * to prevent any new frames to be queued on the device. If +	 * we are not dropping the pending frames, the queue must +	 * only be stopped in the software and not the hardware, +	 * otherwise the queue will never become empty on its own. +	 */ +	started = test_bit(QUEUE_STARTED, &queue->flags); +	if (started) { +		/* +		 * Pause the queue +		 */ +		rt2x00queue_pause_queue(queue); + +		/* +		 * If we are not supposed to drop any pending +		 * frames, this means we must force a start (=kick) +		 * to the queue to make sure the hardware will +		 * start transmitting. +		 */ +		if (!drop && tx_queue) +			queue->rt2x00dev->ops->lib->kick_queue(queue); +	} + +	/* +	 * Check if driver supports flushing, we can only guarentee +	 * full support for flushing if the driver is able +	 * to cancel all pending frames (drop = true). +	 */ +	if (drop && queue->rt2x00dev->ops->lib->flush_queue) +		queue->rt2x00dev->ops->lib->flush_queue(queue); + +	/* +	 * When we don't want to drop any frames, or when +	 * the driver doesn't fully flush the queue correcly, +	 * we must wait for the queue to become empty. +	 */ +	for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++) +		msleep(10); + +	/* +	 * The queue flush has failed... +	 */ +	if (unlikely(!rt2x00queue_empty(queue))) +		WARNING(queue->rt2x00dev, "Queue %d failed to flush", queue->qid); + +	/* +	 * Restore the queue to the previous status +	 */ +	if (started) +		rt2x00queue_unpause_queue(queue); + +	mutex_unlock(&queue->status_lock); +} +EXPORT_SYMBOL_GPL(rt2x00queue_flush_queue); +  void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev)  {  	struct data_queue *queue; @@ -857,6 +931,17 @@ void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)  }  EXPORT_SYMBOL_GPL(rt2x00queue_stop_queues); +void rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop) +{ +	struct data_queue *queue; + +	tx_queue_for_each(rt2x00dev, queue) +		rt2x00queue_flush_queue(queue, drop); + +	rt2x00queue_flush_queue(rt2x00dev->rx, drop); +} +EXPORT_SYMBOL_GPL(rt2x00queue_flush_queues); +  static void rt2x00queue_reset(struct data_queue *queue)  {  	unsigned long irqflags;  |