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

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
......@@ -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
txi->flags |= IEEE80211_TX_STAT_ACK;
}
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);
......
......@@ -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;
......
......@@ -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)
......
......@@ -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 */
......
......@@ -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];
......
......@@ -1387,13 +1387,11 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
info = IEEE80211_SKB_CB(meta->skb);
memset(&info->status, 0, sizeof(info->status));
/*
* Call back to inform the ieee80211 subsystem about
* the status of the transmission.
*/
frame_succeed = b43_fill_txstatus_report(info, status);
frame_succeed = b43_fill_txstatus_report(dev, info, status);
#ifdef CONFIG_B43_DEBUG
if (frame_succeed)
ring->nr_succeed_tx_packets++;
......
......@@ -4555,7 +4555,7 @@ static int b43_wireless_init(struct ssb_device *dev)
BIT(NL80211_IFTYPE_ADHOC);
hw->queues = b43_modparam_qos ? 4 : 1;
hw->max_altrates = 1;
hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac))
SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
......
......@@ -587,9 +587,8 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
spin_lock(&q->lock); /* IRQs are already disabled. */
info = IEEE80211_SKB_CB(pack->skb);
memset(&info->status, 0, sizeof(info->status));
b43_fill_txstatus_report(info, status);
b43_fill_txstatus_report(dev, info, status);
total_len = pack->skb->len + b43_txhdr_size(dev);
total_len = roundup(total_len, 4);
......
......@@ -185,7 +185,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u8 *_txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_info *info,
struct ieee80211_tx_info *info,
u16 cookie)
{
struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
......@@ -202,6 +202,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u16 phy_ctl = 0;
u8 extra_ft = 0;
struct ieee80211_rate *txrate;
struct ieee80211_tx_rate *rates;
memset(txhdr, 0, sizeof(*txhdr));
......@@ -291,7 +292,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
phy_ctl |= B43_TXH_PHY_ENC_OFDM;
else
phy_ctl |= B43_TXH_PHY_ENC_CCK;
if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
......@@ -314,6 +315,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
B43_WARN_ON(1);
}
rates = info->control.rates;
/* MAC control */
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43_TXH_MAC_ACK;
......@@ -324,12 +326,22 @@ int b43_generate_txhdr(struct b43_wldev *dev,
mac_ctl |= B43_TXH_MAC_STMSDU;
if (phy->type == B43_PHYTYPE_A)
mac_ctl |= B43_TXH_MAC_5GHZ;
if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
/* Overwrite rates[0].count to make the retry calculation
* in the tx status easier. need the actual retry limit to
* detect whether the fallback rate was used.
*/
if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
(rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
mac_ctl |= B43_TXH_MAC_LONGFRAME;
} else {
rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
}
/* Generate the RTS or CTS-to-self frame */
if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
(info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
(rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
unsigned int len;
struct ieee80211_hdr *hdr;
int rts_rate, rts_rate_fb;
......@@ -344,7 +356,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
rts_rate_fb = b43_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
struct ieee80211_cts *cts;
if (b43_is_old_txhdr_format(dev)) {
......@@ -687,10 +699,18 @@ void b43_handle_txstatus(struct b43_wldev *dev,
/* Fill out the mac80211 TXstatus report based on the b43-specific
* txstatus report data. This returns a boolean whether the frame was
* successfully transmitted. */
bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
bool b43_fill_txstatus_report(struct b43_wldev *dev,
struct ieee80211_tx_info *report,
const struct b43_txstatus *status)
{
bool frame_success = 1;
int retry_limit;
/* preserve the confiured retry limit before clearing the status
* The xmit function has overwritten the rc's value with the actual
* retry limit done by the hardware */
retry_limit = report->status.rates[0].count;
ieee80211_tx_info_clear_status(report);
if (status->acked) {
/* The frame was ACKed. */
......@@ -700,14 +720,32 @@ bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* ...but we expected an ACK. */
frame_success = 0;
report->status.excessive_retries = 1;
}
}
if (status->frame_count == 0) {
/* The frame was not transmitted at all. */
report->status.retry_count = 0;
} else
report->status.retry_count = status->frame_count - 1;
report->status.rates[0].count = 0;
} else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
/*
* If the short retries (RTS, not data frame) have exceeded
* the limit, the hw will not have tried the selected rate,
* but will have used the fallback rate instead.
* Don't let the rate control count attempts for the selected
* rate in this case, otherwise the statistics will be off.
*/
report->status.rates[0].count = 0;
report->status.rates[1].count = status->frame_count;
} else {
if (status->frame_count > retry_limit) {
report->status.rates[0].count = retry_limit;
report->status.rates[1].count = status->frame_count -
retry_limit;
} else {
report->status.rates[0].count = status->frame_count;
report->status.rates[1].idx = -1;
}
}
return frame_success;
}
......
......@@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_info *txctl, u16 cookie);
struct ieee80211_tx_info *txctl, u16 cookie);
/* Transmit Status */
struct b43_txstatus {
......@@ -294,7 +294,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
void b43_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
bool b43_fill_txstatus_report(struct b43_wldev *dev,
struct ieee80211_tx_info *report,
const struct b43_txstatus *status);
void b43_tx_suspend(struct b43_wldev *dev);
......
......@@ -1411,6 +1411,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
struct b43legacy_dmaring *ring;
struct b43legacy_dmadesc_generic *desc;
struct b43legacy_dmadesc_meta *meta;
int retry_limit;
int slot;
ring = parse_cookie(dev, status->cookie, &slot);
......@@ -1437,25 +1438,42 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
struct ieee80211_tx_info *info;
BUG_ON(!meta->skb);
info = IEEE80211_SKB_CB(meta->skb);
/* Call back to inform the ieee80211 subsystem about the
* status of the transmission.
* Some fields of txstat are already filled in dma_tx().
*/
memset(&info->status, 0, sizeof(info->status));
/* preserve the confiured retry limit before clearing the status
* The xmit function has overwritten the rc's value with the actual
* retry limit done by the hardware */
retry_limit = info->status.rates[0].count;
ieee80211_tx_info_clear_status(info);
if (status->acked) {
if (status->acked)
info->flags |= IEEE80211_TX_STAT_ACK;
if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
/*
* If the short retries (RTS, not data frame) have exceeded
* the limit, the hw will not have tried the selected rate,
* but will have used the fallback rate instead.
* Don't let the rate control count attempts for the selected
* rate in this case, otherwise the statistics will be off.
*/
info->status.rates[0].count = 0;
info->status.rates[1].count = status->frame_count;
} else {
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->status.excessive_retries = 1;
if (status->frame_count > retry_limit) {
info->status.rates[0].count = retry_limit;
info->status.rates[1].count = status->frame_count -
retry_limit;
} else {
info->status.rates[0].count = status->frame_count;
info->status.rates[1].idx = -1;
}
}
if (status->frame_count == 0) {
/* The frame was not transmitted at all. */
info->status.retry_count = 0;
} else
info->status.retry_count = status->frame_count
- 1;
/* Call back to inform the ieee80211 subsystem about the
* status of the transmission.
* Some fields of txstat are already filled in dma_tx().
*/
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
/* skb is freed by ieee80211_tx_status_irqsafe() */
meta->skb = NULL;
......
......@@ -3682,7 +3682,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
BIT(NL80211_IFTYPE_WDS) |
BIT(NL80211_IFTYPE_ADHOC);
hw->queues = 1; /* FIXME: hardware has more queues */
hw->max_altrates = 1;
hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac))
SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
......
......@@ -491,6 +491,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,