forked from Minki/linux
ath5k: implement multi-rate retry support, fix tx status reporting
Clean up the tx status reporting, fix retry counters (short retries are virtual collisions, not actual retries). Implement multi-rate retry support. This also fixes strong throughput fluctuations with rc80211_pid Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
870abdf671
commit
2f7fe87034
@ -431,7 +431,9 @@ struct ath5k_tx_status {
|
|||||||
u16 ts_seqnum;
|
u16 ts_seqnum;
|
||||||
u16 ts_tstamp;
|
u16 ts_tstamp;
|
||||||
u8 ts_status;
|
u8 ts_status;
|
||||||
u8 ts_rate;
|
u8 ts_rate[4];
|
||||||
|
u8 ts_retry[4];
|
||||||
|
u8 ts_final_idx;
|
||||||
s8 ts_rssi;
|
s8 ts_rssi;
|
||||||
u8 ts_shortretry;
|
u8 ts_shortretry;
|
||||||
u8 ts_longretry;
|
u8 ts_longretry;
|
||||||
|
@ -541,6 +541,12 @@ ath5k_pci_probe(struct pci_dev *pdev,
|
|||||||
goto err_irq;
|
goto err_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set up multi-rate retry capabilities */
|
||||||
|
if (sc->ah->ah_version == AR5K_AR5212) {
|
||||||
|
hw->max_altrates = 3;
|
||||||
|
hw->max_altrate_tries = 11;
|
||||||
|
}
|
||||||
|
|
||||||
/* Finish private driver data initialization */
|
/* Finish private driver data initialization */
|
||||||
ret = ath5k_attach(pdev, hw);
|
ret = ath5k_attach(pdev, hw);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1173,7 +1179,9 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
|||||||
struct sk_buff *skb = bf->skb;
|
struct sk_buff *skb = bf->skb;
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
|
unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
|
||||||
int ret;
|
struct ieee80211_rate *rate;
|
||||||
|
unsigned int mrr_rate[3], mrr_tries[3];
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
|
flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
|
||||||
|
|
||||||
@ -1198,6 +1206,22 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_unmap;
|
goto err_unmap;
|
||||||
|
|
||||||
|
memset(mrr_rate, 0, sizeof(mrr_rate));
|
||||||
|
memset(mrr_tries, 0, sizeof(mrr_tries));
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
rate = ieee80211_get_alt_retry_rate(sc->hw, info, i);
|
||||||
|
if (!rate)
|
||||||
|
break;
|
||||||
|
|
||||||
|
mrr_rate[i] = rate->hw_value;
|
||||||
|
mrr_tries[i] = info->control.retries[i].limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ah->ah_setup_mrr_tx_desc(ah, ds,
|
||||||
|
mrr_rate[0], mrr_tries[0],
|
||||||
|
mrr_rate[1], mrr_tries[1],
|
||||||
|
mrr_rate[2], mrr_tries[2]);
|
||||||
|
|
||||||
ds->ds_link = 0;
|
ds->ds_link = 0;
|
||||||
ds->ds_data = bf->skbaddr;
|
ds->ds_data = bf->skbaddr;
|
||||||
|
|
||||||
@ -1814,7 +1838,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
|
|||||||
struct ath5k_desc *ds;
|
struct ath5k_desc *ds;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct ieee80211_tx_info *info;
|
struct ieee80211_tx_info *info;
|
||||||
int ret;
|
int i, ret;
|
||||||
|
|
||||||
spin_lock(&txq->lock);
|
spin_lock(&txq->lock);
|
||||||
list_for_each_entry_safe(bf, bf0, &txq->q, list) {
|
list_for_each_entry_safe(bf, bf0, &txq->q, list) {
|
||||||
@ -1836,7 +1860,25 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
|
|||||||
pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
|
pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
|
||||||
PCI_DMA_TODEVICE);
|
PCI_DMA_TODEVICE);
|
||||||
|
|
||||||
info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
|
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;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
struct ieee80211_tx_altrate *r =
|
||||||
|
&info->status.retries[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];
|
||||||
|
} else {
|
||||||
|
r->rate_idx = -1;
|
||||||
|
r->limit = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info->status.excessive_retries = 0;
|
||||||
if (unlikely(ts.ts_status)) {
|
if (unlikely(ts.ts_status)) {
|
||||||
sc->ll_stats.dot11ACKFailureCount++;
|
sc->ll_stats.dot11ACKFailureCount++;
|
||||||
if (ts.ts_status & AR5K_TXERR_XRETRY)
|
if (ts.ts_status & AR5K_TXERR_XRETRY)
|
||||||
|
@ -318,6 +318,15 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* no mrr support for cards older than 5212 */
|
||||||
|
static int
|
||||||
|
ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc,
|
||||||
|
unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
|
||||||
|
u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Proccess the tx status descriptor on 5210/5211
|
* Proccess the tx status descriptor on 5210/5211
|
||||||
*/
|
*/
|
||||||
@ -352,8 +361,10 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
|
|||||||
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
|
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
|
||||||
ts->ts_antenna = 1;
|
ts->ts_antenna = 1;
|
||||||
ts->ts_status = 0;
|
ts->ts_status = 0;
|
||||||
ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0,
|
ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
|
||||||
AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
|
AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
|
||||||
|
ts->ts_retry[0] = ts->ts_longretry;
|
||||||
|
ts->ts_final_idx = 0;
|
||||||
|
|
||||||
if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
|
if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
|
||||||
if (tx_status->tx_status_0 &
|
if (tx_status->tx_status_0 &
|
||||||
@ -405,29 +416,43 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
|
|||||||
AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
|
AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
|
||||||
ts->ts_status = 0;
|
ts->ts_status = 0;
|
||||||
|
|
||||||
switch (AR5K_REG_MS(tx_status->tx_status_1,
|
ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
|
||||||
AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) {
|
AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX);
|
||||||
case 0:
|
|
||||||
ts->ts_rate = tx_ctl->tx_control_3 &
|
/* The longretry counter has the number of un-acked retries
|
||||||
AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
|
* for the final rate. To get the total number of retries
|
||||||
break;
|
* we have to add the retry counters for the other rates
|
||||||
case 1:
|
* as well
|
||||||
ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
|
*/
|
||||||
AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
|
ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
|
||||||
ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
|
switch (ts->ts_final_idx) {
|
||||||
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
|
|
||||||
AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
|
|
||||||
ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
|
|
||||||
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
|
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
|
ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3,
|
||||||
AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
|
AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
|
||||||
ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
|
|
||||||
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3);
|
ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2,
|
||||||
|
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
|
||||||
|
ts->ts_longretry += ts->ts_retry[2];
|
||||||
|
/* fall through */
|
||||||
|
case 2:
|
||||||
|
ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3,
|
||||||
|
AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
|
||||||
|
|
||||||
|
ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2,
|
||||||
|
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
|
||||||
|
ts->ts_longretry += ts->ts_retry[1];
|
||||||
|
/* fall through */
|
||||||
|
case 1:
|
||||||
|
ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3,
|
||||||
|
AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
|
||||||
|
|
||||||
|
ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2,
|
||||||
|
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
|
||||||
|
ts->ts_longretry += ts->ts_retry[0];
|
||||||
|
/* fall through */
|
||||||
|
case 0:
|
||||||
|
ts->ts_rate[0] = tx_ctl->tx_control_3 &
|
||||||
|
AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,7 +678,7 @@ int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
|
|||||||
} else {
|
} else {
|
||||||
ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
|
ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
|
||||||
ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
|
ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
|
||||||
ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc;
|
ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr;
|
||||||
ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
|
ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user