Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5eb7efe8 authored by Ivo van Doorn's avatar Ivo van Doorn Committed by John W. Linville
Browse files

rt2x00: Move direct access to queue->entries to rt2x00queue.c



All access to queue->entries through the Q_INDEX/Q_INDEX_DONE
variables must be done using spinlock protection. It is best
to manage this completely from rt2x00queue.c.

For safely looping through all entries in the queue, the function
rt2x00queue_for_each_entry is added which will walk from from a index
range in a safe manner.

This also fixes rt2x00usb which walked the entries list from
0 to length to kill each entry (killing entries must be done
from Q_INDEX_DONE to Q_INDEX to enforce TX status reporting to
occur in the correct order.

Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Acked-by: default avatarGertjan van Wingerde <gwingerde@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ee1e755f
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -629,7 +629,7 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry,
static void rt2800pci_kick_tx_queue(struct data_queue *queue)
static void rt2800pci_kick_tx_queue(struct data_queue *queue)
{
{
	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
	unsigned int idx = queue->index[Q_INDEX];
	struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
	unsigned int qidx = 0;
	unsigned int qidx = 0;


	if (queue->qid == QID_MGMT)
	if (queue->qid == QID_MGMT)
@@ -637,7 +637,7 @@ static void rt2800pci_kick_tx_queue(struct data_queue *queue)
	else
	else
		qidx = queue->qid;
		qidx = queue->qid;


	rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
	rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx);
}
}


static void rt2800pci_kill_tx_queue(struct data_queue *queue)
static void rt2800pci_kill_tx_queue(struct data_queue *queue)
+45 −0
Original line number Original line Diff line number Diff line
@@ -625,6 +625,51 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
	return 0;
	return 0;
}
}


void rt2x00queue_for_each_entry(struct data_queue *queue,
				enum queue_index start,
				enum queue_index end,
				void (*fn)(struct queue_entry *entry))
{
	unsigned long irqflags;
	unsigned int index_start;
	unsigned int index_end;
	unsigned int i;

	if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) {
		ERROR(queue->rt2x00dev,
		      "Entry requested from invalid index range (%d - %d)\n",
		      start, end);
		return;
	}

	/*
	 * Only protect the range we are going to loop over,
	 * if during our loop a extra entry is set to pending
	 * it should not be kicked during this run, since it
	 * is part of another TX operation.
	 */
	spin_lock_irqsave(&queue->lock, irqflags);
	index_start = queue->index[start];
	index_end = queue->index[end];
	spin_unlock_irqrestore(&queue->lock, irqflags);

	/*
	 * Start from the TX done pointer, this guarentees that we will
	 * send out all frames in the correct order.
	 */
	if (index_start < index_end) {
		for (i = index_start; i < index_end; i++)
			fn(&queue->entries[i]);
	} else {
		for (i = index_start; i < queue->limit; i++)
			fn(&queue->entries[i]);

		for (i = 0; i < index_end; i++)
			fn(&queue->entries[i]);
	}
}
EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry);

struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
					 const enum data_queue_qid queue)
					 const enum data_queue_qid queue)
{
{
+16 −0
Original line number Original line Diff line number Diff line
@@ -570,6 +570,22 @@ struct data_queue_desc {
#define txall_queue_for_each(__dev, __entry) \
#define txall_queue_for_each(__dev, __entry) \
	queue_loop(__entry, (__dev)->tx, queue_end(__dev))
	queue_loop(__entry, (__dev)->tx, queue_end(__dev))


/**
 * rt2x00queue_for_each_entry - Loop through all entries in the queue
 * @queue: Pointer to @data_queue
 * @start: &enum queue_index Pointer to start index
 * @end: &enum queue_index Pointer to end index
 * @fn: The function to call for each &struct queue_entry
 *
 * This will walk through all entries in the queue, in chronological
 * order. This means it will start at the current @start pointer
 * and will walk through the queue until it reaches the @end pointer.
 */
void rt2x00queue_for_each_entry(struct data_queue *queue,
				enum queue_index start,
				enum queue_index end,
				void (*fn)(struct queue_entry *entry));

/**
/**
 * rt2x00queue_empty - Check if the queue is empty.
 * rt2x00queue_empty - Check if the queue is empty.
 * @queue: Queue to check if empty.
 * @queue: Queue to check if empty.
+20 −55
Original line number Original line Diff line number Diff line
@@ -225,7 +225,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
	ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
	ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
}
}


static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
{
{
	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
	struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
@@ -252,69 +252,34 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)


void rt2x00usb_kick_tx_queue(struct data_queue *queue)
void rt2x00usb_kick_tx_queue(struct data_queue *queue)
{
{
	unsigned long irqflags;
	rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
	unsigned int index;
				   rt2x00usb_kick_tx_entry);
	unsigned int index_done;
	unsigned int i;

	/*
	 * Only protect the range we are going to loop over,
	 * if during our loop a extra entry is set to pending
	 * 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
	 * send out all frames in the correct order.
	 */
	if (index_done < index) {
		for (i = index_done; i < index; i++)
			rt2x00usb_kick_tx_entry(&queue->entries[i]);
	} else {
		for (i = index_done; i < queue->limit; i++)
			rt2x00usb_kick_tx_entry(&queue->entries[i]);

		for (i = 0; i < index; i++)
			rt2x00usb_kick_tx_entry(&queue->entries[i]);
	}
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);


void rt2x00usb_kill_tx_queue(struct data_queue *queue)
static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
{
{
	struct queue_entry_priv_usb *entry_priv;
	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
	struct queue_entry_priv_usb_bcn *bcn_priv;
	struct queue_entry_priv_usb *entry_priv = entry->priv_data;
	unsigned int i;
	struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
	bool kill_guard;


	/*
	if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
	 * When killing the beacon queue, we must also kill
		return;
	 * the beacon guard byte.
	 */
	kill_guard =
	    (queue->qid == QID_BEACON) &&
	    (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &queue->rt2x00dev->flags));


	/*
	 * Cancel all entries.
	 */
	for (i = 0; i < queue->limit; i++) {
		entry_priv = queue->entries[i].priv_data;
	usb_kill_urb(entry_priv->urb);
	usb_kill_urb(entry_priv->urb);


	/*
	/*
	 * Kill guardian urb (if required by driver).
	 * Kill guardian urb (if required by driver).
	 */
	 */
		if (kill_guard) {
	if ((entry->queue->qid == QID_BEACON) &&
			bcn_priv = queue->entries[i].priv_data;
	    (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
		usb_kill_urb(bcn_priv->guardian_urb);
		usb_kill_urb(bcn_priv->guardian_urb);
}
}
	}

void rt2x00usb_kill_tx_queue(struct data_queue *queue)
{
	rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
				   rt2x00usb_kill_tx_entry);
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);