aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2011-08-26 02:11:23 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-29 15:30:32 -0400
commitdfa2bdbab70901ddda3ec41f2e55f8396af9095f (patch)
tree0e547a9e6dc42189f6b0c40a1a72934f0fb6d51c /drivers/net
parentba562f71198a2cb03bb8d20640ffdf996275c3f0 (diff)
iwlagn: upper layer uses slabs to allocate tx cmds
In a near future, the upper layer won't be aware of the tx queues. This allows to remove one place where the upper layer needed to provide the tx queue index to the transport layer. This also saves around 1.5MB. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c57
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h17
6 files changed, 55 insertions, 51 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 9787f0f2a4fd..b02125a6a437 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -276,6 +276,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
276 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 276 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
277 struct iwl_station_priv *sta_priv = NULL; 277 struct iwl_station_priv *sta_priv = NULL;
278 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 278 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
279 struct iwl_device_cmd *dev_cmd = NULL;
279 struct iwl_tx_cmd *tx_cmd; 280 struct iwl_tx_cmd *tx_cmd;
280 int txq_id; 281 int txq_id;
281 282
@@ -386,10 +387,14 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
386 } 387 }
387 } 388 }
388 389
389 tx_cmd = iwl_trans_get_tx_cmd(trans(priv), txq_id); 390 dev_cmd = kmem_cache_alloc(priv->tx_cmd_pool, GFP_ATOMIC);
390 if (unlikely(!tx_cmd)) 391
392 if (unlikely(!dev_cmd))
391 goto drop_unlock_sta; 393 goto drop_unlock_sta;
392 394
395 memset(dev_cmd, 0, sizeof(*dev_cmd));
396 tx_cmd = &dev_cmd->cmd.tx;
397
393 /* Copy MAC header from skb into command buffer */ 398 /* Copy MAC header from skb into command buffer */
394 memcpy(tx_cmd->hdr, hdr, hdr_len); 399 memcpy(tx_cmd->hdr, hdr, hdr_len);
395 400
@@ -409,8 +414,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
409 iwl_update_stats(priv, true, fc, len); 414 iwl_update_stats(priv, true, fc, len);
410 415
411 info->driver_data[0] = ctx; 416 info->driver_data[0] = ctx;
417 info->driver_data[1] = dev_cmd;
412 418
413 if (iwl_trans_tx(trans(priv), skb, tx_cmd, txq_id, fc, is_agg)) 419 if (iwl_trans_tx(trans(priv), skb, dev_cmd, txq_id, fc, is_agg))
414 goto drop_unlock_sta; 420 goto drop_unlock_sta;
415 421
416 if (ieee80211_is_data_qos(fc)) { 422 if (ieee80211_is_data_qos(fc)) {
@@ -436,6 +442,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
436 return 0; 442 return 0;
437 443
438drop_unlock_sta: 444drop_unlock_sta:
445 if (dev_cmd)
446 kmem_cache_free(priv->tx_cmd_pool, dev_cmd);
439 spin_unlock(&priv->shrd->sta_lock); 447 spin_unlock(&priv->shrd->sta_lock);
440drop_unlock_priv: 448drop_unlock_priv:
441 spin_unlock_irqrestore(&priv->shrd->lock, flags); 449 spin_unlock_irqrestore(&priv->shrd->lock, flags);
@@ -1010,6 +1018,8 @@ void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
1010 1018
1011 info = IEEE80211_SKB_CB(skb); 1019 info = IEEE80211_SKB_CB(skb);
1012 ctx = info->driver_data[0]; 1020 ctx = info->driver_data[0];
1021 kmem_cache_free(priv->tx_cmd_pool,
1022 (info->driver_data[1]));
1013 1023
1014 memset(&info->status, 0, sizeof(info->status)); 1024 memset(&info->status, 0, sizeof(info->status));
1015 1025
@@ -1184,6 +1194,9 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
1184 info); 1194 info);
1185 } 1195 }
1186 1196
1197 info = IEEE80211_SKB_CB(skb);
1198 kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
1199
1187 ieee80211_tx_status_irqsafe(priv->hw, skb); 1200 ieee80211_tx_status_irqsafe(priv->hw, skb);
1188 } 1201 }
1189 1202
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index 02b00d177323..ddb255a575df 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -351,6 +351,15 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
351{ 351{
352 int ret; 352 int ret;
353 353
354 if (!priv->tx_cmd_pool)
355 priv->tx_cmd_pool =
356 kmem_cache_create("iwlagn_dev_cmd",
357 sizeof(struct iwl_device_cmd),
358 sizeof(void *), 0, NULL);
359
360 if (!priv->tx_cmd_pool)
361 return -ENOMEM;
362
354 iwl_trans_tx_start(trans(priv)); 363 iwl_trans_tx_start(trans(priv));
355 364
356 ret = iwlagn_send_wimax_coex(priv); 365 ret = iwlagn_send_wimax_coex(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index d3e103c1b1c7..cfb4a4ae52ce 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3124,6 +3124,8 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
3124 iwl_calib_free_results(priv); 3124 iwl_calib_free_results(priv);
3125 iwl_free_geos(priv); 3125 iwl_free_geos(priv);
3126 iwl_free_channel_map(priv); 3126 iwl_free_channel_map(priv);
3127 if (priv->tx_cmd_pool)
3128 kmem_cache_destroy(priv->tx_cmd_pool);
3127 kfree(priv->scan_cmd); 3129 kfree(priv->scan_cmd);
3128 kfree(priv->beacon_cmd); 3130 kfree(priv->beacon_cmd);
3129#ifdef CONFIG_IWLWIFI_DEBUGFS 3131#ifdef CONFIG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 5e79c140ac1a..977015b47c64 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -36,6 +36,7 @@
36#include <linux/kernel.h> 36#include <linux/kernel.h>
37#include <linux/wait.h> 37#include <linux/wait.h>
38#include <linux/leds.h> 38#include <linux/leds.h>
39#include <linux/slab.h>
39#include <net/ieee80211_radiotap.h> 40#include <net/ieee80211_radiotap.h>
40 41
41#include "iwl-eeprom.h" 42#include "iwl-eeprom.h"
@@ -1053,6 +1054,7 @@ struct iwl_priv {
1053 struct ieee80211_hw *hw; 1054 struct ieee80211_hw *hw;
1054 struct ieee80211_channel *ieee_channels; 1055 struct ieee80211_channel *ieee_channels;
1055 struct ieee80211_rate *ieee_rates; 1056 struct ieee80211_rate *ieee_rates;
1057 struct kmem_cache *tx_cmd_pool;
1056 struct iwl_cfg *cfg; 1058 struct iwl_cfg *cfg;
1057 1059
1058 enum ieee80211_band band; 1060 enum ieee80211_band band;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
index e545898cddb3..7de042c6c258 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.c
@@ -317,12 +317,13 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans,
317 if (!txq->meta || !txq->cmd) 317 if (!txq->meta || !txq->cmd)
318 goto error; 318 goto error;
319 319
320 for (i = 0; i < slots_num; i++) { 320 if (txq_id == trans->shrd->cmd_queue)
321 txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd), 321 for (i = 0; i < slots_num; i++) {
322 GFP_KERNEL); 322 txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd),
323 if (!txq->cmd[i]) 323 GFP_KERNEL);
324 goto error; 324 if (!txq->cmd[i])
325 } 325 goto error;
326 }
326 327
327 /* Alloc driver data array and TFD circular buffer */ 328 /* Alloc driver data array and TFD circular buffer */
328 /* Driver private data, only for Tx (not command) queues, 329 /* Driver private data, only for Tx (not command) queues,
@@ -355,7 +356,7 @@ error:
355 txq->skbs = NULL; 356 txq->skbs = NULL;
356 /* since txq->cmd has been zeroed, 357 /* since txq->cmd has been zeroed,
357 * all non allocated cmd[i] will be NULL */ 358 * all non allocated cmd[i] will be NULL */
358 if (txq->cmd) 359 if (txq->cmd && txq_id == trans->shrd->cmd_queue)
359 for (i = 0; i < slots_num; i++) 360 for (i = 0; i < slots_num; i++)
360 kfree(txq->cmd[i]); 361 kfree(txq->cmd[i]);
361 kfree(txq->meta); 362 kfree(txq->meta);
@@ -442,8 +443,10 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
442 iwl_tx_queue_unmap(trans, txq_id); 443 iwl_tx_queue_unmap(trans, txq_id);
443 444
444 /* De-alloc array of command/tx buffers */ 445 /* De-alloc array of command/tx buffers */
445 for (i = 0; i < txq->q.n_window; i++) 446
446 kfree(txq->cmd[i]); 447 if (txq_id == trans->shrd->cmd_queue)
448 for (i = 0; i < txq->q.n_window; i++)
449 kfree(txq->cmd[i]);
447 450
448 /* De-alloc circular buffer of TFDs */ 451 /* De-alloc circular buffer of TFDs */
449 if (txq->q.n_bd) { 452 if (txq->q.n_bd) {
@@ -1009,37 +1012,13 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
1009 iwl_apm_stop(priv(trans)); 1012 iwl_apm_stop(priv(trans));
1010} 1013}
1011 1014
1012static struct iwl_tx_cmd *iwl_trans_pcie_get_tx_cmd(struct iwl_trans *trans,
1013 int txq_id)
1014{
1015 struct iwl_priv *priv = priv(trans);
1016 struct iwl_tx_queue *txq = &priv->txq[txq_id];
1017 struct iwl_queue *q = &txq->q;
1018 struct iwl_device_cmd *dev_cmd;
1019
1020 if (unlikely(iwl_queue_space(q) < q->high_mark))
1021 return NULL;
1022
1023 /*
1024 * Set up the Tx-command (not MAC!) header.
1025 * Store the chosen Tx queue and TFD index within the sequence field;
1026 * after Tx, uCode's Tx response will return this value so driver can
1027 * locate the frame within the tx queue and do post-tx processing.
1028 */
1029 dev_cmd = txq->cmd[q->write_ptr];
1030 memset(dev_cmd, 0, sizeof(*dev_cmd));
1031 dev_cmd->hdr.cmd = REPLY_TX;
1032 dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
1033 INDEX_TO_SEQ(q->write_ptr)));
1034 return &dev_cmd->cmd.tx;
1035}
1036
1037static int iwl_trans_pcie_tx(struct iwl_priv *priv, struct sk_buff *skb, 1015static int iwl_trans_pcie_tx(struct iwl_priv *priv, struct sk_buff *skb,
1038 struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu) 1016 struct iwl_device_cmd *dev_cmd, int txq_id,
1017 __le16 fc, bool ampdu)
1039{ 1018{
1040 struct iwl_tx_queue *txq = &priv->txq[txq_id]; 1019 struct iwl_tx_queue *txq = &priv->txq[txq_id];
1041 struct iwl_queue *q = &txq->q; 1020 struct iwl_queue *q = &txq->q;
1042 struct iwl_device_cmd *dev_cmd = txq->cmd[q->write_ptr]; 1021 struct iwl_tx_cmd *tx_cmd = &dev_cmd->cmd.tx;
1043 struct iwl_cmd_meta *out_meta; 1022 struct iwl_cmd_meta *out_meta;
1044 1023
1045 dma_addr_t phys_addr = 0; 1024 dma_addr_t phys_addr = 0;
@@ -1051,6 +1030,11 @@ static int iwl_trans_pcie_tx(struct iwl_priv *priv, struct sk_buff *skb,
1051 1030
1052 /* Set up driver data for this TFD */ 1031 /* Set up driver data for this TFD */
1053 txq->skbs[q->write_ptr] = skb; 1032 txq->skbs[q->write_ptr] = skb;
1033 txq->cmd[q->write_ptr] = dev_cmd;
1034
1035 dev_cmd->hdr.cmd = REPLY_TX;
1036 dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
1037 INDEX_TO_SEQ(q->write_ptr)));
1054 1038
1055 /* Set up first empty entry in queue's array of Tx/cmd buffers */ 1039 /* Set up first empty entry in queue's array of Tx/cmd buffers */
1056 out_meta = &txq->meta[q->write_ptr]; 1040 out_meta = &txq->meta[q->write_ptr];
@@ -1862,7 +1846,6 @@ const struct iwl_trans_ops trans_ops_pcie = {
1862 .send_cmd = iwl_trans_pcie_send_cmd, 1846 .send_cmd = iwl_trans_pcie_send_cmd,
1863 .send_cmd_pdu = iwl_trans_pcie_send_cmd_pdu, 1847 .send_cmd_pdu = iwl_trans_pcie_send_cmd_pdu,
1864 1848
1865 .get_tx_cmd = iwl_trans_pcie_get_tx_cmd,
1866 .tx = iwl_trans_pcie_tx, 1849 .tx = iwl_trans_pcie_tx,
1867 .reclaim = iwl_trans_pcie_reclaim, 1850 .reclaim = iwl_trans_pcie_reclaim,
1868 1851
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 011c82444566..0691d39bce05 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -76,6 +76,7 @@ struct iwl_priv;
76struct iwl_rxon_context; 76struct iwl_rxon_context;
77struct iwl_host_cmd; 77struct iwl_host_cmd;
78struct iwl_shared; 78struct iwl_shared;
79struct iwl_device_cmd;
79 80
80/** 81/**
81 * struct iwl_trans_ops - transport specific operations 82 * struct iwl_trans_ops - transport specific operations
@@ -90,7 +91,6 @@ struct iwl_shared;
90 * @stop_device:stops the whole device (embedded CPU put to reset) 91 * @stop_device:stops the whole device (embedded CPU put to reset)
91 * @send_cmd:send a host command 92 * @send_cmd:send a host command
92 * @send_cmd_pdu:send a host command: flags can be CMD_* 93 * @send_cmd_pdu:send a host command: flags can be CMD_*
93 * @get_tx_cmd: returns a pointer to a new Tx cmd for the upper layer use
94 * @tx: send an skb 94 * @tx: send an skb
95 * @reclaim: free packet until ssn. Returns a list of freed packets. 95 * @reclaim: free packet until ssn. Returns a list of freed packets.
96 * @txq_agg_setup: setup a tx queue for AMPDU - will be called once the HW is 96 * @txq_agg_setup: setup a tx queue for AMPDU - will be called once the HW is
@@ -117,9 +117,9 @@ struct iwl_trans_ops {
117 117
118 int (*send_cmd_pdu)(struct iwl_trans *trans, u8 id, u32 flags, u16 len, 118 int (*send_cmd_pdu)(struct iwl_trans *trans, u8 id, u32 flags, u16 len,
119 const void *data); 119 const void *data);
120 struct iwl_tx_cmd * (*get_tx_cmd)(struct iwl_trans *trans, int txq_id);
121 int (*tx)(struct iwl_priv *priv, struct sk_buff *skb, 120 int (*tx)(struct iwl_priv *priv, struct sk_buff *skb,
122 struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu); 121 struct iwl_device_cmd *dev_cmd,
122 int txq_id, __le16 fc, bool ampdu);
123 void (*reclaim)(struct iwl_trans *trans, int txq_id, int ssn, 123 void (*reclaim)(struct iwl_trans *trans, int txq_id, int ssn,
124 u32 status, struct sk_buff_head *skbs); 124 u32 status, struct sk_buff_head *skbs);
125 125
@@ -190,16 +190,11 @@ static inline int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id,
190 return trans->ops->send_cmd_pdu(trans, id, flags, len, data); 190 return trans->ops->send_cmd_pdu(trans, id, flags, len, data);
191} 191}
192 192
193static inline struct iwl_tx_cmd *iwl_trans_get_tx_cmd(struct iwl_trans *trans,
194 int txq_id)
195{
196 return trans->ops->get_tx_cmd(trans, txq_id);
197}
198
199static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, 193static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
200 struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu) 194 struct iwl_device_cmd *dev_cmd,
195 int txq_id, __le16 fc, bool ampdu)
201{ 196{
202 return trans->ops->tx(priv(trans), skb, tx_cmd, txq_id, fc, ampdu); 197 return trans->ops->tx(priv(trans), skb, dev_cmd, txq_id, fc, ampdu);
203} 198}
204 199
205static inline void iwl_trans_reclaim(struct iwl_trans *trans, int txq_id, 200static inline void iwl_trans_reclaim(struct iwl_trans *trans, int txq_id,