aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwl8k.c
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2009-07-16 05:07:09 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:38:06 -0400
commit76266b2ad38c33fb2c1475cfeb35ed070adaba2b (patch)
tree6e0abe8fbfd68d8627099358b300c830c99eb42e /drivers/net/wireless/mwl8k.c
parent240e86efd60e6bc232a072273a7f7794bcb035e0 (diff)
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>
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r--drivers/net/wireless/mwl8k.c83
1 files changed, 13 insertions, 70 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 301d2a20d42b..5aa80420c0d1 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -111,17 +111,6 @@ struct mwl8k_rx_queue {
111 struct sk_buff **rx_skb; 111 struct sk_buff **rx_skb;
112}; 112};
113 113
114struct mwl8k_skb {
115 /*
116 * The DMA engine requires a modification to the payload.
117 * If the skbuff is shared/cloned, it needs to be unshared.
118 * This method is used to ensure the stack always gets back
119 * the skbuff it sent for transmission.
120 */
121 struct sk_buff *clone;
122 struct sk_buff *skb;
123};
124
125struct mwl8k_tx_queue { 114struct mwl8k_tx_queue {
126 /* hw transmits here */ 115 /* hw transmits here */
127 int tx_head; 116 int tx_head;
@@ -132,7 +121,7 @@ struct mwl8k_tx_queue {
132 struct ieee80211_tx_queue_stats tx_stats; 121 struct ieee80211_tx_queue_stats tx_stats;
133 struct mwl8k_tx_desc *tx_desc_area; 122 struct mwl8k_tx_desc *tx_desc_area;
134 dma_addr_t tx_desc_dma; 123 dma_addr_t tx_desc_dma;
135 struct mwl8k_skb *tx_skb; 124 struct sk_buff **tx_skb;
136}; 125};
137 126
138/* Pointers to the firmware data and meta information about it. */ 127/* Pointers to the firmware data and meta information about it. */
@@ -714,12 +703,11 @@ struct mwl8k_dma_data {
714} __attribute__((packed)); 703} __attribute__((packed));
715 704
716/* Routines to add/remove DMA header from skb. */ 705/* Routines to add/remove DMA header from skb. */
717static inline int mwl8k_remove_dma_header(struct sk_buff *skb) 706static inline void mwl8k_remove_dma_header(struct sk_buff *skb)
718{ 707{
719 struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data); 708 struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)skb->data;
720 void *dst, *src = &tr->wh; 709 void *dst, *src = &tr->wh;
721 __le16 fc = tr->wh.frame_control; 710 int hdrlen = ieee80211_hdrlen(tr->wh.frame_control);
722 int hdrlen = ieee80211_hdrlen(fc);
723 u16 space = sizeof(struct mwl8k_dma_data) - hdrlen; 711 u16 space = sizeof(struct mwl8k_dma_data) - hdrlen;
724 712
725 dst = (void *)tr + space; 713 dst = (void *)tr + space;
@@ -727,11 +715,9 @@ static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
727 memmove(dst, src, hdrlen); 715 memmove(dst, src, hdrlen);
728 skb_pull(skb, space); 716 skb_pull(skb, space);
729 } 717 }
730
731 return 0;
732} 718}
733 719
734static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) 720static inline void mwl8k_add_dma_header(struct sk_buff *skb)
735{ 721{
736 struct ieee80211_hdr *wh; 722 struct ieee80211_hdr *wh;
737 u32 hdrlen, pktlen; 723 u32 hdrlen, pktlen;
@@ -763,8 +749,6 @@ static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
763 * This includes all crypto material including the MIC. 749 * This includes all crypto material including the MIC.
764 */ 750 */
765 tr->fwlen = cpu_to_le16(pktlen - hdrlen); 751 tr->fwlen = cpu_to_le16(pktlen - hdrlen);
766
767 return skb;
768} 752}
769 753
770 754
@@ -967,10 +951,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
967 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); 951 MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
968 952
969 skb_put(skb, le16_to_cpu(rx_desc->pkt_len)); 953 skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
970 if (mwl8k_remove_dma_header(skb)) { 954 mwl8k_remove_dma_header(skb);
971 dev_kfree_skb(skb);
972 continue;
973 }
974 955
975 wh = (struct ieee80211_hdr *)skb->data; 956 wh = (struct ieee80211_hdr *)skb->data;
976 957
@@ -1224,7 +1205,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
1224 1205
1225 while (txq->tx_stats.len > 0) { 1206 while (txq->tx_stats.len > 0) {
1226 int tx; 1207 int tx;
1227 int rc;
1228 struct mwl8k_tx_desc *tx_desc; 1208 struct mwl8k_tx_desc *tx_desc;
1229 unsigned long addr; 1209 unsigned long addr;
1230 int size; 1210 int size;
@@ -1232,7 +1212,6 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
1232 struct ieee80211_tx_info *info; 1212 struct ieee80211_tx_info *info;
1233 u32 status; 1213 u32 status;
1234 1214
1235 rc = 0;
1236 tx = txq->tx_head; 1215 tx = txq->tx_head;
1237 tx_desc = txq->tx_desc_area + tx; 1216 tx_desc = txq->tx_desc_area + tx;
1238 1217
@@ -1252,40 +1231,18 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
1252 1231
1253 addr = le32_to_cpu(tx_desc->pkt_phys_addr); 1232 addr = le32_to_cpu(tx_desc->pkt_phys_addr);
1254 size = le16_to_cpu(tx_desc->pkt_len); 1233 size = le16_to_cpu(tx_desc->pkt_len);
1255 skb = txq->tx_skb[tx].skb; 1234 skb = txq->tx_skb[tx];
1256 txq->tx_skb[tx].skb = NULL; 1235 txq->tx_skb[tx] = NULL;
1257 1236
1258 BUG_ON(skb == NULL); 1237 BUG_ON(skb == NULL);
1259 pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); 1238 pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE);
1260 1239
1261 rc = mwl8k_remove_dma_header(skb); 1240 mwl8k_remove_dma_header(skb);
1262 1241
1263 /* Mark descriptor as unused */ 1242 /* Mark descriptor as unused */
1264 tx_desc->pkt_phys_addr = 0; 1243 tx_desc->pkt_phys_addr = 0;
1265 tx_desc->pkt_len = 0; 1244 tx_desc->pkt_len = 0;
1266 1245
1267 if (txq->tx_skb[tx].clone) {
1268 /* Replace with original skb
1269 * before returning to stack
1270 * as buffer has been cloned
1271 */
1272 dev_kfree_skb(skb);
1273 skb = txq->tx_skb[tx].clone;
1274 txq->tx_skb[tx].clone = NULL;
1275 }
1276
1277 if (rc) {
1278 /* Something has gone wrong here.
1279 * Failed to remove DMA header.
1280 * Print error message and drop packet.
1281 */
1282 printk(KERN_ERR "%s: Error removing DMA header from "
1283 "tx skb 0x%p.\n", priv->name, skb);
1284
1285 dev_kfree_skb(skb);
1286 continue;
1287 }
1288
1289 info = IEEE80211_SKB_CB(skb); 1246 info = IEEE80211_SKB_CB(skb);
1290 ieee80211_tx_info_clear_status(info); 1247 ieee80211_tx_info_clear_status(info);
1291 if (MWL8K_TXD_SUCCESS(status)) 1248 if (MWL8K_TXD_SUCCESS(status))
@@ -1327,7 +1284,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1327 struct mwl8k_tx_desc *tx; 1284 struct mwl8k_tx_desc *tx;
1328 struct mwl8k_dma_data *tr; 1285 struct mwl8k_dma_data *tr;
1329 struct mwl8k_vif *mwl8k_vif; 1286 struct mwl8k_vif *mwl8k_vif;
1330 struct sk_buff *org_skb = skb;
1331 dma_addr_t dma; 1287 dma_addr_t dma;
1332 u16 qos = 0; 1288 u16 qos = 0;
1333 bool qosframe = false, ampduframe = false; 1289 bool qosframe = false, ampduframe = false;
@@ -1338,21 +1294,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1338 txq = priv->txq + index; 1294 txq = priv->txq + index;
1339 tx = txq->tx_desc_area + txq->tx_tail; 1295 tx = txq->tx_desc_area + txq->tx_tail;
1340 1296
1341 BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL); 1297 BUG_ON(txq->tx_skb[txq->tx_tail] != NULL);
1342 1298
1343 /* 1299 /*
1344 * Append HW DMA header to start of packet. Drop packet if 1300 * Append HW DMA header to start of packet.
1345 * there is not enough space or a failure to unshare/unclone
1346 * the skb.
1347 */ 1301 */
1348 skb = mwl8k_add_dma_header(skb); 1302 mwl8k_add_dma_header(skb);
1349
1350 if (skb == NULL) {
1351 printk(KERN_DEBUG "%s: failed to prepend HW DMA "
1352 "header, dropping TX frame.\n", priv->name);
1353 dev_kfree_skb(org_skb);
1354 return NETDEV_TX_OK;
1355 }
1356 1303
1357 tx_info = IEEE80211_SKB_CB(skb); 1304 tx_info = IEEE80211_SKB_CB(skb);
1358 mwl8k_vif = MWL8K_VIF(tx_info->control.vif); 1305 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)
1380 printk(KERN_DEBUG "%s: failed to dma map skb, " 1327 printk(KERN_DEBUG "%s: failed to dma map skb, "
1381 "dropping TX frame.\n", priv->name); 1328 "dropping TX frame.\n", priv->name);
1382 1329
1383 if (org_skb != NULL)
1384 dev_kfree_skb(org_skb);
1385 if (skb != NULL) 1330 if (skb != NULL)
1386 dev_kfree_skb(skb); 1331 dev_kfree_skb(skb);
1387 return NETDEV_TX_OK; 1332 return NETDEV_TX_OK;
@@ -1437,9 +1382,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
1437 tx->pkt_phys_addr = cpu_to_le32(dma); 1382 tx->pkt_phys_addr = cpu_to_le32(dma);
1438 tx->pkt_len = cpu_to_le16(skb->len); 1383 tx->pkt_len = cpu_to_le16(skb->len);
1439 1384
1440 txq->tx_skb[txq->tx_tail].skb = skb; 1385 txq->tx_skb[txq->tx_tail] = skb;
1441 txq->tx_skb[txq->tx_tail].clone =
1442 skb == org_skb ? NULL : org_skb;
1443 1386
1444 spin_lock_bh(&priv->tx_lock); 1387 spin_lock_bh(&priv->tx_lock);
1445 1388