From patchwork Tue Apr 23 02:37:31 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Lamparter X-Patchwork-Id: 2475231 Return-Path: X-Original-To: patchwork-linux-wireless@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 60C863FCA5 for ; Tue, 23 Apr 2013 02:37:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753839Ab3DWChk (ORCPT ); Mon, 22 Apr 2013 22:37:40 -0400 Received: from mail-bk0-f46.google.com ([209.85.214.46]:36547 "EHLO mail-bk0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753826Ab3DWChj (ORCPT ); Mon, 22 Apr 2013 22:37:39 -0400 Received: by mail-bk0-f46.google.com with SMTP id je9so46594bkc.33 for ; Mon, 22 Apr 2013 19:37:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=x-received:subject:to:cc:from:date:mime-version:content-type :content-transfer-encoding:message-id; bh=+ajw+PbJMqd8BtWi3QWnzSB/nUDxYQCbkeWEzpfcpEM=; b=wn0Ta6U6TQqOh4UxQQMpHUrN+syg29iGnc4fe4EdK5Qj3GG+YG+EuXbbdbMOyEKxhk qh/lPSOxJnNxyi4U2AHPj/BaDE/sB/jtEZRXcWJCxWFqv7ARnU/+AnNwC2FL2TMVFnH0 hpmPjbRc5OypRWWBT/L82RDORcSs4dxXU8DYCISlYN6GJvpsG3sIWlAo8Wk/XctCAfal knGfm+QTvKMHy5ptJlsMmGzwWxY3UmJPLjnuKBOZZo3bAweuywjv/zBsDeefibXsgL7q Hx1OziUHV9RnjomnJ5fMka9J9hewy99eRVrXeVw4atk//bxxCmF9cQJ7MbvlJqfsKoBN /wpw== X-Received: by 10.204.165.140 with SMTP id i12mr12112918bky.128.1366684657267; Mon, 22 Apr 2013 19:37:37 -0700 (PDT) Received: from blech.mobile (f053210179.adsl.alicedsl.de. [78.53.210.179]) by mx.google.com with ESMTPS id io13sm7418086bkc.15.2013.04.22.19.37.34 (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 22 Apr 2013 19:37:35 -0700 (PDT) Received: from localhost (localhost [127.0.0.1]) by blech.mobile (Postfix) with ESMTP id 88E001003E2; Tue, 23 Apr 2013 04:37:33 +0200 (CEST) Received: from blech.mobile ([127.0.0.1]) by localhost (localhost [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id d4lVm5z0rqfk; Tue, 23 Apr 2013 04:37:32 +0200 (CEST) Received: from blech.localnet (localhost [127.0.0.1]) by blech.mobile (Postfix) with ESMTP id 3C26B10035F; Tue, 23 Apr 2013 04:37:32 +0200 (CEST) Subject: [RFC/RFT] carl9170: add support for the new rate control API To: linux-wireless@vger.kernel.org Cc: linville@tuxdriver.com From: Christian Lamparter Date: Tue, 23 Apr 2013 04:37:31 +0200 MIME-Version: 1.0 Message-Id: <201304230437.31850.chunkeey@googlemail.com> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org With the new rate control API, the driver can now apply the tx rate to outgoing frames just before they are uploaded to the device. This is important because the rate control now reacts to fading or improving link conditions "much" faster. Signed-off-by: Christian Lamparter --- Hello, It's been a while since I had the chance to write something even remotely useful. So, let's see if this feature works as intended. Then again, having some actual throughput/latency numbers would be nice. So, if someone has an AR9170 device and can verify or falsify the "claims" I made, I would like to hear from you ;-). Regards, Christian --- drivers/net/wireless/ath/carl9170/main.c | 1 + drivers/net/wireless/ath/carl9170/tx.c | 218 ++++++++++++++++++------------ 2 files changed, 135 insertions(+), 84 deletions(-) diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index e9010a4..df16c6e 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1857,6 +1857,7 @@ void *carl9170_alloc(size_t priv_size) IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | + IEEE80211_HW_SUPPORTS_RC_TABLE | IEEE80211_HW_SIGNAL_DBM; if (!modparam_noht) { diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index c61cafa..5a3b19e 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -105,12 +105,10 @@ static void carl9170_tx_accounting(struct ar9170 *ar, struct sk_buff *skb) } /* needs rcu_read_lock */ -static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar, +static struct ieee80211_vif *__carl9170_get_tx_vif(struct ar9170 *ar, struct sk_buff *skb) { struct _carl9170_tx_superframe *super = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) super->frame_data; - struct ieee80211_vif *vif; unsigned int vif_id; vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> @@ -119,12 +117,18 @@ static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar, if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) return NULL; - vif = rcu_dereference(ar->vif_priv[vif_id].vif); - if (unlikely(!vif)) - return NULL; + return rcu_dereference(ar->vif_priv[vif_id].vif); +} - /* - * Normally we should use wrappers like ieee80211_get_DA to get +/* needs rcu_read_lock */ +static struct ieee80211_sta *___carl9170_get_tx_sta(struct ar9170 *ar, + struct ieee80211_vif *vif, + struct sk_buff *skb) +{ + struct _carl9170_tx_superframe *super = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) super->frame_data; + + /* Normally we should use wrappers like ieee80211_get_DA to get * the correct peer ieee80211_sta. * * But there is a problem with indirect traffic (broadcasts, or @@ -136,6 +140,18 @@ static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar, return ieee80211_find_sta(vif, hdr->addr1); } +/* needs rcu_read_lock */ +static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar, + struct sk_buff *skb) +{ + struct ieee80211_vif *vif = __carl9170_get_tx_vif(ar, skb); + + if (unlikely(!vif)) + return NULL; + + return ___carl9170_get_tx_sta(ar, vif, skb); +} + static void carl9170_tx_ps_unblock(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_sta *sta; @@ -866,6 +882,97 @@ static bool carl9170_tx_cts_check(struct ar9170 *ar, return false; } +static void carl9170_tx_rateset(struct ar9170 *ar, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; + struct ieee80211_vif *vif; + struct ieee80211_sta *sta; + + BUILD_BUG_ON(IEEE80211_TX_MAX_RATES < CARL9170_TX_MAX_RATES); + BUILD_BUG_ON(IEEE80211_TX_MAX_RATES > IEEE80211_TX_RATE_TABLE_SIZE); + + info = IEEE80211_SKB_CB(skb); + + rcu_read_lock(); + vif = __carl9170_get_tx_vif(ar, skb); + sta = ___carl9170_get_tx_sta(ar, vif, skb); + ieee80211_get_tx_rates(vif, sta, skb, + info->control.rates, + IEEE80211_TX_MAX_RATES); + rcu_read_unlock(); +} + +static void carl9170_tx_apply_rateset(struct ar9170 *ar, + struct ieee80211_tx_info *sinfo, + struct sk_buff *skb) +{ + struct ieee80211_tx_rate *txrate; + struct ieee80211_tx_info *info; + struct _carl9170_tx_superframe *txc = (void *) skb->data; + int i; + bool ampdu; + bool no_ack; + + info = IEEE80211_SKB_CB(skb); + ampdu = !!(info->flags & IEEE80211_TX_CTL_AMPDU); + no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK); + + /* Set the rate control probe flag for all (sub-) frames. + * This is because the TX_STATS_AMPDU flag is only set on + * the last frame, so it has to be inherited. + */ + info->flags |= (sinfo->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); + + /* NOTE: For the first rate, the ERP & AMPDU flags are directly + * taken from mac_control. For all fallback rate, the firmware + * updates the mac_control flags from the rate info field. + */ + for (i = 0; i < CARL9170_TX_MAX_RATES; i++) { + __le32 phy_set; + + txrate = &sinfo->control.rates[i]; + if (txrate->idx < 0) + break; + + phy_set = carl9170_tx_physet(ar, info, txrate); + if (i == 0) { + __le16 mac_tmp = cpu_to_le16(0); + + /* first rate - part of the hw's frame header */ + txc->f.phy_control = phy_set; + + if (ampdu && txrate->flags & IEEE80211_TX_RC_MCS) + mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR); + + if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack)) + mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); + else if (carl9170_tx_cts_check(ar, txrate)) + mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); + + txc->f.mac_control |= mac_tmp; + } else { + /* fallback rates are stored in the firmware's + * retry rate set array. + */ + txc->s.rr[i - 1] = phy_set; + } + + SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[i], + txrate->count); + + if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack)) + txc->s.ri[i] |= (AR9170_TX_MAC_PROT_RTS << + CARL9170_TX_SUPER_RI_ERP_PROT_S); + else if (carl9170_tx_cts_check(ar, txrate)) + txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS << + CARL9170_TX_SUPER_RI_ERP_PROT_S); + + if (ampdu && (txrate->flags & IEEE80211_TX_RC_MCS)) + txc->s.ri[i] |= CARL9170_TX_SUPER_RI_AMPDU; + } +} + static int carl9170_tx_prepare(struct ar9170 *ar, struct ieee80211_sta *sta, struct sk_buff *skb) @@ -874,13 +981,10 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct _carl9170_tx_superframe *txc; struct carl9170_vif_info *cvif; struct ieee80211_tx_info *info; - struct ieee80211_tx_rate *txrate; struct carl9170_tx_info *arinfo; unsigned int hw_queue; - int i; __le16 mac_tmp; u16 len; - bool ampdu, no_ack; BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); BUILD_BUG_ON(sizeof(struct _carl9170_tx_superdesc) != @@ -889,8 +993,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar, BUILD_BUG_ON(sizeof(struct _ar9170_tx_hwdesc) != AR9170_TX_HWDESC_LEN); - BUILD_BUG_ON(IEEE80211_TX_MAX_RATES < CARL9170_TX_MAX_RATES); - BUILD_BUG_ON(AR9170_MAX_VIRTUAL_MAC > ((CARL9170_TX_SUPER_MISC_VIF_ID >> CARL9170_TX_SUPER_MISC_VIF_ID_S) + 1)); @@ -932,8 +1034,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar, mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) & AR9170_TX_MAC_QOS); - no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK); - if (unlikely(no_ack)) + if (unlikely(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_tmp |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); if (info->control.hw_key) { @@ -954,8 +1055,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar, } } - ampdu = !!(info->flags & IEEE80211_TX_CTL_AMPDU); - if (ampdu) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { unsigned int density, factor; if (unlikely(!sta || !cvif)) @@ -982,50 +1082,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar, txc->s.ampdu_settings, factor); } - /* - * NOTE: For the first rate, the ERP & AMPDU flags are directly - * taken from mac_control. For all fallback rate, the firmware - * updates the mac_control flags from the rate info field. - */ - for (i = 0; i < CARL9170_TX_MAX_RATES; i++) { - __le32 phy_set; - txrate = &info->control.rates[i]; - if (txrate->idx < 0) - break; - - phy_set = carl9170_tx_physet(ar, info, txrate); - if (i == 0) { - /* first rate - part of the hw's frame header */ - txc->f.phy_control = phy_set; - - if (ampdu && txrate->flags & IEEE80211_TX_RC_MCS) - mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR); - if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack)) - mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); - else if (carl9170_tx_cts_check(ar, txrate)) - mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); - - } else { - /* fallback rates are stored in the firmware's - * retry rate set array. - */ - txc->s.rr[i - 1] = phy_set; - } - - SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[i], - txrate->count); - - if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack)) - txc->s.ri[i] |= (AR9170_TX_MAC_PROT_RTS << - CARL9170_TX_SUPER_RI_ERP_PROT_S); - else if (carl9170_tx_cts_check(ar, txrate)) - txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS << - CARL9170_TX_SUPER_RI_ERP_PROT_S); - - if (ampdu && (txrate->flags & IEEE80211_TX_RC_MCS)) - txc->s.ri[i] |= CARL9170_TX_SUPER_RI_AMPDU; - } - txc->s.len = cpu_to_le16(skb->len); txc->f.length = cpu_to_le16(len + FCS_LEN); txc->f.mac_control = mac_tmp; @@ -1086,24 +1142,23 @@ static void carl9170_set_ampdu_params(struct ar9170 *ar, struct sk_buff *skb) } } -static bool carl9170_tx_rate_check(struct ar9170 *ar, struct sk_buff *_dest, - struct sk_buff *_src) +static void carl9170_set_rates(struct ar9170 *ar, struct sk_buff_head *queue) { - struct _carl9170_tx_superframe *dest, *src; + struct sk_buff *skb; + struct ieee80211_tx_info *info; - dest = (void *) _dest->data; - src = (void *) _src->data; + skb = skb_peek(queue); + carl9170_tx_rateset(ar, skb); + info = IEEE80211_SKB_CB(skb); - /* - * The mac80211 rate control algorithm expects that all MPDUs in - * an AMPDU share the same tx vectors. - * This is not really obvious right now, because the hardware - * does the AMPDU setup according to its own rulebook. - * Our nicely assembled, strictly monotonic increasing mpdu - * chains will be broken up, mashed back together... - */ + /* apply ampdu spacing & factor settings */ + carl9170_set_ampdu_params(ar, skb); + + skb_queue_walk(queue, skb) + carl9170_tx_apply_rateset(ar, info, skb); - return (dest->f.phy_control == src->f.phy_control); + /* set aggregation push bit */ + carl9170_set_immba(ar, skb_peek_tail(queue)); } static void carl9170_tx_ampdu(struct ar9170 *ar) @@ -1166,9 +1221,6 @@ retry: (tid_info->max - 1))) break; - if (!carl9170_tx_rate_check(ar, skb, first)) - break; - atomic_inc(&ar->tx_ampdu_upload); tid_info->snx = seq = SEQ_NEXT(seq); __skb_unlink(skb, &tid_info->queue); @@ -1197,11 +1249,8 @@ processed: if (skb_queue_empty(&agg)) continue; - /* apply ampdu spacing & factor settings */ - carl9170_set_ampdu_params(ar, skb_peek(&agg)); - - /* set aggregation push bit */ - carl9170_set_immba(ar, skb_peek_tail(&agg)); + /* set rate */ + carl9170_set_rates(ar, &agg); spin_lock_bh(&ar->tx_pending[queue].lock); skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]); @@ -1485,7 +1534,8 @@ void carl9170_op_tx(struct ieee80211_hw *hw, } else { unsigned int queue = skb_get_queue_mapping(skb); - + carl9170_tx_rateset(ar, skb); + carl9170_tx_apply_rateset(ar, info, skb); skb_queue_tail(&ar->tx_pending[queue], skb); }