summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2011-09-14 21:24:22 +0200
committerJohn W. Linville <linville@tuxdriver.com>2011-09-16 16:45:40 -0400
commit493cf04fd37bf265dc3c9aad357e3e34654c86e3 (patch)
tree834da35a27d459a4ed0a8208616a51e327c29ba5 /drivers
parent2b63a41d14245345d6c498506c5634613afa80c0 (diff)
ath9k: use the new API for setting tx descriptors
With the new API, tx descriptors can be written in one single pass instead of having to re-read and rewrite fields from multiple places. This makes the code easier to read and also slightly improves performance on embedded MIPS hardware. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c52
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c229
3 files changed, 122 insertions, 160 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 4eba9577386b..94d887b65e69 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -228,7 +228,6 @@ struct ath_buf {
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer, for DMA */
bool bf_stale;
- u16 bf_flags;
struct ath_buf_state bf_state;
};
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index b97d01d2eece..9cdeaebc844f 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -73,45 +73,39 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
struct sk_buff *skb = bf->bf_mpdu;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath_desc *ds;
- struct ath9k_11n_rate_series series[4];
- int flags, ctsrate = 0, ctsduration = 0;
+ struct ath_tx_info info;
struct ieee80211_supported_band *sband;
+ u8 chainmask = ah->txchainmask;
u8 rate = 0;
ath9k_reset_beacon_status(sc);
- ds = bf->bf_desc;
- flags = ATH9K_TXDESC_NOACK;
-
- ds->ds_link = 0;
-
sband = &sc->sbands[common->hw->conf.channel->band];
rate = sband->bitrates[rateidx].hw_value;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
rate |= sband->bitrates[rateidx].hw_value_short;
- ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN,
- ATH9K_PKT_TYPE_BEACON,
- MAX_RATE_POWER,
- ATH9K_TXKEYIX_INVALID,
- ATH9K_KEY_TYPE_CLEAR,
- flags);
-
- /* NB: beacon's BufLen must be a multiple of 4 bytes */
- ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4),
- true, true, ds, bf->bf_buf_addr,
- sc->beacon.beaconq);
-
- memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
- series[0].Tries = 1;
- series[0].Rate = rate;
- series[0].ChSel = ath_txchainmask_reduction(sc,
- ah->txchainmask, series[0].Rate);
- series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
- ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
- series, 4, 0);
- ath9k_hw_set_desc_link(ah, ds, 0);
+ memset(&info, 0, sizeof(info));
+ info.pkt_len = skb->len + FCS_LEN;
+ info.type = ATH9K_PKT_TYPE_BEACON;
+ info.txpower = MAX_RATE_POWER;
+ info.keyix = ATH9K_TXKEYIX_INVALID;
+ info.keytype = ATH9K_KEY_TYPE_CLEAR;
+ info.flags = ATH9K_TXDESC_NOACK;
+
+ info.buf_addr[0] = bf->bf_buf_addr;
+ info.buf_len[0] = roundup(skb->len, 4);
+
+ info.is_first = true;
+ info.is_last = true;
+
+ info.qcu = sc->beacon.beaconq;
+
+ info.rates[0].Tries = 1;
+ info.rates[0].Rate = rate;
+ info.rates[0].ChSel = ath_txchainmask_reduction(sc, chainmask, rate);
+
+ ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
}
static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 485c0a3a9ce1..7f8191eddebe 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -504,7 +504,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
!txfail, sendbar);
} else {
/* retry the un-acked ones */
- ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
if (bf->bf_next == NULL && bf_last->bf_stale) {
struct ath_buf *tbf;
@@ -528,16 +527,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
break;
}
- ath9k_hw_cleartxdesc(sc->sc_ah,
- tbf->bf_desc);
fi->bf = tbf;
- } else {
- /*
- * Clear descriptor status words for
- * software retry
- */
- ath9k_hw_cleartxdesc(sc->sc_ah,
- bf->bf_desc);
}
}
@@ -873,26 +863,25 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
return duration;
}
-static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
+static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_tx_info *info, int len)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath9k_11n_rate_series series[4];
struct sk_buff *skb;
struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *rates;
const struct ieee80211_rate *rate;
struct ieee80211_hdr *hdr;
- int i, flags = 0;
- u8 rix = 0, ctsrate = 0;
- bool is_pspoll;
-
- memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
+ int i;
+ u8 rix = 0;
skb = bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
rates = tx_info->control.rates;
hdr = (struct ieee80211_hdr *)skb->data;
- is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
+
+ /* set dur_update_en for l-sig computation except for PS-Poll frames */
+ info->dur_update = !ieee80211_is_pspoll(hdr->frame_control);
/*
* We check if Short Preamble is needed for the CTS rate by
@@ -900,9 +889,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
* But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
*/
rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
- ctsrate = rate->hw_value;
+ info->rtscts_rate = rate->hw_value;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
- ctsrate |= rate->hw_value_short;
+ info->rtscts_rate |= rate->hw_value_short;
for (i = 0; i < 4; i++) {
bool is_40, is_sgi, is_sp;
@@ -912,20 +901,20 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
continue;
rix = rates[i].idx;
- series[i].Tries = rates[i].count;
+ info->rates[i].Tries = rates[i].count;
if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
- series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
- flags |= ATH9K_TXDESC_RTSENA;
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+ info->flags |= ATH9K_TXDESC_RTSENA;
} else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
- series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
- flags |= ATH9K_TXDESC_CTSENA;
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+ info->flags |= ATH9K_TXDESC_CTSENA;
}
if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- series[i].RateFlags |= ATH9K_RATESERIES_2040;
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_2040;
if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
- series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
@@ -933,13 +922,13 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
if (rates[i].flags & IEEE80211_TX_RC_MCS) {
/* MCS rates */
- series[i].Rate = rix | 0x80;
- series[i].ChSel = ath_txchainmask_reduction(sc,
- ah->txchainmask, series[i].Rate);
- series[i].PktDuration = ath_pkt_duration(sc, rix, len,
+ info->rates[i].Rate = rix | 0x80;
+ info->rates[i].ChSel = ath_txchainmask_reduction(sc,
+ ah->txchainmask, info->rates[i].Rate);
+ info->rates[i].PktDuration = ath_pkt_duration(sc, rix, len,
is_40, is_sgi, is_sp);
if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
- series[i].RateFlags |= ATH9K_RATESERIES_STBC;
+ info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
continue;
}
@@ -951,74 +940,115 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
phy = WLAN_RC_PHY_OFDM;
rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
- series[i].Rate = rate->hw_value;
+ info->rates[i].Rate = rate->hw_value;
if (rate->hw_value_short) {
if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
- series[i].Rate |= rate->hw_value_short;
+ info->rates[i].Rate |= rate->hw_value_short;
} else {
is_sp = false;
}
if (bf->bf_state.bfs_paprd)
- series[i].ChSel = ah->txchainmask;
+ info->rates[i].ChSel = ah->txchainmask;
else
- series[i].ChSel = ath_txchainmask_reduction(sc,
- ah->txchainmask, series[i].Rate);
+ info->rates[i].ChSel = ath_txchainmask_reduction(sc,
+ ah->txchainmask, info->rates[i].Rate);
- series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
+ info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
phy, rate->bitrate * 100, len, rix, is_sp);
}
/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
- flags &= ~ATH9K_TXDESC_RTSENA;
+ info->flags &= ~ATH9K_TXDESC_RTSENA;
/* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
- if (flags & ATH9K_TXDESC_RTSENA)
- flags &= ~ATH9K_TXDESC_CTSENA;
+ if (info->flags & ATH9K_TXDESC_RTSENA)
+ info->flags &= ~ATH9K_TXDESC_CTSENA;
+}
- /* set dur_update_en for l-sig computation except for PS-Poll frames */
- ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
- bf->bf_lastbf->bf_desc,
- !is_pspoll, ctsrate,
- 0, series, 4, flags);
+static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr;
+ enum ath9k_pkt_type htype;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+
+ if (ieee80211_is_beacon(fc))
+ htype = ATH9K_PKT_TYPE_BEACON;
+ else if (ieee80211_is_probe_resp(fc))
+ htype = ATH9K_PKT_TYPE_PROBE_RESP;
+ else if (ieee80211_is_atim(fc))
+ htype = ATH9K_PKT_TYPE_ATIM;
+ else if (ieee80211_is_pspoll(fc))
+ htype = ATH9K_PKT_TYPE_PSPOLL;
+ else
+ htype = ATH9K_PKT_TYPE_NORMAL;
+ return htype;
}
-static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, int len)
+static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
+ struct ath_txq *txq, int len)
{
struct ath_hw *ah = sc->sc_ah;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
struct ath_buf *bf_first = bf;
-
+ struct ath_tx_info info;
bool aggr = !!(bf->bf_state.bf_type & BUF_AGGR);
- bool clrdmask = !!(tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT);
- u32 ds_next;
+ memset(&info, 0, sizeof(info));
+ info.is_first = true;
+ info.is_last = true;
+ info.txpower = MAX_RATE_POWER;
+ info.qcu = txq->axq_qnum;
+
+ info.flags = ATH9K_TXDESC_INTREQ;
+ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+ info.flags |= ATH9K_TXDESC_NOACK;
+ if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
+ info.flags |= ATH9K_TXDESC_LDPC;
+
+ ath_buf_set_rate(sc, bf, &info, len);
+
+ if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+ info.flags |= ATH9K_TXDESC_CLRDMASK;
+
+ if (bf->bf_state.bfs_paprd)
+ info.flags |= (u32) bf->bf_state.bfs_paprd << ATH9K_TXDESC_PAPRD_S;
- ath_buf_set_rate(sc, bf, len);
while (bf) {
+ struct sk_buff *skb = bf->bf_mpdu;
+ struct ath_frame_info *fi = get_frame_info(skb);
+
+ info.type = get_hw_packet_type(skb);
if (bf->bf_next)
- ds_next = bf->bf_next->bf_daddr;
+ info.link = bf->bf_next->bf_daddr;
else
- ds_next = 0;
-
- ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, clrdmask);
- if (!aggr)
- ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
- else if (!bf->bf_next)
- ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_desc);
- else {
+ info.link = 0;
+
+ info.buf_addr[0] = bf->bf_buf_addr;
+ info.buf_len[0] = skb->len;
+ info.pkt_len = fi->framelen;
+ info.keyix = fi->keyix;
+ info.keytype = fi->keytype;
+
+ if (aggr) {
if (bf == bf_first)
- ath9k_hw_set11n_aggr_first(sc->sc_ah,
- bf->bf_desc, len);
+ info.aggr = AGGR_BUF_FIRST;
+ else if (!bf->bf_next)
+ info.aggr = AGGR_BUF_LAST;
+ else
+ info.aggr = AGGR_BUF_MIDDLE;
- ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc,
- bf->bf_state.ndelim);
+ info.ndelim = bf->bf_state.ndelim;
+ info.aggr_len = len;
}
- ath9k_hw_set_desc_link(ah, bf->bf_desc, ds_next);
+ ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
bf = bf->bf_next;
}
}
@@ -1066,7 +1096,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
TX_STAT_INC(txq->axq_qnum, a_aggr);
}
- ath_tx_fill_desc(sc, bf, aggr_len);
+ ath_tx_fill_desc(sc, bf, txq, aggr_len);
ath_tx_txqaddbuf(sc, txq, &bf_q, false);
} while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
status != ATH_AGGR_BAW_CLOSED);
@@ -1655,7 +1685,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
/* Queue to h/w without aggregation */
TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
bf->bf_lastbf = bf;
- ath_tx_fill_desc(sc, bf, fi->framelen);
+ ath_tx_fill_desc(sc, bf, txctl->txq, fi->framelen);
ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
}
@@ -1682,34 +1712,11 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
INCR(tid->seq_start, IEEE80211_SEQ_MAX);
bf->bf_lastbf = bf;
- ath_tx_fill_desc(sc, bf, fi->framelen);
+ ath_tx_fill_desc(sc, bf, txq, fi->framelen);
ath_tx_txqaddbuf(sc, txq, &bf_head, false);
TX_STAT_INC(txq->axq_qnum, queued);
}
-static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr;
- enum ath9k_pkt_type htype;
- __le16 fc;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
-
- if (ieee80211_is_beacon(fc))
- htype = ATH9K_PKT_TYPE_BEACON;
- else if (ieee80211_is_probe_resp(fc))
- htype = ATH9K_PKT_TYPE_PROBE_RESP;
- else if (ieee80211_is_atim(fc))
- htype = ATH9K_PKT_TYPE_ATIM;
- else if (ieee80211_is_pspoll(fc))
- htype = ATH9K_PKT_TYPE_PSPOLL;
- else
- htype = ATH9K_PKT_TYPE_NORMAL;
-
- return htype;
-}
-
static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
int framelen)
{
@@ -1737,22 +1744,6 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
fi->framelen = framelen;
}
-static int setup_tx_flags(struct sk_buff *skb)
-{
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- int flags = 0;
-
- flags |= ATH9K_TXDESC_INTREQ;
-
- if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
- flags |= ATH9K_TXDESC_NOACK;
-
- if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
- flags |= ATH9K_TXDESC_LDPC;
-
- return flags;
-}
-
u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
{
struct ath_hw *ah = sc->sc_ah;
@@ -1774,13 +1765,10 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
struct ath_atx_tid *tid,
struct sk_buff *skb)
{
- struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_frame_info *fi = get_frame_info(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ath_buf *bf;
- struct ath_desc *ds;
- int frm_type;
u16 seqno;
bf = ath_tx_get_buffer(sc);
@@ -1798,7 +1786,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
bf->bf_state.seqno = seqno;
}
- bf->bf_flags = setup_tx_flags(skb);
bf->bf_mpdu = skb;
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
@@ -1812,20 +1799,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
goto error;
}
- frm_type = get_hw_packet_type(skb);
-
- ds = bf->bf_desc;
- ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
- fi->keyix, fi->keytype, bf->bf_flags);
-
- ath9k_hw_filltxdesc(ah, ds,
- skb->len, /* segment length */
- true, /* first segment */
- true, /* last segment */
- ds, /* first descriptor */
- bf->bf_buf_addr,
- txq->axq_qnum);
-
fi->bf = bf;
return bf;
@@ -1868,10 +1841,6 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
bf->bf_state.bfs_paprd = txctl->paprd;
- if (bf->bf_state.bfs_paprd)
- ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
- bf->bf_state.bfs_paprd);
-
if (txctl->paprd)
bf->bf_state.bfs_paprd_timestamp = jiffies;
@@ -2080,7 +2049,7 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
}
if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
- (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
+ (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0 && update_rc) {
/*
* If an underrun error is seen assume it as an excessive
* retry only if max frame trigger level has been reached