summaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSara Sharon <sara.sharon@intel.com>2016-02-18 14:21:12 +0200
committerLuca Coelho <luciano.coelho@intel.com>2016-05-10 22:14:39 +0300
commit0636b938214c90c3a7d145ad86b64a061bb10c50 (patch)
treeea2d1714050c6405dc257869b62ead904e822906 /drivers/net
parente5ed17929bf4177c523465af187ab70c9a454caa (diff)
downloadlinux-0636b938214c90c3a7d145ad86b64a061bb10c50.tar.gz
linux-0636b938214c90c3a7d145ad86b64a061bb10c50.tar.bz2
linux-0636b938214c90c3a7d145ad86b64a061bb10c50.zip
iwlwifi: mvm: implement driver RX queues sync command
mac80211 will call the driver whenever there is a race between RSS queues and control path that requires a processing of all pending frames in RSS queues. Implement that by utilizing the internal notification mechanism: queue a message to all queues. When the message is received on a queue it decrements the atomic counter. This guarantees that all pending frames in the RX queue were processed since the message is in order inside the queue. Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c43
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c7
5 files changed, 58 insertions, 0 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
index 4c086d048097..ade170bd8683 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
@@ -437,9 +437,11 @@ struct iwl_rxq_sync_notification {
/**
* Internal message identifier
*
+* @IWL_MVM_RXQ_SYNC: sync RSS queues
* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
*/
enum iwl_mvm_rxq_notif_type {
+ IWL_MVM_RXQ_SYNC,
IWL_MVM_RXQ_NOTIF_DEL_BA,
};
@@ -448,10 +450,12 @@ enum iwl_mvm_rxq_notif_type {
* in &iwl_rxq_sync_cmd. Should be DWORD aligned.
*
* @type: value from &iwl_mvm_rxq_notif_type
+* @cookie: internal cookie to identify old notifications
* @data: payload
*/
struct iwl_mvm_internal_rxq_notif {
u32 type;
+ u32 cookie;
u8 data[];
} __packed;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 5ace468070cb..d6ad77a2c767 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -4037,6 +4037,47 @@ static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw,
}
}
+static void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm)
+{
+ struct iwl_mvm_internal_rxq_notif data = {
+ .type = IWL_MVM_RXQ_SYNC,
+ .cookie = mvm->queue_sync_cookie,
+ };
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(notif_waitq);
+ u32 qmask = BIT(mvm->trans->num_rx_queues) - 1;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (!iwl_mvm_has_new_rx_api(mvm))
+ return;
+
+ atomic_set(&mvm->queue_sync_counter, mvm->trans->num_rx_queues);
+
+ ret = iwl_mvm_notify_rx_queue(mvm, qmask, (u8 *)&data, sizeof(data));
+ if (ret) {
+ IWL_ERR(mvm, "Failed to trigger RX queues sync (%d)\n", ret);
+ goto out;
+ }
+ ret = wait_event_timeout(notif_waitq,
+ atomic_read(&mvm->queue_sync_counter) == 0,
+ HZ);
+ WARN_ON_ONCE(!ret);
+
+out:
+ atomic_set(&mvm->queue_sync_counter, 0);
+ mvm->queue_sync_cookie++;
+}
+
+static void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_sync_rx_queues_internal(mvm);
+ mutex_unlock(&mvm->mutex);
+}
+
const struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
.ampdu_action = iwl_mvm_mac_ampdu_action,
@@ -4093,6 +4134,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.event_callback = iwl_mvm_mac_event_callback,
+ .sync_rx_queues = iwl_mvm_sync_rx_queues,
+
CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd)
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 85800ba0c667..c7c8a6205eaa 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -633,6 +633,8 @@ struct iwl_mvm {
unsigned long status;
+ u32 queue_sync_cookie;
+ atomic_t queue_sync_counter;
/*
* for beacon filtering -
* currently only one interface can be supported
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 8bfb8e06a90c..7c6a5984105f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -586,6 +586,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
skb_queue_head_init(&mvm->d0i3_tx);
init_waitqueue_head(&mvm->d0i3_exit_waitq);
+ atomic_set(&mvm->queue_sync_counter, 0);
+
SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev);
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 651604d18a32..b4d9c42d411a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -406,6 +406,13 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
internal_notif = (void *)notif->payload;
switch (internal_notif->type) {
+ case IWL_MVM_RXQ_SYNC:
+ if (mvm->queue_sync_cookie == internal_notif->cookie)
+ atomic_dec(&mvm->queue_sync_counter);
+ else
+ WARN_ONCE(1,
+ "Received expired RX queue sync message\n");
+ break;
case IWL_MVM_RXQ_NOTIF_DEL_BA:
/* TODO */
break;