summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
diff options
context:
space:
mode:
authorSara Sharon <sara.sharon@intel.com>2016-03-23 16:32:02 +0200
committerLuca Coelho <luciano.coelho@intel.com>2016-05-10 22:14:42 +0300
commitb915c10174fb7df533b7928046129c8f626cca42 (patch)
tree49aac88d328859f845f1826a1ef0938071d56999 /drivers/net/wireless/intel/iwlwifi/mvm/sta.c
parent2dd493434db68f89c690a665e3ac3dad11b69134 (diff)
downloadblackbird-obmc-linux-b915c10174fb7df533b7928046129c8f626cca42.tar.gz
blackbird-obmc-linux-b915c10174fb7df533b7928046129c8f626cca42.zip
iwlwifi: mvm: add reorder buffer per queue
Next hardware will direct packets to core based on the TCP/UDP streams. This logic can create holes in reorder buffer since packets that belong to other stream were directed to a different core. However, those are valid holes and the packets can be indicated in L3 order. The hardware will utilize a mechanism of informing the driver of the normalized ssn and the driver shall release all packets that SN is lower than the nssn. This enables managing the reorder across the queues without sharing any data between them. The reorder buffer is allocated and released directly in the RX path in order to avoid various races between control path and rx path. The code utilizes the internal messaging to notify rx queues of when to delete the reorder buffer. Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/sta.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c69
1 files changed, 61 insertions, 8 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 4fb4c4e4923d..2b839114a60f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1167,14 +1167,63 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
#define IWL_MAX_RX_BA_SESSIONS 16
-static void iwl_mvm_sync_rxq_del_ba(struct iwl_mvm *mvm)
+static void iwl_mvm_sync_rxq_del_ba(struct iwl_mvm *mvm, u8 baid)
{
- struct iwl_mvm_internal_rxq_notif data = {
- .type = IWL_MVM_RXQ_EMPTY,
- .sync = 1,
+ struct iwl_mvm_delba_notif notif = {
+ .metadata.type = IWL_MVM_RXQ_NOTIF_DEL_BA,
+ .metadata.sync = 1,
+ .delba.baid = baid,
};
+ iwl_mvm_sync_rx_queues_internal(mvm, (void *)&notif, sizeof(notif));
+};
+
+static void iwl_mvm_free_reorder(struct iwl_mvm *mvm,
+ struct iwl_mvm_baid_data *data)
+{
+ int i;
+
+ iwl_mvm_sync_rxq_del_ba(mvm, data->baid);
+
+ for (i = 0; i < mvm->trans->num_rx_queues; i++) {
+ int j;
+ struct iwl_mvm_reorder_buffer *reorder_buf =
+ &data->reorder_buf[i];
- iwl_mvm_sync_rx_queues_internal(mvm, &data, sizeof(data));
+ if (likely(!reorder_buf->num_stored))
+ continue;
+
+ /*
+ * This shouldn't happen in regular DELBA since the internal
+ * delBA notification should trigger a release of all frames in
+ * the reorder buffer.
+ */
+ WARN_ON(1);
+
+ for (j = 0; j < reorder_buf->buf_size; j++)
+ __skb_queue_purge(&reorder_buf->entries[j]);
+ }
+}
+
+static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm,
+ u32 sta_id,
+ struct iwl_mvm_baid_data *data,
+ u16 ssn, u8 buf_size)
+{
+ int i;
+
+ for (i = 0; i < mvm->trans->num_rx_queues; i++) {
+ struct iwl_mvm_reorder_buffer *reorder_buf =
+ &data->reorder_buf[i];
+ int j;
+
+ reorder_buf->num_stored = 0;
+ reorder_buf->head_sn = ssn;
+ reorder_buf->buf_size = buf_size;
+ reorder_buf->queue = i;
+ reorder_buf->sta_id = sta_id;
+ for (j = 0; j < reorder_buf->buf_size; j++)
+ __skb_queue_head_init(&reorder_buf->entries[j]);
+ }
}
int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
@@ -1198,7 +1247,10 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
* Allocate here so if allocation fails we can bail out early
* before starting the BA session in the firmware
*/
- baid_data = kzalloc(sizeof(*baid_data), GFP_KERNEL);
+ baid_data = kzalloc(sizeof(*baid_data) +
+ mvm->trans->num_rx_queues *
+ sizeof(baid_data->reorder_buf[0]),
+ GFP_KERNEL);
if (!baid_data)
return -ENOMEM;
}
@@ -1273,6 +1325,8 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
mod_timer(&baid_data->session_timer,
TU_TO_EXP_TIME(timeout * 2));
+ iwl_mvm_init_reorder_buffer(mvm, mvm_sta->sta_id,
+ baid_data, ssn, buf_size);
/*
* protect the BA data with RCU to cover a case where our
* internal RX sync mechanism will timeout (not that it's
@@ -1297,9 +1351,8 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
return -EINVAL;
/* synchronize all rx queues so we can safely delete */
- iwl_mvm_sync_rxq_del_ba(mvm);
+ iwl_mvm_free_reorder(mvm, baid_data);
del_timer_sync(&baid_data->session_timer);
-
RCU_INIT_POINTER(mvm->baid_map[baid], NULL);
kfree_rcu(baid_data, rcu_head);
}
OpenPOWER on IntegriCloud