Skip to content

Commit

Permalink
carl9170: add support for the new rate control API
Browse files Browse the repository at this point in the history
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 can
now react to fading or improving links a bit sooner.

Also, the driver no longer needs to sort the outgoing frames
for sample attempts (which affected the size of A-MPDUs and
the throughput of the link). For aggregated data frames, the
driver (and rate control) needs only to calculate and apply
a single set of tx rates to every subframe of the whole
aggregate.

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Christian Lamparter authored and John W. Linville committed Jun 13, 2013
1 parent 6ea81c4 commit 9ad86ed
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 78 deletions.
3 changes: 3 additions & 0 deletions drivers/net/wireless/ath/carl9170/carl9170.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ struct carl9170_sta_tid {

/* Preaggregation reorder queue */
struct sk_buff_head queue;

struct ieee80211_sta *sta;
struct ieee80211_vif *vif;
};

#define CARL9170_QUEUE_TIMEOUT 256
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/ath/carl9170/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,8 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
tid_info->state = CARL9170_TID_STATE_PROGRESS;
tid_info->tid = tid;
tid_info->max = sta_info->ampdu_max_len;
tid_info->sta = sta;
tid_info->vif = vif;

INIT_LIST_HEAD(&tid_info->list);
INIT_LIST_HEAD(&tid_info->tmp_list);
Expand Down Expand Up @@ -1857,6 +1859,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) {
Expand Down
182 changes: 104 additions & 78 deletions drivers/net/wireless/ath/carl9170/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar)
msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT)))
goto unlock;

sta = __carl9170_get_tx_sta(ar, skb);
sta = iter->sta;
if (WARN_ON(!sta))
goto unlock;

Expand Down Expand Up @@ -866,6 +866,93 @@ static bool carl9170_tx_cts_check(struct ar9170 *ar,
return false;
}

static void carl9170_tx_get_rates(struct ar9170 *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct sk_buff *skb)
{
struct ieee80211_tx_info *info;

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);

ieee80211_get_tx_rates(vif, sta, skb,
info->control.rates,
IEEE80211_TX_MAX_RATES);
}

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)
Expand All @@ -874,13 +961,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) !=
Expand All @@ -889,8 +973,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));
Expand Down Expand Up @@ -932,8 +1014,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) {
Expand All @@ -954,8 +1035,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))
Expand All @@ -982,50 +1062,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;
Expand Down Expand Up @@ -1086,31 +1122,12 @@ 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)
{
struct _carl9170_tx_superframe *dest, *src;

dest = (void *) _dest->data;
src = (void *) _src->data;

/*
* 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...
*/

return (dest->f.phy_control == src->f.phy_control);
}

static void carl9170_tx_ampdu(struct ar9170 *ar)
{
struct sk_buff_head agg;
struct carl9170_sta_tid *tid_info;
struct sk_buff *skb, *first;
struct ieee80211_tx_info *tx_info_first;
unsigned int i = 0, done_ampdus = 0;
u16 seq, queue, tmpssn;

Expand Down Expand Up @@ -1156,6 +1173,7 @@ static void carl9170_tx_ampdu(struct ar9170 *ar)
goto processed;
}

tx_info_first = NULL;
while ((skb = skb_peek(&tid_info->queue))) {
/* strict 0, 1, ..., n - 1, n frame sequence order */
if (unlikely(carl9170_get_seq(skb) != seq))
Expand All @@ -1166,8 +1184,13 @@ static void carl9170_tx_ampdu(struct ar9170 *ar)
(tid_info->max - 1)))
break;

if (!carl9170_tx_rate_check(ar, skb, first))
break;
if (!tx_info_first) {
carl9170_tx_get_rates(ar, tid_info->vif,
tid_info->sta, first);
tx_info_first = IEEE80211_SKB_CB(first);
}

carl9170_tx_apply_rateset(ar, tx_info_first, skb);

atomic_inc(&ar->tx_ampdu_upload);
tid_info->snx = seq = SEQ_NEXT(seq);
Expand All @@ -1182,8 +1205,7 @@ static void carl9170_tx_ampdu(struct ar9170 *ar)
if (skb_queue_empty(&tid_info->queue) ||
carl9170_get_seq(skb_peek(&tid_info->queue)) !=
tid_info->snx) {
/*
* stop TID, if A-MPDU frames are still missing,
/* stop TID, if A-MPDU frames are still missing,
* or whenever the queue is empty.
*/

Expand Down Expand Up @@ -1450,12 +1472,14 @@ void carl9170_op_tx(struct ieee80211_hw *hw,
struct ar9170 *ar = hw->priv;
struct ieee80211_tx_info *info;
struct ieee80211_sta *sta = control->sta;
struct ieee80211_vif *vif;
bool run;

if (unlikely(!IS_STARTED(ar)))
goto err_free;

info = IEEE80211_SKB_CB(skb);
vif = info->control.vif;

if (unlikely(carl9170_tx_prepare(ar, sta, skb)))
goto err_free;
Expand Down Expand Up @@ -1486,6 +1510,8 @@ void carl9170_op_tx(struct ieee80211_hw *hw,
} else {
unsigned int queue = skb_get_queue_mapping(skb);

carl9170_tx_get_rates(ar, vif, sta, skb);
carl9170_tx_apply_rateset(ar, info, skb);
skb_queue_tail(&ar->tx_pending[queue], skb);
}

Expand Down

0 comments on commit 9ad86ed

Please sign in to comment.