diff options
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 | ||