diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2009-07-16 05:07:09 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-20 11:38:06 -0400 |
commit | 76266b2ad38c33fb2c1475cfeb35ed070adaba2b (patch) | |
tree | 6e0abe8fbfd68d8627099358b300c830c99eb42e /drivers/net/wireless/mwl8k.c | |
parent | 240e86efd60e6bc232a072273a7f7794bcb035e0 (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.c | 83 |
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 | ||
114 | struct 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 | |||
125 | struct mwl8k_tx_queue { | 114 | struct 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. */ |
717 | static inline int mwl8k_remove_dma_header(struct sk_buff *skb) | 706 | static 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 | ||
734 | static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb) | 720 | static 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 | ||