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

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

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: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e2454948
Loading
Loading
Loading
Loading
+14 −17
Original line number Diff line number Diff line
@@ -324,7 +324,7 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
	for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) {
		unsigned int entry = dirty_tx % priv->tx_ring_size;
		u32 status = le32_to_cpu(priv->tx_ring[entry].status);
		struct ieee80211_tx_status tx_status;
		struct ieee80211_tx_info *txi;
		struct adm8211_tx_ring_info *info;
		struct sk_buff *skb;

@@ -334,24 +334,23 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev)

		info = &priv->tx_buffers[entry];
		skb = info->skb;
		txi = IEEE80211_SKB_CB(skb);

		/* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */

		pci_unmap_single(priv->pdev, info->mapping,
				 info->skb->len, PCI_DMA_TODEVICE);

		memset(&tx_status, 0, sizeof(tx_status));
		memset(&txi->status, 0, sizeof(txi->status));
		skb_pull(skb, sizeof(struct adm8211_tx_hdr));
		memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
		memcpy(&tx_status.control, &info->tx_control,
		       sizeof(tx_status.control));
		if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
		if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
			if (status & TDES0_STATUS_ES)
				tx_status.excessive_retries = 1;
				txi->status.excessive_retries = 1;
			else
				tx_status.flags |= IEEE80211_TX_STATUS_ACK;
				txi->flags |= IEEE80211_TX_STAT_ACK;
		}
		ieee80211_tx_status_irqsafe(dev, skb, &tx_status);
		ieee80211_tx_status_irqsafe(dev, skb);

		info->skb = NULL;
	}
@@ -1638,7 +1637,6 @@ static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int
/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
			   u16 plcp_signal,
			   struct ieee80211_tx_control *control,
			   size_t hdrlen)
{
	struct adm8211_priv *priv = dev->priv;
@@ -1664,7 +1662,6 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,

	priv->tx_buffers[entry].skb = skb;
	priv->tx_buffers[entry].mapping = mapping;
	memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control));
	priv->tx_buffers[entry].hdrlen = hdrlen;
	priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);

@@ -1685,17 +1682,17 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
}

/* Put adm8211_tx_hdr on skb and transmit */
static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
		      struct ieee80211_tx_control *control)
static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
	struct adm8211_tx_hdr *txhdr;
	u16 fc;
	size_t payload_len, hdrlen;
	int plcp, dur, len, plcp_signal, short_preamble;
	struct ieee80211_hdr *hdr;
	struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, control);
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);

	short_preamble = !!(txrate->flags & IEEE80211_TXCTL_SHORT_PREAMBLE);
	short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
	plcp_signal = txrate->bitrate;

	hdr = (struct ieee80211_hdr *)skb->data;
@@ -1730,15 +1727,15 @@ 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 (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);

	if (fc & IEEE80211_FCTL_PROTECTED)
		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);

	txhdr->retry_limit = control->retry_limit;
	txhdr->retry_limit = info->control.retry_limit;

	adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen);
	adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);

	return NETDEV_TX_OK;
}
+0 −1
Original line number Diff line number Diff line
@@ -443,7 +443,6 @@ struct adm8211_rx_ring_info {
struct adm8211_tx_ring_info {
	struct sk_buff *skb;
	dma_addr_t mapping;
	struct ieee80211_tx_control tx_control;
	size_t hdrlen;
};

+32 −38
Original line number Diff line number Diff line
@@ -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 @@ ath5k_tasklet_rx(unsigned long data)
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
+0 −1
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ struct ath5k_buf {
	dma_addr_t		daddr;	/* physical addr of desc */
	struct sk_buff		*skb;	/* skbuff for buf */
	dma_addr_t		skbaddr;/* physical addr of skb data */
	struct ieee80211_tx_control ctl;
};

/*
+0 −1
Original line number Diff line number Diff line
@@ -733,7 +733,6 @@ struct b43_wl {
	/* The beacon we are currently using (AP or IBSS mode).
	 * This beacon stuff is protected by the irq_lock. */
	struct sk_buff *current_beacon;
	struct ieee80211_tx_control beacon_txctl;
	bool beacon0_uploaded;
	bool beacon1_uploaded;
	struct work_struct beacon_update_trigger;
Loading