diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2012-02-09 09:08:15 -0500 |
---|---|---|
committer | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2012-02-27 16:26:33 -0500 |
commit | ed277c9361e423df2bc19312c60b9d06cac31ee6 (patch) | |
tree | 210cc5dfe7636aa1a525849a4ca05afe1b73c2a6 /drivers/net/wireless/iwlwifi | |
parent | cbe6ab4e11603e426e01c6349cd5643f3a287ba4 (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.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-op-mode.h | 12 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-shared.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.h | 13 |
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) | |||
1383 | const struct iwl_op_mode_ops iwl_dvm_ops = { | 1385 | const 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) | |||
80 | void iwl_down(struct iwl_priv *priv); | 80 | void iwl_down(struct iwl_priv *priv); |
81 | void iwl_cancel_deferred_work(struct iwl_priv *priv); | 81 | void iwl_cancel_deferred_work(struct iwl_priv *priv); |
82 | void iwlagn_prepare_restart(struct iwl_priv *priv); | 82 | void iwlagn_prepare_restart(struct iwl_priv *priv); |
83 | void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb); | ||
83 | 84 | ||
84 | /* MAC80211 */ | 85 | /* MAC80211 */ |
85 | struct ieee80211_hw *iwl_alloc_all(void); | 86 | struct 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 | ||
45 | const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 46 | const 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 | ||
1467 | void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb) | 1468 | void 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 | ||
66 | struct iwl_op_mode; | 66 | struct iwl_op_mode; |
67 | struct iwl_trans; | 67 | struct iwl_trans; |
68 | struct 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 | */ |
79 | struct iwl_op_mode_ops { | 84 | struct 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 | ||
109 | static 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, | |||
540 | int iwlagn_hw_valid_rtc_data_addr(u32 addr); | 540 | int iwlagn_hw_valid_rtc_data_addr(u32 addr); |
541 | void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state); | 541 | void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state); |
542 | void iwl_nic_config(struct iwl_priv *priv); | 542 | void iwl_nic_config(struct iwl_priv *priv); |
543 | void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb); | ||
544 | void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); | 543 | void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); |
545 | const char *get_cmd_string(u8 cmd); | 544 | const char *get_cmd_string(u8 cmd); |
546 | bool iwl_check_for_ct_kill(struct iwl_priv *priv); | 545 | bool 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 | ||
115 | struct iwl_priv; | 115 | struct iwl_priv; |
116 | struct iwl_shared; | 116 | struct iwl_shared; |
117 | struct 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 | */ |
328 | struct iwl_trans { | 330 | struct 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 | ||
356 | static 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 | |||
353 | static inline int iwl_trans_start_hw(struct iwl_trans *trans) | 366 | static inline int iwl_trans_start_hw(struct iwl_trans *trans) |
354 | { | 367 | { |
355 | might_sleep(); | 368 | might_sleep(); |