Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e6a9854b authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

mac80211/drivers: rewrite the rate control API



So after the previous changes we were still unhappy with how
convoluted the API is and decided to make things simpler for
everybody. This completely changes the rate control API, now
taking into account 802.11n with MCS rates and more control,
most drivers don't support that though.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent cb121bad
Loading
Loading
Loading
Loading
+11 −10
Original line number Diff line number Diff line
@@ -341,15 +341,14 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
		pci_unmap_single(priv->pdev, info->mapping,
				 info->skb->len, PCI_DMA_TODEVICE);

		memset(&txi->status, 0, sizeof(txi->status));
		ieee80211_tx_info_clear_status(txi);

		skb_pull(skb, sizeof(struct adm8211_tx_hdr));
		memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
		if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
			if (status & TDES0_STATUS_ES)
				txi->status.excessive_retries = 1;
			else
		if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) &&
		    !(status & TDES0_STATUS_ES))
			txi->flags |= IEEE80211_TX_STAT_ACK;
		}

		ieee80211_tx_status_irqsafe(dev, skb);

		info->skb = NULL;
@@ -1691,8 +1690,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
	struct ieee80211_hdr *hdr;
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);
	u8 rc_flags;

	short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
	rc_flags = info->control.rates[0].flags;
	short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
	plcp_signal = txrate->bitrate;

	hdr = (struct ieee80211_hdr *)skb->data;
@@ -1724,10 +1725,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
	if (short_preamble)
		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);

	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
	if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);

	txhdr->retry_limit = info->control.retry_limit;
	txhdr->retry_limit = info->control.rates[0].count;

	adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);

+15 −19
Original line number Diff line number Diff line
@@ -541,8 +541,8 @@ ath5k_pci_probe(struct pci_dev *pdev,

	/* set up multi-rate retry capabilities */
	if (sc->ah->ah_version == AR5K_AR5212) {
		hw->max_altrates = 3;
		hw->max_altrate_tries = 11;
		hw->max_rates = 4;
		hw->max_rate_tries = 11;
	}

	/* Finish private driver data initialization */
@@ -1181,7 +1181,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
		ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
		(sc->power_level * 2),
		ieee80211_get_tx_rate(sc->hw, info)->hw_value,
		info->control.retry_limit, keyidx, 0, flags, 0, 0);
		info->control.rates[0].count, keyidx, 0, flags, 0, 0);
	if (ret)
		goto err_unmap;

@@ -1193,7 +1193,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
			break;

		mrr_rate[i] = rate->hw_value;
		mrr_tries[i] = info->control.retries[i].limit;
		mrr_tries[i] = info->control.rates[i + 1].count;
	}

	ah->ah_setup_mrr_tx_desc(ah, ds,
@@ -1849,30 +1849,26 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
		pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
				PCI_DMA_TODEVICE);

		memset(&info->status, 0, sizeof(info->status));
		info->tx_rate_idx = ath5k_hw_to_driver_rix(sc,
				ts.ts_rate[ts.ts_final_idx]);
		info->status.retry_count = ts.ts_longretry;

		ieee80211_tx_info_clear_status(info);
		for (i = 0; i < 4; i++) {
			struct ieee80211_tx_altrate *r =
				&info->status.retries[i];
			struct ieee80211_tx_rate *r =
				&info->status.rates[i];

			if (ts.ts_rate[i]) {
				r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
				r->limit = ts.ts_retry[i];
				r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
				r->count = ts.ts_retry[i];
			} else {
				r->rate_idx = -1;
				r->limit = 0;
				r->idx = -1;
				r->count = 0;
			}
		}

		info->status.excessive_retries = 0;
		/* count the successful attempt as well */
		info->status.rates[ts.ts_final_idx].count++;

		if (unlikely(ts.ts_status)) {
			sc->ll_stats.dot11ACKFailureCount++;
			if (ts.ts_status & AR5K_TXERR_XRETRY)
				info->status.excessive_retries = 1;
			else if (ts.ts_status & AR5K_TXERR_FILT)
			if (ts.ts_status & AR5K_TXERR_FILT)
				info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
		} else {
			info->flags |= IEEE80211_TX_STAT_ACK;
+7 −11
Original line number Diff line number Diff line
@@ -457,12 +457,13 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
	DPRINTF(sc, ATH_DBG_XMIT,
		"%s: TX complete: skb: %p\n", __func__, skb);

	ieee80211_tx_info_clear_status(tx_info);
	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
		tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
		/* free driver's private data area of tx_info */
		if (tx_info->driver_data[0] != NULL)
			kfree(tx_info->driver_data[0]);
			tx_info->driver_data[0] = NULL;
		/* free driver's private data area of tx_info, XXX: HACK! */
		if (tx_info->control.vif != NULL)
			kfree(tx_info->control.vif);
			tx_info->control.vif = NULL;
	}

	if (tx_status->flags & ATH_TX_BAR) {
@@ -470,17 +471,12 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
		tx_status->flags &= ~ATH_TX_BAR;
	}

	if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
		if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
			/* Frame was not ACKed, but an ACK was expected */
			tx_info->status.excessive_retries = 1;
		}
	} else {
	if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
		/* Frame was ACKed */
		tx_info->flags |= IEEE80211_TX_STAT_ACK;
	}

	tx_info->status.retry_count = tx_status->retries;
	tx_info->status.rates[0].count = tx_status->retries + 1;

	ieee80211_tx_status(hw, skb);
	if (an)
+20 −20
Original line number Diff line number Diff line
@@ -1864,24 +1864,21 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,

	hdr = (struct ieee80211_hdr *)skb->data;
	fc = hdr->frame_control;
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
	/* XXX: UGLY HACK!! */
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;

	spin_lock_bh(&sc->node_lock);
	an = ath_node_find(sc, hdr->addr1);
	spin_unlock_bh(&sc->node_lock);

	if (!an || !priv_sta || !ieee80211_is_data(fc)) {
		if (tx_info->driver_data[0] != NULL) {
			kfree(tx_info->driver_data[0]);
			tx_info->driver_data[0] = NULL;
		}
	if (tx_info_priv == NULL)
		return;
	}
	if (tx_info->driver_data[0] != NULL) {

	if (an && priv_sta && ieee80211_is_data(fc))
		ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
		kfree(tx_info->driver_data[0]);
		tx_info->driver_data[0] = NULL;
	}

	kfree(tx_info_priv);
	tx_info->control.vif = NULL;
}

static void ath_tx_aggr_resp(struct ath_softc *sc,
@@ -1927,10 +1924,11 @@ static void ath_tx_aggr_resp(struct ath_softc *sc,
	}
}

static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
			 struct ieee80211_sta *sta, void *priv_sta,
			 struct sk_buff *skb, struct rate_selection *sel)
static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
			 struct ieee80211_tx_rate_control *txrc)
{
	struct ieee80211_supported_band *sband = txrc->sband;
	struct sk_buff *skb = txrc->skb;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
	struct ath_softc *sc = priv;
	struct ieee80211_hw *hw = sc->hw;
@@ -1945,17 +1943,17 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,

	DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);

	/* allocate driver private area of tx_info */
	tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
	ASSERT(tx_info->driver_data[0] != NULL);
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
	/* allocate driver private area of tx_info, XXX: UGLY HACK! */
	tx_info->control.vif = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
	ASSERT(tx_info_priv != NULL);

	lowest_idx = rate_lowest_index(sband, sta);
	tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
	/* lowest rate for management and multicast/broadcast frames */
	if (!ieee80211_is_data(fc) ||
	    is_multicast_ether_addr(hdr->addr1) || !sta) {
		sel->rate_idx = lowest_idx;
		tx_info->control.rates[0].idx = lowest_idx;
		return;
	}

@@ -1966,8 +1964,10 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
			  tx_info_priv->rcs,
			  &is_probe,
			  false);
#if 0
	if (is_probe)
		sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
#endif

	/* Ratecontrol sometimes returns invalid rate index */
	if (tx_info_priv->rcs[0].rix != 0xff)
@@ -1975,7 +1975,7 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
	else
		tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix;

	sel->rate_idx = tx_info_priv->rcs[0].rix;
	tx_info->control.rates[0].idx = tx_info_priv->rcs[0].rix;

	/* Check if aggregation has to be enabled for this tid */

+19 −9
Original line number Diff line number Diff line
@@ -168,7 +168,9 @@ static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl)

	hdr = (struct ieee80211_hdr *)skb->data;
	fc = hdr->frame_control;
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];

	/* XXX: HACK! */
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;

	if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
		txctl->use_minrate = 1;
@@ -288,13 +290,16 @@ static int ath_tx_prepare(struct ath_softc *sc,

	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
		txctl->flags |= ATH9K_TXDESC_NOACK;
	if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)

	if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
		txctl->flags |= ATH9K_TXDESC_RTSENA;

	/*
	 * Setup for rate calculations.
	 */
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];

	/* XXX: HACK! */
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
	rcs = tx_info_priv->rcs;

	if (ieee80211_is_data(fc) && !txctl->use_minrate) {
@@ -855,7 +860,9 @@ static int ath_tx_send_normal(struct ath_softc *sc,

	skb = (struct sk_buff *)bf->bf_mpdu;
	tx_info = IEEE80211_SKB_CB(skb);
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];

	/* XXX: HACK! */
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
	memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));

	/* update starting sequence number for subsequent ADDBA request */
@@ -1249,8 +1256,9 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
		}
		skb = bf->bf_mpdu;
		tx_info = IEEE80211_SKB_CB(skb);
		tx_info_priv = (struct ath_tx_info_priv *)
			tx_info->driver_data[0];

		/* XXX: HACK! */
		tx_info_priv = (struct ath_tx_info_priv *) tx_info->control.vif;
		if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
			tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
		if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
@@ -1431,7 +1439,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,

	skb = (struct sk_buff *)bf->bf_mpdu;
	tx_info = IEEE80211_SKB_CB(skb);
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
	/* XXX: HACK! */
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
	memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));

	/* Add sub-frame to BAW */
@@ -1466,7 +1475,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
	skb = (struct sk_buff *)bf->bf_mpdu;
	tx_info = IEEE80211_SKB_CB(skb);
	tx_info_priv = (struct ath_tx_info_priv *)
		tx_info->driver_data[0];
		tx_info->control.vif; /* XXX: HACK! */
	memcpy(bf->bf_rcs,
		tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));

@@ -1927,7 +1936,8 @@ static int ath_tx_start_dma(struct ath_softc *sc,

	bf->bf_flags = txctl->flags;
	bf->bf_keytype = txctl->keytype;
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
	/* XXX: HACK! */
	tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
	rcs = tx_info_priv->rcs;
	bf->bf_rcs[0] = rcs[0];
	bf->bf_rcs[1] = rcs[1];
Loading