Commit ed277c93 authored by Emmanuel Grumbach's avatar Emmanuel Grumbach Committed by Wey-Yi Guy

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: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
parent cbe6ab4e
...@@ -1170,6 +1170,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans) ...@@ -1170,6 +1170,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans)
priv->shrd = trans->shrd; priv->shrd = trans->shrd;
priv->shrd->priv = priv; priv->shrd->priv = priv;
iwl_trans_configure(trans(priv), op_mode);
/* At this point both hw and priv are allocated. */ /* At this point both hw and priv are allocated. */
SET_IEEE80211_DEV(priv->hw, trans(priv)->dev); 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,6 +1385,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
const struct iwl_op_mode_ops iwl_dvm_ops = { const struct iwl_op_mode_ops iwl_dvm_ops = {
.start = iwl_op_mode_dvm_start, .start = iwl_op_mode_dvm_start,
.stop = iwl_op_mode_dvm_stop, .stop = iwl_op_mode_dvm_stop,
.free_skb = iwl_free_skb,
}; };
/***************************************************************************** /*****************************************************************************
......
...@@ -80,6 +80,7 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) ...@@ -80,6 +80,7 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
void iwl_down(struct iwl_priv *priv); void iwl_down(struct iwl_priv *priv);
void iwl_cancel_deferred_work(struct iwl_priv *priv); void iwl_cancel_deferred_work(struct iwl_priv *priv);
void iwlagn_prepare_restart(struct iwl_priv *priv); void iwlagn_prepare_restart(struct iwl_priv *priv);
void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb);
/* MAC80211 */ /* MAC80211 */
struct ieee80211_hw *iwl_alloc_all(void); struct ieee80211_hw *iwl_alloc_all(void);
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "iwl-shared.h" #include "iwl-shared.h"
#include "iwl-agn.h" #include "iwl-agn.h"
#include "iwl-trans.h" #include "iwl-trans.h"
#include "iwl-wifi.h"
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
...@@ -1464,8 +1465,9 @@ void iwl_nic_config(struct iwl_priv *priv) ...@@ -1464,8 +1465,9 @@ void iwl_nic_config(struct iwl_priv *priv)
cfg(priv)->lib->nic_config(priv); cfg(priv)->lib->nic_config(priv);
} }
void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb) void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
{ {
struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode);
struct ieee80211_tx_info *info; struct ieee80211_tx_info *info;
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
struct iwl_op_mode; struct iwl_op_mode;
struct iwl_trans; struct iwl_trans;
struct sk_buff;
/** /**
* struct iwl_op_mode_ops - op_mode specific operations * struct iwl_op_mode_ops - op_mode specific operations
...@@ -75,10 +76,15 @@ struct iwl_trans; ...@@ -75,10 +76,15 @@ struct iwl_trans;
* May sleep * May sleep
* @stop: stop the op_mode * @stop: stop the op_mode
* May sleep * May sleep
* @free_skb: allows the transport layer to free skbs that haven't been
* reclaimed by the op_mode. This can happen when the driver is freed and
* there are Tx packets pending in the transport layer.
* Must be atomic
*/ */
struct iwl_op_mode_ops { struct iwl_op_mode_ops {
struct iwl_op_mode *(*start)(struct iwl_trans *trans); struct iwl_op_mode *(*start)(struct iwl_trans *trans);
void (*stop)(struct iwl_op_mode *op_mode); void (*stop)(struct iwl_op_mode *op_mode);
void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb);
}; };
/** /**
...@@ -100,6 +106,12 @@ static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode) ...@@ -100,6 +106,12 @@ static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode)
op_mode->ops->stop(op_mode); op_mode->ops->stop(op_mode);
} }
static inline void iwl_op_mode_free_skb(struct iwl_op_mode *op_mode,
struct sk_buff *skb)
{
op_mode->ops->free_skb(op_mode, skb);
}
/***************************************************** /*****************************************************
* Op mode layers implementations * Op mode layers implementations
******************************************************/ ******************************************************/
......
...@@ -540,7 +540,6 @@ int __must_check iwl_rx_dispatch(struct iwl_priv *priv, ...@@ -540,7 +540,6 @@ int __must_check iwl_rx_dispatch(struct iwl_priv *priv,
int iwlagn_hw_valid_rtc_data_addr(u32 addr); int iwlagn_hw_valid_rtc_data_addr(u32 addr);
void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state); void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state);
void iwl_nic_config(struct iwl_priv *priv); void iwl_nic_config(struct iwl_priv *priv);
void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb);
void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
const char *get_cmd_string(u8 cmd); const char *get_cmd_string(u8 cmd);
bool iwl_check_for_ct_kill(struct iwl_priv *priv); bool iwl_check_for_ct_kill(struct iwl_priv *priv);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "iwl-prph.h" #include "iwl-prph.h"
#include "iwl-io.h" #include "iwl-io.h"
#include "iwl-agn-hw.h" #include "iwl-agn-hw.h"
#include "iwl-op-mode.h"
#include "iwl-trans-pcie-int.h" #include "iwl-trans-pcie-int.h"
#define IWL_TX_CRC_SIZE 4 #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,7 +230,7 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
* freed and that the queue is not empty - free the skb * freed and that the queue is not empty - free the skb
*/ */
if (skb) { if (skb) {
iwl_free_skb(priv(trans), skb); iwl_op_mode_free_skb(trans->op_mode, skb);
txq->skbs[index] = NULL; txq->skbs[index] = NULL;
} }
} }
......
...@@ -114,6 +114,7 @@ ...@@ -114,6 +114,7 @@
struct iwl_priv; struct iwl_priv;
struct iwl_shared; struct iwl_shared;
struct iwl_op_mode;
/** /**
* DOC: Host command section * DOC: Host command section
...@@ -312,6 +313,7 @@ enum iwl_trans_state { ...@@ -312,6 +313,7 @@ enum iwl_trans_state {
* struct iwl_trans - transport common data * struct iwl_trans - transport common data
* *
* @ops - pointer to iwl_trans_ops * @ops - pointer to iwl_trans_ops
* @op_mode - pointer to the op_mode
* @shrd - pointer to iwl_shared which holds shared data from the upper layer * @shrd - pointer to iwl_shared which holds shared data from the upper layer
* @hcmd_lock: protects HCMD * @hcmd_lock: protects HCMD
* @reg_lock - protect hw register access * @reg_lock - protect hw register access
...@@ -327,6 +329,7 @@ enum iwl_trans_state { ...@@ -327,6 +329,7 @@ enum iwl_trans_state {
*/ */
struct iwl_trans { struct iwl_trans {
const struct iwl_trans_ops *ops; const struct iwl_trans_ops *ops;
struct iwl_op_mode *op_mode;
struct iwl_shared *shrd; struct iwl_shared *shrd;
enum iwl_trans_state state; enum iwl_trans_state state;
spinlock_t hcmd_lock; spinlock_t hcmd_lock;
...@@ -350,6 +353,16 @@ struct iwl_trans { ...@@ -350,6 +353,16 @@ struct iwl_trans {
char trans_specific[0] __aligned(sizeof(void *)); char trans_specific[0] __aligned(sizeof(void *));
}; };
static inline void iwl_trans_configure(struct iwl_trans *trans,
struct iwl_op_mode *op_mode)
{
/*
* only set the op_mode for the moment. Later on, this function will do
* more
*/
trans->op_mode = op_mode;
}
static inline int iwl_trans_start_hw(struct iwl_trans *trans) static inline int iwl_trans_start_hw(struct iwl_trans *trans)
{ {
might_sleep(); might_sleep();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment