aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2012-02-09 09:08:15 -0500
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2012-02-27 16:26:33 -0500
commited277c9361e423df2bc19312c60b9d06cac31ee6 (patch)
tree210cc5dfe7636aa1a525849a4ca05afe1b73c2a6 /drivers/net/wireless/iwlwifi
parentcbe6ab4e11603e426e01c6349cd5643f3a287ba4 (diff)
iwlwifi: virtualize op_mode's free skb
This handler allows the transport layer to free an skb from the op_mode. This can happen when the driver is stopped while Tx packets are pending in the transport layer. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-op-mode.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-shared.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h13
7 files changed, 34 insertions, 3 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index dbef0f48c3ef..ac62010408a0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1170,6 +1170,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans)
1170 priv->shrd = trans->shrd; 1170 priv->shrd = trans->shrd;
1171 priv->shrd->priv = priv; 1171 priv->shrd->priv = priv;
1172 1172
1173 iwl_trans_configure(trans(priv), op_mode);
1174
1173 /* At this point both hw and priv are allocated. */ 1175 /* At this point both hw and priv are allocated. */
1174 1176
1175 SET_IEEE80211_DEV(priv->hw, trans(priv)->dev); 1177 SET_IEEE80211_DEV(priv->hw, trans(priv)->dev);
@@ -1383,6 +1385,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
1383const struct iwl_op_mode_ops iwl_dvm_ops = { 1385const struct iwl_op_mode_ops iwl_dvm_ops = {
1384 .start = iwl_op_mode_dvm_start, 1386 .start = iwl_op_mode_dvm_start,
1385 .stop = iwl_op_mode_dvm_stop, 1387 .stop = iwl_op_mode_dvm_stop,
1388 .free_skb = iwl_free_skb,
1386}; 1389};
1387 1390
1388/***************************************************************************** 1391/*****************************************************************************
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 79894aca9644..00253f3d987f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -80,6 +80,7 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
80void iwl_down(struct iwl_priv *priv); 80void iwl_down(struct iwl_priv *priv);
81void iwl_cancel_deferred_work(struct iwl_priv *priv); 81void iwl_cancel_deferred_work(struct iwl_priv *priv);
82void iwlagn_prepare_restart(struct iwl_priv *priv); 82void iwlagn_prepare_restart(struct iwl_priv *priv);
83void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
83 84
84/* MAC80211 */ 85/* MAC80211 */
85struct ieee80211_hw *iwl_alloc_all(void); 86struct ieee80211_hw *iwl_alloc_all(void);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index f52d5458a3af..675464a0218e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -41,6 +41,7 @@
41#include "iwl-shared.h" 41#include "iwl-shared.h"
42#include "iwl-agn.h" 42#include "iwl-agn.h"
43#include "iwl-trans.h" 43#include "iwl-trans.h"
44#include "iwl-wifi.h"
44 45
45const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 46const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
46 47
@@ -1464,8 +1465,9 @@ void iwl_nic_config(struct iwl_priv *priv)
1464 cfg(priv)->lib->nic_config(priv); 1465 cfg(priv)->lib->nic_config(priv);
1465} 1466}
1466 1467
1467void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb) 1468void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
1468{ 1469{
1470 struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
1469 struct ieee80211_tx_info *info; 1471 struct ieee80211_tx_info *info;
1470 1472
1471 info = IEEE80211_SKB_CB(skb); 1473 info = IEEE80211_SKB_CB(skb);
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index c85c8dcabb49..59dd3074bf73 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -65,6 +65,7 @@
65 65
66struct iwl_op_mode; 66struct iwl_op_mode;
67struct iwl_trans; 67struct iwl_trans;
68struct sk_buff;
68 69
69/** 70/**
70 * struct iwl_op_mode_ops - op_mode specific operations 71 * struct iwl_op_mode_ops - op_mode specific operations
@@ -75,10 +76,15 @@ struct iwl_trans;
75 * May sleep 76 * May sleep
76 * @stop: stop the op_mode 77 * @stop: stop the op_mode
77 * May sleep 78 * May sleep
79 * @free_skb: allows the transport layer to free skbs that haven't been
80 * reclaimed by the op_mode. This can happen when the driver is freed and
81 * there are Tx packets pending in the transport layer.
82 * Must be atomic
78 */ 83 */
79struct iwl_op_mode_ops { 84struct iwl_op_mode_ops {
80 struct iwl_op_mode *(*start)(struct iwl_trans *trans); 85 struct iwl_op_mode *(*start)(struct iwl_trans *trans);
81 void (*stop)(struct iwl_op_mode *op_mode); 86 void (*stop)(struct iwl_op_mode *op_mode);
87 void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
82}; 88};
83 89
84/** 90/**
@@ -100,6 +106,12 @@ static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode)
100 op_mode->ops->stop(op_mode); 106 op_mode->ops->stop(op_mode);
101} 107}
102 108
109static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode,
110 struct sk_buff *skb)
111{
112 op_mode->ops->free_skb(op_mode, skb);
113}
114
103/***************************************************** 115/*****************************************************
104* Op mode layers implementations 116* Op mode layers implementations
105******************************************************/ 117******************************************************/
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index 635e3eb4f86d..eff9360a0c7f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -540,7 +540,6 @@ int __must_check iwl_rx_dispatch(struct iwl_priv *priv,
540int iwlagn_hw_valid_rtc_data_addr(u32 addr); 540int iwlagn_hw_valid_rtc_data_addr(u32 addr);
541void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state); 541void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state);
542void iwl_nic_config(struct iwl_priv *priv); 542void iwl_nic_config(struct iwl_priv *priv);
543void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb);
544void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); 543void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
545const char *get_cmd_string(u8 cmd); 544const char *get_cmd_string(u8 cmd);
546bool iwl_check_for_ct_kill(struct iwl_priv *priv); 545bool iwl_check_for_ct_kill(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
index a3cebd76dc0c..bca0f4fa2ffa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
@@ -35,6 +35,7 @@
35#include "iwl-prph.h" 35#include "iwl-prph.h"
36#include "iwl-io.h" 36#include "iwl-io.h"
37#include "iwl-agn-hw.h" 37#include "iwl-agn-hw.h"
38#include "iwl-op-mode.h"
38#include "iwl-trans-pcie-int.h" 39#include "iwl-trans-pcie-int.h"
39 40
40#define IWL_TX_CRC_SIZE 4 41#define IWL_TX_CRC_SIZE 4
@@ -229,7 +230,7 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
229 * freed and that the queue is not empty - free the skb 230 * freed and that the queue is not empty - free the skb
230 */ 231 */
231 if (skb) { 232 if (skb) {
232 iwl_free_skb(priv(trans), skb); 233 iwl_op_mode_free_skb(trans->op_mode, skb);
233 txq->skbs[index] = NULL; 234 txq->skbs[index] = NULL;
234 } 235 }
235 } 236 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index f42328605356..fbb09f684670 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -114,6 +114,7 @@
114 114
115struct iwl_priv; 115struct iwl_priv;
116struct iwl_shared; 116struct iwl_shared;
117struct iwl_op_mode;
117 118
118/** 119/**
119 * DOC: Host command section 120 * DOC: Host command section
@@ -312,6 +313,7 @@ enum iwl_trans_state {
312 * struct iwl_trans - transport common data 313 * struct iwl_trans - transport common data
313 * 314 *
314 * @ops - pointer to iwl_trans_ops 315 * @ops - pointer to iwl_trans_ops
316 * @op_mode - pointer to the op_mode
315 * @shrd - pointer to iwl_shared which holds shared data from the upper layer 317 * @shrd - pointer to iwl_shared which holds shared data from the upper layer
316 * @hcmd_lock: protects HCMD 318 * @hcmd_lock: protects HCMD
317 * @reg_lock - protect hw register access 319 * @reg_lock - protect hw register access
@@ -327,6 +329,7 @@ enum iwl_trans_state {
327 */ 329 */
328struct iwl_trans { 330struct iwl_trans {
329 const struct iwl_trans_ops *ops; 331 const struct iwl_trans_ops *ops;
332 struct iwl_op_mode *op_mode;
330 struct iwl_shared *shrd; 333 struct iwl_shared *shrd;
331 enum iwl_trans_state state; 334 enum iwl_trans_state state;
332 spinlock_t hcmd_lock; 335 spinlock_t hcmd_lock;
@@ -350,6 +353,16 @@ struct iwl_trans {
350 char trans_specific[0] __aligned(sizeof(void *)); 353 char trans_specific[0] __aligned(sizeof(void *));
351}; 354};
352 355
356static inline void iwl_trans_configure(struct iwl_trans *trans,
357 struct iwl_op_mode *op_mode)
358{
359 /*
360 * only set the op_mode for the moment. Later on, this function will do
361 * more
362 */
363 trans->op_mode = op_mode;
364}
365
353static inline int iwl_trans_start_hw(struct iwl_trans *trans) 366static inline int iwl_trans_start_hw(struct iwl_trans *trans)
354{ 367{
355 might_sleep(); 368 might_sleep();