ath10k: implement tx pause wmi event

qca6174 wmi-tlv firmware defines a new wmi event
for host tx pausing (i.e. stop/wake tx queues).

Map these events to ath10k/mac80211 tx queue
control.

This is important for multi-channel throughput
performance.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
Michal Kazior
2015-03-31 10:26:24 +00:00
committed by Kalle Valo
parent 96d828d45e
commit b4aa539dd8
4 changed files with 187 additions and 0 deletions

View File

@@ -28,6 +28,7 @@
#include "txrx.h"
#include "testmode.h"
#include "wmi.h"
#include "wmi-tlv.h"
#include "wmi-ops.h"
#include "wow.h"
@@ -2919,6 +2920,83 @@ void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason)
ieee80211_wake_queue(ar->hw, arvif->vdev_id);
}
static void ath10k_mac_vif_handle_tx_pause(struct ath10k_vif *arvif,
enum wmi_tlv_tx_pause_id pause_id,
enum wmi_tlv_tx_pause_action action)
{
struct ath10k *ar = arvif->ar;
lockdep_assert_held(&ar->htt.tx_lock);
switch (pause_id) {
case WMI_TLV_TX_PAUSE_ID_MCC:
case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA:
case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS:
case WMI_TLV_TX_PAUSE_ID_AP_PS:
case WMI_TLV_TX_PAUSE_ID_IBSS_PS:
switch (action) {
case WMI_TLV_TX_PAUSE_ACTION_STOP:
ath10k_mac_vif_tx_lock(arvif, pause_id);
break;
case WMI_TLV_TX_PAUSE_ACTION_WAKE:
ath10k_mac_vif_tx_unlock(arvif, pause_id);
break;
default:
ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n",
action, arvif->vdev_id);
break;
}
break;
case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS:
case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD:
case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA:
case WMI_TLV_TX_PAUSE_ID_HOST:
default:
/* FIXME: Some pause_ids aren't vdev specific. Instead they
* target peer_id and tid. Implementing these could improve
* traffic scheduling fairness across multiple connected
* stations in AP/IBSS modes.
*/
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac ignoring unsupported tx pause vdev %i id %d\n",
arvif->vdev_id, pause_id);
break;
}
}
struct ath10k_mac_tx_pause {
u32 vdev_id;
enum wmi_tlv_tx_pause_id pause_id;
enum wmi_tlv_tx_pause_action action;
};
static void ath10k_mac_handle_tx_pause_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct ath10k_mac_tx_pause *arg = data;
ath10k_mac_vif_handle_tx_pause(arvif, arg->pause_id, arg->action);
}
void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id,
enum wmi_tlv_tx_pause_id pause_id,
enum wmi_tlv_tx_pause_action action)
{
struct ath10k_mac_tx_pause arg = {
.vdev_id = vdev_id,
.pause_id = pause_id,
.action = action,
};
spin_lock_bh(&ar->htt.tx_lock);
ieee80211_iterate_active_interfaces_atomic(ar->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
ath10k_mac_handle_tx_pause_iter,
&arg);
spin_unlock_bh(&ar->htt.tx_lock);
}
static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
{
if (ieee80211_is_mgmt(hdr->frame_control))
@@ -4174,6 +4252,14 @@ err:
return ret;
}
static void ath10k_mac_vif_tx_unlock_all(struct ath10k_vif *arvif)
{
int i;
for (i = 0; i < BITS_PER_LONG; i++)
ath10k_mac_vif_tx_unlock(arvif, i);
}
static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -4240,6 +4326,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
}
spin_lock_bh(&ar->htt.tx_lock);
ath10k_mac_vif_tx_unlock_all(arvif);
spin_unlock_bh(&ar->htt.tx_lock);
mutex_unlock(&ar->conf_mutex);
}