mac80211: move TX info into skb->cb

This patch converts mac80211 and all drivers to have transmit
information and status in skb->cb rather than allocating extra
memory for it and copying all the data around. To make it fit,
a union is used where only data that is necessary for all steps
is kept outside of the union.

A number of fixes were done by Ivo, as well as the rt2x00 part
of this patch.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Johannes Berg
2008-05-15 12:55:29 +02:00
committed by John W. Linville
parent e24549485f
commit e039fa4a41
67 changed files with 976 additions and 1270 deletions
+32 -38
View File
@@ -167,8 +167,7 @@ static struct pci_driver ath5k_pci_driver = {
/*
* Prototypes - MAC 802.11 stack related functions
*/
static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_control *ctl);
static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
static int ath5k_reset(struct ieee80211_hw *hw);
static int ath5k_start(struct ieee80211_hw *hw);
static void ath5k_stop(struct ieee80211_hw *hw);
@@ -196,8 +195,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
static void ath5k_reset_tsf(struct ieee80211_hw *hw);
static int ath5k_beacon_update(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_tx_control *ctl);
struct sk_buff *skb);
static struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
@@ -251,9 +249,7 @@ static void ath5k_desc_free(struct ath5k_softc *sc,
static int ath5k_rxbuf_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf);
static int ath5k_txbuf_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf,
struct ieee80211_tx_control *ctl);
struct ath5k_buf *bf);
static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
@@ -289,8 +285,7 @@ static void ath5k_tx_processq(struct ath5k_softc *sc,
static void ath5k_tasklet_tx(unsigned long data);
/* Beacon handling */
static int ath5k_beacon_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf,
struct ieee80211_tx_control *ctl);
struct ath5k_buf *bf);
static void ath5k_beacon_send(struct ath5k_softc *sc);
static void ath5k_beacon_config(struct ath5k_softc *sc);
static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
@@ -1295,37 +1290,36 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
}
static int
ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
struct ieee80211_tx_control *ctl)
ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
{
struct ath5k_hw *ah = sc->ah;
struct ath5k_txq *txq = sc->txq;
struct ath5k_desc *ds = bf->desc;
struct sk_buff *skb = bf->skb;
struct ieee80211_tx_info *info = (void*) skb->cb;
unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
int ret;
flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
bf->ctl = *ctl;
/* XXX endianness */
bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE);
if (ctl->flags & IEEE80211_TXCTL_NO_ACK)
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
flags |= AR5K_TXDESC_NOACK;
pktlen = skb->len;
if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
keyidx = ctl->hw_key->hw_key_idx;
pktlen += ctl->icv_len;
if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) {
keyidx = info->control.hw_key->hw_key_idx;
pktlen += info->control.icv_len;
}
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
(sc->power_level * 2),
ieee80211_get_tx_rate(sc->hw, ctl)->hw_value,
ctl->retry_limit, keyidx, 0, flags, 0, 0);
ieee80211_get_tx_rate(sc->hw, info)->hw_value,
info->control.retry_limit, keyidx, 0, flags, 0, 0);
if (ret)
goto err_unmap;
@@ -1927,11 +1921,11 @@ next:
static void
ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
{
struct ieee80211_tx_status txs = {};
struct ath5k_tx_status ts = {};
struct ath5k_buf *bf, *bf0;
struct ath5k_desc *ds;
struct sk_buff *skb;
struct ieee80211_tx_info *info;
int ret;
spin_lock(&txq->lock);
@@ -1951,24 +1945,25 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
}
skb = bf->skb;
info = (void*) skb->cb;
bf->skb = NULL;
pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
PCI_DMA_TODEVICE);
txs.control = bf->ctl;
txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
if (unlikely(ts.ts_status)) {
sc->ll_stats.dot11ACKFailureCount++;
if (ts.ts_status & AR5K_TXERR_XRETRY)
txs.excessive_retries = 1;
info->status.excessive_retries = 1;
else if (ts.ts_status & AR5K_TXERR_FILT)
txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED;
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
} else {
txs.flags |= IEEE80211_TX_STATUS_ACK;
txs.ack_signal = ts.ts_rssi;
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ack_signal = ts.ts_rssi;
}
ieee80211_tx_status(sc->hw, skb, &txs);
ieee80211_tx_status(sc->hw, skb);
sc->tx_stats[txq->qnum].count++;
spin_lock(&sc->txbuflock);
@@ -2005,10 +2000,10 @@ ath5k_tasklet_tx(unsigned long data)
* Setup the beacon frame for transmit.
*/
static int
ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
struct ieee80211_tx_control *ctl)
ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
{
struct sk_buff *skb = bf->skb;
struct ieee80211_tx_info *info = (void*) skb->cb;
struct ath5k_hw *ah = sc->ah;
struct ath5k_desc *ds;
int ret, antenna = 0;
@@ -2047,7 +2042,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
ieee80211_get_hdrlen_from_skb(skb),
AR5K_PKT_TYPE_BEACON, (sc->power_level * 2),
ieee80211_get_tx_rate(sc->hw, ctl)->hw_value,
ieee80211_get_tx_rate(sc->hw, info)->hw_value,
1, AR5K_TXKEYIX_INVALID,
antenna, flags, 0, 0);
if (ret)
@@ -2626,11 +2621,11 @@ ath5k_led_event(struct ath5k_softc *sc, int event)
\********************/
static int
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_control *ctl)
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_buf *bf;
struct ieee80211_tx_info *info = (void*) skb->cb;
unsigned long flags;
int hdrlen;
int pad;
@@ -2656,13 +2651,13 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
memmove(skb->data, skb->data+pad, hdrlen);
}
sc->led_txrate = ieee80211_get_tx_rate(hw, ctl)->hw_value;
sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value;
spin_lock_irqsave(&sc->txbuflock, flags);
if (list_empty(&sc->txbuf)) {
ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
spin_unlock_irqrestore(&sc->txbuflock, flags);
ieee80211_stop_queue(hw, ctl->queue);
ieee80211_stop_queue(hw, info->queue);
return -1;
}
bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
@@ -2674,7 +2669,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
bf->skb = skb;
if (ath5k_txbuf_setup(sc, bf, ctl)) {
if (ath5k_txbuf_setup(sc, bf)) {
bf->skb = NULL;
spin_lock_irqsave(&sc->txbuflock, flags);
list_add_tail(&bf->list, &sc->txbuf);
@@ -3052,8 +3047,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw)
}
static int
ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_control *ctl)
ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
int ret;
@@ -3069,7 +3063,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
ath5k_txbuf_free(sc, sc->bbuf);
sc->bbuf->skb = skb;
ret = ath5k_beacon_setup(sc, sc->bbuf, ctl);
ret = ath5k_beacon_setup(sc, sc->bbuf);
if (ret)
sc->bbuf->skb = NULL;
else