@@ -566,7 +566,7 @@ void rt2800mmio_queue_init(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- queue->limit = 128;
+ queue->limit = 512;
queue->data_size = AGGREGATION_SIZE;
queue->desc_size = RXD_DESC_SIZE;
queue->winfo_size = rxwi_size;
@@ -128,7 +128,8 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) {
mutex_lock(&intf->beacon_skb_mutex);
- rt2x00queue_update_beacon(rt2x00dev, vif);
+ if (intf->enable_beacon)
+ rt2x00queue_update_beacon(rt2x00dev, vif);
mutex_unlock(&intf->beacon_skb_mutex);
}
}
@@ -191,6 +192,7 @@ static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rt2x00_dev *rt2x00dev = data;
+ struct rt2x00_intf *intf = vif_to_intf(vif);
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_ADHOC &&
@@ -204,7 +206,8 @@ static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
* never be called for USB devices.
*/
WARN_ON(rt2x00_is_usb(rt2x00dev));
- rt2x00queue_update_beacon(rt2x00dev, vif);
+ if (intf->enable_beacon)
+ rt2x00queue_update_beacon(rt2x00dev, vif);
}
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
@@ -103,6 +103,25 @@ void rt2x00mac_tx(struct ieee80211_hw *hw,
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
goto exit_free_skb;
+ /* Dirty hack for queue overrun protection,
+ * if AC_VO/AC_VI/AC_BE is full, use next queue.
+ * if AC_BK is full use previous queue.
+ */
+ if (qid < 4) {
+ queue = rt2x00queue_get_tx_queue(rt2x00dev,qid);
+ if (unlikely(rt2x00queue_full(queue))) {
+ switch(qid) {
+ case 0: /* QID_AC_VO */
+ case 1: /* QID_AC_VI */
+ case 2: /* QID_AC_BE */
+ qid++;
+ break;
+ case 3: /* QID_AC_BK */
+ qid--;
+ break;
+ }
+ }
+ }
/*
* Use the ATIM queue if appropriate and present.
@@ -602,8 +621,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
* Upload beacon to the H/W. This is only required on
* USB devices. PCI devices fetch beacons periodically.
*/
- if (rt2x00_is_usb(rt2x00dev))
- rt2x00queue_update_beacon(rt2x00dev, vif);
+ rt2x00queue_update_beacon(rt2x00dev, vif);
if (rt2x00dev->intf_beaconing == 1) {
/*
@@ -986,25 +986,37 @@ void rt2x00queue_stop_queue(struct data_queue *queue)
void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
{
+ unsigned int i;
+ bool started;
bool tx_queue =
(queue->qid == QID_AC_VO) ||
(queue->qid == QID_AC_VI) ||
(queue->qid == QID_AC_BE) ||
(queue->qid == QID_AC_BK);
+ 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);
+ }
if (rt2x00queue_empty(queue))
return;
/*
- * 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, if that is the case we can
* defer the flushing to the driver. Otherwise we must use the
* alternative which just waits for the queue to become empty.
@@ -1013,11 +1025,25 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
queue->rt2x00dev->ops->lib->flush_queue(queue, drop);
/*
+ * 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 < 10; i++)
+ msleep(10);
+
+ /*
* The queue flush has failed...
*/
if (unlikely(!rt2x00queue_empty(queue)))
rt2x00_warn(queue->rt2x00dev, "Queue %d failed to flush\n",
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);
Added rt2x00 queue flush fix and beacon frames checks. Signed-off-by: Balakrishna Bandi <b.balakrishna@globaledgesoft.com> --- drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 7 ++-- drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 22 ++++++++++-- drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 44 +++++++++++++++++++----- 4 files changed, 61 insertions(+), 14 deletions(-)