mwl8k: dma header manipulations can't fail

Adding and removing the DMA header that the mwl8k hardware requires
on tx and provides on rx can never fail, since we are guaranteed to
have enough headroom on the tx path to expand the packet, and we only
ever shrink the packet on the rx path.  (And on both paths we are
guaranteed to be the only user of the skb we are handling.)

This allows removing all of the skb clone handling in the tx and tx
reclaim paths, and eliminates error checks in both the tx and rx
paths, simplifying the code a bit more.

Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Lennert Buytenhek 2009-07-16 11:07:09 +02:00 committed by John W. Linville
parent 240e86efd6
commit 76266b2ad3

View file

@ -111,17 +111,6 @@ struct mwl8k_rx_queue {
struct sk_buff **rx_skb;
};
struct mwl8k_skb {
/*
* The DMA engine requires a modification to the payload.
* If the skbuff is shared/cloned, it needs to be unshared.
* This method is used to ensure the stack always gets back
* the skbuff it sent for transmission.
*/
struct sk_buff *clone;
struct sk_buff *skb;
};
struct mwl8k_tx_queue {
/* hw transmits here */
int tx_head;
@ -132,7 +121,7 @@ struct mwl8k_tx_queue {
struct ieee80211_tx_queue_stats tx_stats;
struct mwl8k_tx_desc *tx_desc_area;
dma_addr_t tx_desc_dma;
struct mwl8k_skb *tx_skb;
struct sk_buff **tx_skb;
};
/* Pointers to the firmware data and meta information about it. */
@ -714,12 +703,11 @@ struct mwl8k_dma_data {
} __attribute__((packed));
/* Routines to add/remove DMA header from skb. */
static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
static inline void mwl8k_remove_dma_header(struct sk_buff *skb)
{
struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data);
struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)skb->data;
void *dst, *src = &tr->wh;
__le16 fc = tr->wh.frame_control;
int hdrlen = ieee80211_hdrlen(fc);
int hdrlen = ieee80211_hdrlen(tr->wh.frame_control);
u16 space = sizeof(struct mwl8k_dma_data) - hdrlen;
dst = (void *)tr + space;
@ -727,11 +715,9 @@ static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
memmove(dst, src, hdrlen);
skb_pull(skb, space);
}
return 0;
}
static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
static inline void mwl8k_add_dma_header(struct sk_buff *skb)
{
struct ieee80211_hdr *wh;
u32 hdrlen, pktlen;
@ -763,8 +749,6 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
* This includes all crypto material including the MIC.
*/
tr->fwlen = cpu_to_le16(pktlen - hdrlen);
return skb;
}
@ -967,10 +951,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
if (mwl8k_remove_dma_header(skb)) {
dev_kfree_skb(skb);
continue;
}
mwl8k_remove_dma_header(skb);
wh = (struct ieee80211_hdr *)skb->data;
@ -1224,7 +1205,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
while (txq->tx_stats.len > 0) {
int tx;
int rc;
struct mwl8k_tx_desc *tx_desc;
unsigned long addr;
int size;
@ -1232,7 +1212,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
struct ieee80211_tx_info *info;
u32 status;
rc = 0;
tx = txq->tx_head;
tx_desc = txq->tx_desc_area + tx;
@ -1252,40 +1231,18 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
addr = le32_to_cpu(tx_desc->pkt_phys_addr);
size = le16_to_cpu(tx_desc->pkt_len);
skb = txq->tx_skb[tx].skb;
txq->tx_skb[tx].skb = NULL;
skb = txq->tx_skb[tx];
txq->tx_skb[tx] = NULL;
BUG_ON(skb == NULL);
pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE);
rc = mwl8k_remove_dma_header(skb);
mwl8k_remove_dma_header(skb);
/* Mark descriptor as unused */
tx_desc->pkt_phys_addr = 0;
tx_desc->pkt_len = 0;
if (txq->tx_skb[tx].clone) {
/* Replace with original skb
* before returning to stack
* as buffer has been cloned
*/
dev_kfree_skb(skb);
skb = txq->tx_skb[tx].clone;
txq->tx_skb[tx].clone = NULL;
}
if (rc) {
/* Something has gone wrong here.
* Failed to remove DMA header.
* Print error message and drop packet.
*/
printk(KERN_ERR "%s: Error removing DMA header from "
"tx skb 0x%p.\n", priv->name, skb);
dev_kfree_skb(skb);
continue;
}
info = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(info);
if (MWL8K_TXD_SUCCESS(status))
@ -1327,7 +1284,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
struct mwl8k_tx_desc *tx;
struct mwl8k_dma_data *tr;
struct mwl8k_vif *mwl8k_vif;
struct sk_buff *org_skb = skb;
dma_addr_t dma;
u16 qos = 0;
bool qosframe = false, ampduframe = false;
@ -1338,21 +1294,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
txq = priv->txq + index;
tx = txq->tx_desc_area + txq->tx_tail;
BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL);
BUG_ON(txq->tx_skb[txq->tx_tail] != NULL);
/*
* Append HW DMA header to start of packet. Drop packet if
* there is not enough space or a failure to unshare/unclone
* the skb.
* Append HW DMA header to start of packet.
*/
skb = mwl8k_add_dma_header(skb);
if (skb == NULL) {
printk(KERN_DEBUG "%s: failed to prepend HW DMA "
"header, dropping TX frame.\n", priv->name);
dev_kfree_skb(org_skb);
return NETDEV_TX_OK;
}
mwl8k_add_dma_header(skb);
tx_info = IEEE80211_SKB_CB(skb);
mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
@ -1380,8 +1327,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
printk(KERN_DEBUG "%s: failed to dma map skb, "
"dropping TX frame.\n", priv->name);
if (org_skb != NULL)
dev_kfree_skb(org_skb);
if (skb != NULL)
dev_kfree_skb(skb);
return NETDEV_TX_OK;
@ -1437,9 +1382,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
tx->pkt_phys_addr = cpu_to_le32(dma);
tx->pkt_len = cpu_to_le16(skb->len);
txq->tx_skb[txq->tx_tail].skb = skb;
txq->tx_skb[txq->tx_tail].clone =
skb == org_skb ? NULL : org_skb;
txq->tx_skb[txq->tx_tail] = skb;
spin_lock_bh(&priv->tx_lock);