Merge branches 'core-fixes-for-linus' and 'irq-fixes-for-linus' of git://git.kernel...
[pandora-kernel.git] / drivers / net / wireless / mwifiex / wmm.c
index faa09e3..91634da 100644 (file)
@@ -177,14 +177,20 @@ static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv)
  * This function map ACs to TIDs.
  */
 static void
-mwifiex_wmm_queue_priorities_tid(u8 queue_priority[])
+mwifiex_wmm_queue_priorities_tid(struct mwifiex_wmm_desc *wmm)
 {
+       u8 *queue_priority = wmm->queue_priority;
        int i;
 
        for (i = 0; i < 4; ++i) {
                tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
                tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
        }
+
+       for (i = 0; i < MAX_NUM_TID; ++i)
+               tos_to_tid_inv[tos_to_tid[i]] = (u8)i;
+
+       atomic_set(&wmm->highest_queued_prio, HIGH_PRIO_TID);
 }
 
 /*
@@ -246,7 +252,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
                }
        }
 
-       mwifiex_wmm_queue_priorities_tid(priv->wmm.queue_priority);
+       mwifiex_wmm_queue_priorities_tid(&priv->wmm);
 }
 
 /*
@@ -399,6 +405,9 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
                priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
                priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
                priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
+
+               atomic_set(&priv->wmm.tx_pkts_queued, 0);
+               atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
        }
 }
 
@@ -408,17 +417,13 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
 int
 mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
 {
-       int i, j;
+       int i;
        struct mwifiex_private *priv;
 
-       for (j = 0; j < adapter->priv_num; ++j) {
-               priv = adapter->priv[j];
-               if (priv) {
-                       for (i = 0; i < MAX_NUM_TID; i++)
-                               if (!mwifiex_wmm_is_ra_list_empty(
-                                            &priv->wmm.tid_tbl_ptr[i].ra_list))
-                                       return false;
-               }
+       for (i = 0; i < adapter->priv_num; ++i) {
+               priv = adapter->priv[i];
+               if (priv && atomic_read(&priv->wmm.tx_pkts_queued))
+                               return false;
        }
 
        return true;
@@ -468,6 +473,9 @@ static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv)
        for (i = 0; i < MAX_NUM_TID; i++)
                mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].
                                                     ra_list);
+
+       atomic_set(&priv->wmm.tx_pkts_queued, 0);
+       atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
 }
 
 /*
@@ -638,6 +646,13 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
 
        ra_list->total_pkts_size += skb->len;
 
+       atomic_inc(&priv->wmm.tx_pkts_queued);
+
+       if (atomic_read(&priv->wmm.highest_queued_prio) <
+                                               tos_to_tid_inv[tid_down])
+               atomic_set(&priv->wmm.highest_queued_prio,
+                                               tos_to_tid_inv[tid_down]);
+
        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
 }
 
@@ -863,9 +878,14 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                }
 
                do {
+                       atomic_t *hqp;
+                       spinlock_t *lock;
+
                        priv_tmp = bssprio_node->priv;
+                       hqp = &priv_tmp->wmm.highest_queued_prio;
+                       lock = &priv_tmp->wmm.ra_list_spinlock;
 
-                       for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) {
+                       for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
 
                                tid_ptr = &(priv_tmp)->wmm.
                                        tid_tbl_ptr[tos_to_tid[i]];
@@ -903,6 +923,11 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                                        is_list_empty =
                                                skb_queue_empty(&ptr->skb_head);
                                        if (!is_list_empty) {
+                                               spin_lock_irqsave(lock, flags);
+                                               if (atomic_read(hqp) > i)
+                                                       atomic_set(hqp, i);
+                                               spin_unlock_irqrestore(lock,
+                                                                       flags);
                                                *priv = priv_tmp;
                                                *tid = tos_to_tid[i];
                                                return ptr;
@@ -921,6 +946,12 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                                } while (ptr != head);
                        }
 
+                       /* No packet at any TID for this priv. Mark as such
+                        * to skip checking TIDs for this priv (until pkt is
+                        * added).
+                        */
+                       atomic_set(hqp, NO_PKT_PRIO_TID);
+
                        /* Get next bss priority node */
                        bssprio_node = list_first_entry(&bssprio_node->list,
                                                struct mwifiex_bss_prio_node,
@@ -1028,6 +1059,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
                                .bss_prio_cur->list,
                                struct mwifiex_bss_prio_node,
                                list);
+               atomic_dec(&priv->wmm.tx_pkts_queued);
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
        }
@@ -1134,6 +1166,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
                                .bss_prio_cur->list,
                                struct mwifiex_bss_prio_node,
                                list);
+               atomic_dec(&priv->wmm.tx_pkts_queued);
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
        }
@@ -1227,5 +1260,5 @@ mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter)
 
                if (mwifiex_dequeue_tx_packet(adapter))
                        break;
-       } while (true);
+       } while (!mwifiex_wmm_lists_empty(adapter));
 }